2012-04-17 69 views
5

在我正在編寫的腳本中,我創建了一個專用用戶來啓動我們內部開發的一些Windows服務。爲了啓動這些服務,我們的「專用」用戶需要SeServiceLogonRight特權。目前,我使用的是與Ntrights.exe的從我的PowerShell腳本以下呼叫分配這種特權:從PowerShell向用戶授予SeServiceLogonRight

{.$global:RootInstallDir\..\Common\SupportTools\ntrights.exe -m $env:COMPUTERNAME -u $HealthLinkUser +r SeServiceLogonRight } 

不過,我並不滿足於此。使用PowerShell必須有更簡潔的方法。

+0

[可能的複製(HTTP:// stackoverflow.com/questions/313831/using-powershell-how-do-i-grant-log-on-as-service-to-an-account) – 2012-04-17 08:51:40

+1

你需要p/invoke。這會讓你開始。 http://www.roelvanlisdonk.nl/?p=1151 – 2012-04-17 08:57:46

回答

5

這對我有效。您可以決定哪個更清潔;-)關鍵是LsaAddAccountRights Windows API函數。

Add-Type @' 
using System; 
using System.Collections.Generic; 
using System.Text; 

namespace MyLsaWrapper 
{ 
    using System.Runtime.InteropServices; 
    using System.Security; 
    using System.Management; 
    using System.Runtime.CompilerServices; 
    using System.ComponentModel; 

    using LSA_HANDLE = IntPtr; 

    [StructLayout(LayoutKind.Sequential)] 
    struct LSA_OBJECT_ATTRIBUTES 
    { 
     internal int Length; 
     internal IntPtr RootDirectory; 
     internal IntPtr ObjectName; 
     internal int Attributes; 
     internal IntPtr SecurityDescriptor; 
     internal IntPtr SecurityQualityOfService; 
    } 
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
    struct LSA_UNICODE_STRING 
    { 
     internal ushort Length; 
     internal ushort MaximumLength; 
     [MarshalAs(UnmanagedType.LPWStr)] 
     internal string Buffer; 
    } 
    sealed class Win32Sec 
    { 
     [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), 
     SuppressUnmanagedCodeSecurityAttribute] 
     internal static extern uint LsaOpenPolicy(
     LSA_UNICODE_STRING[] SystemName, 
     ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, 
     int AccessMask, 
     out IntPtr PolicyHandle 
     ); 

     [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), 
     SuppressUnmanagedCodeSecurityAttribute] 
     internal static extern uint LsaAddAccountRights(
     LSA_HANDLE PolicyHandle, 
     IntPtr pSID, 
     LSA_UNICODE_STRING[] UserRights, 
     int CountOfRights 
     ); 

     [DllImport("advapi32", CharSet = CharSet.Unicode, SetLastError = true), 
     SuppressUnmanagedCodeSecurityAttribute] 
     internal static extern int LsaLookupNames2(
     LSA_HANDLE PolicyHandle, 
     uint Flags, 
     uint Count, 
     LSA_UNICODE_STRING[] Names, 
     ref IntPtr ReferencedDomains, 
     ref IntPtr Sids 
     ); 

     [DllImport("advapi32")] 
     internal static extern int LsaNtStatusToWinError(int NTSTATUS); 

     [DllImport("advapi32")] 
     internal static extern int LsaClose(IntPtr PolicyHandle); 

     [DllImport("advapi32")] 
     internal static extern int LsaFreeMemory(IntPtr Buffer); 

    } 
    /// <summary> 
    /// This class is used to grant "Log on as a service", "Log on as a batchjob", "Log on localy" etc. 
    /// to a user. 
    /// </summary> 
    public sealed class LsaWrapper : IDisposable 
    { 
     [StructLayout(LayoutKind.Sequential)] 
     struct LSA_TRUST_INFORMATION 
     { 
      internal LSA_UNICODE_STRING Name; 
      internal IntPtr Sid; 
     } 
     [StructLayout(LayoutKind.Sequential)] 
     struct LSA_TRANSLATED_SID2 
     { 
      internal SidNameUse Use; 
      internal IntPtr Sid; 
      internal int DomainIndex; 
      uint Flags; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     struct LSA_REFERENCED_DOMAIN_LIST 
     { 
      internal uint Entries; 
      internal LSA_TRUST_INFORMATION Domains; 
     } 

     enum SidNameUse : int 
     { 
      User = 1, 
      Group = 2, 
      Domain = 3, 
      Alias = 4, 
      KnownGroup = 5, 
      DeletedAccount = 6, 
      Invalid = 7, 
      Unknown = 8, 
      Computer = 9 
     } 

     enum Access : int 
     { 
      POLICY_READ = 0x20006, 
      POLICY_ALL_ACCESS = 0x00F0FFF, 
      POLICY_EXECUTE = 0X20801, 
      POLICY_WRITE = 0X207F8 
     } 
     const uint STATUS_ACCESS_DENIED = 0xc0000022; 
     const uint STATUS_INSUFFICIENT_RESOURCES = 0xc000009a; 
     const uint STATUS_NO_MEMORY = 0xc0000017; 

     IntPtr lsaHandle; 

     public LsaWrapper() 
      : this(null) 
     { } 
     // // local system if systemName is null 
     public LsaWrapper(string systemName) 
     { 
      LSA_OBJECT_ATTRIBUTES lsaAttr; 
      lsaAttr.RootDirectory = IntPtr.Zero; 
      lsaAttr.ObjectName = IntPtr.Zero; 
      lsaAttr.Attributes = 0; 
      lsaAttr.SecurityDescriptor = IntPtr.Zero; 
      lsaAttr.SecurityQualityOfService = IntPtr.Zero; 
      lsaAttr.Length = Marshal.SizeOf(typeof(LSA_OBJECT_ATTRIBUTES)); 
      lsaHandle = IntPtr.Zero; 
      LSA_UNICODE_STRING[] system = null; 
      if (systemName != null) 
      { 
       system = new LSA_UNICODE_STRING[1]; 
       system[0] = InitLsaString(systemName); 
      } 

      uint ret = Win32Sec.LsaOpenPolicy(system, ref lsaAttr, 
      (int)Access.POLICY_ALL_ACCESS, out lsaHandle); 
      if (ret == 0) 
       return; 
      if (ret == STATUS_ACCESS_DENIED) 
      { 
       throw new UnauthorizedAccessException(); 
      } 
      if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) 
      { 
       throw new OutOfMemoryException(); 
      } 
      throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret)); 
     } 

     public void AddPrivileges(string account, string privilege) 
     { 
      IntPtr pSid = GetSIDInformation(account); 
      LSA_UNICODE_STRING[] privileges = new LSA_UNICODE_STRING[1]; 
      privileges[0] = InitLsaString(privilege); 
      uint ret = Win32Sec.LsaAddAccountRights(lsaHandle, pSid, privileges, 1); 
      if (ret == 0) 
       return; 
      if (ret == STATUS_ACCESS_DENIED) 
      { 
       throw new UnauthorizedAccessException(); 
      } 
      if ((ret == STATUS_INSUFFICIENT_RESOURCES) || (ret == STATUS_NO_MEMORY)) 
      { 
       throw new OutOfMemoryException(); 
      } 
      throw new Win32Exception(Win32Sec.LsaNtStatusToWinError((int)ret)); 
     } 

     public void Dispose() 
     { 
      if (lsaHandle != IntPtr.Zero) 
      { 
       Win32Sec.LsaClose(lsaHandle); 
       lsaHandle = IntPtr.Zero; 
      } 
      GC.SuppressFinalize(this); 
     } 
     ~LsaWrapper() 
     { 
      Dispose(); 
     } 
     // helper functions 

     IntPtr GetSIDInformation(string account) 
     { 
      LSA_UNICODE_STRING[] names = new LSA_UNICODE_STRING[1]; 
      LSA_TRANSLATED_SID2 lts; 
      IntPtr tsids = IntPtr.Zero; 
      IntPtr tdom = IntPtr.Zero; 
      names[0] = InitLsaString(account); 
      lts.Sid = IntPtr.Zero; 
      Console.WriteLine("String account: {0}", names[0].Length); 
      int ret = Win32Sec.LsaLookupNames2(lsaHandle, 0, 1, names, ref tdom, ref tsids); 
      if (ret != 0) 
       throw new Win32Exception(Win32Sec.LsaNtStatusToWinError(ret)); 
      lts = (LSA_TRANSLATED_SID2)Marshal.PtrToStructure(tsids, 
      typeof(LSA_TRANSLATED_SID2)); 
      Win32Sec.LsaFreeMemory(tsids); 
      Win32Sec.LsaFreeMemory(tdom); 
      return lts.Sid; 
     } 

     static LSA_UNICODE_STRING InitLsaString(string s) 
     { 
      // Unicode strings max. 32KB 
      if (s.Length > 0x7ffe) 
       throw new ArgumentException("String too long"); 
      LSA_UNICODE_STRING lus = new LSA_UNICODE_STRING(); 
      lus.Buffer = s; 
      lus.Length = (ushort)(s.Length * sizeof(char)); 
      lus.MaximumLength = (ushort)(lus.Length + sizeof(char)); 
      return lus; 
     } 
    } 
    public class LsaWrapperCaller 
    { 
     public static void AddPrivileges(string account, string privilege) 
     { 
      using (LsaWrapper lsaWrapper = new LsaWrapper()) 
      { 
       lsaWrapper.AddPrivileges(account, privilege); 
      } 
     } 
    } 
} 
'@ 

