public/Get-IvantiWCRegistry.ps1
|
<#
.SYNOPSIS Reads and parses Ivanti Workspace Control registry sets from a Building Block XML file or a standalone .reg file. .DESCRIPTION Accepts either: - An Ivanti Workspace Control Building Block XML file: extracts every <registry type="registry"> node, decodes the hex-encoded registryfile, and parses it. Name and description are taken from the <name> and <description> XML elements. - A standalone .reg file: parses it directly. Name and description are read from the ;<PFNAME> and ;<PFDESC> comment tags if present. Each value entry is returned as a structured object with its registry hive, key, value name, value data, value type, and an optional per-value description captured from the ;<PF>...</PF> comment tag that may follow the value line. Supports all standard .reg value types: - REG_SZ (quoted string or hex(1):) - REG_EXPAND_SZ (hex(2):) - REG_BINARY (hex: / hex(3):) - REG_DWORD (dword: / hex(4):) - REG_MULTI_SZ (hex(7):) - REG_QWORD (qword: / hex(b):) .PARAMETER Path Path to an Ivanti Workspace Control Building Block XML file or a standalone .reg file. .PARAMETER ExportFor Target export format. 'AppVentiX' adds the AppVentiXParams property to each output object. Defaults to 'WEM'. .EXAMPLE # From a Building Block XML Get-IvantiWCRegistry -Path 'C:\temp\LAB-BB.xml' .EXAMPLE # From a standalone .reg file, exported for AppVentiX Get-IvantiWCRegistry -Path 'C:\temp\registry.reg' -ExportFor AppVentiX .NOTES Function : Get-IvantiWCRegistry Author : John Billekens Copyright : (c) John Billekens Consultancy & AppVentiX Version : 2026.0309.1200 #> function Get-IvantiWCRegistry { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidateScript({ Test-Path $_ -PathType Leaf })] [string]$Path, [ValidateSet('AppVentiX', 'WEM')] [string]$ExportFor = 'WEM' ) #region Internal helpers function Convert-HexToString { param([string]$HexString) if ([string]::IsNullOrEmpty($HexString)) { return '' } $bytes = for ($i = 0; $i -lt $HexString.Length; $i += 2) { [System.Convert]::ToByte($HexString.Substring($i, 2), 16) } return [System.Text.Encoding]::GetEncoding(1252).GetString($bytes) } function Convert-RegistryHexToValue { param([string]$hexString, [string]$type) $hexData = $hexString -replace '^hex\(\w+\):', '' -replace '[,\s]', '' if ([string]::IsNullOrEmpty($hexData)) { return $null } try { $bytes = for ($i = 0; $i -lt $hexData.Length; $i += 2) { [System.Convert]::ToByte($hexData.Substring($i, 2), 16) } switch ($type) { 'REG_SZ' { return [System.Text.Encoding]::Unicode.GetString($bytes).TrimEnd([char]0) } 'REG_EXPAND_SZ' { return [System.Text.Encoding]::Unicode.GetString($bytes).TrimEnd([char]0) } 'REG_BINARY' { return [System.BitConverter]::ToString($bytes) } 'REG_DWORD' { if ($bytes.Count -eq 4) { return [System.BitConverter]::ToUInt32($bytes, 0) } return $null } 'REG_MULTI_SZ' { $fullString = [System.Text.Encoding]::Unicode.GetString($bytes) return ($fullString -split '\0' | Where-Object { $_ }) } 'REG_QWORD' { if ($bytes.Count -eq 8) { return [System.BitConverter]::ToUInt64($bytes, 0) } return $null } default { return [System.BitConverter]::ToString($bytes) } } } catch { Write-Warning "Could not decode hex value for type $type. Error: $_" return $hexString } } function ConvertTo-RegistryEntries { param( [string]$Name, [string]$Description, [string]$RegContent, [string]$SourceFile, [bool]$Enabled = $true, [bool]$RunOnce = $false, [string]$ExportFor = 'WEM', [PSCustomObject[]]$Assignments = @() ) $lines = $RegContent.Split([string[]]@("`r`n", "`n", "`r"), [StringSplitOptions]::None) # If name/description not provided, fall back to PFNAME/PFDESC tags in the content $resolvedName = $Name $resolvedDescription = $Description if ([string]::IsNullOrEmpty($resolvedName) -or [string]::IsNullOrEmpty($resolvedDescription)) { foreach ($line in $lines) { if ([string]::IsNullOrEmpty($resolvedName) -and $line -match ';<PFNAME>(.+)</PFNAME>') { $resolvedName = $Matches[1].Trim() } if ([string]::IsNullOrEmpty($resolvedDescription) -and $line -match ';<PFDESC>(.+)</PFDESC>') { $resolvedDescription = $Matches[1].Trim() } if (-not [string]::IsNullOrEmpty($resolvedName) -and -not [string]::IsNullOrEmpty($resolvedDescription)) { break } } } Write-Verbose "Registry set: '$resolvedName' | Description: '$resolvedDescription' | Enabled: '$Enabled' | RunOnce: '$RunOnce'" $entries = [System.Collections.Generic.List[PSCustomObject]]::new() $currentHive = '' $currentKey = '' for ($i = 0; $i -lt $lines.Length; $i++) { $line = $lines[$i] # Section header: [HKEY_...] or ![HKEY_...] (delete entire key) if ($line -match '^(!?)\[((HKEY_[^\\]+)(\\(.+))?)\]$') { $isKeyDeletion = $Matches[1] -eq '!' $sectionHive = $Matches[3] $sectionKey = if ($Matches[5]) { $Matches[5] } else { '' } if ($isKeyDeletion) { # Emit a key-deletion entry; do not update current section context Write-Verbose " Delete key: $sectionHive\$sectionKey" $entries.Add([PSCustomObject]([ordered]@{ RegistryHive = $sectionHive RegistryKey = $sectionKey RegistryKeyPath = if ([string]::IsNullOrEmpty($sectionKey)) { $sectionHive } else { "$sectionHive\$sectionKey" } RegistryValueName = $null Value = $null ValueType = $null Description = '' Delete = $true })) } else { $currentHive = $sectionHive $currentKey = $sectionKey Write-Verbose " Section: $currentHive\$currentKey" } continue } # Skip comments, blank lines, and the editor header if ([string]::IsNullOrWhiteSpace($line) -or $line.StartsWith(';') -or $line.StartsWith('Windows Registry Editor')) { continue } # Skip structural placeholder default values (@="") on keys with no meaningful path # These are Ivanti reg file artifacts — empty-string default values on intermediate keys if ($line -match '^@=""$' -and [string]::IsNullOrEmpty($currentKey)) { continue } # Deletion marker on value: !"ValueName"=... $isDeletion = $false $parsedLine = $line if ($parsedLine.TrimStart().StartsWith('!"')) { $isDeletion = $true $parsedLine = $parsedLine.TrimStart().Substring(1) } $valueName = $null $rawValue = $null if ($parsedLine -match '^"([^"]*)"=(.+)') { $valueName = $Matches[1] $rawValue = $Matches[2].Trim() } elseif ($parsedLine -match '^@=(.+)') { $valueName = '' $rawValue = $Matches[1].Trim() } else { continue } # Skip empty-string default values on intermediate keys (structural artifacts) if ($valueName -eq '' -and $rawValue -eq '""') { continue } # Peek at next line for optional ;<PF>...</PF> per-value description $valueDescription = '' if (($i + 1) -lt $lines.Length -and $lines[$i + 1] -match ';<PF>(.+)</PF>') { $valueDescription = $Matches[1].Trim() } # Decode value data and determine type $registryValue = $null $registryValueType = 'Unknown' if ($rawValue.StartsWith('dword:')) { $registryValueType = 'REG_DWORD' try { $registryValue = [uint64]("0x" + $rawValue.Substring(6)) } catch { $registryValue = $rawValue; $registryValueType = 'Unknown' } } elseif ($rawValue.StartsWith('qword:')) { $registryValueType = 'REG_QWORD' try { $registryValue = [uint64]("0x" + $rawValue.Substring(6)) } catch { $registryValue = $rawValue; $registryValueType = 'Unknown' } } elseif ($rawValue.StartsWith('"') -and $rawValue.EndsWith('"')) { $registryValueType = 'REG_SZ' $registryValue = $rawValue.Substring(1, $rawValue.Length - 2) } elseif ($rawValue.StartsWith('hex(1):')) { $registryValueType = 'REG_SZ' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_SZ' } elseif ($rawValue.StartsWith('hex(2):')) { $registryValueType = 'REG_EXPAND_SZ' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_EXPAND_SZ' } elseif ($rawValue.StartsWith('hex(3):') -or $rawValue.StartsWith('hex:')) { $registryValueType = 'REG_BINARY' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_BINARY' } elseif ($rawValue.StartsWith('hex(4):')) { $registryValueType = 'REG_DWORD' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_DWORD' } elseif ($rawValue.StartsWith('hex(7):')) { $registryValueType = 'REG_MULTI_SZ' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_MULTI_SZ' } elseif ($rawValue.StartsWith('hex(b):')) { $registryValueType = 'REG_QWORD' $registryValue = Convert-RegistryHexToValue -hexString $rawValue -type 'REG_QWORD' } else { $registryValueType = 'REG_SZ' $registryValue = $rawValue } $entries.Add( [PSCustomObject]( [PSCustomObject]@{ RegistryHive = $currentHive RegistryKey = $currentKey RegistryKeyPath = if ([string]::IsNullOrEmpty($currentKey)) { $currentHive } else { "$currentHive\$currentKey" } RegistryValueName = $valueName Value = $registryValue ValueType = $registryValueType Description = $valueDescription Delete = $isDeletion } ) ) } Write-Verbose " Parsed $($entries.Count) registry value(s)" $output = [ordered]@{ Name = $resolvedName Description = $resolvedDescription Enabled = $Enabled RunOnce = $RunOnce Entries = $entries.ToArray() SourceFile = $SourceFile } if ($ExportFor -eq 'AppVentiX') { $registryEntries = @( foreach ($entry in $entries) { $deleteKey = $false if ($entry.Delete -eq $true -and [string]::IsNullOrEmpty($entry.RegistryValueName)) { $deleteKey = $true } $valueType = $entry.ValueType if ([string]::IsNullOrEmpty(($valueType))) { $valueType = 'REG_SZ' } [PSCustomObject]@{ RootKey = $entry.RegistryHive KeyPath = $entry.RegistryKey ValueName = $entry.RegistryValueName ValueData = $entry.Value ValueType = $valueType Action = if ($entry.Delete) { 'Remove' } else { 'Set' } DeleteKey = $deleteKey } } ) $output.AppVentiXAssignments = @($Assignments | Select-Object Sid, Name, Type, DomainFQDN) $output.AppVentiXParams = ( [ordered]@{ FriendlyName = $resolvedName Description = $resolvedDescription RegistryEntries = @($registryEntries) } ) } elseif ($ExportFor -eq 'WEM') { Write-Warning "WEM export format is not implemented yet for registry sets!" } [PSCustomObject]$output } #endregion $absolutePath = (Resolve-Path -LiteralPath $Path).Path $extension = [System.IO.Path]::GetExtension($absolutePath).ToLower() if ($extension -eq '.xml') { # Building Block XML — extract all <registry type="registry"> nodes Write-Verbose "Loading Building Block XML: $absolutePath" try { $xmlContent = New-Object System.Xml.XmlDocument $xmlContent.Load($absolutePath) } catch { $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.Xml.XmlException]::new("Failed to parse XML file '$absolutePath': $($_.Exception.Message)"), 'XmlParseError', [System.Management.Automation.ErrorCategory]::InvalidData, $absolutePath ) ) } $registryNodes = @($xmlContent.GetElementsByTagName('registry') | Where-Object { $_.type -eq 'registry' }) Write-Verbose "Found $($registryNodes.Count) registry set node(s)" if ($registryNodes.Count -eq 0) { Write-Warning "No <registry type='registry'> nodes found in '$absolutePath'" return } foreach ($node in $registryNodes) { $nodeName = $node.name $nodeDescription = $node.description $decodedContent = (Convert-HexToString -HexString $node.registryfile).TrimStart([char]0xFEFF) if ($node.enabled -ieq "yes") { $enabled = $true } else { $enabled = $false } if ($node.runonce -ieq "yes") { $runOnce = $true } else { $runOnce = $false } Write-Verbose "Processing registry set: '$nodeName'" $Assignments = @(ConvertFrom-IvantiAccessControl -AccessControl $node.accesscontrol -IWCComponentName $nodeName -IWCComponent "Policy") ConvertTo-RegistryEntries -Name $nodeName -Description $nodeDescription -RunOnce $runOnce -RegContent $decodedContent -SourceFile $absolutePath -ExportFor $ExportFor -Assignments $Assignments } } else { # Standalone .reg file Write-Verbose "Loading .reg file: $absolutePath" try { $rawContent = Get-Content -LiteralPath $absolutePath -Raw -ErrorAction Stop } catch { $PSCmdlet.ThrowTerminatingError( [System.Management.Automation.ErrorRecord]::new( [System.IO.IOException]::new("Failed to read file '$absolutePath': $($_.Exception.Message)"), 'RegFileReadError', [System.Management.Automation.ErrorCategory]::ReadError, $absolutePath ) ) } ConvertTo-RegistryEntries -Name '' -Description '' -RegContent $rawContent -SourceFile $absolutePath -ExportFor $ExportFor } } # SIG # Begin signature block # MIImdwYJKoZIhvcNAQcCoIImaDCCJmQCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB4GjVcwK8Xe1J4 # N4GEaE9cBZ4zAjIXzYmLcMvb3LoCEqCCIAowggYUMIID/KADAgECAhB6I67aU2mW # D5HIPlz0x+M/MA0GCSqGSIb3DQEBDAUAMFcxCzAJBgNVBAYTAkdCMRgwFgYDVQQK # Ew9TZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRpbWUg # U3RhbXBpbmcgUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIxMjM1OTU5 # WjBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYD # VQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNjCCAaIwDQYJ # KoZIhvcNAQEBBQADggGPADCCAYoCggGBAM2Y2ENBq26CK+z2M34mNOSJjNPvIhKA # VD7vJq+MDoGD46IiM+b83+3ecLvBhStSVjeYXIjfa3ajoW3cS3ElcJzkyZlBnwDE # JuHlzpbN4kMH2qRBVrjrGJgSlzzUqcGQBaCxpectRGhhnOSwcjPMI3G0hedv2eNm # GiUbD12OeORN0ADzdpsQ4dDi6M4YhoGE9cbY11XxM2AVZn0GiOUC9+XE0wI7CQKf # OUfigLDn7i/WeyxZ43XLj5GVo7LDBExSLnh+va8WxTlA+uBvq1KO8RSHUQLgzb1g # bL9Ihgzxmkdp2ZWNuLc+XyEmJNbD2OIIq/fWlwBp6KNL19zpHsODLIsgZ+WZ1AzC # s1HEK6VWrxmnKyJJg2Lv23DlEdZlQSGdF+z+Gyn9/CRezKe7WNyxRf4e4bwUtrYE # 2F5Q+05yDD68clwnweckKtxRaF0VzN/w76kOLIaFVhf5sMM/caEZLtOYqYadtn03 # 4ykSFaZuIBU9uCSrKRKTPJhWvXk4CllgrwIDAQABo4IBXDCCAVgwHwYDVR0jBBgw # FoAU9ndq3T/9ARP/FqFsggIv0Ao9FCUwHQYDVR0OBBYEFF9Y7UwxeqJhQo1SgLqz # YZcZojKbMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMGA1Ud # JQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYEVR0gADBMBgNVHR8ERTBDMEGg # P6A9hjtodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1lU3Rh # bXBpbmdSb290UjQ2LmNybDB8BggrBgEFBQcBAQRwMG4wRwYIKwYBBQUHMAKGO2h0 # dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ1Jv # b3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTAN # BgkqhkiG9w0BAQwFAAOCAgEAEtd7IK0ONVgMnoEdJVj9TC1ndK/HYiYh9lVUacah # RoZ2W2hfiEOyQExnHk1jkvpIJzAMxmEc6ZvIyHI5UkPCbXKspioYMdbOnBWQUn73 # 3qMooBfIghpR/klUqNxx6/fDXqY0hSU1OSkkSivt51UlmJElUICZYBodzD3M/SFj # eCP59anwxs6hwj1mfvzG+b1coYGnqsSz2wSKr+nDO+Db8qNcTbJZRAiSazr7KyUJ # Go1c+MScGfG5QHV+bps8BX5Oyv9Ct36Y4Il6ajTqV2ifikkVtB3RNBUgwu/mSiSU # ice/Jp/q8BMk/gN8+0rNIE+QqU63JoVMCMPY2752LmESsRVVoypJVt8/N3qQ1c6F # ibbcRabo3azZkcIdWGVSAdoLgAIxEKBeNh9AQO1gQrnh1TA8ldXuJzPSuALOz1Uj # b0PCyNVkWk7hkhVHfcvBfI8NtgWQupiaAeNHe0pWSGH2opXZYKYG4Lbukg7HpNi/ # KqJhue2Keak6qH9A8CeEOB7Eob0Zf+fU+CCQaL0cJqlmnx9HCDxF+3BLbUufrV64 # EbTI40zqegPZdA+sXCmbcZy6okx/SjwsusWRItFA3DE8MORZeFb6BmzBtqKJ7l93 # 9bbKBy2jvxcJI98Va95Q5JnlKor3m0E7xpMeYRriWklUPsetMSf2NvUQa/E5vVye # fQIwggZFMIIELaADAgECAhAIMk+dt9qRb2Pk8qM8Xl1RMA0GCSqGSIb3DQEBCwUA # MFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMu # QS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNpZ25pbmcgMjAyMSBDQTAeFw0yNDA0 # MDQxNDA0MjRaFw0yNzA0MDQxNDA0MjNaMGsxCzAJBgNVBAYTAk5MMRIwEAYDVQQH # DAlTY2hpam5kZWwxIzAhBgNVBAoMGkpvaG4gQmlsbGVrZW5zIENvbnN1bHRhbmN5 # MSMwIQYDVQQDDBpKb2huIEJpbGxla2VucyBDb25zdWx0YW5jeTCCAaIwDQYJKoZI # hvcNAQEBBQADggGPADCCAYoCggGBAMslntDbSQwHZXwFhmibivbnd0Qfn6sqe/6f # os3pKzKxEsR907RkDMet2x6RRg3eJkiIr3TFPwqBooyXXgK3zxxpyhGOcuIqyM9J # 28DVf4kUyZHsjGO/8HFjrr3K1hABNUszP0o7H3o6J31eqV1UmCXYhQlNoW9FOmRC # 1amlquBmh7w4EKYEytqdmdOBavAD5Xq4vLPxNP6kyA+B2YTtk/xM27TghtbwFGKn # u9Vwnm7dFcpLxans4ONt2OxDQOMA5NwgcUv/YTpjhq9qoz6ivG55NRJGNvUXsM3w # 2o7dR6Xh4MuEGrTSrOWGg2A5EcLH1XqQtkF5cZnAPM8W/9HUp8ggornWnFVQ9/6M # ga+ermy5wy5XrmQpN+x3u6tit7xlHk1Hc+4XY4a4ie3BPXG2PhJhmZAn4ebNSBwN # Hh8z7WTT9X9OFERepGSytZVeEP7hgyptSLcuhpwWeR4QdBb7dV++4p3PsAUQVHFp # wkSbrRTv4EiJ0Lcz9P1HPGFoHiFAQQIDAQABo4IBeDCCAXQwDAYDVR0TAQH/BAIw # ADA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY2NzY2EyMDIxLmNybC5jZXJ0dW0u # cGwvY2NzY2EyMDIxLmNybDBzBggrBgEFBQcBAQRnMGUwLAYIKwYBBQUHMAGGIGh0 # dHA6Ly9jY3NjYTIwMjEub2NzcC1jZXJ0dW0uY29tMDUGCCsGAQUFBzAChilodHRw # Oi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY2NzY2EyMDIxLmNlcjAfBgNVHSMEGDAW # gBTddF1MANt7n6B0yrFu9zzAMsBwzTAdBgNVHQ4EFgQUO6KtBpOBgmrlANVAnyiQ # C6W6lJwwSwYDVR0gBEQwQjAIBgZngQwBBAEwNgYLKoRoAYb2dwIFAQQwJzAlBggr # BgEFBQcCARYZaHR0cHM6Ly93d3cuY2VydHVtLnBsL0NQUzATBgNVHSUEDDAKBggr # BgEFBQcDAzAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcNAQELBQADggIBAEQsN8wg # PMdWVkwHPPTN+jKpdns5AKVFjcn00psf2NGVVgWWNQBIQc9lEuTBWb54IK6Ga3hx # QRZfnPNo5HGl73YLmFgdFQrFzZ1lnaMdIcyh8LTWv6+XNWfoyCM9wCp4zMIDPOs8 # LKSMQqA/wRgqiACWnOS4a6fyd5GUIAm4CuaptpFYr90l4Dn/wAdXOdY32UhgzmSu # xpUbhD8gVJUaBNVmQaRqeU8y49MxiVrUKJXde1BCrtR9awXbqembc7Nqvmi60tYK # lD27hlpKtj6eGPjkht0hHEsgzU0Fxw7ZJghYG2wXfpF2ziN893ak9Mi/1dmCNmor # GOnybKYfT6ff6YTCDDNkod4egcMZdOSv+/Qv+HAeIgEvrxE9QsGlzTwbRtbm6gwY # YcVBs/SsVUdBn/TSB35MMxRhHE5iC3aUTkDbceo/XP3uFhVL4g2JZHpFfCSu2TQr # rzRn2sn07jfMvzeHArCOJgBW1gPqR3WrJ4hUxL06Rbg1gs9tU5HGGz9KNQMfQFQ7 # 0Wz7UIhezGcFcRfkIfSkMmQYYpsc7rfzj+z0ThfDVzzJr2dMOFsMlfj1T6l22GBq # 9XQx0A4lcc5Fl9pRxbOuHHWFqIBD/BCEhwniOCySzqENd2N+oz8znKooSISStnkN # aYXt6xblJF2dx9Dn89FK7d1IquNxOwt0tI5dMIIGYjCCBMqgAwIBAgIRAKQpO24e # 3denNAiHrXpOtyQwDQYJKoZIhvcNAQEMBQAwVTELMAkGA1UEBhMCR0IxGDAWBgNV # BAoTD1NlY3RpZ28gTGltaXRlZDEsMCoGA1UEAxMjU2VjdGlnbyBQdWJsaWMgVGlt # ZSBTdGFtcGluZyBDQSBSMzYwHhcNMjUwMzI3MDAwMDAwWhcNMzYwMzIxMjM1OTU5 # WjByMQswCQYDVQQGEwJHQjEXMBUGA1UECBMOV2VzdCBZb3Jrc2hpcmUxGDAWBgNV # BAoTD1NlY3RpZ28gTGltaXRlZDEwMC4GA1UEAxMnU2VjdGlnbyBQdWJsaWMgVGlt # ZSBTdGFtcGluZyBTaWduZXIgUjM2MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC # CgKCAgEA04SV9G6kU3jyPRBLeBIHPNyUgVNnYayfsGOyYEXrn3+SkDYTLs1crcw/ # ol2swE1TzB2aR/5JIjKNf75QBha2Ddj+4NEPKDxHEd4dEn7RTWMcTIfm492TW22I # 8LfH+A7Ehz0/safc6BbsNBzjHTt7FngNfhfJoYOrkugSaT8F0IzUh6VUwoHdYDpi # ln9dh0n0m545d5A5tJD92iFAIbKHQWGbCQNYplqpAFasHBn77OqW37P9BhOASdmj # p3IijYiFdcA0WQIe60vzvrk0HG+iVcwVZjz+t5OcXGTcxqOAzk1frDNZ1aw8nFhG # EvG0ktJQknnJZE3D40GofV7O8WzgaAnZmoUn4PCpvH36vD4XaAF2CjiPsJWiY/j2 # xLsJuqx3JtuI4akH0MmGzlBUylhXvdNVXcjAuIEcEQKtOBR9lU4wXQpISrbOT8ux # +96GzBq8TdbhoFcmYaOBZKlwPP7pOp5Mzx/UMhyBA93PQhiCdPfIVOCINsUY4U23 # p4KJ3F1HqP3H6Slw3lHACnLilGETXRg5X/Fp8G8qlG5Y+M49ZEGUp2bneRLZoyHT # yynHvFISpefhBCV0KdRZHPcuSL5OAGWnBjAlRtHvsMBrI3AAA0Tu1oGvPa/4yeei # Ayu+9y3SLC98gDVbySnXnkujjhIh+oaatsk/oyf5R2vcxHahajMCAwEAAaOCAY4w # ggGKMB8GA1UdIwQYMBaAFF9Y7UwxeqJhQo1SgLqzYZcZojKbMB0GA1UdDgQWBBSI # YYyhKjdkgShgoZsx0Iz9LALOTzAOBgNVHQ8BAf8EBAMCBsAwDAYDVR0TAQH/BAIw # ADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDBKBgNVHSAEQzBBMDUGDCsGAQQBsjEB # AgEDCDAlMCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZn # gQwBBAIwSgYDVR0fBEMwQTA/oD2gO4Y5aHR0cDovL2NybC5zZWN0aWdvLmNvbS9T # ZWN0aWdvUHVibGljVGltZVN0YW1waW5nQ0FSMzYuY3JsMHoGCCsGAQUFBwEBBG4w # bDBFBggrBgEFBQcwAoY5aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVi # bGljVGltZVN0YW1waW5nQ0FSMzYuY3J0MCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz # cC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAYEAAoE+pIZyUSH5ZakuPVKK # 4eWbzEsTRJOEjbIu6r7vmzXXLpJx4FyGmcqnFZoa1dzx3JrUCrdG5b//LfAxOGy9 # Ph9JtrYChJaVHrusDh9NgYwiGDOhyyJ2zRy3+kdqhwtUlLCdNjFjakTSE+hkC9F5 # ty1uxOoQ2ZkfI5WM4WXA3ZHcNHB4V42zi7Jk3ktEnkSdViVxM6rduXW0jmmiu71Z # pBFZDh7Kdens+PQXPgMqvzodgQJEkxaION5XRCoBxAwWwiMm2thPDuZTzWp/gUFz # i7izCmEt4pE3Kf0MOt3ccgwn4Kl2FIcQaV55nkjv1gODcHcD9+ZVjYZoyKTVWb4V # qMQy/j8Q3aaYd/jOQ66Fhk3NWbg2tYl5jhQCuIsE55Vg4N0DUbEWvXJxtxQQaVR5 # xzhEI+BjJKzh3TQ026JxHhr2fuJ0mV68AluFr9qshgwS5SpN5FFtaSEnAwqZv3IS # +mlG50rK7W3qXbWwi4hmpylUfygtYLEdLQukNEX1jiOKMIIGgjCCBGqgAwIBAgIQ # NsKwvXwbOuejs902y8l1aDANBgkqhkiG9w0BAQwFADCBiDELMAkGA1UEBhMCVVMx # EzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYD # VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBS # U0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjEwMzIyMDAwMDAwWhcNMzgw # MTE4MjM1OTU5WjBXMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1p # dGVkMS4wLAYDVQQDEyVTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIFJvb3Qg # UjQ2MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAiJ3YuUVnnR3d6Lkm # gZpUVMB8SQWbzFoVD9mUEES0QUCBdxSZqdTkdizICFNeINCSJS+lV1ipnW5ihkQy # C0cRLWXUJzodqpnMRs46npiJPHrfLBOifjfhpdXJ2aHHsPHggGsCi7uE0awqKggE # /LkYw3sqaBia67h/3awoqNvGqiFRJ+OTWYmUCO2GAXsePHi+/JUNAax3kpqstbl3 # vcTdOGhtKShvZIvjwulRH87rbukNyHGWX5tNK/WABKf+Gnoi4cmisS7oSimgHUI0 # Wn/4elNd40BFdSZ1EwpuddZ+Wr7+Dfo0lcHflm/FDDrOJ3rWqauUP8hsokDoI7D/ # yUVI9DAE/WK3Jl3C4LKwIpn1mNzMyptRwsXKrop06m7NUNHdlTDEMovXAIDGAvYy # nPt5lutv8lZeI5w3MOlCybAZDpK3Dy1MKo+6aEtE9vtiTMzz/o2dYfdP0KWZwZIX # bYsTIlg1YIetCpi5s14qiXOpRsKqFKqav9R1R5vj3NgevsAsvxsAnI8Oa5s2oy25 # qhsoBIGo/zi6GpxFj+mOdh35Xn91y72J4RGOJEoqzEIbW3q0b2iPuWLA911cRxgY # 5SJYubvjay3nSMbBPPFsyl6mY4/WYucmyS9lo3l7jk27MAe145GWxK4O3m3gEFEI # kv7kRmefDR7Oe2T1HxAnICQvr9sCAwEAAaOCARYwggESMB8GA1UdIwQYMBaAFFN5 # v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBT2d2rdP/0BE/8WoWyCAi/QCj0U # JTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zATBgNVHSUEDDAKBggr # BgEFBQcDCDARBgNVHSAECjAIMAYGBFUdIAAwUAYDVR0fBEkwRzBFoEOgQYY/aHR0 # cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25B # dXRob3JpdHkuY3JsMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0cDov # L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEADr5lQe1oRLjl # ocXUEYfktzsljOt+2sgXke3Y8UPEooU5y39rAARaAdAxUeiX1ktLJ3+lgxtoLQhn # 5cFb3GF2SSZRX8ptQ6IvuD3wz/LNHKpQ5nX8hjsDLRhsyeIiJsms9yAWnvdYOdEM # q1W61KE9JlBkB20XBee6JaXx4UBErc+YuoSb1SxVf7nkNtUjPfcxuFtrQdRMRi/f # InV/AobE8Gw/8yBMQKKaHt5eia8ybT8Y/Ffa6HAJyz9gvEOcF1VWXG8OMeM7Vy7B # s6mSIkYeYtddU1ux1dQLbEGur18ut97wgGwDiGinCwKPyFO7ApcmVJOtlw9FVJxw # /mL1TbyBns4zOgkaXFnnfzg4qbSvnrwyj1NiurMp4pmAWjR+Pb/SIduPnmFzbSN/ # G8reZCL4fvGlvPFk4Uab/JVCSmj59+/mB2Gn6G/UYOy8k60mKcmaAZsEVkhOFuoj # 4we8CYyaR9vd9PGZKSinaZIkvVjbH/3nlLb0a7SBIkiRzfPfS9T+JesylbHa1LtR # V9U/7m0q7Ma2CQ/t392ioOssXW7oKLdOmMBl14suVFBmbzrt5V5cQPnwtd3UOTpS # 9oCG+ZZheiIvPgkDmA8FzPsnfXW5qHELB43ET7HHFHeRPRYrMBKjkb8/IN7Po0d0 # hQoF4TeMM+zYAJzoKQnVKOLg8pZVPT8wgga5MIIEoaADAgECAhEAmaOACiZVO2Wr # 3G6EprPqOTANBgkqhkiG9w0BAQwFADCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT # GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0 # aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0 # d29yayBDQSAyMB4XDTIxMDUxOTA1MzIxOFoXDTM2MDUxODA1MzIxOFowVjELMAkG # A1UEBhMCUEwxITAfBgNVBAoTGEFzc2VjbyBEYXRhIFN5c3RlbXMgUy5BLjEkMCIG # A1UEAxMbQ2VydHVtIENvZGUgU2lnbmluZyAyMDIxIENBMIICIjANBgkqhkiG9w0B # AQEFAAOCAg8AMIICCgKCAgEAnSPPBDAjO8FGLOczcz5jXXp1ur5cTbq96y34vuTm # flN4mSAfgLKTvggv24/rWiVGzGxT9YEASVMw1Aj8ewTS4IndU8s7VS5+djSoMcbv # IKck6+hI1shsylP4JyLvmxwLHtSworV9wmjhNd627h27a8RdrT1PH9ud0IF+njvM # k2xqbNTIPsnWtw3E7DmDoUmDQiYi/ucJ42fcHqBkbbxYDB7SYOouu9Tj1yHIohzu # C8KNqfcYf7Z4/iZgkBJ+UFNDcc6zokZ2uJIxWgPWXMEmhu1gMXgv8aGUsRdaCtVD # 2bSlbfsq7BiqljjaCun+RJgTgFRCtsuAEw0pG9+FA+yQN9n/kZtMLK+Wo837Q4QO # ZgYqVWQ4x6cM7/G0yswg1ElLlJj6NYKLw9EcBXE7TF3HybZtYvj9lDV2nT8mFSkc # SkAExzd4prHwYjUXTeZIlVXqj+eaYqoMTpMrfh5MCAOIG5knN4Q/JHuurfTI5XDY # O962WZayx7ACFf5ydJpoEowSP07YaBiQ8nXpDkNrUA9g7qf/rCkKbWpQ5boufUnq # 1UiYPIAHlezf4muJqxqIns/kqld6JVX8cixbd6PzkDpwZo4SlADaCi2JSplKShBS # ND36E/ENVv8urPS0yOnpG4tIoBGxVCARPCg1BnyMJ4rBJAcOSnAWd18Jx5n858JS # qPECAwEAAaOCAVUwggFRMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFN10XUwA # 23ufoHTKsW73PMAywHDNMB8GA1UdIwQYMBaAFLahVDkCw6A/joq8+tT4HKbROg79 # MA4GA1UdDwEB/wQEAwIBBjATBgNVHSUEDDAKBggrBgEFBQcDAzAwBgNVHR8EKTAn # MCWgI6Ahhh9odHRwOi8vY3JsLmNlcnR1bS5wbC9jdG5jYTIuY3JsMGwGCCsGAQUF # BwEBBGAwXjAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNv # bTAyBggrBgEFBQcwAoYmaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBsL2N0bmNh # Mi5jZXIwOQYDVR0gBDIwMDAuBgRVHSAAMCYwJAYIKwYBBQUHAgEWGGh0dHA6Ly93 # d3cuY2VydHVtLnBsL0NQUzANBgkqhkiG9w0BAQwFAAOCAgEAdYhYD+WPUCiaU58Q # 7EP89DttyZqGYn2XRDhJkL6P+/T0IPZyxfxiXumYlARMgwRzLRUStJl490L94C9L # GF3vjzzH8Jq3iR74BRlkO18J3zIdmCKQa5LyZ48IfICJTZVJeChDUyuQy6rGDxLU # UAsO0eqeLNhLVsgw6/zOfImNlARKn1FP7o0fTbj8ipNGxHBIutiRsWrhWM2f8pXd # d3x2mbJCKKtl2s42g9KUJHEIiLni9ByoqIUul4GblLQigO0ugh7bWRLDm0CdY9rN # LqyA3ahe8WlxVWkxyrQLjH8ItI17RdySaYayX3PhRSC4Am1/7mATwZWwSD+B7eMc # ZNhpn8zJ+6MTyE6YoEBSRVrs0zFFIHUR08Wk0ikSf+lIe5Iv6RY3/bFAEloMU+vU # BfSouCReZwSLo8WdrDlPXtR0gicDnytO7eZ5827NS2x7gCBibESYkOh1/w1tVxTp # V2Na3PR7nxYVlPu1JPoRZCbH86gc96UTvuWiOruWmyOEMLOGGniR+x+zPF/2DaGg # K2W1eEJfo2qyrBNPvF7wuAyQfiFXLwvWHamoYtPZo0LHuH8X3n9C+xN4YaNjt2yw # zOr+tKyEVAotnyU9vyEVOaIYMk3IeBrmFnn0gbKeTTyYeEEUz/Qwt4HOUBCrW602 # NCmvO1nm+/80nLy5r0AZvCQxaQ4xggXDMIIFvwIBATBqMFYxCzAJBgNVBAYTAlBM # MSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0Nl # cnR1bSBDb2RlIFNpZ25pbmcgMjAyMSBDQQIQCDJPnbfakW9j5PKjPF5dUTANBglg # hkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3 # DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEV # MC8GCSqGSIb3DQEJBDEiBCBPkbpjIMiHhv3ekzplHkeXmVF3hC1rAdiOfhq6uowT # izANBgkqhkiG9w0BAQEFAASCAYAZOh8S9vzjbCHWT0GHuZ0Ql5BXrEDkYLHFIvJj # JAwzTdW3gSpKVceyhV36ThXTEV+S4XeVih6KY2xluEjgUA2/ZGYG3xnbg15mjiUm # mTqCbyGNIo9Uc0Jk2+yFF+JNqOgK7lF3dbVn3+2G8eHVQxp/+14X51r26xp5eG5h # QE+SXddbZd31JQlnv6mTCuOW3Fdb0ZBD17Ko4ayBB+aux0hwcHprUfgYzdSkG2dj # D9JV8pmECmMQ/amEH0KOsfi0g2cmTKf6y7kTrC1j9n+7Q7ALvMsRJ0oZGoH6N/sD # AQIIruu/wYdGfHaB95YoZXuxVJwe24BLMcgb7cYQ4lEU2vzz00H6UIsgSYOqb09d # jEvuBb7qwFemrW9GLqYEkbwvTrjGl3t0kOq8p95+A51yCZ2cJ3dlabLLoYI0jC9P # 43GM4LFe6MY25GtgVmy31zoSHCCri4VcFzMW+tv0hr1VlowO7vGUmb4No+Y9AyLQ # eSEpG/8Vd3+XvMxAFckyIzfGQX+hggMjMIIDHwYJKoZIhvcNAQkGMYIDEDCCAwwC # AQEwajBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSww # KgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNgIRAKQp # O24e3denNAiHrXpOtyQwDQYJYIZIAWUDBAICBQCgeTAYBgkqhkiG9w0BCQMxCwYJ # KoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNjA2MTYxODMyNDZaMD8GCSqGSIb3 # DQEJBDEyBDCIF6oz4pUHjAKvvtu5mJu63tv2HbvaCFNB9ltxFAbnDJBhUOdrXM6B # xHwuvoYSTzcwDQYJKoZIhvcNAQEBBQAEggIAygTjy+FE52ij4kuZ6wVGkADcSqM0 # AbofgEn/GoNb1ci172sG3h2BzNCocA51Ww5aqjnDMtHadXh1IH8kFXPdPpYKLmd6 # 5yQbxeJSoVI83TX+Hyhmif/8HaxLwrdzELuAbmyI9xCWUFEoR5xl7rTeaSBu+JHZ # QbvmAz11jHwzFyEufbsjKU0WIp6TZJ+3O0lZBkaIr+6JgIvEQxXJypyp0K58VXee # vEv0bkKQms2g20LMGuSxGUfqRvX1pyibo8OXpKEw3F6eLo51UyQFtJAhUsYq1Exs # bnMRbxgiKwz4K39f5BQnMVaMQCeXwq1aSLzBl19wjAoehU2H/Oiw4lA6gZFOcsOy # hb4FSLWPeXhVBtWgBp2fKMouS0rvrlnxgZkbV7gguv3GAYxp8rfRTjF3yWqabwUZ # JjY8kjuwigSLcpiPcwKlrExN5sg1+UzpEzWT9+s3+G60DYYfDYJYNfmmCbxHVy1J # 7Kr1NOKAp3HaHL94YwQ5graXQ4JFmekU4DKEJ0kGcgYA8N/cbJ/BI6qIFoDvoM0p # PAhtJygeX9bJm/Eo92d7V5cSJe2OEwobeAu9F/tXGPsl/HvJSVGNrSe/r68mtG4T # qrqrobvOPov8TvfgWH5XSpTL5TWGnETJED9/IYnjyWIEAZyokMiLgKY9OjDGre2a # C50siIGHefxd+m8= # SIG # End signature block |