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
# MIIeYQYJKoZIhvcNAQcCoIIeUjCCHk4CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUmPyX2Zkef9XPSo5mJxfqyVxh
# jOCgghl0MIIE/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/hOvB46NJofrOp79Wz7pZdmGJX36ntI5nePk2mOHLKNpbh6aKLzCCBTEwggQZ
# oAMCAQICEAqhJdbWMht+QeQF2jaXwhUwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UE
# BhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2lj
# ZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQgQXNzdXJlZCBJRCBSb290IENBMB4X
# DTE2MDEwNzEyMDAwMFoXDTMxMDEwNzEyMDAwMFowcjELMAkGA1UEBhMCVVMxFTAT
# BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEx
# MC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBD
# QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL3QMu5LzY9/3am6gpnF
# OVQoV7YjSsQOB0UzURB90Pl9TWh+57ag9I2ziOSXv2MhkJi/E7xX08PhfgjWahQA
# OPcuHjvuzKb2Mln+X2U/4Jvr40ZHBhpVfgsnfsCi9aDg3iI/Dv9+lfvzo7oiPhis
# EeTwmQNtO4V8CdPuXciaC1TjqAlxa+DPIhAPdc9xck4Krd9AOly3UeGheRTGTSQj
# MF287DxgaqwvB8z98OpH2YhQXv1mblZhJymJhFHmgudGUP2UKiyn5HU+upgPhH+f
# MRTWrdXyZMt7HgXQhBlyF/EXBu89zdZN7wZC/aJTKk+FHcQdPK/P2qwQ9d2srOlW
# /5MCAwEAAaOCAc4wggHKMB0GA1UdDgQWBBT0tuEgHf4prtLkYaWyoiWyyBc1bjAf
# BgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzASBgNVHRMBAf8ECDAGAQH/
# AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB5BggrBgEF
# BQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBD
# BggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2Ny
# bDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDig
# NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v
# dENBLmNybDBQBgNVHSAESTBHMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYc
# aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sBwEwDQYJKoZI
# hvcNAQELBQADggEBAHGVEulRh1Zpze/d2nyqY3qzeM8GN0CE70uEv8rPAwL9xafD
# DiBCLK938ysfDCFaKrcFNB1qrpn4J6JmvwmqYN92pDqTD/iy0dh8GWLoXoIlHsS6
# HHssIeLWWywUNUMEaLLbdQLgcseY1jxk5R9IEBhfiThhTWJGJIdjjJFSLK8pieV4
# H9YLFKWA1xJHcLN11ZOFk362kmf7U2GJqPVrlsD0WGkNfMgBsbkodbeZY4UijGHK
# eZR+WfyMD+NvtQEmtmyl7odRIeRYYJu6DC0rbaLEfrvEJStHAgh8Sa4TtuF8QkIo
# xhhWz0E0tmZdtnR79VYzIi8iNrJLokqV2PWmjlIwggduMIIGVqADAgECAhMUAAFl
# rch5WM6kaQfIAAAAAWWtMA0GCSqGSIb3DQEBCwUAMGoxEzARBgoJkiaJk/IsZAEZ
# FgNjb20xFjAUBgoJkiaJk/IsZAEZFgZib3NzY2kxFDASBgoJkiaJk/IsZAEZFgRi
# c2NpMSUwIwYDVQQDExxCU0NJLUVudFN1YkNBLVByaXZhdGUtU0hBMjU2MB4XDTIw
# MDcwNzE1NDkxOVoXDTIyMDcwNzE1NDkxOVowbDELMAkGA1UEBhMCVVMxEjAQBgNV
# BAgTCU1pbm5lc290YTETMBEGA1UEBxMKU2FpbnQgUGF1bDENMAsGA1UEChMEQlND
# STELMAkGA1UECxMCSVQxGDAWBgNVBAMTD0NvbGxhYi5Cc2NpLkNvbTCCASIwDQYJ
# KoZIhvcNAQEBBQADggEPADCCAQoCggEBANUE+I7NrcAJBD48xye/MTN0hd0lZDrz
# uZYBSOXdDNACRFR0LTrCM6xhGRLTsypA+5kfuLW84snz2+NXJq85MemBLn6LiEGS
# DVsBgnLLUmUNCHSgsvHXNFKbE0OKz7XPUIwlFWyKFg6P4DDnUTtt8Lg+S4PXPx9v
# tfzmh+f5kddkY6gjEcWaP/W2S/6ky5HuSCmPvaV0lmls+Cd4NiVHCNe7pCQJkYeu
# llO8R3PA0rZXrbZnTolHvcoY/vaWIugmYvuzIHc5s6gh8xdXzp8yzWtHKmHl3ZFO
# G270ETaEl539La3sGJZk6PddHoEdsqUBYIZp5Vw8JNimparLtkugqD0CAwEAAaOC
# BAkwggQFMB0GA1UdDgQWBBTxiod44r7QBiq0FmUYv84XbqNO0jAfBgNVHSMEGDAW
# gBRqkc3JsALDSWH3cxzd/F7C8fZVSDCCAWcGA1UdHwSCAV4wggFaMIIBVqCCAVKg
# ggFOhoHGbGRhcDovLy9DTj1CU0NJLUVudFN1YkNBLVByaXZhdGUtU0hBMjU2LENO
# PW5hdGNlcnRhcDAyLENOPUNEUCxDTj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxD
# Tj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERDPWJvc3NjaSxEQz1jb20/Y2Vy
# dGlmaWNhdGVSZXZvY2F0aW9uTGlzdD9iYXNlP29iamVjdENsYXNzPWNSTERpc3Ry
# aWJ1dGlvblBvaW50hjpodHRwOi8vc2hlbXAuYnNjaS5jb20vcGtpL0JTQ0ktRW50
# U3ViQ0EtUHJpdmF0ZS1TSEEyNTYuY3JshkdodHRwOi8vbmF0Y2VydGFwMDIuYnNj
# aS5ib3NzY2kuY29tL3BraS9CU0NJLUVudFN1YkNBLVByaXZhdGUtU0hBMjU2LmNy
# bDCCAdkGCCsGAQUFBwEBBIIByzCCAccwgboGCCsGAQUFBzAChoGtbGRhcDovLy9D
# Tj1CU0NJLUVudFN1YkNBLVByaXZhdGUtU0hBMjU2LENOPUFJQSxDTj1QdWJsaWMl
# MjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1cmF0aW9uLERD
# PWJvc3NjaSxEQz1jb20/Y0FDZXJ0aWZpY2F0ZT9iYXNlP29iamVjdENsYXNzPWNl
# cnRpZmljYXRpb25BdXRob3JpdHkwbwYIKwYBBQUHMAKGY2h0dHA6Ly9uYXRjZXJ0
# YXAwMi5ic2NpLmJvc3NjaS5jb20vcGtpL25hdGNlcnRhcDAyLmJzY2kuYm9zc2Np
# LmNvbV9CU0NJLUVudFN1YkNBLVByaXZhdGUtU0hBMjU2LmNydDBiBggrBgEFBQcw
# AoZWaHR0cDovL3NoZW1wLmJzY2kuY29tL3BraS9uYXRjZXJ0YXAwMi5ic2NpLmJv
# c3NjaS5jb21fQlNDSS1FbnRTdWJDQS1Qcml2YXRlLVNIQTI1Ni5jcnQwMwYIKwYB
# BQUHMAGGJ2h0dHA6Ly9uYXRjZXJ0YXAwMi5ic2NpLmJvc3NjaS5jb20vb2NzcDAL
# BgNVHQ8EBAMCB4AwPAYJKwYBBAGCNxUHBC8wLQYlKwYBBAGCNxUIubsggbGCSIXt
# gwiIqw2C8rpUgX2DyMZ3h5TgRgIBZAIBBTATBgNVHSUEDDAKBggrBgEFBQcDAzAb
# BgkrBgEEAYI3FQoEDjAMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQAl
# bK4e7vxLcFjZvrf12u7Z3ZCpL7SjcPLJDaoIayN2KSC9qtDFw5Jv7nRZCvUDg9Mk
# +XGsFniZKzG8vCY9D93Ifjmw4qksZYnUQ5JyGAI1UqsuqmWwjV1OsE/KN/+Ygi9g
# Ej8EPyMauhlQched5moWtim/B04oPynoLd1YpkgvjIvvI3uBtwEAaZD3fccffrGa
# H4xlDMPcP73PwTBmoW+PGFSSUO2gyTza6b7sIeTZfnr4ix39ZpRG8lMg+zYipzsd
# UGo/KksdjCsAL/K/QHN28wKl6QdtzzKOAIwtl0A1DLfBIIzfT/JJRZWoxy8iAbvt
# xxFkdLoN+fbW30MlZKYLMIIHxzCCBa+gAwIBAgITeQAAAAKU/jQK/0fefwAAAAAA
# AjANBgkqhkiG9w0BAQsFADAlMSMwIQYDVQQDExpCU0NJLVJvb3RDQS1Qcml2YXRl
# LVNIQTI1NjAeFw0xNjAyMTcxOTEyMDhaFw0yNjAyMTcxOTIyMDhaMGoxEzARBgoJ
# kiaJk/IsZAEZFgNjb20xFjAUBgoJkiaJk/IsZAEZFgZib3NzY2kxFDASBgoJkiaJ
# k/IsZAEZFgRic2NpMSUwIwYDVQQDExxCU0NJLUVudFN1YkNBLVByaXZhdGUtU0hB
# MjU2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx0zgYMqYf3o7DiUL
# OzuegACqphzMXZcVIcMKsAxip2dX0FVixHDs/3oKRWUL8hCdejZmOFdUvwsI7KQ9
# LfVMgo4hUogBSGMBc3ajqtQA+c6iwNi7QYJqpMV4xeSJP+4aZlgSc0lgsPztVgX/
# VpzOvvBtOZLwe2Xn/7T6+kiwIrkq3o1GmN8rRD4tbrj5x9FCFwU32aOdwelyULPd
# kpihGlaJ71AgDtkPk7r8gmLd+wnXamvbjVl6UZ9UWKFyDKVoETXshCT0Z25YytSa
# PxjPPCAvWJtQK7Frn5AVyDexwdTx/V3WC6wyZmlbAXTGk63aRyMlLdGx/nIRsbgh
# Eixv4QIDAQABo4IDqTCCA6UwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFGqR
# zcmwAsNJYfdzHN38XsLx9lVIMIICFwYDVR0gBIICDjCCAgowggIGBgwrBgEEAYLw
# NYQAAQQwggH0ME4GCCsGAQUFBwIBFkJodHRwOi8vbmF0Y2VydGFwMDIuYnNjaS5i
# b3NzY2kuY29tL1BLSS9JbnRlcm5hbFVzZS1QS0lwb2xpY3kuaHRtbAAwggGgBggr
# BgEFBQcCAjCCAZIeggGOAEwAZQBnAGEAbAAgAFAAbwBsAGkAYwB5ACAAUwB0AGEA
# dABlAG0AZQBuAHQAIAAtACAAVABoAGkAcwAgAFAASwBJACAAaQBzACAAZgBvAHIA
# IABpAG4AdABlAHIAbgBhAGwAIABCAG8AcwB0AG8AbgAgAFMAYwBpAGUAbgB0AGkA
# ZgBpAGMAIABzAHkAcwB0AGUAbQBzAC4AIABSAGUAZgBlAHIAIAB0AG8AIAB0AGgA
# ZQAgAGEAcwBzAG8AYwBpAGEAdABlAGQAIABDAGUAcgB0AGkAZgBpAGMAYQB0AGUA
# IABQAHIAYQBjAHQAaQBjAGUAIABTAHQAYQB0AGUAbQBlAG4AdAAgACgAQwBQAFMA
# KQAgAGYAbwByACAAbQBvAHIAZQAgAGkAbgBmAG8AcgBtAGEAdABpAG8AbgAuACAA
# QQBuAHkAIABvAHQAaABlAHIAIAB1AHMAYQBnAGUAIABpAHMAIABzAHQAcgBpAGMA
# dABsAHkAIABwAHIAbwBoAGkAYgBpAHQAZQBkAC4wGQYJKwYBBAGCNxQCBAweCgBT
# AHUAYgBDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgw
# FoAUfGfvrrVG/aldBjJKoongTf8KtdgwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDov
# L25hdGNlcnRhcDAyLmJzY2kuYm9zc2NpLmNvbS9wa2kvQlNDSS1Sb290Q0EtUHJp
# dmF0ZS1TSEEyNTYuY3JsMIGkBggrBgEFBQcBAQSBlzCBlDBdBggrBgEFBQcwAoZR
# aHR0cDovL25hdGNlcnRhcDAyLmJzY2kuYm9zc2NpLmNvbS9wa2kvbmF0Y2VydGFw
# MDFfQlNDSS1Sb290Q0EtUHJpdmF0ZS1TSEEyNTYuY3J0MDMGCCsGAQUFBzABhido
# dHRwOi8vbmF0Y2VydGFwMDIuYnNjaS5ib3NzY2kuY29tL29jc3AwDQYJKoZIhvcN
# AQELBQADggIBAK6llAbUwMF3LUa1khyN51RTeACKO+D9CKxigjgwrzbTF4C8NP3h
# k9WmtkmhJxzDpObFYuZ50fQ6JeSRIh1iGc8c/CfKuZdDnRKXKK00cQd48NZo26xE
# zLBEWR06+dkgC2djJeQtN/t4Cb36zvEfg1HE5XhV44Zy0kB97OfQRXYuEZL5t2PV
# w9tumn4DGiUlhHVDMTOXeJXfiHlJeuTSbVJNpKUWsDjfmN6VvfD3u/XmsP/rnRPW
# S2vx6TNfx0Q9/AQwuMtiyUPb9VBveMpVH6e+8jCU96pweULY/bWQ8ELdnWVG1EYj
# L8b895gS47DEQr6w3QEx84xGD0/q0kLxS6iJxuqfU9IhaCiBe0s60UNj3pqcjZvp
# e5F01T9BAT9vmEnjNxl/DNcv5bmBQIBkUSzUQIXhfK6nt3jXh0d22go8BsOKUUw6
# n+QUwEN3PQ7EjRMPP3I/rLhor+7raot3Icc1kkzvU5WLPy55/ECXw9AG6FX7RhDE
# EilIBPb179vLYyoCTdc6hiLgHBGe3/RlykSzgzIWdGf9e6qhjHfh1789fzp8Xb7W
# hQOVeVUrnquLzgjme8CRPzkUOeLD0SIoWNpEGm5ASQK4+zps+tM2CGJqzfmhUq67
# dmfKavGbu0Ax0H261ID+oHmYpgeMp5bKrPX0pPl/RkitCVCqbGnDquP+MYIEVzCC
# BFMCAQEwgYEwajETMBEGCgmSJomT8ixkARkWA2NvbTEWMBQGCgmSJomT8ixkARkW
# BmJvc3NjaTEUMBIGCgmSJomT8ixkARkWBGJzY2kxJTAjBgNVBAMTHEJTQ0ktRW50
# U3ViQ0EtUHJpdmF0ZS1TSEEyNTYCExQAAWWtyHlYzqRpB8gAAAABZa0wCQYFKw4D
# AhoFAKB4MBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwG
# CisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZI
# hvcNAQkEMRYEFOhKIPWt7A4IZO2p5id9i7ysIdLBMA0GCSqGSIb3DQEBAQUABIIB
# AJsF5NgDakgw3tWGJg2z765zAWEtOE9+VGCuZq/cdrtbWpoNlumDNCSv3qIH5rrG
# lUOfA3bPA3PY67xSdKdNWyimaw97rdzj2yTpbYZGA50eMPt7GnVHU6F+uSFrme7F
# /w+3LCB0Vs41zbt6r/sstyRVpme0mW09+aO1N0Y34OtPHWZmQfIcn94cdT4a7uAr
# lDvSOBtEVwAPEqKCdfR5XZql6qWtlrz9ABJjI2uF966pmzVtdXiS4UcAu6jTTIMi
# 428Mza/OFeB5x5LctRwmREUZXssXJLnkXAKQUBgmGWdd67ede4egkfYqJtY8sVKm
# SVRwkNCsRxHsZCdBltkc83ihggIwMIICLAYJKoZIhvcNAQkGMYICHTCCAhkCAQEw
# gYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE
# CxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1
# cmVkIElEIFRpbWVzdGFtcGluZyBDQQIQDUJK4L46iP9gQCHOFADw3TANBglghkgB
# ZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkF
# MQ8XDTIxMDQyOTAxNDUyN1owLwYJKoZIhvcNAQkEMSIEILmpj9DSn6b5RGDtdxpn
# 42I6mxcPqgb5UZjtijCXdoEyMA0GCSqGSIb3DQEBAQUABIIBAFuj8lkOWbut7iim
# /NJyMon0OowapuKvF6Z8cEVs9Kd7JNuas8GZ+tBvK+lZDtvQCBa6O+PdgZdKqeeX
# Jxvu6XUucCf/Dvaml3azT/kaMtc6PXeEpyN02nxceAkUlcG86O5oBaTE7LZZYphl
# 2qvUqV9pC364fgeKpDIg9G8VZTdUJw7/SRH/WiP/jz9ZMqforWLA93EN5zRfqne0
# G+7xDv4kK34XH2qJXUJCznRSyzucatCffzjZF/KWIvL+AEWkUxBlkDXRhJNqaBb1
# Uy76039CcW4padW8+OHrnAB5+Q/hxa5SMoLec4nKTJFVsohOka/2EIkyFlcCdqD6
# I4fkaW4=
# SIG # End signature block