[MyLsaWrapper.LsaWrapperCaller]::AddPrivileges("andy", "SeServiceLogonRight") 
+0

我用過這個,因爲我不想依賴於ntrights.exe。它的工作原理,但只在第二次嘗試。在第一次嘗試時,它會在AddPrivileges中引發Win32Exception - 「參數不正確」。還沒有制定出爲什麼呢。 – 2013-01-14 19:28:07

5

這真的應該是對Andy的回答的一個評論,但是我沒有需要評論的代表。

所提供的代碼將訪問已釋放的內存 - 可能「有效」(有時),但始終是不好的做法。請參閱我對有關同一代碼問題的另一個問題的回答:Why might LsaAddAccountRights return STATUS_INVALID_PARAMETER?

看起來這個代碼已經被傳遞了好幾年了。

3

基本上相同的P/Invoke技術,採用C#調用系統DLL的程序,但這個例子可能有點更容易跟蹤:

$code = @" 
using System; 
using System.Runtime.InteropServices; 

public class TokenManipulator 
{ 

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] 
    internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, 
    ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen); 

    [DllImport("kernel32.dll", ExactSpelling = true)] 
    internal static extern IntPtr GetCurrentProcess(); 

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)] 
    internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr 
    phtok); 

    [DllImport("advapi32.dll", SetLastError = true)] 
    internal static extern bool LookupPrivilegeValue(string host, string name, 
    ref long pluid); 

    [StructLayout(LayoutKind.Sequential, Pack = 1)] 
    internal struct TokPriv1Luid 
    { 
    public int Count; 
    public long Luid; 
    public int Attr; 
    } 

    internal const int SE_PRIVILEGE_DISABLED = 0x00000000; 
    internal const int SE_PRIVILEGE_ENABLED = 0x00000002; 
    internal const int TOKEN_QUERY = 0x00000008; 
    internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020; 

    public static bool AddPrivilege(string privilege) 
    { 
    try 
    { 
    bool retVal; 
    TokPriv1Luid tp; 
    IntPtr hproc = GetCurrentProcess(); 
    IntPtr htok = IntPtr.Zero; 
    retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); 
    tp.Count = 1; 
    tp.Luid = 0; 
    tp.Attr = SE_PRIVILEGE_ENABLED; 
    retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid); 
    retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); 
    return retVal; 
    } 
    catch (Exception ex) 
    { 
    throw ex; 
    } 
    } 

    public static bool RemovePrivilege(string privilege) 
    { 
    try 
    { 
    bool retVal; 
    TokPriv1Luid tp; 
    IntPtr hproc = GetCurrentProcess(); 
    IntPtr htok = IntPtr.Zero; 
    retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok); 
    tp.Count = 1; 

    tp.Luid = 0; 
    tp.Attr = SE_PRIVILEGE_DISABLED; 
    retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid); 
    retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero); 
    return retVal; 
    } 
    catch (Exception ex) 
    { 
    throw ex; 
    } 
    } 

} 
"@ 

