DSCResources/cUserRight/cUserRight.psm1
#requires -Version 4.0 data LocalizedData { # culture="en-US" ConvertFrom-StringData -StringData @' VerboseTestTargetTrueResult = The target resource is already in the desired state. No action is required. VerboseTestTargetFalseResult = The target resource is not in the desired state. VerboseGetUserRight = Getting the user rights assigned to the principal "{0}". VerboseGrantUserRight = Granting the following user rights to the principal "{0}": "{1}". VerboseRevokeUserRight = Revoking the following user rights from the principal "{0}": "{1}". '@ } function Get-TargetResource { [CmdletBinding()] [OutputType([Hashtable])] param ( [Parameter(Mandatory = $true)] [ValidateSet( 'SeAssignPrimaryTokenPrivilege', 'SeAuditPrivilege', 'SeBackupPrivilege', 'SeBatchLogonRight', 'SeChangeNotifyPrivilege', 'SeCreateGlobalPrivilege', 'SeCreatePagefilePrivilege', 'SeCreatePermanentPrivilege', 'SeCreateSymbolicLinkPrivilege', 'SeCreateTokenPrivilege', 'SeDebugPrivilege', 'SeDenyBatchLogonRight', 'SeDenyInteractiveLogonRight', 'SeDenyNetworkLogonRight', 'SeDenyRemoteInteractiveLogonRight', 'SeDenyServiceLogonRight', 'SeEnableDelegationPrivilege', 'SeImpersonatePrivilege', 'SeIncreaseBasePriorityPrivilege', 'SeIncreaseQuotaPrivilege', 'SeIncreaseWorkingSetPrivilege', 'SeInteractiveLogonRight', 'SeLoadDriverPrivilege', 'SeLockMemoryPrivilege', 'SeMachineAccountPrivilege', 'SeManageVolumePrivilege', 'SeNetworkLogonRight', 'SeProfileSingleProcessPrivilege', 'SeRelabelPrivilege', 'SeRemoteInteractiveLogonRight', 'SeRemoteShutdownPrivilege', 'SeRestorePrivilege', 'SeSecurityPrivilege', 'SeServiceLogonRight', 'SeShutdownPrivilege', 'SeSyncAgentPrivilege', 'SeSystemEnvironmentPrivilege', 'SeSystemProfilePrivilege', 'SeSystemTimePrivilege', 'SeTakeOwnershipPrivilege', 'SeTcbPrivilege', 'SeTimeZonePrivilege', 'SeTrustedCredManAccessPrivilege', 'SeUndockPrivilege' )] [String] $Constant, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Principal ) $UserRights = [String[]]@( Get-UserRight -Principal $Principal | Select-Object -ExpandProperty UserRights ) if ($UserRights -contains $Constant) { $EnsureResult = 'Present' } else { $EnsureResult = 'Absent' } $ReturnValue = @{ Ensure = $EnsureResult Constant = $Constant Principal = $Principal } return $ReturnValue } function Test-TargetResource { [CmdletBinding()] [OutputType([Boolean])] param ( [Parameter(Mandatory = $false)] [ValidateSet('Absent', 'Present')] [String] $Ensure = 'Present', [Parameter(Mandatory = $true)] [ValidateSet( 'SeAssignPrimaryTokenPrivilege', 'SeAuditPrivilege', 'SeBackupPrivilege', 'SeBatchLogonRight', 'SeChangeNotifyPrivilege', 'SeCreateGlobalPrivilege', 'SeCreatePagefilePrivilege', 'SeCreatePermanentPrivilege', 'SeCreateSymbolicLinkPrivilege', 'SeCreateTokenPrivilege', 'SeDebugPrivilege', 'SeDenyBatchLogonRight', 'SeDenyInteractiveLogonRight', 'SeDenyNetworkLogonRight', 'SeDenyRemoteInteractiveLogonRight', 'SeDenyServiceLogonRight', 'SeEnableDelegationPrivilege', 'SeImpersonatePrivilege', 'SeIncreaseBasePriorityPrivilege', 'SeIncreaseQuotaPrivilege', 'SeIncreaseWorkingSetPrivilege', 'SeInteractiveLogonRight', 'SeLoadDriverPrivilege', 'SeLockMemoryPrivilege', 'SeMachineAccountPrivilege', 'SeManageVolumePrivilege', 'SeNetworkLogonRight', 'SeProfileSingleProcessPrivilege', 'SeRelabelPrivilege', 'SeRemoteInteractiveLogonRight', 'SeRemoteShutdownPrivilege', 'SeRestorePrivilege', 'SeSecurityPrivilege', 'SeServiceLogonRight', 'SeShutdownPrivilege', 'SeSyncAgentPrivilege', 'SeSystemEnvironmentPrivilege', 'SeSystemProfilePrivilege', 'SeSystemTimePrivilege', 'SeTakeOwnershipPrivilege', 'SeTcbPrivilege', 'SeTimeZonePrivilege', 'SeTrustedCredManAccessPrivilege', 'SeUndockPrivilege' )] [String] $Constant, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Principal ) $TargetResource = Get-TargetResource -Constant $Constant -Principal $Principal $InDesiredState = $Ensure -eq $TargetResource.Ensure if ($InDesiredState -eq $true) { Write-Verbose -Message ($LocalizedData.VerboseTestTargetTrueResult) } else { Write-Verbose -Message ($LocalizedData.VerboseTestTargetFalseResult) } return $InDesiredState } function Set-TargetResource { [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory = $false)] [ValidateSet('Absent', 'Present')] [String] $Ensure = 'Present', [Parameter(Mandatory = $true)] [ValidateSet( 'SeAssignPrimaryTokenPrivilege', 'SeAuditPrivilege', 'SeBackupPrivilege', 'SeBatchLogonRight', 'SeChangeNotifyPrivilege', 'SeCreateGlobalPrivilege', 'SeCreatePagefilePrivilege', 'SeCreatePermanentPrivilege', 'SeCreateSymbolicLinkPrivilege', 'SeCreateTokenPrivilege', 'SeDebugPrivilege', 'SeDenyBatchLogonRight', 'SeDenyInteractiveLogonRight', 'SeDenyNetworkLogonRight', 'SeDenyRemoteInteractiveLogonRight', 'SeDenyServiceLogonRight', 'SeEnableDelegationPrivilege', 'SeImpersonatePrivilege', 'SeIncreaseBasePriorityPrivilege', 'SeIncreaseQuotaPrivilege', 'SeIncreaseWorkingSetPrivilege', 'SeInteractiveLogonRight', 'SeLoadDriverPrivilege', 'SeLockMemoryPrivilege', 'SeMachineAccountPrivilege', 'SeManageVolumePrivilege', 'SeNetworkLogonRight', 'SeProfileSingleProcessPrivilege', 'SeRelabelPrivilege', 'SeRemoteInteractiveLogonRight', 'SeRemoteShutdownPrivilege', 'SeRestorePrivilege', 'SeSecurityPrivilege', 'SeServiceLogonRight', 'SeShutdownPrivilege', 'SeSyncAgentPrivilege', 'SeSystemEnvironmentPrivilege', 'SeSystemProfilePrivilege', 'SeSystemTimePrivilege', 'SeTakeOwnershipPrivilege', 'SeTcbPrivilege', 'SeTimeZonePrivilege', 'SeTrustedCredManAccessPrivilege', 'SeUndockPrivilege' )] [String] $Constant, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Principal ) if (-not $PSCmdlet.ShouldProcess($Constant)) { return } if ($Ensure -eq 'Present') { Grant-UserRight -Principal $Principal -UserRights $Constant -Verbose:$VerbosePreference } else { Revoke-UserRight -Principal $Principal -UserRights $Constant -Verbose:$VerbosePreference } } #region Helper Functions function Initialize-CustomType { if (-not ('cUserRight.Lsa' -as [Type])) { #region C# Source Code $TypeDefinition = @' using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.InteropServices; using System.Security.Principal; using System.Text; namespace cUserRight { // The AccountRights enumeration is needed to work around case-sensitivity of logon right and privilege names public enum AccountRights { SeAssignPrimaryTokenPrivilege, // Replace a process level token SeAuditPrivilege, // Generate security audits SeBackupPrivilege, // Back up files and directories SeBatchLogonRight, // Log on as a batch job SeChangeNotifyPrivilege, // Bypass traverse checking SeCreateGlobalPrivilege, // Create global objects SeCreatePagefilePrivilege, // Create a pagefile SeCreatePermanentPrivilege, // Create permanent shared objects SeCreateSymbolicLinkPrivilege, // Create symbolic links SeCreateTokenPrivilege, // Create a token object SeDebugPrivilege, // Debug programs SeDenyBatchLogonRight, // Deny log on as a batch job SeDenyInteractiveLogonRight, // Deny log on locally SeDenyNetworkLogonRight, // Deny access to this computer from the network SeDenyRemoteInteractiveLogonRight, // Deny log on through Remote Desktop Services SeDenyServiceLogonRight, // Deny log on as a service SeEnableDelegationPrivilege, // Enable computer and user accounts to be trusted for delegation SeImpersonatePrivilege, // Impersonate a client after authentication SeIncreaseBasePriorityPrivilege, // Increase scheduling priority SeIncreaseQuotaPrivilege, // Adjust memory quotas for a process SeIncreaseWorkingSetPrivilege, // Increase a process working set SeInteractiveLogonRight, // Allow log on locally SeLoadDriverPrivilege, // Load and unload device drivers SeLockMemoryPrivilege, // Lock pages in memory SeMachineAccountPrivilege, // Add workstations to domain SeManageVolumePrivilege, // Perform volume maintenance tasks SeNetworkLogonRight, // Access this computer from the network SeProfileSingleProcessPrivilege, // Profile single process SeRelabelPrivilege, // Modify an object label SeRemoteInteractiveLogonRight, // Allow log on through Remote Desktop Services SeRemoteShutdownPrivilege, // Force shutdown from a remote system SeRestorePrivilege, // Restore files and directories SeSecurityPrivilege, // Manage auditing and security log SeServiceLogonRight, // Log on as a service SeShutdownPrivilege, // Shut down the system SeSyncAgentPrivilege, // Synchronize directory service data SeSystemEnvironmentPrivilege, // Modify firmware environment values SeSystemProfilePrivilege, // Profile system performance SeSystemTimePrivilege, // Change the system time SeTakeOwnershipPrivilege, // Take ownership of files or other objects SeTcbPrivilege, // Act as part of the operating system SeTimeZonePrivilege, // Change the time zone SeTrustedCredManAccessPrivilege, // Access Credential Manager as a trusted caller SeUndockPrivilege, // Remove computer from docking station } public class Lsa { // ACCESS_MASK for Policy Objects // https://msdn.microsoft.com/en-us/library/cc234246.aspx [Flags] public enum LsaPolicyAccessRights : uint { POLICY_VIEW_LOCAL_INFORMATION = 0x00000001, POLICY_VIEW_AUDIT_INFORMATION = 0x00000002, POLICY_GET_PRIVATE_INFORMATION = 0x00000004, POLICY_TRUST_ADMIN = 0x00000008, POLICY_CREATE_ACCOUNT = 0x00000010, POLICY_CREATE_SECRET = 0x00000020, POLICY_CREATE_PRIVILEGE = 0x00000040, POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080, POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100, POLICY_AUDIT_LOG_ADMIN = 0x00000200, POLICY_SERVER_ADMIN = 0x00000400, POLICY_LOOKUP_NAMES = 0x00000800, POLICY_NOTIFICATION = 0x00001000, POLICY_ALL_ACCESS = POLICY_VIEW_LOCAL_INFORMATION | POLICY_VIEW_AUDIT_INFORMATION | POLICY_GET_PRIVATE_INFORMATION | POLICY_TRUST_ADMIN | POLICY_CREATE_ACCOUNT | POLICY_CREATE_SECRET | POLICY_CREATE_PRIVILEGE | POLICY_SET_DEFAULT_QUOTA_LIMITS | POLICY_SET_AUDIT_REQUIREMENTS | POLICY_AUDIT_LOG_ADMIN | POLICY_SERVER_ADMIN | POLICY_LOOKUP_NAMES | POLICY_NOTIFICATION } [StructLayout(LayoutKind.Sequential)] internal struct LSA_UNICODE_STRING { internal ushort Length; internal ushort MaximumLength; internal IntPtr Buffer; } [StructLayout(LayoutKind.Sequential)] internal struct LSA_OBJECT_ATTRIBUTES { internal uint Length; internal IntPtr RootDirectory; internal IntPtr ObjectName; internal uint Attributes; internal IntPtr SecurityDescriptor; internal IntPtr SecurityQualityOfService; } // LSA Policy NTSTATUS return codes // https://msdn.microsoft.com/en-us/library/windows/desktop/ms721859%28v=vs.85%29.aspx#lsa_policy_function_return_values // https://msdn.microsoft.com/en-us/library/cc704588.aspx internal const uint STATUS_SUCCESS = 0x00000000; internal const uint STATUS_ACCESS_DENIED = 0xC0000022; internal const uint STATUS_INSUFFICIENT_RESOURCES = 0xC000009A; internal const uint STATUS_INTERNAL_DB_ERROR = 0xC0000158; internal const uint STATUS_INVALID_HANDLE = 0xC0000008; internal const uint STATUS_INVALID_SERVER_STATE = 0xC00000DC; internal const uint STATUS_INVALID_PARAMETER = 0xC000000D; internal const uint STATUS_NO_SUCH_PRIVILEGE = 0xC0000060; internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; internal const uint STATUS_UNSUCCESSFUL = 0xC0000001; private static readonly Dictionary<uint, string> LsaNtStatusMessages = new Dictionary<uint, string> { {STATUS_SUCCESS, "The operation completed successfully."}, {STATUS_ACCESS_DENIED, "Access is denied."}, {STATUS_INSUFFICIENT_RESOURCES, "There are not enough system resources to complete the call."}, {STATUS_INTERNAL_DB_ERROR, "The LSA database contains an internal inconsistency."}, {STATUS_INVALID_HANDLE, "An object or RPC handle is not valid."}, {STATUS_INVALID_SERVER_STATE, "The LSA server is currently disabled."}, {STATUS_INVALID_PARAMETER, "One of the parameters is not valid."}, {STATUS_NO_SUCH_PRIVILEGE, "A specified privilege does not exist."}, {STATUS_OBJECT_NAME_NOT_FOUND, "An object in the LSA policy database was not found."}, {STATUS_UNSUCCESSFUL, "The requested operation was unsuccessful."} }; private static void HandleLsaNtStatus(uint ntStatusCode) { if (ntStatusCode == STATUS_SUCCESS) { return; } var winErrorCode = (int)(LsaNtStatusToWinError(ntStatusCode)); if (LsaNtStatusMessages.ContainsKey(ntStatusCode)) { throw new Win32Exception(winErrorCode, LsaNtStatusMessages[ntStatusCode]); } throw new Win32Exception(winErrorCode); } private static LSA_UNICODE_STRING ConvertToLsaString(string inputString) { if (inputString.Length > 0x7ffe) { throw new ArgumentOutOfRangeException(); }; LSA_UNICODE_STRING lsaString = new LSA_UNICODE_STRING(); if (inputString != null) { lsaString.Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize); lsaString.MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize); lsaString.Buffer = Marshal.StringToHGlobalAuto(inputString); } return lsaString; } private static IntPtr GetLsaPolicyHandle() { var systemName = new LSA_UNICODE_STRING(); var objectAttributes = new LSA_OBJECT_ATTRIBUTES { Length = 0, RootDirectory = IntPtr.Zero, ObjectName = IntPtr.Zero, Attributes = 0, SecurityDescriptor = IntPtr.Zero, SecurityQualityOfService = IntPtr.Zero }; IntPtr lsaPolicyHandle; var ntStatus = LsaOpenPolicy(ref systemName, ref objectAttributes, (uint)(LsaPolicyAccessRights.POLICY_ALL_ACCESS), out lsaPolicyHandle); HandleLsaNtStatus(ntStatus); return lsaPolicyHandle; } private static IntPtr GetSidPointer(string accountName) { var ntAccount = new NTAccount(accountName); var sid = (SecurityIdentifier)ntAccount.Translate(typeof(SecurityIdentifier)); var sidBytes = new byte[sid.BinaryLength]; sid.GetBinaryForm(sidBytes, 0); var sidPtr = Marshal.AllocHGlobal(sidBytes.Length); Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length); return sidPtr; } public static string[] EnumerateAccountRights(string accountName) { var lsaPolicyHandle = GetLsaPolicyHandle(); var sidPtr = GetSidPointer(accountName); var lsaUserRights = IntPtr.Zero; uint countOfRights; try { var ntStatus = LsaEnumerateAccountRights(lsaPolicyHandle, sidPtr, out lsaUserRights, out countOfRights); if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) { return new string[0]; } HandleLsaNtStatus(ntStatus); LSA_UNICODE_STRING lsaUserRight; var userRights = new List<string>(); long pointerValue = lsaUserRights.ToInt64(); for (int i = 0; i < countOfRights; i++) { lsaUserRight = (LSA_UNICODE_STRING)Marshal.PtrToStructure(new IntPtr(pointerValue), typeof(LSA_UNICODE_STRING)); string userRight = Marshal.PtrToStringAuto(lsaUserRight.Buffer); userRights.Add(userRight); pointerValue += Marshal.SizeOf(lsaUserRight); } return userRights.ToArray(); } finally { Marshal.FreeHGlobal(sidPtr); var ntStatus = LsaClose(lsaPolicyHandle); HandleLsaNtStatus(ntStatus); } } public static void AddAccountRights(string accountName, AccountRights[] accountRights) { var lsaPolicyHandle = GetLsaPolicyHandle(); var sidPtr = GetSidPointer(accountName); try { var lsaAccountRights = new LSA_UNICODE_STRING[accountRights.Length]; for (int i = 0; i < accountRights.Length; ++i) { lsaAccountRights[i] = ConvertToLsaString(accountRights[i].ToString()); } var ntStatus = LsaAddAccountRights(lsaPolicyHandle, sidPtr, lsaAccountRights, (uint)lsaAccountRights.Length); HandleLsaNtStatus(ntStatus); } finally { Marshal.FreeHGlobal(sidPtr); var ntStatus = LsaClose(lsaPolicyHandle); HandleLsaNtStatus(ntStatus); } } public static void RemoveAccountRights(string accountName, AccountRights?[] accountRights, bool allRights = false) { var lsaPolicyHandle = GetLsaPolicyHandle(); var sidPtr = GetSidPointer(accountName); try { var lsaAccountRightsList = new List<LSA_UNICODE_STRING>(); if (accountRights != null) { for (int i = 0; i < accountRights.Length; ++i) { var lsaAccountRight = ConvertToLsaString(accountRights[i].ToString()); lsaAccountRightsList.Add(lsaAccountRight); } } LSA_UNICODE_STRING[] lsaAccountRights = lsaAccountRightsList.ToArray(); var ntStatus = LsaRemoveAccountRights(lsaPolicyHandle, sidPtr, allRights, lsaAccountRights, (uint)lsaAccountRights.Length); // The user does not have any logon rights or privileges if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) { return; } HandleLsaNtStatus(ntStatus); } finally { Marshal.FreeHGlobal(sidPtr); var ntStatus = LsaClose(lsaPolicyHandle); HandleLsaNtStatus(ntStatus); } } #region P/Invoke Definitions // The LsaAddAccountRights function assigns one or more privileges to an account [DllImport("advapi32.dll", SetLastError = true)] private static extern uint LsaAddAccountRights( IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, uint CountOfRights ); // The LsaClose function closes a handle to the Policy object [DllImport("advapi32.dll", SetLastError = false)] private static extern uint LsaClose(IntPtr ObjectHandle); // The LsaEnumerateAccountRights function enumerates the privileges assigned to an account [DllImport("advapi32.dll", SetLastError = true)] private static extern uint LsaEnumerateAccountRights( IntPtr PolicyHandle, IntPtr AccountSid, out IntPtr UserRights, out uint CountOfRights ); // The LsaNtStatusToWinError function converts an NTSTATUS code returned by an LSA function to a Windows error code [DllImport("advapi32.dll", SetLastError = false)] private static extern uint LsaNtStatusToWinError(uint status); // The LsaOpenPolicy function opens a handle to the Policy object. [DllImport("advapi32.dll", SetLastError = true)] private static extern uint LsaOpenPolicy( ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, uint DesiredAccess, out IntPtr PolicyHandle ); // The LsaRemoveAccountRights function removes one or more privileges from an account [DllImport("advapi32.dll", SetLastError = true)] private static extern uint LsaRemoveAccountRights( IntPtr PolicyHandle, IntPtr AccountSid, [MarshalAs(UnmanagedType.U1)] Boolean AllRights, LSA_UNICODE_STRING[] UserRights, uint CountOfRights ); #endregion } } '@ #endregion Add-Type -TypeDefinition $TypeDefinition -Language CSharp -ErrorAction Stop } } function Get-UserRight { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Principal ) Initialize-CustomType Write-Verbose -Message ($LocalizedData.VerboseGetUserRight -f $Principal) $OutputObject = [PSCustomObject]@{ Principal = $Principal UserRights = [String[]]@( [cUserRight.Lsa]::EnumerateAccountRights($Principal) ) } return $OutputObject } function Grant-UserRight { [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Principal, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String[]] $UserRights ) Initialize-CustomType $VerboseMessage = $LocalizedData.VerboseGrantUserRight -f $Principal, ($UserRights -join '", "') if ($PSCmdlet.ShouldProcess($VerboseMessage, $null, $null)) { [cUserRight.Lsa]::AddAccountRights($Principal, $UserRights) } } function Revoke-UserRight { [CmdletBinding(SupportsShouldProcess = $true)] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Principal, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String[]] $UserRights ) Initialize-CustomType $VerboseMessage = $LocalizedData.VerboseRevokeUserRight -f $Principal, ($UserRights -join '", "') if ($PSCmdlet.ShouldProcess($VerboseMessage, $null, $null)) { [cUserRight.Lsa]::RemoveAccountRights($Principal, $UserRights) } } #endregion |