2012-04-17 37 views
5

Trong tập lệnh tôi hiện đang viết, tôi tạo người dùng chuyên dụng để bắt đầu một số dịch vụ windows mà chúng tôi đã phát triển nội bộ. Để bắt đầu các dịch vụ này, người dùng "chuyên dụng" của chúng ta cần đặc quyền SeServiceLogonRight. Hiện tại, tôi đang chỉ định đặc quyền đó bằng cách sử dụng ntrights.exe với lệnh gọi sau từ kịch bản PowerShell của tôi:Cấp SeServiceLogonRight cho người dùng từ PowerShell

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

Tuy nhiên, tôi không hài lòng với điều này. Phải có cách làm sạch hơn với PowerShell.

+0

[Có thể trùng lặp] (http: // stackoverflow.com/questions/313831/using-powershell-how-do-i-grant-log-on-as-service-to-an-account) –

+1

Bạn cần p/gọi. Điều này sẽ giúp bạn bắt đầu. http://www.roelvanlisdonk.nl/?p=1151 –

Trả lời

5

Điều này phù hợp với tôi. Bạn có thể quyết định cái nào là sạch hơn ;-) Điều quan trọng là hàm API cửa sổ LsaAddAccountRights.

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

Tôi đã sử dụng điều này vì tôi không muốn phụ thuộc vào ntrights.exe. Nó hoạt động nhưng chỉ vào lần thử thứ hai. Trong lần thử đầu tiên, nó ném ra một Win32Exception trong AddPrivileges - "Tham số không chính xác". Chưa hiểu tại sao. –

5

Điều này thực sự phải là nhận xét cho câu trả lời của Andy nhưng tôi không có đại diện cần thiết để nhận xét.

Mã được cung cấp sẽ truy cập vào bộ nhớ đã được giải phóng - có thể "hoạt động" (đôi khi) nhưng luôn luôn là thực hành không tốt. Vui lòng xem câu trả lời của tôi cho một câu hỏi khác về sự cố có cùng mã: Why might LsaAddAccountRights return STATUS_INVALID_PARAMETER?

Dường như mã này đã được chuyển đi trong vài năm.

3

Về cơ bản P cùng/kỹ thuật Invoke để sử dụng C# để gọi thủ tục hệ thống DLL, nhưng ví dụ này có thể là một chút dễ dàng hơn để làm theo:

$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" 

này nhầm lẫn cho tôi rất nhiều, và có rất nhiều ví dụ về các chuỗi diễn đàn kết thúc bằng ứng dụng 'sử dụng bên thứ 3'. Nó sẽ được tốt đẹp nếu Net bao gồm chức năng cần thiết này, nhưng mặc dù chiều dài của mẫu mã này, nó là khá dễ dàng để tái tạo :) Chúc mừng, Barnaby

0

Đây là cách tôi giải quyết nó:

Dựa trên : this article

Bạn có thể tải Carbon from here

Đầu tiên mô-đun Carbon nhập khẩu như sau:

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

Kịch bản này chứa các chức năng hoạt động tốt và không có bất kỳ phụ thuộc:

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

Bên cạnh đó, đây là giải pháp cụ thể cho vấn đề của bạn:

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 
} 
Các vấn đề liên quan