5 changed files with 0 additions and 1312 deletions
@ -1,555 +0,0 @@ |
|||||
#requires -Version 2.0 |
|
||||
|
|
||||
$scriptRoot = Split-Path $MyInvocation.MyCommand.Path |
|
||||
. "$scriptRoot\Common.ps1" |
|
||||
|
|
||||
<# |
|
||||
.SYNOPSIS |
|
||||
Creates or modifies a value in a .pol file. |
|
||||
.DESCRIPTION |
|
||||
Creates or modifies a value in a .pol file. By default, also updates the version number in the policy's gpt.ini file. |
|
||||
.PARAMETER Path |
|
||||
Path to the .pol file that is to be modified. |
|
||||
.PARAMETER Key |
|
||||
The registry key inside the .pol file that you want to modify. |
|
||||
.PARAMETER ValueName |
|
||||
The name of the registry value. May be set to an empty string to modify the default value of a key. |
|
||||
.PARAMETER Data |
|
||||
The new value to assign to the registry key / value. Cannot be $null, but can be set to an empty string or empty array. |
|
||||
.PARAMETER Type |
|
||||
The type of registry value to set in the policy file. Cannot be set to Unknown or None, but all other values of the RegistryValueKind enum are legal. |
|
||||
.PARAMETER NoGptIniUpdate |
|
||||
When this switch is used, the command will not attempt to update the version number in the gpt.ini file |
|
||||
.EXAMPLE |
|
||||
Set-PolicyFileEntry -Path $env:systemroot\system32\GroupPolicy\Machine\registry.pol -Key Software\Policies\Something -ValueName SomeValue -Data 'Hello, World!' -Type String |
|
||||
|
|
||||
Assigns a value of 'Hello, World!' to the String value Software\Policies\Something\SomeValue in the local computer Machine GPO. Updates the Machine version counter in $env:systemroot\system32\GroupPolicy\gpt.ini |
|
||||
.EXAMPLE |
|
||||
Set-PolicyFileEntry -Path $env:systemroot\system32\GroupPolicy\Machine\registry.pol -Key Software\Policies\Something -ValueName SomeValue -Data 'Hello, World!' -Type String -NoGptIniUpdate |
|
||||
|
|
||||
Same as example 1, except this one does not update gpt.ini right away. This can be useful if you want to set multiple |
|
||||
values in the policy file and only trigger a single Group Policy refresh. |
|
||||
.EXAMPLE |
|
||||
Set-PolicyFileEntry -Path $env:systemroot\system32\GroupPolicy\Machine\registry.pol -Key Software\Policies\Something -ValueName SomeValue -Data '0x12345' -Type DWord |
|
||||
|
|
||||
Example demonstrating that strings with valid numeric data (including hexadecimal strings beginning with 0x) can be assigned to the numeric types DWord, QWord and Binary. |
|
||||
.EXAMPLE |
|
||||
$entries = @( |
|
||||
New-Object psobject -Property @{ ValueName = 'MaxXResolution'; Data = 1680 } |
|
||||
New-Object psobject -Property @{ ValueName = 'MaxYResolution'; Data = 1050 } |
|
||||
) |
|
||||
|
|
||||
$entries | Set-PolicyFileEntry -Path $env:SystemRoot\system32\GroupPolicy\Machine\registry.pol ` |
|
||||
-Key 'SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' ` |
|
||||
-Type DWord |
|
||||
|
|
||||
Example of using pipeline input to set multiple values at once. The advantage to this approach is that the |
|
||||
.pol file on disk (and the GPT.ini file) will be updated if _any_ of the specified settings had to be modified, |
|
||||
and will be left alone if the file already contained all of the correct values. |
|
||||
|
|
||||
The Key and Type properties could have also been specified via the pipeline objects instead of on the command line, |
|
||||
but since both values shared the same Key and Type, this example shows that you can pass the values in either way. |
|
||||
.INPUTS |
|
||||
The Key, ValueName, Data, and Type properties may be bound via the pipeline by property name. |
|
||||
.OUTPUTS |
|
||||
None. This command does not generate output. |
|
||||
.NOTES |
|
||||
If the specified policy file already contains the correct value, the file will not be modified, and the gpt.ini file will not be updated. |
|
||||
.LINK |
|
||||
Get-PolicyFileEntry |
|
||||
.LINK |
|
||||
Remove-PolicyFileEntry |
|
||||
.LINK |
|
||||
Update-GptIniVersion |
|
||||
.LINK |
|
||||
about_RegistryValuesForAdminTemplates |
|
||||
#> |
|
||||
|
|
||||
function Set-PolicyFileEntry |
|
||||
{ |
|
||||
[CmdletBinding(SupportsShouldProcess = $true)] |
|
||||
param ( |
|
||||
[Parameter(Mandatory = $true, Position = 0)] |
|
||||
[string] $Path, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, Position = 1, ValueFromPipelineByPropertyName = $true)] |
|
||||
[string] $Key, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, Position = 2, ValueFromPipelineByPropertyName = $true)] |
|
||||
[AllowEmptyString()] |
|
||||
[string] $ValueName, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, Position = 3, ValueFromPipelineByPropertyName = $true)] |
|
||||
[AllowEmptyString()] |
|
||||
[AllowEmptyCollection()] |
|
||||
[object] $Data, |
|
||||
|
|
||||
[Parameter(ValueFromPipelineByPropertyName = $true)] |
|
||||
[ValidateScript({ |
|
||||
if ($_ -eq [Microsoft.Win32.RegistryValueKind]::Unknown) |
|
||||
{ |
|
||||
throw 'Unknown is not a valid value for the Type parameter' |
|
||||
} |
|
||||
|
|
||||
if ($_ -eq [Microsoft.Win32.RegistryValueKind]::None) |
|
||||
{ |
|
||||
throw 'None is not a valid value for the Type parameter' |
|
||||
} |
|
||||
|
|
||||
return $true |
|
||||
})] |
|
||||
[Microsoft.Win32.RegistryValueKind] $Type = [Microsoft.Win32.RegistryValueKind]::String, |
|
||||
|
|
||||
[switch] $NoGptIniUpdate |
|
||||
) |
|
||||
|
|
||||
begin |
|
||||
{ |
|
||||
if (Get-Command [G]et-CallerPreference -CommandType Function -Module PreferenceVariables) |
|
||||
{ |
|
||||
Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState |
|
||||
} |
|
||||
|
|
||||
$dirty = $false |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
$policyFile = OpenPolicyFile -Path $Path -ErrorAction Stop |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$PSCmdlet.ThrowTerminatingError($_) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
process |
|
||||
{ |
|
||||
$existingEntry = $policyFile.GetValue($Key, $ValueName) |
|
||||
|
|
||||
if ($null -ne $existingEntry -and $Type -eq (PolEntryTypeToRegistryValueKind $existingEntry.Type)) |
|
||||
{ |
|
||||
$existingData = GetEntryData -Entry $existingEntry -Type $Type |
|
||||
if (DataIsEqual $Data $existingData -Type $Type) |
|
||||
{ |
|
||||
Write-Verbose "Policy setting '$Key\$ValueName' is already set to '$Data' of type '$Type'." |
|
||||
return |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
Write-Verbose "Configuring '$Key\$ValueName' to value '$Data' of type '$Type'." |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
switch ($Type) |
|
||||
{ |
|
||||
([Microsoft.Win32.RegistryValueKind]::Binary) |
|
||||
{ |
|
||||
$bytes = $Data -as [byte[]] |
|
||||
if ($null -eq $bytes) |
|
||||
{ |
|
||||
$errorRecord = InvalidDataTypeCombinationErrorRecord -Message 'When -Type is set to Binary, -Data must be passed a Byte[] array.' |
|
||||
$PSCmdlet.ThrowTerminatingError($errorRecord) |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
$policyFile.SetBinaryValue($Key, $ValueName, $bytes) |
|
||||
} |
|
||||
|
|
||||
break |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::String) |
|
||||
{ |
|
||||
$array = @($Data) |
|
||||
|
|
||||
if ($array.Count -ne 1) |
|
||||
{ |
|
||||
$errorRecord = InvalidDataTypeCombinationErrorRecord -Message 'When -Type is set to String, -Data must be passed a scalar value or single-element array.' |
|
||||
$PSCmdlet.ThrowTerminatingError($errorRecord) |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
$policyFile.SetStringValue($Key, $ValueName, $array[0].ToString()) |
|
||||
} |
|
||||
|
|
||||
break |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::ExpandString) |
|
||||
{ |
|
||||
$array = @($Data) |
|
||||
|
|
||||
if ($array.Count -ne 1) |
|
||||
{ |
|
||||
$errorRecord = InvalidDataTypeCombinationErrorRecord -Message 'When -Type is set to ExpandString, -Data must be passed a scalar value or single-element array.' |
|
||||
$PSCmdlet.ThrowTerminatingError($errorRecord) |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
$policyFile.SetStringValue($Key, $ValueName, $array[0].ToString(), $true) |
|
||||
} |
|
||||
|
|
||||
break |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::DWord) |
|
||||
{ |
|
||||
$array = @($Data) |
|
||||
$dword = ($array | Select-Object -First 1) -as [UInt32] |
|
||||
if ($null -eq $dword -or $array.Count -ne 1) |
|
||||
{ |
|
||||
$errorRecord = InvalidDataTypeCombinationErrorRecord -Message 'When -Type is set to DWord, -Data must be passed a valid UInt32 value.' |
|
||||
$PSCmdlet.ThrowTerminatingError($errorRecord) |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
$policyFile.SetDWORDValue($key, $ValueName, $dword) |
|
||||
} |
|
||||
|
|
||||
break |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::QWord) |
|
||||
{ |
|
||||
$array = @($Data) |
|
||||
$qword = ($array | Select-Object -First 1) -as [UInt64] |
|
||||
if ($null -eq $qword -or $array.Count -ne 1) |
|
||||
{ |
|
||||
$errorRecord = InvalidDataTypeCombinationErrorRecord -Message 'When -Type is set to QWord, -Data must be passed a valid UInt64 value.' |
|
||||
$PSCmdlet.ThrowTerminatingError($errorRecord) |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
$policyFile.SetQWORDValue($key, $ValueName, $qword) |
|
||||
} |
|
||||
|
|
||||
break |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::MultiString) |
|
||||
{ |
|
||||
$strings = [string[]] @( |
|
||||
foreach ($item in @($Data)) |
|
||||
{ |
|
||||
$item.ToString() |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
$policyFile.SetMultiStringValue($Key, $ValueName, $strings) |
|
||||
|
|
||||
break |
|
||||
} |
|
||||
|
|
||||
} # switch ($Type) |
|
||||
|
|
||||
$dirty = $true |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
throw |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
end |
|
||||
{ |
|
||||
if ($dirty) |
|
||||
{ |
|
||||
$doUpdateGptIni = -not $NoGptIniUpdate |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
# SavePolicyFile contains the calls to $PSCmdlet.ShouldProcess, and will inherit our |
|
||||
# WhatIfPreference / ConfirmPreference values from here. |
|
||||
SavePolicyFile -PolicyFile $policyFile -UpdateGptIni:$doUpdateGptIni -ErrorAction Stop |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$PSCmdlet.ThrowTerminatingError($_) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
<# |
|
||||
.SYNOPSIS |
|
||||
Retrieves the current setting(s) from a .pol file. |
|
||||
.DESCRIPTION |
|
||||
Retrieves the current setting(s) from a .pol file. |
|
||||
.PARAMETER Path |
|
||||
Path to the .pol file that is to be read. |
|
||||
.PARAMETER Key |
|
||||
The registry key inside the .pol file that you want to read. |
|
||||
.PARAMETER ValueName |
|
||||
The name of the registry value. May be set to an empty string to read the default value of a key. |
|
||||
.PARAMETER All |
|
||||
Switch indicating that all entries from the specified .pol file should be output, instead of searching for a specific key / ValueName pair. |
|
||||
.EXAMPLE |
|
||||
Get-PolicyFileEntry -Path $env:systemroot\system32\GroupPolicy\Machine\registry.pol -Key Software\Policies\Something -ValueName SomeValue |
|
||||
|
|
||||
Reads the value of Software\Policies\Something\SomeValue from the Machine admin templates of the local GPO. |
|
||||
Either returns an object with the data and type of this registry value (if present), or returns nothing, if not found. |
|
||||
.EXAMPLE |
|
||||
Get-PolicyFileEntry -Path $env:systemroot\system32\GroupPolicy\Machine\registry.pol -All |
|
||||
|
|
||||
Outputs all of the registry values from the local machine Administrative Templates |
|
||||
.INPUTS |
|
||||
None. This command does not accept pipeline input. |
|
||||
.OUTPUTS |
|
||||
If the specified registry value is found, the function outputs a PSCustomObject with the following properties: |
|
||||
ValueName: The same value that was passed to the -ValueName parameter |
|
||||
Key: The same value that was passed to the -Key parameter |
|
||||
Data: The current value assigned to the specified Key / ValueName in the .pol file. |
|
||||
Type: The RegistryValueKind type of the specified Key / ValueName in the .pol file. |
|
||||
If the specified registry value is not found in the .pol file, the command returns nothing. No error is produced. |
|
||||
.LINK |
|
||||
Set-PolicyFileEntry |
|
||||
.LINK |
|
||||
Remove-PolicyFileEntry |
|
||||
.LINK |
|
||||
Update-GptIniVersion |
|
||||
.LINK |
|
||||
about_RegistryValuesForAdminTemplates |
|
||||
#> |
|
||||
|
|
||||
function Get-PolicyFileEntry |
|
||||
{ |
|
||||
[CmdletBinding(DefaultParameterSetName = 'ByKeyAndValue')] |
|
||||
param ( |
|
||||
[Parameter(Mandatory = $true, Position = 0)] |
|
||||
[string] $Path, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, Position = 1, ParameterSetName = 'ByKeyAndValue')] |
|
||||
[string] $Key, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, Position = 2, ParameterSetName = 'ByKeyAndValue')] |
|
||||
[string] $ValueName, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'All')] |
|
||||
[switch] $All |
|
||||
) |
|
||||
|
|
||||
if (Get-Command [G]et-CallerPreference -CommandType Function -Module PreferenceVariables) |
|
||||
{ |
|
||||
Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState |
|
||||
} |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
$policyFile = OpenPolicyFile -Path $Path -ErrorAction Stop |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$PSCmdlet.ThrowTerminatingError($_) |
|
||||
} |
|
||||
|
|
||||
if ($PSCmdlet.ParameterSetName -eq 'ByKeyAndValue') |
|
||||
{ |
|
||||
$entry = $policyFile.GetValue($Key, $ValueName) |
|
||||
|
|
||||
if ($null -ne $entry) |
|
||||
{ |
|
||||
PolEntryToPsObject -PolEntry $entry |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
foreach ($entry in $policyFile.Entries) |
|
||||
{ |
|
||||
PolEntryToPsObject -PolEntry $entry |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
<# |
|
||||
.SYNOPSIS |
|
||||
Removes a value from a .pol file. |
|
||||
.DESCRIPTION |
|
||||
Removes a value from a .pol file. By default, also updates the version number in the policy's gpt.ini file. |
|
||||
.PARAMETER Path |
|
||||
Path to the .pol file that is to be modified. |
|
||||
.PARAMETER Key |
|
||||
The registry key inside the .pol file from which you want to remove a value. |
|
||||
.PARAMETER ValueName |
|
||||
The name of the registry value to be removed. May be set to an empty string to remove the default value of a key. |
|
||||
.PARAMETER NoGptIniUpdate |
|
||||
When this switch is used, the command will not attempt to update the version number in the gpt.ini file |
|
||||
.EXAMPLE |
|
||||
Remove-PolicyFileEntry -Path $env:systemroot\system32\GroupPolicy\Machine\registry.pol -Key Software\Policies\Something -ValueName SomeValue |
|
||||
|
|
||||
Removes the value Software\Policies\Something\SomeValue from the local computer Machine GPO, if present. Updates the Machine version counter in $env:systemroot\system32\GroupPolicy\gpt.ini |
|
||||
.EXAMPLE |
|
||||
$entries = @( |
|
||||
New-Object psobject -Property @{ ValueName = 'MaxXResolution'; Data = 1680 } |
|
||||
New-Object psobject -Property @{ ValueName = 'MaxYResolution'; Data = 1050 } |
|
||||
) |
|
||||
|
|
||||
$entries | Remove-PolicyFileEntry -Path $env:SystemRoot\system32\GroupPolicy\Machine\registry.pol ` |
|
||||
-Key 'SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services' |
|
||||
|
|
||||
Example of using pipeline input to remove multiple values at once. The advantage to this approach is that the |
|
||||
.pol file on disk (and the GPT.ini file) will be updated if _any_ of the specified settings had to be removed, |
|
||||
and will be left alone if the file already did not contain any of those values. |
|
||||
|
|
||||
The Key property could have also been specified via the pipeline objects instead of on the command line, but |
|
||||
since both values shared the same Key, this example shows that you can pass the value in either way. |
|
||||
|
|
||||
.INPUTS |
|
||||
The Key and ValueName properties may be bound via the pipeline by property name. |
|
||||
.OUTPUTS |
|
||||
None. This command does not generate output. |
|
||||
.NOTES |
|
||||
If the specified policy file is already not present in the .pol file, the file will not be modified, and the gpt.ini file will not be updated. |
|
||||
.LINK |
|
||||
Get-PolicyFileEntry |
|
||||
.LINK |
|
||||
Set-PolicyFileEntry |
|
||||
.LINK |
|
||||
Update-GptIniVersion |
|
||||
.LINK |
|
||||
about_RegistryValuesForAdminTemplates |
|
||||
#> |
|
||||
|
|
||||
function Remove-PolicyFileEntry |
|
||||
{ |
|
||||
[CmdletBinding(SupportsShouldProcess = $true)] |
|
||||
param ( |
|
||||
[Parameter(Mandatory = $true, Position = 0)] |
|
||||
[string] $Path, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, Position = 1, ValueFromPipelineByPropertyName = $true)] |
|
||||
[string] $Key, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, Position = 2, ValueFromPipelineByPropertyName = $true)] |
|
||||
[string] $ValueName, |
|
||||
|
|
||||
[switch] $NoGptIniUpdate |
|
||||
) |
|
||||
|
|
||||
begin |
|
||||
{ |
|
||||
if (Get-Command [G]et-CallerPreference -CommandType Function -Module PreferenceVariables) |
|
||||
{ |
|
||||
Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState |
|
||||
} |
|
||||
|
|
||||
$dirty = $false |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
$policyFile = OpenPolicyFile -Path $Path -ErrorAction Stop |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$PSCmdlet.ThrowTerminatingError($_) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
process |
|
||||
{ |
|
||||
$entry = $policyFile.GetValue($Key, $ValueName) |
|
||||
|
|
||||
if ($null -eq $entry) |
|
||||
{ |
|
||||
Write-Verbose "Entry '$Key\$ValueName' is already not present in file '$Path'." |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
Write-Verbose "Removing entry '$Key\$ValueName' from file '$Path'" |
|
||||
$policyFile.DeleteValue($Key, $ValueName) |
|
||||
$dirty = $true |
|
||||
} |
|
||||
|
|
||||
end |
|
||||
{ |
|
||||
if ($dirty) |
|
||||
{ |
|
||||
$doUpdateGptIni = -not $NoGptIniUpdate |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
# SavePolicyFile contains the calls to $PSCmdlet.ShouldProcess, and will inherit our |
|
||||
# WhatIfPreference / ConfirmPreference values from here. |
|
||||
SavePolicyFile -PolicyFile $policyFile -UpdateGptIni:$doUpdateGptIni -ErrorAction Stop |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$PSCmdlet.ThrowTerminatingError($_) |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
<# |
|
||||
.SYNOPSIS |
|
||||
Increments the version counter in a gpt.ini file. |
|
||||
.DESCRIPTION |
|
||||
Increments the version counter in a gpt.ini file. |
|
||||
.PARAMETER Path |
|
||||
Path to the gpt.ini file that is to be modified. |
|
||||
.PARAMETER PolicyType |
|
||||
Can be set to either 'Machine', 'User', or both. This affects how the value of the Version number in the ini file is changed. |
|
||||
.EXAMPLE |
|
||||
Update-GptIniVersion -Path $env:SystemRoot\system32\GroupPolicy\gpt.ini -PolicyType Machine |
|
||||
|
|
||||
Increments the Machine version counter of the local GPO. |
|
||||
.EXAMPLE |
|
||||
Update-GptIniVersion -Path $env:SystemRoot\system32\GroupPolicy\gpt.ini -PolicyType User |
|
||||
|
|
||||
Increments the User version counter of the local GPO. |
|
||||
.EXAMPLE |
|
||||
Update-GptIniVersion -Path $env:SystemRoot\system32\GroupPolicy\gpt.ini -PolicyType Machine,User |
|
||||
|
|
||||
Increments both the Machine and User version counters of the local GPO. |
|
||||
.INPUTS |
|
||||
None. This command does not accept pipeline input. |
|
||||
.OUTPUTS |
|
||||
None. This command does not generate output. |
|
||||
.NOTES |
|
||||
A gpt.ini file contains only a single Version value. However, this represents two separate counters, for machine and user versions. |
|
||||
The high 16 bits of the value are the User counter, and the low 16 bits are the Machine counter. For example (on PowerShell 3.0 |
|
||||
and later), the Version value when the Machine counter is set to 3 and the User counter is set to 5 can be found by evaluating this |
|
||||
expression: (5 -shl 16) -bor 3 , which will show up as decimal value 327683 in the INI file. |
|
||||
.LINK |
|
||||
Get-PolicyFileEntry |
|
||||
.LINK |
|
||||
Set-PolicyFileEntry |
|
||||
.LINK |
|
||||
Remove-PolicyFileEntry |
|
||||
.LINK |
|
||||
about_RegistryValuesForAdminTemplates |
|
||||
#> |
|
||||
|
|
||||
function Update-GptIniVersion |
|
||||
{ |
|
||||
[CmdletBinding(SupportsShouldProcess = $true)] |
|
||||
param ( |
|
||||
[Parameter(Mandatory = $true)] |
|
||||
[ValidateScript({ |
|
||||
if (Test-Path -LiteralPath $_ -PathType Leaf) |
|
||||
{ |
|
||||
return $true |
|
||||
} |
|
||||
|
|
||||
throw "Path '$_' does not exist." |
|
||||
})] |
|
||||
[string] $Path, |
|
||||
|
|
||||
[Parameter(Mandatory = $true)] |
|
||||
[ValidateSet('Machine', 'User')] |
|
||||
[string[]] $PolicyType |
|
||||
) |
|
||||
|
|
||||
if (Get-Command [G]et-CallerPreference -CommandType Function -Module PreferenceVariables) |
|
||||
{ |
|
||||
Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState |
|
||||
} |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
IncrementGptIniVersion @PSBoundParameters |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$PSCmdlet.ThrowTerminatingError($_) |
|
||||
} |
|
||||
} |
|
||||
@ -1,704 +0,0 @@ |
|||||
#requires -Version 2.0 |
|
||||
|
|
||||
$script:MachineExtensionGuids = '[{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F72-3407-48AE-BA88-E8213C6761F1}]' |
|
||||
$script:UserExtensionGuids = '[{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F73-3407-48AE-BA88-E8213C6761F1}]' |
|
||||
|
|
||||
function OpenPolicyFile |
|
||||
{ |
|
||||
[CmdletBinding()] |
|
||||
param ( |
|
||||
[Parameter(Mandatory = $true)] |
|
||||
[string] $Path |
|
||||
) |
|
||||
|
|
||||
$policyFile = New-Object TJX.PolFileEditor.PolFile |
|
||||
$policyFile.FileName = $PSCmdlet.GetUnresolvedProviderPathFromPSPath($Path) |
|
||||
|
|
||||
if (Test-Path -LiteralPath $policyFile.FileName) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
$policyFile.LoadFile() |
|
||||
} |
|
||||
catch [TJX.PolFileEditor.FileFormatException] |
|
||||
{ |
|
||||
$message = "File '$Path' is not a valid POL file." |
|
||||
$exception = New-Object System.Exception($message) |
|
||||
|
|
||||
$errorRecord = New-Object System.Management.Automation.ErrorRecord( |
|
||||
$exception, 'InvalidPolFileContents', [System.Management.Automation.ErrorCategory]::InvalidData, $Path |
|
||||
) |
|
||||
|
|
||||
throw $errorRecord |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$errorRecord = $_ |
|
||||
$message = "Error loading policy file at path '$Path': $($errorRecord.Exception.Message)" |
|
||||
$exception = New-Object System.Exception($message, $errorRecord.Exception) |
|
||||
|
|
||||
$newErrorRecord = New-Object System.Management.Automation.ErrorRecord( |
|
||||
$exception, 'FailedToOpenPolicyFile', [System.Management.Automation.ErrorCategory]::OperationStopped, $Path |
|
||||
) |
|
||||
|
|
||||
throw $newErrorRecord |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return $policyFile |
|
||||
} |
|
||||
|
|
||||
function PolEntryToPsObject |
|
||||
{ |
|
||||
param ( |
|
||||
[TJX.PolFileEditor.PolEntry] $PolEntry |
|
||||
) |
|
||||
|
|
||||
$type = PolEntryTypeToRegistryValueKind $PolEntry.Type |
|
||||
$data = GetEntryData -Entry $PolEntry -Type $type |
|
||||
|
|
||||
return New-Object psobject -Property @{ |
|
||||
Key = $PolEntry.KeyName |
|
||||
ValueName = $PolEntry.ValueName |
|
||||
Type = $type |
|
||||
Data = $data |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function GetEntryData |
|
||||
{ |
|
||||
param ( |
|
||||
[TJX.PolFileEditor.PolEntry] $Entry, |
|
||||
[Microsoft.Win32.RegistryValueKind] $Type |
|
||||
) |
|
||||
|
|
||||
switch ($type) |
|
||||
{ |
|
||||
([Microsoft.Win32.RegistryValueKind]::Binary) |
|
||||
{ |
|
||||
return $Entry.BinaryValue |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::DWord) |
|
||||
{ |
|
||||
return $Entry.DWORDValue |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::ExpandString) |
|
||||
{ |
|
||||
return $Entry.StringValue |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::MultiString) |
|
||||
{ |
|
||||
return $Entry.MultiStringValue |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::QWord) |
|
||||
{ |
|
||||
return $Entry.QWORDValue |
|
||||
} |
|
||||
|
|
||||
([Microsoft.Win32.RegistryValueKind]::String) |
|
||||
{ |
|
||||
return $Entry.StringValue |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
function SavePolicyFile |
|
||||
{ |
|
||||
[CmdletBinding(SupportsShouldProcess = $true)] |
|
||||
param ( |
|
||||
[Parameter(Mandatory = $true)] |
|
||||
[TJX.PolFileEditor.PolFile] $PolicyFile, |
|
||||
|
|
||||
[switch] $UpdateGptIni |
|
||||
) |
|
||||
|
|
||||
if ($PSCmdlet.ShouldProcess($PolicyFile.FileName, 'Save new settings')) |
|
||||
{ |
|
||||
$parentPath = Split-Path $PolicyFile.FileName -Parent |
|
||||
if (-not (Test-Path -LiteralPath $parentPath -PathType Container)) |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
$null = New-Item -Path $parentPath -ItemType Directory -ErrorAction Stop -Confirm:$false -WhatIf:$false |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$errorRecord = $_ |
|
||||
$message = "Error creating parent folder of path '$Path': $($errorRecord.Exception.Message)" |
|
||||
$exception = New-Object System.Exception($message, $errorRecord.Exception) |
|
||||
|
|
||||
$newErrorRecord = New-Object System.Management.Automation.ErrorRecord( |
|
||||
$exception, 'CreateParentFolderError', $errorRecord.CategoryInfo.Category, $Path |
|
||||
) |
|
||||
|
|
||||
throw $newErrorRecord |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
$PolicyFile.SaveFile() |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$errorRecord = $_ |
|
||||
$message = "Error saving policy file to path '$($PolicyFile.FileName)': $($errorRecord.Exception.Message)" |
|
||||
$exception = New-Object System.Exception($message, $errorRecord.Exception) |
|
||||
|
|
||||
$newErrorRecord = New-Object System.Management.Automation.ErrorRecord( |
|
||||
$exception, 'FailedToSavePolicyFile', [System.Management.Automation.ErrorCategory]::OperationStopped, $PolicyFile |
|
||||
) |
|
||||
|
|
||||
throw $newErrorRecord |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if ($UpdateGptIni) |
|
||||
{ |
|
||||
if ($policyFile.FileName -match '^(.*)\\+([^\\]+)\\+[^\\]+$' -and |
|
||||
$Matches[2] -eq 'User' -or $Matches[2] -eq 'Machine') |
|
||||
{ |
|
||||
$iniPath = Join-Path $Matches[1] GPT.ini |
|
||||
|
|
||||
if (Test-Path -LiteralPath $iniPath -PathType Leaf) |
|
||||
{ |
|
||||
if ($PSCmdlet.ShouldProcess($iniPath, 'Increment version number in INI file')) |
|
||||
{ |
|
||||
IncrementGptIniVersion -Path $iniPath -PolicyType $Matches[2] -Confirm:$false -WhatIf:$false |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
if ($PSCmdlet.ShouldProcess($iniPath, 'Create new gpt.ini file')) |
|
||||
{ |
|
||||
NewGptIni -Path $iniPath -PolicyType $Matches[2] |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function NewGptIni |
|
||||
{ |
|
||||
param ( |
|
||||
[string] $Path, |
|
||||
[string[]] $PolicyType |
|
||||
) |
|
||||
|
|
||||
$parent = Split-Path $Path -Parent |
|
||||
|
|
||||
if (-not (Test-Path $parent -PathType Container)) |
|
||||
{ |
|
||||
$null = New-Item -Path $parent -ItemType Directory -ErrorAction Stop |
|
||||
} |
|
||||
|
|
||||
$version = GetNewVersionNumber -Version 0 -PolicyType $PolicyType |
|
||||
|
|
||||
Set-Content -Path $Path -Encoding Ascii -Value @" |
|
||||
[General] |
|
||||
gPCMachineExtensionNames=$script:MachineExtensionGuids |
|
||||
Version=$version |
|
||||
gPCUserExtensionNames=$script:UserExtensionGuids |
|
||||
"@ |
|
||||
} |
|
||||
|
|
||||
function IncrementGptIniVersion |
|
||||
{ |
|
||||
[CmdletBinding(SupportsShouldProcess = $true)] |
|
||||
param ( |
|
||||
[string] $Path, |
|
||||
[string[]] $PolicyType |
|
||||
) |
|
||||
|
|
||||
$foundVersionLine = $false |
|
||||
$section = '' |
|
||||
|
|
||||
$newContents = @( |
|
||||
foreach ($line in Get-Content $Path) |
|
||||
{ |
|
||||
# This might not be the most unreadable regex ever, but it's trying hard to be! |
|
||||
# It's looking for section lines: [SectionName] |
|
||||
if ($line -match '^\s*\[([^\]]+)\]\s*$') |
|
||||
{ |
|
||||
if ($section -eq 'General') |
|
||||
{ |
|
||||
if (-not $foundVersionLine) |
|
||||
{ |
|
||||
$foundVersionLine = $true |
|
||||
$newVersion = GetNewVersionNumber -Version 0 -PolicyType $PolicyType |
|
||||
|
|
||||
"Version=$newVersion" |
|
||||
} |
|
||||
|
|
||||
if (-not $foundMachineExtensionLine) |
|
||||
{ |
|
||||
$foundMachineExtensionLine = $true |
|
||||
"gPCMachineExtensionNames=$script:MachineExtensionGuids" |
|
||||
} |
|
||||
|
|
||||
if (-not $foundUserExtensionLine) |
|
||||
{ |
|
||||
$foundUserExtensionLine = $true |
|
||||
"gPCUserExtensionNames=$script:UserExtensionGuids" |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
$section = $matches[1] |
|
||||
} |
|
||||
elseif ($section -eq 'General' -and |
|
||||
$line -match '^\s*Version\s*=\s*(\d+)\s*$' -and |
|
||||
$null -ne ($version = $matches[1] -as [uint32])) |
|
||||
{ |
|
||||
$foundVersionLine = $true |
|
||||
$newVersion = GetNewVersionNumber -Version $version -PolicyType $PolicyType |
|
||||
$line = "Version=$newVersion" |
|
||||
} |
|
||||
elseif ($section -eq 'General' -and $line -match '^\s*gPC(Machine|User)ExtensionNames\s*=') |
|
||||
{ |
|
||||
if ($matches[1] -eq 'Machine') |
|
||||
{ |
|
||||
$foundMachineExtensionLine = $true |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
$foundUserExtensionLine = $true |
|
||||
} |
|
||||
|
|
||||
$line = EnsureAdminTemplateCseGuidsArePresent $line |
|
||||
} |
|
||||
|
|
||||
$line |
|
||||
} |
|
||||
|
|
||||
if ($section -eq 'General') |
|
||||
{ |
|
||||
if (-not $foundVersionLine) |
|
||||
{ |
|
||||
$foundVersionLine = $true |
|
||||
$newVersion = GetNewVersionNumber -Version 0 -PolicyType $PolicyType |
|
||||
|
|
||||
"Version=$newVersion" |
|
||||
} |
|
||||
|
|
||||
if (-not $foundMachineExtensionLine) |
|
||||
{ |
|
||||
$foundMachineExtensionLine = $true |
|
||||
"gPCMachineExtensionNames=$script:MachineExtensionGuids" |
|
||||
} |
|
||||
|
|
||||
if (-not $foundUserExtensionLine) |
|
||||
{ |
|
||||
$foundUserExtensionLine = $true |
|
||||
"gPCUserExtensionNames=$script:MachineExtensionGuids" |
|
||||
} |
|
||||
} |
|
||||
) |
|
||||
|
|
||||
if ($PSCmdlet.ShouldProcess($Path, 'Increment Version number')) |
|
||||
{ |
|
||||
Set-Content -Path $Path -Value $newContents -Encoding Ascii -Confirm:$false -WhatIf:$false |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function EnsureAdminTemplateCseGuidsArePresent |
|
||||
{ |
|
||||
param ([string] $Line) |
|
||||
|
|
||||
# These lines contain pairs of GUIDs in "registry" format (with the curly braces), separated by nothing, with |
|
||||
# each pair of GUIDs wrapped in square brackets. Example: |
|
||||
|
|
||||
# gPCMachineExtensionNames=[{35378EAC-683F-11D2-A89A-00C04FBBCFA2}{D02B1F72-3407-48AE-BA88-E8213C6761F1}] |
|
||||
|
|
||||
# Per Darren Mar-Elia, these GUIDs must be in alphabetical order, or GP processing will have problems. |
|
||||
|
|
||||
if ($Line -notmatch '\s*(gPC(?:Machine|User)ExtensionNames)\s*=\s*(.*)$') |
|
||||
{ |
|
||||
throw "Malformed gpt.ini line: $Line" |
|
||||
} |
|
||||
|
|
||||
$valueName = $matches[1] |
|
||||
$guidStrings = @($matches[2] -split '(?<=\])(?=\[)') |
|
||||
|
|
||||
if ($matches[1] -eq 'gPCMachineExtensionNames') |
|
||||
{ |
|
||||
$toolExtensionGuid = $script:MachineExtensionGuids |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
$toolExtensionGuid = $script:UserExtensionGuids |
|
||||
} |
|
||||
|
|
||||
$guidList = @( |
|
||||
$guidStrings |
|
||||
$toolExtensionGuid |
|
||||
) |
|
||||
|
|
||||
$newGuidString = ($guidList | Sort-Object -Unique) -join '' |
|
||||
|
|
||||
return "$valueName=$newGuidString" |
|
||||
} |
|
||||
|
|
||||
function GetNewVersionNumber |
|
||||
{ |
|
||||
param ( |
|
||||
[UInt32] $Version, |
|
||||
[string[]] $PolicyType |
|
||||
) |
|
||||
|
|
||||
# User version is the high 16 bits, Machine version is the low 16 bits. |
|
||||
# Reference: http://blogs.technet.com/b/grouppolicy/archive/2007/12/14/understanding-the-gpo-version-number.aspx |
|
||||
|
|
||||
$pair = UInt32ToUInt16Pair -UInt32 $version |
|
||||
|
|
||||
if ($PolicyType -contains 'User') |
|
||||
{ |
|
||||
$pair.HighPart++ |
|
||||
} |
|
||||
|
|
||||
if ($PolicyType -contains 'Machine') |
|
||||
{ |
|
||||
$pair.LowPart++ |
|
||||
} |
|
||||
|
|
||||
return UInt16PairToUInt32 -UInt16Pair $pair |
|
||||
} |
|
||||
|
|
||||
function UInt32ToUInt16Pair |
|
||||
{ |
|
||||
param ([UInt32] $UInt32) |
|
||||
|
|
||||
# Deliberately avoiding bitwise shift operators here, for PowerShell v2 compatibility. |
|
||||
|
|
||||
$lowPart = $UInt32 -band 0xFFFF |
|
||||
$highPart = ($UInt32 - $lowPart) / 0x10000 |
|
||||
|
|
||||
return New-Object psobject -Property @{ |
|
||||
LowPart = [UInt16] $lowPart |
|
||||
HighPart = [UInt16] $highPart |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function UInt16PairToUInt32 |
|
||||
{ |
|
||||
param ([object] $UInt16Pair) |
|
||||
|
|
||||
# Deliberately avoiding bitwise shift operators here, for PowerShell v2 compatibility. |
|
||||
|
|
||||
return ([UInt32] $UInt16Pair.HighPart) * 0x10000 + $UInt16Pair.LowPart |
|
||||
} |
|
||||
|
|
||||
function PolEntryTypeToRegistryValueKind |
|
||||
{ |
|
||||
param ([TJX.PolFileEditor.PolEntryType] $PolEntryType) |
|
||||
|
|
||||
switch ($PolEntryType) |
|
||||
{ |
|
||||
([TJX.PolFileEditor.PolEntryType]::REG_NONE) |
|
||||
{ |
|
||||
return [Microsoft.Win32.RegistryValueKind]::None |
|
||||
} |
|
||||
|
|
||||
([TJX.PolFileEditor.PolEntryType]::REG_DWORD) |
|
||||
{ |
|
||||
return [Microsoft.Win32.RegistryValueKind]::DWord |
|
||||
} |
|
||||
|
|
||||
([TJX.PolFileEditor.PolEntryType]::REG_DWORD_BIG_ENDIAN) |
|
||||
{ |
|
||||
return [Microsoft.Win32.RegistryValueKind]::DWord |
|
||||
} |
|
||||
|
|
||||
([TJX.PolFileEditor.PolEntryType]::REG_BINARY) |
|
||||
{ |
|
||||
return [Microsoft.Win32.RegistryValueKind]::Binary |
|
||||
} |
|
||||
|
|
||||
([TJX.PolFileEditor.PolEntryType]::REG_EXPAND_SZ) |
|
||||
{ |
|
||||
return [Microsoft.Win32.RegistryValueKind]::ExpandString |
|
||||
} |
|
||||
|
|
||||
([TJX.PolFileEditor.PolEntryType]::REG_MULTI_SZ) |
|
||||
{ |
|
||||
return [Microsoft.Win32.RegistryValueKind]::MultiString |
|
||||
} |
|
||||
|
|
||||
([TJX.PolFileEditor.PolEntryType]::REG_QWORD) |
|
||||
{ |
|
||||
return [Microsoft.Win32.RegistryValueKind]::QWord |
|
||||
} |
|
||||
|
|
||||
([TJX.PolFileEditor.PolEntryType]::REG_SZ) |
|
||||
{ |
|
||||
return [Microsoft.Win32.RegistryValueKind]::String |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function GetPolFilePath |
|
||||
{ |
|
||||
param ( |
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'PolicyType')] |
|
||||
[string] $PolicyType, |
|
||||
|
|
||||
[Parameter(Mandatory = $true, ParameterSetName = 'Account')] |
|
||||
[string] $Account |
|
||||
) |
|
||||
|
|
||||
if ($PolicyType) |
|
||||
{ |
|
||||
switch ($PolicyType) |
|
||||
{ |
|
||||
'Machine' |
|
||||
{ |
|
||||
return Join-Path $env:SystemRoot System32\GroupPolicy\Machine\registry.pol |
|
||||
} |
|
||||
|
|
||||
'User' |
|
||||
{ |
|
||||
return Join-Path $env:SystemRoot System32\GroupPolicy\User\registry.pol |
|
||||
} |
|
||||
|
|
||||
'Administrators' |
|
||||
{ |
|
||||
# BUILTIN\Administrators well-known SID |
|
||||
return Join-Path $env:SystemRoot System32\GroupPolicyUsers\S-1-5-32-544\User\registry.pol |
|
||||
} |
|
||||
|
|
||||
'NonAdministrators' |
|
||||
{ |
|
||||
# BUILTIN\Users well-known SID |
|
||||
return Join-Path $env:SystemRoot System32\GroupPolicyUsers\S-1-5-32-545\User\registry.pol |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
try |
|
||||
{ |
|
||||
$sid = $Account -as [System.Security.Principal.SecurityIdentifier] |
|
||||
|
|
||||
if ($null -eq $sid) |
|
||||
{ |
|
||||
$sid = GetSidForAccount $Account |
|
||||
} |
|
||||
|
|
||||
return Join-Path $env:SystemRoot "System32\GroupPolicyUsers\$($sid.Value)\User\registry.pol" |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
throw |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function GetSidForAccount($Account) |
|
||||
{ |
|
||||
$acc = $Account |
|
||||
if ($acc -notlike '*\*') { $acc = "$env:COMPUTERNAME\$acc" } |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
$ntAccount = [System.Security.Principal.NTAccount]$acc |
|
||||
return $ntAccount.Translate([System.Security.Principal.SecurityIdentifier]) |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
$message = "Could not translate account '$acc' to a security identifier." |
|
||||
$exception = New-Object System.Exception($message, $_.Exception) |
|
||||
$errorRecord = New-Object System.Management.Automation.ErrorRecord( |
|
||||
$exception, |
|
||||
'CouldNotGetSidForAccount', |
|
||||
[System.Management.Automation.ErrorCategory]::ObjectNotFound, |
|
||||
$Acc |
|
||||
) |
|
||||
|
|
||||
throw $errorRecord |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function DataIsEqual |
|
||||
{ |
|
||||
param ( |
|
||||
[object] $First, |
|
||||
[object] $Second, |
|
||||
[Microsoft.Win32.RegistryValueKind] $Type |
|
||||
) |
|
||||
|
|
||||
if ($Type -eq [Microsoft.Win32.RegistryValueKind]::String -or |
|
||||
$Type -eq [Microsoft.Win32.RegistryValueKind]::ExpandString -or |
|
||||
$Type -eq [Microsoft.Win32.RegistryValueKind]::DWord -or |
|
||||
$Type -eq [Microsoft.Win32.RegistryValueKind]::QWord) |
|
||||
{ |
|
||||
return @($First)[0] -ceq @($Second)[0] |
|
||||
} |
|
||||
|
|
||||
# If we get here, $Type is either MultiString or Binary, both of which need to compare arrays. |
|
||||
# The PolicyFileEditor module never returns type Unknown or None. |
|
||||
|
|
||||
$First = @($First) |
|
||||
$Second = @($Second) |
|
||||
|
|
||||
if ($First.Count -ne $Second.Count) { return $false } |
|
||||
|
|
||||
$count = $First.Count |
|
||||
for ($i = 0; $i -lt $count; $i++) |
|
||||
{ |
|
||||
if ($First[$i] -cne $Second[$i]) { return $false } |
|
||||
} |
|
||||
|
|
||||
return $true |
|
||||
} |
|
||||
|
|
||||
function ParseKeyValueName |
|
||||
{ |
|
||||
param ([string] $KeyValueName) |
|
||||
|
|
||||
$key = $KeyValueName -replace '^\\+|\\+$' |
|
||||
$valueName = '' |
|
||||
|
|
||||
if ($KeyValueName -match '^\\*(?<Key>.+?)\\+(?<ValueName>[^\\]*)$') |
|
||||
{ |
|
||||
$key = $matches['Key'] -replace '\\{2,}', '\' |
|
||||
$valueName = $matches['ValueName'] |
|
||||
} |
|
||||
|
|
||||
return $key, $valueName |
|
||||
} |
|
||||
|
|
||||
function GetTargetResourceCommon |
|
||||
{ |
|
||||
param ( |
|
||||
[string] $Path, |
|
||||
[string] $KeyValueName |
|
||||
) |
|
||||
|
|
||||
$configuration = @{ |
|
||||
KeyValueName = $KeyValueName |
|
||||
Ensure = 'Absent' |
|
||||
Data = $null |
|
||||
Type = [Microsoft.Win32.RegistryValueKind]::Unknown |
|
||||
} |
|
||||
|
|
||||
if (Test-Path -LiteralPath $path -PathType Leaf) |
|
||||
{ |
|
||||
$key, $valueName = ParseKeyValueName $KeyValueName |
|
||||
$entry = Get-PolicyFileEntry -Path $Path -Key $key -ValueName $valueName |
|
||||
|
|
||||
if ($entry) |
|
||||
{ |
|
||||
$configuration['Ensure'] = 'Present' |
|
||||
$configuration['Type'] = $entry.Type |
|
||||
$configuration['Data'] = @($entry.Data) |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return $configuration |
|
||||
} |
|
||||
|
|
||||
function SetTargetResourceCommon |
|
||||
{ |
|
||||
param ( |
|
||||
[string] $Path, |
|
||||
[string] $KeyValueName, |
|
||||
[string] $Ensure, |
|
||||
[string[]] $Data, |
|
||||
[Microsoft.Win32.RegistryValueKind] $Type |
|
||||
) |
|
||||
|
|
||||
if ($null -eq $Data) { $Data = @() } |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
Assert-ValidDataAndType -Data $Data -Type $Type |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
Write-Error -ErrorRecord $_ |
|
||||
return |
|
||||
} |
|
||||
|
|
||||
$key, $valueName = ParseKeyValueName $KeyValueName |
|
||||
|
|
||||
if ($Ensure -eq 'Present') |
|
||||
{ |
|
||||
Set-PolicyFileEntry -Path $Path -Key $key -ValueName $valueName -Data $Data -Type $Type |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
Remove-PolicyFileEntry -Path $Path -Key $key -ValueName $valueName |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function TestTargetResourceCommon |
|
||||
{ |
|
||||
[OutputType([bool])] |
|
||||
param ( |
|
||||
[string] $Path, |
|
||||
[string] $KeyValueName, |
|
||||
[string] $Ensure, |
|
||||
[string[]] $Data, |
|
||||
[Microsoft.Win32.RegistryValueKind] $Type |
|
||||
) |
|
||||
|
|
||||
if ($null -eq $Data) { $Data = @() } |
|
||||
|
|
||||
try |
|
||||
{ |
|
||||
Assert-ValidDataAndType -Data $Data -Type $Type |
|
||||
} |
|
||||
catch |
|
||||
{ |
|
||||
Write-Error -ErrorRecord $_ |
|
||||
return $false |
|
||||
} |
|
||||
|
|
||||
$key, $valueName = ParseKeyValueName $KeyValueName |
|
||||
|
|
||||
$fileExists = Test-Path -LiteralPath $Path -PathType Leaf |
|
||||
|
|
||||
if ($Ensure -eq 'Present') |
|
||||
{ |
|
||||
if (-not $fileExists) { return $false } |
|
||||
$entry = Get-PolicyFileEntry -Path $Path -Key $key -ValueName $valueName |
|
||||
|
|
||||
return $null -ne $entry -and $Type -eq $entry.Type -and (DataIsEqual $entry.Data $Data -Type $Type) |
|
||||
} |
|
||||
else # Ensure is 'Absent' |
|
||||
{ |
|
||||
if (-not $fileExists) { return $true } |
|
||||
$entry = Get-PolicyFileEntry -Path $Path -Key $key -ValueName $valueName |
|
||||
|
|
||||
return $null -eq $entry |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
function Assert-ValidDataAndType |
|
||||
{ |
|
||||
param ( |
|
||||
[string[]] $Data, |
|
||||
[Microsoft.Win32.RegistryValueKind] $Type |
|
||||
) |
|
||||
|
|
||||
if ($Type -ne [Microsoft.Win32.RegistryValueKind]::MultiString -and |
|
||||
$Type -ne [Microsoft.Win32.RegistryValueKind]::Binary -and |
|
||||
$Data.Count -gt 1) |
|
||||
{ |
|
||||
$errorRecord = InvalidDataTypeCombinationErrorRecord -Message 'Do not pass arrays with multiple values to the -Data parameter when -Type is not set to either Binary or MultiString.' |
|
||||
throw $errorRecord |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
function InvalidDataTypeCombinationErrorRecord($Message) |
|
||||
{ |
|
||||
$exception = New-Object System.Exception($Message) |
|
||||
return New-Object System.Management.Automation.ErrorRecord( |
|
||||
$exception, 'InvalidDataTypeCombination', [System.Management.Automation.ErrorCategory]::InvalidArgument, $null |
|
||||
) |
|
||||
} |
|
||||
Binary file not shown.
@ -1,43 +0,0 @@ |
|||||
@{ |
|
||||
ModuleToProcess = 'PolicyFileEditor.psm1' |
|
||||
ModuleVersion = '3.0.1' |
|
||||
GUID = '110a2398-3053-4ffc-89d1-1b6a38a2dc86' |
|
||||
Author = 'Dave Wyatt' |
|
||||
CompanyName = 'Home' |
|
||||
Copyright = '(c) 2015 Dave Wyatt. All rights reserved.' |
|
||||
Description = 'Commands and DSC resource for modifying Administrative Templates settings in local GPO registry.pol files.' |
|
||||
PowerShellVersion = '2.0' |
|
||||
# PowerShellHostName = '' |
|
||||
# PowerShellHostVersion = '' |
|
||||
DotNetFrameworkVersion = '2.0' |
|
||||
# CLRVersion = '' |
|
||||
# ProcessorArchitecture = '' |
|
||||
# RequiredModules = @() |
|
||||
# RequiredAssemblies = @() |
|
||||
# ScriptsToProcess = @() |
|
||||
# TypesToProcess = @() |
|
||||
# FormatsToProcess = @() |
|
||||
# NestedModules = @() |
|
||||
FunctionsToExport = @('Set-PolicyFileEntry', 'Remove-PolicyFileEntry', 'Get-PolicyFileEntry', 'Update-GptIniVersion') |
|
||||
# CmdletsToExport = '*' |
|
||||
# VariablesToExport = '*' |
|
||||
# AliasesToExport = '*' |
|
||||
# DscResourcesToExport = @() |
|
||||
# ModuleList = @() |
|
||||
# FileList = @() |
|
||||
|
|
||||
# HelpInfoURI = '' |
|
||||
|
|
||||
# DefaultCommandPrefix = '' |
|
||||
|
|
||||
PrivateData = @{ |
|
||||
PSData = @{ |
|
||||
# Tags = @() |
|
||||
LicenseUri = 'https://www.apache.org/licenses/LICENSE-2.0.html' |
|
||||
ProjectUri = 'https://github.com/dlwyatt/PolicyFileEditor' |
|
||||
# IconUri = '' |
|
||||
ReleaseNotes = 'Updated resource schemas to be more friendly with Invoke-DscResource.' |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
@ -1,10 +0,0 @@ |
|||||
#requires -Version 2.0 |
|
||||
|
|
||||
$scriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent |
|
||||
$dllPath = Join-Path $scriptRoot PolFileEditor.dll |
|
||||
|
|
||||
Add-Type -Path $dllPath -ErrorAction Stop |
|
||||
|
|
||||
$commandsFile = Join-Path $scriptRoot Commands.ps1 |
|
||||
|
|
||||
. $commandsFile |
|
||||
Loading…
Reference in new issue