Public/Get-ADFSTkHealth.ps1
function Get-ADFSTkHealth { [CmdletBinding()] param ( #The path to the institution configuration file that should be handled. If not provided all institution config files present in ADFSTk config will be used. $ConfigFile, #The HealtheCheckMode states how rigorous tests should be done. Defalut is done every time Sync-ADFSTkAggregates are run. [ValidateSet("CriticalOnly", "Default", "Full")] $HealthCheckMode = "Default", #Silent only reports true/false without output. It also tries to fix errors that can be fixed automatically. [switch]$Silent ) $healthChecks = @{ CheckSignature = ($HealthCheckMode -ne "CriticalOnly") #Don't run i CriticalOnly CheckADFSTkConfigVersion = $true CheckInstitutionConfigVersion = $true MFAAccesControlPolicy = $true RemovedSPsStillInSPHash = ($HealthCheckMode -eq "Full") #Only run in Full mode ScheduledTaskPresent = ($HealthCheckMode -eq "Full") #Checks if the Import Metadata Scheduled Task is present MissingSPsInADFS = ($HealthCheckMode -eq "Full") #Only run in Full mode FticksScheduledTaskPresent = ($HealthCheckMode -eq "Full") #Checks if the F-ticks Scheduled Task is present } enum Result { None Pass Warning Fail } $healthResults = @() #Get All paths if ([string]::IsNullOrEmpty($Global:ADFSTkPaths)) { $Global:ADFSTkPaths = Get-ADFSTKPaths } #region get config file(s) $ADFSTkConfig = Get-ADFSTkConfiguration $configFiles = @() if ($PSBoundParameters.ContainsKey('configFile')) { $configFiles += $configFile } else { $configFiles = $ADFSTkConfig.Configuration.ConfigFiles.ConfigFile | ? enabled -eq $true | select -ExpandProperty '#text' } #endregion if (!$Silent) { $numberOfHealthChecks = ($healthChecks.Values | ? { $_ -eq $true }).Count $numberOfHealthChecksDone = 0 Write-Progress -Activity "Processing Health Checks..." } #region check script signatures if ($healthChecks.CheckSignature) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckSignatureStartMessage) if (!$Silent) { $numberOfHealthChecksDone++ Write-Progress -Activity "Processing Health Checks..." -Status "$numberOfHealthChecksDone/$numberOfHealthChecks" -CurrentOperation (Get-ADFSTkLanguageText healthCheckMissingSignaturesName) -PercentComplete ($numberOfHealthChecksDone / $numberOfHealthChecks * 100) } $Signatures = Get-ChildItem -Path $Global:ADFSTkPaths.modulePath -Filter *.ps1 -Recurse | Get-AuthenticodeSignature $validSignatures = $Signatures | ? Status -eq Valid | Select -ExpandProperty Path $invalidSignatures = $Signatures | ? Status -eq HashMismatch | Select -ExpandProperty Path $missingSignatures = $Signatures | ? Status -eq NotSigned | Select -ExpandProperty Path Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckSignatureValidSignaturesResult -f $validSignatures.Count) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckSignatureInvalidSignaturesResult -f $invalidSignatures.Count) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckSignatureMissingSignaturesResult -f $missingSignatures.Count) #Signature(s) missing... $resultObject = [PSCustomObject]@{ CheckID = "CheckSignature" CheckName = Get-ADFSTkLanguageText healthCheckMissingSignaturesName ResultValue = [Result]::Pass ResultText = "No files with missing signatures!" ResultData = @() ReferenceFile = "" FixID = "" } if ($missingSignatures.Count -gt 0) { if ($Global:ADFSTkSkipNotSignedHealthCheck -eq $true) { $resultObject.ResultText = Get-ADFSTkLanguageText healthCheckSignatureSkipNotSignedMessage Write-ADFSTkVerboseLog $resultObject.ResultText $healthResults += $resultObject } else { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = Get-ADFSTkLanguageText healthCheckSignatureMissingSignaturesResult -f $missingSignatures.Count $resultObject.ResultData = $missingSignatures Write-ADFSTkLog (Get-ADFSTkLanguageText healthCheckSignatureMissingSignaturesMessage -f ($missingSignatures | Out-String)) -EntryType Warning $healthResults += $resultObject } } else { $healthResults += $resultObject } #Invalid signature(s)... $resultObject = [PSCustomObject]@{ CheckID = "CheckSignature" CheckName = Get-ADFSTkLanguageText healthCheckIncorectSignaturesName ResultValue = [Result]::Pass ResultText = "No files with incorrect signature!" ResultData = @() ReferenceFile = "" FixID = "" } if ($invalidSignatures.Count -gt 0) { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = Get-ADFSTkLanguageText healthCheckSignatureInvalidSignaturesMessage -f ($invalidSignatures | Out-String) $resultObject.ResultData = $invalidSignatures Write-ADFSTkVerboseLog $resultObject.ResultText -EntryType Warning $healthResults += $resultObject } else { $healthResults += $resultObject } if ($resultObject.ResultValue -eq [Result]::Pass) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckSignaturePass) } else { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckSignatureFail) } } #endregion #region check ADFS Toolkit config version if ($healthChecks.CheckADFSTkConfigVersion) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckADFSTkConfigVersionStartMessage) if (!$Silent) { $numberOfHealthChecksDone++ Write-Progress -Activity "Processing Health Checks..." -Status "$numberOfHealthChecksDone/$numberOfHealthChecks" -CurrentOperation (Get-ADFSTkLanguageText healthCheckADFSTkConfigVersionStartMessage) -PercentComplete ($numberOfHealthChecksDone / $numberOfHealthChecks * 100) } $resultObject = [PSCustomObject]@{ CheckID = "CheckADFSTkConfigVersion" CheckName = "ADFS Toolkit Configuration Version control" ResultValue = [Result]::None ResultText = "" ResultData = @() ReferenceFile = "" FixID = "" } #Check against compatible version Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckConfigVersionVerifyingVersionStart) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckConfigVersionVerifyingVersionCompareVersions -f $ADFSTkConfig.Configuration.ConfigVersion, $Global:ADFSTkCompatibleADFSTkConfigVersion) if ([float]$ADFSTkConfig.Configuration.ConfigVersion -eq [float]$Global:ADFSTkCompatibleADFSTkConfigVersion) { $resultObject.ResultValue = [Result]::Pass $resultObject.ResultText = Get-ADFSTkLanguageText healthCheckConfigVersionVerifyingVersionSucceeded Write-ADFSTkVerboseLog $resultObject.ResultText } else { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = Get-ADFSTkLanguageText healthIncompatibleADFSTkConfigVersion -f $ADFSTkConfig.Configuration.ConfigVersion, $Global:ADFSTkCompatibleADFSTkConfigVersion $resultObject.FixID = "FixADFSTkConfigVersion" Write-ADFSTkLog $resultObject.ResultText -EntryType Warning } $healthResults += $resultObject if ($resultObject.ResultValue -eq [Result]::Pass) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckConfigVersionPass) } else { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckConfigVersionFail) } } #endregion #region check institution config version if ($healthChecks.CheckInstitutionConfigVersion) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckInstitutionConfigVersionStartMessage) if (!$Silent) { $numberOfHealthChecksDone++ Write-Progress -Activity "Processing Health Checks..." -Status "$numberOfHealthChecksDone/$numberOfHealthChecks" -CurrentOperation (Get-ADFSTkLanguageText healthCheckInstitutionConfigVersionStartMessage) -PercentComplete ($numberOfHealthChecksDone / $numberOfHealthChecks * 100) } foreach ($cf in $configFiles) { $resultObject = [PSCustomObject]@{ CheckID = "CheckInstitutionConfigVersion" CheckName = "Institution Configuration Version control" ResultValue = [Result]::None ResultText = "" ResultData = @() ReferenceFile = $cf FixID = "" } Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healhCheckConfigVersionVerifyingPath -f $cf) if (Test-Path $cf) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healhCheckConfigVersionVerifyingPathSucceeded) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healhCheckConfigVersionVerifyingXMLParse) try { [xml]$xmlCf = Get-Content $cf Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healhCheckConfigVersionVerifyingXMLParseSucceeded) #Check against compatible version Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckConfigVersionVerifyingVersionStart) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckConfigVersionVerifyingVersionCompareVersions -f $xmlCf.configuration.ConfigVersion, $Global:ADFSTkCompatibleInstitutionConfigVersion) if ([float]$xmlCf.configuration.ConfigVersion -eq [float]$Global:ADFSTkCompatibleInstitutionConfigVersion) { $resultObject.ResultValue = [Result]::Pass $resultObject.ResultText = Get-ADFSTkLanguageText healthCheckConfigVersionVerifyingVersionSucceeded Write-ADFSTkVerboseLog $resultObject.ResultText } else { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = Get-ADFSTkLanguageText healthIncompatibleInstitutionConfigVersion -f $xmlCf.configuration.ConfigVersion, $Global:ADFSTkCompatibleInstitutionConfigVersion $resultObject.ResultData = $xmlCf.configuration.ConfigVersion $resultObject.FixID = "FixInstitutionConfigVersion" Write-ADFSTkLog $resultObject.ResultText -EntryType Warning } } catch { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = Get-ADFSTkLanguageText healhCheckConfigVersionVerifyingXMLParseFailed -f $cf $resultObject.ResultData = $cf Write-ADFSTkLog $resultObject.ResultText -EntryType Warning } } else { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = Get-ADFSTkLanguageText cFileDontExist -f $cf $resultObject.ResultData = $cf Write-ADFSTkLog $resultObject.ResultText -EntryType Warning } $healthResults += $resultObject if ($resultObject.ResultValue -eq [Result]::Pass) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckConfigVersionPass) } else { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckConfigVersionFail) } } } #endregion #region check Access Control Policy if MFA Adapter is installed Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckMFAAccessPolicyStartMessage) if (!$Silent) { $numberOfHealthChecksDone++ Write-Progress -Activity "Processing Health Checks..." -Status "$numberOfHealthChecksDone/$numberOfHealthChecks" -CurrentOperation (Get-ADFSTkLanguageText healthCheckMFAAccessPolicyStartMessage) -PercentComplete ($numberOfHealthChecksDone / $numberOfHealthChecks * 100) } if ($healthChecks.MFAAccesControlPolicy) { $resultObject = [PSCustomObject]@{ CheckID = "MFAAccesControlPolicy" CheckName = "MFA Access Control Policy" ResultValue = [Result]::None ResultText = "" ResultData = @() ReferenceFile = "" FixID = "" } #Only if MFA Adapter installed! # Check if the ADFSTK MFA Adapter is installed and add rules if so if ([string]::IsNullOrEmpty($Global:ADFSTKRefedsMFAUsernamePasswordAdapterInstalled)) { $Global:ADFSTKRefedsMFAUsernamePasswordAdapterInstalled = ![string]::IsNullOrEmpty((Get-AdfsAuthenticationProvider -Name RefedsMFAUsernamePasswordAdapter -WarningAction Ignore)) } if ($Global:ADFSTKRefedsMFAUsernamePasswordAdapterInstalled) { if ((Get-AdfsAccessControlPolicy -Identifier ADFSToolkitPermitEveryoneAndRequireMFA) -eq $null) { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = Get-ADFSTkLanguageText healthMFAAccesControlPolicyInstalledACPMissing $resultObject.FixID = "CreateACP" } else { $resultObject.ResultValue = [Result]::Pass $resultObject.ResultText = Get-ADFSTkLanguageText healthMFAAccesControlPolicyInstalledACPPresent } } else { $resultObject.ResultValue = [Result]::Pass $resultObject.ResultText = Get-ADFSTkLanguageText healthMFAAccesControlPolicyNotInstalled } $healthResults += $resultObject if ($resultObject.ResultValue -eq [Result]::Pass) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthMFAAccesControlPolicyPass) } else { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthMFAAccesControlPolicyFail) } } #endregion #region check removedSPsStillInSPHash if ($healthChecks.removedSPsStillInSPHash) { #Automatically remove SP's from SPHash File that's not in the Metadata Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthCheckRemovedSPsStillInSPHashSPHashStartMessage) if (!$Silent) { $numberOfHealthChecksDone++ Write-Progress -Activity "Processing Health Checks..." -Status "$numberOfHealthChecksDone/$numberOfHealthChecks" -CurrentOperation (Get-ADFSTkLanguageText healthCheckRemovedSPsStillInSPHashSPHashStartMessage) -PercentComplete ($numberOfHealthChecksDone / $numberOfHealthChecks * 100) } foreach ($cf in $configFiles) { $resultObject = [PSCustomObject]@{ CheckID = "RemovedSPsStillInSPHash" CheckName = "SP's in SPHash File not in Metadata" ResultValue = [Result]::None ResultText = "" ResultData = @() ReferenceFile = $cf FixID = "" } try { $instConfig = Get-ADFSTkInstitutionConfig -ConfigFile $cf $spHashFile = Join-Path $Global:ADFSTkPaths.cacheDir $instConfig.configuration.SPHashFile $metadataCacheFile = Join-Path $Global:ADFSTkPaths.cacheDir $instConfig.configuration.MetadataCacheFile if (Test-Path $spHashFile) { try { $fromHash = [string[]](Import-Clixml $spHashFile).Keys } catch { #What to do? #Rename it? Delete it? $resultObject.Checkname = "SPHash File corrupt" $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = (Get-ADFSTkLanguageText healthCheckRemovedSPsStillInSPHashSPHashCorrupt -f $spHashFile) $resultObject.ReferenceFile = $spHashFile $resultObject.FixID = "DeleteSPHashFile" } if ($resultObject.ResultValue -ne [Result]::Fail) { $MetadataXML = Get-ADFSTkMetadata -metadataURL $instConfig.configuration.metadataURL -CachedMetadataFile $metadataCacheFile $RawAllSPs = $MetadataXML.EntitiesDescriptor.EntityDescriptor | ? { $_.SPSSODescriptor -ne $null } $MetadataSPs = $RawAllSPs.EntityID $compare = Compare-ADFSTkObject $MetadataSPs $fromHash -CompareType InSecondSetOnly if ($compare.MembersInCompareSet -gt 0) { $resultObject.ResultValue = [Result]::Warning $resultObject.ResultText = (Get-ADFSTkLanguageText healthCheckRemovedSPsStillInSPHashMissingInMetadata -f $compare.MembersInCompareSet) $resultObject.ReferenceFile = $spHashFile $resultObject.ResultData = $compare.CompareSet $resultObject.FixID = "RemoveSPsFromSPHashFile" } else { $resultObject.ResultValue = [Result]::Pass $resultObject.ResultText = Get-ADFSTkLanguageText healthCheckRemovedSPsStillInSPHashNoSPsMissingInMetadata } } } else { $resultObject.CheckID = "SPHashMissing" $resultObject.CheckName = "SP Hash File existance" $resultObject.ResultValue = [Result]::Warning $resultObject.ResultText = (Get-ADFSTkLanguageText healthCheckRemovedSPsStillInSPHashAllSPsWillBeImported -f $spHashFile) $resultObject.ReferenceFile = $spHashFile } } catch { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = $_ } $healthResults += $resultObject } } #endregion #region remove/rerun missing SP's if ($healthChecks.MissingSPsInADFS) { #Automatically remove SP's from SPHash File that's not in the Metadata Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthMissingSPsInADFSStartMessage) if (!$Silent) { $numberOfHealthChecksDone++ Write-Progress -Activity "Processing Health Checks..." -Status "$numberOfHealthChecksDone/$numberOfHealthChecks" -CurrentOperation (Get-ADFSTkLanguageText healthMissingSPsInADFSStartMessage) -PercentComplete ($numberOfHealthChecksDone / $numberOfHealthChecks * 100) } foreach ($cf in $configFiles) { $resultObject = [PSCustomObject]@{ CheckID = "MissingSPsInADFS" CheckName = "SP's in SPHash File missing in ADFS" ResultValue = [Result]::None ResultText = "" ResultData = @() ReferenceFile = $cf FixID = "" } try { $instConfig = Get-ADFSTkInstitutionConfig -ConfigFile $cf $spHashFile = Join-Path $Global:ADFSTkPaths.cacheDir $instConfig.configuration.SPHashFile $metadataCacheFile = Join-Path $Global:ADFSTkPaths.cacheDir $instConfig.configuration.MetadataCacheFile if (Test-Path $spHashFile) { try { $fromHash = [string[]](Import-Clixml $spHashFile).Keys } catch { #What to do? #Rename it? Delete it? $resultObject.Checkname = "SPHash File corrupt" $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = (Get-ADFSTkLanguageText healthCheckRemovedSPsStillInSPHashSPHashCorrupt -f $spHashFile) $resultObject.ReferenceFile = $spHashFile $resultObject.FixID = "DeleteSPHashFile" } if ($resultObject.ResultValue -ne [Result]::Fail) { $installed = [string[]](Get-ADFSTkToolEntityId -All | Select -ExpandProperty Identifier) $compare = Compare-ADFSTkObject $installed $fromHash -CompareType InSecondSetOnly if ($compare.MembersInCompareSet -gt 0) { $resultObject.ResultValue = [Result]::Warning $resultObject.ResultText = (Get-ADFSTkLanguageText healthMissingSPsInADFSSPsMissingInADFS -f $compare.MembersInCompareSet) $resultObject.ResultData = $compare.CompareSet $resultObject.ReferenceFile = $spHashFile $resultObject.FixID = "AddMissingSPsInADFS" } else { $resultObject.ResultValue = [Result]::Pass $resultObject.ResultText = Get-ADFSTkLanguageText healthMissingSPsInADFSNoSPsMissingInADFS } } } else { $resultObject.CheckID = "SPHashMissing" $resultObject.CheckName = "SP Hash File existance" $resultObject.ResultValue = [Result]::Warning $resultObject.ResultText = (Get-ADFSTkLanguageText healthCheckRemovedSPsStillInSPHashAllSPsWillBeImported -f $spHashFile) $resultObject.ReferenceFile = $spHashFile } } catch { $resultObject.ResultValue = [Result]::Fail $resultObject.ResultText = $_ } $healthResults += $resultObject } } #endregion #region Check if the Import Metadata Scheduled Task is present if ($healthChecks.ScheduledTaskPresent) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthScheduledTaskPresentStartMessage -f "Import Metadata") if (!$Silent) { $numberOfHealthChecksDone++ Write-Progress -Activity "Processing Health Checks..." -Status "$numberOfHealthChecksDone/$numberOfHealthChecks" -CurrentOperation (Get-ADFSTkLanguageText healthScheduledTaskPresentStartMessage -f "Import Metadata") -PercentComplete ($numberOfHealthChecksDone / $numberOfHealthChecks * 100) } $resultObject = [PSCustomObject]@{ CheckID = "ScheduledTaskPresent" CheckName = "Import Metadata Scheduled Task present" ResultValue = [Result]::None ResultText = "" ResultData = @() ReferenceFile = "" FixID = "" } $schedTask = Get-ScheduledTask -TaskName (Get-ADFSTkLanguageText confImportMetadata) -TaskPath "\ADFSToolkit\" -ErrorAction SilentlyContinue if (![string]::IsNullOrEmpty($schedTask)) { $resultObject.ResultValue = [Result]::Pass $resultObject.ResultText = Get-ADFSTkLanguageText healthScheduledTaskPresentScheduledTaskPresent -f "Import Metadata" } else { $resultObject.ResultValue = [Result]::Warning $resultObject.ResultText = Get-ADFSTkLanguageText healthScheduledTaskPresentScheduledTaskNotPresent -f "Import Metadata" $resultObject.FixID = "RegisterScheduledTask" } $healthResults += $resultObject } #endregion #region Check if F-Ticks Scheduled Task is present if ($healthChecks.FticksScheduledTaskPresent) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText healthScheduledTaskPresentStartMessage -f "F-Ticks") if (!$Silent) { $numberOfHealthChecksDone++ Write-Progress -Activity "Processing Health Checks..." -Status "$numberOfHealthChecksDone/$numberOfHealthChecks" -CurrentOperation (Get-ADFSTkLanguageText healthScheduledTaskPresentStartMessage -f "F-Ticks") -PercentComplete ($numberOfHealthChecksDone / $numberOfHealthChecks * 100) } $resultObject = [PSCustomObject]@{ CheckID = "FticksScheduledTaskPresent" CheckName = "F-Ticks Scheduled Task present" ResultValue = [Result]::None ResultText = "" ResultData = @() ReferenceFile = "" FixID = "" } $schedTask = Get-ScheduledTask -TaskName (Get-ADFSTkLanguageText confProcessLoginEvents) -TaskPath "\ADFSToolkit\" -ErrorAction SilentlyContinue if (![string]::IsNullOrEmpty($schedTask)) { $resultObject.ResultValue = [Result]::Pass $resultObject.ResultText = Get-ADFSTkLanguageText healthScheduledTaskPresentScheduledTaskPresent -f "F-Ticks" } else { $resultObject.ResultValue = [Result]::Warning $resultObject.ResultText = Get-ADFSTkLanguageText healthScheduledTaskPresentScheduledTaskNotPresent -f "F-Ticks" $resultObject.FixID = "RegisterFticksScheduledTask" } $healthResults += $resultObject } #endregion #region Show result if (!$Silent) { Write-Progress -Activity "Processing Health Checks..." -PercentComplete 100 -Completed $healthResults | Select CheckName, ResultValue, ResultText, ReferenceFile | sort ResultValue, CheckName, ReferenceFile | ft -AutoSize -Wrap } #endregion #region Correct fixable errors $FixedAnything = $false #region Fix incorrect Institution Config Version(s) #Only if run manually if (!$Silent) { $resultObject = $healthResults | ? FixID -eq "FixADFSTkConfigVersion" if (![String]::IsNullOrEmpty($resultObject)) { if ((Get-ADFSTkAnswer (Get-ADFSTkLanguageText healthUpdateADFSTkConfigVersion))) { Update-ADFSTk $resultObject.ResultText = (Get-ADFSTkLanguageText healthFixed) + $resultObject.ResultText $resultObject.ResultValue = [Result]::Pass $FixedAnything = $true } } } #endregion #region Fix incorrect Institution Config Version(s) #Only if run manually if (!$Silent) { $resultObjects = $healthResults | ? FixID -eq "FixInstitutionConfigVersion" foreach ($resultObject in $resultObjects) { if (![String]::IsNullOrEmpty($resultObject)) { if ((Get-ADFSTkAnswer (Get-ADFSTkLanguageText healthUpdateInstitutionConfigVersion))) { Update-ADFSTk $resultObject.ResultText = (Get-ADFSTkLanguageText healthFixed) + $resultObject.ResultText $resultObject.ResultValue = [Result]::Pass $FixedAnything = $true } } } } #endregion #region MFAAccesControlPolicy #createACP $MFAAccesControlPolicy = $healthResults | ? FixID -eq "CreateACP" if (![String]::IsNullOrEmpty($MFAAccesControlPolicy)) { if ($Silent -or (Get-ADFSTkAnswer (Get-ADFSTkLanguageText healthMFAAccesControlPolicyRegisterACP))) { New-ADFSTKAccessControlPolicy Write-ADFSTkLog "Access Control Policy 'ADFSTk:Permit everyone and force MFA' created." $MFAAccesControlPolicy.ResultValue = [Result]::Pass $MFAAccesControlPolicy.ResultText = (Get-ADFSTkLanguageText healthFixed) + $resultObject.ResultText $FixedAnything = $true } } #endregion #region RemovedSPsStillInSPHash #Do we have SP's in SP Hash file that are missing in the Metadata? They should be removed... $removedSPsStillInSPHash = $healthResults | ? FixID -eq "RemoveSPsFromSPHashFile" if (![String]::IsNullOrEmpty($removedSPsStillInSPHash)) { foreach ($resultObject in $removedSPsStillInSPHash) { if ($Silent -or (Get-ADFSTkAnswer (Get-ADFSTkLanguageText healthRemoveSPsFromSPHashFileRemoveSPsNotInMetadata -f $resultObject.ReferenceFile ))) { Remove-ADFSTkEntityHash -SPHashFile $resultObject.ReferenceFile -EntityIDs $resultObject.ResultData $resultObject.ResultText = (Get-ADFSTkLanguageText healthFixed) + $resultObject.ResultText $resultObject.ResultValue = [Result]::Pass $FixedAnything = $true } else { #No need to fail, carry on! } } } #Do we have corrupt SP Hash files? $removedSPsStillInSPHash = $healthResults | ? FixID -eq 'DeleteSPHashFile' if (![String]::IsNullOrEmpty($removedSPsStillInSPHash)) { foreach ($resultObject in $removedSPsStillInSPHash) { if ($Silent -or (Get-ADFSTkAnswer (Get-ADFSTkLanguageText healthDeleteSPHashFileDeleteCorruptSPHashFile -f $resultObject.ReferenceFile ))) { Remove-Item -Path $resultObject.ReferenceFile $resultObject.ResultText = (Get-ADFSTkLanguageText healthFixed) + $resultObject.ResultText $resultObject.ResultValue = [Result]::Pass $FixedAnything = $true } else { #The fail result will stand! } } } #endregion #region RemovedSPsStillInSPHash #Do we have SP's in SP Hash file that are missing in ADFS? They should be removed from SP Hash File... $addMissingSPs = $healthResults | ? FixID -eq "AddMissingSPsInADFS" if (![String]::IsNullOrEmpty($addMissingSPs)) { foreach ($resultObject in $addMissingSPs) { if ($Silent -or (Get-ADFSTkAnswer (Get-ADFSTkLanguageText healthAddMissingSPsInADFSRemoveMissingSPs -f $resultObject.ReferenceFile ))) { Remove-ADFSTkEntityHash -SPHashFile $resultObject.ReferenceFile -EntityIDs $resultObject.ResultData $resultObject.ResultText = (Get-ADFSTkLanguageText healthFixed) + $resultObject.ResultText $resultObject.ResultValue = [Result]::Pass $FixedAnything = $true } else { #No need to fail, carry on! } } } #endregion #region Add Import Metadata Scheduled Task #Only if run manually if (!$Silent) { $resultObject = $healthResults | ? FixID -eq "RegisterScheduledTask" if (![String]::IsNullOrEmpty($resultObject)) { if ((Get-ADFSTkAnswer (Get-ADFSTkLanguageText healthRegisterScheduledTaskCreateSchedTask -f "Import Metadata"))) { Register-ADFSTkScheduledTask $resultObject.ResultText = (Get-ADFSTkLanguageText healthFixed) + $resultObject.ResultText $resultObject.ResultValue = [Result]::Pass $FixedAnything = $true } } } #endregion #region Add F-Ticks Scheduled Task #Only if run manually if (!$Silent) { $resultObject = $healthResults | ? FixID -eq "RegisterFticksScheduledTask" if (![String]::IsNullOrEmpty($resultObject)) { if ((Get-ADFSTkAnswer (Get-ADFSTkLanguageText healthRegisterScheduledTaskCreateSchedTask -f "F-Ticks"))) { Register-ADFSTkFTicksScheduledTask $resultObject.ResultText = (Get-ADFSTkLanguageText healthFixed) + $resultObject.ResultText $resultObject.ResultValue = [Result]::Pass $FixedAnything = $true } } } #endregion if ($FixedAnything -and -not $Silent) { $healthResults | Select CheckName, ResultValue, ResultText, ReferenceFile | sort ResultValue, CheckName, ReferenceFile | ft -AutoSize -Wrap } if ($Silent) { return !($healthResults.ResultValue.Contains([Result]::Fail)) } else { if ($healthResults.ResultValue.Contains([Result]::Fail)) { Write-ADFSTkLog -Message (Get-ADFSTkLanguageText healthFailed) -EntryType Error } elseif ($healthResults.ResultValue.Contains([Result]::Warning)) { Write-ADFSTkLog -Message (Get-ADFSTkLanguageText healthPassedWithWarnings) -EntryType Warning } else { Write-ADFSTkLog -Message (Get-ADFSTkLanguageText healthPassed) -EntryType Information -ForegroundColor Green } } <# .SYNOPSIS Use this cmdlet to check the health of your installation of ADFS Toolkit .DESCRIPTION This cmdlet can check different things on the installation of ADFS Toolkit. Every time Sync-ADFSTkAggregates are run a default helath check is run. If an error is found that the health check can fix you will be asked if you want to do so. If the cmdlet is run with -Silent it will automatically fix errors. .EXAMPLE PS C:\> Get-ADFSTkHealth Does a default check which includes checking that all files in the module are signed and has not been altered, that the institution configuration files has the correct version for the installed version of ADFS Toolkit and that the MFA Access Control Policy exists (if the Refeds MFA adapter is installed). .EXAMPLE PS C:\> Get-ADFSTkHealth -HealthCheckMode CriticalOnly This excludes the check of signatures. Run this if you have changed any files in the module. .EXAMPLE PS C:\> Get-ADFSTkHealth -HealthCheckMode Full Run this after upgrade of the ADFS Toolkit. It does a full scan of the installation including tests of missing SP's. #> } # SIG # Begin signature block # MIItNgYJKoZIhvcNAQcCoIItJzCCLSMCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDY5SZ2ZuWKWUAw # LsIsCwTo8MrqfgUM9FLbsw1L+Vs906CCJj8wggWNMIIEdaADAgECAhAOmxiO+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 # twGpn1eqXijiuZQwggXfMIIEx6ADAgECAhBOQOQ3VO3mjAAAAABR05R/MA0GCSqG # SIb3DQEBCwUAMIG+MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNRW50cnVzdCwgSW5j # LjEoMCYGA1UECxMfU2VlIHd3dy5lbnRydXN0Lm5ldC9sZWdhbC10ZXJtczE5MDcG # A1UECxMwKGMpIDIwMDkgRW50cnVzdCwgSW5jLiAtIGZvciBhdXRob3JpemVkIHVz # ZSBvbmx5MTIwMAYDVQQDEylFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRo # b3JpdHkgLSBHMjAeFw0yMTA1MDcxNTQzNDVaFw0zMDExMDcxNjEzNDVaMGkxCzAJ # BgNVBAYTAlVTMRYwFAYDVQQKDA1FbnRydXN0LCBJbmMuMUIwQAYDVQQDDDlFbnRy # dXN0IENvZGUgU2lnbmluZyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g # Q1NCUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCngY/3FEW2YkPy # 2K7TJV5IT1G/xX2fUBw10dZ+YSqUGW0nRqSmGl33VFFqgCLGqGZ1TVSDyV5oG6v2 # W2Swra0gvVTvRmttAudFrnX2joq5Mi6LuHccUk15iF+lOhjJUCyXJy2/2gB9Y3/v # MuxGh2Pbmp/DWiE2e/mb1cqgbnIs/OHxnnBNCFYVb5Cr+0i6udfBgniFZS5/tcnA # 4hS3NxFBBuKK4Kj25X62eAUBw2DtTwdBLgoTSeOQm3/dvfqsv2RR0VybtPVc51z/ # O5uloBrXfQmywrf/bhy8yH3m6Sv8crMU6UpVEoScRCV1HfYq8E+lID1oJethl3wP # 5bY9867DwRG8G47M4EcwXkIAhnHjWKwGymUfe5SmS1dnDH5erXhnW1XjXuvH2OxM # bobL89z4n4eqclgSD32m+PhCOTs8LOQyTUmM4OEAwjignPqEPkHcblauxhpb9Gdo # BQHNG7+uh7ydU/Yu6LZr5JnexU+HWKjSZR7IH9Vybu5ZHFc7CXKd18q3kMbNe0WS # kUIDTH0/yvKquMIOhvMQn0YupGaGaFpoGHApOBGAYGuKQ6NzbOOzazf/5p1nAZKG # 3y9I0ftQYNVc/iHTAUJj/u9wtBfAj6ju08FLXxLq/f0uDodEYOOp9MIYo+P9zgyE # Ig3zp3jak/PbOM+5LzPG/wc8Xr5F0wIDAQABo4IBKzCCAScwDgYDVR0PAQH/BAQD # AgGGMBIGA1UdEwEB/wQIMAYBAf8CAQEwHQYDVR0lBBYwFAYIKwYBBQUHAwMGCCsG # AQUFBwMIMDsGA1UdIAQ0MDIwMAYEVR0gADAoMCYGCCsGAQUFBwIBFhpodHRwOi8v # d3d3LmVudHJ1c3QubmV0L3JwYTAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGG # F2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDAGA1UdHwQpMCcwJaAjoCGGH2h0dHA6 # Ly9jcmwuZW50cnVzdC5uZXQvZzJjYS5jcmwwHQYDVR0OBBYEFIK61j2Xzp/PceiS # N6/9s7VpNVfPMB8GA1UdIwQYMBaAFGpyJnrQHu995ztpUdRsjZ+QEmarMA0GCSqG # SIb3DQEBCwUAA4IBAQAfXkEEtoNwJFMsVXMdZTrA7LR7BJheWTgTCaRZlEJeUL9P # bG4lIJCTWEAN9Rm0Yu4kXsIBWBUCHRAJb6jU+5J+Nzg+LxR9jx1DNmSzZhNfFMyl # cfdbIUvGl77clfxwfREc0yHd0CQ5KcX+Chqlz3t57jpv3ty/6RHdFoMI0yyNf02o # FHkvBWFSOOtg8xRofcuyiq3AlFzkJg4sit1Gw87kVlHFVuOFuE2bRXKLB/GK+0m4 # X9HyloFdaVIk8Qgj0tYjD+uL136LwZNr+vFie1jpUJuXbheIDeHGQ5jXgWG2hZ1H # 7LGerj8gO0Od2KIc4NR8CMKvdgb4YmZ6tvf6yK81MIIGgzCCBGugAwIBAgIQNa+3 # e500H2r8j4RGqzE1KzANBgkqhkiG9w0BAQ0FADBpMQswCQYDVQQGEwJVUzEWMBQG # A1UECgwNRW50cnVzdCwgSW5jLjFCMEAGA1UEAww5RW50cnVzdCBDb2RlIFNpZ25p # bmcgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIENTQlIxMB4XDTIxMDUw # NzE5MTk1MloXDTQwMTIyOTIzNTkwMFowYzELMAkGA1UEBhMCVVMxFjAUBgNVBAoT # DUVudHJ1c3QsIEluYy4xPDA6BgNVBAMTM0VudHJ1c3QgRXh0ZW5kZWQgVmFsaWRh # dGlvbiBDb2RlIFNpZ25pbmcgQ0EgLSBFVkNTMjCCAiIwDQYJKoZIhvcNAQEBBQAD # ggIPADCCAgoCggIBAL69pznJpX3sXWXx9Cuph9DnrRrFGjsYzuGhUY1y+s5YH1y4 # JEIPRtUxl9BKTeObMMm6l6ic/kU2zyeA53u4bsEkt9+ndNyF8qMkWEXMlJQ7AuvE # jXxG9VxmguOkwdMfrG4MUyMO1Dr62kLxg1RfNTJW8rV4m1cASB6pYWEnDnMDQ7bW # cJL71IWaMMaz5ppeS+8dKthmqxZG/wvYD6aJSgJRV0E8QThOl8dRMm1njmahXk2f # NSKv1Wq3f0BfaDXMafrxBfDqhabqMoXLwcHKg2lFSQbcCWy6SWUZjPm3NyeMZJ41 # 4+Xs5wegnahyvG+FOiymFk49nM8I5oL1RH0owL2JrWwv3C94eRHXHHBL3Z0ITF4u # +o29p91j9n/wUjGEbjrY2VyFRJ5jBmnQhlh4iZuHu1gcpChsxv5pCpwerBFgal7J # aWUu7UMtafF4tzstNfKqT+If4wFvkEaq1agNBFegtKzjbb2dGyiAJ0bH2qpnlfHR # h3vHyCXphAyPiTbSvjPhhcAz1aA8GYuvOPLlk4C/xsOre5PEPZ257kV2wNRobzBe # PLQ2+ddFQuASBoDbpSH85wV6KI20jmB798i1SkesFGaXoFppcjFXa1OEzWG6cwcV # cDt7AfynP4wtPYeM+wjX5S8Xg36Cq08J8inhflV3ZZQFHVnUCt2TfuMUXeK7AgMB # AAGjggErMIIBJzASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBTOiU+CUaoV # ooRiyjEjYdJh+/j+eDAfBgNVHSMEGDAWgBSCutY9l86fz3Hokjev/bO1aTVXzzAz # BggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3Qu # bmV0MDEGA1UdHwQqMCgwJqAkoCKGIGh0dHA6Ly9jcmwuZW50cnVzdC5uZXQvY3Ni # cjEuY3JsMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzBEBgNV # HSAEPTA7MDAGBFUdIAAwKDAmBggrBgEFBQcCARYaaHR0cDovL3d3dy5lbnRydXN0 # Lm5ldC9ycGEwBwYFZ4EMAQMwDQYJKoZIhvcNAQENBQADggIBAD4AVLgq849mr2EW # xFiTZPRBi2RVjRs1M6GbkdirRsqrX7y+fnDk0tcHqJYH14bRVwoI0NB4Tfgq37IE # 85rh13zwwQB6wUCh34qMt8u0HQFh8piapt24gwXKqSwW3JwtDv6nl+RQqZeVwUsq # jFHjxALga3w1TVO8S5QTi1MYFl6mCqe4NMFssess5DF9DCzGfOGkVugtdtWyE3Xq # gwCuAHfGb6k97mMUgVAW/FtPEhkOWw+N6kvOBkyJS64gzI5HpnXWZe4vMOhdNI8f # gk1cQqbyFExQIJwJonQkXDnYiTKFPK+M5Wqe5gQ6pRP/qh3NR0suAgW0ao/rhU+B # 7wrbfZ8pj6XCP1I4UkGVO7w+W1QwQiMJY95QjYk1RfqruA+Poq17ehGT8Y8ohHto # eUdq6GQpTR/0HS9tHsiUhjzTWpl6a3yrNfcrOUtPuT8Wku8pjI2rrAEazHFEOctA # PiASzghw40f+3IDXCADRC2rqIbV5ZhfpaqpW3c0VeLEDwBStPkcYde0KU0syk83/ # gLGQ1hPl5EF4Iu1BguUO37DOlSFF5osB0xn39CtVrNlWc2MQ4LigbctUlpigmSFR # BqqmDDorY8t52kO50hLM3o9VeukJ8+Ka0yXBezaS2uDlUmfN4+ZUCqWd1HOj0y9d # BmSFA3d/YNjCvHTJlZFot7d+YRl1MIIGrjCCBJagAwIBAgIQBzY3tyRUfNhHrP0o # ZipeWzANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhE # aWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjIwMzIzMDAwMDAwWhcNMzcwMzIy # MjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4x # OzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGlt # ZVN0YW1waW5nIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxoY1 # BkmzwT1ySVFVxyUDxPKRN6mXUaHW0oPRnkyibaCwzIP5WvYRoUQVQl+kiPNo+n3z # nIkLf50fng8zH1ATCyZzlm34V6gCff1DtITaEfFzsbPuK4CEiiIY3+vaPcQXf6sZ # Kz5C3GeO6lE98NZW1OcoLevTsbV15x8GZY2UKdPZ7Gnf2ZCHRgB720RBidx8ald6 # 8Dd5n12sy+iEZLRS8nZH92GDGd1ftFQLIWhuNyG7QKxfst5Kfc71ORJn7w6lY2zk # psUdzTYNXNXmG6jBZHRAp8ByxbpOH7G1WE15/tePc5OsLDnipUjW8LAxE6lXKZYn # LvWHpo9OdhVVJnCYJn+gGkcgQ+NDY4B7dW4nJZCYOjgRs/b2nuY7W+yB3iIU2YIq # x5K/oN7jPqJz+ucfWmyU8lKVEStYdEAoq3NDzt9KoRxrOMUp88qqlnNCaJ+2RrOd # OqPVA+C/8KI8ykLcGEh/FDTP0kyr75s9/g64ZCr6dSgkQe1CvwWcZklSUPRR8zZJ # TYsg0ixXNXkrqPNFYLwjjVj33GHek/45wPmyMKVM1+mYSlg+0wOI/rOP015LdhJR # k8mMDDtbiiKowSYI+RQQEgN9XyO7ZONj4KbhPvbCdLI/Hgl27KtdRnXiYKNYCQEo # AA6EVO7O6V3IXjASvUaetdN2udIOa5kM0jO0zbECAwEAAaOCAV0wggFZMBIGA1Ud # EwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFLoW2W1NhS9zKXaaL3WMaiCPnshvMB8G # A1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjAT # BgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGG # GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2Nh # Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYD # VR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0 # VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9 # bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQB9WY7Ak7ZvmKlEIgF+ZtbYIULhsBguEE0T # zzBTzr8Y+8dQXeJLKftwig2qKWn8acHPHQfpPmDI2AvlXFvXbYf6hCAlNDFnzbYS # lm/EUExiHQwIgqgWvalWzxVzjQEiJc6VaT9Hd/tydBTX/6tPiix6q4XNQ1/tYLaq # T5Fmniye4Iqs5f2MvGQmh2ySvZ180HAKfO+ovHVPulr3qRCyXen/KFSJ8NWKcXZl # 2szwcqMj+sAngkSumScbqyQeJsG33irr9p6xeZmBo1aGqwpFyd/EjaDnmPv7pp1y # r8THwcFqcdnGE4AJxLafzYeHJLtPo0m5d2aR8XKc6UsCUqc3fpNTrDsdCEkPlM05 # et3/JWOZJyw9P2un8WbDQc1PtkCbISFA0LcTJM3cHXg65J6t5TRxktcma+Q4c6um # AU+9Pzt4rUyt+8SVe+0KXzM5h0F4ejjpnOHdI/0dKNPH+ejxmF/7K9h+8kaddSwe # Jywm228Vex4Ziza4k9Tm8heZWcpw8De/mADfIBZPJ/tgZxahZrrdVcA6KYawmKAr # 7ZVBtzrVFZgxtGIJDwq9gdkT/r+k0fNX2bwE+oLeMt8EifAAzV3C+dAjfwAL5HYC # JtnwZXZCpimHCUcr5n8apIUP/JiW9lVUKx+A+sDyDivl1vupL0QVSucTDh3bNzga # oSv27dZ8/DCCBsIwggSqoAMCAQICEAVEr/OUnQg5pr/bP1/lYRYwDQYJKoZIhvcN # AQELBQAwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTsw # OQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVT # dGFtcGluZyBDQTAeFw0yMzA3MTQwMDAwMDBaFw0zNDEwMTMyMzU5NTlaMEgxCzAJ # BgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEgMB4GA1UEAxMXRGln # aUNlcnQgVGltZXN0YW1wIDIwMjMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK # AoICAQCjU0WHHYOOW6w+VLMj4M+f1+XS512hDgncL0ijl3o7Kpxn3GIVWMGpkxGn # zaqyat0QKYoeYmNp01icNXG/OpfrlFCPHCDqx5o7L5Zm42nnaf5bw9YrIBzBl5S0 # pVCB8s/LB6YwaMqDQtr8fwkklKSCGtpqutg7yl3eGRiF+0XqDWFsnf5xXsQGmjzw # xS55DxtmUuPI1j5f2kPThPXQx/ZILV5FdZZ1/t0QoRuDwbjmUpW1R9d4KTlr4HhZ # l+NEK0rVlc7vCBfqgmRN/yPjyobutKQhZHDr1eWg2mOzLukF7qr2JPUdvJscsrdf # 3/Dudn0xmWVHVZ1KJC+sK5e+n+T9e3M+Mu5SNPvUu+vUoCw0m+PebmQZBzcBkQ8c # tVHNqkxmg4hoYru8QRt4GW3k2Q/gWEH72LEs4VGvtK0VBhTqYggT02kefGRNnQ/f # ztFejKqrUBXJs8q818Q7aESjpTtC/XN97t0K/3k0EH6mXApYTAA+hWl1x4Nk1nXN # jxJ2VqUk+tfEayG66B80mC866msBsPf7Kobse1I4qZgJoXGybHGvPrhvltXhEBP+ # YUcKjP7wtsfVx95sJPC/QoLKoHE9nJKTBLRpcCcNT7e1NtHJXwikcKPsCvERLmTg # yyIryvEoEyFJUX4GZtM7vvrrkTjYUQfKlLfiUKHzOtOKg8tAewIDAQABo4IBizCC # AYcwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYI # KwYBBQUHAwgwIAYDVR0gBBkwFzAIBgZngQwBBAIwCwYJYIZIAYb9bAcBMB8GA1Ud # IwQYMBaAFLoW2W1NhS9zKXaaL3WMaiCPnshvMB0GA1UdDgQWBBSltu8T5+/N0GSh # 1VapZTGj3tXjSTBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsMy5kaWdpY2Vy # dC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1waW5n # Q0EuY3JsMIGQBggrBgEFBQcBAQSBgzCBgDAkBggrBgEFBQcwAYYYaHR0cDovL29j # c3AuZGlnaWNlcnQuY29tMFgGCCsGAQUFBzAChkxodHRwOi8vY2FjZXJ0cy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRSU0E0MDk2U0hBMjU2VGltZVN0YW1w # aW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUAA4ICAQCBGtbeoKm1mBe8cI1PijxonNgl # /8ss5M3qXSKS7IwiAqm4z4Co2efjxe0mgopxLxjdTrbebNfhYJwr7e09SI64a7p8 # Xb3CYTdoSXej65CqEtcnhfOOHpLawkA4n13IoC4leCWdKgV6hCmYtld5j9smViuw # 86e9NwzYmHZPVrlSwradOKmB521BXIxp0bkrxMZ7z5z6eOKTGnaiaXXTUOREEr4g # DZ6pRND45Ul3CFohxbTPmJUaVLq5vMFpGbrPFvKDNzRusEEm3d5al08zjdSNd311 # RaGlWCZqA0Xe2VC1UIyvVr1MxeFGxSjTredDAHDezJieGYkD6tSRN+9NUvPJYCHE # Vkft2hFLjDLDiOZY4rbbPvlfsELWj+MXkdGqwFXjhr+sJyxB0JozSqg21Llyln6X # eThIX8rC3D0y33XWNmdaifj2p8flTzU8AL2+nCpseQHc2kTmOt44OwdeOVj0fHMx # VaCAEcsUDH6uvP6k63llqmjWIso765qCNVcoFstp8jKastLYOrixRoZruhf9xHds # FWyuq69zOuhJRrfVf8y2OMDY7Bz1tqG4QyzfTkx9HmhwwHcK1ALgXGC7KP845VJa # 1qwXIiNO9OzTF/tQa/8Hdx9xl0RBybhG02wyfFgvZ0dl5Rtztpn5aywGRu9BHvDw # X+Db2a2QgESvgBBBijCCBsgwggSwoAMCAQICEDVP8/CYmCMy0wHfstCzixQwDQYJ # KoZIhvcNAQELBQAwYzELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIElu # Yy4xPDA6BgNVBAMTM0VudHJ1c3QgRXh0ZW5kZWQgVmFsaWRhdGlvbiBDb2RlIFNp # Z25pbmcgQ0EgLSBFVkNTMjAeFw0yNDAzMjIxNDAyMzdaFw0yNTAzMjkxNDAyMzZa # MIGjMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEPMA0GA1UEBxMGT3R0 # YXdhMRMwEQYLKwYBBAGCNzwCAQMTAkNBMRQwEgYDVQQKEwtDQU5BUklFIElOQzEd # MBsGA1UEDxMUUHJpdmF0ZSBPcmdhbml6YXRpb24xETAPBgNVBAUTCDI5MDIwOC03 # MRQwEgYDVQQDEwtDQU5BUklFIElOQzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC # AgoCggIBAIbar6/W1oMcwPbrTZBOR7XAFQ43Qt/AyPGUT42dOQnfcqWqPlZKN2mr # euYTFdaAknd2pJZC/3b16Yu2O0ElPuqUBwF0CrKapWGjQ5eUvC65Dn5c0hXmPzIV # 8snCTqREm8nGl5BZmlvqMc7MxaDrMh88kHVxNpHevYP3729AD7AoBKmiwglAOtZn # XPNVllH5qx4ZHYKt9dVCbEz0nGjzs1LobknyvRV8onsmGaRDhIYvYb27sttPmmKS # C6yqnwNlZV00d3KbUt1jOo9PGlS//4ZIw60rm+atIHWvwCVNXLj8WNYOs29xb3Ie # M1a0JO/QIyQ6n5TZRxns8ateQkuEfsNU9Z5/K9GcyXuiZinGsBjVxvwSQoj2YhXt # nlz/ZRzKabsH1ZtQ3ygedVpt4d1TGJbU3uJI2PrynXqRYgxTYoJ0F38EBvbgY33T # iC/fzemTNtqkyYJHAzfE7ksUdYQq6GMSDEy5nZA+vXvTB59aSk63S+mHNTDBRPYB # Dwg5nn10NUh+0TGUu+MKwoDCq4Qy8w8VdooxS10RHzYflMp4/b9FxhXfWd9/qtFU # QaZtjEvgV53s4GpVtsa52ij5L9VSu+ta6ZSZAarxiH/5/ni4bn1n+Q/n7bUfTHk8 # y8GT3SoXzKwOZXsSeUVq4my7beGwn13O2efES/cdx1EzxmHZl18NAgMBAAGjggE1 # MIIBMTAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQSgPtIskRFyN7+qGdwcp+8w1kG # DDAfBgNVHSMEGDAWgBTOiU+CUaoVooRiyjEjYdJh+/j+eDBnBggrBgEFBQcBAQRb # MFkwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLmVudHJ1c3QubmV0MDIGCCsGAQUF # BzAChiZodHRwOi8vYWlhLmVudHJ1c3QubmV0L2V2Y3MyLWNoYWluLnA3YzAxBgNV # HR8EKjAoMCagJKAihiBodHRwOi8vY3JsLmVudHJ1c3QubmV0L2V2Y3MyLmNybDAO # BgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwIAYDVR0gBBkwFzAH # BgVngQwBAzAMBgpghkgBhvpsCgECMA0GCSqGSIb3DQEBCwUAA4ICAQBd5heW6V8s # 8owim1XLvy2aMSMHXB6gjP7suiiyx4WGKZAZn1tY0TWexrjZE66GQI0IxdOrMQQf # IXfaTLPy3g6qBNf5IazlcanmgKT45dpGVB0ixKmoOnxBCZKtESJvmmBuXe5/QyH1 # /EECx1y8SA1mO6j9uUKhY+/ZG0jHOYQXTuT/X1e2wfEwmJCGKC/OGiLi2iLjRWWH # EwEnYXw13S0cBqcXhuVpjL+Ce9W/N833TFQ8AA3rjN2ZWuti9RMoO5rabeSXbjGX # rDWHi5y6MbZL3+QYjHPKSTySjIYjENICf6rFcvCdHnrmNbLP3fWd5plzAObhiJSw # gXyiBoMOcP+6ZtNMDR/8U3TwUmWbwPH5ulfgVvmyPhchq1cRksxRj6uz48dHSksm # Dx+pZHMSyDj5yITRTwZBa9Q41+giSxPGRxUB/7HyX5slQGZdW6Y4SQHQ06SGvCkr # M3dJQ4aGYbw3NBtcwUmhA79pYOu3YhrJmpUXUx5mVQDqnTUrpn6P0RhW9tWopBYS # lXRJy2qF0UvguDm0jqhSMmc0wnLl725zGLbC2/lG1NLIvGtDRsGAq5zMbAVpDRUM # m4O04R+WQeCssBMWFT1HR7PmJyfvUo4cQCkpeZRRS2DL5/AlgBINqTiv+lP2nXKw # mkpg6lEXvNAaRgMSGgtnMNkDbjpU8ldKsTGCBk0wggZJAgEBMHcwYzELMAkGA1UE # BhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xPDA6BgNVBAMTM0VudHJ1c3Qg # RXh0ZW5kZWQgVmFsaWRhdGlvbiBDb2RlIFNpZ25pbmcgQ0EgLSBFVkNTMgIQNU/z # 8JiYIzLTAd+y0LOLFDANBglghkgBZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQow # CKACgAChAoAAMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcC # AQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBUyCBuTL6lBR9Ys9yc # zN/u7h6/32IJKRV7qanM8jE7TzANBgkqhkiG9w0BAQEFAASCAgA/VG0Lwmb86DNW # VnXTjHb3O22s/BT00wr6Q64ihzsGuW6WA6bbrOJhe4/xL6v27u3fkLJr6mmCLqRy # H+QD2SKHVxyHqK3c72tRnYTM3/Be4A8yHgak2Z3PG6cTsj1/L9Dy46vgKp4vKR6u # vvDfS1/sH3WKrtlml6poaaNPEi1qCVjkaRVp7G0hpl1Q/seQQ62epPeF/3qnUaMa # jH64d5hsatU+aeOL2QNSE5GXsNDEytYMznyYrkLW6J9ew+FrdAgAGY7ZvZ4QdoOd # Sd37DzqzRnOXlYMqfVHNfaipGeeMLQR4mHnUv8e0D+A3k6SU0LQF1YvM0Bf8QySk # CkZ8Ea0niVldenpYxpLVKm20hnboxJBG6vHb3HGCbJJRqbdP27rIUPIGMNCglhy/ # X7pF88qzqWRXhTHyGhOqajConDbZ/Y4uZg7Ngi0uaxXUP0aXpC6HPe38vpH2KZt3 # kg7FEFgnC+Leguj+buaBjMZHGaTHqFtStFU4uuIYYXq9dDg0BM8EJ9baKL98dFTh # q0I/by80msBXBJNX0UA+BK66vHKr0g833oyzhXMCBvmVSBI8JRZsDVKLAmWkIGiA # orMNbjeM9CuS0DKSlBz4gYvYhjNddWTqwl1V7/KFD4B528aT1rR1A5v8SB5XKT9I # AUpUQvpi4PP+Toi2GUzkGmlNqxoWMqGCAyAwggMcBgkqhkiG9w0BCQYxggMNMIID # CQIBATB3MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7 # MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1l # U3RhbXBpbmcgQ0ECEAVEr/OUnQg5pr/bP1/lYRYwDQYJYIZIAWUDBAIBBQCgaTAY # BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0yNDA4MjEx # NTExNTZaMC8GCSqGSIb3DQEJBDEiBCDBPoH58NJoFAXpdZR+GrelmOR731xPmtkF # rD7tkSiIOjANBgkqhkiG9w0BAQEFAASCAgBbcUYyrDWoIgwVxfi55/GdcLb2YBdh # ds4p3Bu+ImSxWJI8dhdK5fDUwhSUrnlokpAbqrc3Tyclp5/rWv6xhH+c7/nWGf7q # pGmfSjXW9D0zIPI6Ci1XIdAB1gT71DWIrH1poWoXxW7sQf3nxG1muxDWmgt4A9ua # c1Gnxz8zNNwYX1fVmxip7IpQM13mUlp0MlY0lFomjNs1IRZcWvlj7JCvZt8JyuVy # CIhac/XpD5wD8It1ftcqVBxcTZ9Q2Y29EX031Jt4A/7l2qVEHOjHbGN1Iy7cPoTb # z45gu8B46M/edUR6CUKm5Uc6iuugX97YIzXVuGEoqCJihggudRYiHr4IBZwkKz7i # tVZYutAjc5UsYEM9QNB74Sp3Fw9DnI+YFpUJarcaoawecJ4HBlQiKi80rjhCxjdb # g3aYFUQKAPg8ePtVkn9k8AIjZdykiVqQhA1AA1M2H8kzHjgZOBjlA+snvIDxWtHR # vHKRvYnOcCeSp/SJ0kxu9TrOUPeFSdWtR0MMJdZQ8+17v0EXifa8ZF9Jm5oPC3tA # x3Ilhebr07XLYg2SMfNVTK/zR4QxEtoGUadbAUlK8SlYg1294Wt3KF2cE46GOCo2 # 4mcfuUCEQuYrTc14KhKfiEEe/T3SNgcqf+xUkjxI+8rKAYz2lAUoKWlvq07/Cwpj # +WpCCxsH3jvL/g== # SIG # End signature block |