public/Grant-UcmOffice365UserLicence.ps1
#PerformScriptSigning Function Grant-UcmOffice365UserLicence { <# .SYNOPSIS Assigns a licence to an Office365 user .DESCRIPTION Function will check for available licences and assign one to the supplied user This function will also notify you if you are below 5% of your below licences, a similar warning will be generated if you have less than 5 licences available For a full list of Licence codes, see https://docs.microsoft.com/en-us/azure/active-directory/enterprise-users/licensing-service-plan-reference .EXAMPLE PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'MCOEV' -Country 'AU' Grants the Microsoft Phone System Licence to the user Button Mash PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'MCOCAP' -Country 'AU' Grants the Teams Common Area Phone Licence to the user Button Mash PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'MCOPSTN1' -Country 'AU' Grants the Microsoft Domestic Calling Licence to the user Button Mash PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'MCOPSTN2' -Country 'AU' Grants the Microsoft Domestic/International Calling Licence to the user Button Mash PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'MCOPSTNEAU2' -Country 'AU' Grants the TELSTRA CALLING FOR O365 Licence to the user Button Mash (Australia Only) PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'MEETING_ROOM' -Country 'AU' Grants the Teams Meeting Room Licence to the user Button Mash PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'MCOMEETADV' -Country 'AU' Grants the Teams Advanced Meeting Room Licence to the user Button Mash PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'ENTERPRISEPREMIUM' -Country 'AU' Grants the Microsoft E5 Licence to the user Button Mash PS> Grant-UcmOffice365UserLicence -upn 'button.mash@contoso.com' -LicenceType 'ENTERPRISEPACK' -Country 'AU' Grants the Microsoft E3 Licence to the user Button Mash .INPUTS This function accepts both parameter and pipline input .PARAMETER upn The UPN of the user you wish to enable the licence on, eg: button.mash@contoso.com .PARAMETER LicenceType The licence you wish to assign, eg: 'MCOEV' .PARAMETER Country The 2 letter country code for the users country, must be in capitals. eg: AU .OUTPUT This Cmdet returns a PSCustomObject with multiple Keys to indicate status $Return.Status $Return.Message Return.Status can return one of four values "OK" : The licence has been assigned, or is already assigned to the user. "Warn" : The licence was assigned, but there was an issue. for example, low availability of licences. Check $return.message for more information "Error" : Unable to assign licence. check $return.message for more information "Unknown" : Cmdlet reached the end of the fucntion without returning anything, this shouldnt happen, if it does please log an issue on Github Return.Message returns descriptive text based on the outcome, mainly for logging or reporting .NOTES Version: 1.4 Date: 23/03/2023 .VERSION HISTORY 1.4: Added Country Validation 1.3: Updated Comment based help to include PARAMETER tags 1.2: Updated Examples to include more licences Added link to Microsoft licence documentation 1.1: Updated to "Ucm" naming convention 1.0: Initial Public Release .REQUIRED FUNCTIONS/MODULES Modules AzureAD (Install-Module AzureAD) MSOnline (Install-Module MSOnline) UcmPSTools (Install-Module UcmPSTools) Includes Cmdlets below. Cmdlets Write-UcmLog: https://github.com/Atreidae/UcmPSTools/blob/main/public/Write-UcmLog.ps1 Test-UcmMSOLConnection: https://github.com/Atreidae/UcmPSTools/blob/main/public/Test-UcmMSOLConnection.ps1 New-UcmMSOLConnection: https://github.com/Atreidae/UcmPSTools/blob/main/public/New-UcmMSOLConnection.ps1 Write-UcmHTMLReport: https://github.com/Atreidae/UcmPSTools/blob/main/public/Write-UcmHTMLReport.ps1 .REQUIRED PERMISSIONS 'Office365 User Admin' or better .LINK https://www.UcMadScientist.com https://github.com/Atreidae/UcmPSTools .ACKNOWLEDGEMENTS Assign licenses for specific services in Office 365 using PowerShell: #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseProcessBlockForPipelineCommand', '', Scope='Function')] #todo, https://github.com/Atreidae/UcmPSTools/issues/23 Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=1,HelpMessage='The UPN of the user you wish to enable the licence on, eg: button.mash@contoso.com')] [string]$UPN, [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=2,HelpMessage='The licence you wish to assign, eg: MCOEV')] [string]$LicenceType, [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory, Position=3,HelpMessage='The 2 letter country code for the users country, must be in capitals. eg: AU')] [ValidateSet("AF","AX","AL","DZ","AS","AD","AO","AI","AQ","AG","AR","AM","AW","AU","AT","AZ","BS","BH","BD","BB","BY","BE","BZ","BJ","BM","BT","BO","BQ","BA","BW","BV","BR","IO","BN","BG","BF","BI","CV","KH","CM","CA","KY","CF","TD","CL","CN","CX","CC","CO","KM","CG","CD","CK","CR","CI","HR","CU","CW","CY","CZ","DK","DJ","DM","DO","EC","EG","SV","GQ","ER","EE","SZ","ET","FK","FO","FJ","FI","FR","GF","PF","TF","GA","GM","GE","DE","GH","GI","GR","GL","GD","GP","GU","GT","GG","GN","GW","GY","HT","HM","VA","HN","HK","HU","IS","IN","ID","IR","IQ","IE","IM","IL","IT","JM","JP","JE","JO","KZ","KE","KI","KP","KR","KW","KG","LA","LV","LB","LS","LR","LY","LI","LT","LU","MO","MG","MW","MY","MV","ML","MT","MH","MQ","MR","MU","YT","MX","FM","MD","MC","MN","ME","MS","MA","MZ","MM","NA","NR","NP","NL","NC","NZ","NI","NE","NG","NU","NF","MK","MP","NO","OM","PK","PW","PS","PA","PG","PY","PE","PH","PN","PL","PT","PR","QA","RE","RO","RU","RW","BL","SH","KN","LC","MF","PM","VC","WS","SM","ST","SA","SN","RS","SC","SL","SG","SX","SK","SI","SB","SO","ZA","GS","SS","ES","LK","SD","SR","SJ","SE","CH","SY","TW","TJ","TZ","TH","TL","TG","TK","TO","TT","TN","TR","TM","TC","TV","UG","UA","AE","GB","US","UM","UY","UZ","VU","VE","VN","VG","VI","WF","EH","YE","ZM","ZW")][String]$Country ) #region FunctionSetup, Set Default Variables for HTML Reporting and Write Log $Function = 'Grant-UcmOffice365UserLicence' [hashtable]$Return = @{} $return.function = $Function $return.Status = "Unknown" $return.Message = "Function did not return a status message" # Log why we were called Write-UcmLog -Message "$($MyInvocation.InvocationName) called with $($MyInvocation.Line)" -Severity 1 -Component $function Write-UcmLog -Message "Parameters" -Severity 1 -Component $function -LogOnly Write-UcmLog -Message "$($PsBoundParameters.Keys)" -Severity 1 -Component $function -LogOnly Write-UcmLog -Message "Parameters Values" -Severity 1 -Component $function -LogOnly Write-UcmLog -Message "$($PsBoundParameters.Values)" -Severity 1 -Component $function -LogOnly Write-UcmLog -Message "Optional Arguments" -Severity 1 -Component $function -LogOnly Write-UcmLog -Message "$Args" -Severity 1 -Component $function -LogOnly #endregion functionSetup #region FunctionWork #Check to see if we are connected to MSOL $Test = (Test-UcmMSOLConnection -Reconnect) If ($Test.Status -ne "OK") { #MSOL check failed, return an error. Write-UcmLog -Message "Something went wrong granting $UPN's licence" -Severity 3 -Component $function Write-UcmLog -Message "Test-UcmMSOLConnection could not locate an MSOL connection" -Severity 2 -Component $function $Return.Status = "Error" $Return.Message = "No MSOL Connection" Return $Return } #MSOL Connection test passed, check the tenant has the requested licence. Write-UcmLog -Message "Verifying $LicenceType is available" -Severity 2 -Component $function Try { #Office365 does this thing where it preprends the tenant name on the licence #For example PHONESYSTEM_VIRTUALUSER would be "contoso:PHONESYSTEM_VIRTUALUSER" #So we need to learn the prefix, we do this by looking for the licence and storing its name $O365AcctSku = $null $O365AcctSku = Get-MsolAccountSku | Where-Object {$_.SkuPartNumber -like $LicenceType} #Using the stored details, build the full licence name $LicenceToAssign = "$($O365AcctSku.AccountName):$LicenceType" } Catch { #We couldnt get the licence details, it could be a permissions issue or the connection might be broken. Return an error. Write-UcmLog -Message "Error Running Get-MsolAccountSku" -Severity 3 -Component $function Write-UcmLog -Message $error[0] -Severity 3 -Component $function $Return.Status = "Error" $Return.Message = "Unable to run Get-MsolAccountSku to obtain tenant prefix" Return $Return } If ($null -eq $O365AcctSku) { #The licence requested doesnt exist on the tenant, return an error Write-UcmLog -Message "Unable to locate requested licence on the current tenant" -Severity 3 -Component $function $Return.Status = "Error" $Return.Message = "Unable to locate $LicenceType licence" Return $Return } #The tenant has the requested licence, check to see any are free. Trigger a warning when there is less than 5 or 5% available $LicenceUsedPercent = (($O365AcctSku.ConsumedUnits / $O365AcctSku.ActiveUnits) * 100) $AvailableLicenceCount = ($O365AcctSku.ActiveUnits - $O365AcctSku.ConsumedUnits) If (($LicenceUsedPercent -ge 95) -or ($AvailableLicenceCount -le 5)) { Write-UcmLog -Message "Only $AvailableLicenceCount $LicenceType Licences Left" -Severity 3 -Component $function Write-UcmLog -Message "Available licence count low..." -Severity 3 -Component $function #We encountered something we need to report on, set the warning flag and store a warning message. $WarningFlag = $True $WarningMessage = "Low Licence Count" } #There are licences free, check to see if the specified user exists. Try { Write-UcmLog -Message "Checking for existing User $UPN ..." -Severity 2 -Component $function $O365User = (Get-MsolUser -UserPrincipalName $UPN -ErrorAction Stop) Write-UcmLog -Message "User exists. checking their assigned licences..." -Severity 2 -Component $function #Found the user, check to see if they already have the licence. If ($O365User.Licenses.accountSkuID -contains $LicenceToAssign) { #Looks like the user already has that licence Write-UcmLog -Message "User already has that licence, Skipping" -Severity 3 -Component $function #Check to see if we encountered a warning during the run and inject it into the status message If ($warningFlag) { #Yes, we did, return the warning $Return.Status = "Warning" $Return.Message = "Skipped: Already Licenced, Warning Message $WarningMessage" Return $Return } Else { #No warning, just return OK $Return.Status = "OK" $Return.Message = "Skipped: Already Licenced" Return $Return } } #User exists, and doesnt already have the licence, try assigning the licence to them Try { Write-UcmLog -Message "User Exists, Grant Licence" -Severity 2 -Component $function #Set the user location, this is required to set the relevant licences. Users can be created without setting a country mistakenly. Write-UcmLog -Message "Setting Location" -Severity 2 -Component $function [void] (Set-MsolUser -UserPrincipalName $UPN -UsageLocation $Country) #Try assigning the licence to the user [Void] (Set-MsolUserLicense -UserPrincipalName $UPN -AddLicenses $LicenceToAssign -ErrorAction stop) Write-UcmLog -Message "Licence Granted" -Severity 2 -Component $function #Licence assigned OK. Check to see if we encountered a warning during the run and inject it into the status message If ($warningFlag) { #Yes, we did, return the warning $Return.Status = "Warning" $Return.Message = "Licence Granted, Warning Message $WarningMessage" Return $Return } Else { #No warning, just return OK $Return.Status = "OK" $Return.Message = "Licence Granted" Return $Return } } #Something Failed either setting the licence or the country Catch { #Return an error Write-UcmLog -Message "Something went wrong licencing user $UPN" -Severity 3 -Component $function Write-UcmLog -Message $Error[0] -Severity 3 -Component $function $Return.Status = "Error" $Return.Message = $Error[0] Return $Return } } #End User Check try block #Todo, split this up into seperate blocks to minimise nesting. #User doesnt exist, throw error message Catch { #Return an error Write-UcmLog -Message "Something went wrong granting $UPN's licence" -Severity 3 -Component $function Write-UcmLog -Message "Could not locate user $UPN" -Severity 2 -Component $function $Return.Status = "Error" $Return.Message = "User Not Found" Return $Return } #endregion FunctionWork #region FunctionReturn #Default Return Variable for my HTML Reporting Fucntion Write-UcmLog -Message "Reached end of $function without a Return Statement" -Severity 3 -Component $function $return.Status = "Unknown" $return.Message = "Write-UcmLog did not encounter return statement" Return $Return #endregion Write-UcmLogReturn } # SIG # Begin signature block # MIIRwgYJKoZIhvcNAQcCoIIRszCCEa8CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU+LI+hRyRJAAeUBCGBVe5/UH0 # mVqggg4OMIIGsDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0B # AQwFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVk # IFJvb3QgRzQwHhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg # Q0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5 # WRuxiEL1M4zrPYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJP # DqFX/IiZwZHMgQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXz # ENOLsvsI8IrgnQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bq # HPNlaJGiTUyCEUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTC # fMjqGzLmysL0p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaD # G7dqZy3SvUQakhCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urO # kfW+0/tvk2E0XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7AD # K5GyNnm+960IHnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4 # R+Z1MI3sMJN2FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlN # Wdt4z4FKPkBHX8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0I # U0F8WD1Hs/q27IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYB # Af8CAQAwHQYDVR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaA # FOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK # BggrBgEFBQcDAzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9v # Y3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4 # oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJv # b3RHNC5jcmwwHAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcN # AQEMBQADggIBADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcT # Ep6QRJ9L/Z6jfCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WT # auPrINHVUHmImoqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9 # ntSZz0rdKOtfJqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np37 # 5SFTWsPK6Wrxoj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0 # HKKlS43Nb3Y3LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL # 6TEa/y4ZXDlx4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+1 # 6oh7cGvmoLr9Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8 # M4+uKIw8y4+ICw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrF # hsP2JjMMB0ug0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy # 1lKQ/a+FSCH5Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIHVjCC # BT6gAwIBAgIQDyLHeeRvkUFg5QtSFTT8FjANBgkqhkiG9w0BAQsFADBpMQswCQYD # VQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lD # ZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEg # Q0ExMB4XDTIzMDIyMzAwMDAwMFoXDTI2MDIyMzIzNTk1OVowXjELMAkGA1UEBhMC # QVUxETAPBgNVBAgTCFZpY3RvcmlhMRAwDgYDVQQHEwdCZXJ3aWNrMRQwEgYDVQQK # EwtKYW1lcyBBcmJlcjEUMBIGA1UEAxMLSmFtZXMgQXJiZXIwggIiMA0GCSqGSIb3 # DQEBAQUAA4ICDwAwggIKAoICAQC47oExh25TrxvApIYdMRYvjOdZCb8WwgeTemm3 # ZY7BElIWu6+gzRGqQe8RFsN7oIgin5pvjTYIToxt1CCag2A5o8L0NtULmxJEegc+ # VaF24DZQqI4qGQGH/Qnglqys6+yPkwLnfeSxpeWe4u49HUUGDFIxHCh42MlCLp/f # fHT49QhhpO+LyeLnDoUs6DmahyIb6NeE2cW5AYRXEesW7GRNfXzygBSlVWJOgvcy # V5Y4IvAZVx2hKKMTjYFIz4/RYMg7fwYZEJ2LRJ/GnVazobKAvh6ZBet5KwVNI9EI # 29DtWQyK/RoPOguTRcB5VuiZVlv0xjBYM7iJuH2Soa3StQYVxL/5gjZCC9WOs4NR # EIGU3XmHoogFDvoT1vf1izMPFQzdZfgPvy/XXsbgTVo5ncesJ6WtZwqwCXG1K0XW # IPZqTHolc1MyU6K1bEHO+7YWLpKgM9THl644G7PEhcKpNDsHlfvLVQdYhI55UJtc # iyMrTw11CNECvk3GK1mrluvKsrxdaH6G3Sp9VVHRtef6OZ5SlzkM5ID4egB2bXRb # R/69bEuZr5hhm+v2lBSWIbZj/Mva6i/a/TAvy4vvPLo3DRcASkYZDC4T8gDMzmpG # Xs4jAc9sfTL9z+o5u1PLJHFGRjJ+Wa2CgSftCdbKLjn+AY9m8ipc8jmOBKNY9yGI # pQWapQIDAQABo4ICAzCCAf8wHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0 # TkIwHQYDVR0OBBYEFOBsg1xudlbXVSql8pWbiHoTyZS/MA4GA1UdDwEB/wQEAwIH # gDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRw # Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmlu # Z1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGln # aWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hB # Mzg0MjAyMUNBMS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcC # ARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMIGUBggrBgEFBQcBAQSBhzCB # hDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUF # BzAChlBodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVk # RzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAJBgNVHRMEAjAA # MA0GCSqGSIb3DQEBCwUAA4ICAQBOh5vRXqTCQzv0T1F2EgDkq5VnljlHsa7Ov/d/ # lpOvr8NebBiatxbhfhPCnToY7BD2f7YVsUuQ+VDdcIYsskcU5spBHcFYidg2jGu4 # 59FGMaS765XStDwGGTN/360gEsNYSnKWYL4+8jYWHlzRO0jHloyWz+gF5dYWzdDJ # u1dudLIJ0RgrEVJeLSgIBWygLL5EyIzOPlrxztsILMSbdPTQLeBIm7ipOk4EACx1 # hhBVUsUoCAlASH+yCKDU4v2HFd7SzrkRUrf7XJ2Na2YsiHjiTGqHIE86KyvxGDhT # 3n2/jX23Nh/bkWHurHwTfaTCOQ44ZlAbnZQjBlmrFn5hPMXRpciiQFmrKTPD/nuo # 9MVnCciHEpHJ63/JZNF/eno1122/wVkL7MuRlCVHN7L/wuNQxQk3ARdIju6OD/Gi # Mwg0Qih6HVWJtkHK3ExoUKKKUZCOvIeHxzp+K6FWUupPZKUgWzn4AHMxm6zr+Sde # laIAACqAkxYsDYKbM7WlNi3uIH2HeXqU9uSDt5tgPpImrog/ab4HrhpDfITRgT1c # cxaWQezpJEPC+kqVD41T3wlEie1Qm4vYWg+oBVEMBxVLh6CYbeppCRTEXRGnAiCH # /Ma1uwyWnNCWxrhd1uSi6sj4ISzgnFyGCvsI0gavKpS5AQhapJgk6/fULTFeS+Ee # kRH9FDGCAx4wggMaAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lD # ZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2ln # bmluZyBSU0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQDyLHeeRvkUFg5QtSFTT8FjAJ # BgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0B # CQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAj # BgkqhkiG9w0BCQQxFgQUz7Ac7tehNVq8iVyyIwQvZspnoBAwDQYJKoZIhvcNAQEB # BQAEggIAiBngpp7EtlJHDdvCS4ODKlC0FzNBieCOFjOPGyhcdA9JtvVziPUokGrH # yn3OZ0XXh+JY0ypLT3LY1J44+yYvEkfs8CtcHVZvFOmqcGqp7bi88s+/ClZHEEsB # phwHKHldhlRTgUA2pc4CwcauClhJ65Aked9sIionLwld9sQbtu66ET0rgHv9+8fL # 2MNaOqCzfHLGG3TUhrVn/X5UGZ7kgrAHGI6BzaOFb+QxpwqWlwmPmkcYLIaphksW # WvN5/DzbZ45FcxtwVI/xt5qFp391b3tQyoG5G9UJRG8igmwq0joIj2zogvdG6jJD # UGpbIgrX89ALKNXMkSQCPkdnqv1b+RoMOl8ioJwi3VwUeck5vJshUZ/g+ciBbTCW # 9x11bVb/bhwnasIpNilkFJTzi7RGrez50dqU/9tvNGP5afdKLUd6pw7r45BSnxiw # okPV3aqlLakeTuPI0hs4e54+KlSZP7XVwGWrby8JNMkaNvlLKi0qVGIrlvPkTJd3 # kZZZhJOkIm3F7C3Ay2OEYt2vd0ECT6JbLSMpLs6Lbmly24ugimtDd08anIXeU1Ip # eDkx/CE8azCDf3+G3hSyTJyZuwtQde82ALByHjMkm96+2a1IihpYgwd4oCGwdHxQ # I6gZOzdyqjj7OyS5onjWCrLYjImYtiZYWb1IcjMaIJzUSxmxezk= # SIG # End signature block |