Public/Invoke/Enable-NetFx3.ps1
|
function Enable-NetFx3 { <# .SYNOPSIS Enables the .NET Framework 3.5 feature on the specified computer(s). .DESCRIPTION This function allows you to enable the .NET Framework 3.5 feature on local or remote computers. It supports specifying a source path for the feature files, using CredSSP for delegated credentials, and various other options. .PARAMETER ComputerName The name(s) of the target computer(s) where the .NET Framework 3.5 feature should be enabled. .PARAMETER Credential The credentials to use for the remote session. If not specified, the script will attempt to use stored domain admin credentials. .PARAMETER Source The path to the source files for the .NET Framework 3.5 feature. Can be a local path or a UNC path. .PARAMETER UseCredSSP Switch to indicate whether to use CredSSP for delegated credentials in remote sessions. .PARAMETER Quiet Switch to suppress output messages. .PARAMETER NoRestart Switch to prevent automatic restart after enabling the feature. .PARAMETER TimeoutMinutes The maximum time, in minutes, to wait for the feature to be enabled. Default is 60 minutes. .PARAMETER Validate Switch to perform validation after enabling the feature. #> [CmdletBinding()] param( [string[]]$ComputerName, [System.Management.Automation.PSCredential]$Credential, [string]$Source, [switch]$UseCredSSP, [switch]$Quiet, [switch]$NoRestart, [int]$TimeoutMinutes = 60, [switch]$Validate ) Initialize-TechToolboxRuntime # ---------------------------- # Remote mode # ---------------------------- if ($ComputerName -and $ComputerName.Count -gt 0) { if (-not $Credential -and $script:domainAdminCred) { $Credential = $script:domainAdminCred } if ($Source -and -not ($Source.StartsWith('\\'))) { Write-Log -Level 'Warn' -Message "[Enable-NetFx3] -Source '$Source' is not a UNC path. Ensure it exists on EACH target." } if ($Source -and $Source.StartsWith('\\') -and -not $UseCredSSP) { Write-Log -Level 'Warn' -Message "[Enable-NetFx3] UNC source detected without -UseCredSSP. If the share requires delegated credentials, remote feature enablement can fail with access denied." } Write-Log -Level 'Info' -Message "[Enable-NetFx3] Remote mode → targets: $($ComputerName -join ', ')" $moduleRoot = Get-ModuleRoot $workerLocal = Join-Path $moduleRoot 'Workers\Enable-NetFx3.worker.ps1' $pkg = New-HelpersPackage -HelperLibs @() -WorkerFiles @( $workerLocal ) function Get-Tail { param( [string]$Text, [int]$Lines = 8 ) if ([string]::IsNullOrWhiteSpace($Text)) { return $null } $parts = @($Text -split "`r?`n" | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) if ($parts.Count -eq 0) { return $null } ($parts | Select-Object -Last $Lines) -join "`n" } function Format-NetFx3State { param([string]$StateValue) if ([string]::IsNullOrWhiteSpace($StateValue)) { return $null } $trimmed = $StateValue.Trim() switch ($trimmed) { '0' { return 'Unknown' } '1' { return 'Disabled' } '2' { return 'Enabled' } '3' { return 'EnablePending' } '4' { return 'DisablePending' } default { return $trimmed } } } $results = @() foreach ($cn in $ComputerName) { $session = $null try { $session = Start-NewPSRemoteSession -ComputerName $cn -Credential $Credential -UseCredSSP:$UseCredSSP $r = Invoke-RemoteWorker ` -Session $session ` -HelpersZip $pkg.ZipPath ` -HelpersZipHash $pkg.ZipHash ` -WorkerRemotePath 'IGNORED' ` -WorkerLocalPath $workerLocal ` -EntryPoint 'Enable-NetFx3Core' ` -EntryParameters @{ Source = $Source TimeoutMinutes = $TimeoutMinutes Validate = $Validate NoRestart = $NoRestart Quiet = $Quiet } if ($r -and $r.SystemTaskPending) { $taskName = [string]$r.SystemTaskName $resultPath = [string]$r.SystemTaskResultPath $workDir = [string]$r.SystemTaskWorkDir if ($r.SystemTaskReused) { Write-Log -Level 'Info' -Message "[Enable-NetFx3][$cn] Reusing existing pending SYSTEM fallback task '$taskName'." } Wait-TerminalState ` -Target "SYSTEM fallback $cn" ` -PollScript { $statusObj = Invoke-Command -Session $session -ScriptBlock { param($tn, $rp) if (Test-Path -LiteralPath $rp) { return [pscustomobject]@{ Status = 'ResultReady' } } $statusOut = & schtasks.exe /Query /TN $tn /FO LIST /V 2>$null if (-not $statusOut) { return [pscustomobject]@{ Status = 'Unknown' } } $stateLine = @($statusOut | Where-Object { $_ -match '^\s*Status\s*:\s*' } | Select-Object -First 1) $state = if ($stateLine) { ($stateLine -replace '^\s*Status\s*:\s*', '').Trim() } else { 'Unknown' } if ($state -match 'Could not start|Could not run') { return [pscustomobject]@{ Status = 'TaskFinishedNoResult' } } [pscustomobject]@{ Status = 'Waiting' } } -ArgumentList $taskName, $resultPath $statusObj } ` -GetStatus { param($o) $o.Status } ` -TerminalStates @{ ResultReady = @{ Level = 'Ok'; Message = "[Enable-NetFx3][$cn] SYSTEM fallback result ready." } TaskFinishedNoResult = @{ Level = 'Warn'; Message = "[Enable-NetFx3][$cn] SYSTEM task finished without result file." } } ` -TimeoutSeconds ([int][TimeSpan]::FromMinutes([Math]::Max(1, $TimeoutMinutes)).TotalSeconds) ` -PollSeconds 15 ` -HeartbeatSeconds 120 ` -NotFoundToken 'TaskRunning' ` -NotFoundMessage 'Waiting for SYSTEM feature task result...' ` -WaitingMessage "Waiting SYSTEM feature task [$cn] " ` -ThrowOnTimeout:$false ` -ReturnLastOnTimeout ` -ContextFormatter { param($lastObj, $lastStatus) "Computer=$cn Task=$taskName LastStatus=$lastStatus" } | Out-Null $fallback = Invoke-Command -Session $session -ScriptBlock { param($rp) $result = [pscustomobject]@{ ExitCode = 1 Success = $false RebootRequired = $false State = $null Message = 'SYSTEM fallback task did not produce result.json before timeout or completion.' } try { if (Test-Path -LiteralPath $rp) { $raw = Get-Content -LiteralPath $rp -Raw -Encoding UTF8 $parsed = $raw | ConvertFrom-Json if ($parsed) { $result.ExitCode = [int]$parsed.ExitCode $result.Success = [bool]$parsed.Success $result.RebootRequired = [bool]$parsed.RebootRequired $result.State = Format-NetFx3State -StateValue ([string]$parsed.State) $result.Message = [string]$parsed.Message } } } catch { $result.Message = $_.Exception.Message } $result } -ArgumentList $resultPath if (-not $r.SystemTaskReused) { Invoke-Command -Session $session -ScriptBlock { param($tn, $wd) try { & schtasks.exe /Delete /TN $tn /F 2>$null | Out-Null } catch {} if (-not [string]::IsNullOrWhiteSpace($wd) -and (Test-Path -LiteralPath $wd)) { try { Remove-Item -LiteralPath $wd -Recurse -Force -ErrorAction Stop } catch {} } } -ArgumentList $taskName, $workDir | Out-Null } $r.SystemTaskPending = $false $r.SystemFallbackUsed = $true $r.ExitCode = [int]$fallback.ExitCode $r.Success = [bool]$fallback.Success $r.RebootRequired = [bool]$fallback.RebootRequired $r.State = $fallback.State $r.Message = $fallback.Message $r.DismStdOutTail = $null $r.DismStdErrTail = Get-Tail -Text $fallback.Message -Lines 8 } if ($r) { $results += $r } } catch { $results += [pscustomobject]@{ ComputerName = $cn ExitCode = 1 Success = $false RebootRequired = $false State = $null Message = $_.Exception.Message } } finally { if ($session) { Remove-PSSession -Session $session -ErrorAction SilentlyContinue } } } foreach ($r in $results) { if ($r.Success) { if ($r.SystemFallbackUsed) { Write-Log -Level 'Warn' -Message "[Enable-NetFx3][$($r.ComputerName)] Completed via SYSTEM fallback path." } if ($r.RebootRequired) { Write-Log -Level 'Warn' -Message "[Enable-NetFx3][$($r.ComputerName)] Success (reboot required)." } else { Write-Log -Level 'Ok' -Message "[Enable-NetFx3][$($r.ComputerName)] Success." } } else { $tail = if ($r.Message) { " - $($r.Message)" } else { "" } Write-Log -Level 'Error' -Message "[Enable-NetFx3][$($r.ComputerName)] Failed (Exit $($r.ExitCode))$tail" if ($r.ExitCode -eq 5) { Write-Log -Level 'Warn' -Message "[Enable-NetFx3][$($r.ComputerName)] Exit 5 typically means access denied. Confirm elevated token on target and use -Source with -UseCredSSP for UNC media when required." } elseif ($r.Message -match '(?i)access is denied|0x80070005') { Write-Log -Level 'Warn' -Message "[Enable-NetFx3][$($r.ComputerName)] Access denied indicates the remote token is not elevated enough for feature servicing. Configure the target WinRM endpoint with -RunAsCredential (an admin account) and retry." } if ($r.ExitCode -eq 5 -and -not $Source) { Write-Log -Level 'Warn' -Message "[Enable-NetFx3][$($r.ComputerName)] Try again with -Source \\server\share\sources\sxs (matching OS build) plus -UseCredSSP." } } } return $results } # ---------------------------- # Local mode # ---------------------------- Write-Log -Level 'Info' -Message "[Enable-NetFx3] Starting enablement (local)." $invokeParams = @{ Online = $true FeatureName = 'NetFx3' All = $true ErrorAction = 'Stop' } if ($NoRestart) { $invokeParams.NoRestart = $true } if ($Source) { $invokeParams.Source = $Source $invokeParams.LimitAccess = $true } $overallSuccess = $false $exitCode = 1 $state = $null $msg = $null $savedProgressPreference = $null try { if ($Quiet) { $savedProgressPreference = $ProgressPreference $ProgressPreference = 'SilentlyContinue' } $result = Enable-WindowsOptionalFeature @invokeParams $state = (Get-WindowsOptionalFeature -Online -FeatureName NetFx3 -ErrorAction Stop).State $restartNeeded = [bool]$result.RestartNeeded -or ($state -in 'EnablePending', 'EnabledPending') if ($state -in 'Enabled', 'EnablePending', 'EnabledPending') { $overallSuccess = $true $exitCode = if ($restartNeeded) { 3010 } else { 0 } if ($exitCode -eq 3010) { Write-Log -Level 'Warn' -Message "[Enable-NetFx3] Reboot required to complete NetFx3 enablement." } else { Write-Log -Level 'Ok' -Message "[Enable-NetFx3] Feature enablement completed successfully." } } else { $msg = "NetFx3 state not enabled after operation (State=$state)." Write-Log -Level 'Error' -Message "[Enable-NetFx3] $msg" $overallSuccess = $false $exitCode = 1 } } catch { $overallSuccess = $false $msg = $_.Exception.Message $exitCode = if ($_.Exception -is [System.UnauthorizedAccessException]) { 5 } else { 1 } Write-Log -Level 'Error' -Message "[Enable-NetFx3] Failed: $msg" } finally { if ($Quiet -and $null -ne $savedProgressPreference) { $ProgressPreference = $savedProgressPreference } } if ($overallSuccess -and $Validate) { try { $state = (Get-WindowsOptionalFeature -Online -FeatureName NetFx3).State Write-Log -Level 'Info' -Message "[Enable-NetFx3] Feature state: $state" if ($state -in 'Enabled', 'EnablePending', 'EnabledPending') { Write-Log -Level 'Ok' -Message "[Enable-NetFx3] NetFx3 enablement validated." } else { Write-Log -Level 'Error' -Message "[Enable-NetFx3] NetFx3 state not enabled after operation." $overallSuccess = $false } } catch { Write-Log -Level 'Warn' -Message "[Enable-NetFx3] Validation skipped: $($_.Exception.Message)" } } [pscustomobject]@{ ComputerName = $env:COMPUTERNAME ExitCode = $exitCode Success = [bool]$overallSuccess RebootRequired = ($exitCode -eq 3010) State = $state Message = $msg } } # SIG # Begin signature block # MIIfAgYJKoZIhvcNAQcCoIIe8zCCHu8CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAQ8zgCgV1zq904 # p2o5uLfOBWRTN/etGVnmooLNLvUDNqCCGEowggUMMIIC9KADAgECAhAR+U4xG7FH # qkyqS9NIt7l5MA0GCSqGSIb3DQEBCwUAMB4xHDAaBgNVBAMME1ZBRFRFSyBDb2Rl # IFNpZ25pbmcwHhcNMjUxMjE5MTk1NDIxWhcNMjYxMjE5MjAwNDIxWjAeMRwwGgYD # VQQDDBNWQURURUsgQ29kZSBTaWduaW5nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A # MIICCgKCAgEA3pzzZIUEY92GDldMWuzvbLeivHOuMupgpwbezoG5v90KeuN03S5d # nM/eom/PcIz08+fGZF04ueuCS6b48q1qFnylwg/C/TkcVRo0WFcKoFGT8yGxdfXi # caHtapZfbSRh73r7qR7w0CioVveNBVgfMsTgE0WKcuwxemvIe/ptmkfzwAiw/IAC # Ib0E0BjiX4PySbwWy/QKy/qMXYY19xpRItVTKNBtXzADUtzPzUcFqJU83vM2gZFs # Or0MhPvM7xEVkOWZFBAWAubbMCJ3rmwyVv9keVDJChhCeLSz2XR11VGDOEA2OO90 # Y30WfY9aOI2sCfQcKMeJ9ypkHl0xORdhUwZ3Wz48d3yJDXGkduPm2vl05RvnA4T6 # 29HVZTmMdvP2475/8nLxCte9IB7TobAOGl6P1NuwplAMKM8qyZh62Br23vcx1fXZ # TJlKCxBFx1nTa6VlIJk+UbM4ZPm954peB/fIqEacm8LkZ0cPwmLE5ckW7hfK4Trs # o+RaudU1sKeA+FvpOWgsPccVRWcEYyGkwbyTB3xrIBXA+YckbANZ0XL7fv7x29hn # gXbZipGu3DnTISiFB43V4MhNDKZYfbWdxze0SwLe8KzIaKnwlwRgvXDMwXgk99Mi # EbYa3DvA/5ZWikLW9PxBFD7Vdr8ZiG/tRC9I2Y6fnb+PVoZKc/2xsW0CAwEAAaNG # MEQwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMB0GA1UdDgQW # BBRfYLVE8caSc990rnrIHUjoB7X/KjANBgkqhkiG9w0BAQsFAAOCAgEAiGB2Wmk3 # QBtd1LcynmxHzmu+X4Y5DIpMMNC2ahsqZtPUVcGqmb5IFbVuAdQphL6PSrDjaAR8 # 1S8uTfUnMa119LmIb7di7TlH2F5K3530h5x8JMj5EErl0xmZyJtSg7BTiBA/UrMz # 6WCf8wWIG2/4NbV6aAyFwIojfAcKoO8ng44Dal/oLGzLO3FDE5AWhcda/FbqVjSJ # 1zMfiW8odd4LgbmoyEI024KkwOkkPyJQ2Ugn6HMqlFLazAmBBpyS7wxdaAGrl18n # 6bS7QuAwCd9hitdMMitG8YyWL6tKeRSbuTP5E+ASbu0Ga8/fxRO5ZSQhO6/5ro1j # PGe1/Kr49Uyuf9VSCZdNIZAyjjeVAoxmV0IfxQLKz6VOG0kGDYkFGskvllIpQbQg # WLuPLJxoskJsoJllk7MjZJwrpr08+3FQnLkRuisjDOc3l4VxFUsUe4fnJhMUONXT # Sk7vdspgxirNbLmXU4yYWdsizz3nMUR0zebUW29A+HYme16hzrMPOeyoQjy4I5XX # 3wXAFdworfPEr/ozDFrdXKgbLwZopymKbBwv6wtT7+1zVhJXr+jGVQ1TWr6R+8ea # tIOFnY7HqGaxe5XB7HzOwJKdj+bpHAfXft1vUoiKr16VajLigcYCG8MdwC3sngO3 # JDyv2V+YMfsYBmItMGBwvizlQ6557NbK95EwggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwgga0MIIEnKADAgECAhANx6xXBf8hmS5AQyIMOkmGMA0GCSqG # SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcwMDAwMDBaFw0zODAxMTQyMzU5NTlaMGkx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4 # RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYg # MjAyNSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC0eDHTCphB # cr48RsAcrHXbo0ZodLRRF51NrY0NlLWZloMsVO1DahGPNRcybEKq+RuwOnPhof6p # vF4uGjwjqNjfEvUi6wuim5bap+0lgloM2zX4kftn5B1IpYzTqpyFQ/4Bt0mAxAHe # HYNnQxqXmRinvuNgxVBdJkf77S2uPoCj7GH8BLuxBG5AvftBdsOECS1UkxBvMgEd # gkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQSku2Ws3IfDReb6e3mmdglTcaarps0wjU # jsZvkgFkriK9tUKJm/s80FiocSk1VYLZlDwFt+cVFBURJg6zMUjZa/zbCclF83bR # VFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+8y9oHRaQT/aofEnS5xLrfxnGpTXiUOeS # LsJygoLPp66bkDX1ZlAeSpQl92QOMeRxykvq6gbylsXQskBBBnGy3tW/AMOMCZIV # NSaz7BX8VtYGqLt9MmeOreGPRdtBx3yGOP+rx3rKWDEJlIqLXvJWnY0v5ydPpOjL # 6s36czwzsucuoKs7Yk/ehb//Wx+5kMqIMRvUBDx6z1ev+7psNOdgJMoiwOrUG2Zd # SoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm1UUl9VnePs6BaaeEWvjJSjNm2qA+sdFU # eEY0qVjPKOWug/G6X5uAiynM7Bu2ayBjUwIDAQABo4IBXTCCAVkwEgYDVR0TAQH/ # BAgwBgEB/wIBADAdBgNVHQ4EFgQU729TSunkBnx6yuKQVvYv1Ensy04wHwYDVR0j # BBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1Ud # JQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0 # cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0 # cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8E # PDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz # dGVkUm9vdEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEw # DQYJKoZIhvcNAQELBQADggIBABfO+xaAHP4HPRF2cTC9vgvItTSmf83Qh8WIGjB/ # T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQM2qEJPe36zwbSI/mS83afsl3YTj+IQhQ # E7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt6vJy9lMDPjTLxLgXf9r5nWMQwr8Myb9r # EVKChHyfpzee5kH0F8HABBgr0UdqirZ7bowe9Vj2AIMD8liyrukZ2iA/wdG2th9y # 1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmSNq1UH410ANVko43+Cdmu4y81hjajV/gx # dEkMx1NKU4uHQcKfZxAvBAKqMVuqte69M9J6A47OvgRaPs+2ykgcGV00TYr2Lr3t # y9qIijanrUR3anzEwlvzZiiyfTPjLbnFRsjsYg39OlV8cipDoq7+qNNjqFzeGxcy # tL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmMThi0vw9vODRzW6AxnJll38F0cuJG7uEB # YTptMSbhdhGQDpOXgpIUsWTjd6xpR6oaQf/DJbg3s6KCLPAlZ66RzIg9sC+NJpud # /v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx9yHbxtl5TPau1j/1MIDpMPx0LckTetiS # uEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3/BAPvIXKUjPSxyZsq8WhbaM2tszWkPZP # ubdcMIIG7TCCBNWgAwIBAgIQCoDvGEuN8QWC0cR2p5V0aDANBgkqhkiG9w0BAQsF # ADBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNV # BAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJTQTQwOTYgU0hB # MjU2IDIwMjUgQ0ExMB4XDTI1MDYwNDAwMDAwMFoXDTM2MDkwMzIzNTk1OVowYzEL # MAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTswOQYDVQQDEzJE # aWdpQ2VydCBTSEEyNTYgUlNBNDA5NiBUaW1lc3RhbXAgUmVzcG9uZGVyIDIwMjUg # MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANBGrC0Sxp7Q6q5gVrMr # V7pvUf+GcAoB38o3zBlCMGMyqJnfFNZx+wvA69HFTBdwbHwBSOeLpvPnZ8ZN+vo8 # dE2/pPvOx/Vj8TchTySA2R4QKpVD7dvNZh6wW2R6kSu9RJt/4QhguSssp3qome7M # rxVyfQO9sMx6ZAWjFDYOzDi8SOhPUWlLnh00Cll8pjrUcCV3K3E0zz09ldQ//nBZ # ZREr4h/GI6Dxb2UoyrN0ijtUDVHRXdmncOOMA3CoB/iUSROUINDT98oksouTMYFO # nHoRh6+86Ltc5zjPKHW5KqCvpSduSwhwUmotuQhcg9tw2YD3w6ySSSu+3qU8DD+n # igNJFmt6LAHvH3KSuNLoZLc1Hf2JNMVL4Q1OpbybpMe46YceNA0LfNsnqcnpJeIt # K/DhKbPxTTuGoX7wJNdoRORVbPR1VVnDuSeHVZlc4seAO+6d2sC26/PQPdP51ho1 # zBp+xUIZkpSFA8vWdoUoHLWnqWU3dCCyFG1roSrgHjSHlq8xymLnjCbSLZ49kPmk # 8iyyizNDIXj//cOgrY7rlRyTlaCCfw7aSUROwnu7zER6EaJ+AliL7ojTdS5PWPsW # eupWs7NpChUk555K096V1hE0yZIXe+giAwW00aHzrDchIc2bQhpp0IoKRR7YufAk # prxMiXAJQ1XCmnCfgPf8+3mnAgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAAMB0G # A1UdDgQWBBTkO/zyMe39/dfzkXFjGVBDz2GM6DAfBgNVHSMEGDAWgBTvb1NK6eQG # fHrK4pBW9i/USezLTjAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYB # BQUHAwgwgZUGCCsGAQUFBwEBBIGIMIGFMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz # cC5kaWdpY2VydC5jb20wXQYIKwYBBQUHMAKGUWh0dHA6Ly9jYWNlcnRzLmRpZ2lj # ZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRpbWVTdGFtcGluZ1JTQTQwOTZTSEEy # NTYyMDI1Q0ExLmNydDBfBgNVHR8EWDBWMFSgUqBQhk5odHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hB # MjU2MjAyNUNBMS5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcB # MA0GCSqGSIb3DQEBCwUAA4ICAQBlKq3xHCcEua5gQezRCESeY0ByIfjk9iJP2zWL # pQq1b4URGnwWBdEZD9gBq9fNaNmFj6Eh8/YmRDfxT7C0k8FUFqNh+tshgb4O6Lgj # g8K8elC4+oWCqnU/ML9lFfim8/9yJmZSe2F8AQ/UdKFOtj7YMTmqPO9mzskgiC3Q # YIUP2S3HQvHG1FDu+WUqW4daIqToXFE/JQ/EABgfZXLWU0ziTN6R3ygQBHMUBaB5 # bdrPbF6MRYs03h4obEMnxYOX8VBRKe1uNnzQVTeLni2nHkX/QqvXnNb+YkDFkxUG # tMTaiLR9wjxUxu2hECZpqyU1d0IbX6Wq8/gVutDojBIFeRlqAcuEVT0cKsb+zJNE # suEB7O7/cuvTQasnM9AWcIQfVjnzrvwiCZ85EE8LUkqRhoS3Y50OHgaY7T/lwd6U # Arb+BOVAkg2oOvol/DJgddJ35XTxfUlQ+8Hggt8l2Yv7roancJIFcbojBcxlRcGG # 0LIhp6GvReQGgMgYxQbV1S3CrWqZzBt1R9xJgKf47CdxVRd/ndUlQ05oxYy2zRWV # FjF7mcr4C34Mj3ocCVccAvlKV9jEnstrniLvUxxVZE/rptb7IRE2lskKPIJgbaP5 # t2nGj/ULLi49xTcBZU8atufk+EMF/cWuiC7POGT75qaL6vdCvHlshtjdNXOCIUjs # arfNZzGCBg4wggYKAgEBMDIwHjEcMBoGA1UEAwwTVkFEVEVLIENvZGUgU2lnbmlu # ZwIQEflOMRuxR6pMqkvTSLe5eTANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3 # AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisG # AQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBbUXhdfDUp # +4DtjuX4VzMfJtvIB4h+RFutKgGZNXnYuzANBgkqhkiG9w0BAQEFAASCAgDCutO7 # h05iAeWA6KTeQ0gEwXLibOfNl5TvVOiBL4bRGg7nklB0uSx/MWOmJYX6SL2WzfN+ # 7SIext5lBVoXRYALdwuysc0ArHeHVZGHnFhmcE+iyLYmIK4PlaOH2ZbSp2lNbtbp # 8yKgiP9cJRk4zlplTtYjofvcz7l49Po5GxxhPzc+DpnDEwiZ8x80rsdeByCq6EYV # P3AKiwKyon6f7k3/GEjm5wRQ9nnyVhqrQxsP1lwBBHnt42ZwADBOh85+r71aVU6p # ZAmrdTZLH6+FEjN26npiOLyByh6wQrqJ8Yi6ddC+Vj6Dg3Vrtuhq90QmUKbxsyfx # kca1p64D9wtJxukTZZqL0UVZbW40iJ4xutJnfvLVKP/mJsdpfK1V8PtjmZILCHqM # X4H0MTOlWlBCB/8dD1MrXAiKmTAfHOL5eOvANT+FSUiiYboxwRRhK74PuMHbk9uJ # edIMFGoBohXXEfRXe8EXEXWCU1hLeEbvz0tXEKPumEaSuoCdJ75hp/MewOSxzuFe # JQ4LEq2f+upbld0ti98QMuwaC2Tn0Sdz3xSb627JGZcqGE4kCTAS93dCpYYj3M4b # vbRfzAUhZU0pN1835hJtyBIpwZjvXSCQO9/gnu5+dFblOml9LhcuRMhau1hy9QGN # xJe4puqkYNu2+PqAf3FgF8g+knEXS5hv8a5x9aGCAyYwggMiBgkqhkiG9w0BCQYx # ggMTMIIDDwIBATB9MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg # SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1lU3RhbXBpbmcg # UlNBNDA5NiBTSEEyNTYgMjAyNSBDQTECEAqA7xhLjfEFgtHEdqeVdGgwDQYJYIZI # AWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJ # BTEPFw0yNjA1MjgxNDMzNDlaMC8GCSqGSIb3DQEJBDEiBCCqp5NmakHYzbRjyELX # o1SX1yxFSomEkyyMV9Hu83wjDDANBgkqhkiG9w0BAQEFAASCAgCaI5m3ExauNa1i # ypXufxV+JxlYiItJ/zV1cRA1sfyM3CTwzVVKrF7aqT0m1B0GE6yBn6cqKeGoK9SS # K8VeIrIN1VTJLMNDKXqooma/yI0F2MVLLzZHuS+4uMCBIvlMN8Xc4fx+E88i4ZV+ # GNDOOrCR937xi/6omNy8SmH5jF0tMDkCRevOTc1kisb75vQzMj98r6hV0HkVtrJT # QHrlMYQs6slQaamXDR1l7WhfrFn7hym7nK+vGMO8p7mTnC2tvsme5M/VrJoprJo9 # sj3b3N6yVboBGbmu30W5tMFMrgTaeqaNitG8b0NGovstEHg4JyiaA4nDM4hCqNTk # cpBGz0eZFP3hCG4b/SR1GQnGuWdFdwoXQUB3D+ajiFSeqYiIWqtZ5llRQ1DVXzN5 # S3GQLFBP89UEfSctIPymSbQ4OigEDA7F7Fimb8zUadqzvXjsvshJlaQUwiiwPBYB # xUwjXbmlDt1HG1Kzl798TlCnxJWnLzJlu7gWYn5ezIxEvRjIE0sDsm4Z9dXBhZfR # CCNy4dOe9NhE7PEquPfqMqs/E3+A3jeXg9nurqBX8uoBxA+Thd5ROgsodBBKFUDD # pHMhbeDyWs2GWRlyjhEhjxWyhXxxiUaBgCGFtqc3tB5XRKH7cVPDnSUePGs+6cQs # PXlkRTiO7KPOEcKUo0XWAkiaoHgskQ== # SIG # End signature block |