add-type $code 

"`nInitial privileges" 
whoami /priv | Select-String "SeRestorePrivilege" 
whoami /priv | Select-String "SeBackupPrivilege" 
whoami /priv | Select-String "SeTakeOwnershipPrivilege" 

"`nAdding privileges" 
#Activate necessary admin privileges to make changes without NTFS perms 
[void][TokenManipulator]::AddPrivilege("SeRestorePrivilege") #Necessary to set Owner Permissions 
[void][TokenManipulator]::AddPrivilege("SeBackupPrivilege") #Necessary to bypass Traverse Checking 
[void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege") #Necessary to override FilePermissions 
whoami /priv | Select-String "SeRestorePrivilege" 
whoami /priv | Select-String "SeBackupPrivilege" 
whoami /priv | Select-String "SeTakeOwnershipPrivilege" 

"`nRemoving privileges just added before terminating" 
[void][TokenManipulator]::AddPrivilege("SeRestorePrivilege") #Necessary to set Owner Permissions 
[void][TokenManipulator]::AddPrivilege("SeBackupPrivilege") #Necessary to bypass Traverse Checking 
[void][TokenManipulator]::AddPrivilege("SeTakeOwnershipPrivilege") #Necessary to override 
whoami /priv | Select-String "SeRestorePrivilege" 
whoami /priv | Select-String "SeBackupPrivilege" 
whoami /priv | Select-String "SeTakeOwnershipPrivilege" 

這混淆了我很多,並有大量的例子論壇主題以'使用第三方'應用程序結束。如果淨列入本必備的功能這將是很好,但儘管此代碼示例的長度,它是非常簡單的複製:) 乾杯,巴納比

