├── .gitignore ├── Tests ├── Integration │ ├── cUserRight.Config.ps1 │ └── cUserRight.Integration.Tests.ps1 └── Unit │ └── cUserRight.Tests.ps1 ├── Examples └── Sample_cUserRight.ps1 ├── cUserRightsAssignment.psd1 ├── LICENSE ├── README.md ├── appveyor.yml └── DSCResources └── cUserRight ├── cUserRight.schema.mof └── cUserRight.psm1 /.gitignore: -------------------------------------------------------------------------------- 1 | DSCResource.Tests 2 | -------------------------------------------------------------------------------- /Tests/Integration/cUserRight.Config.ps1: -------------------------------------------------------------------------------- 1 | $TestParameters = [PSCustomObject]@{ 2 | Constant = 'SeBatchLogonRight' 3 | Principal = 'BUILTIN\Power Users' 4 | } 5 | 6 | Configuration cUserRight_Present 7 | { 8 | Import-DscResource -ModuleName cUserRightsAssignment 9 | 10 | Node localhost 11 | { 12 | cUserRight TestPresent 13 | { 14 | Ensure = 'Present' 15 | Constant = $TestParameters.Constant 16 | Principal = $TestParameters.Principal 17 | } 18 | } 19 | } 20 | 21 | Configuration cUserRight_Absent 22 | { 23 | Import-DscResource -ModuleName cUserRightsAssignment 24 | 25 | Node localhost 26 | { 27 | cUserRight TestAbsent 28 | { 29 | Ensure = 'Absent' 30 | Constant = $TestParameters.Constant 31 | Principal = $TestParameters.Principal 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Examples/Sample_cUserRight.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Assign logon rights. 4 | .DESCRIPTION 5 | This example shows how to use the cUserRight DSC resource to assign logon rights. 6 | #> 7 | 8 | Configuration Sample_cUserRight 9 | { 10 | Import-DscResource -ModuleName cUserRightsAssignment 11 | 12 | # Ensure the 'Log on as a service' logon right is assigned to the local 'Power Users' group. 13 | cUserRight GrantServiceLogonRight 14 | { 15 | Ensure = 'Present' 16 | Constant = 'SeServiceLogonRight' 17 | Principal = 'BUILTIN\Power Users' 18 | } 19 | 20 | # Ensure the 'Log on as a batch job' logon right is not assigned to the local 'Power Users' group. 21 | cUserRight RevokeBatchLogonRight 22 | { 23 | Ensure = 'Absent' 24 | Constant = 'SeBatchLogonRight' 25 | Principal = 'BUILTIN\Power Users' 26 | } 27 | } 28 | 29 | $OutputPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'Sample_cUserRight' 30 | Sample_cUserRight -OutputPath $OutputPath 31 | Start-DscConfiguration -Path $OutputPath -Force -Verbose -Wait 32 | -------------------------------------------------------------------------------- /cUserRightsAssignment.psd1: -------------------------------------------------------------------------------- 1 | <# 2 | Module manifest for the 'cUserRightsAssignment' DSC resource module. 3 | Generated by Serge Nikalaichyk. 4 | #> 5 | 6 | @{ 7 | ModuleVersion = '1.0.2' 8 | GUID = 'a0e73619-0077-46fb-8c5e-5fb2f282a653' 9 | Author = 'Serge Nikalaichyk' 10 | Copyright = '(c) 2016 Serge Nikalaichyk. All rights reserved.' 11 | Description = 'The cUserRightsAssignment module contains the cUserRight DSC resource that provides a mechanism to manage user rights: logon rights and privileges.' 12 | PowerShellVersion = '4.0' 13 | CLRVersion = '4.0' 14 | FunctionsToExport = '*' 15 | CmdletsToExport = '*' 16 | VariablesToExport = '*' 17 | AliasesToExport = '*' 18 | PrivateData = @{ 19 | PSData = @{ 20 | Tags = @('AccessControl', 'DesiredStateConfiguration', 'DSC', 'LogonRight', 'Privilege', 'PSModule', 'UserRight', 'UserRightsAssignment') 21 | LicenseUri = 'https://github.com/SNikalaichyk/cUserRightsAssignment/blob/master/LICENSE' 22 | ProjectUri = 'https://github.com/SNikalaichyk/cUserRightsAssignment' 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Serge Nikalaichyk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/wd1lvxj75hrvbfp7?svg=true)](https://ci.appveyor.com/project/SNikalaichyk/cuserrightsassignment) 2 | 3 | # cUserRightsAssignment 4 | The **cUserRightsAssignment** module contains the **cUserRight** DSC resource that provides a mechanism to manage user rights: logon rights and privileges. 5 | 6 | You can also download this module from the [PowerShell Gallery](https://www.powershellgallery.com/packages/cUserRightsAssignment). 7 | 8 | ## Resources 9 | 10 | ### cUserRight 11 | 12 | The **cUserRight** DSC resource provides a mechanism to manage user rights: logon rights and privileges. 13 | 14 | * **Ensure**: Indicates if the user right is assigned. Set this property to `Absent` to ensure that the user right is not assigned. 15 | Setting it to `Present` (the default value) ensures that the user right is assigned. 16 | * **Constant**: Indicates the constant name that is associated with a user right. 17 | For the list of available constants, see [User Rights Assignment](https://technet.microsoft.com/en-us/library/dn221963.aspx). 18 | * **Principal**: Indicates the identity of the principal. Valid formats are: 19 | * [Down-Level Logon Name](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380525%28v=vs.85%29.aspx#down_level_logon_name) 20 | * [Security Accounts Manager (SAM) Account Name (sAMAccountName)](https://msdn.microsoft.com/en-us/library/windows/desktop/ms679635%28v=vs.85%29.aspx) 21 | * [User Principal Name (UPN)](https://msdn.microsoft.com/en-us/library/windows/desktop/aa380525%28v=vs.85%29.aspx#user_principal_name) 22 | 23 | ## Versions 24 | 25 | ### 1.0.2 (February 19, 2016) 26 | 27 | * General improvements. 28 | 29 | ### 1.0.1 (February 2, 2016) 30 | 31 | * General improvements. 32 | 33 | ### 1.0.0 (January 18, 2016) 34 | 35 | * Initial release with the following DSC resources: 36 | * **cUserRight** 37 | 38 | ## Examples 39 | 40 | ### Assign logon rights 41 | 42 | This example shows how to use the **cUserRight** DSC resource to assign logon rights. 43 | 44 | ```powershell 45 | 46 | Configuration Sample_cUserRight 47 | { 48 | Import-DscResource -ModuleName cUserRightsAssignment 49 | 50 | # Ensure the 'Log on as a service' logon right is assigned to the local 'Power Users' group. 51 | cUserRight GrantServiceLogonRight 52 | { 53 | Ensure = 'Present' 54 | Constant = 'SeServiceLogonRight' 55 | Principal = 'BUILTIN\Power Users' 56 | } 57 | 58 | # Ensure the 'Log on as a batch job' logon right is not assigned to the local 'Power Users' group. 59 | cUserRight RevokeBatchLogonRight 60 | { 61 | Ensure = 'Absent' 62 | Constant = 'SeBatchLogonRight' 63 | Principal = 'BUILTIN\Power Users' 64 | } 65 | } 66 | 67 | $OutputPath = Join-Path -Path ([System.IO.Path]::GetTempPath()) -ChildPath 'Sample_cUserRight' 68 | Sample_cUserRight -OutputPath $OutputPath 69 | Start-DscConfiguration -Path $OutputPath -Force -Verbose -Wait 70 | 71 | ``` 72 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | #---------------------------------# 2 | # environment configuration # 3 | #---------------------------------# 4 | 5 | os: WMF 5 6 | version: 1.0.2.{build} 7 | install: 8 | - cinst -y pester 9 | - git clone https://github.com/PowerShell/DscResource.Tests 10 | - ps: Push-Location 11 | - cd DscResource.Tests 12 | - ps: Import-Module -Name '.\TestHelper.psm1' -Force 13 | - ps: Pop-Location 14 | - ps: Get-PackageProvider -Name NuGet -ForceBootstrap -Force 15 | 16 | #---------------------------------# 17 | # build configuration # 18 | #---------------------------------# 19 | 20 | build: false 21 | 22 | #---------------------------------# 23 | # test configuration # 24 | #---------------------------------# 25 | 26 | test_script: 27 | - ps: | 28 | $TestResultsFilePath = '.\TestsResults.xml' 29 | $TestResults = Invoke-Pester -OutputFormat NUnitXml -OutputFile $TestResultsFilePath -PassThru 30 | (New-Object -TypeName System.Net.WebClient).UploadFile( 31 | "https://ci.appveyor.com/api/testresults/nunit/$($env:APPVEYOR_JOB_ID)", 32 | (Resolve-Path -Path $TestResultsFilePath)) 33 | if ($TestResults.FailedCount -gt 0) {throw "$($TestResults.FailedCount) tests failed."} 34 | 35 | #---------------------------------# 36 | # deployment configuration # 37 | #---------------------------------# 38 | 39 | deploy_script: 40 | - ps: | 41 | $ManifestFileName = 'cUserRightsAssignment.psd1' 42 | $ManifestFilePath = Join-Path -Path $PWD -ChildPath $ManifestFileName 43 | $StagingDirectoryPath = (Resolve-Path -Path '..').Path 44 | 45 | # Replace module version in the manifest file 46 | (Get-Content -Path $ManifestFilePath) -replace "(ModuleVersion\s*?=\s*?['|`"])(.*?)(['|`"])", ('${1}' + $env:APPVEYOR_BUILD_VERSION + '${3}') | 47 | Set-Content -Path $ManifestFilePath 48 | 49 | # Load module manifest 50 | $Manifest = Invoke-Expression -Command (Get-Content -Path $ManifestFilePath | Out-String) 51 | 52 | # Create project artifact 53 | $ZipFilePath = Join-Path -Path $StagingDirectoryPath -ChildPath "$(Split-Path -Path $PWD -Leaf).zip" 54 | Add-Type -AssemblyName System.IO.Compression.FileSystem 55 | [System.IO.Compression.ZipFile]::CreateFromDirectory($PWD, $ZipFilePath) 56 | 57 | # Create NuGet package artifact 58 | $NuspecSplat = @{ 59 | packageName = $env:APPVEYOR_PROJECT_NAME 60 | version = $env:APPVEYOR_BUILD_VERSION 61 | author = $Manifest.Author 62 | owners = $Manifest.Author 63 | licenseUrl = $Manifest.PrivateData.PSData.LicenseUri 64 | projectUrl = $Manifest.PrivateData.PSData.ProjectUri 65 | packageDescription = $env:APPVEYOR_PROJECT_NAME 66 | tags = (($Manifest.PrivateData.PSData.Tags) -join ' ') 67 | destinationPath = '.' 68 | } 69 | 70 | New-Nuspec @NuspecSplat 71 | nuget pack ".\$($env:APPVEYOR_PROJECT_NAME).nuspec" -OutputDirectory '.' 72 | $NuGetPackageName = "$($env:APPVEYOR_PROJECT_NAME).$($env:APPVEYOR_BUILD_VERSION).nupkg" 73 | $NuGetPackagePath = (Get-Item -Path $NuGetPackageName).FullName 74 | 75 | # Push artifacts 76 | @( 77 | $ZipFilePath 78 | $NuGetPackagePath 79 | ) | 80 | ForEach-Object -Process { 81 | Write-Verbose -Message "Pushing package '$($_)' to AppVeyor artifacts." -Verbose 82 | Push-AppVeyorArtifact -Path $_ 83 | } 84 | -------------------------------------------------------------------------------- /Tests/Integration/cUserRight.Integration.Tests.ps1: -------------------------------------------------------------------------------- 1 | #requires -Version 4.0 -Modules Pester 2 | 3 | $Global:DSCModuleName = 'cUserRightsAssignment' 4 | $Global:DSCResourceName = 'cUserRight' 5 | 6 | #region Header 7 | 8 | $ModuleRoot = Split-Path -Path $Script:MyInvocation.MyCommand.Path -Parent | Split-Path -Parent | Split-Path -Parent 9 | 10 | if ( 11 | (-not (Test-Path -Path (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests') -PathType Container)) -or 12 | (-not (Test-Path -Path (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -PathType Leaf)) 13 | ) 14 | { 15 | & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests')) 16 | } 17 | else 18 | { 19 | & git @('-C', (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests'), 'pull') 20 | } 21 | 22 | Import-Module -Name (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force 23 | 24 | $TestEnvironment = Initialize-TestEnvironment -DSCModuleName $Global:DSCModuleName -DSCResourceName $Global:DSCResourceName -TestType Integration 25 | 26 | #endregion 27 | 28 | # Begin Testing 29 | try 30 | { 31 | #region Integration Tests 32 | 33 | $ConfigFile = Join-Path -Path $PSScriptRoot -ChildPath "$($Global:DSCResourceName).Config.ps1" 34 | . $ConfigFile 35 | 36 | Describe "$($Global:DSCResourceName)_Integration - Ensure is set to Present" { 37 | 38 | $ConfigurationName = 'cUserRight_Present' 39 | 40 | #region Default Tests 41 | 42 | It 'Should compile without throwing' { 43 | { 44 | Invoke-Expression -Command ('{0} -OutputPath "{1}"' -f $ConfigurationName, $TestEnvironment.WorkingFolder) 45 | Start-DscConfiguration -Path $TestEnvironment.WorkingFolder -ComputerName localhost -Wait -Verbose -Force 46 | } | Should Not Throw 47 | } 48 | 49 | It 'Should be able to call Get-DscConfiguration without throwing' { 50 | { 51 | Get-DscConfiguration -Verbose -ErrorAction Stop 52 | } | Should Not Throw 53 | } 54 | 55 | #endregion 56 | 57 | It 'Should have set the resource and all the parameters should match' { 58 | $Current = Get-DscConfiguration | Where-Object {$_.ConfigurationName -eq $ConfigurationName} 59 | $Current.Ensure | Should Be 'Present' 60 | $Current.Constant | Should Be $TestParameters.Constant 61 | $Current.Principal | Should Be $TestParameters.Principal 62 | } 63 | 64 | } 65 | 66 | Describe "$($Global:DSCResourceName)_Integration - Ensure is set to Absent" { 67 | 68 | $ConfigurationName = 'cUserRight_Absent' 69 | 70 | #region Default Tests 71 | 72 | It 'Should compile without throwing' { 73 | { 74 | Invoke-Expression -Command ('{0} -OutputPath "{1}"' -f $ConfigurationName, $TestEnvironment.WorkingFolder) 75 | Start-DscConfiguration -Path $TestEnvironment.WorkingFolder -ComputerName localhost -Wait -Verbose -Force 76 | } | Should Not Throw 77 | } 78 | 79 | It 'Should be able to call Get-DscConfiguration without throwing' { 80 | { 81 | Get-DscConfiguration -Verbose -ErrorAction Stop 82 | } | Should Not Throw 83 | } 84 | 85 | #endregion 86 | 87 | It 'Should have set the resource and all the parameters should match' { 88 | $Current = Get-DscConfiguration | Where-Object {$_.ConfigurationName -eq $ConfigurationName} 89 | $Current.Ensure | Should Be 'Absent' 90 | $Current.Constant | Should Be $TestParameters.Constant 91 | $Current.Principal | Should Be $TestParameters.Principal 92 | } 93 | 94 | } 95 | 96 | #endregion 97 | } 98 | finally 99 | { 100 | #region Footer 101 | 102 | Restore-TestEnvironment -TestEnvironment $TestEnvironment 103 | 104 | #endregion 105 | } 106 | -------------------------------------------------------------------------------- /DSCResources/cUserRight/cUserRight.schema.mof: -------------------------------------------------------------------------------- 1 | [ClassVersion("1.0.0.0"), FriendlyName("cUserRight")] 2 | class cUserRight : OMI_BaseResource 3 | { 4 | [Write, Description("Indicates if the user right is assigned."), ValueMap{"Absent","Present"}, Values{"Absent","Present"}] String Ensure; 5 | [ 6 | Key, 7 | Description("Indicates the constant name that is associated with a user right."), 8 | ValueMap{ 9 | "SeAssignPrimaryTokenPrivilege", 10 | "SeAuditPrivilege", 11 | "SeBackupPrivilege", 12 | "SeBatchLogonRight", 13 | "SeChangeNotifyPrivilege", 14 | "SeCreateGlobalPrivilege", 15 | "SeCreatePagefilePrivilege", 16 | "SeCreatePermanentPrivilege", 17 | "SeCreateSymbolicLinkPrivilege", 18 | "SeCreateTokenPrivilege", 19 | "SeDebugPrivilege", 20 | "SeDenyBatchLogonRight", 21 | "SeDenyInteractiveLogonRight", 22 | "SeDenyNetworkLogonRight", 23 | "SeDenyRemoteInteractiveLogonRight", 24 | "SeDenyServiceLogonRight", 25 | "SeEnableDelegationPrivilege", 26 | "SeImpersonatePrivilege", 27 | "SeIncreaseBasePriorityPrivilege", 28 | "SeIncreaseQuotaPrivilege", 29 | "SeIncreaseWorkingSetPrivilege", 30 | "SeInteractiveLogonRight", 31 | "SeLoadDriverPrivilege", 32 | "SeLockMemoryPrivilege", 33 | "SeMachineAccountPrivilege", 34 | "SeManageVolumePrivilege", 35 | "SeNetworkLogonRight", 36 | "SeProfileSingleProcessPrivilege", 37 | "SeRelabelPrivilege", 38 | "SeRemoteInteractiveLogonRight", 39 | "SeRemoteShutdownPrivilege", 40 | "SeRestorePrivilege", 41 | "SeSecurityPrivilege", 42 | "SeServiceLogonRight", 43 | "SeShutdownPrivilege", 44 | "SeSyncAgentPrivilege", 45 | "SeSystemEnvironmentPrivilege", 46 | "SeSystemProfilePrivilege", 47 | "SeSystemTimePrivilege", 48 | "SeTakeOwnershipPrivilege", 49 | "SeTcbPrivilege", 50 | "SeTimeZonePrivilege", 51 | "SeTrustedCredManAccessPrivilege", 52 | "SeUndockPrivilege" 53 | }, 54 | Values{ 55 | "SeAssignPrimaryTokenPrivilege", 56 | "SeAuditPrivilege", 57 | "SeBackupPrivilege", 58 | "SeBatchLogonRight", 59 | "SeChangeNotifyPrivilege", 60 | "SeCreateGlobalPrivilege", 61 | "SeCreatePagefilePrivilege", 62 | "SeCreatePermanentPrivilege", 63 | "SeCreateSymbolicLinkPrivilege", 64 | "SeCreateTokenPrivilege", 65 | "SeDebugPrivilege", 66 | "SeDenyBatchLogonRight", 67 | "SeDenyInteractiveLogonRight", 68 | "SeDenyNetworkLogonRight", 69 | "SeDenyRemoteInteractiveLogonRight", 70 | "SeDenyServiceLogonRight", 71 | "SeEnableDelegationPrivilege", 72 | "SeImpersonatePrivilege", 73 | "SeIncreaseBasePriorityPrivilege", 74 | "SeIncreaseQuotaPrivilege", 75 | "SeIncreaseWorkingSetPrivilege", 76 | "SeInteractiveLogonRight", 77 | "SeLoadDriverPrivilege", 78 | "SeLockMemoryPrivilege", 79 | "SeMachineAccountPrivilege", 80 | "SeManageVolumePrivilege", 81 | "SeNetworkLogonRight", 82 | "SeProfileSingleProcessPrivilege", 83 | "SeRelabelPrivilege", 84 | "SeRemoteInteractiveLogonRight", 85 | "SeRemoteShutdownPrivilege", 86 | "SeRestorePrivilege", 87 | "SeSecurityPrivilege", 88 | "SeServiceLogonRight", 89 | "SeShutdownPrivilege", 90 | "SeSyncAgentPrivilege", 91 | "SeSystemEnvironmentPrivilege", 92 | "SeSystemProfilePrivilege", 93 | "SeSystemTimePrivilege", 94 | "SeTakeOwnershipPrivilege", 95 | "SeTcbPrivilege", 96 | "SeTimeZonePrivilege", 97 | "SeTrustedCredManAccessPrivilege", 98 | "SeUndockPrivilege" 99 | } 100 | ] String Constant; 101 | [Key, Description("Indicates the identity of the principal.")] String Principal; 102 | }; 103 | -------------------------------------------------------------------------------- /Tests/Unit/cUserRight.Tests.ps1: -------------------------------------------------------------------------------- 1 | #requires -Version 4.0 -Modules Pester 2 | 3 | $Global:DSCModuleName = 'cUserRightsAssignment' 4 | $Global:DSCResourceName = 'cUserRight' 5 | 6 | #region Header 7 | 8 | $ModuleRoot = Split-Path -Path $Script:MyInvocation.MyCommand.Path -Parent | Split-Path -Parent | Split-Path -Parent 9 | 10 | if ( 11 | (-not (Test-Path -Path (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests') -PathType Container)) -or 12 | (-not (Test-Path -Path (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -PathType Leaf)) 13 | ) 14 | { 15 | & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests')) 16 | } 17 | else 18 | { 19 | & git @('-C', (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests'), 'pull') 20 | } 21 | 22 | Import-Module -Name (Join-Path -Path $ModuleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force 23 | 24 | $TestEnvironment = Initialize-TestEnvironment -DSCModuleName $Global:DSCModuleName -DSCResourceName $Global:DSCResourceName -TestType Unit 25 | 26 | #endregion 27 | 28 | # Begin Testing 29 | try 30 | { 31 | #region Unit Tests 32 | 33 | InModuleScope $Global:DSCResourceName { 34 | 35 | $TestParameters = [PSCustomObject]@{ 36 | Constant = 'SeBatchLogonRight' 37 | Principal = 'CONTOSO\John_Doe' 38 | } 39 | 40 | Describe "$Global:DSCResourceName\Get-TargetResource" { 41 | 42 | Context 'User right is granted' { 43 | 44 | Mock -CommandName Get-UserRight -MockWith { 45 | [PSCustomObject]@{ 46 | Principal = $TestParameters.Principal 47 | UserRights = [String[]]@($TestParameters.Constant) 48 | } 49 | } 50 | 51 | $Result = Get-TargetResource -Constant $TestParameters.Constant -Principal $TestParameters.Principal 52 | 53 | It 'Should call the Get-UserRight helper function once' { 54 | Assert-MockCalled -CommandName Get-UserRight -Exactly 1 55 | } 56 | 57 | It 'Should return Ensure set to Present' { 58 | $Result.Ensure | Should Be 'Present' 59 | } 60 | 61 | It 'Should return Constant' { 62 | $Result.Constant | Should Be $TestParameters.Constant 63 | } 64 | 65 | It 'Should return Principal' { 66 | $Result.Principal | Should Be $TestParameters.Principal 67 | } 68 | 69 | } 70 | 71 | Context 'User right is not granted' { 72 | 73 | Mock -CommandName Get-UserRight -MockWith { 74 | [PSCustomObject]@{ 75 | Principal = $TestParameters.Principal 76 | UserRights = [String[]]@() 77 | } 78 | } 79 | 80 | $Result = Get-TargetResource -Constant $TestParameters.Constant -Principal $TestParameters.Principal 81 | 82 | It 'Should call the Get-UserRight helper function once' { 83 | Assert-MockCalled -CommandName Get-UserRight -Exactly 1 84 | } 85 | 86 | It 'Should return Ensure set to Absent' { 87 | $Result.Ensure | Should Be 'Absent' 88 | } 89 | 90 | It 'Should return Constant' { 91 | $Result.Constant | Should Be $TestParameters.Constant 92 | } 93 | 94 | It 'Should return Principal' { 95 | $Result.Principal | Should Be $TestParameters.Principal 96 | } 97 | 98 | } 99 | 100 | } 101 | 102 | Describe "$Global:DSCResourceName\Test-TargetResource" { 103 | 104 | Context 'Ensure is set to Absent and user right is granted' { 105 | 106 | Mock -CommandName Get-UserRight -MockWith { 107 | [PSCustomObject]@{ 108 | Principal = $TestParameters.Principal 109 | UserRights = [String[]]@($TestParameters.Constant) 110 | } 111 | } 112 | 113 | $Result = Test-TargetResource -Ensure 'Absent' -Constant $TestParameters.Constant -Principal $TestParameters.Principal 114 | 115 | It 'Should return False' { 116 | $Result | Should Be $false 117 | } 118 | 119 | } 120 | 121 | Context 'Ensure is set to Absent and user right is not granted' { 122 | 123 | Mock -CommandName Get-UserRight -MockWith { 124 | [PSCustomObject]@{ 125 | Principal = $TestParameters.Principal 126 | UserRights = [String[]]@() 127 | } 128 | } 129 | 130 | $Result = Test-TargetResource -Ensure 'Absent' -Constant $TestParameters.Constant -Principal $TestParameters.Principal 131 | 132 | It 'Should return True' { 133 | $Result | Should Be $true 134 | } 135 | 136 | } 137 | 138 | Context 'Ensure is set to Present and user right is granted' { 139 | 140 | Mock -CommandName Get-UserRight -MockWith { 141 | [PSCustomObject]@{ 142 | Principal = $TestParameters.Principal 143 | UserRights = [String[]]@($TestParameters.Constant) 144 | } 145 | } 146 | 147 | $Result = Test-TargetResource -Ensure 'Present' -Constant $TestParameters.Constant -Principal $TestParameters.Principal 148 | 149 | It 'Should return True' { 150 | $Result | Should Be $true 151 | } 152 | 153 | } 154 | 155 | Context 'Ensure is set to Present and user right is not granted' { 156 | 157 | Mock -CommandName Get-UserRight -MockWith { 158 | [PSCustomObject]@{ 159 | Principal = $TestParameters.Principal 160 | UserRights = [String[]]@() 161 | } 162 | } 163 | 164 | $Result = Test-TargetResource -Ensure 'Present' -Constant $TestParameters.Constant -Principal $TestParameters.Principal 165 | 166 | It 'Should return False' { 167 | $Result | Should Be $false 168 | } 169 | 170 | } 171 | 172 | } 173 | 174 | Describe "$Global:DSCResourceName\Set-TargetResource" { 175 | 176 | Context 'Ensure is set to Absent' { 177 | 178 | Mock -CommandName Revoke-UserRight -ParameterFilter { 179 | $Principal -eq $TestParameters.Principal -and $UserRights -eq $TestParameters.Constant 180 | } 181 | 182 | Set-TargetResource -Ensure 'Absent' -Constant $TestParameters.Constant -Principal $TestParameters.Principal 183 | 184 | It 'Should call the Revoke-UserRight helper function once' { 185 | Assert-MockCalled -CommandName Revoke-UserRight -Exactly 1 186 | } 187 | 188 | } 189 | 190 | Context 'Ensure is set to Present' { 191 | 192 | Mock -CommandName Grant-UserRight -ParameterFilter { 193 | $Principal -eq $TestParameters.Principal -and $UserRights -eq $TestParameters.Constant 194 | } 195 | 196 | Set-TargetResource -Ensure 'Present' -Constant $TestParameters.Constant -Principal $TestParameters.Principal 197 | 198 | It 'Should call the Grant-UserRight helper function once' { 199 | Assert-MockCalled -CommandName Grant-UserRight -Exactly 1 200 | } 201 | 202 | } 203 | 204 | } 205 | 206 | Describe "$Global:DSCResourceName\Initialize-CustomType" { 207 | 208 | It 'Should not throw' { 209 | {Initialize-CustomType} | Should Not Throw 210 | } 211 | 212 | } 213 | 214 | } 215 | 216 | #endregion 217 | } 218 | finally 219 | { 220 | #region Footer 221 | 222 | Restore-TestEnvironment -TestEnvironment $TestEnvironment 223 | 224 | #endregion 225 | } 226 | -------------------------------------------------------------------------------- /DSCResources/cUserRight/cUserRight.psm1: -------------------------------------------------------------------------------- 1 | #requires -Version 4.0 2 | 3 | data LocalizedData 4 | { 5 | # culture="en-US" 6 | ConvertFrom-StringData -StringData @' 7 | VerboseTestTargetTrueResult = The target resource is already in the desired state. No action is required. 8 | VerboseTestTargetFalseResult = The target resource is not in the desired state. 9 | VerboseGetUserRight = Getting the user rights assigned to the principal "{0}". 10 | VerboseGrantUserRight = Granting the following user rights to the principal "{0}": "{1}". 11 | VerboseRevokeUserRight = Revoking the following user rights from the principal "{0}": "{1}". 12 | '@ 13 | } 14 | 15 | function Get-TargetResource 16 | { 17 | [CmdletBinding()] 18 | [OutputType([Hashtable])] 19 | param 20 | ( 21 | [Parameter(Mandatory = $true)] 22 | [ValidateSet( 23 | 'SeAssignPrimaryTokenPrivilege', 24 | 'SeAuditPrivilege', 25 | 'SeBackupPrivilege', 26 | 'SeBatchLogonRight', 27 | 'SeChangeNotifyPrivilege', 28 | 'SeCreateGlobalPrivilege', 29 | 'SeCreatePagefilePrivilege', 30 | 'SeCreatePermanentPrivilege', 31 | 'SeCreateSymbolicLinkPrivilege', 32 | 'SeCreateTokenPrivilege', 33 | 'SeDebugPrivilege', 34 | 'SeDenyBatchLogonRight', 35 | 'SeDenyInteractiveLogonRight', 36 | 'SeDenyNetworkLogonRight', 37 | 'SeDenyRemoteInteractiveLogonRight', 38 | 'SeDenyServiceLogonRight', 39 | 'SeEnableDelegationPrivilege', 40 | 'SeImpersonatePrivilege', 41 | 'SeIncreaseBasePriorityPrivilege', 42 | 'SeIncreaseQuotaPrivilege', 43 | 'SeIncreaseWorkingSetPrivilege', 44 | 'SeInteractiveLogonRight', 45 | 'SeLoadDriverPrivilege', 46 | 'SeLockMemoryPrivilege', 47 | 'SeMachineAccountPrivilege', 48 | 'SeManageVolumePrivilege', 49 | 'SeNetworkLogonRight', 50 | 'SeProfileSingleProcessPrivilege', 51 | 'SeRelabelPrivilege', 52 | 'SeRemoteInteractiveLogonRight', 53 | 'SeRemoteShutdownPrivilege', 54 | 'SeRestorePrivilege', 55 | 'SeSecurityPrivilege', 56 | 'SeServiceLogonRight', 57 | 'SeShutdownPrivilege', 58 | 'SeSyncAgentPrivilege', 59 | 'SeSystemEnvironmentPrivilege', 60 | 'SeSystemProfilePrivilege', 61 | 'SeSystemTimePrivilege', 62 | 'SeTakeOwnershipPrivilege', 63 | 'SeTcbPrivilege', 64 | 'SeTimeZonePrivilege', 65 | 'SeTrustedCredManAccessPrivilege', 66 | 'SeUndockPrivilege' 67 | )] 68 | [String] 69 | $Constant, 70 | 71 | [Parameter(Mandatory = $true)] 72 | [ValidateNotNullOrEmpty()] 73 | [String] 74 | $Principal 75 | ) 76 | 77 | $UserRights = [String[]]@( 78 | Get-UserRight -Principal $Principal | 79 | Select-Object -ExpandProperty UserRights 80 | ) 81 | 82 | if ($UserRights -contains $Constant) 83 | { 84 | $EnsureResult = 'Present' 85 | } 86 | else 87 | { 88 | $EnsureResult = 'Absent' 89 | } 90 | 91 | $ReturnValue = @{ 92 | Ensure = $EnsureResult 93 | Constant = $Constant 94 | Principal = $Principal 95 | } 96 | 97 | return $ReturnValue 98 | } 99 | 100 | function Test-TargetResource 101 | { 102 | [CmdletBinding()] 103 | [OutputType([Boolean])] 104 | param 105 | ( 106 | [Parameter(Mandatory = $false)] 107 | [ValidateSet('Absent', 'Present')] 108 | [String] 109 | $Ensure = 'Present', 110 | 111 | [Parameter(Mandatory = $true)] 112 | [ValidateSet( 113 | 'SeAssignPrimaryTokenPrivilege', 114 | 'SeAuditPrivilege', 115 | 'SeBackupPrivilege', 116 | 'SeBatchLogonRight', 117 | 'SeChangeNotifyPrivilege', 118 | 'SeCreateGlobalPrivilege', 119 | 'SeCreatePagefilePrivilege', 120 | 'SeCreatePermanentPrivilege', 121 | 'SeCreateSymbolicLinkPrivilege', 122 | 'SeCreateTokenPrivilege', 123 | 'SeDebugPrivilege', 124 | 'SeDenyBatchLogonRight', 125 | 'SeDenyInteractiveLogonRight', 126 | 'SeDenyNetworkLogonRight', 127 | 'SeDenyRemoteInteractiveLogonRight', 128 | 'SeDenyServiceLogonRight', 129 | 'SeEnableDelegationPrivilege', 130 | 'SeImpersonatePrivilege', 131 | 'SeIncreaseBasePriorityPrivilege', 132 | 'SeIncreaseQuotaPrivilege', 133 | 'SeIncreaseWorkingSetPrivilege', 134 | 'SeInteractiveLogonRight', 135 | 'SeLoadDriverPrivilege', 136 | 'SeLockMemoryPrivilege', 137 | 'SeMachineAccountPrivilege', 138 | 'SeManageVolumePrivilege', 139 | 'SeNetworkLogonRight', 140 | 'SeProfileSingleProcessPrivilege', 141 | 'SeRelabelPrivilege', 142 | 'SeRemoteInteractiveLogonRight', 143 | 'SeRemoteShutdownPrivilege', 144 | 'SeRestorePrivilege', 145 | 'SeSecurityPrivilege', 146 | 'SeServiceLogonRight', 147 | 'SeShutdownPrivilege', 148 | 'SeSyncAgentPrivilege', 149 | 'SeSystemEnvironmentPrivilege', 150 | 'SeSystemProfilePrivilege', 151 | 'SeSystemTimePrivilege', 152 | 'SeTakeOwnershipPrivilege', 153 | 'SeTcbPrivilege', 154 | 'SeTimeZonePrivilege', 155 | 'SeTrustedCredManAccessPrivilege', 156 | 'SeUndockPrivilege' 157 | )] 158 | [String] 159 | $Constant, 160 | 161 | [Parameter(Mandatory = $true)] 162 | [ValidateNotNullOrEmpty()] 163 | [String] 164 | $Principal 165 | ) 166 | 167 | $TargetResource = Get-TargetResource -Constant $Constant -Principal $Principal 168 | 169 | $InDesiredState = $Ensure -eq $TargetResource.Ensure 170 | 171 | if ($InDesiredState -eq $true) 172 | { 173 | Write-Verbose -Message ($LocalizedData.VerboseTestTargetTrueResult) 174 | } 175 | else 176 | { 177 | Write-Verbose -Message ($LocalizedData.VerboseTestTargetFalseResult) 178 | } 179 | 180 | return $InDesiredState 181 | } 182 | 183 | function Set-TargetResource 184 | { 185 | [CmdletBinding(SupportsShouldProcess = $true)] 186 | param 187 | ( 188 | [Parameter(Mandatory = $false)] 189 | [ValidateSet('Absent', 'Present')] 190 | [String] 191 | $Ensure = 'Present', 192 | 193 | [Parameter(Mandatory = $true)] 194 | [ValidateSet( 195 | 'SeAssignPrimaryTokenPrivilege', 196 | 'SeAuditPrivilege', 197 | 'SeBackupPrivilege', 198 | 'SeBatchLogonRight', 199 | 'SeChangeNotifyPrivilege', 200 | 'SeCreateGlobalPrivilege', 201 | 'SeCreatePagefilePrivilege', 202 | 'SeCreatePermanentPrivilege', 203 | 'SeCreateSymbolicLinkPrivilege', 204 | 'SeCreateTokenPrivilege', 205 | 'SeDebugPrivilege', 206 | 'SeDenyBatchLogonRight', 207 | 'SeDenyInteractiveLogonRight', 208 | 'SeDenyNetworkLogonRight', 209 | 'SeDenyRemoteInteractiveLogonRight', 210 | 'SeDenyServiceLogonRight', 211 | 'SeEnableDelegationPrivilege', 212 | 'SeImpersonatePrivilege', 213 | 'SeIncreaseBasePriorityPrivilege', 214 | 'SeIncreaseQuotaPrivilege', 215 | 'SeIncreaseWorkingSetPrivilege', 216 | 'SeInteractiveLogonRight', 217 | 'SeLoadDriverPrivilege', 218 | 'SeLockMemoryPrivilege', 219 | 'SeMachineAccountPrivilege', 220 | 'SeManageVolumePrivilege', 221 | 'SeNetworkLogonRight', 222 | 'SeProfileSingleProcessPrivilege', 223 | 'SeRelabelPrivilege', 224 | 'SeRemoteInteractiveLogonRight', 225 | 'SeRemoteShutdownPrivilege', 226 | 'SeRestorePrivilege', 227 | 'SeSecurityPrivilege', 228 | 'SeServiceLogonRight', 229 | 'SeShutdownPrivilege', 230 | 'SeSyncAgentPrivilege', 231 | 'SeSystemEnvironmentPrivilege', 232 | 'SeSystemProfilePrivilege', 233 | 'SeSystemTimePrivilege', 234 | 'SeTakeOwnershipPrivilege', 235 | 'SeTcbPrivilege', 236 | 'SeTimeZonePrivilege', 237 | 'SeTrustedCredManAccessPrivilege', 238 | 'SeUndockPrivilege' 239 | )] 240 | [String] 241 | $Constant, 242 | 243 | [Parameter(Mandatory = $true)] 244 | [ValidateNotNullOrEmpty()] 245 | [String] 246 | $Principal 247 | ) 248 | 249 | if (-not $PSCmdlet.ShouldProcess($Constant)) 250 | { 251 | return 252 | } 253 | 254 | if ($Ensure -eq 'Present') 255 | { 256 | Grant-UserRight -Principal $Principal -UserRights $Constant -Verbose:$VerbosePreference 257 | } 258 | else 259 | { 260 | Revoke-UserRight -Principal $Principal -UserRights $Constant -Verbose:$VerbosePreference 261 | } 262 | } 263 | 264 | #region Helper Functions 265 | 266 | function Initialize-CustomType 267 | { 268 | if (-not ('cUserRight.Lsa' -as [Type])) 269 | { 270 | #region C# Source Code 271 | 272 | $TypeDefinition = @' 273 | 274 | using System; 275 | using System.Collections.Generic; 276 | using System.ComponentModel; 277 | using System.Runtime.InteropServices; 278 | using System.Security.Principal; 279 | using System.Text; 280 | 281 | namespace cUserRight 282 | { 283 | // The AccountRights enumeration is needed to work around case-sensitivity of logon right and privilege names 284 | public enum AccountRights 285 | { 286 | SeAssignPrimaryTokenPrivilege, // Replace a process level token 287 | SeAuditPrivilege, // Generate security audits 288 | SeBackupPrivilege, // Back up files and directories 289 | SeBatchLogonRight, // Log on as a batch job 290 | SeChangeNotifyPrivilege, // Bypass traverse checking 291 | SeCreateGlobalPrivilege, // Create global objects 292 | SeCreatePagefilePrivilege, // Create a pagefile 293 | SeCreatePermanentPrivilege, // Create permanent shared objects 294 | SeCreateSymbolicLinkPrivilege, // Create symbolic links 295 | SeCreateTokenPrivilege, // Create a token object 296 | SeDebugPrivilege, // Debug programs 297 | SeDenyBatchLogonRight, // Deny log on as a batch job 298 | SeDenyInteractiveLogonRight, // Deny log on locally 299 | SeDenyNetworkLogonRight, // Deny access to this computer from the network 300 | SeDenyRemoteInteractiveLogonRight, // Deny log on through Remote Desktop Services 301 | SeDenyServiceLogonRight, // Deny log on as a service 302 | SeEnableDelegationPrivilege, // Enable computer and user accounts to be trusted for delegation 303 | SeImpersonatePrivilege, // Impersonate a client after authentication 304 | SeIncreaseBasePriorityPrivilege, // Increase scheduling priority 305 | SeIncreaseQuotaPrivilege, // Adjust memory quotas for a process 306 | SeIncreaseWorkingSetPrivilege, // Increase a process working set 307 | SeInteractiveLogonRight, // Allow log on locally 308 | SeLoadDriverPrivilege, // Load and unload device drivers 309 | SeLockMemoryPrivilege, // Lock pages in memory 310 | SeMachineAccountPrivilege, // Add workstations to domain 311 | SeManageVolumePrivilege, // Perform volume maintenance tasks 312 | SeNetworkLogonRight, // Access this computer from the network 313 | SeProfileSingleProcessPrivilege, // Profile single process 314 | SeRelabelPrivilege, // Modify an object label 315 | SeRemoteInteractiveLogonRight, // Allow log on through Remote Desktop Services 316 | SeRemoteShutdownPrivilege, // Force shutdown from a remote system 317 | SeRestorePrivilege, // Restore files and directories 318 | SeSecurityPrivilege, // Manage auditing and security log 319 | SeServiceLogonRight, // Log on as a service 320 | SeShutdownPrivilege, // Shut down the system 321 | SeSyncAgentPrivilege, // Synchronize directory service data 322 | SeSystemEnvironmentPrivilege, // Modify firmware environment values 323 | SeSystemProfilePrivilege, // Profile system performance 324 | SeSystemTimePrivilege, // Change the system time 325 | SeTakeOwnershipPrivilege, // Take ownership of files or other objects 326 | SeTcbPrivilege, // Act as part of the operating system 327 | SeTimeZonePrivilege, // Change the time zone 328 | SeTrustedCredManAccessPrivilege, // Access Credential Manager as a trusted caller 329 | SeUndockPrivilege, // Remove computer from docking station 330 | } 331 | 332 | public class Lsa 333 | { 334 | // ACCESS_MASK for Policy Objects 335 | // https://msdn.microsoft.com/en-us/library/cc234246.aspx 336 | [Flags] 337 | public enum LsaPolicyAccessRights : uint 338 | { 339 | POLICY_VIEW_LOCAL_INFORMATION = 0x00000001, 340 | POLICY_VIEW_AUDIT_INFORMATION = 0x00000002, 341 | POLICY_GET_PRIVATE_INFORMATION = 0x00000004, 342 | POLICY_TRUST_ADMIN = 0x00000008, 343 | POLICY_CREATE_ACCOUNT = 0x00000010, 344 | POLICY_CREATE_SECRET = 0x00000020, 345 | POLICY_CREATE_PRIVILEGE = 0x00000040, 346 | POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080, 347 | POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100, 348 | POLICY_AUDIT_LOG_ADMIN = 0x00000200, 349 | POLICY_SERVER_ADMIN = 0x00000400, 350 | POLICY_LOOKUP_NAMES = 0x00000800, 351 | POLICY_NOTIFICATION = 0x00001000, 352 | POLICY_ALL_ACCESS = POLICY_VIEW_LOCAL_INFORMATION | 353 | POLICY_VIEW_AUDIT_INFORMATION | 354 | POLICY_GET_PRIVATE_INFORMATION | 355 | POLICY_TRUST_ADMIN | 356 | POLICY_CREATE_ACCOUNT | 357 | POLICY_CREATE_SECRET | 358 | POLICY_CREATE_PRIVILEGE | 359 | POLICY_SET_DEFAULT_QUOTA_LIMITS | 360 | POLICY_SET_AUDIT_REQUIREMENTS | 361 | POLICY_AUDIT_LOG_ADMIN | 362 | POLICY_SERVER_ADMIN | 363 | POLICY_LOOKUP_NAMES | 364 | POLICY_NOTIFICATION 365 | } 366 | 367 | [StructLayout(LayoutKind.Sequential)] 368 | internal struct LSA_UNICODE_STRING 369 | { 370 | internal ushort Length; 371 | internal ushort MaximumLength; 372 | internal IntPtr Buffer; 373 | } 374 | 375 | [StructLayout(LayoutKind.Sequential)] 376 | internal struct LSA_OBJECT_ATTRIBUTES 377 | { 378 | internal uint Length; 379 | internal IntPtr RootDirectory; 380 | internal IntPtr ObjectName; 381 | internal uint Attributes; 382 | internal IntPtr SecurityDescriptor; 383 | internal IntPtr SecurityQualityOfService; 384 | } 385 | 386 | // LSA Policy NTSTATUS return codes 387 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ms721859%28v=vs.85%29.aspx#lsa_policy_function_return_values 388 | // https://msdn.microsoft.com/en-us/library/cc704588.aspx 389 | internal const uint STATUS_SUCCESS = 0x00000000; 390 | internal const uint STATUS_ACCESS_DENIED = 0xC0000022; 391 | internal const uint STATUS_INSUFFICIENT_RESOURCES = 0xC000009A; 392 | internal const uint STATUS_INTERNAL_DB_ERROR = 0xC0000158; 393 | internal const uint STATUS_INVALID_HANDLE = 0xC0000008; 394 | internal const uint STATUS_INVALID_SERVER_STATE = 0xC00000DC; 395 | internal const uint STATUS_INVALID_PARAMETER = 0xC000000D; 396 | internal const uint STATUS_NO_SUCH_PRIVILEGE = 0xC0000060; 397 | internal const uint STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; 398 | internal const uint STATUS_UNSUCCESSFUL = 0xC0000001; 399 | 400 | private static readonly Dictionary LsaNtStatusMessages = new Dictionary 401 | { 402 | {STATUS_SUCCESS, "The operation completed successfully."}, 403 | {STATUS_ACCESS_DENIED, "Access is denied."}, 404 | {STATUS_INSUFFICIENT_RESOURCES, "There are not enough system resources to complete the call."}, 405 | {STATUS_INTERNAL_DB_ERROR, "The LSA database contains an internal inconsistency."}, 406 | {STATUS_INVALID_HANDLE, "An object or RPC handle is not valid."}, 407 | {STATUS_INVALID_SERVER_STATE, "The LSA server is currently disabled."}, 408 | {STATUS_INVALID_PARAMETER, "One of the parameters is not valid."}, 409 | {STATUS_NO_SUCH_PRIVILEGE, "A specified privilege does not exist."}, 410 | {STATUS_OBJECT_NAME_NOT_FOUND, "An object in the LSA policy database was not found."}, 411 | {STATUS_UNSUCCESSFUL, "The requested operation was unsuccessful."} 412 | }; 413 | 414 | private static void HandleLsaNtStatus(uint ntStatusCode) 415 | { 416 | if (ntStatusCode == STATUS_SUCCESS) 417 | { 418 | return; 419 | } 420 | 421 | var winErrorCode = (int)(LsaNtStatusToWinError(ntStatusCode)); 422 | 423 | if (LsaNtStatusMessages.ContainsKey(ntStatusCode)) 424 | { 425 | throw new Win32Exception(winErrorCode, LsaNtStatusMessages[ntStatusCode]); 426 | } 427 | 428 | throw new Win32Exception(winErrorCode); 429 | } 430 | 431 | private static LSA_UNICODE_STRING ConvertToLsaString(string inputString) 432 | { 433 | if (inputString.Length > 0x7ffe) 434 | { 435 | throw new ArgumentOutOfRangeException(); 436 | }; 437 | 438 | LSA_UNICODE_STRING lsaString = new LSA_UNICODE_STRING(); 439 | 440 | if (inputString != null) 441 | { 442 | lsaString.Length = (ushort)(inputString.Length * UnicodeEncoding.CharSize); 443 | lsaString.MaximumLength = (ushort)((inputString.Length + 1) * UnicodeEncoding.CharSize); 444 | lsaString.Buffer = Marshal.StringToHGlobalAuto(inputString); 445 | } 446 | 447 | return lsaString; 448 | } 449 | 450 | private static IntPtr GetLsaPolicyHandle() 451 | { 452 | var systemName = new LSA_UNICODE_STRING(); 453 | 454 | var objectAttributes = new LSA_OBJECT_ATTRIBUTES 455 | { 456 | Length = 0, 457 | RootDirectory = IntPtr.Zero, 458 | ObjectName = IntPtr.Zero, 459 | Attributes = 0, 460 | SecurityDescriptor = IntPtr.Zero, 461 | SecurityQualityOfService = IntPtr.Zero 462 | }; 463 | 464 | IntPtr lsaPolicyHandle; 465 | var ntStatus = LsaOpenPolicy(ref systemName, ref objectAttributes, (uint)(LsaPolicyAccessRights.POLICY_ALL_ACCESS), out lsaPolicyHandle); 466 | HandleLsaNtStatus(ntStatus); 467 | 468 | return lsaPolicyHandle; 469 | } 470 | 471 | private static IntPtr GetSidPointer(string accountName) 472 | { 473 | var ntAccount = new NTAccount(accountName); 474 | var sid = (SecurityIdentifier)ntAccount.Translate(typeof(SecurityIdentifier)); 475 | 476 | var sidBytes = new byte[sid.BinaryLength]; 477 | sid.GetBinaryForm(sidBytes, 0); 478 | var sidPtr = Marshal.AllocHGlobal(sidBytes.Length); 479 | Marshal.Copy(sidBytes, 0, sidPtr, sidBytes.Length); 480 | 481 | return sidPtr; 482 | } 483 | 484 | public static string[] EnumerateAccountRights(string accountName) 485 | { 486 | var lsaPolicyHandle = GetLsaPolicyHandle(); 487 | var sidPtr = GetSidPointer(accountName); 488 | 489 | var lsaUserRights = IntPtr.Zero; 490 | uint countOfRights; 491 | 492 | try 493 | { 494 | var ntStatus = LsaEnumerateAccountRights(lsaPolicyHandle, sidPtr, out lsaUserRights, out countOfRights); 495 | 496 | if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) 497 | { 498 | return new string[0]; 499 | } 500 | 501 | HandleLsaNtStatus(ntStatus); 502 | 503 | LSA_UNICODE_STRING lsaUserRight; 504 | var userRights = new List(); 505 | long pointerValue = lsaUserRights.ToInt64(); 506 | 507 | for (int i = 0; i < countOfRights; i++) 508 | { 509 | lsaUserRight = (LSA_UNICODE_STRING)Marshal.PtrToStructure(new IntPtr(pointerValue), typeof(LSA_UNICODE_STRING)); 510 | string userRight = Marshal.PtrToStringAuto(lsaUserRight.Buffer); 511 | userRights.Add(userRight); 512 | pointerValue += Marshal.SizeOf(lsaUserRight); 513 | } 514 | 515 | return userRights.ToArray(); 516 | } 517 | finally 518 | { 519 | Marshal.FreeHGlobal(sidPtr); 520 | 521 | var ntStatus = LsaClose(lsaPolicyHandle); 522 | HandleLsaNtStatus(ntStatus); 523 | } 524 | } 525 | 526 | public static void AddAccountRights(string accountName, AccountRights[] accountRights) 527 | { 528 | var lsaPolicyHandle = GetLsaPolicyHandle(); 529 | var sidPtr = GetSidPointer(accountName); 530 | 531 | try 532 | { 533 | var lsaAccountRights = new LSA_UNICODE_STRING[accountRights.Length]; 534 | 535 | for (int i = 0; i < accountRights.Length; ++i) 536 | { 537 | lsaAccountRights[i] = ConvertToLsaString(accountRights[i].ToString()); 538 | } 539 | 540 | var ntStatus = LsaAddAccountRights(lsaPolicyHandle, sidPtr, lsaAccountRights, (uint)lsaAccountRights.Length); 541 | HandleLsaNtStatus(ntStatus); 542 | } 543 | finally 544 | { 545 | Marshal.FreeHGlobal(sidPtr); 546 | 547 | var ntStatus = LsaClose(lsaPolicyHandle); 548 | HandleLsaNtStatus(ntStatus); 549 | } 550 | } 551 | 552 | public static void RemoveAccountRights(string accountName, AccountRights?[] accountRights, bool allRights = false) 553 | { 554 | var lsaPolicyHandle = GetLsaPolicyHandle(); 555 | var sidPtr = GetSidPointer(accountName); 556 | 557 | try 558 | { 559 | var lsaAccountRightsList = new List(); 560 | 561 | if (accountRights != null) 562 | { 563 | for (int i = 0; i < accountRights.Length; ++i) 564 | { 565 | var lsaAccountRight = ConvertToLsaString(accountRights[i].ToString()); 566 | lsaAccountRightsList.Add(lsaAccountRight); 567 | } 568 | } 569 | 570 | LSA_UNICODE_STRING[] lsaAccountRights = lsaAccountRightsList.ToArray(); 571 | 572 | var ntStatus = LsaRemoveAccountRights(lsaPolicyHandle, sidPtr, allRights, lsaAccountRights, (uint)lsaAccountRights.Length); 573 | 574 | // The user does not have any logon rights or privileges 575 | if (ntStatus == STATUS_OBJECT_NAME_NOT_FOUND) 576 | { 577 | return; 578 | } 579 | 580 | HandleLsaNtStatus(ntStatus); 581 | } 582 | finally 583 | { 584 | Marshal.FreeHGlobal(sidPtr); 585 | 586 | var ntStatus = LsaClose(lsaPolicyHandle); 587 | HandleLsaNtStatus(ntStatus); 588 | } 589 | } 590 | 591 | #region P/Invoke Definitions 592 | 593 | // The LsaAddAccountRights function assigns one or more privileges to an account 594 | [DllImport("advapi32.dll", SetLastError = true)] 595 | private static extern uint LsaAddAccountRights( 596 | IntPtr PolicyHandle, 597 | IntPtr AccountSid, 598 | LSA_UNICODE_STRING[] UserRights, 599 | uint CountOfRights 600 | ); 601 | 602 | // The LsaClose function closes a handle to the Policy object 603 | [DllImport("advapi32.dll", SetLastError = false)] 604 | private static extern uint LsaClose(IntPtr ObjectHandle); 605 | 606 | // The LsaEnumerateAccountRights function enumerates the privileges assigned to an account 607 | [DllImport("advapi32.dll", SetLastError = true)] 608 | private static extern uint LsaEnumerateAccountRights( 609 | IntPtr PolicyHandle, 610 | IntPtr AccountSid, 611 | out IntPtr UserRights, 612 | out uint CountOfRights 613 | ); 614 | 615 | // The LsaNtStatusToWinError function converts an NTSTATUS code returned by an LSA function to a Windows error code 616 | [DllImport("advapi32.dll", SetLastError = false)] 617 | private static extern uint LsaNtStatusToWinError(uint status); 618 | 619 | // The LsaOpenPolicy function opens a handle to the Policy object. 620 | [DllImport("advapi32.dll", SetLastError = true)] 621 | private static extern uint LsaOpenPolicy( 622 | ref LSA_UNICODE_STRING SystemName, 623 | ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, 624 | uint DesiredAccess, 625 | out IntPtr PolicyHandle 626 | ); 627 | 628 | // The LsaRemoveAccountRights function removes one or more privileges from an account 629 | [DllImport("advapi32.dll", SetLastError = true)] 630 | private static extern uint LsaRemoveAccountRights( 631 | IntPtr PolicyHandle, 632 | IntPtr AccountSid, 633 | [MarshalAs(UnmanagedType.U1)] Boolean AllRights, 634 | LSA_UNICODE_STRING[] UserRights, 635 | uint CountOfRights 636 | ); 637 | 638 | #endregion 639 | } 640 | } 641 | 642 | '@ 643 | 644 | #endregion 645 | 646 | Add-Type -TypeDefinition $TypeDefinition -Language CSharp -ErrorAction Stop 647 | } 648 | } 649 | 650 | function Get-UserRight 651 | { 652 | [CmdletBinding()] 653 | param 654 | ( 655 | [Parameter(Mandatory = $true)] 656 | [ValidateNotNullOrEmpty()] 657 | [String] 658 | $Principal 659 | ) 660 | 661 | Initialize-CustomType 662 | 663 | Write-Verbose -Message ($LocalizedData.VerboseGetUserRight -f $Principal) 664 | 665 | $OutputObject = [PSCustomObject]@{ 666 | Principal = $Principal 667 | UserRights = [String[]]@( 668 | [cUserRight.Lsa]::EnumerateAccountRights($Principal) 669 | ) 670 | } 671 | 672 | return $OutputObject 673 | } 674 | 675 | function Grant-UserRight 676 | { 677 | [CmdletBinding(SupportsShouldProcess = $true)] 678 | param 679 | ( 680 | [Parameter(Mandatory = $true)] 681 | [ValidateNotNullOrEmpty()] 682 | [String] 683 | $Principal, 684 | 685 | [Parameter(Mandatory = $true)] 686 | [ValidateNotNullOrEmpty()] 687 | [String[]] 688 | $UserRights 689 | ) 690 | 691 | Initialize-CustomType 692 | 693 | $VerboseMessage = $LocalizedData.VerboseGrantUserRight -f $Principal, ($UserRights -join '", "') 694 | 695 | if ($PSCmdlet.ShouldProcess($VerboseMessage, $null, $null)) 696 | { 697 | [cUserRight.Lsa]::AddAccountRights($Principal, $UserRights) 698 | } 699 | } 700 | 701 | function Revoke-UserRight 702 | { 703 | [CmdletBinding(SupportsShouldProcess = $true)] 704 | param 705 | ( 706 | [Parameter(Mandatory = $true)] 707 | [ValidateNotNullOrEmpty()] 708 | [String] 709 | $Principal, 710 | 711 | [Parameter(Mandatory = $true)] 712 | [ValidateNotNullOrEmpty()] 713 | [String[]] 714 | $UserRights 715 | ) 716 | 717 | Initialize-CustomType 718 | 719 | $VerboseMessage = $LocalizedData.VerboseRevokeUserRight -f $Principal, ($UserRights -join '", "') 720 | 721 | if ($PSCmdlet.ShouldProcess($VerboseMessage, $null, $null)) 722 | { 723 | [cUserRight.Lsa]::RemoveAccountRights($Principal, $UserRights) 724 | } 725 | } 726 | 727 | #endregion 728 | --------------------------------------------------------------------------------