public/Invoke-VPASHealthCheck.ps1
<#
.Synopsis RUN A SYSTEM HEALTHCHECK CREATED BY: Vadim Melamed, EMAIL: vpasmodule@gmail.com .DESCRIPTION USE THIS FUNCTION TO RUN A HEALTHCHECK THAT RUNS VARIOUS CHECKS IN A CYBERARK ENVIRONMENT .LINK https://vpasmodule.com/commands/Invoke-VPASHealthCheck .NOTES SelfHosted: TRUE PrivCloudStandard: TRUE SharedServices: TRUE .PARAMETER token HashTable of data containing various pieces of login information (PVWA, LoginToken, HeaderType, etc). If -token is not passed, function will use last known hashtable generated by New-VPASToken .PARAMETER ExportToCSV Output results to a CSV file found in AppData\Local\VPASModuleOutputs directory .PARAMETER CSVDirectory Output directory where the exported CSV file will be saved to Default value: C:\Users\{CurrentUser}\AppData\Local\VPASModuleOutputs\ExportedCSVs .PARAMETER InputParameters HashTable of values containing the parameters required to make the API call .EXAMPLE $HealthCheck = Invoke-VPASHealthCheck .EXAMPLE $InputParameters = @{ ExportToCSV = $true|$false CSVDirectory = "C:\Temp" } $HealthCheck = Invoke-VPASHealthCheck -InputParameters $InputParameters .OUTPUTS If successful: { ... "UnusedAssetsCheck": [ ... { "TargetName": "UnusedAppID", "Category": "ApplicationID", "Recommendation": "Recommendation: delete unused application IDs (UnusedAppID) to help reduce clutter", "Check": "UnusedAssetsCheck" }, { "TargetName": "UnusedSafe1", "Category": "Safe", "Recommendation": "Recommendation: delete unused Safes (UnusedSafe1) to help reduce clutter", "Check": "UnusedAssetsCheck" }, ... } --- $false if failed #> function Invoke-VPASHealthCheck{ [OutputType('System.Object',[bool])] [CmdletBinding(DefaultParameterSetName='Set1')] Param( [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)] [Switch]$ExportToCSV, [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)] [String]$CSVDirectory, [Parameter(Mandatory=$true,ParameterSetName='InputParameters',ValueFromPipelineByPropertyName=$true,HelpMessage="Hashtable of parameters required to make API call, refer to get-help -examples for valid inputs")] [hashtable]$InputParameters, [Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,Position=0)] [hashtable]$token ) Begin{ $tokenval,$sessionval,$PVWA,$Header,$ISPSS,$IdentityURL,$EnableTextRecorder,$AuditTimeStamp,$NoSSL,$VaultVersion,$HideWarnings,$AuthenticatedAs,$SubDomain,$EnableTroubleshooting = Get-VPASSession -token $token $CommandName = $MyInvocation.MyCommand.Name $log = Write-VPASTextRecorder -inputval $CommandName -token $token -LogType COMMAND } Process{ try{ if($PSCmdlet.ParameterSetName -eq "InputParameters"){ $KeyHash = @{ set1 = @{ AcceptableKeys = @("ExportToCSV","CSVDirectory") MandatoryKeys = @() } } $CheckSet = Test-VPASHashtableKeysHelper -InputHash $InputParameters -KeyHash $KeyHash if(!$CheckSet){ $log = Write-VPASTextRecorder -inputval "FAILED TO FIND TARGET PARAMETER SET" -token $token -LogType MISC Write-Verbose "FAILED TO FIND TARGET PARAMETER SET" Write-VPASOutput -str "FAILED TO FIND TARGET PARAMETER SET...VIEW EXAMPLES BELOW:" -type E $examples = Write-VPASExampleHelper -CommandName $CommandName return $false } else{ foreach($key in $InputParameters.Keys){ Set-Variable -Name $key -Value $InputParameters.$key } } } }catch{ $log = Write-VPASTextRecorder -inputval $_ -token $token -LogType ERROR $log = Write-VPASTextRecorder -inputval "REST API COMMAND RETURNED: FALSE" -token $token -LogType MISC Write-Verbose "FAILED TO GENERATE HEALTHCHECK REPORT" Write-VPASOutput -str $_ -type E return $false } try{ Write-VPASOutput -str "***INITIALIZING HEALTHCHECK VARIABLES***" -type G $outputmatrix = @{ VersionCheck = @() ComponentStatusCheck = @() EmptySafeCheck = @() ApplicationAuthMethodCheck = @() AccountComplianceCheck = @() InactivePlatformCheck = @() UnusedAssetsCheck = @() InactiveUserCheck = @() UnknownAssetCheck = @() } $onpremflag = $false if(!$ISPSS -and ($PVWA -notmatch ".privilegecloud.cyberark.")){ $onpremflag = $true } $SystemComponents = @{ CPM = @{ UniqueNames = @() } PVWA = @{ UniqueNames = @() } AIMPROV = @{ UniqueNames = @() } PSM = @{ UniqueNames = @() } VAULT = @{ Version = 0 } APPID = @{ Uniquenames = @() } SAFE = @{ Uniquenames = @() } PLATFORM = @{ Uniquenames = @() } PSMSERVERID = @{ Uniquenames = @() } CONNECTIONCOMPONENT = @{ Uniquenames = @() } ACCOUNT = @{ } } Write-VPASOutput -str "*Note, some of the checks below may take some time depending on the environment size" -type C #region VersionCheck Write-VPASOutput -str "***RUNNING COMPONENT VERSION + HEALTH CHECKS***" -type G $AllCPMs = Get-VPASSystemHealth -Component CPM $AllPSMs = Get-VPASSystemHealth -Component PSM $AllPVWAs = Get-VPASSystemHealth -Component PVWA $AllAIMs = Get-VPASSystemHealth -Component AIM $VaultVersion = (Get-VPASVaultVersion).ExternalVersion if(!$VaultVersion){ $SystemComponents.Vault = @{ Version = "UNCLEAR" } } else{ $tempversionarr = $VaultVersion -split "\." $VaultVersion = [Double]($tempversionarr[0] + "." + $tempversionarr[1]) $SystemComponents.Vault = @{ Version = $VaultVersion } } foreach($rec in $AllCPMs.ComponentsDetails){ $ComponentName = $rec.ComponentUserName $ComponentVersion = $rec.ComponentVersion $ComponentStatus = $rec.IsLoggedOn $ComponentIP = $rec.ComponentIP $tempversionarr = $ComponentVersion -split "\." $ComponentVersion = [Double]($tempversionarr[0] + "." + $tempversionarr[1]) $SystemComponents.CPM += @{ $ComponentName = @{ ComponentUsername = $ComponentName ComponentVersion = $ComponentVersion ComponentStatus = $ComponentStatus ComponentIP = $ComponentIP SafeAccess = $false } } $SystemComponents.CPM.UniqueNames += $ComponentName if($ComponentVersion -lt $VaultVersion){ $outputmatrix.VersionCheck += @{ Check = "VersionCheck" Category = "CPM" TargetName = $ComponentName Recommendation = "Recommendation: update CPM $ComponentName@$ComponentIP from $ComponentVersion to match vault version $VaultVersion" } } if(!$ComponentStatus){ $outputmatrix.ComponentStatusCheck += @{ Check = "ComponentStatusCheck" Category = "CPM" TargetName = $ComponentName Recommendation = "Recommendation: reconnect CPM $ComponentName@$ComponentIP to restore functionality" } } } foreach($rec in $AllPSMs.ComponentsDetails){ $ComponentName = $rec.ComponentUserName $ComponentVersion = $rec.ComponentVersion $ComponentStatus = $rec.IsLoggedOn $ComponentIP = $rec.ComponentIP $tempversionarr = $ComponentVersion -split "\." $ComponentVersion = [Double]($tempversionarr[0] + "." + $tempversionarr[1]) $SystemComponents.PSM += @{ $ComponentName = @{ ComponentUsername = $ComponentName ComponentVersion = $ComponentVersion ComponentStatus = $ComponentStatus ComponentIP = $ComponentIP } } $SystemComponents.PSM.UniqueNames += $ComponentName if($ComponentVersion -lt $VaultVersion){ $outputmatrix.VersionCheck += @{ Check = "VersionCheck" Category = "PSM" TargetName = $ComponentName Recommendation = "Recommendation: update PSM $ComponentName@$ComponentIP from $ComponentVersion to match vault version $VaultVersion" } } if(!$ComponentStatus){ $outputmatrix.ComponentStatusCheck += @{ Check = "ComponentStatusCheck" Category = "PSM" TargetName = $ComponentName Recommendation = "Recommendation: reconnect PSM $ComponentName@$ComponentIP to restore functionality" } } } if($onpremflag){ foreach($rec in $AllPVWAs.ComponentsDetails){ $ComponentName = $rec.ComponentUserName $ComponentVersion = $rec.ComponentVersion $ComponentStatus = $rec.IsLoggedOn $ComponentIP = $rec.ComponentIP $tempversionarr = $ComponentVersion -split "\." $ComponentVersion = [Double]($tempversionarr[0] + "." + $tempversionarr[1]) $SystemComponents.PVWA += @{ $ComponentName = @{ ComponentUsername = $ComponentName ComponentVersion = $ComponentVersion ComponentStatus = $ComponentStatus ComponentIP = $ComponentIP } } $SystemComponents.PVWA.UniqueNames += $ComponentName if($ComponentVersion -lt $VaultVersion){ $outputmatrix.VersionCheck += @{ Check = "VersionCheck" Category = "PVWA" TargetName = $ComponentName Recommendation = "Recommendation: update PVWA $ComponentName@$ComponentIP from $ComponentVersion to match vault version $VaultVersion" } } if(!$ComponentStatus){ $outputmatrix.ComponentStatusCheck += @{ Check = "ComponentStatusCheck" Category = "PVWA" TargetName = $ComponentName Recommendation = "Recommendation: reconnect PVWA $ComponentName@$ComponentIP to restore functionality" } } } } foreach($rec in $AllAIMs.ComponentsDetails){ $ComponentName = $rec.ComponentUserName $ComponentVersion = $rec.ComponentVersion $ComponentStatus = $rec.IsLoggedOn $ComponentIP = $rec.ComponentIP $tempversionarr = $ComponentVersion -split "\." $ComponentVersion = [Double]($tempversionarr[0] + "." + $tempversionarr[1]) $SystemComponents.AIMPROV += @{ $ComponentName = @{ ComponentUsername = $ComponentName ComponentVersion = $ComponentVersion ComponentStatus = $ComponentStatus ComponentIP = $ComponentIP SafeAccess = $false IsGroup = $false } } $SystemComponents.AIMPROV.UniqueNames += $ComponentName $epvgroups = (Get-VPASEPVUserDetails -EPVUsername $ComponentName).groupsMembership foreach($grouprec in $epvgroups){ $group = $grouprec.groupName if($SystemComponents.AIMPROV.$group){ $SystemComponents.AIMPROV.$group.Providers += $ComponentName } else{ $SystemComponents.AIMPROV += @{ $group = @{ IsGroup = $true Providers = @($ComponentName) SafeAccess = $false } } $SystemComponents.AIMPROV.Uniquenames += $group } } if($ComponentVersion -lt $VaultVersion){ $outputmatrix.VersionCheck += @{ Check = "VersionCheck" Category = "AIM" TargetName = $ComponentName Recommendation = "Recommendation: update AIM Provider $ComponentName@$ComponentIP from $ComponentVersion to match vault version $VaultVersion" } } if(!$ComponentStatus){ $outputmatrix.ComponentStatusCheck += @{ Check = "ComponentStatusCheck" Category = "AIM" TargetName = $ComponentName Recommendation = "Recommendation: reconnect AIM Provider $ComponentName@$ComponentIP to restore functionality" } } } #endregion VersionCheck #region ApplicationCheck Write-VPASOutput -str "***RUNNING APPLICATION HEALTH CHECKS***" -type G if($SystemComponents.AIMPROV.UniqueNames.Count -gt 0){ $AllApplications = Get-VPASAllApplications foreach($app in $AllApplications){ $appname = $app.AppID if($appname -eq "AIMWebService"){ #DO NOTHING } else{ $SystemComponents.APPID += @{ $appname = @{ AppID = $appname SafeAccess = $false IsGroup = $false } } $SystemComponents.APPID.Uniquenames += $appname $epvgroups = (Get-VPASEPVUserDetails -EPVUsername $appname).groupsMembership foreach($grouprec in $epvgroups){ $group = $grouprec.groupName if($SystemComponents.APPID.$group){ $SystemComponents.APPID.$group.AppIDs += $appname } else{ $SystemComponents.APPID += @{ $group = @{ IsGroup = $true AppIDs = @($appname) SafeAccess = $false } } $SystemComponents.APPID.Uniquenames += $group } } $ApplicationAuthmethods = Get-VPASApplicationAuthentications -AppID $appname if($ApplicationAuthmethods.authentication.Count -eq 0){ $outputmatrix.ApplicationAuthMethodCheck += @{ Check = "ApplicationAuthMethodCheck" Category = "Application" TargetName = $appname Recommendation = "Recommendation: Using an application with no authentication method configured is not recommended in any scenario. Add an authentication method to ApplicationID: $appname" } } } } } #endregion ApplicationCheck #region SafeCheck Write-VPASOutput -str "***RUNNING SAFE + SAFE MEMBER HEALTH CHECKS***" -type G $SkipSafes = @( "VaultInternal", "Notification Engine", "SharedAuth_Internal", "PVWAReports", "PVWATicketingSystem", "PVWAPublicData", "TelemetryConfig", "PasswordManager_Pending", "AccountsFeedADAccounts", "AccountsFeedDiscoveryLogs", "PSM", "PSMUniversalConnectors", "PSMRecordings", "PVWAConfig", "PVWAUserPrefs", "PVWAPrivateUserPrefs", "PVWATaskDefinitions", "PSMSessions", "PSMLiveSessions", "PSMUnmanagedSessionAccounts", "PSMNotifications", "PSMPConf", "PSMPLiveSessions", "PSMPADBUserProfile", "PSMPADBridgeCustom", "PSMPADBridgeConf", "AppProviderCacheSafe" ) foreach($val in $SystemComponents.CPM.UniqueNames){ $SkipSafes += $val $SkipSafes += $val + "_Accounts" } $AllSafes = Get-VPASAllSafes -IncludeAccounts foreach($safe in $AllSafes.value){ $safename = $safe.safeName if(!$SkipSafes.Contains($safename)){ $SystemComponents.SAFE.Uniquenames += $safename $SystemComponents.SAFE += @{ $safename = @{ Accounts = @{} } } #EMPTY SAFE CHECK if($safe.accounts.count -eq 0){ $outputmatrix.EmptySafeCheck += @{ Check = "EmptySafeCheck" Category = "Safe" TargetName = $safename Recommendation = "Recommendation: delete unused or empty safes ($safename) to help reduce clutter (assuming safe permissions allow viewing safe content)" } } else{ foreach($acct in $safe.accounts.id){ $SystemComponents.SAFE.$safename.Accounts += @{ $acct = @{ AcctID = $acct } } } } #GET MANAGED CPM $managedCPM = $safe.managingCPM if(![String]::IsNullOrEmpty($managedCPM)){ $SystemComponents.CPM.$managedCPM.SafeAccess = $true } #CHECK SAFE MEMBERS $AllSafeMembers = Get-VPASSafeMembers -safe $safename foreach($mem in $AllSafeMembers.value.membername){ if($SystemComponents.APPID.Uniquenames.Contains($mem)){ $SystemComponents.APPID.$mem.SafeAccess = $true } if($SystemComponents.AIMPROV.UniqueNames.Contains($mem)){ $SystemComponents.AIMPROV.$mem.SafeAccess = $true } } } } #endregion SafeCheck #region PSMCheck Write-VPASOutput -str "***RUNNING PSM + CONNECTOR HEALTH CHECKS***" -type G $AllPSMServerIDs = Get-VPASAllPSMServers foreach($PSMServerID in $AllPSMServerIDs.PSMServers.ID){ $SystemComponents.PSMSERVERID += @{ $PSMServerID = @{ PSMServerID = $PSMServerID InUse = $false } } $SystemComponents.PSMSERVERID.Uniquenames += $PSMServerID } $AllConnectors = Get-VPASAllConnectionComponents foreach($connector in $AllConnectors.PSMConnectors.ID){ if($connector -match "sample"){ $SystemComponents.CONNECTIONCOMPONENT += @{ $connector = @{ ConnectorID = $connector InUse = $true } } } else{ $SystemComponents.CONNECTIONCOMPONENT += @{ $connector = @{ ConnectorID = $connector InUse = $false } } } $SystemComponents.CONNECTIONCOMPONENT.Uniquenames += $connector } #endregion PSMCheck #region AccountCheck Write-VPASOutput -str "***RUNNING ACCOUNT HEALTH CHECKS***" -type G $ignoreplatforms = @("EPMLCDKey") $AllPlatforms = Get-VPASAllTargetPlatforms foreach($plat in $AllPlatforms.Platforms){ $platID = $plat.PlatformID $platStatus = $plat.Active $platPSM = $plat.PrivilegedSessionManagement.PSMServerId $SystemComponents.PLATFORM.Uniquenames += $platID $SystemComponents.PLATFORM += @{ $platID = @{ platformID = $platID platformStatus = $platStatus platformInUse = $false } } if(![String]::IsNullOrEmpty($platID)){ if(![String]::IsNullOrEmpty($platPSM)){ if($SystemComponents.PSMSERVERID.$platPSM){ $SystemComponents.PSMSERVERID.$platPSM.InUse = $true } else{ $outputmatrix.UnknownAssetCheck += @{ Check = "UnknownAssetCheck" Category = "PSM" TargetName = "$platPSM" Recommendation = "Recommendation: unknown PSMServerID assigned to platform $platID (PSMServerID: $platPSM)...assign an existing PSMServerID to restore functionality" } } } $platdetails = Get-VPASPSMSettingsByPlatformID -PlatformID $platID foreach($con in $platdetails.PSMConnectors.PSMConnectorID){ if($SystemComponents.CONNECTIONCOMPONENT.$con){ $SystemComponents.CONNECTIONCOMPONENT.$con.InUse = $true } else{ $outputmatrix.UnknownAssetCheck += @{ Check = "UnknownAssetCheck" Category = "PSMConnector" TargetName = "$con" Recommendation = "Recommendation: unknown PSMConnector assigned to platform $platID (PSMConnector: $con). Remove the connector from the platform to clear up clutter" } } } } } foreach($safe in $SystemComponents.SAFE.Keys){ #LOOP THROUGH EVERY SAFE if($safe -ne "Uniquenames"){ foreach($AcctID in $SystemComponents.SAFE.$safe.Accounts.Keys){ $AcctDetails = Get-VPASAccountDetailsExtended -AcctID $AcctID $IsCompliant = $AcctDetails.Compliance.IsCompliant $targetPlat = $AcctDetails.Platform.PlatformID $platstatus = $AcctDetails.Platform.IsActive $acctname = $AcctDetails.Details.Name if([String]::IsNullOrEmpty($targetPlat)){ $outputmatrix.InactivePlatformCheck += @{ Check = "InactivePlatformCheck" Category = "Account" TargetName = $acctname Recommendation = "Recommendation: accounts attached to an inactive or blank platform will remain non functional. Move $acctname from {BlankPlatform} to an active platfrom" } } elseif($ignoreplatforms.Contains($targetPlat)){ #DO NOTHING } else{ if($SystemComponents.PLATFORM.$targetPlat){ $SystemComponents.PLATFORM.$targetPlat.platformInUse = $true } else{ $SystemComponents.PLATFORM += @{ $targetPlat = @{ platformID = $targetPlat platformStatus = $platStatus platformInUse = $true } } } if(!$IsCompliant){ $outputmatrix.AccountComplianceCheck += @{ Check = "AccountComplianceCheck" Category = "Account" TargetName = $acctname Recommendation = "Recommendation: resolve any errors associated with the account ($acctname) to restore compliance and enable rotation where applicable" } } if(!$platStatus){ $outputmatrix.InactivePlatformCheck += @{ Check = "InactivePlatformCheck" Category = "Account" TargetName = $acctname Recommendation = "Recommendation: accounts attached to an inactive or blank platform will remain non functional. Move $acctname from platform $targetPlat to an active platfrom" } } } } } } #endregion AccountCheck #region UnusedAssetCheck Write-VPASOutput -str "***RUNNING UNUSED ASSETS CHECKS***" -type G #APPIDS - Step1 Groups foreach($targetval in $SystemComponents.APPID.Keys){ if($targetval -ne "Uniquenames"){ $inuse = $SystemComponents.APPID.$targetval.SafeAccess $isgroup = $SystemComponents.APPID.$targetval.IsGroup if($isgroup){ if($inuse){ foreach($appid in $SystemComponents.APPID.$targetval.AppIDs){ $SystemComponents.APPID.$appid.SafeAccess = $true } } } } } #APPIDS - Step2 AppIDs foreach($targetval in $SystemComponents.APPID.Keys){ if($targetval -ne "Uniquenames"){ $inuse = $SystemComponents.APPID.$targetval.SafeAccess $isgroup = $SystemComponents.APPID.$targetval.IsGroup if(!$isgroup){ if(!$inuse){ $outputmatrix.UnusedAssetsCheck += @{ Check = "UnusedAssetsCheck" Category = "ApplicationID" TargetName = $targetval Recommendation = "Recommendation: delete unused application IDs ($targetval) to help reduce clutter" } } } } } #PLATFORMS foreach($targetval in $SystemComponents.PLATFORM.Keys){ if($targetval -ne "Uniquenames"){ if($ignoreplatforms.Contains($targetval)){ #DO NOTHING } else{ $inuse = $SystemComponents.PLATFORM.$targetval.platformInUse $isactive = $SystemComponents.PLATFORM.$targetval.platformStatus if($isactive){ if(!$inuse){ $outputmatrix.UnusedAssetsCheck += @{ Check = "UnusedAssetsCheck" Category = "Platform" TargetName = $targetval Recommendation = "Recommendation: deactivate or delete unused platforms ($targetval) to help reduce clutter and CPM load" } } } } } } #AIMPROV - Step1 Groups foreach($targetval in $SystemComponents.AIMPROV.Keys){ if($targetval -ne "Uniquenames"){ $inuse = $SystemComponents.AIMPROV.$targetval.SafeAccess $isgroup = $SystemComponents.AIMPROV.$targetval.IsGroup if($isgroup){ if($inuse){ foreach($appid in $SystemComponents.AIMPROV.$targetval.Providers){ $SystemComponents.AIMPROV.$appid.SafeAccess = $true } } } } } #AIMPROV - Step2 Providers foreach($targetval in $SystemComponents.AIMPROV.Keys){ if($targetval -ne "Uniquenames"){ $inuse = $SystemComponents.AIMPROV.$targetval.SafeAccess $isgroup = $SystemComponents.AIMPROV.$targetval.IsGroup if(!$isgroup){ if(!$inuse){ $outputmatrix.UnusedAssetsCheck += @{ Check = "UnusedAssetsCheck" Category = "AIMProviders" TargetName = $targetval Recommendation = "Recommendation: delete/uninstall unused providers ($targetval) to help reduce clutter and to free up provider licenses" } } } } } #CPMs foreach($targetval in $SystemComponents.CPM.Keys){ if($targetval -ne "Uniquenames"){ $inuse = $SystemComponents.CPM.$targetval.SafeAccess if(!$inuse){ $outputmatrix.UnusedAssetsCheck += @{ Check = "UnusedAssetsCheck" Category = "CPM" TargetName = $targetval Recommendation = "Recommendation: delete/uninstall unused CPMs ($targetval) to help reduce clutter and to free up a CPM license" } } } } #PSMServerIDs foreach($targetval in $SystemComponents.PSMSERVERID.Keys){ if($targetval -ne "Uniquenames"){ $inuse = $SystemComponents.PSMSERVERID.$targetval.InUse if(!$inuse){ $outputmatrix.UnusedAssetsCheck += @{ Check = "UnusedAssetsCheck" Category = "PSMServer" TargetName = $targetval Recommendation = "Recommendation: delete unused PSM configuration ($targetval) to help reduce clutter" } } } } #ConnectionComponents foreach($targetval in $SystemComponents.CONNECTIONCOMPONENT.Keys){ if($targetval -ne "Uniquenames"){ $inuse = $SystemComponents.CONNECTIONCOMPONENT.$targetval.InUse if(!$inuse){ $outputmatrix.UnusedAssetsCheck += @{ Check = "UnusedAssetsCheck" Category = "ConnectionComponent" TargetName = $targetval Recommendation = "Recommendation: delete unused ConnectionComponent configurations ($targetval) to help reduce clutter" } } } } #endregion UnusedAssetCheck #region UserCheck Write-VPASOutput -str "***RUNNING USER HEALTH CHECKS***" -type G $curTime = ([int][double]::Parse((Get-Date (get-date (get-date).Date).ToLocalTime() -UFormat %s))) $cutTime = ([int][double]::Parse((Get-Date (get-date (get-date).Date.AddYears(-1)).ToLocalTime() -UFormat %s))) $ignoreusers = @() $AllUsers = Get-VPASAllEPVUsers foreach($user in $AllUsers.Users){ $userusername = $user.username $userid = $user.id $usertype = $user.userType if($usertype -eq "EPVUser"){ $userdetails = Get-VPASEPVUserDetails -EPVUserID $userid $lastlogin = $userdetails.lastSuccessfulLoginDate if($lastlogin -le $cutTime){ $outputmatrix.InactivePlatformCheck += @{ Check = "InactiveUserCheck" Category = "User" TargetName = "$userusername" Recommendation = "Recommendation: $userusername has not logged into CyberArk in the last year. Consider removing the user to free up a user license" } } } } #endregion UserCheck if($ExportToCSV){ $runexport = Write-VPASExportCSV -Data $outputmatrix -CommandName $CommandName -CSVDirectory $CSVDirectory } $log = Write-VPASTextRecorder -inputval $outputmatrix -token $token -LogType RETURNARRAY Write-Verbose "PARSING DATA FROM CYBERARK" Write-Verbose "RETURNING JSON OBJECT" return $outputmatrix }catch{ $log = Write-VPASTextRecorder -inputval $_ -token $token -LogType ERROR $log = Write-VPASTextRecorder -inputval "REST API COMMAND RETURNED: FALSE" -token $token -LogType MISC Write-Verbose "UNABLE TO GENERATE USER LICENSE REPORT" Write-VPASOutput -str $_ -type E return $false } } End{ $log = Write-VPASTextRecorder -inputval $CommandName -token $token -LogType DIVIDER } } # SIG # Begin signature block # MIIroAYJKoZIhvcNAQcCoIIrkTCCK40CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUpFQCTtMtQDRlY5z/6VLynnWB # 8HeggiTbMIIFbzCCBFegAwIBAgIQSPyTtGBVlI02p8mKidaUFjANBgkqhkiG9w0B # AQwFADB7MQswCQYDVQQGEwJHQjEbMBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVy # MRAwDgYDVQQHDAdTYWxmb3JkMRowGAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEh # MB8GA1UEAwwYQUFBIENlcnRpZmljYXRlIFNlcnZpY2VzMB4XDTIxMDUyNTAwMDAw # MFoXDTI4MTIzMTIzNTk1OVowVjELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1NlY3Rp # Z28gTGltaXRlZDEtMCsGA1UEAxMkU2VjdGlnbyBQdWJsaWMgQ29kZSBTaWduaW5n # IFJvb3QgUjQ2MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjeeUEiIE # JHQu/xYjApKKtq42haxH1CORKz7cfeIxoFFvrISR41KKteKW3tCHYySJiv/vEpM7 # fbu2ir29BX8nm2tl06UMabG8STma8W1uquSggyfamg0rUOlLW7O4ZDakfko9qXGr # YbNzszwLDO/bM1flvjQ345cbXf0fEj2CA3bm+z9m0pQxafptszSswXp43JJQ8mTH # qi0Eq8Nq6uAvp6fcbtfo/9ohq0C/ue4NnsbZnpnvxt4fqQx2sycgoda6/YDnAdLv # 64IplXCN/7sVz/7RDzaiLk8ykHRGa0c1E3cFM09jLrgt4b9lpwRrGNhx+swI8m2J # mRCxrds+LOSqGLDGBwF1Z95t6WNjHjZ/aYm+qkU+blpfj6Fby50whjDoA7NAxg0P # OM1nqFOI+rgwZfpvx+cdsYN0aT6sxGg7seZnM5q2COCABUhA7vaCZEao9XOwBpXy # bGWfv1VbHJxXGsd4RnxwqpQbghesh+m2yQ6BHEDWFhcp/FycGCvqRfXvvdVnTyhe # Be6QTHrnxvTQ/PrNPjJGEyA2igTqt6oHRpwNkzoJZplYXCmjuQymMDg80EY2NXyc # uu7D1fkKdvp+BRtAypI16dV60bV/AK6pkKrFfwGcELEW/MxuGNxvYv6mUKe4e7id # FT/+IAx1yCJaE5UZkADpGtXChvHjjuxf9OUCAwEAAaOCARIwggEOMB8GA1UdIwQY # MBaAFKARCiM+lvEH7OKvKe+CpX/QMKS0MB0GA1UdDgQWBBQy65Ka/zWWSC8oQEJw # IDaRXBeF5jAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zATBgNVHSUE # DDAKBggrBgEFBQcDAzAbBgNVHSAEFDASMAYGBFUdIAAwCAYGZ4EMAQQBMEMGA1Ud # HwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0FBQUNlcnRpZmlj # YXRlU2VydmljZXMuY3JsMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYYaHR0 # cDovL29jc3AuY29tb2RvY2EuY29tMA0GCSqGSIb3DQEBDAUAA4IBAQASv6Hvi3Sa # mES4aUa1qyQKDKSKZ7g6gb9Fin1SB6iNH04hhTmja14tIIa/ELiueTtTzbT72ES+ # BtlcY2fUQBaHRIZyKtYyFfUSg8L54V0RQGf2QidyxSPiAjgaTCDi2wH3zUZPJqJ8 # ZsBRNraJAlTH/Fj7bADu/pimLpWhDFMpH2/YGaZPnvesCepdgsaLr4CnvYFIUoQx # 2jLsFeSmTD1sOXPUC4U5IOCFGmjhp0g4qdE2JXfBjRkWxYhMZn0vY86Y6GnfrDyo # XZ3JHFuu2PMvdM+4fvbXg50RlmKarkUT2n/cR/vfw1Kf5gZV6Z2M8jpiUbzsJA8p # 1FiAhORFe1rYMIIGFDCCA/ygAwIBAgIQeiOu2lNplg+RyD5c9MfjPzANBgkqhkiG # 9w0BAQwFADBXMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVk # MS4wLAYDVQQDEyVTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIFJvb3QgUjQ2 # MB4XDTIxMDMyMjAwMDAwMFoXDTM2MDMyMTIzNTk1OVowVTELMAkGA1UEBhMCR0Ix # GDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEsMCoGA1UEAxMjU2VjdGlnbyBQdWJs # aWMgVGltZSBTdGFtcGluZyBDQSBSMzYwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw # ggGKAoIBgQDNmNhDQatugivs9jN+JjTkiYzT7yISgFQ+7yavjA6Bg+OiIjPm/N/t # 3nC7wYUrUlY3mFyI32t2o6Ft3EtxJXCc5MmZQZ8AxCbh5c6WzeJDB9qkQVa46xiY # Epc81KnBkAWgsaXnLURoYZzksHIzzCNxtIXnb9njZholGw9djnjkTdAA83abEOHQ # 4ujOGIaBhPXG2NdV8TNgFWZ9BojlAvflxNMCOwkCnzlH4oCw5+4v1nssWeN1y4+R # laOywwRMUi54fr2vFsU5QPrgb6tSjvEUh1EC4M29YGy/SIYM8ZpHadmVjbi3Pl8h # JiTWw9jiCKv31pcAaeijS9fc6R7DgyyLIGflmdQMwrNRxCulVq8ZpysiSYNi79tw # 5RHWZUEhnRfs/hsp/fwkXsynu1jcsUX+HuG8FLa2BNheUPtOcgw+vHJcJ8HnJCrc # UWhdFczf8O+pDiyGhVYX+bDDP3GhGS7TmKmGnbZ9N+MpEhWmbiAVPbgkqykSkzyY # Vr15OApZYK8CAwEAAaOCAVwwggFYMB8GA1UdIwQYMBaAFPZ3at0//QET/xahbIIC # L9AKPRQlMB0GA1UdDgQWBBRfWO1MMXqiYUKNUoC6s2GXGaIymzAOBgNVHQ8BAf8E # BAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcDCDAR # BgNVHSAECjAIMAYGBFUdIAAwTAYDVR0fBEUwQzBBoD+gPYY7aHR0cDovL2NybC5z # ZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljVGltZVN0YW1waW5nUm9vdFI0Ni5jcmww # fAYIKwYBBQUHAQEEcDBuMEcGCCsGAQUFBzAChjtodHRwOi8vY3J0LnNlY3RpZ28u # Y29tL1NlY3RpZ29QdWJsaWNUaW1lU3RhbXBpbmdSb290UjQ2LnA3YzAjBggrBgEF # BQcwAYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggIB # ABLXeyCtDjVYDJ6BHSVY/UwtZ3Svx2ImIfZVVGnGoUaGdltoX4hDskBMZx5NY5L6 # SCcwDMZhHOmbyMhyOVJDwm1yrKYqGDHWzpwVkFJ+996jKKAXyIIaUf5JVKjccev3 # w16mNIUlNTkpJEor7edVJZiRJVCAmWAaHcw9zP0hY3gj+fWp8MbOocI9Zn78xvm9 # XKGBp6rEs9sEiq/pwzvg2/KjXE2yWUQIkms6+yslCRqNXPjEnBnxuUB1fm6bPAV+ # Tsr/Qrd+mOCJemo06ldon4pJFbQd0TQVIMLv5koklInHvyaf6vATJP4DfPtKzSBP # kKlOtyaFTAjD2Nu+di5hErEVVaMqSVbfPzd6kNXOhYm23EWm6N2s2ZHCHVhlUgHa # C4ACMRCgXjYfQEDtYEK54dUwPJXV7icz0rgCzs9VI29DwsjVZFpO4ZIVR33LwXyP # DbYFkLqYmgHjR3tKVkhh9qKV2WCmBuC27pIOx6TYvyqiYbntinmpOqh/QPAnhDge # xKG9GX/n1PggkGi9HCapZp8fRwg8RftwS21Ln61euBG0yONM6noD2XQPrFwpm3Gc # uqJMf0o8LLrFkSLRQNwxPDDkWXhW+gZswbaiie5fd/W2ygcto78XCSPfFWveUOSZ # 5SqK95tBO8aTHmEa4lpJVD7HrTEn9jb1EGvxOb1cnn0CMIIGGjCCBAKgAwIBAgIQ # Yh1tDFIBnjuQeRUgiSEcCjANBgkqhkiG9w0BAQwFADBWMQswCQYDVQQGEwJHQjEY # MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdvIFB1Ymxp # YyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIx # MjM1OTU5WjBUMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVk # MSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0EgUjM2MIIB # ojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAmyudU/o1P45gBkNqwM/1f/bI # U1MYyM7TbH78WAeVF3llMwsRHgBGRmxDeEDIArCS2VCoVk4Y/8j6stIkmYV5Gej4 # NgNjVQ4BYoDjGMwdjioXan1hlaGFt4Wk9vT0k2oWJMJjL9G//N523hAm4jF4UjrW # 2pvv9+hdPX8tbbAfI3v0VdJiJPFy/7XwiunD7mBxNtecM6ytIdUlh08T2z7mJEXZ # D9OWcJkZk5wDuf2q52PN43jc4T9OkoXZ0arWZVeffvMr/iiIROSCzKoDmWABDRzV # /UiQ5vqsaeFaqQdzFf4ed8peNWh1OaZXnYvZQgWx/SXiJDRSAolRzZEZquE6cbcH # 747FHncs/Kzcn0Ccv2jrOW+LPmnOyB+tAfiWu01TPhCr9VrkxsHC5qFNxaThTG5j # 4/Kc+ODD2dX/fmBECELcvzUHf9shoFvrn35XGf2RPaNTO2uSZ6n9otv7jElspkfK # 9qEATHZcodp+R4q2OIypxR//YEb3fkDn3UayWW9bAgMBAAGjggFkMIIBYDAfBgNV # HSMEGDAWgBQy65Ka/zWWSC8oQEJwIDaRXBeF5jAdBgNVHQ4EFgQUDyrLIIcouOxv # SK4rVKYpqhekzQwwDgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAw # EwYDVR0lBAwwCgYIKwYBBQUHAwMwGwYDVR0gBBQwEjAGBgRVHSAAMAgGBmeBDAEE # ATBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3Rp # Z29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYuY3JsMHsGCCsGAQUFBwEBBG8wbTBG # BggrBgEFBQcwAoY6aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGlj # Q29kZVNpZ25pbmdSb290UjQ2LnA3YzAjBggrBgEFBQcwAYYXaHR0cDovL29jc3Au # c2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggIBAAb/guF3YzZue6EVIJsT/wT+ # mHVEYcNWlXHRkT+FoetAQLHI1uBy/YXKZDk8+Y1LoNqHrp22AKMGxQtgCivnDHFy # AQ9GXTmlk7MjcgQbDCx6mn7yIawsppWkvfPkKaAQsiqaT9DnMWBHVNIabGqgQSGT # rQWo43MOfsPynhbz2Hyxf5XWKZpRvr3dMapandPfYgoZ8iDL2OR3sYztgJrbG6VZ # 9DoTXFm1g0Rf97Aaen1l4c+w3DC+IkwFkvjFV3jS49ZSc4lShKK6BrPTJYs4NG1D # GzmpToTnwoqZ8fAmi2XlZnuchC4NPSZaPATHvNIzt+z1PHo35D/f7j2pO1S8BCys # QDHCbM5Mnomnq5aYcKCsdbh0czchOm8bkinLrYrKpii+Tk7pwL7TjRKLXkomm5D1 # Umds++pip8wH2cQpf93at3VDcOK4N7EwoIJB0kak6pSzEu4I64U6gZs7tS/dGNSl # jf2OSSnRr7KWzq03zl8l75jy+hOds9TWSenLbjBQUGR96cFr6lEUfAIEHVC1L68Y # 1GGxx4/eRI82ut83axHMViw1+sVpbPxg51Tbnio1lB93079WPFnYaOvfGAA0e0zc # fF/M9gXr+korwQTh2Prqooq2bYNMvUoUKD85gnJ+t0smrWrb8dee2CvYZXD5laGt # aAxOfy/VKNmwuWuAh9kcMIIGRzCCBK+gAwIBAgIQacs5SDkvNuif0aEmZmr03jAN # BgkqhkiG9w0BAQwFADBUMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBM # aW1pdGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0Eg # UjM2MB4XDTI1MDEyOTAwMDAwMFoXDTI4MDEyOTIzNTk1OVowXjELMAkGA1UEBhMC # VVMxEzARBgNVBAgMCk5ldyBKZXJzZXkxHDAaBgNVBAoME0N5YmVyTWVsIENvbnN1 # bHRpbmcxHDAaBgNVBAMME0N5YmVyTWVsIENvbnN1bHRpbmcwggIiMA0GCSqGSIb3 # DQEBAQUAA4ICDwAwggIKAoICAQDBQmSvdfamF8o0CJr4vbHCcJ4rwx6T1HR3d32u # 4aIf9v9p/GV4nFdG4PP9SMjWw7Nx9CLFqGPpkw7aDU2IxwpfPYExDzkCj2pgiyeV # KlL0itTlPocb6i1cZLe/WHV7aUkGkVlfvyYIqdJ9uw711dhNWmMhlqo+/qyp+gpK # qaiFHm6mWNVg2KLTH5Pu38cBoGhS1tn7mlQbtALNjehkpFw2AAntEIBzM3ZEg9WB # xQlgYY0yAPkydYbJfTEOEFJqHUPTSV46jx22Jb9dl0cEIPsGrCp+Jo5Ugusp9oZE # CZ8bGt7Vc9jYoIWGpqcRDq1JZFNCSVvNE4N3ECGjq6W3kYW7ot0CP1DkpJ93a5wr # ksQ6bvYGUy3lghkMvzjkkq/NVUDEVcdNR7PsUFf654vSw+iLINZ+9kYg+Znplfnd # T/JSMJDAaWkM5oLu6+ao0774QWrsHOttz7M8EDU+3PntYHglwWoej6qXIFRurgXd # wAXXyXYcSmkOTbPqrjSwsbs8CuSwGqebbRSDKfjRzDqQ9D1AZ/JHHaaUkBbAYBsV # MrvypDSrP/1o37mt4Zky28BnEp5ztEGp0HJ44X4rFVWWz+BfeuZWcVUcGKW2YFHo # bNwGmJ/OanLvlnmtpZIRLF9ZkbzCHHomi+RId4g3fc3FsGxKqEW9Vj8PCumwKc6L # UwZU4wIDAQABo4IBiTCCAYUwHwYDVR0jBBgwFoAUDyrLIIcouOxvSK4rVKYpqhek # zQwwHQYDVR0OBBYEFCiCHmEfvPkU1uIc2sPugFDBq88SMA4GA1UdDwEB/wQEAwIH # gDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMEoGA1UdIARDMEEw # NQYMKwYBBAGyMQECAQMCMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5j # b20vQ1BTMAgGBmeBDAEEATBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLnNl # Y3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ0NBUjM2LmNybDB5Bggr # BgEFBQcBAQRtMGswRAYIKwYBBQUHMAKGOGh0dHA6Ly9jcnQuc2VjdGlnby5jb20v # U2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYuY3J0MCMGCCsGAQUFBzABhhdo # dHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAYEAmLUUP/C5 # nHN/qX27dIrfNezHdUul/uhOA5CwNkD7P4pvLJButR/S1OmvozuzJJTce6824Iyl # nXkRwUFj04XLbodkBL7+YwQ5ml7CjdDSVo+sI/38jcEQ6FgosV/TTJSiFAgqMNwk # x/kSzvQ1/Ufp5YVKggCXGJ4VitIzl5nMbzzu35G/uy4vmCQfh0KPYUTJYiRsF6Z3 # XJiIVtYrEwN/ikif/WFGrzsFj1OOWHNn5qDOP80xExmRS09z/wdZE9RdjPv5fYLn # KWy1+GQ/w1vzg/l2vUXIgBV0MxalUfTP4V9Spsodrb+noPXiCy5n+6hy9yCf3EQb # 3G1n8rT/a454fLSijMm6bhrgBRqhPUUtn6ZIBdEJzJUI6ftuXrQnB/U7zf32xcTT # AW7WPem7DFK/4JrSaxiXcSkxQ4kXJDVoDPUJdpb0c5XdWVJO0DCkB35ONEIoqT6V # jEIjLPSw9UXE420r1OIpV8FRJqrW4Fr5RUveEUlyF+FyygVOYZECNsjRMIIGXTCC # BMWgAwIBAgIQOlJqLITOVeYdZfzMEtjpiTANBgkqhkiG9w0BAQwFADBVMQswCQYD # VQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSwwKgYDVQQDEyNTZWN0 # aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNjAeFw0yNDAxMTUwMDAwMDBa # Fw0zNTA0MTQyMzU5NTlaMG4xCzAJBgNVBAYTAkdCMRMwEQYDVQQIEwpNYW5jaGVz # dGVyMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxMDAuBgNVBAMTJ1NlY3RpZ28g # UHVibGljIFRpbWUgU3RhbXBpbmcgU2lnbmVyIFIzNTCCAiIwDQYJKoZIhvcNAQEB # BQADggIPADCCAgoCggIBAI3RZ/TBSJu9/ThJOk1hgZvD2NxFpWEENo0GnuOYloD1 # 1BlbmKCGtcY0xiMrsN7LlEgcyoshtP3P2J/vneZhuiMmspY7hk/Q3l0FPZPBllo9 # vwT6GpoNnxXLZz7HU2ITBsTNOs9fhbdAWr/Mm8MNtYov32osvjYYlDNfefnBajrQ # qSV8Wf5ZvbaY5lZhKqQJUaXxpi4TXZKohLgxU7g9RrFd477j7jxilCU2ptz+d1OC # zNFAsXgyPEM+NEMPUz2q+ktNlxMZXPF9WLIhOhE3E8/oNSJkNTqhcBGsbDI/1qCU # 9fBhuSojZ0u5/1+IjMG6AINyI6XLxM8OAGQmaMB8gs2IZxUTOD7jTFR2HE1xoL7q # vSO4+JHtvNceHu//dGeVm5Pdkay3Et+YTt9EwAXBsd0PPmC0cuqNJNcOI0XnwjE+ # 2+Zk8bauVz5ir7YHz7mlj5Bmf7W8SJ8jQwO2IDoHHFC46ePg+eoNors0QrC0PWnO # gDeMkW6gmLBtq3CEOSDU8iNicwNsNb7ABz0W1E3qlSw7jTmNoGCKCgVkLD2FaMs2 # qAVVOjuUxvmtWMn1pIFVUvZ1yrPIVbYt1aTld2nrmh544Auh3tgggy/WluoLXlHt # AJgvFwrVsKXj8ekFt0TmaPL0lHvQEe5jHbufhc05lvCtdwbfBl/2ARSTuy1s8CgF # AgMBAAGjggGOMIIBijAfBgNVHSMEGDAWgBRfWO1MMXqiYUKNUoC6s2GXGaIymzAd # BgNVHQ4EFgQUaO+kMklptlI4HepDOSz0FGqeDIUwDgYDVR0PAQH/BAQDAgbAMAwG # A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwSgYDVR0gBEMwQTA1 # BgwrBgEEAbIxAQIBAwgwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNv # bS9DUFMwCAYGZ4EMAQQCMEoGA1UdHwRDMEEwP6A9oDuGOWh0dHA6Ly9jcmwuc2Vj # dGlnby5jb20vU2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ0NBUjM2LmNybDB6Bggr # BgEFBQcBAQRuMGwwRQYIKwYBBQUHMAKGOWh0dHA6Ly9jcnQuc2VjdGlnby5jb20v # U2VjdGlnb1B1YmxpY1RpbWVTdGFtcGluZ0NBUjM2LmNydDAjBggrBgEFBQcwAYYX # aHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggGBALDcLsn6 # TzZMii/2yU/V7xhPH58Oxr/+EnrZjpIyvYTz2u/zbL+fzB7lbrPml8ERajOVbuda # n6x08J1RMXD9hByq+yEfpv1G+z2pmnln5XucfA9MfzLMrCArNNMbUjVcRcsAr18e # eZeloN5V4jwrovDeLOdZl0tB7fOX5F6N2rmXaNTuJR8yS2F+EWaL5VVg+RH8FelX # tRvVDLJZ5uqSNIckdGa/eUFhtDKTTz9LtOUh46v2JD5Q3nt8mDhAjTKp2fo/KJ6F # LWdKAvApGzjpPwDqFeJKf+kJdoBKd2zQuwzk5Wgph9uA46VYK8p/BTJJahKCuGdy # KFIFfEfakC4NXa+vwY4IRp49lzQPLo7WticqMaaqb8hE2QmCFIyLOvWIg4837bd+ # 60FcCGbHwmL/g1ObIf0rRS9ceK4DY9rfBnHFH2v1d4hRVvZXyCVlrL7ZQuVzjjkL # MK9VJlXTVkHpuC8K5S4HHTv2AJx6mOdkMJwS4gLlJ7gXrIVpnxG+aIniGDCCBoIw # ggRqoAMCAQICEDbCsL18Gzrno7PdNsvJdWgwDQYJKoZIhvcNAQEMBQAwgYgxCzAJ # BgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQwEgYDVQQHEwtKZXJzZXkg # Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMS4wLAYDVQQDEyVV # U0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTIxMDMyMjAw # MDAwMFoXDTM4MDExODIzNTk1OVowVzELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1Nl # Y3RpZ28gTGltaXRlZDEuMCwGA1UEAxMlU2VjdGlnbyBQdWJsaWMgVGltZSBTdGFt # cGluZyBSb290IFI0NjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIid # 2LlFZ50d3ei5JoGaVFTAfEkFm8xaFQ/ZlBBEtEFAgXcUmanU5HYsyAhTXiDQkiUv # pVdYqZ1uYoZEMgtHES1l1Cc6HaqZzEbOOp6YiTx63ywTon434aXVydmhx7Dx4IBr # Aou7hNGsKioIBPy5GMN7KmgYmuu4f92sKKjbxqohUSfjk1mJlAjthgF7Hjx4vvyV # DQGsd5KarLW5d73E3ThobSkob2SL48LpUR/O627pDchxll+bTSv1gASn/hp6IuHJ # orEu6EopoB1CNFp/+HpTXeNARXUmdRMKbnXWflq+/g36NJXB35ZvxQw6zid61qmr # lD/IbKJA6COw/8lFSPQwBP1ityZdwuCysCKZ9ZjczMqbUcLFyq6KdOpuzVDR3ZUw # xDKL1wCAxgL2Mpz7eZbrb/JWXiOcNzDpQsmwGQ6Stw8tTCqPumhLRPb7YkzM8/6N # nWH3T9ClmcGSF22LEyJYNWCHrQqYubNeKolzqUbCqhSqmr/UdUeb49zYHr7ALL8b # AJyPDmubNqMtuaobKASBqP84uhqcRY/pjnYd+V5/dcu9ieERjiRKKsxCG1t6tG9o # j7liwPddXEcYGOUiWLm742st50jGwTzxbMpepmOP1mLnJskvZaN5e45NuzAHteOR # lsSuDt5t4BBRCJL+5EZnnw0ezntk9R8QJyAkL6/bAgMBAAGjggEWMIIBEjAfBgNV # HSMEGDAWgBRTeb9aqitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQU9ndq3T/9ARP/ # FqFsggIv0Ao9FCUwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wEwYD # VR0lBAwwCgYIKwYBBQUHAwgwEQYDVR0gBAowCDAGBgRVHSAAMFAGA1UdHwRJMEcw # RaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0 # aWZpY2F0aW9uQXV0aG9yaXR5LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUH # MAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggIB # AA6+ZUHtaES45aHF1BGH5Lc7JYzrftrIF5Ht2PFDxKKFOct/awAEWgHQMVHol9ZL # Syd/pYMbaC0IZ+XBW9xhdkkmUV/KbUOiL7g98M/yzRyqUOZ1/IY7Ay0YbMniIibJ # rPcgFp73WDnRDKtVutShPSZQZAdtFwXnuiWl8eFARK3PmLqEm9UsVX+55DbVIz33 # Mbhba0HUTEYv3yJ1fwKGxPBsP/MgTECimh7eXomvMm0/GPxX2uhwCcs/YLxDnBdV # VlxvDjHjO1cuwbOpkiJGHmLXXVNbsdXUC2xBrq9fLrfe8IBsA4hopwsCj8hTuwKX # JlSTrZcPRVSccP5i9U28gZ7OMzoJGlxZ5384OKm0r568Mo9TYrqzKeKZgFo0fj2/ # 0iHbj55hc20jfxvK3mQi+H7xpbzxZOFGm/yVQkpo+ffv5gdhp+hv1GDsvJOtJinJ # mgGbBFZIThbqI+MHvAmMmkfb3fTxmSkop2mSJL1Y2x/955S29Gu0gSJIkc3z30vU # /iXrMpWx2tS7UVfVP+5tKuzGtgkP7d/doqDrLF1u6Ci3TpjAZdeLLlRQZm867eVe # XED58LXd1Dk6UvaAhvmWYXoiLz4JA5gPBcz7J311uahxCweNxE+xxxR3kT0WKzAS # o5G/PyDez6NHdIUKBeE3jDPs2ACc6CkJ1Sji4PKWVT0/MYIGLzCCBisCAQEwaDBU # MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSswKQYDVQQD # EyJTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgQ0EgUjM2AhBpyzlIOS826J/R # oSZmavTeMAkGBSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkG # CSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEE # AYI3AgEVMCMGCSqGSIb3DQEJBDEWBBRK7wCdUPEWffW2LAcJTWvBQQV0SzANBgkq # hkiG9w0BAQEFAASCAgBLf5b/XvZv+uDWIRqDlc4z4vuXBM1szPLzMAwgt2yB7Kec # 22RzmMgBXbiQmZ+1ENJr2OWSR5HMZYpyjALRSfbm/DqGmOPyA2v0Ch4fObRnDwYz # x8VKJY89FxNCuP1nZFZoqvi9qqTeJuIYHdOUCZZNpC5Qc4OpiLGn9MCR532frJHu # VyP8ymssZPKaDJ5Vl49FKkE3BC5R5QLwqbYFyRJHsGyP8htHffBKX1vUTS0A3UVA # 3CQ5/ldecT3SBNqENVr1AoyBJLmosSIsxhp5ehjmWlGMV6bYfmY3eX0b2S7Te6f9 # S62gv4TX9BpiZC+ZSZ9YV0LIWb6sSX9OS+gcgj/j77AF0CGXI25b/eubFlDps/1e # P0LmrdUnjAXhvCM/aOe5a4eLycAeUd6an2RCd0Dv/G99RxxA4XtLwyYOIUJkkTKp # 0VOfJIDTnOImf0GsoVwCnPYGDUiaYhCqMr4GgVi8jU8sezIvb/FgumRGQh/HsCCs # KcS/qsPFJl34kjSNrrwEfJfZsJ3EtaYFFGs9lRFrjYVsDSdWF47HE38FWN00R+5V # RWx9aNpEJQQl6VJVJCb5juHAifOoKzUlinFgNqHQieEXpHkM4yK5brbOXih5593D # q0AM+DTpY/gophSqwe2yeCrE/wHE67meKuSKWqqIgIk77d4TrsKmIdx943iZ2qGC # AyIwggMeBgkqhkiG9w0BCQYxggMPMIIDCwIBATBpMFUxCzAJBgNVBAYTAkdCMRgw # FgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLDAqBgNVBAMTI1NlY3RpZ28gUHVibGlj # IFRpbWUgU3RhbXBpbmcgQ0EgUjM2AhA6UmoshM5V5h1l/MwS2OmJMA0GCWCGSAFl # AwQCAgUAoHkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG9w0BCQUx # DxcNMjUwMjA1MTQxNjAxWjA/BgkqhkiG9w0BCQQxMgQw1yaE/ilU1ZUiIsfOjcz7 # 3mF//M01U4hACt9lZBMXxTgTHAGMe6OktVbmUkrjPFwJMA0GCSqGSIb3DQEBAQUA # BIICAAO+Ffi+o2X7gj6qawIT9/O3SV1A6MLzZyh4BsXsYpn5bk09J7Cp/clRKAd/ # AhXgB2LQ+yTO0U8PKS791NWR0+sCwJ2O3tLuJ7fjgGkmS+lXuUDN39zFs6Rt9aNA # yJ/1V0xYHFaeToS2zvAWkZsocVPLMo9khmMCZm8+9Sg6PFxHn/4PVZb1k1Fz9ryW # DljSiG5eD1T93HSPY6FRXu+MQDYpQHISNJpaYEQ1BM3vZr0x1FufL6jXAqZk3ilF # 3KQkkSejKUjzUux02HcTAMr9pRUWC5tX5LFME1J9BXFXl0YyMWBVYsJER8/mIboA # 4SBmzrXN7zOKj8tlN7PG3Mc/K7cZXMwa2wmREgf7fgnMdbFKiqmZw3TdgVUr+wGn # 81VeFjPFgZKvJKpTwNEiKjYKpk+OsNyZO4Yke22YoID5Yaanqv6ULTmZMOPPBdRl # aofhBupLyYRZfrx3dRQ+gbPbyVJn77qBHTlx8VSk9ooWjIXEidKDjfkUv3ksQMyC # Py7AUD8FO5vvemnlUhIyuW7z+SLdO+aovEfrFtQwWgRy8EThVPqi3x5S0Fv0vt0o # 7eXxwF6Q8IYlIW/HgQal6d8ezQ31KjCFAasn58Nc4hM5QWqcc/b+wVXysqC5nJ3n # ctkydLnpnqLg0vrDtvl+aJl7sCLno640PpZAtTNJJt7M8WKs # SIG # End signature block |