0

這是我如何解決它:基於

this article

可以按如下方式下載Carbon from here

首次進口碳模塊:

Import-Module -Name $Path_To_Carbon -Global -Prefix CA 

[array]$UserPrivileges = Get-CAPrivileges -Identity $UserName; 
[bool]$LogOnAsAServiceprivilegeFound = $false; 

if ($UserPrivileges.Length > 0) 
{ 
    if ($UserPrivileges -contains "SeServiceLogonRight") 
    { 
     $LogOnAsAServiceprivilegeFound = $true; 
    } 
} 

if ($LogOnAsAServiceprivilegeFound -eq $false) 
{ 
    Grant-CAPrivilege -Identity $UserName "SeServiceLogonRight" 
} 
2

此腳本包含了做工精細的功能,沒有任何依賴關係:

https://gallery.technet.microsoft.com/scriptcenter/Grant-Revoke-Query-user-26e259b0

除此之外,這裏是你的問題的具體的解決方案:

function Add-ServiceLogonRight([string] $Username) { 
    Write-Host "Enable ServiceLogonRight for $Username" 

    $tmp = New-TemporaryFile 
    secedit /export /cfg "$tmp.inf" | Out-Null 
    (gc -Encoding ascii "$tmp.inf") -replace '^SeServiceLogonRight .+', "`$0,$Username" | sc -Encoding ascii "$tmp.inf" 
    secedit /import /cfg "$tmp.inf" /db "$tmp.sdb" | Out-Null 
    secedit /configure /db "$tmp.sdb" /cfg "$tmp.inf" | Out-Null 
    rm $tmp* -ea 0 
}