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
    ===========================================================================
    .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
#############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)]
    [ValidateSet('5','9','14','20')]
    [int]$NumberofChars
  )
  switch ($NumberofChars){
    "5" {
      $Password = $null
      $Password += ([char[]]([char]33..[char]47) | sort {Get-Random})[0] -join '' # one special char
      $Password += ([char[]]([char]65..[char]90) | sort {Get-Random})[0] -join '' # one caps
      $Password += ([char[]]([char]97..[char]122) | sort {Get-Random})[0..1] -join '' #two small
      $Password += ([char[]]([char]48..[char]57) | sort {Get-Random})[0] -join ''  #one numbers
      $arrpassword = $Password.ToChararray()
      $randomarr = $arrpassword | Get-Random -Count $arrpassword.Length
      $Password = -join $randomarr
      return $Password
    }
    "9" {
      $Password = $null
      $Password += ([char[]]([char]33..[char]47) | sort {Get-Random})[0] -join '' # one special char
      $Password += ([char[]]([char]65..[char]90) | sort {Get-Random})[0..1] -join '' # two caps
      $Password += ([char[]]([char]97..[char]122) | sort {Get-Random})[0..2] -join '' # thrice small
      $Password += ([char[]]([char]48..[char]57) | sort {Get-Random})[0..2] -join ''  #thrice numbers
      $arrpassword = $Password.ToChararray()
      $randomarr = $arrpassword | Get-Random -Count $arrpassword.Length
      $Password = -join $randomarr
      return $Password
    }
    "14"{
      $Password = $null
      $Password += ([char[]]([char]33..[char]47) | sort {Get-Random})[0..1] -join '' # two special char
      $Password += ([char[]]([char]65..[char]90) | sort {Get-Random})[0..3] -join '' # 4 caps
      $Password += ([char[]]([char]97..[char]122) | sort {Get-Random})[0..3] -join '' # 4 small
      $Password += ([char[]]([char]48..[char]57) | sort {Get-Random})[0..3] -join ''  #4 numbers
      $arrpassword = $Password.ToChararray()
      $randomarr = $arrpassword | Get-Random -Count $arrpassword.Length
      $Password = -join $randomarr
      return $Password
    }
    "20"{
      $Password = $null
      $Password += ([char[]]([char]33..[char]47) | sort {Get-Random})[0..2] -join '' # 3 special char
      $Password += ([char[]]([char]65..[char]90) | sort {Get-Random})[0..5] -join '' # 6 caps
      $Password += ([char[]]([char]97..[char]122) | sort {Get-Random})[0..5] -join '' # 6 small
      $Password += ([char[]]([char]48..[char]57) | sort {Get-Random})[0..4] -join ''  #5 numbers
      $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
# MIIZiQYJKoZIhvcNAQcCoIIZejCCGXYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUmPyX2Zkef9XPSo5mJxfqyVxh
# jOCgghSXMIIE/jCCA+agAwIBAgIQDUJK4L46iP9gQCHOFADw3TANBgkqhkiG9w0B
# AQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD
# VQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEyIEFz
# c3VyZWQgSUQgVGltZXN0YW1waW5nIENBMB4XDTIxMDEwMTAwMDAwMFoXDTMxMDEw
# NjAwMDAwMFowSDELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMu
# MSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyMTCCASIwDQYJKoZIhvcN
# AQEBBQADggEPADCCAQoCggEBAMLmYYRnxYr1DQikRcpja1HXOhFCvQp1dU2UtAxQ
# tSYQ/h3Ib5FrDJbnGlxI70Tlv5thzRWRYlq4/2cLnGP9NmqB+in43Stwhd4CGPN4
# bbx9+cdtCT2+anaH6Yq9+IRdHnbJ5MZ2djpT0dHTWjaPxqPhLxs6t2HWc+xObTOK
# fF1FLUuxUOZBOjdWhtyTI433UCXoZObd048vV7WHIOsOjizVI9r0TXhG4wODMSlK
# XAwxikqMiMX3MFr5FK8VX2xDSQn9JiNT9o1j6BqrW7EdMMKbaYK02/xWVLwfoYer
# vnpbCiAvSwnJlaeNsvrWY4tOpXIc7p96AXP4Gdb+DUmEvQECAwEAAaOCAbgwggG0
# MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsG
# AQUFBwMIMEEGA1UdIAQ6MDgwNgYJYIZIAYb9bAcBMCkwJwYIKwYBBQUHAgEWG2h0
# dHA6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAfBgNVHSMEGDAWgBT0tuEgHf4prtLk
# YaWyoiWyyBc1bjAdBgNVHQ4EFgQUNkSGjqS6sGa+vCgtHUQ23eNqerwwcQYDVR0f
# BGowaDAyoDCgLoYsaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl
# ZC10cy5jcmwwMqAwoC6GLGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFz
# c3VyZWQtdHMuY3JsMIGFBggrBgEFBQcBAQR5MHcwJAYIKwYBBQUHMAGGGGh0dHA6
# Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBPBggrBgEFBQcwAoZDaHR0cDovL2NhY2VydHMu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRFRpbWVzdGFtcGluZ0NB
# LmNydDANBgkqhkiG9w0BAQsFAAOCAQEASBzctemaI7znGucgDo5nRv1CclF0CiNH
# o6uS0iXEcFm+FKDlJ4GlTRQVGQd58NEEw4bZO73+RAJmTe1ppA/2uHDPYuj1UUp4
# eTZ6J7fz51Kfk6ftQ55757TdQSKJ+4eiRgNO/PT+t2R3Y18jUmmDgvoaU+2QzI2h
# F3MN9PNlOXBL85zWenvaDLw9MtAby/Vh/HUIAHa8gQ74wOFcz8QRcucbZEnYIpp1
# FUL1LTI4gdr0YKK6tFL7XOBhJCVPst/JKahzQ1HavWPWH1ub9y4bTxMd90oNcX6X
# t/Q/hOvB46NJofrOp79Wz7pZdmGJX36ntI5nePk2mOHLKNpbh6aKLzCCBSgwggQQ
# oAMCAQICEAQXI353dv9JT7ZOAHNl5BMwDQYJKoZIhvcNAQELBQAwcjELMAkGA1UE
# BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj
# ZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIENvZGUg
# U2lnbmluZyBDQTAeFw0yMDA3MDgwMDAwMDBaFw0yMzA3MTMxMjAwMDBaMGUxCzAJ
# BgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMRQwEgYDVQQHEwtNaXNzaXNzYXVn
# YTEWMBQGA1UEChMNVmlrYXMgU3VraGlqYTEWMBQGA1UEAxMNVmlrYXMgU3VraGlq
# YTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOErfHfQ6pn1mETF7PWp
# qbB4eqlRuJFRGgdQAPRkvYrVRlILZM/tfFuZkr6cplV+3u/eRxlAqkeRnzbiRK+o
# wmi12Znw5otzPJuZRSb6gm1dSGbZTfay2JXCglc8L0ZtsnLXHRUi8wdbKSpv9eYI
# 8reeOiXVbUHubs73+EXH+UlDiCMs7LpwPyVjyt5o0JMdBcoHjdRIhx1UKEBCeWy0
# wziqDY94pwCuzeDQrsXt/UfMWzk11H2Zuf2XYPDIy0F7NsyhDx7bMifM0QFWC0C1
# Iinbh8MGUue18mjllTpYcSwzNUF11d9VzRGwhZ8AU2bet8TIAekt/4P5aWMdT9ta
# K1ECAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5Y
# MB0GA1UdDgQWBBTLtvyqDKFiIsTfPo2xPDoKTFK+oDAOBgNVHQ8BAf8EBAMCB4Aw
# EwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2Ny
# bDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0
# dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwG
# A1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
# LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZC
# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJ
# RENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD
# ggEBAE/k53BL9tN6EKPruAwxzJ+qZE3J88f1t5a8LIx1fgtEXBL00NJJqaoKkNVz
# t7RoT4d6yQHSFC/TNYFBLUnYOF3myRuO9L2ty05toSzGxHKUmK5E3ablxM0PQTuC
# GgHVkV85/1VlXkUu/UQUXuESsvEm70OUW36AlI2dMugHRrnwYSrEqjBIk8imUV0X
# G2sNd/AJFoo0PCfRpNVABjxfJeZmKOdKeYBYZpXqSmKdJ7TQSRiRP50XDD1egWOW
# bfL6qZyxoa3XHmZF18APCRbEuWdHZEBr4QfMfI1/sUDFMlOf4hU6tTav9uyxSo+7
# 8QyfP5YBCemOOrKeKwY4Yv0PxRgwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7Vv
# lVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp
# Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0Rp
# Z2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEw
# MjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx
# GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNI
# QTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUA
# A4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx
# 6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEj
# lpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJN
# YBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2
# DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9
# hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNV
# HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEF
# BQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRp
# Z2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQu
# Y29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDig
# NoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v
# dENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAo
# BggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgB
# hv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAU
# Reuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi
# 0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6l
# jlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0k
# riTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/P
# QMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d
# 9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJm
# oecYpJpkUe8wggUxMIIEGaADAgECAhAKoSXW1jIbfkHkBdo2l8IVMA0GCSqGSIb3
# DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAX
# BgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3Vy
# ZWQgSUQgUm9vdCBDQTAeFw0xNjAxMDcxMjAwMDBaFw0zMTAxMDcxMjAwMDBaMHIx
# CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
# dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJ
# RCBUaW1lc3RhbXBpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQC90DLuS82Pf92puoKZxTlUKFe2I0rEDgdFM1EQfdD5fU1ofue2oPSNs4jkl79j
# IZCYvxO8V9PD4X4I1moUADj3Lh477sym9jJZ/l9lP+Cb6+NGRwYaVX4LJ37AovWg
# 4N4iPw7/fpX786O6Ij4YrBHk8JkDbTuFfAnT7l3ImgtU46gJcWvgzyIQD3XPcXJO
# Cq3fQDpct1HhoXkUxk0kIzBdvOw8YGqsLwfM/fDqR9mIUF79Zm5WYScpiYRR5oLn
# RlD9lCosp+R1PrqYD4R/nzEU1q3V8mTLex4F0IQZchfxFwbvPc3WTe8GQv2iUypP
# hR3EHTyvz9qsEPXdrKzpVv+TAgMBAAGjggHOMIIByjAdBgNVHQ4EFgQU9LbhIB3+
# Ka7S5GGlsqIlssgXNW4wHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8w
# EgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0lBAwwCgYI
# KwYBBQUHAwgweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz
# cC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2lj
# ZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6MHgw
# OqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJ
# RFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdp
# Q2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwUAYDVR0gBEkwRzA4BgpghkgBhv1sAAIE
# MCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCwYJ
# YIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4IBAQBxlRLpUYdWac3v3dp8qmN6s3jP
# BjdAhO9LhL/KzwMC/cWnww4gQiyvd/MrHwwhWiq3BTQdaq6Z+CeiZr8JqmDfdqQ6
# kw/4stHYfBli6F6CJR7Euhx7LCHi1lssFDVDBGiy23UC4HLHmNY8ZOUfSBAYX4k4
# YU1iRiSHY4yRUiyvKYnleB/WCxSlgNcSR3CzddWThZN+tpJn+1Nhiaj1a5bA9Fhp
# DXzIAbG5KHW3mWOFIoxhynmUfln8jA/jb7UBJrZspe6HUSHkWGCbugwtK22ixH67
# xCUrRwIIfEmuE7bhfEJCKMYYVs9BNLZmXbZ0e/VWMyIvIjayS6JKldj1po5SMYIE
# XDCCBFgCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu
# YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQg
# U0hBMiBBc3N1cmVkIElEIENvZGUgU2lnbmluZyBDQQIQBBcjfnd2/0lPtk4Ac2Xk
# EzAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG
# 9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIB
# FTAjBgkqhkiG9w0BCQQxFgQU6Eog9a3sDghk7anmJ32LvKwh0sEwDQYJKoZIhvcN
# AQEBBQAEggEAXlqia3fOYPCsFT+5S6PFRKQdElnWaKrVODGbEailrbadSBgqWH0u
# ix+bQ9NNcicnX2AKFPo0cq5/DDrcoXuHIVxJNlyuyRYILAzAjtL8EbW/zqw+KJBf
# Em0ngndSlf8igVNoIz5D/+ldP5pk5NZk0dOQ43P06qtNAoFgmwuu634OBrU1MhVp
# OkWL8HdQDy09rKo7/lAvArcf0CIiSgcfQv2b5/fpYA/XVJHStbFx9EXXGPeRGYtX
# YoB09nuKLu3UX2XLWt1HdRXi9EBncqdjg5dJoOZS8Cue+KpdeqIWSqhX9/58lt06
# E/MD6wIcNJtx3I9SWGvvxbkCmXomv/gBGaGCAjAwggIsBgkqhkiG9w0BCQYxggId
# MIICGQIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT
# SEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBAhANQkrgvjqI/2BAIc4UAPDd
# MA0GCWCGSAFlAwQCAQUAoGkwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkq
# hkiG9w0BCQUxDxcNMjExMjIwMjMyNzE1WjAvBgkqhkiG9w0BCQQxIgQglbUNmmd3
# aaw6e+2sUvUY+D5Wyrbjty1rxwMJ4hmnV4AwDQYJKoZIhvcNAQEBBQAEggEAfBZm
# UH0UhiHzpTxeZM0sXtIywfO0WlJR7Hrm3IXy8wOFoAbubdpNHlNmMS/uBusZp+9y
# /6aDZSd3B5qiDX5LtRRWlJ2oCgkOdQm0ZHsmsjbFBjYROu7owBzdFX4+LrcIcmVf
# tf24+DZUBahmCGtLtNIvP9ed6GGUayNMPiwonmddL7ggI7a5S55vgC64p/jPz3C4
# uB3kiC16YoZMMHVeGN3dasrs3cAKBHHVE5b2XMroDtePZov2hEGt4S3MBaiTEGgT
# c63zvkh51+LAVFrXC1vPoY4l1mUVIS8YBBIcy+yn6Y/GSHFGTpJkzYAyR8WPT82Y
# ElZNT1/tqpaQMGHqbA==
# SIG # End signature block