Parse-OSOTConfig.ps1
<#PSScriptInfo
.VERSION 0.7.1 .GUID 9665fc5d-be92-46e9-acac-cfd3637a3b0a .AUTHOR Evgenij Smirnov .COMPANYNAME metaBPA.org .COPYRIGHT 2020 metaBPA.org .TAGS .LICENSEURI .PROJECTURI https://metabpa.org/projects/various-scripts/osot-parser/ .ICONURI https://metabpa.org/wp-content/uploads/2019/11/metaBPA-150x150.ico .EXTERNALMODULEDEPENDENCIES .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES #> <# .SYNOPSIS Parses an OSOT configuration file and generates actual executable scripts (.cmd and .ps1). .DESCRIPTION Parses an OSOT (VMware OS Optimization Tool) configuration file and generates actual executable scripts. These can then be invoked without using the actual OSOT Tool, e.g. as part of a deployment task sequence. The commands are split into classical batch shell (.cmd) and PowerShell (.ps1) commands, with the choice of generating either batch or PS commands for a. disabling services, and b. disabling scheduled tasks. See project site linked under "Info" for more details. .PARAMETER OSOTFIle Full path to XML file generated by OSOT. .PARAMETER OutPath Full path to folder where generated files will be created. .PARAMETER UsePowerShellForServiceCommands Output 'Set-Service' and 'Stop-Service' instead of 'sc config' and 'sc stop'. .PARAMETER UsePowerShellForSchTasksCommands Output 'Enable-ScheduledTask' and 'Disable-ScheduledTask' instead of 'schtasks.exe'. .PARAMETER AddCommentsToOutput Incorporate commets from the XML file into the script .PARAMETER PassThru Output the actual commands to the pipeline instead of statistics. .PARAMETER MaskExtensions Make the output files non-executable by adding.txt to the full path. .PARAMETER SuppressFileOutput Suppress the creation of output files. .INPUTS None. You cannot pipe objects to Parse-OSOTConfig.ps1. .OUTPUTS If -PassThru is specified, an array of PSCustomObjects each representing a command to run on an image. If -PassThru is not specified, an PSCustomObject that contains some statistics about the processed config. .EXAMPLE ./Parse-OSOTConfig.ps1 -OSOTFile c:\temp\Win10Config.xml -OutPath c:\temp\osotcommands -PassThru .EXAMPLE ./Parse-OSOTConfig.ps1 -OSOTFile c:\temp\Win10Config.xml -OutPath c:\temp\osotcommands -UsePowerShellForServiceCommands -AddCommentsToOutput .LINK https://metabpa.org/projects/various-scripts/osot-parser/ .LINK https://flings.vmware.com/vmware-os-optimization-tool #> [CmdletBinding()] Param( [Parameter(Mandatory=$true)][System.IO.FileInfo]$OSOTFile, [Parameter(Mandatory=$true)][System.IO.FileInfo]$OutPath, [Parameter(Mandatory=$false)][switch]$UsePowerShellForServiceCommands, [Parameter(Mandatory=$false)][switch]$UsePowerShellForSchTasksCommands, [Parameter(Mandatory=$false)][switch]$AddCommentsToOutput, [Parameter(Mandatory=$false)][switch]$PassThru, [Parameter(Mandatory=$false)][switch]$MaskExtensions, [Parameter(Mandatory=$false)][switch]$SuppressFileOutput ) #region functions function Make-Content { [CmdletBinding()] Param( [Parameter(Mandatory=$true)][string]$OutFile, [Parameter(Mandatory=$false)][string]$FileComment, [Parameter(Mandatory=$true)][PSCustomObject[]]$ContentData ) if ($ContentData.Where({$_.lang -eq 'powershell'}).Count -gt 0) { $ps_out_file = "$OutPath\$($OutFile).ps1" if ($MaskExtensions) { $ps_out_file = $ps_out_file + ".txt" } "<#`r`n`t$FileComment from OST File $($OSOTFile.FullName)`r`n#>`r`n" | Set-Content -Path $ps_out_file -Encoding UTF8 -Force } if ($ContentData.Where({$_.lang -eq 'cmd'}).Count -gt 0) { $cmd_out_file = "$OutPath\$($OutFile).cmd" if ($MaskExtensions) { $cmd_out_file = $cmd_out_file + ".txt" } "@ECHO OFF`r`nREM $FileComment from OST File $($OSOTFile.FullName)`r`n" | Set-Content -Path $cmd_out_file -Encoding UTF8 -Force } foreach ($action in $ContentData.where({!$_.defuser})) { if ($action.lang -eq 'cmd') { if ($AddCommentsToOutput) { "REM $($action.group) | $($action.comment)" | Add-Content $cmd_out_file -Encoding UTF8 } $action.line | Add-Content $cmd_out_file -Encoding UTF8 } elseif ($action.lang -eq 'powershell') { if ($AddCommentsToOutput) { "# $($action.group) | $($action.comment)" | Add-Content $ps_out_file -Encoding UTF8 } $action.line | Add-Content $ps_out_file -Encoding UTF8 } } if ($stats.DefaultUserActions -gt 0) { 'reg LOAD "HKEY_USERS\temp" C:\Users\Default\NTUSERS.DAT' | Add-Content $cmd_out_file -Encoding UTF8 foreach ($action in $ContentData.where({$_.defuser})) { if ($action.lang -eq 'cmd') { if ($AddCommentsToOutput) { "REM $($action.group) | $($action.comment)" | Add-Content $cmd_out_file -Encoding UTF8 } $action.line | Add-Content $cmd_out_file -Encoding UTF8 } elseif ($action.lang -eq 'powershell') { Write-Warning "PowerShell action in default user context: $($action.line)" } } 'reg UNLOAD "HKEY_USERS\temp"' | Add-Content $cmd_out_file -Encoding UTF8 } } #endregion #region init if (Test-Path -Path $OSOTFile -PathType Leaf) { try { $OSOTConfig = [xml](Get-Content -Path $OSOTFile) } catch { Write-Warning "Error parsing XML: $($_.Exception.Message)" return 7 } } else { Write-Warning "File not found: $OSOTFile" return 2 } if ($SuppressFileOutput -and ($MaskExtensions -or $AddCommentsToOutput)) { Write-Warning "You specified -SuppressFileOutput together with one of the file modifiers (-MaskExtensions and -AddCommentsToOutput). No output files will be created." } $cmd = @() $unprocessed = 0 $nline = 0 #endregion #region parse foreach ($ActionGroup in $OSOTConfig.sequence.group.ChildNodes) { foreach ($ActionStepBlock in $ActionGroup.childNodes) { $ActionStep = $ActionStepBlock.action $nline++ switch ($ActionStep.type) { 'Registry' { $regcmd = $null if ($ActionStep.params.keyName -eq $null) { Write-Warning "Null key value encountered!" $unprocessed++ } else { $xkey = (($ActionStep.params.keyName.Trim() -replace "HKLM","HKEY_LOCAL_MACHINE") -replace "HKU","HKEY_USERS") -replace "HKCU","HKEY_CURRENT_USER" $xval = $null $xtype = $null $xdata = $null switch ($ActionStep.command) { 'ADD' { $xval = $ActionStep.params.valueName $xdata = $ActionStep.params.data $xtype = $ActionStep.params.type if ($xval -eq $null) { if ($xtype -ne $null) { $xval = '(Default)' } } else { $xval = $xval.Trim() } if ($xval) { $xval = ('/v "{0}"' -f $xval) if ($xtype -eq 'REG_SZ') { $xdata = ('/d "{0}"' -f $xdata) } else { $xdata = ('/d {0}' -f $xdata) } $xtype = ('/t {0}' -f $xtype) } $regcmd = "$(('reg ADD "{0}" {1} {2} {3}' -f $xkey,$xval,$xtype,$xdata).Trim()) /f" } 'DELETEVALUE' { $xval = $ActionStep.params.valueName if ($xval) { $xkey = ('{0}\{1}' -f $xkey,$xval) } $regcmd = "$('reg DELETE "{0}"' -f $xkey) /f" } 'LOAD' { <# nuthin' to do, will be added automatically #> } 'UNLOAD' { <# nuthin' to do, will be added automatically #> } default { Write-Warning "Unknown registry operation: $($ActionStep.command)" $unprocessed++ } } if ($null -ne $regcmd) { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'cmd' 'line' = $regcmd 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = ($regcmd -match 'HKEY_USERS\\temp\\') 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } } } 'Service' { $xname = $ActionStep.params.serviceName $xmode = $ActionStep.params.startMode if ($null -ne $xname) { if ($null -ne $xmode) { if ($UsePowerShellForServiceCommands) { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'powershell' 'line' = 'Set-Service "{0}" -StartupType {1}' -f $xname,$xmode 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } if ($xmode -ne 'AUTOMATIC') { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'powershell' 'line' = 'Stop-Service "{0}" -Force' -f $xname 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } } else { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'cmd' 'line' = 'sc config "{0}" start={1}' -f $xname,$xmode 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } if ($xmode -ne 'AUTOMATIC') { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'cmd' 'line' = 'sc stop "{0}"' -f $xname 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } } } else { Write-Warning "Service start mode empty at step $($ActionStepBlock.name)" $unprocessed++ } } else { Write-Warning "Service name empty at step $($ActionStepBlock.name)" $unprocessed++ } } 'SchTasks' { $xname = $ActionStep.params.TaskName $xmode = $ActionStep.params.Status if ($null -ne $xname) { if ($null -ne $xmode) { if ($UsePowerShellForServiceCommands) { if ($xmode -eq 'DISABLED') { $xmode = 'Disable' } else { $xmode = 'Enable' } if ($xname -match "\\") { $xpath = "\" + $xname.Substring(0,$xname.LastIndexOf("\") + 1) $xname = $xname.Substring($xname.LastIndexOf("\") + 1) } else { $xpath = "\" } $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'powershell' 'line' = '{1}-ScheduledTask -TaskName "{0}" -TaskPath "{2}"' -f $xname,$xmode,$xpath 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } else { if ($xmode -eq 'DISABLED') { $xmode = 'disable' } else { $xmode = 'enable' } $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'cmd' 'line' = 'schtasks /change /tn "{0}" /{1}' -f $xname,$xmode 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } } else { Write-Warning "SchTask status empty at step $($ActionStepBlock.name)" $unprocessed++ } } else { Write-Warning "SchTask name empty at step $($ActionStepBlock.name)" $unprocessed++ } } 'ShellExecute' { $xcmd = $ActionStep.command if (($xcmd -match '^Powershell "& {(?<pscmd>[a-zA-Z\d]+\-[a-zA-Z\d]+\s.*)}"$') -or ($xcmd -match '^Powershell (?<pscmd>[a-zA-Z\d]+\-[a-zA-Z\d]+\s.*)$')) { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'powershell' 'line' = $Matches['pscmd'] 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } elseif ($xcmd -match '^Powershell "& {(?<batcmd>.*)}"$') { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'cmd' 'line' = $Matches['batcmd'] 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } elseif ($xcmd -match '^Powershell (?<batcmd>.*)$') { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'cmd' 'line' = $Matches['batcmd'] 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } else { $cmd += [PSCustomObject]@{ 'nline' = $nline 'lang' = 'cmd' 'line' = $xcmd 'recommended' = ($ActionStepBlock.category -eq 'recommended') 'mandatory' = ($ActionStepBlock.category -eq 'mandatory') 'defuser' = $false 'comment' = $ActionStepBlock.description 'group' = $ActionGroup.name } } } default { if ($ActionStep.type -ne $null) { Write-Warning "Unknown action type: $($ActionStep.type) at step $($ActionStepBlock.name)" $unprocessed++ } } } } } #endregion #region stats $stats = [PSCustomObject]@{ 'OSOTFile' = $OSOTFile.FullName 'TotalActions' = $cmd.Count 'CMDActions' = $cmd.Where({$_.lang -eq 'cmd'}).Count 'PSActions' = $cmd.Where({$_.lang -eq 'powershell'}).Count 'DefaultUserActions' = $cmd.Where({$_.defuser}).Count 'MandatoryActions' = $cmd.Where({$_.mandatory}).Count 'RecommendedActions' = $cmd.Where({$_.recommended}).Count 'OptionalActions' = $cmd.Where({!$_.recommended -and !$_.mandatory}).Count 'UnprocessedSteps' = $unprocessed } #endregion #region output if (!$SuppressFileOutput) { if (!(Test-Path $OutPath -Pathtype Container)) { New-Item $OutPath -ItemType Directory -Force } [ordered]@{'stats' = $stats; 'commands' = $cmd} | ConvertTo-Json -Depth 4 | Set-Content "$OutPath\osot_processed.json" -Force Make-Content -OutFile 'all_actions' -FileComment 'All Actions' -ContentData $cmd Make-Content -OutFile 'mandatory_actions' -FileComment 'Mandatory Actions' -ContentData ($cmd.Where({$_.mandatory})) Make-Content -OutFile 'recommended_actions' -FileComment 'Recommended Actions' -ContentData ($cmd.Where({$_.recommended})) Make-Content -OutFile 'optional_actions' -FileComment 'Optional Actions' -ContentData ($cmd.Where({!$_.mandatory -and !$_.recommended})) } #endregion if ($PassThru) { return $cmd } else { return $stats } # SIG # Begin signature block # MIIefQYJKoZIhvcNAQcCoIIebjCCHmoCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQURb2EqgZSVisw24ZOfnhfyDKI # 7CugghnAMIIFQTCCAymgAwIBAgITXwAAAAIjZCsPuYSflAAAAAAAAjANBgkqhkiG # 9w0BAQsFADBcMQswCQYDVQQGEwJERTEPMA0GA1UEBxMGQmVybGluMRQwEgYDVQQK # EwttZXRhQlBBLm9yZzEMMAoGA1UECxMDRGV2MRgwFgYDVQQDEw9tZXRhQlBBIFJv # b3QgQ0EwHhcNMTkxMTA4MjEwNzI4WhcNMjAxMTA4MjExNzI4WjBcMQswCQYDVQQG # EwJERTEPMA0GA1UEBxMGQmVybGluMRQwEgYDVQQKEwttZXRhQlBBLm9yZzEMMAoG # A1UECxMDRGV2MRgwFgYDVQQDEw9FdmdlbmlqIFNtaXJub3YwggEiMA0GCSqGSIb3 # DQEBAQUAA4IBDwAwggEKAoIBAQDBL4oFbzMU7zkuwMFsG8Ckbk73VtcvE/gz5CFd # Rf3f/WVMe27r6VQLUfeaLYwjavfe9MaSHngXhC0Ivsbf6IlKtY1oXJFKXuEnNvzC # s3njl5LXVoWf29wGmOOAbPWBlI7+nBwvcNRHYnZ4ZaLSO9cdhre9gARTvMptUUL9 # 3Njf3jw9iwdLRg7wMk1TB3yB7nlHHd0G8YiPzlltOV9sesfpnFuorR2IPwkfaEfu # Z6t/nHsuWtvliaT++PbDv9d0tnKiQVJ+h9cwMoTO8kIbg7Q52pT+paMrcEn7hyN+ # XjyG/oJUb6IyDOMgv2Fa+MJ9SWnT9z4Ueap4/JJhkiv8qaf5AgMBAAGjgfswgfgw # DgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQWBBRm # y7quPiRE14SnwXiztcO0WxBDYzAfBgNVHSMEGDAWgBT5ujnudnaVxT34rTRrGEb0 # f87i+DA7BgNVHR8ENDAyMDCgLqAshipodHRwOi8vcGtpLm1ldGFicGEub3JnL21l # dGFCUEFfUm9vdF9DQS5jcmwwRgYIKwYBBQUHAQEEOjA4MDYGCCsGAQUFBzAChipo # dHRwOi8vcGtpLm1ldGFicGEub3JnL21ldGFCUEFfUm9vdF9DQS5jcnQwDAYDVR0T # AQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAc05mB0AuoLmHwh5aPGw+VYSlXzDg # ugs1HwjI3iNe6FQZ1a+E1yupvdLHFrjs+7nBtRzQNdbf6Gs2ulQgaxKzC+qtrgiu # vkiO7q9mPza1WkkXCDtVatyMnRt6i9aK/Qy0B+lQxVL3gZhHKNiBlZd9lZbps699 # SHuT2lyytJEIQdXWKEm137+3FHFKIso9cQ820Lzh+251VukxuqRHR2A5BhiHRPww # phRzMyfxGwUZWx1WSqgefEyHcqft562LnYluDXPxfEUNRPtTzAMbR8MH6zuom6QE # pA3UzrJvwgYGnKkGyfj7SQijvvukfwHbcTRbbq73Jv6YKnFlwG8A6BKDYWYpQdgT # 7ENlXhJ1TEZe+8O4XOUZokYQoFJbOn9dz2AyKJCQDYev3+uDqNhlVavcMG8YXBjv # W/Y6NbUb1W2W+kDFtdCG74sXgTZyvqsDsEb57UniGxo0+/uYqxRnFexruJ/Il3OO # kLv2Up4aov018yowmSYriJY2u9B7NyzPqNTh8KYo/RCm9INUn/SA3JNJ0g9udssR # tkdbPCpq+e1j9Xjf6V5qkXQcNMuuZLf6RswS/tsuaqlhqRrHDdk4I+EcDj5o0n+C # ur9horiACMCK5fjpgogRaqkuzCshtO1qc20F9tk0tUr3iD8N63MSbQBmxeyP16Et # 7ZEHLtu+fmM06ckwggZqMIIFUqADAgECAhADAZoCOv9YsWvW1ermF/BmMA0GCSqG # SIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IEFz # c3VyZWQgSUQgQ0EtMTAeFw0xNDEwMjIwMDAwMDBaFw0yNDEwMjIwMDAwMDBaMEcx # CzAJBgNVBAYTAlVTMREwDwYDVQQKEwhEaWdpQ2VydDElMCMGA1UEAxMcRGlnaUNl # cnQgVGltZXN0YW1wIFJlc3BvbmRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC # AQoCggEBAKNkXfx8s+CCNeDg9sYq5kl1O8xu4FOpnx9kWeZ8a39rjJ1V+JLjntVa # Y1sCSVDZg85vZu7dy4XpX6X51Id0iEQ7Gcnl9ZGfxhQ5rCTqqEsskYnMXij0ZLZQ # t/USs3OWCmejvmGfrvP9Enh1DqZbFP1FI46GRFV9GIYFjFWHeUhG98oOjafeTl/i # qLYtWQJhiGFyGGi5uHzu5uc0LzF3gTAfuzYBje8n4/ea8EwxZI3j6/oZh6h+z+yM # DDZbesF6uHjHyQYuRhDIjegEYNu8c3T6Ttj+qkDxss5wRoPp2kChWTrZFQlXmVYw # k/PJYczQCMxr7GJCkawCwO+k8IkRj3cCAwEAAaOCAzUwggMxMA4GA1UdDwEB/wQE # AwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYD # VR0gBIIBtjCCAbIwggGhBglghkgBhv1sBwEwggGSMCgGCCsGAQUFBwIBFhxodHRw # czovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBB # AG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBh # AHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBj # AGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABT # ACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABB # AGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBh # AGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBh # AHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAu # MAsGCWCGSAGG/WwDFTAfBgNVHSMEGDAWgBQVABIrE5iymQftHt+ivlcNK2cCzTAd # BgNVHQ4EFgQUYVpNJLZJMp1KKnkag0v0HonByn0wfQYDVR0fBHYwdDA4oDagNIYy # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5j # cmwwOKA2oDSGMmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy # ZWRJRENBLTEuY3JsMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDov # L29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5k # aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURDQS0xLmNydDANBgkqhkiG9w0B # AQUFAAOCAQEAnSV+GzNNsiaBXJuGziMgD4CH5Yj//7HUaiwx7ToXGXEXzakbvFoW # OQCd42yE5FpA+94GAYw3+puxnSR+/iCkV61bt5qwYCbqaVchXTQvH3Gwg5QZBWs1 # kBCge5fH9j/n4hFBpr1i2fAnPTgdKG86Ugnw7HBi02JLsOBzppLA044x2C/jbRcT # Bu7kA7YUq/OPQ6dxnSHdFMoVXZJB2vkPgdGZdA0mxA5/G7X1oPHGdwYoFenYk+VV # FvC7Cqsc21xIJ2bIo4sKHOWV2q7ELlmgYd3a822iYemKC23sEhi991VUQAOSK2vC # UcIKSK+w1G7g9BQKOhvjjz3Kr2qNe9zYRDCCBs0wggW1oAMCAQICEAb9+QOWA63q # AArrPye7uhswDQYJKoZIhvcNAQEFBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoT # DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UE # AxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTA2MTExMDAwMDAwMFoX # DTIxMTExMDAwMDAwMFowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0 # IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNl # cnQgQXNzdXJlZCBJRCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEA6IItmfnKwkKVpYBzQHDSnlZUXKnE0kEGj8kz/E1FkVyBn+0snPgWWd+etSQV # wpi5tHdJ3InECtqvy15r7a2wcTHrzzpADEZNk+yLejYIA6sMNP4YSYL+x8cxSIB8 # HqIPkg5QycaH6zY/2DDD/6b3+6LNb3Mj/qxWBZDwMiEWicZwiPkFl32jx0PdAug7 # Pe2xQaPtP77blUjE7h6z8rwMK5nQxl0SQoHhg26Ccz8mSxSQrllmCsSNvtLOBq6t # hG9IhJtPQLnxTPKvmPv2zkBdXPao8S+v7Iki8msYZbHBc63X8djPHgp0XEK4aH63 # 1XcKJ1Z8D2KkPzIUYJX9BwSiCQIDAQABo4IDejCCA3YwDgYDVR0PAQH/BAQDAgGG # MDsGA1UdJQQ0MDIGCCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUF # BwMEBggrBgEFBQcDCDCCAdIGA1UdIASCAckwggHFMIIBtAYKYIZIAYb9bAABBDCC # AaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMt # cmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBz # AGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBv # AG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAg # AHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAg # AHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBt # AGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0 # AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABo # AGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9 # bAMVMBIGA1UdEwEB/wQIMAYBAf8CAQAweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUF # BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6 # Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5j # cnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwHQYDVR0OBBYE # FBUAEisTmLKZB+0e36K+Vw0rZwLNMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6en # IZ3zbcgPMA0GCSqGSIb3DQEBBQUAA4IBAQBGUD7Jtygkpzgdtlspr1LPUukxR6tW # XHvVDQtBs+/sdR90OPKyXGGinJXDUOSCuSPRujqGcq04eKx1XRcXNHJHhZRW0eu7 # NoR3zCSl8wQZVann4+erYs37iy2QwsDStZS9Xk+xBdIOPRqpFFumhjFiqKgz5Js5 # p8T1zh14dpQlc+Qqq8+cdkvtX8JLFuRLcEwAiR78xXm8TBJX/l/hHrwCXaj++wc4 # Tw3GXZG5D2dFzdaD7eeSDY2xaYxP+1ngIw/Sqq4AfO6cQg7PkdcntxbuD8O9fAqg # 7iwIVYUiuOsYGk38KiGtSTGDR5V3cdyxG0tLHBCcdxTBnU8vWpUIKRAmMIIHODCC # BSCgAwIBAgIQEw12KjF18pBAJDt0qQwq6jANBgkqhkiG9w0BAQsFADBcMQswCQYD # VQQGEwJERTEPMA0GA1UEBxMGQmVybGluMRQwEgYDVQQKEwttZXRhQlBBLm9yZzEM # MAoGA1UECxMDRGV2MRgwFgYDVQQDEw9tZXRhQlBBIFJvb3QgQ0EwHhcNMTkxMTA4 # MjAwMDU5WhcNMzkxMTA4MjAxMDU0WjBcMQswCQYDVQQGEwJERTEPMA0GA1UEBxMG # QmVybGluMRQwEgYDVQQKEwttZXRhQlBBLm9yZzEMMAoGA1UECxMDRGV2MRgwFgYD # VQQDEw9tZXRhQlBBIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK # AoICAQCw2DkS2wXYAPJTQVkEccotAn/ba+ZxjYqvZOnOO1QbHk8XDSZCFrTADHjU # BvYZPVZDg/OPg082TOmln7uVfipsHt29WSWCVco6WTGbb2gHfTFpAoltfdRnsTWt # +J0l69tdPWVVxMpvsNv1S/FrfkEVLBW6k9glHSjmvz6uJNvF/UKtkkkElpPtbLsS # jNCwIqXJ7maZTNEEUGnmDYHhj2Bi7Ex5w2fKw5k5IvCr4BO6LLIim9HialiT0pMK # JMkWSQmQqDlC/WUjh5cmOD4fRq2cL8QiiJjz1mpbALd9zz7F9KO/7F9WZXQaiEK/ # vgBsB8LnjWlE/qh9eoWSw1ib+Pp2Nxs2Wmk433Di4pgkad4eZHC0ENF8/8VU/Via # a2PQJdwoK/ouAvUJz+JQ/q7hNClpoNa7dbgrtw63W0DeC7NbSHE7469ftrkkHsfy # S7y2YM68Nw/0s1kgQSneeqbOAMYIW1d634QJniOqzn1kb2wSHj+f/g90HTa+8vmh # wBC/AGWPZB28qxVz7CjQ6uRfNpQnP3WvEXaJbmKldhvzyTzAWxfhXRzNlRx8Ije1 # BsditmsB1W3V93AU+EH/FXs4r4toQCyAQL4ldXCEmcVxHO2qk3ZDjVIrDddk3wP3 # 9VZP9UTm/laSs/zhWIDYHdZe6Kh7kX95pt10hZqS73O4gcfWmQIDAQABo4IB9DCC # AfAwCwYDVR0PBAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0OBBYEFPm6 # Oe52dpXFPfitNGsYRvR/zuL4MBAGCSsGAQQBgjcVAQQDAgEAMIIBmgYDVR0gBIIB # kTCCAY0wggGJBgwrBgEEAYOHcQEBAQEwggF3MIIBRgYIKwYBBQUHAgIwggE4HoIB # NABUAGgAaQBzACAAUABLAEkAIABpAHMAIABpAG4AdABlAG4AZABlAGQAIABmAG8A # cgAgAGMAZQByAHQAaQBmAGkAYwBhAHQAaQBvAG4AIABiAHkAIABtAGUAdABhAEIA # UABBAC4AbwByAGcALAAgAEUAdgBnAGUAbgBpAGoAIABTAG0AaQByAG4AbwB2ACwA # IABCAGUAcgBsAGkAbgAgAG8AbgBsAHkALgAgAEYAbwByACAAZABlAHQAYQBpAGwA # cwAsACAAYwBvAG4AcwB1AGwAdAAgAHQAaABlACAAQwBlAHIAdABpAGYAaQBjAGEA # dABpAG8AbgAgAFAAbwBsAGkAYwB5ACAAUwB0AGEAdABlAG0AZQBuAHQAIABsAGkA # bgBrAGUAZAAgAGIAZQBsAG8AdwAuMCsGCCsGAQUFBwIBFh9odHRwOi8vcGtpLm1l # dGFicGEub3JnL2Nwcy5odG1sMA0GCSqGSIb3DQEBCwUAA4ICAQBuwVs984+DElFQ # BzO7r96a2/QZosjcZst3/KLCJQXRNjfrtHzGNDFRCj5MSqet9jXfC0Q0XQnus28S # NG75qpzdkdKFruAjffOP1qOWEjnsljK+KkNafHXywlNUDI4Y3LzO44jF33gpTPjM # 0KjWUGPRmwkOyapyEh629S7AlXikuYJLFDddsEVmzf9jVMjEQi37BzyaERwokkwg # bW4hxIVycoPyfPhiAVChPj/IHFVaUDYb6vvL5/LD6fS9qd7VbJgOtkrpZhBzV3n4 # Gi7cOHVvGylta/gp4sdpB62QBNTjUS8JOkU1ECLDpO+QfKdKn1jYqpv9vIVYvj52 # 4yPx92T/dp2zZqJd9/3/M35b9pk0J3ACf77Lb2sM98/G4HK5NI8LqdM8iEKQkPQ4 # 9gkujnnQrmm1CMYRND498GfcgxQo2h+TFrxEWfZRHrPmoPtp90E9lW/vgwsgvtGN # iBR6+wcEeBGm3TnwDUZsXhSUO0wyWSGhPWzxnM+ADC0iMpeBeTn22v+NA2S2mNOF # f0K83O+r6LhjcnoD6kehQ30hHdvplxUs/D+IiOVkwyhznAmEpLP0Wv3e+ggN0qDP # zYbKRjgJYcJBFU0us1+UADDg2mxxuJbNWmT7QXnh6eOlFPrYnwIdjmhJwkeaY7/N # bSbexF0k2hTNI6d526AFcHAVSjJqBDGCBCcwggQjAgEBMHMwXDELMAkGA1UEBhMC # REUxDzANBgNVBAcTBkJlcmxpbjEUMBIGA1UEChMLbWV0YUJQQS5vcmcxDDAKBgNV # BAsTA0RldjEYMBYGA1UEAxMPbWV0YUJQQSBSb290IENBAhNfAAAAAiNkKw+5hJ+U # AAAAAAACMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkG # CSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEE # AYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRRnGhZNHueNwMnuu4Vf6hdhrPndzANBgkq # hkiG9w0BAQEFAASCAQA7CjoR2kfK1x877RLNPbgS+CkZsqQ0Oo2hLximmrQQ5jGR # eFPMVSFDLrRUvVymY6x3R5x9fFoyiXezG9Nvtx3++Gi02/VvRHL2+k3yaDAtBWc7 # UPi3DmXtNSYucUrCxGAx1emq0iYGITCn/IaCYTkYr4VhmURJxz368DJX3PelS+h8 # LE/ivWLPNdCj93f6tGgouVo1C5i4gJSASrjIvS3TqPUy11W2PAtgNWqW79bXTRcr # iD29d063GF50EiygD7zOX0+vDL4EcLjFFLH464zu5snkr6anGThGe8OdMJE6ezuJ # gee5PpFd2CBIiEp0oA9Nrhz2Xy90BYd7YwzvFFLtoYICDzCCAgsGCSqGSIb3DQEJ # BjGCAfwwggH4AgEBMHYwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0 # IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNl # cnQgQXNzdXJlZCBJRCBDQS0xAhADAZoCOv9YsWvW1ermF/BmMAkGBSsOAwIaBQCg # XTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yMDAz # MjYyMDU2MzFaMCMGCSqGSIb3DQEJBDEWBBRo+bEvcxWlKn38ZSOITFobziDFoDAN # BgkqhkiG9w0BAQEFAASCAQA+hj2jhLpwsQ4WP9xXNJ1eM8g2sGds357jDgHYyu1h # f5EwXS9FKV/nXg5jDlaHGSbArIwgTfjg/wD6BCmzDrfiMWZJKLbmUfHEwBCcl1dL # Dw5YbYfeoO+Lp4a7y0jrWyzJ/TC2CuxSSSsOsBjbcgmuod/qQPN8eg10hevIee9G # 92HklMzceGoybsZ3zlRkbSXkZhWrPp1iG0zbpLGoDSFzBa85lELBrBRWgQlaCkUW # DN4BKpED8BNmP99Fzb7cBOoV3S4qwKt3Gc+AaR0qGVEvdQH/6390XiBKDSjJf44O # 0q4ASjuZ0DvU9J/txcMO1M7A4GaoaGz0ic3hF2mpbCSL # SIG # End signature block |