DSCResources/MSFT_RegistryPolicyFile/MSFT_RegistryPolicyFile.psm1
using module ..\..\Modules\GPRegistryPolicyFileParser $script:resourceModulePath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent $script:modulesFolderPath = Join-Path -Path $script:resourceModulePath -ChildPath 'Modules' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'GPRegistryPolicyDsc.Common' $script:GPRegistryPolicyFileParserModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'GPRegistryPolicyFileParser' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'GPRegistryPolicyDsc.Common.psm1') Import-Module -Name (Join-Path -Path $script:GPRegistryPolicyFileParserModulePath -ChildPath 'GPRegistryPolicyFileParser.psm1') $script:localizedData = Get-LocalizedData -ResourceName 'MSFT_RegistryPolicyFile' <# .SYNOPSIS Returns the current state of the registry policy file. .PARAMETER Key Indicates the path of the registry key for which you want to ensure a specific state. This path must include the hive. .PARAMETER ValueName Indicates the name of the registry value. .PARAMETER TargetType Indicates the target type. This is needed to determine the .pol file path. Supported values are LocalMachine, User, Administrators, NonAdministrators, Account. .PARAMETER AccountName Specifies the name of the account for an user specific pol file to be managed. #> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [System.String] $Key, [Parameter(Mandatory = $true)] [System.String] $ValueName, [Parameter(Mandatory = $true)] [ValidateSet('ComputerConfiguration','UserConfiguration','Administrators','NonAdministrators','Account')] [System.String] $TargetType, [Parameter()] [AllowNull()] [System.String] $AccountName ) Write-Verbose -Message ($script:localizedData.RetrievingCurrentState -f $Key, $ValueName) # determine pol file path $polFilePath = Get-RegistryPolicyFilePath -TargetType $TargetType -AccountName $AccountName $assertPolFile = Test-Path -Path $polFilePath # read the pol file if ($assertPolFile -eq $true) { $polFileContents = Read-GPRegistryPolicyFile -Path $polFilePath $currentResults = $polFileContents | Where-Object -FilterScript {$PSItem.Key -eq $Key -and $PSItem.ValueName -eq $ValueName} } # determine if the key is present or not if ($null -eq $currentResults.ValueName) { $ensureResult = 'Absent' } else { $ensureResult = 'Present' $valueTypeResult = $currentResults.GetRegTypeString() } # resolve account name $polFilePathArray = $polFilePath -split '\\' $system32Index = $polFilePathArray.IndexOf('System32') $accountNameFromPath = $polFilePathArray[$system32Index+2] if ($accountNameFromPath -match '^S-1-') { $accountNameResult = ConvertTo-NTAccountName -SecurityIdentifier $accountNameFromPath } else { $accountNameResult = $accountNameFromPath } # return the results $getTargetResourceResult = @{ Key = $Key ValueName = $ValueName ValueData = [System.String[]] $currentResults.ValueData ValueType = $valueTypeResult TargetType = $TargetType Ensure = $ensureResult Path = $polFilePath AccountName = $accountNameResult } return $getTargetResourceResult } <# .SYNOPSIS Adds or removes the policy key in the pol file. .PARAMETER Key Indicates the path of the registry key for which you want to ensure a specific state. This path must include the hive. .PARAMETER ValueName Indicates the name of the registry value. .PARAMETER ValueData The data for the registry value. .PARAMETER ValueType Indicates the type of the value. .PARAMETER TargetType Indicates the target type. This is needed to determine the .pol file path. Supported values are LocalMachine, User, Administrators, NonAdministrators, Account. .PARAMETER AccountName Specifies the name of the account for an user specific pol file to be managed. .PARAMETER Ensure Specifies the desired state of the registry policy. When set to 'Present', the registry policy will be created. When set to 'Absent', the registry policy will be removed. Default value is 'Present'. #> function Set-TargetResource { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [System.String] $Key, [Parameter(Mandatory = $true)] [System.String] $ValueName, [Parameter(Mandatory = $true)] [ValidateSet('ComputerConfiguration','UserConfiguration','Administrators','NonAdministrators','Account')] [System.String] $TargetType, [Parameter()] [System.String[]] $ValueData, [Parameter()] [ValidateSet('Binary','Dword','ExpandString','MultiString','Qword','String','None')] [System.String] $ValueType, [Parameter()] [System.String] $AccountName, [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present' ) $getTargetResourceParameters = @{ Key = $Key TargetType = $TargetType ValueName = $ValueName AccountName = $AccountName } $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters $polFilePath = Get-RegistryPolicyFilePath -TargetType $TargetType -AccountName $AccountName $gpRegistryEntry = New-GPRegistryPolicy -Key $Key -ValueName $ValueName -ValueData $ValueData -ValueType ([GPRegistryPolicy]::GetRegTypeFromString($ValueType)) if ($Ensure -eq 'Present') { if ($getTargetResourceResult.Ensure -eq 'Absent') { $assertPolFile = Test-Path -Path $polFilePath if ($assertPolFile -eq $false) { # create the pol file New-GPRegistryPolicyFile -Path $polFilePath } } # write the desired value Write-Verbose -Message ($script:localizedData.AddPolicyToFile -f $Key, $ValueName, $ValueData, $ValueType) Set-GPRegistryPolicyFileEntry -Path $polFilePath -RegistryPolicy $gpRegistryEntry } else { if ($getTargetResourceResult.Ensure -eq 'Present') { Write-Verbose -Message ($script:localizedData.RemovePolicyFromFile -f $Key, $ValueName) Remove-GPRegistryPolicyFileEntry -Path $polFilePath -RegistryPolicy $gpRegistryEntry } } Set-RefreshRegistryKey } <# .SYNOPSIS Tests for the desired state of the policy key in the pol file. .PARAMETER Key Indicates the path of the registry key for which you want to ensure a specific state. This path must include the hive. .PARAMETER ValueName Indicates the name of the registry value. .PARAMETER ValueData The data for the registry value. .PARAMETER ValueType Indicates the type of the value. .PARAMETER TargetType Indicates the target type. This is needed to determine the .pol file path. Supported values are LocalMachine, User, Administrators, NonAdministrators, Account. .PARAMETER AccountName Specifies the name of the account for an user specific pol file to be managed. .PARAMETER Ensure Specifies the desired state of the registry policy. When set to 'Present', the registry policy will be created. When set to 'Absent', the registry policy will be removed. Default value is 'Present'. #> function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [System.String] $Key, [Parameter(Mandatory = $true)] [System.String] $ValueName, [Parameter(Mandatory = $true)] [ValidateSet('ComputerConfiguration','UserConfiguration','Administrators','NonAdministrators','Account')] [System.String] $TargetType, [Parameter()] [System.String[]] $ValueData, [Parameter()] [ValidateSet('Binary','Dword','ExpandString','MultiString','Qword','String','None')] [System.String] $ValueType, [Parameter()] [System.String] $AccountName, [Parameter()] [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present' ) $getTargetResourceParameters = @{ Key = $Key TargetType = $TargetType ValueName = $ValueName AccountName = $AccountName } $testTargetResourceResult = $false $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters if ($Ensure -eq 'Present') { $valuesToCheck = @( 'Key' 'ValueName' 'TargetType' 'ValueData' 'ValueType' 'Ensure' ) $testTargetResourceResult = Test-DscParameterState -CurrentValues $getTargetResourceResult -DesiredValues $PSBoundParameters -ValuesToCheck $valuesToCheck } else { if ($Ensure -eq $getTargetResourceResult.Ensure) { Write-Verbose -Message ($script:localizedData.InDesiredState) $testTargetResourceResult = $true } } return $testTargetResourceResult } <# .SYNOPSIS Retrieves the path to the pol file. .PARAMETER TargetType Indicates the target type. This is needed to determine the .pol file path. Supported values are LocalMachine, User, Administrators, NonAdministrators, Account. .PARAMETER AccountName Specifies the name of the account for an user specific pol file to be managed. #> function Get-RegistryPolicyFilePath { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [ValidateSet("ComputerConfiguration","UserConfiguration","Administrators","NonAdministrators","Account")] [System.String] $TargetType, [Parameter()] [System.String] $AccountName ) switch ($TargetType) { 'ComputerConfiguration' { $childPath = 'System32\GroupPolicy\Machine\registry.pol' } 'UserConfiguration' { $childPath = 'System32\GroupPolicy\User\registry.pol' } 'Administrators' { $childPath = 'System32\GroupPolicyUsers\S-1-5-32-544\User\registry.pol' } 'NonAdministrators' { $childPath = 'System32\GroupPolicyUsers\S-1-5-32-545\User\registry.pol' } 'Account' { if ([System.String]::IsNullOrEmpty($AccountName)) { throw $script:localizedData.AccountNameNull } $sid = ConvertTo-SecurityIdentifier -AccountName $AccountName $childPath = "System32\GroupPolicyUsers\$sid\User\registry.pol" } } return (Join-Path -Path $env:SystemRoot -ChildPath $childPath) } <# .SYNOPSIS Converts an identity to a SID to verify it's a valid account. .PARAMETER AccountName Specifies the identity to convert. #> function ConvertTo-SecurityIdentifier { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [System.String] $AccountName ) Write-Verbose -Message ($script:localizedData.TranslatingNameToSid -f $AccountName) $id = [System.Security.Principal.NTAccount] $AccountName return $id.Translate([System.Security.Principal.SecurityIdentifier]).Value } <# .SYNOPSIS Converts a SID to an NTAccount name. .PARAMETER SecurityIdentifier Specifies SID of the identity to convert. #> function ConvertTo-NTAccountName { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [System.Security.Principal.SecurityIdentifier] $SecurityIdentifier ) $identiy = [System.Security.Principal.SecurityIdentifier] $SecurityIdentifier return $identiy.Translate([System.Security.Principal.NTAccount]).Value } <# .SYNOPSIS Writes a registry key indicating a group policy refresh is required. .PARAMETER Path Specifies the value of the registry path that will contain the properties pertaining to requiring a refresh. .PARAMETER PropertyName Specifies a name for the new property. .PARAMETER Value Specifies the property value. #> function Set-RefreshRegistryKey { [CmdletBinding()] param ( [Parameter()] [System.String] $Path = 'HKLM:\SOFTWARE\Microsoft\GPRegistryPolicy', [Parameter()] [System.String] $PropertyName = 'RefreshRequired', [Parameter()] [System.Object] $Value = 1 ) New-Item -Path $Path -Force New-ItemProperty -Path $Path -Name $PropertyName -Value $Value -Force } |