AuditPolicy.psm1
function ConvertFrom-SID { <# .SYNOPSIS Small command that can resolve SID values .DESCRIPTION Small command that can resolve SID values .PARAMETER SID Value to resolve .PARAMETER OnlyWellKnown Only resolve SID when it's well know SID. Otherwise return $null .PARAMETER OnlyWellKnownAdministrative Only resolve SID when it's administrative well know SID. Otherwise return $null .PARAMETER DoNotResolve Uses only dicrionary values without querying AD .EXAMPLE ConvertFrom-SID -SID 'S-1-5-8', 'S-1-5-9', 'S-1-5-11', 'S-1-5-18', 'S-1-1-0' -DoNotResolve .NOTES General notes #> [cmdletbinding(DefaultParameterSetName = 'Standard')] param([Parameter(ParameterSetName = 'Standard')] [Parameter(ParameterSetName = 'OnlyWellKnown')] [Parameter(ParameterSetName = 'OnlyWellKnownAdministrative')] [string[]] $SID, [Parameter(ParameterSetName = 'OnlyWellKnown')][switch] $OnlyWellKnown, [Parameter(ParameterSetName = 'OnlyWellKnownAdministrative')][switch] $OnlyWellKnownAdministrative, [Parameter(ParameterSetName = 'Standard')][switch] $DoNotResolve) $WellKnownAdministrative = @{'S-1-5-18' = [PSCustomObject] @{Name = 'NT AUTHORITY\SYSTEM' SID = 'S-1-5-18' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'S-1-5-32-544' = [PSCustomObject] @{Name = 'BUILTIN\Administrators' SID = 'S-1-5-32-544' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } } $wellKnownSIDs = @{'S-1-0' = [PSCustomObject] @{Name = 'Null AUTHORITY' SID = 'S-1-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-0-0' = [PSCustomObject] @{Name = 'NULL SID' SID = 'S-1-0-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-1' = [PSCustomObject] @{Name = 'WORLD AUTHORITY' SID = 'S-1-1' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-1-0' = [PSCustomObject] @{Name = 'Everyone' SID = 'S-1-1-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-2' = [PSCustomObject] @{Name = 'LOCAL AUTHORITY' SID = 'S-1-2' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-2-0' = [PSCustomObject] @{Name = 'LOCAL' SID = 'S-1-2-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-2-1' = [PSCustomObject] @{Name = 'CONSOLE LOGON' SID = 'S-1-2-1' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3' = [PSCustomObject] @{Name = 'CREATOR AUTHORITY' SID = 'S-1-3' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3-0' = [PSCustomObject] @{Name = 'CREATOR OWNER' SID = 'S-1-3-0' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'S-1-3-1' = [PSCustomObject] @{Name = 'CREATOR GROUP' SID = 'S-1-3-1' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3-2' = [PSCustomObject] @{Name = 'CREATOR OWNER SERVER' SID = 'S-1-3-2' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3-3' = [PSCustomObject] @{Name = 'CREATOR GROUP SERVER' SID = 'S-1-3-3' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-3-4' = [PSCustomObject] @{Name = 'OWNER RIGHTS' SID = 'S-1-3-4' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80-0' = [PSCustomObject] @{Name = 'NT SERVICE\ALL SERVICES' SID = 'S-1-5-80-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-4' = [PSCustomObject] @{Name = 'Non-unique Authority' SID = 'S-1-4' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5' = [PSCustomObject] @{Name = 'NT AUTHORITY' SID = 'S-1-5' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-1' = [PSCustomObject] @{Name = 'NT AUTHORITY\DIALUP' SID = 'S-1-5-1' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-2' = [PSCustomObject] @{Name = 'NT AUTHORITY\NETWORK' SID = 'S-1-5-2' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-3' = [PSCustomObject] @{Name = 'NT AUTHORITY\BATCH' SID = 'S-1-5-3' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-4' = [PSCustomObject] @{Name = 'NT AUTHORITY\INTERACTIVE' SID = 'S-1-5-4' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-6' = [PSCustomObject] @{Name = 'NT AUTHORITY\SERVICE' SID = 'S-1-5-6' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-7' = [PSCustomObject] @{Name = 'NT AUTHORITY\ANONYMOUS LOGON' SID = 'S-1-5-7' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-8' = [PSCustomObject] @{Name = 'NT AUTHORITY\PROXY' SID = 'S-1-5-8' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-9' = [PSCustomObject] @{Name = 'NT AUTHORITY\ENTERPRISE DOMAIN CONTROLLERS' SID = 'S-1-5-9' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-10' = [PSCustomObject] @{Name = 'NT AUTHORITY\SELF' SID = 'S-1-5-10' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-11' = [PSCustomObject] @{Name = 'NT AUTHORITY\Authenticated Users' SID = 'S-1-5-11' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-12' = [PSCustomObject] @{Name = 'NT AUTHORITY\RESTRICTED' SID = 'S-1-5-12' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-13' = [PSCustomObject] @{Name = 'NT AUTHORITY\TERMINAL SERVER USER' SID = 'S-1-5-13' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-14' = [PSCustomObject] @{Name = 'NT AUTHORITY\REMOTE INTERACTIVE LOGON' SID = 'S-1-5-14' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-15' = [PSCustomObject] @{Name = 'NT AUTHORITY\This Organization' SID = 'S-1-5-15' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-17' = [PSCustomObject] @{Name = 'NT AUTHORITY\IUSR' SID = 'S-1-5-17' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-18' = [PSCustomObject] @{Name = 'NT AUTHORITY\SYSTEM' SID = 'S-1-5-18' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'S-1-5-19' = [PSCustomObject] @{Name = 'NT AUTHORITY\NETWORK SERVICE' SID = 'S-1-5-19' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-20' = [PSCustomObject] @{Name = 'NT AUTHORITY\NETWORK SERVICE' SID = 'S-1-5-20' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-544' = [PSCustomObject] @{Name = 'BUILTIN\Administrators' SID = 'S-1-5-32-544' DomainName = '' Type = 'WellKnownAdministrative' Error = '' } 'S-1-5-32-545' = [PSCustomObject] @{Name = 'BUILTIN\Users' SID = 'S-1-5-32-545' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-546' = [PSCustomObject] @{Name = 'BUILTIN\Guests' SID = 'S-1-5-32-546' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-547' = [PSCustomObject] @{Name = 'BUILTIN\Power Users' SID = 'S-1-5-32-547' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-548' = [PSCustomObject] @{Name = 'BUILTIN\Account Operators' SID = 'S-1-5-32-548' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-549' = [PSCustomObject] @{Name = 'BUILTIN\Server Operators' SID = 'S-1-5-32-549' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-550' = [PSCustomObject] @{Name = 'BUILTIN\Print Operators' SID = 'S-1-5-32-550' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-551' = [PSCustomObject] @{Name = 'BUILTIN\Backup Operators' SID = 'S-1-5-32-551' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-552' = [PSCustomObject] @{Name = 'BUILTIN\Replicators' SID = 'S-1-5-32-552' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-64-10' = [PSCustomObject] @{Name = 'NT AUTHORITY\NTLM Authentication' SID = 'S-1-5-64-10' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-64-14' = [PSCustomObject] @{Name = 'NT AUTHORITY\SChannel Authentication' SID = 'S-1-5-64-14' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-64-21' = [PSCustomObject] @{Name = 'NT AUTHORITY\Digest Authentication' SID = 'S-1-5-64-21' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-80' = [PSCustomObject] @{Name = 'NT SERVICE' SID = 'S-1-5-80' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-83-0' = [PSCustomObject] @{Name = 'NT VIRTUAL MACHINE\Virtual Machines' SID = 'S-1-5-83-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-0' = [PSCustomObject] @{Name = 'Untrusted Mandatory Level' SID = 'S-1-16-0' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-4096' = [PSCustomObject] @{Name = 'Low Mandatory Level' SID = 'S-1-16-4096' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-8192' = [PSCustomObject] @{Name = 'Medium Mandatory Level' SID = 'S-1-16-8192' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-8448' = [PSCustomObject] @{Name = 'Medium Plus Mandatory Level' SID = 'S-1-16-8448' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-12288' = [PSCustomObject] @{Name = 'High Mandatory Level' SID = 'S-1-16-12288' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-16384' = [PSCustomObject] @{Name = 'System Mandatory Level' SID = 'S-1-16-16384' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-20480' = [PSCustomObject] @{Name = 'Protected Process Mandatory Level' SID = 'S-1-16-20480' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-16-28672' = [PSCustomObject] @{Name = 'Secure Process Mandatory Level' SID = 'S-1-16-28672' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-554' = [PSCustomObject] @{Name = 'BUILTIN\Pre-Windows 2000 Compatible Access' SID = 'S-1-5-32-554' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-555' = [PSCustomObject] @{Name = 'BUILTIN\Remote Desktop Users' SID = 'S-1-5-32-555' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-556' = [PSCustomObject] @{Name = 'BUILTIN\Network Configuration Operators' SID = 'S-1-5-32-556' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-557' = [PSCustomObject] @{Name = 'BUILTIN\Incoming Forest Trust Builders' SID = 'S-1-5-32-557' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-558' = [PSCustomObject] @{Name = 'BUILTIN\Performance Monitor Users' SID = 'S-1-5-32-558' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-559' = [PSCustomObject] @{Name = 'BUILTIN\Performance Log Users' SID = 'S-1-5-32-559' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-560' = [PSCustomObject] @{Name = 'BUILTIN\Windows Authorization Access Group' SID = 'S-1-5-32-560' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-561' = [PSCustomObject] @{Name = 'BUILTIN\Terminal Server License Servers' SID = 'S-1-5-32-561' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-562' = [PSCustomObject] @{Name = 'BUILTIN\Distributed COM Users' SID = 'S-1-5-32-562' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-569' = [PSCustomObject] @{Name = 'BUILTIN\Cryptographic Operators' SID = 'S-1-5-32-569' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-573' = [PSCustomObject] @{Name = 'BUILTIN\Event Log Readers' SID = 'S-1-5-32-573' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-574' = [PSCustomObject] @{Name = 'BUILTIN\Certificate Service DCOM Access' SID = 'S-1-5-32-574' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-575' = [PSCustomObject] @{Name = 'BUILTIN\RDS Remote Access Servers' SID = 'S-1-5-32-575' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-576' = [PSCustomObject] @{Name = 'BUILTIN\RDS Endpoint Servers' SID = 'S-1-5-32-576' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-577' = [PSCustomObject] @{Name = 'BUILTIN\RDS Management Servers' SID = 'S-1-5-32-577' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-578' = [PSCustomObject] @{Name = 'BUILTIN\Hyper-V Administrators' SID = 'S-1-5-32-578' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-579' = [PSCustomObject] @{Name = 'BUILTIN\Access Control Assistance Operators' SID = 'S-1-5-32-579' DomainName = '' Type = 'WellKnownGroup' Error = '' } 'S-1-5-32-580' = [PSCustomObject] @{Name = 'BUILTIN\Remote Management Users' SID = 'S-1-5-32-580' DomainName = '' Type = 'WellKnownGroup' Error = '' } } foreach ($S in $SID) { if ($OnlyWellKnownAdministrative) { if ($WellKnownAdministrative[$S]) { $WellKnownAdministrative[$S] } } elseif ($OnlyWellKnown) { if ($wellKnownSIDs[$S]) { $wellKnownSIDs[$S] } } else { if ($wellKnownSIDs[$S]) { $wellKnownSIDs[$S] } else { if ($DoNotResolve) { if ($S -like "S-1-5-21-*-519" -or $S -like "S-1-5-21-*-512") { [PSCustomObject] @{Name = $S SID = $S DomainName = '' Type = 'Administrative' Error = '' } } else { [PSCustomObject] @{Name = $S SID = $S DomainName = '' Error = '' Type = 'NotAdministrative' } } } else { try { if ($S -like "S-1-5-21-*-519" -or $S -like "S-1-5-21-*-512") { $Type = 'Administrative' } else { $Type = 'NotAdministrative' } $Name = (([System.Security.Principal.SecurityIdentifier]::new($S)).Translate([System.Security.Principal.NTAccount])).Value [PSCustomObject] @{Name = $Name SID = $S DomainName = (ConvertFrom-NetbiosName -Identity $Name).DomainName Type = $Type Error = '' } } catch { [PSCustomObject] @{Name = $S SID = $S DomainName = '' Error = $_.Exception.Message -replace [environment]::NewLine, ' ' Type = 'Unknown' } } } } } } } function ConvertTo-JsonLiteral { <# .SYNOPSIS Converts an object to a JSON-formatted string. .DESCRIPTION The ConvertTo-Json cmdlet converts any object to a string in JavaScript Object Notation (JSON) format. The properties are converted to field names, the field values are converted to property values, and the methods are removed. .PARAMETER Object Specifies the objects to convert to JSON format. Enter a variable that contains the objects, or type a command or expression that gets the objects. You can also pipe an object to ConvertTo-JsonLiteral .PARAMETER Depth Specifies how many levels of contained objects are included in the JSON representation. The default value is 0. .PARAMETER AsArray Outputs the object in array brackets, even if the input is a single object. .PARAMETER DateTimeFormat Changes DateTime string format. Default "yyyy-MM-dd HH:mm:ss" .PARAMETER NumberAsString Provides an alternative serialization option that converts all numbers to their string representation. .PARAMETER BoolAsString Provides an alternative serialization option that converts all bool to their string representation. .PARAMETER PropertyName Uses PropertyNames provided by user (only works with Force) .PARAMETER NewLineFormat Provides a way to configure how new lines are converted for property names .PARAMETER NewLineFormatProperty Provides a way to configure how new lines are converted for values .PARAMETER PropertyName Allows passing property names to be used for custom objects (hashtables and alike are unaffected) .PARAMETER ArrayJoin Forces any array to be a string regardless of depth level .PARAMETER ArrayJoinString Uses defined string or char for array join. By default it uses comma with a space when used. .PARAMETER Force Forces using property names from first object or given thru PropertyName parameter .EXAMPLE Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral .EXAMPLE Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -Depth 3 .EXAMPLE Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NewLineFormat $NewLineFormat = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" } -NumberAsString -BoolAsString .EXAMPLE Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NumberAsString -BoolAsString -DateTimeFormat "yyyy-MM-dd HH:mm:ss" .EXAMPLE # Keep in mind this advanced replace will break ConvertFrom-Json, but it's sometimes useful for projects like PSWriteHTML Get-Process | Select-Object -First 2 | ConvertTo-JsonLiteral -NewLineFormat $NewLineFormat = @{ NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" } -NumberAsString -BoolAsString -AdvancedReplace @{ '.' = '\.'; '$' = '\$' } .NOTES General notes #> [cmdletBinding()] param([alias('InputObject')][Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0, Mandatory)][Array] $Object, [int] $Depth, [switch] $AsArray, [string] $DateTimeFormat = "yyyy-MM-dd HH:mm:ss", [switch] $NumberAsString, [switch] $BoolAsString, [System.Collections.IDictionary] $NewLineFormat = @{NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $NewLineFormatProperty = @{NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $AdvancedReplace, [string] $ArrayJoinString, [switch] $ArrayJoin, [string[]]$PropertyName, [switch] $Force) Begin { $TextBuilder = [System.Text.StringBuilder]::new() $CountObjects = 0 filter IsNumeric() { return $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] } filter IsOfType() { return $_ -is [bool] -or $_ -is [char] -or $_ -is [datetime] -or $_ -is [string] -or $_ -is [timespan] -or $_ -is [URI] -or $_ -is [byte] -or $_ -is [int16] -or $_ -is [int32] -or $_ -is [int64] -or $_ -is [sbyte] -or $_ -is [uint16] -or $_ -is [uint32] -or $_ -is [uint64] -or $_ -is [float] -or $_ -is [double] -or $_ -is [decimal] } [int] $MaxDepth = $Depth [int] $InitialDepth = 0 } Process { for ($a = 0; $a -lt $Object.Count; $a++) { $CountObjects++ if ($CountObjects -gt 1) { $null = $TextBuilder.Append(',') } if ($Object[$a] -is [System.Collections.IDictionary]) { $null = $TextBuilder.AppendLine("{") for ($i = 0; $i -lt ($Object[$a].Keys).Count; $i++) { $Property = ([string[]]$Object[$a].Keys)[$i] $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $null = $TextBuilder.Append("`"$DisplayProperty`":") $Value = ConvertTo-StringByType -Value $Object[$a][$Property] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace $null = $TextBuilder.Append("$Value") if ($i -ne ($Object[$a].Keys).Count - 1) { $null = $TextBuilder.AppendLine(',') } } $null = $TextBuilder.Append("}") } elseif ($Object[$a] | IsOfType) { $Value = ConvertTo-StringByType -Value $Object[$a] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace $null = $TextBuilder.Append($Value) } else { $null = $TextBuilder.AppendLine("{") if ($Force -and -not $PropertyName) { $PropertyName = $Object[0].PSObject.Properties.Name } elseif ($Force -and $PropertyName) {} else { $PropertyName = $Object[$a].PSObject.Properties.Name } $PropertyCount = 0 foreach ($Property in $PropertyName) { $PropertyCount++ $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $null = $TextBuilder.Append("`"$DisplayProperty`":") $Value = ConvertTo-StringByType -Value $Object[$a].$Property -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $InitialDepth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -NewLineFormat $NewLineFormat -NewLineFormatProperty $NewLineFormatProperty -Force:$Force -ArrayJoin:$ArrayJoin -ArrayJoinString $ArrayJoinString -AdvancedReplace $AdvancedReplace $null = $TextBuilder.Append("$Value") if ($PropertyCount -ne $PropertyName.Count) { $null = $TextBuilder.AppendLine(',') } } $null = $TextBuilder.Append("}") } $InitialDepth = 0 } } End { if ($CountObjects -gt 1 -or $AsArray) { "[$($TextBuilder.ToString())]" } else { $TextBuilder.ToString() } } } function Get-PSRegistry { <# .SYNOPSIS Get registry key values. .DESCRIPTION Get registry key values. .PARAMETER RegistryPath The registry path to get the values from. .PARAMETER ComputerName The computer to get the values from. If not specified, the local computer is used. .EXAMPLE Get-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters' -ComputerName AD1 .EXAMPLE Get-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters' .EXAMPLE Get-PSRegistry -RegistryPath "HKLM\SYSTEM\CurrentControlSet\Services\DFSR\Parameters" -ComputerName AD1,AD2,AD3 | ft -AutoSize .EXAMPLE Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Directory Service' .EXAMPLE Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Windows PowerShell' | Format-Table -AutoSize .EXAMPLE Get-PSRegistry -RegistryPath 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\Directory Service' -ComputerName AD1 -Advanced .EXAMPLE Get-PSRegistry -RegistryPath "HKLM:\Software\Microsoft\Powershell\1\Shellids\Microsoft.Powershell\" .EXAMPLE # Get default key and it's value Get-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -Key "" .EXAMPLE # Get default key and it's value (alternative) o Get-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -DefaultKey .NOTES General notes #> [cmdletbinding()] param([alias('Path')][string[]] $RegistryPath, [string[]] $ComputerName = $Env:COMPUTERNAME, [string] $Key, [switch] $Advanced, [switch] $DefaultKey) Get-PSRegistryDictionaries $RegistryPath = foreach ($R in $RegistryPath) { If ($R -like '*:*') { foreach ($DictionaryKey in $Script:Dictionary.Keys) { if ($R.StartsWith($DictionaryKey, [System.StringComparison]::CurrentCultureIgnoreCase)) { $R -replace $DictionaryKey, $Script:Dictionary[$DictionaryKey] break } } } else { $R } } [Array] $Computers = Get-ComputerSplit -ComputerName $ComputerName [Array] $RegistryTranslated = Get-PSConvertSpecialRegistry -RegistryPath $RegistryPath -Computers $ComputerName -HiveDictionary $Script:HiveDictionary if ($PSBoundParameters.ContainsKey("Key") -or $DefaultKey) { [Array] $RegistryValues = Get-PSSubRegistryTranslated -RegistryPath $RegistryTranslated -HiveDictionary $Script:HiveDictionary -Key $Key foreach ($Computer in $Computers[0]) { foreach ($R in $RegistryValues) { Get-PSSubRegistry -Registry $R -ComputerName $Computer } } foreach ($Computer in $Computers[1]) { foreach ($R in $RegistryValues) { Get-PSSubRegistry -Registry $R -ComputerName $Computer -Remote } } } else { [Array] $RegistryValues = Get-PSSubRegistryTranslated -RegistryPath $RegistryTranslated -HiveDictionary $Script:HiveDictionary foreach ($Computer in $Computers[0]) { foreach ($R in $RegistryValues) { Get-PSSubRegistryComplete -Registry $R -ComputerName $Computer -Advanced:$Advanced } } foreach ($Computer in $Computers[1]) { foreach ($R in $RegistryValues) { Get-PSSubRegistryComplete -Registry $R -ComputerName $Computer -Remote -Advanced:$Advanced } } } } function Set-PSRegistry { <# .SYNOPSIS Sets/Updates registry entries locally and remotely using .NET methods. .DESCRIPTION Sets/Updates registry entries locally and remotely using .NET methods. If the registry path to key doesn't exists it will be created. .PARAMETER ComputerName The computer to run the command on. Defaults to local computer. .PARAMETER RegistryPath Registry Path to Update .PARAMETER Type Registry type to use. Options are: REG_SZ, REG_EXPAND_SZ, REG_BINARY, REG_DWORD, REG_MULTI_SZ, REG_QWORD, string, expandstring, binary, dword, multistring, qword .PARAMETER Key Registry key to set. If the path to registry key doesn't exists it will be created. .PARAMETER Value Registry value to set. .PARAMETER Suppress Suppresses the output of the command. By default the command outputs PSObject with the results of the operation. .EXAMPLE Set-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics' -Type REG_DWORD -Key "16 LDAP Interface Events" -Value 2 -ComputerName AD1 .EXAMPLE Set-PSRegistry -RegistryPath 'HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Diagnostics' -Type REG_SZ -Key "LDAP Interface Events" -Value 'test' -ComputerName AD1 .EXAMPLE Set-PSRegistry -RegistryPath "HKCU:\\Tests" -Key "LimitBlankPass1wordUse" -Value "0" -Type REG_DWORD .EXAMPLE Set-PSRegistry -RegistryPath "HKCU:\\Tests\MoreTests\Tests1" -Key "LimitBlankPass1wordUse" -Value "0" -Type REG_DWORD .EXAMPLE # Setting default value $ValueData = [byte[]] @( 0, 1, 0, 0, 9, 0, 0, 0, 128, 0, 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 0, 0, 5, 0, 10, 0, 14, 0, 3, 0, 5, 0, 6, 0, 6, 0, 4, 0, 4, 0 ) Set-PSRegistry -RegistryPath "HKEY_CURRENT_USER\Tests" -Key '' -Value $ValueData -Type 'NONE' .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param([string[]] $ComputerName = $Env:COMPUTERNAME, [Parameter(Mandatory)][string] $RegistryPath, [Parameter(Mandatory)][ValidateSet('REG_SZ', 'REG_NONE', 'None', 'REG_EXPAND_SZ', 'REG_BINARY', 'REG_DWORD', 'REG_MULTI_SZ', 'REG_QWORD', 'string', 'binary', 'dword', 'qword', 'multistring', 'expandstring')][string] $Type, [Parameter()][string] $Key, [Parameter(Mandatory)][object] $Value, [switch] $Suppress) Get-PSRegistryDictionaries [Array] $ComputersSplit = Get-ComputerSplit -ComputerName $ComputerName If ($RegistryPath -like '*:*') { foreach ($DictionaryKey in $Script:Dictionary.Keys) { if ($RegistryPath.StartsWith($DictionaryKey, [System.StringComparison]::CurrentCultureIgnoreCase)) { $RegistryPath = $RegistryPath -replace $DictionaryKey, $Script:Dictionary[$DictionaryKey] break } } } $RegistryPath = $RegistryPath.Replace("\\", "\").Replace("\\", "\") [Array] $RegistryTranslated = Get-PSConvertSpecialRegistry -RegistryPath $RegistryPath -Computers $ComputerName -HiveDictionary $Script:HiveDictionary foreach ($Registry in $RegistryTranslated) { $RegistryValue = Get-PrivateRegistryTranslated -RegistryPath $Registry -HiveDictionary $Script:HiveDictionary -Key $Key -Value $Value -Type $Type -ReverseTypesDictionary $Script:ReverseTypesDictionary if ($RegistryValue.HiveKey) { foreach ($Computer in $ComputersSplit[0]) { Set-PrivateRegistry -RegistryValue $RegistryValue -Computer $Computer -Suppress:$Suppress.IsPresent -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference } foreach ($Computer in $ComputersSplit[1]) { Set-PrivateRegistry -RegistryValue $RegistryValue -Computer $Computer -Remote -Suppress:$Suppress.IsPresent -ErrorAction $ErrorActionPreference -WhatIf:$WhatIfPreference } } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning "Set-PSRegistry - Setting registry to $Registry have failed. Couldn't translate HIVE." } } } } function ConvertFrom-NetbiosName { [cmdletBinding()] param([Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)] [string[]] $Identity) process { foreach ($Ident in $Identity) { if ($Ident -like '*\*') { $NetbiosWithObject = $Ident -split "\\" if ($NetbiosWithObject.Count -eq 2) { $LDAPQuery = ([ADSI]"LDAP://$($NetbiosWithObject[0])") $DomainName = ConvertFrom-DistinguishedName -DistinguishedName $LDAPQuery.distinguishedName -ToDomainCN [PSCustomObject] @{DomainName = $DomainName Name = $NetbiosWithObject[1] } } else { [PSCustomObject] @{DomainName = '' Name = $Ident } } } else { [PSCustomObject] @{DomainName = '' Name = $Ident } } } } } function ConvertTo-StringByType { <# .SYNOPSIS Private function to use within ConvertTo-JsonLiteral .DESCRIPTION Private function to use within ConvertTo-JsonLiteral .PARAMETER Value Value to convert to JsonValue .PARAMETER Depth Specifies how many levels of contained objects are included in the JSON representation. The default value is 0. .PARAMETER AsArray Outputs the object in array brackets, even if the input is a single object. .PARAMETER DateTimeFormat Changes DateTime string format. Default "yyyy-MM-dd HH:mm:ss" .PARAMETER NumberAsString Provides an alternative serialization option that converts all numbers to their string representation. .PARAMETER BoolAsString Provides an alternative serialization option that converts all bool to their string representation. .PARAMETER PropertyName Uses PropertyNames provided by user (only works with Force) .PARAMETER ArrayJoin Forces any array to be a string regardless of depth level .PARAMETER ArrayJoinString Uses defined string or char for array join. By default it uses comma with a space when used. .PARAMETER Force Forces using property names from first object or given thru PropertyName parameter .EXAMPLE $Value = ConvertTo-StringByType -Value $($Object[$a][$i]) -DateTimeFormat $DateTimeFormat .NOTES General notes #> [cmdletBinding()] param([Object] $Value, [int] $Depth, [int] $MaxDepth, [string] $DateTimeFormat, [switch] $NumberAsString, [switch] $BoolAsString, [System.Collections.IDictionary] $NewLineFormat = @{NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $NewLineFormatProperty = @{NewLineCarriage = '\r\n' NewLine = "\n" Carriage = "\r" }, [System.Collections.IDictionary] $AdvancedReplace, [System.Text.StringBuilder] $TextBuilder, [string[]] $PropertyName, [switch] $ArrayJoin, [string] $ArrayJoinString, [switch] $Force) Process { if ($null -eq $Value) { "`"`"" } elseif ($Value -is [string]) { $Value = $Value.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormat.NewLineCarriage).Replace("`n", $NewLineFormat.NewLine).Replace("`r", $NewLineFormat.Carriage) foreach ($Key in $AdvancedReplace.Keys) { $Value = $Value.Replace($Key, $AdvancedReplace[$Key]) } "`"$Value`"" } elseif ($Value -is [DateTime]) { "`"$($($Value).ToString($DateTimeFormat))`"" } elseif ($Value -is [bool]) { if ($BoolAsString) { "`"$($Value)`"" } else { $Value.ToString().ToLower() } } elseif ($Value -is [System.Collections.IDictionary]) { if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) { "`"$($Value)`"" } else { $Depth++ $null = $TextBuilder.AppendLine("{") for ($i = 0; $i -lt ($Value.Keys).Count; $i++) { $Property = ([string[]]$Value.Keys)[$i] $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $null = $TextBuilder.Append("`"$DisplayProperty`":") $OutputValue = ConvertTo-StringByType -Value $Value[$Property] -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -ArrayJoinString $ArrayJoinString $null = $TextBuilder.Append("$OutputValue") if ($i -ne ($Value.Keys).Count - 1) { $null = $TextBuilder.AppendLine(',') } } $null = $TextBuilder.Append("}") } } elseif ($Value -is [System.Collections.IList] -or $Value -is [System.Collections.ReadOnlyCollectionBase]) { if ($ArrayJoin) { $Value = $Value -join $ArrayJoinString $Value = "$Value".Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) "`"$Value`"" } else { if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) { $Value = "$Value".Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) "`"$Value`"" } else { $CountInternalObjects = 0 $null = $TextBuilder.Append("[") foreach ($V in $Value) { $CountInternalObjects++ if ($CountInternalObjects -gt 1) { $null = $TextBuilder.Append(',') } if ($Force -and -not $PropertyName) { $PropertyName = $V.PSObject.Properties.Name } elseif ($Force -and $PropertyName) {} else { $PropertyName = $V.PSObject.Properties.Name } $OutputValue = ConvertTo-StringByType -Value $V -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -PropertyName $PropertyName -ArrayJoinString $ArrayJoinString $null = $TextBuilder.Append($OutputValue) } $null = $TextBuilder.Append("]") } } } elseif ($Value -is [System.Enum]) { "`"$($($Value).ToString())`"" } elseif (($Value | IsNumeric) -eq $true) { $Value = $($Value).ToString().Replace(',', '.') if ($NumberAsString) { "`"$Value`"" } else { $Value } } elseif ($Value -is [PSObject]) { if ($MaxDepth -eq 0 -or $Depth -eq $MaxDepth) { "`"$($Value)`"" } else { $Depth++ $CountInternalObjects = 0 $null = $TextBuilder.AppendLine("{") if ($Force -and -not $PropertyName) { $PropertyName = $Value.PSObject.Properties.Name } elseif ($Force -and $PropertyName) {} else { $PropertyName = $Value.PSObject.Properties.Name } foreach ($Property in $PropertyName) { $CountInternalObjects++ if ($CountInternalObjects -gt 1) { $null = $TextBuilder.AppendLine(',') } $DisplayProperty = $Property.Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) $null = $TextBuilder.Append("`"$DisplayProperty`":") $OutputValue = ConvertTo-StringByType -Value $Value.$Property -DateTimeFormat $DateTimeFormat -NumberAsString:$NumberAsString -BoolAsString:$BoolAsString -Depth $Depth -MaxDepth $MaxDepth -TextBuilder $TextBuilder -Force:$Force -ArrayJoinString $ArrayJoinString $null = $TextBuilder.Append("$OutputValue") } $null = $TextBuilder.Append("}") } } else { $Value = $Value.ToString().Replace('\', "\\").Replace('"', '\"').Replace([System.Environment]::NewLine, $NewLineFormatProperty.NewLineCarriage).Replace("`n", $NewLineFormatProperty.NewLine).Replace("`r", $NewLineFormatProperty.Carriage) "`"$Value`"" } } } function Get-ComputerSplit { [CmdletBinding()] param([string[]] $ComputerName) if ($null -eq $ComputerName) { $ComputerName = $Env:COMPUTERNAME } try { $LocalComputerDNSName = [System.Net.Dns]::GetHostByName($Env:COMPUTERNAME).HostName } catch { $LocalComputerDNSName = $Env:COMPUTERNAME } $ComputersLocal = $null [Array] $Computers = foreach ($Computer in $ComputerName) { if ($Computer -eq '' -or $null -eq $Computer) { $Computer = $Env:COMPUTERNAME } if ($Computer -ne $Env:COMPUTERNAME -and $Computer -ne $LocalComputerDNSName) { $Computer } else { $ComputersLocal = $Computer } } , @($ComputersLocal, $Computers) } function Get-PrivateRegistryTranslated { [cmdletBinding()] param([Array] $RegistryPath, [System.Collections.IDictionary] $HiveDictionary, [System.Collections.IDictionary] $ReverseTypesDictionary, [Parameter(Mandatory)][ValidateSet('REG_SZ', 'REG_NONE', 'None', 'REG_EXPAND_SZ', 'REG_BINARY', 'REG_DWORD', 'REG_MULTI_SZ', 'REG_QWORD', 'string', 'binary', 'dword', 'qword', 'multistring', 'expandstring')][string] $Type, [Parameter()][string] $Key, [Parameter(Mandatory)][object] $Value) foreach ($Registry in $RegistryPath) { if ($Registry -is [string]) { $Registry = $Registry.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") } else { $Registry.RegistryPath = $Registry.RegistryPath.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") } foreach ($Hive in $HiveDictionary.Keys) { if ($Registry -is [string] -and $Registry.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) { if ($Hive.Length -eq $Registry.Length) { [ordered] @{HiveKey = $HiveDictionary[$Hive] SubKeyName = $null ValueKind = [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) Key = $Key Value = $Value } } else { [ordered] @{HiveKey = $HiveDictionary[$Hive] SubKeyName = $Registry.substring($Hive.Length + 1) ValueKind = [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) Key = $Key Value = $Value } } break } elseif ($Registry -isnot [string] -and $Registry.RegistryPath.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) { if ($Hive.Length -eq $Registry.RegistryPath.Length) { [ordered] @{ComputerName = $Registry.ComputerName HiveKey = $HiveDictionary[$Hive] SubKeyName = $null ValueKind = [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) Key = $Key Value = $Value } } else { [ordered] @{ComputerName = $Registry.ComputerName HiveKey = $HiveDictionary[$Hive] SubKeyName = $Registry.RegistryPath.substring($Hive.Length + 1) ValueKind = [Microsoft.Win32.RegistryValueKind]::($ReverseTypesDictionary[$Type]) Key = $Key Value = $Value } } break } } } } function Get-PSConvertSpecialRegistry { [cmdletbinding()] param([Array] $RegistryPath, [Array] $Computers, [System.Collections.IDictionary] $HiveDictionary) $FixedPath = foreach ($R in $RegistryPath) { foreach ($DictionaryKey in $HiveDictionary.Keys) { if ($R.StartsWith($DictionaryKey, [System.StringComparison]::CurrentCultureIgnoreCase)) { if ($HiveDictionary[$DictionaryKey] -in 'All', 'All+Default', 'Default', 'AllDomain+Default', 'AllDomain') { foreach ($Computer in $Computers) { $SubKeys = Get-PSRegistry -RegistryPath "HKEY_USERS" -ComputerName $Computer if ($SubKeys.PSSubKeys) { $RegistryKeys = ConvertTo-HKeyUser -SubKeys ($SubKeys.PSSubKeys | Sort-Object) -HiveDictionary $HiveDictionary -DictionaryKey $DictionaryKey foreach ($S in $RegistryKeys) { [PSCustomObject] @{ComputerName = $Computer RegistryPath = $S Error = $null ErrorMessage = $null } } } else { [PSCustomObject] @{ComputerName = $Computer RegistryPath = $R Error = $true ErrorMessage = "Couldn't connect to $Computer to list HKEY_USERS" } } } } else { $R } break } } } $FixedPath } function Get-PSRegistryDictionaries { [cmdletBinding()] param() if ($Script:Dictionary) { return } $Script:Dictionary = @{'HKUAD:' = 'HKEY_ALL_USERS_DEFAULT' 'HKUA:' = 'HKEY_ALL_USERS' 'HKUD:' = 'HKEY_DEFAULT_USER' 'HKUDUD:' = 'HKEY_ALL_DOMAIN_USERS_DEFAULT' 'HKUDU:' = 'HKEY_ALL_DOMAIN_USERS' 'HKCR:' = 'HKEY_CLASSES_ROOT' 'HKCU:' = 'HKEY_CURRENT_USER' 'HKLM:' = 'HKEY_LOCAL_MACHINE' 'HKU:' = 'HKEY_USERS' 'HKCC:' = 'HKEY_CURRENT_CONFIG' 'HKDD:' = 'HKEY_DYN_DATA' 'HKPD:' = 'HKEY_PERFORMANCE_DATA' } $Script:HiveDictionary = [ordered] @{'HKEY_ALL_USERS_DEFAULT' = 'All+Default' 'HKUAD' = 'All+Default' 'HKEY_ALL_USERS' = 'All' 'HKUA' = 'All' 'HKEY_ALL_DOMAIN_USERS_DEFAULT' = 'AllDomain+Default' 'HKUDUD' = 'AllDomain+Default' 'HKEY_ALL_DOMAIN_USERS' = 'AllDomain' 'HKUDU' = 'AllDomain' 'HKEY_DEFAULT_USER' = 'Default' 'HKUD' = 'Default' 'HKEY_CLASSES_ROOT' = 'ClassesRoot' 'HKCR' = 'ClassesRoot' 'ClassesRoot' = 'ClassesRoot' 'HKCU' = 'CurrentUser' 'HKEY_CURRENT_USER' = 'CurrentUser' 'CurrentUser' = 'CurrentUser' 'HKLM' = 'LocalMachine' 'HKEY_LOCAL_MACHINE' = 'LocalMachine' 'LocalMachine' = 'LocalMachine' 'HKU' = 'Users' 'HKEY_USERS' = 'Users' 'Users' = 'Users' 'HKCC' = 'CurrentConfig' 'HKEY_CURRENT_CONFIG' = 'CurrentConfig' 'CurrentConfig' = 'CurrentConfig' 'HKDD' = 'DynData' 'HKEY_DYN_DATA' = 'DynData' 'DynData' = 'DynData' 'HKPD' = 'PerformanceData' 'HKEY_PERFORMANCE_DATA ' = 'PerformanceData' 'PerformanceData' = 'PerformanceData' } $Script:ReverseTypesDictionary = [ordered] @{'REG_SZ' = 'string' 'REG_NONE' = 'none' 'REG_EXPAND_SZ' = 'expandstring' 'REG_BINARY' = 'binary' 'REG_DWORD' = 'dword' 'REG_MULTI_SZ' = 'multistring' 'REG_QWORD' = 'qword' 'string' = 'string' 'expandstring' = 'expandstring' 'binary' = 'binary' 'dword' = 'dword' 'multistring' = 'multistring' 'qword' = 'qword' 'none' = 'none' } } function Get-PSSubRegistry { [cmdletBinding()] param([System.Collections.IDictionary] $Registry, [string] $ComputerName, [switch] $Remote) if ($Registry.ComputerName) { if ($Registry.ComputerName -ne $ComputerName) { return } } if (-not $Registry.Error) { try { if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($Registry.HiveKey, $ComputerName, 0) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($Registry.HiveKey, 0) } $PSConnection = $true $PSError = $null } catch { $PSConnection = $false $PSError = $($_.Exception.Message) } } else { $PSConnection = $false $PSError = $($Registry.ErrorMessage) } if ($PSError) { [PSCustomObject] @{PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = $PSError PSPath = $Registry.Registry PSKey = $Registry.Key PSValue = $null PSType = $null } } else { try { $SubKey = $BaseHive.OpenSubKey($Registry.SubKeyName, $false) if ($null -ne $SubKey) { [PSCustomObject] @{PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $false PSErrorMessage = $null PSPath = $Registry.Registry PSKey = $Registry.Key PSValue = $SubKey.GetValue($Registry.Key) PSType = $SubKey.GetValueKind($Registry.Key) } } else { [PSCustomObject] @{PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = "Registry path $($Registry.Registry) doesn't exists." PSPath = $Registry.Registry PSKey = $Registry.Key PSValue = $null PSType = $null } } } catch { [PSCustomObject] @{PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = $_.Exception.Message PSPath = $Registry.Registry PSKey = $Registry.Key PSValue = $null PSType = $null } } } } function Get-PSSubRegistryComplete { [cmdletBinding()] param([System.Collections.IDictionary] $Registry, [string] $ComputerName, [switch] $Remote, [switch] $Advanced) if ($Registry.ComputerName) { if ($Registry.ComputerName -ne $ComputerName) { return } } if (-not $Registry.Error) { try { if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($R.HiveKey, $ComputerName, 0) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($R.HiveKey, 0) } $PSConnection = $true $PSError = $null } catch { $PSConnection = $false $PSError = $($_.Exception.Message) } } else { $PSConnection = $false $PSError = $($Registry.ErrorMessage) } if ($PSError) { [PSCustomObject] @{PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = $PSError PSSubKeys = $null PSPath = $Registry.Registry PSKey = $Registry.Key } } else { try { $SubKey = $BaseHive.OpenSubKey($Registry.SubKeyName, $false) if ($null -ne $SubKey) { $Object = [ordered] @{PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $false PSErrorMessage = $null PSSubKeys = $SubKey.GetSubKeyNames() PSPath = $Registry.Registry } $Keys = $SubKey.GetValueNames() foreach ($K in $Keys) { if ($K -eq "") { if ($Advanced) { $Object['DefaultKey'] = [ordered] @{Value = $SubKey.GetValue($K) Type = $SubKey.GetValueKind($K) } } else { $Object['DefaultKey'] = $SubKey.GetValue($K) } } else { if ($Advanced) { $Object[$K] = [ordered] @{Value = $SubKey.GetValue($K) Type = $SubKey.GetValueKind($K) } } else { $Object[$K] = $SubKey.GetValue($K) } } } [PSCustomObject] $Object } else { [PSCustomObject] @{PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = "Registry path $($Registry.Registry) doesn't exists." PSSubKeys = $null PSPath = $Registry.Registry } } } catch { [PSCustomObject] @{PSComputerName = $ComputerName PSConnection = $PSConnection PSError = $true PSErrorMessage = $_.Exception.Message PSSubKeys = $null PSPath = $Registry.Registry } } } } function Get-PSSubRegistryTranslated { [cmdletBinding()] param([Array] $RegistryPath, [System.Collections.IDictionary] $HiveDictionary, [string] $Key) foreach ($Registry in $RegistryPath) { if ($Registry -is [string]) { $Registry = $Registry.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") } else { $Registry.RegistryPath = $Registry.RegistryPath.Replace("\\", "\").Replace("\\", "\").TrimStart("\").TrimEnd("\") } foreach ($Hive in $HiveDictionary.Keys) { if ($Registry -is [string] -and $Registry.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) { if ($Hive.Length -eq $Registry.Length) { [ordered] @{Registry = $Registry HiveKey = $HiveDictionary[$Hive] SubKeyName = $null Key = if ($Key -eq "") { $null } else { $Key } Error = $null ErrorMessage = $null } } else { [ordered] @{Registry = $Registry HiveKey = $HiveDictionary[$Hive] SubKeyName = $Registry.substring($Hive.Length + 1) Key = if ($Key -eq "") { $null } else { $Key } Error = $null ErrorMessage = $null } } break } elseif ($Registry -isnot [string] -and $Registry.RegistryPath.StartsWith($Hive, [System.StringComparison]::CurrentCultureIgnoreCase)) { if ($Hive.Length -eq $Registry.RegistryPath.Length) { [ordered] @{ComputerName = $Registry.ComputerName Registry = $Registry.RegistryPath HiveKey = $HiveDictionary[$Hive] SubKeyName = $null Key = if ($Key -eq "") { $null } else { $Key } Error = $Registry.Error ErrorMessage = $Registry.ErrorMessage } } else { [ordered] @{ComputerName = $Registry.ComputerName Registry = $Registry.RegistryPath HiveKey = $HiveDictionary[$Hive] SubKeyName = $Registry.RegistryPath.substring($Hive.Length + 1) Key = if ($Key -eq "") { $null } else { $Key } Error = $Registry.Error ErrorMessage = $Registry.ErrorMessage } } break } } } } function Set-PrivateRegistry { [cmdletBinding(SupportsShouldProcess)] param([System.Collections.IDictionary] $RegistryValue, [string] $Computer, [switch] $Remote, [switch] $Suppress) if ($RegistryValue.ComputerName) { if ($RegistryValue.ComputerName -ne $Computer) { return } } try { if ($Remote) { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($RegistryValue.HiveKey, $Computer, 0) } else { $BaseHive = [Microsoft.Win32.RegistryKey]::OpenBaseKey($RegistryValue.HiveKey, 0) } $PSConnection = $true $PSError = $null } catch { $PSConnection = $false $PSError = $($_.Exception.Message) if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning "Set-PSRegistry - Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" } } if ($PSCmdlet.ShouldProcess($Computer, "Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind)")) { if ($PSError) { if (-not $Suppress) { [PSCustomObject] @{PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = $PSError Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key Value = $RegistryValue.Value Type = $RegistryValue.ValueKind } } } else { try { $SubKey = $BaseHive.OpenSubKey($RegistryValue.SubKeyName, $true) if (-not $SubKey) { $SubKeysSplit = $RegistryValue.SubKeyName.Split('\') $SubKey = $BaseHive.OpenSubKey($SubKeysSplit[0], $true) if (-not $SubKey) { $SubKey = $BaseHive.CreateSubKey($SubKeysSplit[0]) } $SubKey = $BaseHive.OpenSubKey($SubKeysSplit[0], $true) foreach ($S in $SubKeysSplit | Select-Object -Skip 1) { $SubKey = $SubKey.CreateSubKey($S) } } if ($RegistryValue.ValueKind -eq [Microsoft.Win32.RegistryValueKind]::MultiString) { $SubKey.SetValue($RegistryValue.Key, [string[]] $RegistryValue.Value, $RegistryValue.ValueKind) } elseif ($RegistryValue.ValueKind -in [Microsoft.Win32.RegistryValueKind]::None, [Microsoft.Win32.RegistryValueKind]::Binary) { $SubKey.SetValue($RegistryValue.Key, [byte[]] $RegistryValue.Value, $RegistryValue.ValueKind) } else { $SubKey.SetValue($RegistryValue.Key, $RegistryValue.Value, $RegistryValue.ValueKind) } if (-not $Suppress) { [PSCustomObject] @{PSComputerName = $Computer PSConnection = $PSConnection PSError = $false PSErrorMessage = $null Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key Value = $RegistryValue.Value Type = $RegistryValue.ValueKind } } } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning "Set-PSRegistry - Setting registry $($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName) on $($RegistryValue.Key) to $($RegistryValue.Value) of $($RegistryValue.ValueKind) on $Computer have failed. Error: $($_.Exception.Message.Replace([System.Environment]::NewLine, " "))" } if (-not $Suppress) { [PSCustomObject] @{PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = $_.Exception.Message Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key Value = $RegistryValue.Value Type = $RegistryValue.ValueKind } } } } } else { if (-not $Suppress) { [PSCustomObject] @{PSComputerName = $Computer PSConnection = $PSConnection PSError = $true PSErrorMessage = if ($PSError) { $PSError } else { "WhatIf used - skipping registry setting" } Path = "$($RegistryValue.HiveKey)\$($RegistryValue.SubKeyName)" Key = $RegistryValue.Key Value = $RegistryValue.Value Type = $RegistryValue.ValueKind } } } } function ConvertFrom-DistinguishedName { <# .SYNOPSIS Converts a Distinguished Name to CN, OU, Multiple OUs or DC .DESCRIPTION Converts a Distinguished Name to CN, OU, Multiple OUs or DC .PARAMETER DistinguishedName Distinguished Name to convert .PARAMETER ToOrganizationalUnit Converts DistinguishedName to Organizational Unit .PARAMETER ToDC Converts DistinguishedName to DC .PARAMETER ToDomainCN Converts DistinguishedName to Domain CN .EXAMPLE $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName -ToOrganizationalUnit Output: OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz .EXAMPLE $DistinguishedName = 'CN=Przemyslaw Klys,OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' ConvertFrom-DistinguishedName -DistinguishedName $DistinguishedName Output: Przemyslaw Klys .EXAMPLE ConvertFrom-DistinguishedName -DistinguishedName 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -ToMultipleOrganizationalUnit -IncludeParent Output: OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz OU=Production,DC=ad,DC=evotec,DC=xyz .EXAMPLE ConvertFrom-DistinguishedName -DistinguishedName 'OU=Users,OU=Production,DC=ad,DC=evotec,DC=xyz' -ToMultipleOrganizationalUnit Output: OU=Production,DC=ad,DC=evotec,DC=xyz .EXAMPLE $Con = @( 'CN=Windows Authorization Access Group,CN=Builtin,DC=ad,DC=evotec,DC=xyz' 'CN=Mmm,DC=elo,CN=nee,DC=RootDNSServers,CN=MicrosoftDNS,CN=System,DC=ad,DC=evotec,DC=xyz' 'CN=e6d5fd00-385d-4e65-b02d-9da3493ed850,CN=Operations,CN=DomainUpdates,CN=System,DC=ad,DC=evotec,DC=xyz' 'OU=Domain Controllers,DC=ad,DC=evotec,DC=pl' 'OU=Microsoft Exchange Security Groups,DC=ad,DC=evotec,DC=xyz' ) ConvertFrom-DistinguishedName -DistinguishedName $Con -ToLastName Output: Windows Authorization Access Group Mmm e6d5fd00-385d-4e65-b02d-9da3493ed850 Domain Controllers Microsoft Exchange Security Groups .NOTES General notes #> [CmdletBinding(DefaultParameterSetName = 'Default')] param([Parameter(ParameterSetName = 'ToOrganizationalUnit')] [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')] [Parameter(ParameterSetName = 'ToDC')] [Parameter(ParameterSetName = 'ToDomainCN')] [Parameter(ParameterSetName = 'Default')] [Parameter(ParameterSetName = 'ToLastName')] [alias('Identity', 'DN')][Parameter(ValueFromPipeline, ValueFromPipelineByPropertyName, Position = 0)][string[]] $DistinguishedName, [Parameter(ParameterSetName = 'ToOrganizationalUnit')][switch] $ToOrganizationalUnit, [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')][alias('ToMultipleOU')][switch] $ToMultipleOrganizationalUnit, [Parameter(ParameterSetName = 'ToMultipleOrganizationalUnit')][switch] $IncludeParent, [Parameter(ParameterSetName = 'ToDC')][switch] $ToDC, [Parameter(ParameterSetName = 'ToDomainCN')][switch] $ToDomainCN, [Parameter(ParameterSetName = 'ToLastName')][switch] $ToLastName) Process { foreach ($Distinguished in $DistinguishedName) { if ($ToDomainCN) { $DN = $Distinguished -replace '.*?((DC=[^=]+,)+DC=[^=]+)$', '$1' $CN = $DN -replace ',DC=', '.' -replace "DC=" if ($CN) { $CN } } elseif ($ToOrganizationalUnit) { $Value = [Regex]::Match($Distinguished, '(?=OU=)(.*\n?)(?<=.)').Value if ($Value) { $Value } } elseif ($ToMultipleOrganizationalUnit) { if ($IncludeParent) { $Distinguished } while ($true) { $Distinguished = $Distinguished -replace '^.+?,(?=..=)' if ($Distinguished -match '^DC=') { break } $Distinguished } } elseif ($ToDC) { $Value = $Distinguished -replace '.*?((DC=[^=]+,)+DC=[^=]+)$', '$1' if ($Value) { $Value } } elseif ($ToLastName) { $NewDN = $Distinguished -split ",DC=" if ($NewDN[0].Contains(",OU=")) { [Array] $ChangedDN = $NewDN[0] -split ",OU=" } elseif ($NewDN[0].Contains(",CN=")) { [Array] $ChangedDN = $NewDN[0] -split ",CN=" } else { [Array] $ChangedDN = $NewDN[0] } if ($ChangedDN[0].StartsWith('CN=')) { $ChangedDN[0] -replace 'CN=', '' } else { $ChangedDN[0] -replace 'OU=', '' } } else { $Regex = '^CN=(?<cn>.+?)(?<!\\),(?<ou>(?:(?:OU|CN).+?(?<!\\),)+(?<dc>DC.+?))$' $Found = $Distinguished -match $Regex if ($Found) { $Matches.cn } } } } } function ConvertTo-HkeyUser { [CmdletBinding()] param([System.Collections.IDictionary] $HiveDictionary, [Array] $SubKeys, [string] $DictionaryKey) foreach ($Sub in $Subkeys) { if ($HiveDictionary[$DictionaryKey] -eq 'All') { if ($Sub -notlike "*_Classes*" -and $Sub -ne '.DEFAULT') { $R.Replace($DictionaryKey, "Users\$Sub") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'All+Default') { if ($Sub -notlike "*_Classes*") { $R.Replace($DictionaryKey, "Users\$Sub") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'Default') { if ($Sub -eq '.DEFAULT') { $R.Replace($DictionaryKey, "Users\.DEFAULT") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'AllDomain+Default') { if (($Sub.StartsWith("S-1-5-21") -and $Sub -notlike "*_Classes*") -or $Sub -eq '.DEFAULT') { $R.Replace($DictionaryKey, "Users\$Sub") } } elseif ($HiveDictionary[$DictionaryKey] -eq 'AllDomain') { if ($Sub.StartsWith("S-1-5-21") -and $Sub -notlike "*_Classes*") { $R.Replace($DictionaryKey, "Users\$Sub") } } } } function Set-SystemAuditPolicyAuditpol { <# .SYNOPSIS This command is used to set the audit policy for the system using auditpol.exe .DESCRIPTION This command is used to set the audit policy for the system using auditpol.exe .PARAMETER Policies This parameter is used to specify the audit policy to be set. .PARAMETER Value This parameter is used to specify the value of the audit policy to be set. Options are: NotConfigured, Success, Failure, and SuccessAndFailure. .PARAMETER Suppress Suppresses the output of the command .EXAMPLE Set-SystemAuditPolicyLocalSecurity -AccountManagement 'Computer Account Management' -Value Failure -Verbose -WhatIf .EXAMPLE Set-SystemAuditPolicyLocalSecurity -AccountManagement 'Application Group Management' -Value Success -Verbose -WhatIf .NOTES General notes #> [cmdletBinding(SupportsShouldProcess)] param([parameter(Mandatory)][ValidateSet("Security System Extension", "System Integrity", "IPsec Driver", "Other System Events", "Security State Change", "Logon", "Logoff", "Account Lockout", "IPsec Main Mode", "IPsec Quick Mode", "IPsec Extended Mode", "Special Logon", "Other Logon/Logoff Events", "Network Policy Server", "User / Device Claims", "Group Membership", "File System", "Registry", "Kernel Object", "SAM", "Certification Services", "Application Generated", "Handle Manipulation", "File Share", "Filtering Platform Packet Drop", "Filtering Platform Connection", "Other Object Access Events", "Detailed File Share", "Removable Storage", "Central Policy Staging", "Non Sensitive Privilege Use", "Other Privilege Use Events", "Sensitive Privilege Use", "Process Creation", "Process Termination", "DPAPI Activity", "RPC Events", "Plug and Play Events", "Token Right Adjusted Events", "Audit Policy Change", "Authentication Policy Change", "Authorization Policy Change", "MPSSVC Rule-Level Policy Change", "Filtering Platform Policy Change", "Other Policy Change Events", "Computer Account Management", "Security Group Management", "Distribution Group Management", "Application Group Management", "Other Account Management Events", "User Account Management", "Directory Service Access", "Directory Service Changes", "Directory Service Replication", "Detailed Directory Service Replication", "Kerberos Service Ticket Operations", "Kerberos Service Ticket Operations", "Other Account Logon Events", "Kerberos Authentication Service", "Credential Validation")][string[]] $Policies, [parameter(Mandatory)][validateSet('NoAuditing', 'NotConfigured', 'Success', 'Failure', 'SuccessAndFailure')][string] $Value) if ($Value -in 'NotConfigured', 'NoAuditing') { $Success = 'disable' $Failure = 'disable' } elseif ($Value -eq 'Success') { $Success = 'enable' $Failure = 'disable' } elseif ($Value -eq 'Failure') { $Success = 'disable' $Failure = 'enable' } elseif ($Value -eq 'SuccessAndFailure') { $Success = 'enable' $Failure = 'enable' } foreach ($Policy in $Policies) { if ($PSCmdlet.ShouldProcess("SubCategory $Policy", "Setting $Value (Success: $Success / Failure: $Failure)")) { Write-Verbose -Message "Set-SystemAuditPolicyAuditpol - Executing: auditpol.exe /set /subcategory:$Policy /success:$Success /failure:$Failure" $pinfo = [System.Diagnostics.ProcessStartInfo]::new() $pinfo.FileName = "auditpol.exe" $pinfo.RedirectStandardError = $true $pinfo.RedirectStandardOutput = $true $pinfo.UseShellExecute = $false $pinfo.Arguments = " /set /subcategory:`"$Policy`" /success:`"$Success`" /failure:`"$Failure`"" $p = [System.Diagnostics.Process]::new() $p.StartInfo = $pinfo $p.Start() | Out-Null $p.WaitForExit() $Output = $p.StandardOutput.ReadToEnd() $Errors = $p.StandardError.ReadToEnd() if ($Output -like "*The command was successfully*" -and -not $Errors) { if (-not $Suppress) { [PSCustomObject] @{'Policy' = $Policy 'Value' = $Value 'Result' = 'Success' 'Error' = '' } } } else { if (-not $Suppress) { $SplitErrors = ($Errors -split "\n").Trim() -join " " [PSCustomObject] @{'Policy' = $Policy 'Value' = $Value 'Result' = 'Failed' 'Error' = $SplitErrors } } } } else { if (-not $Suppress) { [PSCustomObject] @{'Policy' = $Policy 'Value' = $Value 'Result' = 'WhatIf' 'Error' = 'WhatIf in use.' } } } } } function Set-SystemAuditPolicyLocalSecurity { <# .SYNOPSIS This function will set the audit policy for the local machine using Local Security Policy (audit.csv) .DESCRIPTION This function will set the audit policy for the local machine using Local Security Policy (audit.csv) It's IMPORTANT to know that Local Security Policy doesn't apply until next GPO refresh .PARAMETER Policies This parameter is used to specify the audit policy to be set. .PARAMETER Value This parameter is used to specify the value of the audit policy to be set. Options are: NoAuditing, NotConfigured, Success, Failure, and SuccessAndFailure. .PARAMETER Suppress Suppresses the output of the command .EXAMPLE Set-SystemAuditPolicyLocalSecurity -AccountManagement 'Computer Account Management' -Value Failure -Verbose -WhatIf .EXAMPLE Set-SystemAuditPolicyLocalSecurity -AccountManagement 'Application Group Management' -Value Success -Verbose -WhatIf .NOTES General notes #> [CmdletBinding(SupportsShouldProcess)] param([parameter(Mandatory)][ValidateSet("Security System Extension", "System Integrity", "IPsec Driver", "Other System Events", "Security State Change", "Logon", "Logoff", "Account Lockout", "IPsec Main Mode", "IPsec Quick Mode", "IPsec Extended Mode", "Special Logon", "Other Logon/Logoff Events", "Network Policy Server", "User / Device Claims", "Group Membership", "File System", "Registry", "Kernel Object", "SAM", "Certification Services", "Application Generated", "Handle Manipulation", "File Share", "Filtering Platform Packet Drop", "Filtering Platform Connection", "Other Object Access Events", "Detailed File Share", "Removable Storage", "Central Policy Staging", "Non Sensitive Privilege Use", "Other Privilege Use Events", "Sensitive Privilege Use", "Process Creation", "Process Termination", "DPAPI Activity", "RPC Events", "Plug and Play Events", "Token Right Adjusted Events", "Audit Policy Change", "Authentication Policy Change", "Authorization Policy Change", "MPSSVC Rule-Level Policy Change", "Filtering Platform Policy Change", "Other Policy Change Events", "Computer Account Management", "Security Group Management", "Distribution Group Management", "Application Group Management", "Other Account Management Events", "User Account Management", "Directory Service Access", "Directory Service Changes", "Directory Service Replication", "Detailed Directory Service Replication", "Kerberos Service Ticket Operations", "Kerberos Service Ticket Operations", "Other Account Logon Events", "Kerberos Authentication Service", "Credential Validation")][alias('Policies')][string] $Policy, [parameter(Mandatory)][validateSet('NotConfigured', 'Success', 'Failure', 'SuccessAndFailure', 'NoAuditing')][string] $Value) $AuditPoliciesGuids = [ordered] @{'IPsec Driver' = '{0CCE9213-69AE-11D9-BED3-505054503030}' 'System Integrity' = '{0CCE9212-69AE-11D9-BED3-505054503030}' 'Security System Extension' = '{0CCE9211-69AE-11D9-BED3-505054503030}' 'Security State Change' = '{0CCE9210-69AE-11D9-BED3-505054503030}' 'Other System Events' = '{0CCE9214-69AE-11D9-BED3-505054503030}' 'Group Membership' = '{0CCE9249-69AE-11D9-BED3-505054503030}' 'User / Device Claims' = '{0CCE9247-69AE-11D9-BED3-505054503030}' 'Network Policy Server' = '{0CCE9243-69AE-11D9-BED3-505054503030}' 'Other Logon/Logoff Events' = '{0CCE921C-69AE-11D9-BED3-505054503030}' 'Special Logon' = '{0CCE921B-69AE-11D9-BED3-505054503030}' 'IPsec Extended Mode' = '{0CCE921A-69AE-11D9-BED3-505054503030}' 'IPsec Quick Mode' = '{0CCE9219-69AE-11D9-BED3-505054503030}' 'IPsec Main Mode' = '{0CCE9218-69AE-11D9-BED3-505054503030}' 'Account Lockout' = '{0CCE9217-69AE-11D9-BED3-505054503030}' 'Logoff' = '{0CCE9216-69AE-11D9-BED3-505054503030}' 'Logon' = '{0CCE9215-69AE-11D9-BED3-505054503030}' 'Handle Manipulation' = '{0CCE9223-69AE-11D9-BED3-505054503030}' 'Central Policy Staging' = '{0CCE9246-69AE-11D9-BED3-505054503030}' 'Removable Storage' = '{0CCE9245-69AE-11D9-BED3-505054503030}' 'Detailed File Share' = '{0CCE9244-69AE-11D9-BED3-505054503030}' 'Other Object Access Events' = '{0CCE9227-69AE-11D9-BED3-505054503030}' 'Filtering Platform Connection' = '{0CCE9226-69AE-11D9-BED3-505054503030}' 'Filtering Platform Packet Drop' = '{0CCE9225-69AE-11D9-BED3-505054503030}' 'File Share' = '{0CCE9224-69AE-11D9-BED3-505054503030}' 'Application Generated' = '{0CCE9222-69AE-11D9-BED3-505054503030}' 'Certification Services' = '{0CCE9221-69AE-11D9-BED3-505054503030}' 'SAM' = '{0CCE9220-69AE-11D9-BED3-505054503030}' 'Kernel Object' = '{0CCE921F-69AE-11D9-BED3-505054503030}' 'Registry' = '{0CCE921E-69AE-11D9-BED3-505054503030}' 'File System' = '{0CCE921D-69AE-11D9-BED3-505054503030}' 'Other Privilege Use Events' = '{0CCE922A-69AE-11D9-BED3-505054503030}' 'Non Sensitive Privilege Use' = '{0CCE9229-69AE-11D9-BED3-505054503030}' 'Sensitive Privilege Use' = '{0CCE9228-69AE-11D9-BED3-505054503030}' 'RPC Events' = '{0CCE922E-69AE-11D9-BED3-505054503030}' 'Token Right Adjusted Events' = '{0CCE924A-69AE-11D9-BED3-505054503030}' 'Process Creation' = '{0CCE922B-69AE-11D9-BED3-505054503030}' 'Process Termination' = '{0CCE922C-69AE-11D9-BED3-505054503030}' 'Plug and Play Events' = '{0CCE9248-69AE-11D9-BED3-505054503030}' 'DPAPI Activity' = '{0CCE922D-69AE-11D9-BED3-505054503030}' 'Other Policy Change Events' = '{0CCE9234-69AE-11D9-BED3-505054503030}' 'Authentication Policy Change' = '{0CCE9230-69AE-11D9-BED3-505054503030}' 'Audit Policy Change' = '{0CCE922F-69AE-11D9-BED3-505054503030}' 'Filtering Platform Policy Change' = '{0CCE9233-69AE-11D9-BED3-505054503030}' 'Authorization Policy Change' = '{0CCE9231-69AE-11D9-BED3-505054503030}' 'MPSSVC Rule-Level Policy Change' = '{0CCE9232-69AE-11D9-BED3-505054503030}' 'Other Account Management Events' = '{0CCE923A-69AE-11D9-BED3-505054503030}' 'Application Group Management' = '{0CCE9239-69AE-11D9-BED3-505054503030}' 'Distribution Group Management' = '{0CCE9238-69AE-11D9-BED3-505054503030}' 'Security Group Management' = '{0CCE9237-69AE-11D9-BED3-505054503030}' 'Computer Account Management' = '{0CCE9236-69AE-11D9-BED3-505054503030}' 'User Account Management' = '{0CCE9235-69AE-11D9-BED3-505054503030}' 'Directory Service Replication' = '{0CCE923D-69AE-11D9-BED3-505054503030}' 'Directory Service Access' = '{0CCE923B-69AE-11D9-BED3-505054503030}' 'Detailed Directory Service Replication' = '{0CCE923E-69AE-11D9-BED3-505054503030}' 'Directory Service Changes' = '{0CCE923C-69AE-11D9-BED3-505054503030}' 'Other Account Logon Events' = '{0CCE9241-69AE-11D9-BED3-505054503030}' 'Kerberos Service Ticket Operations' = '{0CCE9240-69AE-11D9-BED3-505054503030}' 'Credential Validation' = '{0CCE923F-69AE-11D9-BED3-505054503030}' 'Kerberos Authentication Service' = '{0CCE9242-69AE-11D9-BED3-505054503030}' } $ListTranslated = @{'NoAuditing' = 'No Auditing' 'NotConfigured' = '' 'Success' = 'Success' 'Failure' = 'Failure' 'SuccessAndFailure' = 'Success and Failure' } $ValuesTranslated = @{'NoAuditing' = 0 'NotConfigured' = -1 'Success' = 1 'Failure' = 2 'SuccessAndFailure' = 3 } $LocalSecurity = [ordered] @{} $LocalSecurityPolicy = [io.path]::Combine($Env:SystemRoot, "System32", "GroupPolicy", "Machine", "Microsoft", "Windows NT", "Audit", 'Audit.csv') if (Test-Path -LiteralPath $LocalSecurityPolicy) { $CurrentCSV = Get-Content -LiteralPath $LocalSecurityPolicy -Raw | ConvertFrom-Csv foreach ($C in $CurrentCSV) { $LocalSecurity[$C.Subcategory] = $C } } if ($Value -eq 'NotConfigured') { $LocalSecurity.Remove($Policy) } else { $InputValue = [PScustomObject] @{'Machine Name' = '' 'Policy Target' = 'System' 'Subcategory' = $Policy 'Subcategory GUID' = $AuditPoliciesGuids[$Policy] 'Inclusion Setting' = $ListTranslated[$Value] 'Exclusion Setting' = '' 'Setting Value' = $ValuesTranslated[$Value] } $LocalSecurity[$Policy] = $InputValue } if ($PSCmdlet.ShouldProcess("SubCategory $Policy", "Setting $Value")) { try { $LocalSecurity.Values | ConvertTo-Csv -NoTypeInformation -Delimiter "," | ForEach-Object { $_ -replace '"', '' } | Set-Content -LiteralPath $LocalSecurityPolicy -ErrorAction Stop $Message = '' $Result = 'Success' } catch { $Result = 'Failed' $Message = $($_.Exception.Message) if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyLocalSecurityPolicy - Audit policies couldn't be saved to $LocalSecurityPolicy. Error: $($_.Exception.Message)" } } } else { $Message = 'WhatIf in use.' $Result = 'WhatIf' } if (-not $Suppress) { [PSCustomObject] @{'Policy' = $Policy 'Value' = $Value 'Result' = $Result 'Error' = $Message } } } function Backup-SystemAuditPolicy { <# .SYNOPSIS Backups the current system audit policy to a file or json or as object .DESCRIPTION Backups the current system audit policy to a file or json or as object .PARAMETER ComputerName ComputerName for remote system to read audit policy from. Requires permissions on the destination. .PARAMETER FilePath FilePath to write the audit policy to. If not given will be returned as JSON .PARAMETER AsJson If true will return the audit policy as JSON .PARAMETER AsObject If true will return the audit policy as an object .PARAMETER Policy Returns the specified policy, and only that policy. .EXAMPLE Backup-SystemAuditPolicy | Out-File -FilePath $PSScriptRoot\Backups\AuditPolicy.json .NOTES General notes #> [cmdletBinding(DefaultParameterSetName = 'File')] param([string] $ComputerName, [parameter(ParameterSetName = 'File')] [string] $FilePath, [parameter(ParameterSetName = 'AsObject')][switch] $AsObject, [parameter(ParameterSetName = 'AsJson')][switch] $AsJson, [ValidateSet("Security System Extension", "System Integrity", "IPsec Driver", "Other System Events", "Security State Change", "Logon", "Logoff", "Account Lockout", "IPsec Main Mode", "IPsec Quick Mode", "IPsec Extended Mode", "Special Logon", "Other Logon/Logoff Events", "Network Policy Server", "User / Device Claims", "Group Membership", "File System", "Registry", "Kernel Object", "SAM", "Certification Services", "Application Generated", "Handle Manipulation", "File Share", "Filtering Platform Packet Drop", "Filtering Platform Connection", "Other Object Access Events", "Detailed File Share", "Removable Storage", "Central Policy Staging", "Non Sensitive Privilege Use", "Other Privilege Use Events", "Sensitive Privilege Use", "Process Creation", "Process Termination", "DPAPI Activity", "RPC Events", "Plug and Play Events", "Token Right Adjusted Events", "Audit Policy Change", "Authentication Policy Change", "Authorization Policy Change", "MPSSVC Rule-Level Policy Change", "Filtering Platform Policy Change", "Other Policy Change Events", "Computer Account Management", "Security Group Management", "Distribution Group Management", "Application Group Management", "Other Account Management Events", "User Account Management", "Directory Service Access", "Directory Service Changes", "Directory Service Replication", "Detailed Directory Service Replication", "Kerberos Service Ticket Operations", "Kerberos Service Ticket Operations", "Other Account Logon Events", "Kerberos Authentication Service", "Credential Validation")][alias('Policies')][string] $Policy) if ($Policy) { $AuditPolicy = Get-SystemAuditPolicy -ComputerName $ComputerName -Policy $Policy } else { $AuditPolicy = Get-SystemAuditPolicy -ComputerName $ComputerName } if ($FilePath) { $AuditPolicy | ConvertTo-JsonLiteral -Depth 5 | Out-File -LiteralPath $FilePath } elseif ($AsObject) { $AuditPolicy } else { $AuditPolicy | ConvertTo-JsonLiteral -Depth 5 } } function Clear-SystemAuditPolicy { <# .SYNOPSIS Clears all audit policies to their default values (Not Configured) .DESCRIPTION Clears all audit policies to their default values (Not Configured) .PARAMETER ComputerName ComputerName for remote system to clear audit policy from. Requires permissions on the destination. .EXAMPLE Clear-SystemAuditPolicy -WhatIf .NOTES General notes #> [cmdletBinding(SupportsShouldProcess)] param([string] $ComputerName) $CurrentPolicies = Get-SystemAuditPolicy -ComputerName $ComputerName foreach ($Policy in $CurrentPolicies.Keys) { $Value = $CurrentPolicies[$Policy] if ($Value -ne 'NotConfigured') { $setSystemAuditPolicySplat = @{Policy = $Policy ComputerName = $ComputerName WhatIf = $WhatIfPreference Value = 'NotConfigured' } $Success = Set-SystemAuditPolicy @setSystemAuditPolicySplat if ($Success.Result -in 'Success', 'Not Required') {} elseif ($Success.Result -eq 'WhatIf') {} else { Write-Warning -Message " Clear-SystemAuditPolicy - Failed to clear $Policy, status: $($Success.Result) error: $($Success.Error)" } } } } function Get-SystemAuditPolicy { <# .SYNOPSIS Small functions that reads Audit Policy (the same way as auditpol.exe) and returns a hashtable with the values. .DESCRIPTION Small functions that reads Audit Policy (the same way as auditpol.exe) and returns a hashtable with the values. .PARAMETER ComputerName ComputerName for remote system to read audit policy from. Requires permissions on the destination. .PARAMETER Policy Returns the specified policy, and only that policy. .PARAMETER Categories Forces display in category view .EXAMPLE $AuditPolicies = Get-SystemAuditPolicy $AuditPolicies | Format-Table $AuditPolicies.AccountLogon | Format-Table $AuditPolicies.AccountManagement | Format-Table $AuditPolicies.DetailedTracking | Format-Table .NOTES General notes #> [CmdletBinding()] param([string] $ComputerName, [ValidateSet("Security System Extension", "System Integrity", "IPsec Driver", "Other System Events", "Security State Change", "Logon", "Logoff", "Account Lockout", "IPsec Main Mode", "IPsec Quick Mode", "IPsec Extended Mode", "Special Logon", "Other Logon/Logoff Events", "Network Policy Server", "User / Device Claims", "Group Membership", "File System", "Registry", "Kernel Object", "SAM", "Certification Services", "Application Generated", "Handle Manipulation", "File Share", "Filtering Platform Packet Drop", "Filtering Platform Connection", "Other Object Access Events", "Detailed File Share", "Removable Storage", "Central Policy Staging", "Non Sensitive Privilege Use", "Other Privilege Use Events", "Sensitive Privilege Use", "Process Creation", "Process Termination", "DPAPI Activity", "RPC Events", "Plug and Play Events", "Token Right Adjusted Events", "Audit Policy Change", "Authentication Policy Change", "Authorization Policy Change", "MPSSVC Rule-Level Policy Change", "Filtering Platform Policy Change", "Other Policy Change Events", "Computer Account Management", "Security Group Management", "Distribution Group Management", "Application Group Management", "Other Account Management Events", "User Account Management", "Directory Service Access", "Directory Service Changes", "Directory Service Replication", "Detailed Directory Service Replication", "Kerberos Service Ticket Operations", "Kerberos Service Ticket Operations", "Other Account Logon Events", "Kerberos Authentication Service", "Credential Validation")][alias('Policies')][string] $Policy, [switch] $Categories) Add-Type -TypeDefinition @" using System; namespace AuditPolicies { public enum Events { NotConfigured = 0, Success = 1, Failure = 2, SuccessAndFailure = 3 } } "@ $IsSystem = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem if (-not $IsSystem) { $SID = ConvertFrom-SID -SID "S-1-5-32-544" Set-SystemAuditPolicyPermissions -Identity $SID.Name -Permissions FullControl -WhatIf:$false } $Audit = Get-PSRegistry -RegistryPath "HKEY_LOCAL_MACHINE\SECURITY\Policy\PolAdtEv" -Key "" -ComputerName $ComputerName if (-not $IsSystem) { $SID = ConvertFrom-SID -SID "S-1-5-32-544" Remove-SystemAuditPolicyPermissions -Identity $SID.Name -Permissions FullControl -WhatIf:$false } if ($Audit.PSConnection -eq $true -and $Audit.PSError -eq $false) { $Data = $Audit.PSValue $AuditPolicies = [ordered] @{System = [ordered] @{'Security State Change' = [AuditPolicies.Events] $Data[12] 'Security System Extension' = [AuditPolicies.Events] $Data[14] 'System Integrity' = [AuditPolicies.Events] $Data[16] 'IPsec Driver' = [AuditPolicies.Events] $Data[18] 'Other System Events' = [AuditPolicies.Events] $Data[20] } LogonLogoff = [ordered] @{'Logon' = [AuditPolicies.Events] $Data[22] 'Logoff' = [AuditPolicies.Events] $Data[24] 'Account Lockout' = [AuditPolicies.Events] $Data[26] 'IPSec Main Mode' = [AuditPolicies.Events] $Data[28] 'Special Logon' = [AuditPolicies.Events] $Data[30] 'IPSec Quick Mode' = [AuditPolicies.Events] $Data[32] 'IPSec Extended Mode' = [AuditPolicies.Events] $Data[34] 'Other Logon/Logoff Events' = [AuditPolicies.Events] $Data[36] 'Network Policy Server' = [AuditPolicies.Events] $Data[38] 'User / Device Claims' = [AuditPolicies.Events] $Data[40] 'Group Membership' = [AuditPolicies.Events] $Data[42] } ObjectAccess = [ordered] @{'File System' = [AuditPolicies.Events] $Data[44] 'Registry' = [AuditPolicies.Events] $Data[46] 'Kernel Object' = [AuditPolicies.Events] $Data[48] 'SAM' = [AuditPolicies.Events] $Data[50] 'Other Object Access Events' = [AuditPolicies.Events] $Data[52] 'Certification Services' = [AuditPolicies.Events] $Data[54] 'Application Generated' = [AuditPolicies.Events] $Data[56] 'Handle Manipulation' = [AuditPolicies.Events] $Data[58] 'File Share' = [AuditPolicies.Events] $Data[60] 'Filtering Platform Packet Drop' = [AuditPolicies.Events] $Data[62] 'Filtering Platform Connection' = [AuditPolicies.Events] $Data[64] 'Detailed File Share' = [AuditPolicies.Events] $Data[66] 'Removable Storage' = [AuditPolicies.Events] $Data[68] 'Central Policy Staging' = [AuditPolicies.Events] $Data[70] } PrivilegeUse = [ordered] @{'Sensitive Privilege Use' = [AuditPolicies.Events] $Data[72] 'Non Sensitive Privilege Use' = [AuditPolicies.Events] $Data[74] 'Other Privilege Use Events' = [AuditPolicies.Events] $Data[76] } DetailedTracking = [ordered] @{'Process Creation' = [AuditPolicies.Events] $Data[78] 'Process Termination' = [AuditPolicies.Events] $Data[80] 'DPAPI Activity' = [AuditPolicies.Events] $Data[82] 'RPC Events' = [AuditPolicies.Events] $Data[84] 'Plug and Play Events' = [AuditPolicies.Events] $Data[86] 'Token Right Adjusted Events' = [AuditPolicies.Events] $Data[88] } PolicyChange = [ordered] @{'Audit Policy Change' = [AuditPolicies.Events] $Data[90] 'Authentication Policy Change' = [AuditPolicies.Events] $Data[92] 'Authorization Policy Change' = [AuditPolicies.Events] $Data[94] 'MPSSVC Rule-Level Policy Change' = [AuditPolicies.Events] $Data[96] 'Filtering Platform Policy Change' = [AuditPolicies.Events] $Data[98] 'Other Policy Change Events' = [AuditPolicies.Events] $Data[100] } AccountManagement = [ordered] @{'User Account Management' = [AuditPolicies.Events] $Data[102] 'Computer Account Management' = [AuditPolicies.Events] $Data[104] 'Security Group Management' = [AuditPolicies.Events] $Data[106] 'Distribution Group Management' = [AuditPolicies.Events] $Data[108] 'Application Group Management' = [AuditPolicies.Events] $Data[110] 'Other Account Management Events' = [AuditPolicies.Events] $Data[112] } DSAccess = [ordered] @{'Directory Service Access' = [AuditPolicies.Events] $Data[114] 'Directory Service Changes' = [AuditPolicies.Events] $Data[116] 'Directory Service Replication' = [AuditPolicies.Events] $Data[118] 'Detailed Directory Service Replication' = [AuditPolicies.Events] $Data[120] } AccountLogon = [ordered] @{'Credential Validation' = [AuditPolicies.Events] $Data[122] 'Kerberos Service Ticket Operations' = [AuditPolicies.Events] $Data[124] 'Other Account Logon Events' = [AuditPolicies.Events] $Data[126] 'Kerberos Authentication Service' = [AuditPolicies.Events] $Data[128] } } if ($Policy) { foreach ($Entry in $AuditPolicies.Keys) { foreach ($Key in $AuditPolicies[$Entry].Keys) { if ($Policy -eq $Key) { return [PSCustomObject] @{'Category' = $Entry 'Policy' = $Policy 'Value' = $AuditPolicies[$Entry][$Key] } } } } } else { if (-not $Categories) { $OutputObject = [ordered] @{} foreach ($Entry in $AuditPolicies.Keys) { foreach ($Key in $AuditPolicies[$Entry].Keys) { $OutputObject[$Key] = $AuditPolicies[$Entry][$Key] } } $OutputObject } else { $AuditPolicies } } } else { Write-Warning -Message "Get-SystemAuditPolicies - Audit policies couldn't be read: $($Audit.PSErrorMessage)" } } function Get-SystemAuditPolicyFromFile { <# .SYNOPSIS Get local security policy audit policies and group policies that contain audit policies in them (if cache is used). .DESCRIPTION Get local security policy audit policies and group policies that contain audit policies in them (if cache is used). .EXAMPLE An example .NOTES General notes #> [cmdletBinding()] param() $Output = [ordered] @{} $GPOPath = [io.path]::Combine($Env:SystemRoot, "System32", "GroupPolicy", 'DataStore') $GPOWithAudit = Get-ChildItem -LiteralPath $GPOPath -Filter "Audit.csv" -Recurse -Force -ErrorAction SilentlyContinue if ($GPOWithAudit) { foreach ($File in $GPOWithAudit) { $pattern = "Policies\\(.*?)\\Machine\\" $GUID = [regex]::Match($File.FullName, $pattern).Groups[1].Value if ($GUID) { $Output[$GUID] = Get-Content -LiteralPath $File.FullName -Raw | ConvertFrom-Csv } } } $LocalSecurityPolicy = [io.path]::Combine($Env:SystemRoot, "System32", "GroupPolicy", "Machine", "Microsoft", "Windows NT", "Audit", 'Audit.csv') if (Test-Path -LiteralPath $LocalSecurityPolicy) { $Output["LocalSecurityPolicy"] = Get-Content -LiteralPath $LocalSecurityPolicy -Raw | ConvertFrom-Csv } $Output } function Remove-SystemAuditPolicyPermissions { <# .SYNOPSIS Removes audit policy permissions from a user or group. .DESCRIPTION Removes audit policy permissions from a user or group. By default only SYSTEM account has any permissions. This command can be used to remove audit policy permissions from a user or group. .PARAMETER Identity Specifies the user or group to remove audit policy permissions from. .PARAMETER Permissions Specifies the audit policy permissions to remove. By default FullControl .EXAMPLE Remove-SystemAuditPolicyPermissions -Identity "przemyslaw.klys" -Verbose -WhatIf .NOTES General notes #> [cmdletBinding(SupportsShouldProcess)] param([parameter(Mandatory)][string] $Identity, [System.Security.AccessControl.RegistryRights] $Permissions = [System.Security.AccessControl.RegistryRights]::FullControl) try { $RegistryKeyControl = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SECURITY', [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::ChangePermissions) } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyPermissions - Opening registry failed $($_.Exception.Message)" } return } $AccessControlList = $RegistryKeyControl.GetAccessControl() $Account = [System.Security.Principal.NTAccount] $Identity $InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit' $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None $AccessType = [System.Security.AccessControl.AccessControlType]::Allow $AccessRule = [System.Security.AccessControl.RegistryAccessRule]::new($Account, $Permissions, $InheritanceFlag, $PropagationFlag, $AccessType) if ($PSCmdlet.ShouldProcess("Registry HKLM\SECURITY", "Adding 'FullControl' access to $Identity for SECURITY subkey")) { try { $Output = $AccessControlList.RemoveAccessRule($AccessRule) } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyPermissions - Adding access rule failed $($_.Exception.Message)" } } if ($Output) { $RegistryKeyControl.SetAccessControl($AccessControlList) } } } function Restore-SystemAuditPolicy { <# .SYNOPSIS Restore the system audit policy to the one from backup. .DESCRIPTION Restore the system audit policy to the one from backup. .PARAMETER ComputerName ComputerName for remote system to restore audit policy on. Requires permissions on the destination. .PARAMETER Object Object to restore audit policy from .PARAMETER JSON JSON object to restore audit policy from .PARAMETER FilePath File path to restore audit policy from .PARAMETER Policy Pick policy/policies to restore from all policies provided .EXAMPLE $FilePath = "$PSScriptRoot\Backups\AuditPolicy.json" Restore-SystemAuditPolicy -FilePath $FilePath -Verbose -WhatIf .EXAMPLE $FilePath = "$PSScriptRoot\Backups\AuditPolicy.json" Restore-SystemAuditPolicy -FilePath $FilePath -Verbose -Policy 'Application Group Management' .NOTES General notes #> [cmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "File")] param([string] $ComputerName, [parameter(Mandatory, ParameterSetName = 'Object')][System.Collections.IDictionary] $Object, [parameter(Mandatory, ParameterSetName = 'JSON')][string] $JSON, [parameter(Mandatory, ParameterSetName = 'File')][string] $FilePath, [ValidateSet("Security System Extension", "System Integrity", "IPsec Driver", "Other System Events", "Security State Change", "Logon", "Logoff", "Account Lockout", "IPsec Main Mode", "IPsec Quick Mode", "IPsec Extended Mode", "Special Logon", "Other Logon/Logoff Events", "Network Policy Server", "User / Device Claims", "Group Membership", "File System", "Registry", "Kernel Object", "SAM", "Certification Services", "Application Generated", "Handle Manipulation", "File Share", "Filtering Platform Packet Drop", "Filtering Platform Connection", "Other Object Access Events", "Detailed File Share", "Removable Storage", "Central Policy Staging", "Non Sensitive Privilege Use", "Other Privilege Use Events", "Sensitive Privilege Use", "Process Creation", "Process Termination", "DPAPI Activity", "RPC Events", "Plug and Play Events", "Token Right Adjusted Events", "Audit Policy Change", "Authentication Policy Change", "Authorization Policy Change", "MPSSVC Rule-Level Policy Change", "Filtering Platform Policy Change", "Other Policy Change Events", "Computer Account Management", "Security Group Management", "Distribution Group Management", "Application Group Management", "Other Account Management Events", "User Account Management", "Directory Service Access", "Directory Service Changes", "Directory Service Replication", "Detailed Directory Service Replication", "Kerberos Service Ticket Operations", "Kerberos Service Ticket Operations", "Other Account Logon Events", "Kerberos Authentication Service", "Credential Validation")][alias('Policies')][string[]] $Policy) if ($PSBoundParameters.ContainsKey('FilePath')) { if ($FilePath -and (Test-Path -LiteralPath $FilePath)) { try { $FileContent = Get-Content -LiteralPath $FilePath -Raw -ErrorAction Stop $SystemPolicies = $FileContent | ConvertFrom-Json -ErrorAction Stop } catch { Write-Warning -Message "Restore-SystemAuditPolicy - JSON $JSON is not valid. Restore aborted. Error: $($_.Exception.Message)" } } else { Write-Warning -Message "Restore-SystemAuditPolicy - File $FilePath not found. Restore aborted." } } elseif ($PSBoundParameters.ContainsKey('Object')) { $SystemPolicies = $Object } elseif ($PSBoundParameters.ContainsKey('JSON')) { try { $SystemPolicies = $JSON | ConvertFrom-Json -ErrorAction Stop } catch { Write-Warning -Message "Restore-SystemAuditPolicy - JSON $JSON is not valid. Restore aborted. Error: $($_.Exception.Message)" return } } else { Write-Warning -Message "Restore-SystemAuditPolicy - No file or object specified. Restore aborted." return } if ($SystemPolicies) { $AuditPolicy = Get-SystemAuditPolicy -ComputerName $ComputerName if ($AuditPolicy) { if ($SystemPolicies -is [System.Collections.IDictionary]) { foreach ($CurrentPolicy in $SystemPolicies.Keys) { if ($Policy) { if ($CurrentPolicy -notin $Policy) { continue } } $Value = $SystemPolicies[$CurrentPolicy] if ($Value -ne $AuditPolicy[$CurrentPolicy]) { $setSystemAuditPolicySplat = @{Policy = $CurrentPolicy ComputerName = $ComputerName WhatIf = $WhatIfPreference Value = $Value } $Success = Set-SystemAuditPolicy @setSystemAuditPolicySplat $Success } else { [PSCustomObject] @{'Policy' = $CurrentPolicy 'Value' = $Value 'Result' = 'Not required' 'Error' = '' } } } } else { foreach ($CurrentPolicy in $SystemPolicies.PSObject.Properties.Name) { if ($Policy) { if ($CurrentPolicy -notin $Policy) { continue } } $Value = $SystemPolicies.$CurrentPolicy if ($Value -ne $AuditPolicy[$CurrentPolicy]) { Write-Verbose -Message "Restore-SystemAuditPolicies - Current value for $CurrentPolicy is $($AuditPolicy[$CurrentPolicy]) to be replaced with $Value" $setSystemAuditPolicySplat = @{Policy = $CurrentPolicy ComputerName = $ComputerName WhatIf = $WhatIfPreference Value = $Value } $Success = Set-SystemAuditPolicy @setSystemAuditPolicySplat $Success } else { [PSCustomObject] @{'Policy' = $CurrentPolicy 'Value' = $Value 'Result' = 'Not required' 'Error' = '' } Write-Verbose -Message "Restore-SystemAuditPolicies - Current value for $CurrentPolicy is $($AuditPolicy[$CurrentPolicy]) is the same as requested $Value" } } } } } } function Set-SystemAuditPolicy { <# .SYNOPSIS Sets the audit policy similary to what auditpol.exe does. .DESCRIPTION Sets the audit policy similary to what auditpol.exe does. .PARAMETER ComputerName ComputerName for remote system to clear audit policy from. Requires permissions on the destination. .PARAMETER Policy The policy to set from all categories .PARAMETER AccountLogon Choose one of the options for the AccountLogon parameter. .PARAMETER AccountManagement Choose one of the options for the AccountManagement parameter. .PARAMETER DetailedTracking Choose one of the options for the DetailedTracking parameter. .PARAMETER DSAccess Choose one of the options for the DSAccess parameter. .PARAMETER LogonLogoff Choose one of the options for the LogonLogoff parameter. .PARAMETER ObjectAccess Choose one of the options for the ObjectAccess parameter. .PARAMETER PolicyChange Choose one of the options for the PolicyChange parameter. .PARAMETER PrivilegeUse Choose one of the options for the PrivilegeUse parameter. .PARAMETER System Choose one of the options for the System parameter. .PARAMETER Value Choose one of the options for the Value parameter. .PARAMETER UseAuditPol Forces use of AuditPol.exe instead of registry approach .PARAMETER UseLocalSecurityPolicy Forces use of LocalSecurityPolicy (audit.csv) to instead of registry approach It's important to know that refresh of policies happens on next GPO refresh rather than being applied immediately. .PARAMETER Suppress Suppresses the output of the command .EXAMPLE $WhatIf = $false Set-SystemAuditPolicy -AccountLogon 'Kerberos Service Ticket Operations' -Value Failure -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountLogon 'Other AccountLogon Events' -Value Failure -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountLogon 'Kerberos Authentication Service' -Value SuccessAndFailure -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountLogon 'Credential Validation' -Value Success -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountManagement 'Computer Account Management' -Value Failure -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountManagement 'Application Group Management' -Value Success -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountManagement 'Distribution Group Management' -Value Failure -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountManagement 'Other Account ManagementEvents' -Value Failure -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountManagement 'Security Group Management' -Value Failure -Verbose -WhatIf:$WhatIf Set-SystemAuditPolicy -AccountManagement 'User Account Management' -Value Failure -Verbose -WhatIf:$WhatIf .EXAMPLE Set-SystemAuditPolicy -AccountManagement 'User Account Management' -Value Failure -Verbose -WhatIf -UseLocalSecurityPolicy .EXAMPLE Set-SystemAuditPolicy -AccountManagement 'User Account Management' -Value Failure -Verbose -WhatIf -UseAuditPol .NOTES General notes #> [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = 'AllPolicies')] param([string] $ComputerName, [parameter(Mandatory, ParameterSetName = 'AllPolicies')] [ValidateSet("Security System Extension", "System Integrity", "IPsec Driver", "Other System Events", "Security State Change", "Logon", "Logoff", "Account Lockout", "IPsec Main Mode", "IPsec Quick Mode", "IPsec Extended Mode", "Special Logon", "Other Logon/Logoff Events", "Network Policy Server", "User / Device Claims", "Group Membership", "File System", "Registry", "Kernel Object", "SAM", "Certification Services", "Application Generated", "Handle Manipulation", "File Share", "Filtering Platform Packet Drop", "Filtering Platform Connection", "Other Object Access Events", "Detailed File Share", "Removable Storage", "Central Policy Staging", "Non Sensitive Privilege Use", "Other Privilege Use Events", "Sensitive Privilege Use", "Process Creation", "Process Termination", "DPAPI Activity", "RPC Events", "Plug and Play Events", "Token Right Adjusted Events", "Audit Policy Change", "Authentication Policy Change", "Authorization Policy Change", "MPSSVC Rule-Level Policy Change", "Filtering Platform Policy Change", "Other Policy Change Events", "Computer Account Management", "Security Group Management", "Distribution Group Management", "Application Group Management", "Other Account Management Events", "User Account Management", "Directory Service Access", "Directory Service Changes", "Directory Service Replication", "Detailed Directory Service Replication", "Kerberos Service Ticket Operations", "Kerberos Service Ticket Operations", "Other Account Logon Events", "Kerberos Authentication Service", "Credential Validation")][alias('Policies')][string] $Policy, [parameter(Mandatory, ParameterSetName = 'AccountLogon')][ValidateSet('Credential Validation', 'Kerberos Service Ticket Operations', 'Other Account Logon Events', 'Kerberos Authentication Service')][string] $AccountLogon, [parameter(Mandatory, ParameterSetName = 'AccountManagement')][ValidateSet('User Account Management', 'Computer Account Management', 'Security Group Management', 'Distribution Group Management', 'Application Group Management', 'Other Account Management Events')][string] $AccountManagement, [parameter(Mandatory, ParameterSetName = 'DetailedTracking')][ValidateSet('Process Creation', 'Process Termination', 'DPAPI Activity', 'RPC Events', 'Plug and Play Events', 'Token Right Adjusted Events')][string] $DetailedTracking, [parameter(Mandatory, ParameterSetName = 'DSAccess')][ValidateSet('Directory Service Access', 'Directory Service Changes', 'Directory Service Replication', 'Detailed Directory Service Replication')][string] $DSAccess, [parameter(Mandatory, ParameterSetName = 'LogonLogoff')][ValidateSet('Logon', 'Logoff', 'Account Lockout', 'IPSec Main Mode', 'Special Logon', 'IPSec Quick Mode', 'IPSec Extended Mode', 'Other Logon/Logoff Events', 'Network Policy Server', 'User / Device Claims', 'Group Membership')][string] $LogonLogoff, [parameter(Mandatory, ParameterSetName = 'ObjectAccess')][ValidateSet('File System', 'Registry', 'Kernel Object', 'SAM', 'Other Object Access Events', 'Certification Services', 'Application Generated', 'Handle Manipulation', 'File Share', 'Filtering Platform Packet Drop', 'Filtering Platform Connection', 'Detailed File Share', 'Removable Storage', 'Central Policy Staging')][string] $ObjectAccess, [parameter(Mandatory, ParameterSetName = 'PolicyChange')][ValidateSet('Audit Policy Change', 'Authentication Policy Change', 'Authorization Policy Change', 'MPSSVC Rule-Level Policy Change', 'Filtering Platform Policy Change', 'Other Policy Change Events')][string] $PolicyChange, [parameter(Mandatory, ParameterSetName = 'PrivilegeUse')][ValidateSet('Sensitive Privilege Use', 'Non Sensitive Privilege Use', 'Other Privilege Use Events')][string] $PrivilegeUse, [parameter(Mandatory, ParameterSetName = 'System')][ValidateSet('Security State Change', 'Security System Extension', 'System Integrity', 'IPsec Driver', 'Other System Events')][string] $System, [parameter(Mandatory)][validateSet('NoAuditing', 'NotConfigured', 'Success', 'Failure', 'SuccessAndFailure')][string] $Value, [switch] $UseAuditPol, [switch] $UseLocalSecurityPolicy, [switch] $Suppress) Add-Type -TypeDefinition @" using System; namespace AuditPolicies { public enum Events { NoAuditing = 0, NotConfigured = 0, Success = 1, Failure = 2, SuccessAndFailure = 3 } } "@ $AuditValues = @{'NoAuditing' = 0 'NotConfigured' = 0 'Success' = 1 'Failure' = 2 'SuccessAndFailure' = 3 } $AuditPoliciesByte = [ordered] @{AccountLogon = [ordered] @{'Credential Validation' = 122 'Kerberos Service Ticket Operations' = 124 'Other Account Logon Events' = 126 'Kerberos Authentication Service' = 128 } AccountManagement = [ordered] @{'User Account Management' = 102 'Computer Account Management' = 104 'Security Group Management' = 106 'Distribution Group Management' = 108 'Application Group Management' = 110 'Other Account Management Events' = 112 } DetailedTracking = [ordered] @{'Process Creation' = 78 'Process Termination' = 80 'DPAPI Activity' = 82 'RPC Events' = 84 'Plug and Play Events' = 86 'Token Right Adjusted Events' = 88 } DSAccess = [ordered] @{'Directory Service Access' = 114 'Directory Service Changes' = 116 'Directory Service Replication' = 118 'Detailed Directory Service Replication' = 120 } LogonLogoff = [ordered] @{'Logon' = 22 'Logoff' = 24 'Account Lockout' = 26 'IPSec Main Mode' = 28 'Special Logon' = 30 'IPSec Quick Mode' = 32 'IPSec Extended Mode' = 34 'Other Logon/Logoff Events' = 36 'Network Policy Server' = 38 'User / Device Claims' = 40 'Group Membership' = 42 } ObjectAccess = [ordered] @{'File System' = 44 'Registry' = 46 'Kernel Object' = 48 'SAM' = 50 'Other Object Access Events' = 52 'Certification Services' = 54 'Application Generated' = 56 'Handle Manipulation' = 58 'File Share' = 60 'Filtering Platform Packet Drop' = 62 'Filtering Platform Connection' = 64 'Detailed File Share' = 66 'Removable Storage' = 68 'Central Policy Staging' = 70 } PolicyChange = [ordered] @{'Audit Policy Change' = 90 'Authentication Policy Change' = 92 'Authorization Policy Change' = 94 'MPSSVC Rule-Level Policy Change' = 96 'Filtering Platform Policy Change' = 98 'Other Policy Change Events' = 100 } PrivilegeUse = [ordered] @{'Sensitive Privilege Use' = 72 'Non Sensitive Privilege Use' = 74 'Other Privilege Use Events' = 76 } System = [ordered] @{'Security State Change' = 12 'Security System Extension' = 14 'System Integrity' = 16 'IPsec Driver' = 18 'Other System Events' = 20 } } $BoundParameters = $PSBoundParameters $CurrentParameterSet = $PsCmdlet.ParameterSetName $ChosenParameter = $BoundParameters.$CurrentParameterSet if ($UseAuditPol) { if ($Policy) { Set-SystemAuditPolicyAuditpol -Policies $Policy -Value $Value -WhatIf:$WhatIfPreference } elseif ($ChosenParameter) { Set-SystemAuditPolicyAuditpol -Policies $ChosenParameter -Value $Value -WhatIf:$WhatIfPreference } } elseif ($UseLocalSecurityPolicy) { if ($Policy) { Set-SystemAuditPolicyLocalSecurity -Policies $Policy -Value $Value -WhatIf:$WhatIfPreference } elseif ($ChosenParameter) { Set-SystemAuditPolicyLocalSecurity -Policies $ChosenParameter -Value $Value -WhatIf:$WhatIfPreference } } else { $IsSystem = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem if (-not $IsSystem) { $SID = ConvertFrom-SID -SID "S-1-5-32-544" Set-SystemAuditPolicyPermissions -Identity $SID.Name -Permissions FullControl -WhatIf:$false } $Audit = Get-PSRegistry -RegistryPath "HKEY_LOCAL_MACHINE\SECURITY\Policy\PolAdtEv" -Key "" -ComputerName $ComputerName if ($Audit.PSConnection -eq $true -and $Audit.PSError -eq $false) {} else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $($Audit.PSErrorMessage) } else { Write-Warning -Message "Set-SystemAuditPolicy - Audit policies couldn't be read: $($Audit.PSErrorMessage)" } return } if ($CurrentParameterSet) { if ($CurrentParameterSet -eq 'AllPolicies') { foreach ($Key in $AuditPoliciesByte.Keys) { if ($AuditPoliciesByte[$Key][$Policy]) { $ByteNumber = $AuditPoliciesByte[$Key][$Policy] $CurrentParameterSet = $Key $ChosenParameter = $Policy break } } } else { $ByteNumber = $AuditPoliciesByte[$CurrentParameterSet][$ChosenParameter] } $ExpectedValue = $AuditValues[$Value] $CurrentValue = $Audit.PSValue[$ByteNumber] $CurrentTranslatedValue = [AuditPolicies.Events] $CurrentValue $ExpectedTranslatedValue = [AuditPolicies.Events] $ExpectedValue Write-Verbose -Message "Set-SystemAuditPolicy - Current value for $CurrentParameterSet\$ChosenParameter is $CurrentTranslatedValue ($CurrentValue) to be replaced with $ExpectedTranslatedValue ($ExpectedValue)" if ($CurrentTranslatedValue -ne $ExpectedTranslatedValue) { $ValueToSet = $Audit.PSValue $ValueToSet[$ByteNumber] = $ExpectedValue if ($PSCmdlet.ShouldProcess("SubCategory $Policy", "Setting $Value on $Policy")) { $AuditOutput = Set-PSRegistry -RegistryPath "HKEY_LOCAL_MACHINE\SECURITY\Policy\PolAdtEv" -Key "" -ComputerName $ComputerName -Type None -Value $ValueToSet -WhatIf:$WhatIfPreference if ($AuditOutput.PSConnection -eq $true -and $AuditOutput.PSError -eq $false) { $Result = 'Success' $Message = '' } else { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw $($AuditOutput.PSErrorMessage) } else { Write-Warning -Message "Set-SystemAuditPolicy - Audit policies couldn't be set because: $($AuditOutput.PSErrorMessage)" } $Result = 'Failed' $Message = $($AuditOutput.PSErrorMessage) } } else { $Result = 'WhatIf' $Message = 'WhatIf in use.' } } else { $Result = 'Not required' Write-Verbose -Message "Set-SystemAuditPolicy - Current value for $CurrentParameterSet\$ChosenParameter ($ByteNumber) is $CurrentTranslatedValue ($CurrentValue) - nothing to do." } } if (-not $IsSystem) { $SID = ConvertFrom-SID -SID "S-1-5-32-544" Remove-SystemAuditPolicyPermissions -Identity $SID.Name -Permissions FullControl -WhatIf:$false } if (-not $Suppress) { [PSCustomObject] @{'Policy' = $ChosenParameter 'Value' = $ExpectedTranslatedValue 'Result' = $Result 'Error' = $Message } } } } function Set-SystemAuditPolicyPermissions { <# .SYNOPSIS This function will set the audit policy permissions for the specified user or group to FullControl. .DESCRIPTION This function will set the audit policy permissions for the specified user or group to FullControl. By default only SYSTEM account has any permission. This command can be used to add audit policy permissions for the specified user or group. .PARAMETER Identity The identity of the user or group to set the audit policy permissions for .PARAMETER Permissions The permissions to set for the specified user or group. By default FullControl. .EXAMPLE Set-SystemAuditPolicyPermissions -Identity "przemyslaw.klys" -Verbose -WhatIf .NOTES General notes #> [cmdletBinding(SupportsShouldProcess)] param([parameter(Mandatory)][string] $Identity, [System.Security.AccessControl.RegistryRights] $Permissions = [System.Security.AccessControl.RegistryRights]::FullControl) try { $RegistryKeyControl = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SECURITY', [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree, [System.Security.AccessControl.RegistryRights]::ChangePermissions) } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyPermissions - Opening registry failed $($_.Exception.Message)" } return } $AccessControlList = $RegistryKeyControl.GetAccessControl() $Account = [System.Security.Principal.NTAccount] $Identity $InheritanceFlag = [System.Security.AccessControl.InheritanceFlags]'ContainerInherit,ObjectInherit' $PropagationFlag = [System.Security.AccessControl.PropagationFlags]::None $AccessType = [System.Security.AccessControl.AccessControlType]::Allow $AccessRule = [System.Security.AccessControl.RegistryAccessRule]::new($Account, $Permissions, $InheritanceFlag, $PropagationFlag, $AccessType) if ($PSCmdlet.ShouldProcess("Registry HKLM\Security", "Adding 'FullControl' access to $Identity for SECURITY subkey")) { try { $AccessControlList.AddAccessRule($AccessRule) } catch { if ($PSBoundParameters.ErrorAction -eq 'Stop') { throw } else { Write-Warning -Message "Set-SystemAuditPolicyPermissions - Adding access rule failed $($_.Exception.Message)" } } $RegistryKeyControl.SetAccessControl($AccessControlList) } } Export-ModuleMember -Function @('Backup-SystemAuditPolicy', 'Clear-SystemAuditPolicy', 'Get-SystemAuditPolicy', 'Get-SystemAuditPolicyFromFile', 'Remove-SystemAuditPolicyPermissions', 'Restore-SystemAuditPolicy', 'Set-SystemAuditPolicy', 'Set-SystemAuditPolicyPermissions') -Alias @() # SIG # Begin signature block # MIIhjgYJKoZIhvcNAQcCoIIhfzCCIXsCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU3PZJ5TRCJRpwMAKb+0kHNWF0 # xcGgghusMIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0B # AQUFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk # IElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg # Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg # +XESpa7cJpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lT # XDGEKvYPmDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5 # a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g # 0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1 # roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf # GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G # A1UdDgQWBBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLL # gjEtUYunpyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3 # cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmr # EthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+ # fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5Q # Z7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu # 838fYxAe+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw # 8jCCBTAwggQYoAMCAQICEAQJGBtf1btmdVNDtW+VUAgwDQYJKoZIhvcNAQELBQAw # ZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ # d3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBS # b290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcjELMAkGA1UE # BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj # ZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUg # U2lnbmluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPjTsxx/ # DhGvZ3cH0wsxSRnP0PtFmbE620T1f+Wondsy13Hqdp0FLreP+pJDwKX5idQ3Gde2 # qvCchqXYJawOeSg6funRZ9PG+yknx9N7I5TkkSOWkHeC+aGEI2YSVDNQdLEoJrsk # acLCUvIUZ4qJRdQtoaPpiCwgla4cSocI3wz14k1gGL6qxLKucDFmM3E+rHCiq85/ # 6XzLkqHlOzEcz+ryCuRXu0q16XTmK/5sy350OTYNkO/ktU6kqepqCquE86xnTrXE # 94zRICUj6whkPlKWwfIPEvTFjg/BougsUfdzvL2FsWKDc0GCB+Q4i2pzINAPZHM8 # np+mM6n9Gd8lk9ECAwEAAaOCAc0wggHJMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYD # VR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHkGCCsGAQUFBwEBBG0w # azAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUF # BzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk # SURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdp # Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRw # Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3Js # ME8GA1UdIARIMEYwOAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczov # L3d3dy5kaWdpY2VydC5jb20vQ1BTMAoGCGCGSAGG/WwDMB0GA1UdDgQWBBRaxLl7 # KgqjpepxA8Bg+S32ZXUOWDAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823I # DzANBgkqhkiG9w0BAQsFAAOCAQEAPuwNWiSz8yLRFcgsfCUpdqgdXRwtOhrE7zBh # 134LYP3DPQ/Er4v97yrfIFU3sOH20ZJ1D1G0bqWOWuJeJIFOEKTuP3GOYw4TS63X # X0R58zYUBor3nEZOXP+QsRsHDpEV+7qvtVHCjSSuJMbHJyqhKSgaOnEoAjwukaPA # JRHinBRHoXpoaK+bp1wgXNlxsQyPu6j4xRJon89Ay0BEpRPw5mQMJQhCMrI2iiQC # /i9yfhzXSUWW6Fkd6fp0ZGuy62ZD2rOwjNXpDd32ASDOmTFjPQgaGLOBm0/GkxAG # /AeB+ova+YJJ92JuoVP6EpQYhS6SkepobEQysmah5xikmmRR7zCCBT0wggQloAMC # AQICEATV3B9I6snYUgC6zZqbKqcwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UEBhMC # VVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0 # LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2ln # bmluZyBDQTAeFw0yMDA2MjYwMDAwMDBaFw0yMzA3MDcxMjAwMDBaMHoxCzAJBgNV # BAYTAlBMMRIwEAYDVQQIDAnFmmzEhXNraWUxETAPBgNVBAcTCEthdG93aWNlMSEw # HwYDVQQKDBhQcnplbXlzxYJhdyBLxYJ5cyBFVk9URUMxITAfBgNVBAMMGFByemVt # eXPFgmF3IEvFgnlzIEVWT1RFQzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC # ggEBAL+ygd4sga4ZC1G2xXvasYSijwWKgwapZ69wLaWaZZIlY6YvXTGQnIUnk+Tg # 7EoT7mQiMSaeSPOrn/Im6N74tkvRfQJXxY1cnt3U8//U5grhh/CULdd6M3/Z4h3n # MCq7LQ1YVaa4MYub9F8WOdXO84DANoNVG/t7YotL4vzqZil3S9pHjaidp3kOXGJc # vxrCPAkRFBKvUmYo23QPFa0Rd0qA3bFhn97WWczup1p90y2CkOf28OVOOObv1fNE # EqMpLMx0Yr04/h+LPAAYn6K4YtIu+m3gOhGuNc3B+MybgKePAeFIY4EQzbqvCMy1 # iuHZb6q6ggRyqrJ6xegZga7/gV0CAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrE # uXsqCqOl6nEDwGD5LfZldQ5YMB0GA1UdDgQWBBQYsTUn6BxQICZOCZA0CxS0TZSU # ZjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAw # bjA1oDOgMYYvaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1j # cy1nMS5jcmwwNaAzoDGGL2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFz # c3VyZWQtY3MtZzEuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYB # BQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGE # BggrBgEFBQcBAQR4MHYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0 # LmNvbTBOBggrBgEFBQcwAoZCaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0U0hBMkFzc3VyZWRJRENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQC # MAAwDQYJKoZIhvcNAQELBQADggEBAJq9bM+JbCwEYuMBtXoNAfH1SRaMLXnLe0py # VK6el0Z1BtPxiNcF4iyHqMNVD4iOrgzLEVzx1Bf/sYycPEnyG8Gr2tnl7u1KGSjY # enX4LIXCZqNEDQCeTyMstNv931421ERByDa0wrz1Wz5lepMeCqXeyiawqOxA9fB/ # 106liR12vL2tzGC62yXrV6WhD6W+s5PpfEY/chuIwVUYXp1AVFI9wi2lg0gaTgP/ # rMfP1wfVvaKWH2Bm/tU5mwpIVIO0wd4A+qOhEia3vn3J2Zz1QDxEprLcLE9e3Gmd # G5+8xEypTR23NavhJvZMgY2kEXBEKEEDaXs0LoPbn6hMcepR2A4wggauMIIElqAD # AgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYT # AlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2Vy # dC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMjAz # MjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQK # Ew5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBS # U0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdRodbSg9GeTKJtoLDM # g/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhXqAJ9/UO0hNoR8XOx # s+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69OxtXXnHwZljZQp09ns # ad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ3V+0VAshaG43IbtA # rF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLFuk4fsbVYTXn+149z # k6wsOeKlSNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD40NjgHt1biclkJg6 # OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpURK1h0QCirc0PO30qh # HGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/STKvvmz3+DrhkKvp1 # KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfcYd6T/jnA+bIwpUzX # 6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31fI7tk42PgpuE+9sJ0 # sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a50g5rmQzSM7TNsQID # AQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUuhbZbU2F # L3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08w # DgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEB # BGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsG # AQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz # dGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgG # BmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBAH1ZjsCTtm+Y # qUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaopafxpwc8dB+k+YMjY # C+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXONASIlzpVpP0d3+3J0 # FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9nXzQcAp876i8dU+6 # WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4mwbfeKuv2nrF5mYGj # VoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4cku0+jSbl3ZpHxcpzp # SwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2QJshIUDQtxMkzdwd # eDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmHQXh6OOmc4d0j/R0o # 08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZynDwN7+YAN8gFk8n # +2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+v6TR81fZvAT6gt4y # 3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8mJb2VVQrH4D6wPIO # K+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIGxjCCBK6gAwIBAgIQCnpKiJ7JmUKQ # BmM4TYaXnTANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMO # RGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNB # NDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTIyMDMyOTAwMDAwMFoXDTMz # MDMxNDIzNTk1OVowTDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMSQwIgYDVQQDExtEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMiAtIDIwggIiMA0G # CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC5KpYjply8X9ZJ8BWCGPQz7sxcbOPg # JS7SMeQ8QK77q8TjeF1+XDbq9SWNQ6OB6zhj+TyIad480jBRDTEHukZu6aNLSOiJ # QX8Nstb5hPGYPgu/CoQScWyhYiYB087DbP2sO37cKhypvTDGFtjavOuy8YPRn80J # xblBakVCI0Fa+GDTZSw+fl69lqfw/LH09CjPQnkfO8eTB2ho5UQ0Ul8PUN7UWSxE # dMAyRxlb4pguj9DKP//GZ888k5VOhOl2GJiZERTFKwygM9tNJIXogpThLwPuf4UC # yYbh1RgUtwRF8+A4vaK9enGY7BXn/S7s0psAiqwdjTuAaP7QWZgmzuDtrn8oLsKe # 4AtLyAjRMruD+iM82f/SjLv3QyPf58NaBWJ+cCzlK7I9Y+rIroEga0OJyH5fsBrd # Gb2fdEEKr7mOCdN0oS+wVHbBkE+U7IZh/9sRL5IDMM4wt4sPXUSzQx0jUM2R1y+d # +/zNscGnxA7E70A+GToC1DGpaaBJ+XXhm+ho5GoMj+vksSF7hmdYfn8f6CvkFLIW # 1oGhytowkGvub3XAsDYmsgg7/72+f2wTGN/GbaR5Sa2Lf2GHBWj31HDjQpXonrub # S7LitkE956+nGijJrWGwoEEYGU7tR5thle0+C2Fa6j56mJJRzT/JROeAiylCcvd5 # st2E6ifu/n16awIDAQABo4IBizCCAYcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB # /wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZngQwB # BAIwCwYJYIZIAYb9bAcBMB8GA1UdIwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCPnshv # MB0GA1UdDgQWBBSNZLeJIf5WWESEYafqbxw2j92vDTBaBgNVHR8EUzBRME+gTaBL # hklodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0 # MDk2U0hBMjU2VGltZVN0YW1waW5nQ0EuY3JsMIGQBggrBgEFBQcBAQSBgzCBgDAk # BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAC # hkxodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRS # U0E0MDk2U0hBMjU2VGltZVN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4IC # AQANLSN0ptH1+OpLmT8B5PYM5K8WndmzjJeCKZxDbwEtqzi1cBG/hBmLP13lhk++ # kzreKjlaOU7YhFmlvBuYquhs79FIaRk4W8+JOR1wcNlO3yMibNXf9lnLocLqTHbK # odyhK5a4m1WpGmt90fUCCU+C1qVziMSYgN/uSZW3s8zFp+4O4e8eOIqf7xHJMUpY # tt84fMv6XPfkU79uCnx+196Y1SlliQ+inMBl9AEiZcfqXnSmWzWSUHz0F6aHZE8+ # RokWYyBry/J70DXjSnBIqbbnHWC9BCIVJXAGcqlEO2lHEdPu6cegPk8QuTA25POq # aQmoi35komWUEftuMvH1uzitzcCTEdUyeEpLNypM81zctoXAu3AwVXjWmP5UbX9x # qUgaeN1Gdy4besAzivhKKIwSqHPPLfnTI/KeGeANlCig69saUaCVgo4oa6TOnXbe # qXOqSGpZQ65f6vgPBkKd3wZolv4qoHRbY2beayy4eKpNcG3wLPEHFX41tOa1DKKZ # pdcVazUOhdbgLMzgDCS4fFILHpl878jIxYxYaa+rPeHPzH0VrhS/inHfypex2Efq # HIXgRU4SHBQpWMxv03/LvsEOSm8gnK7ZczJZCOctkqEaEf4ymKZdK5fgi9OczG21 # Da5HYzhHF1tvE9pqEG4fSbdEW7QICodaWQR2EaGndwITHDGCBUwwggVIAgEBMIGG # MHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT # EHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJl # ZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEATV3B9I6snYUgC6zZqbKqcwCQYFKw4DAhoF # AKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisG # AQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcN # AQkEMRYEFKqUvvAT4KBQD95u0llXuNolOrNOMA0GCSqGSIb3DQEBAQUABIIBAEfI # JMqPwhs08B+Zh7uVkiMAH8WpQUXmNDmJn2+DTv1iO+cMPMnl0kTzvGUqMXSNJaKo # m73Sxc54qJtGtqyfYTyWcgLQbR4S6SJ6w+1znxWNDDG8EBpPwDdDor3qRv+Keynf # hq6FmrMuKzBOlWuQkJv75cwdvQ5/H0fSFecVSFzlOaa+niG5CuNslI5DX3UIMSVl # +j6Bm02zOz1DzxHTV8bCDeRNcpJpNJzpb8QKuMe7u7J83kRaWm+j9c+pWrP8tDGt # HsPNmMHrzFcMe4xjT6nft3z2Gsc/jdxYjguoaPgMXh/+dt5G8YPZnclCrjf9jur/ # kbtOXUl5Px4Lof+OfiGhggMgMIIDHAYJKoZIhvcNAQkGMYIDDTCCAwkCAQEwdzBj # MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMT # MkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5n # IENBAhAKekqInsmZQpAGYzhNhpedMA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcN # AQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMjIwNTE1MTk0NTQyWjAv # BgkqhkiG9w0BCQQxIgQgPpNz7sAKZo9kOGjrFAqWslwFzP+rHBo3DMH6P5ZISwIw # DQYJKoZIhvcNAQEBBQAEggIAlt/KcnCelQGdeMreLU1p4wMOTw+/zf1OLiwI9Ry4 # cZ29MyF04Jdm/u3lei+QfWHO/CJHxhLv11+oaOxOGbQ3qL31r/HsQH4Gmedx4rk6 # P2SWebj/1/Rb7VYDJIdDZ6KBf6gsPgbnKs+nGVtrU8sKgVoscW0X5MPLzhZoVfhx # 2Y6J139UWUyfam8EgFNZY/lvROF5OXFoELoB+IPZQFnYl+TL8slHoo6LdvPmK7y5 # UP6mbgiW5Kif09LgPO8nrgILC5b40FGtCwHOfhtCli5VP4PD9Ed07uuG1+fNTary # vXaEGrV9YbKoFfA2/FTiJP5rz6OgrN7EnZQkqGx6lH+y6iZAa9dMKYEAmLBh+rGS # IAe13iwm9AiE2D0gaZJB+uE96wEWN/neOAYXO9fKmeNfaDeIKlyNpOp2HhERo28j # qQvXHtiEjwJYddYPh2XtmtLCE8YKF7/f5e5DCGcMsqFB+adv830zqHmlog05xZRW # L5IBm/QjHkti/lLZyE81wY/8SM7MM0s8L744zpmcslKmr0+tD0PO+JWUDYLNkbbw # M9w9dWc2dbwy9EVhMJ6/I86qYrD/gNqzPunEKrr44edMuUWihv6p+y7FQAnjvGhH # z+74PG6oF+YP9B0FFbnACXJ1LaI3pfLRg3KcDYjFkYFKUMrGi+LzQlC4eDKWTts+ # 7w0= # SIG # End signature block |