ozo-ad-windows-enumerate-directory-users.ps1
#Requires -Modules ActiveDirectory,ImportExcel,@{ModuleName="OZO";ModuleVersion="1.6.0"},OZOFiles,OZOLogger -Version 5.1 <#PSScriptInfo .VERSION 1.0.0 .GUID 7465a5f8-752f-4b68-a91c-b681bc639e81 .AUTHOR Andy Lievertz <alievertz@onezeroone.dev> .COMPANYNAME One Zero One .COPYRIGHT This script is released under the terms of the GNU General Public License ("GPL") version 2.0. .TAGS .LICENSEURI https://github.com/onezeroone-dev/OZO-AD-Windows-Enumrate-Directory-Users/blob/main/LICENSE .PROJECTURI https://github.com/onezeroone-dev/OZO-AD-Windows-Enumrate-Directory-Users .ICONURI .EXTERNALMODULEDEPENDENCIES ActiveDirectory,ImportExcel .REQUIREDSCRIPTS .EXTERNALSCRIPTDEPENDENCIES .RELEASENOTES https://github.com/onezeroone-dev/OZO-AD-Windows-Enumrate-Directory-Users/blob/main/CHANGELOG.md #> <# .SYNOPSIS See description. .DESCRIPTION Enumerates the directories and files in a given path and produces an Excel report containing users, email addresses, groups, and last modified child date. .PARAMETER OutDir Directory for the Excel report. Defaults to the current directory. .PARAMETER Path The path to inspect. Defaults to the current directory. .LINK https://github.com/onezeroone-dev/OZO-AD-Windows-Enumrate-Directory-Users/blob/main/README.md #> # PARAMETERS [CmdletBinding(SupportsShouldProcess = $true)] Param ( [Parameter(Mandatory=$false,HelpMessage="Path for the Excel report")][String]$OutDir = (Get-Location), [Parameter(Mandatory=$false,HelpMessage="Path to inspect")][String]$Path = (Get-Location) ) # CLASSES Class OZOMain { # PROPERTIES: Booleans, Strings [Boolean] $Validates = $true [String] $excelPath = $null [String] $outDir = $null [String] $Path = $null # PROPERTIES: PSCustomObjects [PSCustomObject] $ozoLogger = $null # PROPERTIES: Lists [System.Collections.Generic.List[PSCustomObject]] $childItems = @() # METHODS # Constructor method OZOMain($OutDir,$Path) { # Set properties $this.outDir = $OutDir $this.Path = $Path # Create a logger $this.ozoLogger = (New-OZOLogger) # Log a process start message $this.ozoLogger.Write("Starting process.","Information") # Determine if the configuation is valid If (($this.ValidateEnvironment()) -eq $true) { # Call GetItems to generate OZOItem objects $this.GetChildItems() } # Report $this.Report() # Log a process end message $this.ozoLogger.Write(("Process complete."),"Information") } # Environment validation method Hidden [Boolean] ValidateEnvironment() { # Control variable [Boolean] $Return = $true # Determine if the outDir exists If ([Boolean](Test-Path -Path $this.outDir) -eq $true) { # Output directory exists; set the Excel path $this.excelPath = (Join-Path -Path $this.outDir -ChildPath ((Get-OZO8601Date -Time) + "-ozo-ad-windows-directory-users.xlsx")) } Else { # Output directory does not exist; report $this.ozoLogger.Write(("Output directory is invalid or inaccessible."),"Error") $Return = $false } # Return return $Return } # GetItems method Hidden [Void] GetChildItems() { # Iterate through the child items ForEach ($childItem in (Get-ChildItem -Path $this.Path)) { # Add an OZOitem object to the Items list $this.childItems.Add(([OZOChildItem]::new($childItem))) } } # Report method Hidden [Void] Report() { # Determine if any ChildItems were processed If ($this.ChildItems.Count -gt 0) { # At least one ChildItem was processed; produce the Item Detail sheet $this.childItems | Select-Object -Property @{Name="Name";Expression={$_.childItem.Name}}, @{Name="Path";Expression={$_.ozoDirectorySummary.Path}}, @{Name="Last Modified";Expression={$_.ozoDirectorySummary.newestChildWriteTime}}, @{Name="Total size (GB)";Expression={($_.ozoDirectorySummary.totalSize / 1073741824)}}, @{Name="Long paths";Expression={[Boolean]$_.ozoDirectorySummary.longPaths}}, @{Name="Problem paths";Expression={[Boolean]$_.ozoDirectorySummary.problemPaths}}, @{Name="Messages";Expression={$_.Messages -Join "; "}} | Export-Excel -WorksheetName "Item Detail" -Path $this.excelPath # Produce the sheet detailing all unique users found for all child items $this.childItems.adObjects | Where-Object {$null -ne $_.adUser} | Select-Object -Unique -Property @{Name="Last Name";Expression={$_.adUser.Surname}}, @{Name="First Name";Expression={$_.adUser.GivenName}}, @{Name="Account";Expression={$_.adUser.SamAccountName}}, @{Name="Email Address";Expression={$_.adUser.EmailAddress}} | Sort-Object -Property "Last Name","First Name","Account" | Export-Excel -WorksheetName "Users" -Path $this.excelPath # Produce the sheet detailing all unique groups found for all items $this.childItems.adObjects | Where-Object {$null -ne $_.adGroup} | Select-Object -Unique -Property @{Name="Group Name";Expression={$_.adGroup.Name}} | Export-Excel -WorksheetName "Groups" -Path $this.excelPath # Determine if there are any invalid SIDs If (($this.childItems.adObjects | Where-Object {$_.Validates -eq $false}).Count -gt 0) { # Found invalid SIDs; produce the sheet detailing all unique invalid SIDs $this.childItems.adObjects | Where-Object {$_.Validates -eq $false} | Select-Object -Unique -Property @{Name="SID";Expression={$_.objectSID}},@{Name="Messasges";Expression={$_.Messages -Join "; "}} | Export-Excel -WorksheetName "Invalid Objects" -Path $this.excelPath } # Determine if there are any long paths If (($this.childItems.ozoDirectorySummary.longPaths).Count -gt 0) { # Found long paths on one or more objects; produce sheet detailing all long paths $this.childItems.ozoDirectorySummary.longPaths | Select-Object -Property @{Name="Path";Expression={$_.FullName}},@{Name="Path Length";Expression={$_.FullName.Length}} | Export-Excel -WorksheetName "Long Paths" -Path $this.excelPath } # Determine if there are any problem paths If (($this.childItems.ozoDirectorySummary.problemPaths).Count -gt 0) { # Found problem paths on one or more objects; produce sheet detailing all problem paths $this.childItems.ozoDirectorySummary.problemPaths | Select-Object -Property @{Name="Path";Expression={$_.FullName}},@{Name="Error Message";Expression={$_.ErrorMessage}} | Export-Excel -WorksheetName "Problem Paths" -Path $this.excelPath } } Else { # No ChildItems were processed $this.ozoLogger.Write("No child items were processed.","Warning") } } } Class OZOChildItem { # PROPERTIES: FileSystemInfo [System.IO.FileSystemInfo] $childItem = $null # PROPERTIES: PSCustomObjects [PSCustomObject] $ozoDirectorySummary = $null # PROPERTIES: PSCustomObject Lists [System.Collections.Generic.List[PSCustomObject]] $adObjects = @() # PROPERTIES: String Lists [System.Collections.Generic.List[String]] $Messages = @() # METHODS # Constructor method OZOChildItem($ChildItem) { # Set properties $this.childItem = $ChildItem # Get directory summary $this.ozoDirectorySummary = (Get-OZODirectorySummary -Path $this.childItem.FullName) # Iterate through the SIDs in the directory summary ForEach ($objectSID in $this.ozoDirectorySummary.objectSIDs) { # Determine if identity reference is a a domain ID If ($objectSID -Like "S-1-5-21*") { # objectSID is a domain ID; add an OZOADObject to the adObjects list $this.adObjects.Add(([OZOADObject]::new($objectSID))) } } # Iterate through the valid adObjects that contain an AD group ForEach ($adObject in ($this.adObjects | Where-Object {$_.Validates -eq $true -And $null -ne $_.adGroup})) { # Iterate through the members of the group, recusrively ForEach ($groupMember in (Get-ADGroupMember -Identity $adObject.objectSID -Recursive)) { # Try to get the SID for this user Try { $userSID = (Get-ADUser -Ideneity $groupMember -ErrorAction Stop).SID # Success; determine if adObjects does not already contain this SID If ($this.adObjects.objectSID -NotContains $userSID) { # adObjects does not already contain an object with this SID; add it $this.adObjects.Add(([OZOADObject]::new($userSID))) } } Catch { # Failure $this.Messages.Add(("While processing the " + $adObject.adGroup.Name + " [recursive] group members, unable to get SID for user with DN " + $groupMember + ". Error message is: " + $_)) } } } } } Class OZOADObject { # PROPERTIES: Booleans, Strings [Boolean] $Validates = $true [String] $objectSID = $null # PROPERTIES: PSCustomObjects [PSCustomObject] $adGroup = $null [PSCustomObject] $adObject = $null [PSCustomObject] $adUser = $null # PROPERTIES: String Lists [System.Collections.Generic.List[String]] $Messages = @() # METHODS # Constructor method OZOADObject($ObjectSID) { # Set properties $this.objectSID = $ObjectSID # Try to get the AD object Try { $this.adObject = (Get-ADObject -Filter {objectSid -eq $this.objectSID} -ErrorAction Stop) # Success; switch on objectClass Switch ($this.adObject.objectClass) { "user" { $this.Validates = $this.GetADUser() } "group" { $this.Validates = $this.GetADGroup() } default { $this.Messages.Add(("ObjectClass " + $this.adObject.objectClass + " is not handled")) $this.Validates -eq $false } } } Catch { # Failure $this.Messages.Add(("Unable to get AD object. Error message is: " + $_)) } } # Get AD User method Hidden [Boolean] GetADUser() { # Control variable [Boolean] $Return = $true # Determine that the object is valid and not null and class is User If ($this.Validates -eq $true -And $null -ne $this.adObject -And $this.adObject.objectClass -eq "user") { # Valid, not null, and user class; try to get the AD user Try { $this.adUser = (Get-ADUser -Identity $this.objectSID -Properties SamAccountName,GivenName,Surname,EmailAddress -ErrorAction Stop) # Success; determine if user is disabled If ($this.adUser.Enabled -eq $false) { # User is disabled $this.Messages.Add("User is disabled") $Return = $false } } Catch { # Failure $this.Messages.Add(("Unable to get AD user object. Error message is: " + $_)) $Return = $false } # Make sure group is null $this.adGroup = $null } # Return return $Return } # Get AD Group method Hidden [Boolean] GetADGroup() { # Control variable [Boolean] $Return = $true # Determine that the object is valid and not null and class is Group If ($this.Validates -eq $true -And $null -ne $this.adObject -And $this.adObject.objectClass -eq "group") { # Valid, not null, and group class; try to get the group Try { $this.adGroup = (Get-ADGroup -Identity $this.objectSID -ErrorAction Stop) # Success } Catch { # Failure $this.Messages.Add(("Unable to get AD group object. Error message is: " + $_)) $Return = $false } # Make sure user is null $this.adUser = $null } # Return return $Return } } # Create a Main object [OZOMain]::new($OutDir,$Path) | Out-Null # SIG # Begin signature block # MIIfcQYJKoZIhvcNAQcCoIIfYjCCH14CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCARlBjK0tlQ2jAB # DRDor8fogYuWuNVSPI5hkN+CKdb9HaCCDPgwggZyMIIEWqADAgECAghkM1HTxzif # CDANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMx # EDAOBgNVBAcMB0hvdXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8G # A1UEAwwoU1NMLmNvbSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTAe # Fw0xNjA2MjQyMDQ0MzBaFw0zMTA2MjQyMDQ0MzBaMHgxCzAJBgNVBAYTAlVTMQ4w # DAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENv # cnAxNDAyBgNVBAMMK1NTTC5jb20gQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBD # QSBSU0EgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCfgxNzqrDG # bSHL24t6h3TQcdyOl3Ka5LuINLTdgAPGL0WkdJq/Hg9Q6p5tePOf+lEmqT2d0bKU # Vz77OYkbkStW72fL5gvjDjmMxjX0jD3dJekBrBdCfVgWQNz51ShEHZVkMGE6ZPKX # 13NMfXsjAm3zdetVPW+qLcSvvnSsXf5qtvzqXHnpD0OctVIFD+8+sbGP0EmtpuNC # GVQ/8y8Ooct8/hP5IznaJRy4PgBKOm8yMDdkHseudQfYVdIYyQ6KvKNc8HwKp4WB # wg6vj5lc02AlvINaaRwlE81y9eucgJvcLGfE3ckJmNVz68Qho+Uyjj4vUpjGYDdk # jLJvSlRyGMwnh/rNdaJjIUy1PWT9K6abVa8mTGC0uVz+q0O9rdATZlAfC9KJpv/X # gAbxwxECMzNhF/dWH44vO2jnFfF3VkopngPawismYTJboFblSSmNNqf1x1KiVgMg # Lzh4gL32Bq5BNMuURb2bx4kYHwu6/6muakCZE93vUN8BuvIE1tAx3zQ4XldbyDge # VtSsSKbt//m4wTvtwiS+RGCnd83VPZhZtEPqqmB9zcLlL/Hr9dQg1Zc0bl0EawUR # 0tOSjAknRO1PNTFGfnQZBWLsiePqI3CY5NEv1IoTGEaTZeVYc9NMPSd6Ij/D+KNV # t/nmh4LsRR7Fbjp8sU65q2j3m2PVkUG8qQIDAQABo4H7MIH4MA8GA1UdEwEB/wQF # MAMBAf8wHwYDVR0jBBgwFoAU3QQJB6L1en1SUxKSle44gCUNplkwMAYIKwYBBQUH # AQEEJDAiMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTARBgNVHSAE # CjAIMAYGBFUdIAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwOwYDVR0fBDQwMjAwoC6g # LIYqaHR0cDovL2NybHMuc3NsLmNvbS9zc2wuY29tLXJzYS1Sb290Q0EuY3JsMB0G # A1UdDgQWBBRUwv4QlQCTzWr158DX2bJLuI8M4zAOBgNVHQ8BAf8EBAMCAYYwDQYJ # KoZIhvcNAQELBQADggIBAPUPJodwr5miyvXWyfCNZj05gtOII9iCv49UhCe204MH # 154niU2EjlTRIO5gQ9tXQjzHsJX2vszqoz2OTwbGK1mGf+tzG8rlQCbgPW/M9r1x # xs19DiBAOdYF0q+UCL9/wlG3K7V7gyHwY9rlnOFpLnUdTsthHvWlM98CnRXZ7WmT # V7pGRS6AvGW+5xI+3kf/kJwQrfZWsqTU+tb8LryXIbN2g9KR+gZQ0bGAKID+260P # Z+34fdzZcFt6umi1s0pmF4/n8OdX3Wn+vF7h1YyfE7uVmhX7eSuF1W0+Z0duGwdc # +1RFDxYRLhHDsLy1bhwzV5Qe/kI0Ro4xUE7bM1eV+jjk5hLbq1guRbfZIsr0WkdJ # LCjoT4xCPGRo6eZDrBmRqccTgl/8cQo3t51Qezxd96JSgjXktefTCm9r/o35pNfV # HUvnfWII+NnXrJlJ27WEQRQu9i5gl1NLmv7xiHp0up516eDap8nMLDt7TAp4z5T3 # NmC2gzyKVMtODWgqlBF1JhTqIDfM63kXdlV4cW3iSTgzN9vkbFnHI2LmvM4uVEv9 # XgMqyN0eS3FE0HU+MWJliymm7STheh2ENH+kF3y0rH0/NVjLw78a3Z9UVm1F5VPz # iIorMaPKPlDRADTsJwjDZ8Zc6Gi/zy4WZbg8Zv87spWrmo2dzJTw7XhQf+xkR6Od # MIIGfjCCBGagAwIBAgIQZ2iSsNbwOsjnLExSAX6F6DANBgkqhkiG9w0BAQsFADB4 # MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x # ETAPBgNVBAoMCFNTTCBDb3JwMTQwMgYDVQQDDCtTU0wuY29tIENvZGUgU2lnbmlu # ZyBJbnRlcm1lZGlhdGUgQ0EgUlNBIFIxMB4XDTI0MTExNjEwMzUyOFoXDTI1MTEx # NjEwMzUyOFowZTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCENvbG9yYWRvMQ8wDQYD # VQQHDAZEZW52ZXIxGDAWBgNVBAoMD0FuZHJldyBMaWV2ZXJ0ejEYMBYGA1UEAwwP # QW5kcmV3IExpZXZlcnR6MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA # vIBAQzK0aahepOrPmvCEqfd6dMZC4GvV7kflKwrn4QPJGfqhFmUtadP1e3ange8O # QZ3/w7UjOTAUNUHfhjbSgUBlKjbS6EWQKZuRFzI3SNkMJkcjTX4uS2P4QsnwM+SW # IE5me3CTssdjtgue+Iiy53TMgW8JpoxiULVxmm3bhCRUAgxWeT6tzjytR1UyGcMc # cm/YE6TOgsCHiZoo4X4HJD9iHDrNldArq04Jl6FsADxEswttKyfqpIRJLoAysVl1 # f8CEDBwhszJrEXBnAlWViJFfNY+dKP4jhf7lLqSvPCuADqP2jvM0Ym5I8qDGMz9j # XPSMLF58MFB4vM4viS7nLRFJ8S1Q98vQvB8W4kk0WPuiZbZTHsROzohE1VSbLnIY # ag5dDOWI8L6yutAsfdZFYFmSTKcMSiOj5VbK4LhAJUL2G8vPwpTGFgr+cEp0p62F # P0WXK+/cRfGqodI5S+bg+9rQTD9zf829DwraSRAt5P5zrQk4WPst3JW/vIKNx7cV # AgMBAAGjggGVMIIBkTAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFFTC/hCVAJPN # avXnwNfZsku4jwzjMHoGCCsGAQUFBwEBBG4wbDBIBggrBgEFBQcwAoY8aHR0cDov # L2NlcnQuc3NsLmNvbS9TU0xjb20tU3ViQ0EtQ29kZVNpZ25pbmctUlNBLTQwOTYt # UjEuY2VyMCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3NsLmNvbTBRBgNVHSAE # SjBIMAgGBmeBDAEEATA8BgwrBgEEAYKpMAEDAwEwLDAqBggrBgEFBQcCARYeaHR0 # cHM6Ly93d3cuc3NsLmNvbS9yZXBvc2l0b3J5MBMGA1UdJQQMMAoGCCsGAQUFBwMD # ME0GA1UdHwRGMEQwQqBAoD6GPGh0dHA6Ly9jcmxzLnNzbC5jb20vU1NMY29tLVN1 # YkNBLUNvZGVTaWduaW5nLVJTQS00MDk2LVIxLmNybDAdBgNVHQ4EFgQUSj8HrSK7 # f/j+Dz31jJFhOF7rJUMwDgYDVR0PAQH/BAQDAgeAMA0GCSqGSIb3DQEBCwUAA4IC # AQBf4lcc6FUJ1W/opNz8yjS9qLUy9cQt0s35BhasB5QoTbDaW4jv9xnFGhQVg6n+ # jhL0i94Vsywd/MRBb8lYGpuBZnS/7LHuRZu7qUuud+IMDyRHIyBK6koN5bfyA5VY # c7bFbNpbe1s1hMWke8di4qgMLZKDfyG/RtA0swf5t4UgQLPP0h+koZ8X8V5+P0V0 # 1HsdXyXd+ojo38EoZyCKfQL2aAwMPwzZfCbmI5SRXNOc6K8oqXzQcendhlKSfVBo # Zgpi+1updqbD4jmJfYdK5AYPxJ3YH6td6ETtr8owL+bmX8lQjlXPOwVnC11rVlNB # VjqtaJRUClLtiNiYSTKVfjdmGVJ4+sNov0dWhHc0A9o5NX/05VVYTlImuJpnG5Og # o7w6kWRdsgE8gM58jWf7XfI6aQS0Np/z2B+ZBj0K93khEHBX7cvvORa92LCHiVeP # km+zEAMXgxIPs/e8cmcc/o3CORgzEwxlH9Z3UOWCuXSHD3P2RPNDAY+WPdjSHm9f # JFlGq+f9iKyedxYa/NNjNag/5EbZ+Z2NldtSMNeFdsejGJ/TJHF1PyJd4aXx9J1i # B/IZBOoJYyh9xpQ3ljZUKE/4otPi7INpuDFwgWiUHZZJVvrGTWwxH1Yhf8P+VpFf # aNqsBuvklUcUDs3RNE0f1qlgFfcnAepFF+RiBRqmsj29fjGCEc8wghHLAgEBMIGM # MHgxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3Rv # bjERMA8GA1UECgwIU1NMIENvcnAxNDAyBgNVBAMMK1NTTC5jb20gQ29kZSBTaWdu # aW5nIEludGVybWVkaWF0ZSBDQSBSU0EgUjECEGdokrDW8DrI5yxMUgF+hegwDQYJ # YIZIAWUDBAIBBQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMxDAYK # KwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG # 9w0BCQQxIgQgf770Vpd7OuJneXDOWkWO6jvHEZDcGfXqfAOjuIrcBtMwDQYJKoZI # hvcNAQEBBQAEggGAZBBaEtX4260b71c0BQdvQhDZAsaAYZw0vR/wRkPq0+IdUDiD # umTdRwsiUiFokJpK0qQ8RYO+7idsF0KQPkZo5Yat6qC33PetgCZF7U00wtBZWLsY # 1toYJREZq8LybY5vCx02nWI9YUxT+v7bgHQBYNwC7T8ZmZGGnyigR3q0hU29d661 # IALLRZAGvvLpVpKlHiyy5yc/cK+tIyJ8pdFsdc2X4sd+uLKc2/m/tA2qJ33MPbe/ # QekTfRFSgthh/Q4t9SOtJCzXcOS7s9wu7H0BP7uc1ihLBslYq0K/ryTx/UbyIBIq # 6Ht7mV7DSeO+oo8Y+UXodIp+Dp/o9uYP0ts9aKioFHY31jBkVLyzqmkjwST33HfI # kdAnRPSuo2WXyyygWesCVIN/1cdVeNOP0KfNyTMwyGPAIFVnJ3+7uxWZqnLKuODX # HF8Dz652+zgiXoQrYGW+kZ81XmT10XlWLtKdd5CXOVHAiKATipTT2q7fmRJ7IFMN # fs/wS8nTdtKnYlhDoYIPFTCCDxEGCisGAQQBgjcDAwExgg8BMIIO/QYJKoZIhvcN # AQcCoIIO7jCCDuoCAQMxDTALBglghkgBZQMEAgEwdwYLKoZIhvcNAQkQAQSgaARm # MGQCAQEGDCsGAQQBgqkwAQMGATAxMA0GCWCGSAFlAwQCAQUABCArPJCh2s4tzI2v # SFTSjBihmZPvxKmu1mc1gsR6NH0UqgIIN1mw0DG4X8gYDzIwMjUwNTIwMTgxMTI4 # WjADAgEBoIIMADCCBPwwggLkoAMCAQICEFparOgaNW60YoaNV33gPccwDQYJKoZI # hvcNAQELBQAwczELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQH # DAdIb3VzdG9uMREwDwYDVQQKDAhTU0wgQ29ycDEvMC0GA1UEAwwmU1NMLmNvbSBU # aW1lc3RhbXBpbmcgSXNzdWluZyBSU0EgQ0EgUjEwHhcNMjQwMjE5MTYxODE5WhcN # MzQwMjE2MTYxODE4WjBuMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAO # BgNVBAcMB0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMSowKAYDVQQDDCFTU0wu # Y29tIFRpbWVzdGFtcGluZyBVbml0IDIwMjQgRTEwWTATBgcqhkjOPQIBBggqhkjO # PQMBBwNCAASnYXL1MOl6xIMUlgVC49zonduUbdkyb0piy2i8t3JlQEwA74cjK8g9 # mRC8GH1cAAVMIr8M2HdZpVgkV1LXBLB8o4IBWjCCAVYwHwYDVR0jBBgwFoAUDJ0Q # JY6apxuZh0PPCH7hvYGQ9M8wUQYIKwYBBQUHAQEERTBDMEEGCCsGAQUFBzAChjVo # dHRwOi8vY2VydC5zc2wuY29tL1NTTC5jb20tdGltZVN0YW1waW5nLUktUlNBLVIx # LmNlcjBRBgNVHSAESjBIMDwGDCsGAQQBgqkwAQMGATAsMCoGCCsGAQUFBwIBFh5o # dHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkwCAYGZ4EMAQQCMBYGA1UdJQEB # /wQMMAoGCCsGAQUFBwMIMEYGA1UdHwQ/MD0wO6A5oDeGNWh0dHA6Ly9jcmxzLnNz # bC5jb20vU1NMLmNvbS10aW1lU3RhbXBpbmctSS1SU0EtUjEuY3JsMB0GA1UdDgQW # BBRQTySs77U+YxMjCZIm7Lo6luRdIjAOBgNVHQ8BAf8EBAMCB4AwDQYJKoZIhvcN # AQELBQADggIBAJigjwMAkbyrxGRBf0Ih4r+rbCB57lTuwViC6nH2fZSciMogpqSz # rSeVZ2eIb5vhj9rT7jqWXZn02Fncs4YTrA1QyxJW36yjC4jl5/bsFCaWuXzGXt2Y # 6Ifp//A3Z0sNTMWTTBobmceM3sqnovdX9ToRFP+29r5yQnPcgRTI2PvrVSqLxY9E # yk9/0cviM3W29YBl080ENblRcu3Y8RsfzRtVT/2snuDocRxvRYmd0TPaMgIj2xII # 651QnPp1hiq9xU0AyovLzbsi5wlR5Ip4i/i8+x+HwYJNety5cYtdWJ7uQP6YaZtW # /jNoHp76qNftq/IlSx6xEYBRjFBxHSq2fzhUQ5oBawk2OsZ2j0wOf7q7AqjCt6t/ # +fbmWjrAWYWZGj/RLjltqdFPBpIKqdhjVIxaGgzVhaE/xHKBg4k4DfFZkBYJ9BWu # P93Tm+paWBDwXI7Fg3alGsboErWPWlvwMAmpeJUjeKLZY26JPLt9ZWceTVWuIyuj # erqb5IMmeqLJm5iFq/Qy4YPGyPiolw5w1k9OeO4ErmS2FKvk1ejvw4SWR+S1VyWn # ktY442WaoStxBCCVWZdMWFeB+EpL8uoQNq1MhSt/sIUjUudkyZLIbMVQjj7b6gPX # nD6mS8FgWiCAhuM1a/hgA+6o1sJWizHdmcpYDhyNzorf9KVRE6iR7rcmMIIG/DCC # BOSgAwIBAgIQbVIYcIfoI02FYADQgI+TVjANBgkqhkiG9w0BAQsFADB8MQswCQYD # VQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24xGDAWBgNV # BAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBSb290IENlcnRp # ZmljYXRpb24gQXV0aG9yaXR5IFJTQTAeFw0xOTExMTMxODUwMDVaFw0zNDExMTIx # ODUwMDVaMHMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwH # SG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxLzAtBgNVBAMMJlNTTC5jb20gVGlt # ZXN0YW1waW5nIElzc3VpbmcgUlNBIENBIFIxMIICIjANBgkqhkiG9w0BAQEFAAOC # Ag8AMIICCgKCAgEArlEQE9L5PCCgIIXeyVAcZMnh/cXpNP8KfzFI6HJaxV6oYf3x # h/dRXPu35tDBwhOwPsJjoqgY/Tg6yQGBqt65t94wpx0rAgTVgEGMqGri6vCI6rEt # SZVy9vagzTDHcGfFDc0Eu71mTAyeNCUhjaYTBkyANqp9m6IRrYEXOKdd/eREsqVD # mhryd7dBTS9wbipm+mHLTHEFBdrKqKDM3fPYdBOro3bwQ6OmcDZ1qMY+2Jn1o0l4 # N9wORrmPcpuEGTOThFYKPHm8/wfoMocgizTYYeDG/+MbwkwjFZjWKwb4hoHT2WK8 # pvGW/OE0Apkrl9CZSy2ulitWjuqpcCEm2/W1RofOunpCm5Qv10T9tIALtQo73GHI # lIDU6xhYPH/ACYEDzgnNfwgnWiUmMISaUnYXijp0IBEoDZmGT4RTguiCmjAFF5OV # NbY03BQoBb7wK17SuGswFlDjtWN33ZXSAS+i45My1AmCTZBV6obAVXDzLgdJ1A1r # yyXz4prLYyfJReEuhAsVp5VouzhJVcE57dRrUanmPcnb7xi57VPhXnCuw26hw1Hd # +ulK3jJEgbc3rwHPWqqGT541TI7xaldaWDo85k4lR2bQHPNGwHxXuSy3yczyOg57 # TcqqG6cE3r0KR6jwzfaqjTvN695GsPAPY/h2YksNgF+XBnUD9JBtL4c34AcCAwEA # AaOCAYEwggF9MBIGA1UdEwEB/wQIMAYBAf8CAQAwHwYDVR0jBBgwFoAU3QQJB6L1 # en1SUxKSle44gCUNplkwgYMGCCsGAQUFBwEBBHcwdTBRBggrBgEFBQcwAoZFaHR0 # cDovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkvU1NMY29tUm9vdENlcnRpZmljYXRp # b25BdXRob3JpdHlSU0EuY3J0MCAGCCsGAQUFBzABhhRodHRwOi8vb2NzcHMuc3Ns # LmNvbTA/BgNVHSAEODA2MDQGBFUdIAAwLDAqBggrBgEFBQcCARYeaHR0cHM6Ly93 # d3cuc3NsLmNvbS9yZXBvc2l0b3J5MBMGA1UdJQQMMAoGCCsGAQUFBwMIMDsGA1Ud # HwQ0MDIwMKAuoCyGKmh0dHA6Ly9jcmxzLnNzbC5jb20vc3NsLmNvbS1yc2EtUm9v # dENBLmNybDAdBgNVHQ4EFgQUDJ0QJY6apxuZh0PPCH7hvYGQ9M8wDgYDVR0PAQH/ # BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQCSGXUNplpCzxkH2fL8lPrAm/AV6USW # Wi9xM91Q5RN7mZN3D8T7cm1Xy7qmnItFukgdtiUzLbQokDJyFTrF1pyLgGw/2hU3 # FJEywSN8crPsBGo812lyWFgAg0uOwUYw7WJQ1teICycX/Fug0KB94xwxhsvJBiRT # pQyhu/2Kyu1Bnx7QQBA1XupcmfhbQrK5O3Q/yIi//kN0OkhQEiS0NlyPPYoRboHW # C++wogzV6yNjBbKUBrMFxABqR7mkA0x1Kfy3Ud08qyLC5Z86C7JFBrMBfyhfPpKV # lIiiTQuKz1rTa8ZW12ERoHRHcfEjI1EwwpZXXK5J5RcW6h7FZq/cZE9kLRZhvnRK # tb+X7CCtLx2h61ozDJmifYvuKhiUg9LLWH0Or9D3XU+xKRsRnfOuwHWuhWch8G7k # EmnTG9CtD9Dgtq+68KgVHtAWjKk2ui1s1iLYAYxnDm13jMZm0KpRM9mLQHBK5Gb4 # dFgAQwxOFPBslf99hXWgLyYE33vTIi9p0gYqGHv4OZh1ElgGsvyKdUUJkAr5hfbD # X6pYScJI8v9VNYm1JEyFAV9x4MpskL6kE2Sy8rOqS9rQnVnIyPWLi8N9K4GZvPit # /Oy+8nFL6q5kN2SZbox5d69YYFe+rN1sDD4CpNWwBBTI/q0V4pkgvhL99IV2Xasj # HZf4peSrHdL4RjGCAlcwggJTAgEBMIGHMHMxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI # DAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjERMA8GA1UECgwIU1NMIENvcnAxLzAt # BgNVBAMMJlNTTC5jb20gVGltZXN0YW1waW5nIElzc3VpbmcgUlNBIENBIFIxAhBa # WqzoGjVutGKGjVd94D3HMAsGCWCGSAFlAwQCAaCCAWEwGgYJKoZIhvcNAQkDMQ0G # CyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yNTA1MjAxODExMjhaMCgGCSqG # SIb3DQEJNDEbMBkwCwYJYIZIAWUDBAIBoQoGCCqGSM49BAMCMC8GCSqGSIb3DQEJ # BDEiBCCPQ9eqiNP2Bl2QcczoM7Qugl027BTxaoa0PnjD3bLBPTCByQYLKoZIhvcN # AQkQAi8xgbkwgbYwgbMwgbAEIJ1xf43CN2Wqzl5KsOH1ddeaF9Qc7tj9r+8D/T29 # iUfnMIGLMHekdTBzMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNV # BAcMB0hvdXN0b24xETAPBgNVBAoMCFNTTCBDb3JwMS8wLQYDVQQDDCZTU0wuY29t # IFRpbWVzdGFtcGluZyBJc3N1aW5nIFJTQSBDQSBSMQIQWlqs6Bo1brRiho1XfeA9 # xzAKBggqhkjOPQQDAgRGMEQCICzilBuaNR/eETKSCe5DnZEiISGeyGFJ0VraNa0p # XhovAiASVDwxUjYaUqPsNTb+mCios977c1KJmSVpG6CT/Oxz1Q== # SIG # End signature block |