GeneralFunctions.ps1
<#
.NOTES =========================================================================== Created on: 12/29/2016 2:46 PM Created by: Vikas Sukhija Organization: https://techwizard.cloud Filename: Generalutilities.ps1 Update: 7/15/2020 Converted to module Update: 7/23/2020 updated getauth with validation script update: 7/25/2020 rmeoved move-file unused function update: 7/25/2020 added read ini contnet function update: 7/25/2020 added save-encrypt function update: 9/2/2020 added new-randompassword function update: 9/16/2020 added get-adrecursive group function update: 12/30/2020 added get-adusermemberof function update: 4/28/2021 updated Get-ADGroupMembersRecursive function to include groups update: 4/1/2022 updated random password to atke any number of chars update: 6/8/2022 ADDED Set-IniContent and Out-IniFile from author Sean Seymour <seanjseymour@gmail.com> based on work by Oliver Lipkau <oliver@lipkau.net> =========================================================================== .DESCRIPTION General Utilities #> ######################get AD User member Of###################### Function Get-ADUserMemberOf { Param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$User, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String]$Group ) try{ $GroupDN = (Get-ADGroup $Group).DistinguishedName $UserDN = (Get-ADUser $User).DistinguishedName $Getaduser = Get-ADUser -Filter "memberOf -RecursiveMatch '$GroupDN'" -SearchBase $UserDN If($Getaduser) { $true } Else { $false } } catch{ } } #Get-ADUserMemberOf ######################get AD recursive group membership###################### Function Get-ADGroupMembersRecursive{ Param( [Parameter(Mandatory = $true,ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [String[]]$Groups, [ValidateNotNullOrEmpty()] [String[]]$Properties, [ValidateSet($true,$false)] [string]$ShowGroups ) Begin{ $Results = @() [String[]]$defaultproperties = "distinguishedName","name","objectClass","objectGUID","SamAccountName","SID" $Properties+=$defaultproperties $Properties = $Properties | Sort-Object -Unique } Process{ ForEach($adobj in $Groups){ $getgroupdn = (Get-ADGroup -identity $adobj).DistinguishedName $findallgroups = Get-ADGroup -identity $getgroupdn -Properties members| Select-Object -ExpandProperty members | get-adobject | Where-Object{$_.objectClass -eq "Group"} |Select DistinguishedName $Results+=$getgroupdn ForEach($Object in $findallgroups){ if($ShowGroups -eq $true){ Get-ADGroupMembersRecursive $Object.DistinguishedName -Properties $Properties -ShowGroups $true } else{ Get-ADGroupMembersRecursive $Object.DistinguishedName -Properties $Properties } } } } End{ $Results = $Results | Select-Object -Unique foreach($item in $Results){ $arrgroupmembers =@() if($ShowGroups -eq $true){ Get-ADGroup -id $item -Properties $Properties | Select-Object $Properties } $arrgroupmembers = Get-ADGroup -id $item -Properties members | Select-Object -ExpandProperty members |get-adobject | Where-Object{$_.objectClass -eq "user"} | Get-ADUser -properties $Properties | Select-Object $Properties $arrgroupmembers } } } #Get-ADGroupMembersRecursive ######################Authentication Function################################## Function Get-Auth { [CmdletBinding()] param ( [Parameter(Mandatory = $true,ParameterSetName = 'file')] [Parameter(Mandatory = $true,ParameterSetName = 'encrypt')] $userId, [Parameter(Mandatory = $true,ParameterSetName = 'file')] [ValidateScript({ if(-Not ($_ | Test-Path) ){throw "File or folder does not exist"} if(-Not ($_ | Test-Path -PathType Leaf) ){throw "The Path argument must be a file. Folder paths are not allowed."} if($_ -notmatch "(\.txt)"){throw "The file specified in the path argument must be either of type txt"} return $true })] [System.IO.FileInfo]$passwordfile, [Parameter(ParameterSetName = 'file',Position = 0)][switch]$file, [Parameter(ParameterSetName = 'encrypt',Position = 0)][switch]$encrypt, [Parameter(Mandatory = $true,ParameterSetName = 'encrypt')] [string]$password ) switch ($PsCmdlet.ParameterSetName) { "file"{ $encrypted1 = Get-Content $passwordfile $pwd = ConvertTo-SecureString -string $encrypted1 $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $userId, $pwd return $pwd, $Credential } "encrypt"{ $pwd = ConvertTo-SecureString -string $password $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $userId, $pwd return $pwd, $Credential } } }#get-auth ######################read INI files################################## Function Get-IniContent { [CmdletBinding()] Param( [ValidateNotNullOrEmpty()] [ValidateScript({(Test-Path $_) -and ((Get-Item $_).Extension -eq ".ini")})] [Parameter(ValueFromPipeline = $true,Mandatory = $true)] [string]$FilePath ) Begin {Write-Verbose -Message "$($MyInvocation.MyCommand.Name):: Function started"} Process { Write-Verbose -Message "$($MyInvocation.MyCommand.Name):: Processing file: $FilePath" $ini = @{} switch -regex -file $FilePath { "^\[(.+)\]$" # Section { $section = $matches[1] $ini[$section] = @{} $CommentCount = 0 } "^(;.*)$" # Comment { if (!($section)) { $section = "No-Section" $ini[$section] = @{} } $value = $matches[1] $CommentCount = $CommentCount + 1 $Name = "Comment" + $CommentCount $ini[$section][$Name] = $value } "(.+?)\s*=\s*(.*)" # Key { if (!($section)) { $section = "No-Section" $ini[$section] = @{} } $Name, $value = $matches[1..2] $ini[$section][$Name] = $value } } Write-Verbose -Message "$($MyInvocation.MyCommand.Name):: Finished Processing file: $FilePath" Return $ini } End {Write-Verbose -Message "$($MyInvocation.MyCommand.Name):: Function ended"} } #get-inicontent ##################Set-Inicontent################################################ Function Set-IniContent { <# .Synopsis Updates existing values or adds new key-value pairs to an INI file .Description Updates specified keys to new values in all sections or certain sections. Used to add new or change existing values. To comment, uncomment or remove keys use the related functions instead. The ini source can be specified by a file or piped in by the result of Get-IniContent. The modified content is returned as a ordered dictionary hashtable and can be piped to a file with Out-IniFile. .Notes Author : Sean Seymour <seanjseymour@gmail.com> based on work by Oliver Lipkau <oliver@lipkau.net> Source : https://github.com/lipkau/PsIni http://gallery.technet.microsoft.com/scriptcenter/ea40c1ef-c856-434b-b8fb-ebd7a76e8d91 Version : 1.0.0 - 2016/08/18 - SS - Initial release : 1.0.1 - 2016/12/29 - SS - Removed need for delimiters by making Sections a string array and NameValuePairs a hashtable. Thanks Oliver! #Requires -Version 2.0 .Inputs System.String System.Collections.IDictionary .Outputs System.Collections.Specialized.OrderedDictionary .Example $ini = Set-IniContent -FilePath "C:\myinifile.ini" -Sections 'Printers' -NameValuePairs @{'Name With Space' = 'Value1' ; 'AnotherName' = 'Value2'} ----------- Description Reads in the INI File c:\myinifile.ini, adds or updates the 'Name With Space' and 'AnotherName' keys in the [Printers] section to the values specified, and saves the modified ini to $ini. .Example Set-IniContent -FilePath "C:\myinifile.ini" -Sections 'Terminals','Monitors' -NameValuePairs @{'Updated=FY17Q2'} | Out-IniFile "C:\myinifile.ini" -Force ----------- Description Reads in the INI File c:\myinifile.ini and adds or updates the 'Updated' key in the [Terminals] and [Monitors] sections to the value specified. The ini is then piped to Out-IniFile to write the INI File to c:\myinifile.ini. If the file is already present it will be overwritten. .Example Get-IniContent "C:\myinifile.ini" | Set-IniContent -NameValuePairs @{'Headers' = 'True' ; 'Update' = 'False'} | Out-IniFile "C:\myinifile.ini" -Force ----------- Description Reads in the INI File c:\myinifile.ini using Get-IniContent, which is then piped to Set-IniContent to add or update the 'Headers' and 'Update' keys in all sections to the specified values. The ini is then piped to Out-IniFile to write the INI File to c:\myinifile.ini. If the file is already present it will be overwritten. .Example Get-IniContent "C:\myinifile.ini" | Set-IniContent -NameValuePairs @{'Updated'='FY17Q2'} -Sections '_' | Out-IniFile "C:\myinifile.ini" -Force ----------- Description Reads in the INI File c:\myinifile.ini using Get-IniContent, which is then piped to Set-IniContent to add or update the 'Updated' key that is orphaned, i.e. not specifically in a section. The ini is then piped to Out-IniFile to write the INI File to c:\myinifile.ini. .Link Get-IniContent Out-IniFile #> [CmdletBinding(DefaultParameterSetName = "File")] [OutputType( [System.Collections.IDictionary] )] Param ( # Specifies the path to the input file. [Parameter( Position = 0, Mandatory = $true, ParameterSetName = "File" )] [ValidateNotNullOrEmpty()] [String] $FilePath, # Specifies the Hashtable to be modified. # Enter a variable that contains the objects or type a command or expression that gets the objects. [Parameter( Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = "Object")] [ValidateNotNullOrEmpty()] [System.Collections.IDictionary] $InputObject, # Hashtable of one or more key names and values to modify. Required. [Parameter( Mandatory = $true, ParameterSetName = "File")] [Parameter( Mandatory = $true, ParameterSetName = "Object")] [ValidateNotNullOrEmpty()] [HashTable] $NameValuePairs, # String array of one or more sections to limit the changes to, separated by a comma. # Surrounding section names with square brackets is not necessary but is supported. # Ini keys that do not have a defined section can be modified by specifying '_' (underscore) for the section. [Parameter( ParameterSetName = "File" )] [Parameter( ParameterSetName = "Object" )] [ValidateNotNullOrEmpty()] [String[]] $Sections ) Begin { Write-Debug "PsBoundParameters:" $PSBoundParameters.GetEnumerator() | ForEach-Object { Write-Debug $_ } if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } Write-Debug "DebugPreference: $DebugPreference" Write-Verbose "$($MyInvocation.MyCommand.Name):: Function started" # Update or add the name/value pairs to the section. Function Update-IniEntry { param ($content, $section) foreach ($pair in $NameValuePairs.GetEnumerator()) { if (!($content[$section])) { Write-Verbose ("$($MyInvocation.MyCommand.Name):: '{0}' section does not exist, creating it." -f $section) $content[$section] = New-Object System.Collections.Specialized.OrderedDictionary([System.StringComparer]::OrdinalIgnoreCase) } Write-Verbose ("$($MyInvocation.MyCommand.Name):: Setting '{0}' key in section {1} to '{2}'." -f $pair.key, $section, $pair.value) $content[$section][$pair.key] = $pair.value } } } # Update the specified keys in the list, either in the specified section or in all sections. Process { # Get the ini from either a file or object passed in. if ($PSCmdlet.ParameterSetName -eq 'File') { $content = Get-IniContent $FilePath } if ($PSCmdlet.ParameterSetName -eq 'Object') { $content = $InputObject } # Specific section(s) were requested. if ($Sections) { foreach ($section in $Sections) { # Get rid of whitespace and section brackets. $section = $section.Trim() -replace '[][]', '' Write-Debug ("Processing '{0}' section." -f $section) Update-IniEntry $content $section } } else { # No section supplied, go through the entire ini since changes apply to all sections. foreach ($item in $content.GetEnumerator()) { $section = $item.key Write-Debug ("Processing '{0}' section." -f $section) Update-IniEntry $content $section } } Write-Output $content } End { Write-Verbose "$($MyInvocation.MyCommand.Name):: Function ended" } } ###########################out-ini############################################# Function Out-IniFile { <# .Synopsis Write hash content to INI file .Description Write hash content to INI file .Notes Author : Oliver Lipkau <oliver@lipkau.net> Blog : http://oliver.lipkau.net/blog/ Source : https://github.com/lipkau/PsIni http://gallery.technet.microsoft.com/scriptcenter/ea40c1ef-c856-434b-b8fb-ebd7a76e8d91 #Requires -Version 2.0 .Inputs System.String System.Collections.IDictionary .Outputs System.IO.FileSystemInfo .Example Out-IniFile $IniVar "C:\myinifile.ini" ----------- Description Saves the content of the $IniVar Hashtable to the INI File c:\myinifile.ini .Example $IniVar | Out-IniFile "C:\myinifile.ini" -Force ----------- Description Saves the content of the $IniVar Hashtable to the INI File c:\myinifile.ini and overwrites the file if it is already present .Example $file = Out-IniFile $IniVar "C:\myinifile.ini" -PassThru ----------- Description Saves the content of the $IniVar Hashtable to the INI File c:\myinifile.ini and saves the file into $file .Example $Category1 = @{“Key1”=”Value1”;”Key2”=”Value2”} $Category2 = @{“Key1”=”Value1”;”Key2”=”Value2”} $NewINIContent = @{“Category1”=$Category1;”Category2”=$Category2} Out-IniFile -InputObject $NewINIContent -FilePath "C:\MyNewFile.ini" ----------- Description Creating a custom Hashtable and saving it to C:\MyNewFile.ini .Link Get-IniContent #> [CmdletBinding()] [OutputType( [System.IO.FileSystemInfo] )] Param( # Adds the output to the end of an existing file, instead of replacing the file contents. [switch] $Append, # Specifies the file encoding. The default is UTF8. # # Valid values are: # -- ASCII: Uses the encoding for the ASCII (7-bit) character set. # -- BigEndianUnicode: Encodes in UTF-16 format using the big-endian byte order. # -- Byte: Encodes a set of characters into a sequence of bytes. # -- String: Uses the encoding type for a string. # -- Unicode: Encodes in UTF-16 format using the little-endian byte order. # -- UTF7: Encodes in UTF-7 format. # -- UTF8: Encodes in UTF-8 format. [ValidateSet("Unicode", "UTF7", "UTF8", "ASCII", "BigEndianUnicode", "Byte", "String")] [Parameter()] [String] $Encoding = "UTF8", # Specifies the path to the output file. [ValidateNotNullOrEmpty()] [ValidateScript( {Test-Path $_ -IsValid} )] [Parameter( Position = 0, Mandatory = $true )] [String] $FilePath, # Allows the cmdlet to overwrite an existing read-only file. Even using the Force parameter, the cmdlet cannot override security restrictions. [Switch] $Force, # Specifies the Hashtable to be written to the file. Enter a variable that contains the objects or type a command or expression that gets the objects. [Parameter( Mandatory = $true, ValueFromPipeline = $true )] [System.Collections.IDictionary] $InputObject, # Passes an object representing the location to the pipeline. By default, this cmdlet does not generate any output. [Switch] $Passthru, # Adds spaces around the equal sign when writing the key = value [Switch] $Loose, # Writes the file as "pretty" as possible # # Adds an extra linebreak between Sections [Switch] $Pretty ) Begin { Write-Debug "PsBoundParameters:" $PSBoundParameters.GetEnumerator() | ForEach-Object { Write-Debug $_ } if ($PSBoundParameters['Debug']) { $DebugPreference = 'Continue' } Write-Debug "DebugPreference: $DebugPreference" Write-Verbose "$($MyInvocation.MyCommand.Name):: Function started" function Out-Keys { param( [ValidateNotNullOrEmpty()] [Parameter( Mandatory, ValueFromPipeline )] [System.Collections.IDictionary] $InputObject, [ValidateSet("Unicode", "UTF7", "UTF8", "ASCII", "BigEndianUnicode", "Byte", "String")] [Parameter( Mandatory )] [string] $Encoding = "UTF8", [ValidateNotNullOrEmpty()] [ValidateScript( {Test-Path $_ -IsValid})] [Parameter( Mandatory, ValueFromPipelineByPropertyName )] [Alias("Path")] [string] $FilePath, [Parameter( Mandatory )] $Delimiter, [Parameter( Mandatory )] $MyInvocation ) Process { if (!($InputObject.get_keys())) { Write-Warning ("No data found in '{0}'." -f $FilePath) } Foreach ($key in $InputObject.get_keys()) { if ($key -match "^Comment\d+") { Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing comment: $key" "$($InputObject[$key])" | Out-File -Encoding $Encoding -FilePath $FilePath -Append } else { Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing key: $key" $InputObject[$key] | ForEach-Object { "$key$delimiter$_" } | Out-File -Encoding $Encoding -FilePath $FilePath -Append } } } } $delimiter = '=' if ($Loose) { $delimiter = ' = ' } # Splatting Parameters $parameters = @{ Encoding = $Encoding; FilePath = $FilePath } } Process { $extraLF = "" if ($Append) { Write-Debug ("Appending to '{0}'." -f $FilePath) $outfile = Get-Item $FilePath } else { Write-Debug ("Creating new file '{0}'." -f $FilePath) $outFile = New-Item -ItemType file -Path $Filepath -Force:$Force } if (!(Test-Path $outFile.FullName)) {Throw "Could not create File"} Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing to file: $Filepath" foreach ($i in $InputObject.get_keys()) { if (!($InputObject[$i].GetType().GetInterface('IDictionary'))) { #Key value pair Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing key: $i" "$i$delimiter$($InputObject[$i])" | Out-File -Append @parameters } elseif ($i -eq $script:NoSection) { #Key value pair of NoSection Out-Keys $InputObject[$i] ` @parameters ` -Delimiter $delimiter ` -MyInvocation $MyInvocation } else { #Sections Write-Verbose "$($MyInvocation.MyCommand.Name):: Writing Section: [$i]" # Only write section, if it is not a dummy ($script:NoSection) if ($i -ne $script:NoSection) { "$extraLF[$i]" | Out-File -Append @parameters } if ($Pretty) { $extraLF = "`r`n" } if ( $InputObject[$i].Count) { Out-Keys $InputObject[$i] ` @parameters ` -Delimiter $delimiter ` -MyInvocation $MyInvocation } } } Write-Verbose "$($MyInvocation.MyCommand.Name):: Finished Writing to file: $FilePath" } End { if ($PassThru) { Write-Debug ("Returning file due to PassThru argument.") Write-Output (Get-Item $outFile) } Write-Verbose "$($MyInvocation.MyCommand.Name):: Function ended" } } #############Checkgroup used for checking group in user acces extract########### function Group-Validate { [CmdletBinding()] param ( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] $User, [Parameter(Mandatory = $true)] $dom, $greport ) begin { Write-Host "Start Checking objects for group validation" -ForegroundColor Green $coll = @() $cdom = $dom + "\" + "*" } process { if ($User -like $cdom) { $User = [string]$User try {if (Get-Group $User -ErrorAction Stop) { $coll += $User }} catch { Write-Host "$User is not a valid group" -ForegroundColor yellow Add-Content $greport $User } } } end { Write-Host "----------end---------------" -ForegroundColor Green return $coll } } #################Check if folder is created################## function New-FolderCreation { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$foldername ) $logpath = (Get-Location).path + "\" + "$foldername" $testlogpath = Test-Path -Path $logpath if($testlogpath -eq $false) { #Start-ProgressBar -Title "Creating $foldername folder" -Timer 10 $null = New-Item -Path (Get-Location).path -Name $foldername -Type directory } } #########Random Password############## Function New-RandomPassword{ [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [int]$NumberofChars ) switch ($NumberofChars){ $NumberofChars { $Password = $null $Password += ([char[]]([char]33..[char]122) | sort {Get-Random})[0..$NumberofChars] -join '' $arrpassword = $Password.ToChararray() $randomarr = $arrpassword | Get-Random -Count $arrpassword.Length $Password = -join $randomarr return $Password } } } #######################Create Encryted password############### Function Save-EncryptedPassword { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] [string]$password, [Parameter(Mandatory = $true)] [ValidateScript({ if($_ -notmatch "(\.txt)"){throw "The file specified in the path argument must be either of type txt"} return $true })] [System.IO.FileInfo]$path ) $secure = ConvertTo-SecureString $password -force -asPlainText $bytes = ConvertFrom-SecureString $secure $bytes | Out-File $path -Encoding unicode }#Save-EncryptedPassword # SIG # Begin signature block # MIIdvgYJKoZIhvcNAQcCoIIdrzCCHasCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUh6xvL0QkhV8iwDVK0x9qfgQJ # w6GgghfcMIIFKDCCBBCgAwIBAgIQBBcjfnd2/0lPtk4Ac2XkEzANBgkqhkiG9w0B # AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz # c3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTIwMDcwODAwMDAwMFoXDTIzMDcx # MzEyMDAwMFowZTELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xFDASBgNV # BAcTC01pc3Npc3NhdWdhMRYwFAYDVQQKEw1WaWthcyBTdWtoaWphMRYwFAYDVQQD # Ew1WaWthcyBTdWtoaWphMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA # 4St8d9DqmfWYRMXs9ampsHh6qVG4kVEaB1AA9GS9itVGUgtkz+18W5mSvpymVX7e # 795HGUCqR5GfNuJEr6jCaLXZmfDmi3M8m5lFJvqCbV1IZtlN9rLYlcKCVzwvRm2y # ctcdFSLzB1spKm/15gjyt546JdVtQe5uzvf4Rcf5SUOIIyzsunA/JWPK3mjQkx0F # ygeN1EiHHVQoQEJ5bLTDOKoNj3inAK7N4NCuxe39R8xbOTXUfZm5/Zdg8MjLQXs2 # zKEPHtsyJ8zRAVYLQLUiKduHwwZS57XyaOWVOlhxLDM1QXXV31XNEbCFnwBTZt63 # xMgB6S3/g/lpYx1P21orUQIDAQABo4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoK # o6XqcQPAYPkt9mV1DlgwHQYDVR0OBBYEFMu2/KoMoWIixN8+jbE8OgpMUr6gMA4G # A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWg # M6Axhi9odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcx # LmNybDA1oDOgMYYvaHR0cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl # ZC1jcy1nMS5jcmwwTAYDVR0gBEUwQzA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcC # ARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsG # AQUFBwEBBHgwdjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t # ME4GCCsGAQUFBzAChkJodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl # cnRTSEEyQXNzdXJlZElEQ29kZVNpZ25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADAN # BgkqhkiG9w0BAQsFAAOCAQEAT+TncEv203oQo+u4DDHMn6pkTcnzx/W3lrwsjHV+ # C0RcEvTQ0kmpqgqQ1XO3tGhPh3rJAdIUL9M1gUEtSdg4XebJG470va3LTm2hLMbE # cpSYrkTdpuXEzQ9BO4IaAdWRXzn/VWVeRS79RBRe4RKy8SbvQ5RbfoCUjZ0y6AdG # ufBhKsSqMEiTyKZRXRcbaw138AkWijQ8J9Gk1UAGPF8l5mYo50p5gFhmlepKYp0n # tNBJGJE/nRcMPV6BY5Zt8vqpnLGhrdceZkXXwA8JFsS5Z0dkQGvhB8x8jX+xQMUy # U5/iFTq1Nq/27LFKj7vxDJ8/lgEJ6Y46sp4rBjhi/Q/FGDCCBTAwggQYoAMCAQIC # EAQJGBtf1btmdVNDtW+VUAgwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx # FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv # bTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTEzMTAy # MjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTATBgNVBAoT # DERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UE # AxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQTCCASIw # DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPjTsxx/DhGvZ3cH0wsxSRnP0PtF # mbE620T1f+Wondsy13Hqdp0FLreP+pJDwKX5idQ3Gde2qvCchqXYJawOeSg6funR # Z9PG+yknx9N7I5TkkSOWkHeC+aGEI2YSVDNQdLEoJrskacLCUvIUZ4qJRdQtoaPp # iCwgla4cSocI3wz14k1gGL6qxLKucDFmM3E+rHCiq85/6XzLkqHlOzEcz+ryCuRX # u0q16XTmK/5sy350OTYNkO/ktU6kqepqCquE86xnTrXE94zRICUj6whkPlKWwfIP # EvTFjg/BougsUfdzvL2FsWKDc0GCB+Q4i2pzINAPZHM8np+mM6n9Gd8lk9ECAwEA # AaOCAc0wggHJMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MIGB # BgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNl # cnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdpY2Vy # dC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsME8GA1UdIARIMEYwOAYK # YIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5j # b20vQ1BTMAoGCGCGSAGG/WwDMB0GA1UdDgQWBBRaxLl7KgqjpepxA8Bg+S32ZXUO # WDAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0BAQsF # AAOCAQEAPuwNWiSz8yLRFcgsfCUpdqgdXRwtOhrE7zBh134LYP3DPQ/Er4v97yrf # IFU3sOH20ZJ1D1G0bqWOWuJeJIFOEKTuP3GOYw4TS63XX0R58zYUBor3nEZOXP+Q # sRsHDpEV+7qvtVHCjSSuJMbHJyqhKSgaOnEoAjwukaPAJRHinBRHoXpoaK+bp1wg # XNlxsQyPu6j4xRJon89Ay0BEpRPw5mQMJQhCMrI2iiQC/i9yfhzXSUWW6Fkd6fp0 # ZGuy62ZD2rOwjNXpDd32ASDOmTFjPQgaGLOBm0/GkxAG/AeB+ova+YJJ92JuoVP6 # EpQYhS6SkepobEQysmah5xikmmRR7zCCBq4wggSWoAMCAQICEAc2N7ckVHzYR6z9 # KGYqXlswDQYJKoZIhvcNAQELBQAwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERp # Z2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMY # RGlnaUNlcnQgVHJ1c3RlZCBSb290IEc0MB4XDTIyMDMyMzAwMDAwMFoXDTM3MDMy # MjIzNTk1OVowYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu # MTswOQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRp # bWVTdGFtcGluZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMaG # NQZJs8E9cklRVcclA8TykTepl1Gh1tKD0Z5Mom2gsMyD+Vr2EaFEFUJfpIjzaPp9 # 85yJC3+dH54PMx9QEwsmc5Zt+FeoAn39Q7SE2hHxc7Gz7iuAhIoiGN/r2j3EF3+r # GSs+QtxnjupRPfDWVtTnKC3r07G1decfBmWNlCnT2exp39mQh0YAe9tEQYncfGpX # evA3eZ9drMvohGS0UvJ2R/dhgxndX7RUCyFobjchu0CsX7LeSn3O9TkSZ+8OpWNs # 5KbFHc02DVzV5huowWR0QKfAcsW6Th+xtVhNef7Xj3OTrCw54qVI1vCwMROpVymW # Jy71h6aPTnYVVSZwmCZ/oBpHIEPjQ2OAe3VuJyWQmDo4EbP29p7mO1vsgd4iFNmC # KseSv6De4z6ic/rnH1pslPJSlRErWHRAKKtzQ87fSqEcazjFKfPKqpZzQmiftkaz # nTqj1QPgv/CiPMpC3BhIfxQ0z9JMq++bPf4OuGQq+nUoJEHtQr8FnGZJUlD0UfM2 # SU2LINIsVzV5K6jzRWC8I41Y99xh3pP+OcD5sjClTNfpmEpYPtMDiP6zj9NeS3YS # UZPJjAw7W4oiqMEmCPkUEBIDfV8ju2TjY+Cm4T72wnSyPx4JduyrXUZ14mCjWAkB # KAAOhFTuzuldyF4wEr1GnrXTdrnSDmuZDNIztM2xAgMBAAGjggFdMIIBWTASBgNV # HRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBS6FtltTYUvcyl2mi91jGogj57IbzAf # BgNVHSMEGDAWgBTs1+OC0nFdZEzfLmc/57qYrhwPTzAOBgNVHQ8BAf8EBAMCAYYw # EwYDVR0lBAwwCgYIKwYBBQUHAwgwdwYIKwYBBQUHAQEEazBpMCQGCCsGAQUFBzAB # hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQQYIKwYBBQUHMAKGNWh0dHA6Ly9j # YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRSb290RzQuY3J0MEMG # A1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy # dFRydXN0ZWRSb290RzQuY3JsMCAGA1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG # /WwHATANBgkqhkiG9w0BAQsFAAOCAgEAfVmOwJO2b5ipRCIBfmbW2CFC4bAYLhBN # E88wU86/GPvHUF3iSyn7cIoNqilp/GnBzx0H6T5gyNgL5Vxb122H+oQgJTQxZ822 # EpZvxFBMYh0MCIKoFr2pVs8Vc40BIiXOlWk/R3f7cnQU1/+rT4osequFzUNf7WC2 # qk+RZp4snuCKrOX9jLxkJodskr2dfNBwCnzvqLx1T7pa96kQsl3p/yhUifDVinF2 # ZdrM8HKjI/rAJ4JErpknG6skHibBt94q6/aesXmZgaNWhqsKRcnfxI2g55j7+6ad # cq/Ex8HBanHZxhOACcS2n82HhyS7T6NJuXdmkfFynOlLAlKnN36TU6w7HQhJD5TN # OXrd/yVjmScsPT9rp/Fmw0HNT7ZAmyEhQNC3EyTN3B14OuSereU0cZLXJmvkOHOr # pgFPvT87eK1MrfvElXvtCl8zOYdBeHo46Zzh3SP9HSjTx/no8Zhf+yvYfvJGnXUs # HicsJttvFXseGYs2uJPU5vIXmVnKcPA3v5gA3yAWTyf7YGcWoWa63VXAOimGsJig # K+2VQbc61RWYMbRiCQ8KvYHZE/6/pNHzV9m8BPqC3jLfBInwAM1dwvnQI38AC+R2 # AibZ8GV2QqYphwlHK+Z/GqSFD/yYlvZVVCsfgPrA8g4r5db7qS9EFUrnEw4d2zc4 # GqEr9u3WfPwwggbGMIIErqADAgECAhAKekqInsmZQpAGYzhNhpedMA0GCSqGSIb3 # DQEBCwUAMGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7 # MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1l # U3RhbXBpbmcgQ0EwHhcNMjIwMzI5MDAwMDAwWhcNMzMwMzE0MjM1OTU5WjBMMQsw # CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJDAiBgNVBAMTG0Rp # Z2lDZXJ0IFRpbWVzdGFtcCAyMDIyIC0gMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP # ADCCAgoCggIBALkqliOmXLxf1knwFYIY9DPuzFxs4+AlLtIx5DxArvurxON4XX5c # Nur1JY1Do4HrOGP5PIhp3jzSMFENMQe6Rm7po0tI6IlBfw2y1vmE8Zg+C78KhBJx # bKFiJgHTzsNs/aw7ftwqHKm9MMYW2Nq867Lxg9GfzQnFuUFqRUIjQVr4YNNlLD5+ # Xr2Wp/D8sfT0KM9CeR87x5MHaGjlRDRSXw9Q3tRZLER0wDJHGVvimC6P0Mo//8Zn # zzyTlU6E6XYYmJkRFMUrDKAz200kheiClOEvA+5/hQLJhuHVGBS3BEXz4Di9or16 # cZjsFef9LuzSmwCKrB2NO4Bo/tBZmCbO4O2ufyguwp7gC0vICNEyu4P6IzzZ/9KM # u/dDI9/nw1oFYn5wLOUrsj1j6siugSBrQ4nIfl+wGt0ZvZ90QQqvuY4J03ShL7BU # dsGQT5TshmH/2xEvkgMwzjC3iw9dRLNDHSNQzZHXL537/M2xwafEDsTvQD4ZOgLU # MalpoEn5deGb6GjkagyP6+SxIXuGZ1h+fx/oK+QUshbWgaHK2jCQa+5vdcCwNiay # CDv/vb5/bBMY38ZtpHlJrYt/YYcFaPfUcONCleieu5tLsuK2QT3nr6caKMmtYbCg # QRgZTu1Hm2GV7T4LYVrqPnqYklHNP8lE54CLKUJy93my3YTqJ+7+fXprAgMBAAGj # ggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8E # DDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEw # HwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8wHQYDVR0OBBYEFI1kt4kh # /lZYRIRhp+pvHDaP3a8NMFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1lU3Rh # bXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQGCCsGAQUFBzABhhhodHRw # Oi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKGTGh0dHA6Ly9jYWNlcnRz # LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQwOTZTSEEyNTZUaW1l # U3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIBAA0tI3Sm0fX46kuZPwHk # 9gzkrxad2bOMl4IpnENvAS2rOLVwEb+EGYs/XeWGT76TOt4qOVo5TtiEWaW8G5iq # 6Gzv0UhpGThbz4k5HXBw2U7fIyJs1d/2WcuhwupMdsqh3KErlribVakaa33R9QIJ # T4LWpXOIxJiA3+5JlbezzMWn7g7h7x44ip/vEckxSli23zh8y/pc9+RTv24KfH7X # 3pjVKWWJD6KcwGX0ASJlx+pedKZbNZJQfPQXpodkTz5GiRZjIGvL8nvQNeNKcEip # tucdYL0EIhUlcAZyqUQ7aUcR0+7px6A+TxC5MDbk86ppCaiLfmSiZZQR+24y8fW7 # OK3NwJMR1TJ4Sks3KkzzXNy2hcC7cDBVeNaY/lRtf3GpSBp43UZ3Lht6wDOK+Eoo # jBKoc88t+dMj8p4Z4A2UKKDr2xpRoJWCjihrpM6ddt6pc6pIallDrl/q+A8GQp3f # BmiW/iqgdFtjZt5rLLh4qk1wbfAs8QcVfjW05rUMopml1xVrNQ6F1uAszOAMJLh8 # UgsemXzvyMjFjFhpr6s94c/MfRWuFL+Kcd/Kl7HYR+ocheBFThIcFClYzG/Tf8u+ # wQ5KbyCcrtlzMlkI5y2SoRoR/jKYpl0rl+CL05zMbbUNrkdjOEcXW28T2moQbh9J # t0RbtAgKh1pZBHYRoad3AhMcMYIFTDCCBUgCAQEwgYYwcjELMAkGA1UEBhMCVVMx # FTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNv # bTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmlu # ZyBDQQIQBBcjfnd2/0lPtk4Ac2XkEzAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIB # DDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEE # AYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUuYMfOZLzw9Po # EvXONiVR+KNGfQIwDQYJKoZIhvcNAQEBBQAEggEAZEqPicm+s/Ku6jHIKLG6hMlx # 25GFP02yaycQlmoAPAKzZH9E1CZxfHDhY7gcwr9gu5IDmcKuf1BCuKgKg/STnMnU # O8d4/3ULa3eW9ISmHuw9C0hKBT+RFNpGVXwiHhayJpiCMxH/NC0xIIJP/hWtbguP # lECQ3hYjJ99YW58K4sidxh7StYDx6sHnBxsdMkD5xrDFjsmUSNXfKmQ+q5fKJO4K # X03sTmcKyUUWSafwU/JpWdLbKOCLW3N0mHmtepy99utJEKI0oRkukJa3QCd7PY04 # IKVV6K0FcdJE5eiUBWyfsoMkAzSV1IP4uqInoBFAlYF7H7XjYC76mzsWRQ94VKGC # AyAwggMcBgkqhkiG9w0BCQYxggMNMIIDCQIBATB3MGMxCzAJBgNVBAYTAlVTMRcw # FQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgVHJ1c3Rl # ZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0ECEAp6SoieyZlCkAZj # OE2Gl50wDQYJYIZIAWUDBAIBBQCgaTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcB # MBwGCSqGSIb3DQEJBTEPFw0yMjA2MDgxNTI4MzZaMC8GCSqGSIb3DQEJBDEiBCDW # +xdZ5BM7L1l74MFPxyTqDKiIzC9pSf4Go+ssKWSwhjANBgkqhkiG9w0BAQEFAASC # AgCa1Id49rQLXk+DZZnIUzS82382mMPdT7m8VFi+/oVO8i1zPheKyxjSmAFnfFem # OFmXn3gZvtIOt2og17sHNVfdx+My2idKvpkc2b60/HoMp1BBwKASvV5VAev7fPvj # WTOuRaz2BIQAkOdNfEZJCd+DURaUCwSgPnSjQxUOCsvOqUsxa8dI5UZkCWI8kVuS # RyjoQ4Z2dz3rDxREwLy9XEh4uyGUiAr3GZHYBlDhQ7wYLBL9pGBUZZHzMdREcWJy # OFGnvovMHbnOcEYjx8U7I6EdRFM47ynAyYt9V+oQLsVoPB97T2nZ6Ypz1vmQFfOL # O19ZFKX4f+/fBIbOg4ETHy8IfT4um8WX3/gQMQrA42U/+0X9P0XMhTY4l/x2D2Ve # mwicASgWXFzhjBOKHgV3S4dOtFF252aOMJHlT8uTlakx7i1Zq4DxiUdS70PAEkz3 # 72p7fZwybrulr+R+oCJESzFW0Er1dwW5Rj3qdA4KFU9Rfl0sqO2IYBuM3KEriyPr # KSEMzFJuHucbva4cTv1MXLA8rL56Ypuo++PHNov+X6Zcv1FmOFF3nq+8hiEzYYEC # UDT1Nf/MAQXFCTTfmmC87nJ6U7hSUi1SqglIH6yiLDg8zylm4OQmLJkN2Ot3jmvC # JryX6u2Ln89l7hfuAMZawYXFTzPqXFDmTREvakfOog3ACA== # SIG # End signature block |