D365SalesIAM.psm1
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 #==================================================================== # if (-not(get-module -ListAvailable -Name JWTDetails)) { # Install-Module -Name JWTDetails -AllowClobber -Force # } # if (-not(get-module -ListAvailable -Name MSAL.PS)) { # Install-Module -Name MSAL.PS -AllowClobber -Force # } # JWT Token Module # Import-Module JWTDetails # Set-ExecutionPolicy RemoteSigned Import-Module -Name $PSScriptRoot\Modules\JWTDetails\1.0.3\JWTDetails.psm1 # MSAL.PS Token Module # Import-Module MSAL.PS # Import-Module -Name $PSScriptRoot\Modules\MSAL.PS\4.37.0.0\MSAL.PS.psm1 function Set-D365SalesGlobals { <# .SYNOPSIS Set Global variables used in D365 oData API functions .DESCRIPTION Set Global variables used in D365 oData API functions .PARAMETER D365SalesOrgURI D365 Org Id. e.g. https://YOUROrg.api.crm6.dynamics.com/ .PARAMETER EntraIDTenantID Entra ID TenantId e.g. https://yourtenant.onmicrosoft.com or d227d874-8033-4640-8a16-a86e1d3e9eee .PARAMETER D365SalesCreds PS Credential object with EntraID Application Registration Client (Application) ID as UserName and EntraID Application Registration Client Secret as the Password. e.g. d55a2c66-727a-460d-ba91-56bd167ccdad & System.Security.SecureString .INPUTS Token from Pipeline .OUTPUTS PowerShell Object SYNTAX Set-D365SalesGlobals .EXAMPLE PS> Set-D365SalesGlobals -D365SalesOrgURI "https://yourtenant.api.crm6.dynamics.com" -EntraIDTenantID "https://yourtenant.onmicrosoft.com" -D365SalesCreds $myD365SalesCreds .LINK https://blog.darrenjrobinson.com #> [cmdletbinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$D365SalesOrgURI, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$EntraIDTenantID, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [pscredential]$D365SalesCreds ) if (-not $D365SalesOrgURI.EndsWith("/")) { $D365SalesOrgURI = "$($D365SalesOrgURI)/" } $Global:D365SalesOrgURI = $D365SalesOrgURI $Global:EntraIDTenantID = $EntraIDTenantID $Global:D365SalesAPIURI = "$($D365SalesOrgURI)api/data/v9.2" $Global:d365SalesCreds = $D365SalesCreds if ($null -ne $D365SalesCreds.UserName -and $null -ne $D365SalesCreds.Password) { Try { $Global:D365SalesToken = Get-D365SalesToken if (get-module -name JWTDetails) { Get-JWTDetails -token ($Global:D365SalesToken) } } catch { Write-Error $_ -ErrorAction Continue } } } Function Get-D365SalesToken { <# .SYNOPSIS Acquires an access token for Dynamics 365 Sales using OAuth2 client credentials authentication. .DESCRIPTION The Get-D365SalesToken function retrieves an access token for Dynamics 365 Sales using the OAuth2 client credentials grant flow. It requires the global variables $Global:d365SalesCreds, $Global:D365SalesOrgURI, and $Global:EntraIDTenantID to be set beforehand, which contain the Dynamics 365 Sales client ID, client secret, organization URI, and EntraID tenant ID, respectively. The function returns the acquired access token. .PARAMETER None. .INPUTS None. .OUTPUTS The acquired access token as a string. .EXAMPLE # Assuming $Global:d365SalesCreds, $Global:D365SalesOrgURI, and $Global:EntraIDTenantID are set using Set-D365SalesGlobals $d365SalesToken = Get-D365SalesToken #> [cmdletbinding()] param() $tokenBody = @{ "grant_type" = "client_credentials" "client_id" = $Global:d365SalesCreds.UserName "client_secret" = $Global:d365SalesCreds.GetNetworkCredential().Password #($Global:d365SalesCreds.Password | ConvertFrom-SecureString) "resource" = $Global:D365SalesOrgURI } try { $tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$Global:EntraIDTenantID/oauth2/token" -Method POST -Body $tokenBody return $tokenResponse.access_token } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Get-D365SalesSystemUsers { <# .SYNOPSIS Retrieves Dynamics 365 Sales system users. .DESCRIPTION The Get-D365SalesSystemUsers function retrieves Dynamics 365 Sales system users using the REST API. It optionally takes a systemuser ID as a parameter to retrieve a specific user. If no parameter is specified, all system users are retrieved. The function returns the user data as a PowerShell object. .PARAMETER systemuserid (Optional) The ID of the system user to retrieve. .INPUTS None. .OUTPUTS value: A PowerShell object containing the user data. .EXAMPLE Retrieving all system users Get-D365SalesSystemUsers .EXAMPLE Retrieving a specific system user: Get-D365SalesSystemUsers -systemuserid "00000000-0000-0000-0000-000000000000" Get-D365SalesSystemUsers -filter "internalemailaddress eq 'some.email@address'" #> [cmdletbinding()] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$systemuserid, [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$filter, [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$select ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { if ($systemuserid) { $uri = "$($Global:D365SalesAPIURI)/systemusers($($systemuserid))" if ($select) { $uri = $uri + "?`$select=$($select)" } $response = Invoke-RestMethod -Method Get -Uri $uri -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response } elseif ($filter) { $uri = "$($Global:D365SalesAPIURI)/systemusers?`$filter=$($filter)" if ($select) { $uri = $uri + "&`$select=$($select)" } $response = Invoke-RestMethod -Method Get ` -Uri $uri ` -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response.value[0] } else { $uri = "$($Global:D365SalesAPIURI)/systemusers" if ($select) { $uri = $uri + "?`$select=$($select)" } $response = Invoke-RestMethod -Method Get -Uri $uri -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response.value } } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Get-D365SalesSystemRoles { <# .SYNOPSIS Retrieves Dynamics 365 Sales system roles. .DESCRIPTION The Get-D365SalesSystemRoles function retrieves Dynamics 365 Sales system roles using the REST API. It optionally takes a role ID as a parameter to retrieve a specific role. If no parameter is specified, all system roles are retrieved. The function returns the role data as a PowerShell object. .PARAMETER roleid (Optional) The ID of the system role to retrieve. .INPUTS None. .OUTPUTS A PowerShell object containing the role data. .EXAMPLE Retrieving all system roles Get-D365SalesSystemRoles .EXAMPLE Retrieving a specific system role Get-D365SalesSystemRoles -roleid "00000000-0000-0000-0000-000000000000" #> [cmdletbinding()] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$roleid, [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$select ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { if ($roleid) { $uri = "$($Global:D365SalesAPIURI)/roles($($roleid))" if ($select) { $uri = $uri + "?`$select=$($select)" } $response = Invoke-RestMethod -Method Get -Uri $uri -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response } else { $uri = "$($Global:D365SalesAPIURI)/roles" if ($select) { $uri = $uri + "?`$select=$($select)" } $response = Invoke-RestMethod -Method Get -Uri $uri -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response.value } } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Get-D365SalesSystemUserRoles { <# .SYNOPSIS Retrieves the system user roles associated with a specified Dynamics 365 Sales system user. .DESCRIPTION The Get-D365SalesSystemUserRoles function retrieves the system user roles associated with a specified Dynamics 365 Sales system user using the REST API. It requires the system user ID as a mandatory parameter. The function returns the system user role data as a PowerShell object. .PARAMETER systemuserid (Mandatory) The ID of the system user for which to retrieve system user roles. .INPUTS None. .OUTPUTS value: A PowerShell object containing the system user role data. .EXAMPLE Get-D365SalesSystemUserRoles -systemuserid "00000000-0000-0000-0000-000000000000" #> [cmdletbinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$systemuserid, [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$select ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { $uri = "$($Global:D365SalesAPIURI)/systemusers($($systemuserid))/systemuserroles_association" if ($select) { $uri = $uri + "?`$select=$($select)" } $response = Invoke-RestMethod -Method Get -Uri $uri -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response.value } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Get-D365SalesRolesSystemUserMembership { <# .SYNOPSIS Retrieves the system users associated with a specified Dynamics 365 Sales system role. .DESCRIPTION The Get-D365SalesRolesSystemUserMembership function retrieves the system users associated with a specified Dynamics 365 Sales system role using the REST API. It requires the system role ID as a mandatory parameter. The function returns the system user membership data as a PowerShell object. .PARAMETER roleid (Mandatory) The ID of the system role for which to retrieve associated system users. .INPUTS None. .OUTPUTS value: A PowerShell object containing the system user membership data. .EXAMPLE Get-D365SalesRolesSystemUserMembership -roleid "00000000-0000-0000-0000-000000000000" #> [cmdletbinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$roleid, [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$select ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { $uri = "$($Global:D365SalesAPIURI)/roles($($roleid))/systemuserroles_association" if ($select) { $uri = $uri + "?`$select=$($select)" } $response = Invoke-RestMethod -Method Get -Uri $uri -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response.value } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Add-D365SalesRoleToSystemUser { <# .SYNOPSIS Adds a Dynamics 365 Sales system role to a specified system user. .DESCRIPTION The Add-D365SalesRoleToSystemUser function adds a specified Dynamics 365 Sales system role to a specified system user using the REST API. It requires the system user ID and system role ID as mandatory parameters. The function returns the response from the REST API. .PARAMETER systemuserid (Mandatory) The ID of the system user to which to add the system role. .PARAMETER roleid (Mandatory) The ID of the system role to add to the system user. .INPUTS None. .Outputs The response from the REST API as a PowerShell object. .EXAMPLE Add-D365SalesRoleToSystemUser -systemuserid "00000000-0000-0000-0000-000000000000" -roleid "00000000-0000-0000-0000-000000000000" #> [cmdletbinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$systemuserid, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$roleid ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { $body = @{"@odata.id" = "$($Global:D365SalesAPIURI)/roles($($roleid))" } $response = Invoke-RestMethod -Method Post -Uri "$($Global:D365SalesAPIURI)/systemusers($($systemuserid))/systemuserroles_association/`$ref" -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } -Body ($body | ConvertTo-Json) return $response } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Remove-D365SalesRoleFromSystemUser { <# .SYNOPSIS Removes a Dynamics 365 Sales system role from a specified system user. .DESCRIPTION The Remove-D365SalesRoleFromSystemUser function removes a specified Dynamics 365 Sales system role from a specified system user using the REST API. It requires the system user ID and system role ID as mandatory parameters. The function returns the response from the REST API. .PARAMETER systemuserid (Mandatory) The ID of the system user from which to remove the system role. .PARAMETER roleid (Mandatory) The ID of the system role to remove from the system user. .INPUTS None. .OUTPUTS The response from the REST API as a PowerShell object. .EXAMPLE Remove-D365SalesRoleFromSystemUser -systemuserid "00000000-0000-0000-0000-000000000000" -roleid "00000000-0000-0000-0000-000000000000" #> [cmdletbinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$systemuserid, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$roleid ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { $response = Invoke-RestMethod -Method Delete -Uri "$($Global:D365SalesAPIURI)/roles($($roleid))/systemuserroles_association($($systemuserid))/`$ref" -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Get-D365SalesBusinessUnits { <# .SYNOPSIS Retrieves Dynamics 365 Sales business units. .DESCRIPTION The Get-D365SalesBusinessUnits function retrieves Dynamics 365 Sales business units using the REST API. It requires the Global:D365SalesToken variable to be set, which contains the access token for Dynamics 365 Sales. The function returns the business unit data as a PowerShell object. .PARAMETER None. .INPUTS None. .OUTPUTS value: A PowerShell object containing the business unit data. .EXAMPLE $Global:D365SalesToken = Get-D365SalesToken $businessUnits = Get-D365SalesBusinessUnits Write-Output $businessUnits #> [cmdletbinding()] param( [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$filter, [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$select ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { if ($filter) { $uri = "$($Global:D365SalesAPIURI)/businessunits?`$filter=$($filter)" if ($select) { $uri = $uri + "&`$select=$($select)" } } else { $uri = "$($Global:D365SalesAPIURI)/businessunits" if ($select) { $uri = $uri + "?`$select=$($select)" } } $response = Invoke-RestMethod -method Get -URI $uri -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response.value } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Get-D365SalesOrganisations { <# .SYNOPSIS Retrieves Dynamics 365 Sales organizations. .DESCRIPTION The Get-D365SalesOrganisations function retrieves Dynamics 365 Sales organizations using the REST API. It requires the Global:D365SalesToken variable to be set, which contains the access token for Dynamics 365 Sales. The function returns the organization data as a PowerShell object. .PARAMETER None. .INPUTS None. .OUTPUTS value: A PowerShell object containing the organization data. .EXAMPLE $organizations = Get-D365SalesOrganisations Write-Output $organizations #> [cmdletbinding()] param() # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { $response = Invoke-RestMethod -method Get ` -URI "$($Global:D365SalesAPIURI)/organizations" ` -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } return $response.value } catch { Write-Error $_ throw GetErrorMessage $_ } } Function New-D365SalesSystemUser { <# .SYNOPSIS Creates a new Dynamics 365 Sales system user. .DESCRIPTION The New-D365SalesSystemUser function creates a new Dynamics 365 Sales system user using the REST API. It requires a PSCustomObject containing the system user details as a mandatory parameter. The function returns the response from the REST API. .Parameter userDetails (Mandatory) A PSCustomObject containing the system user details. The PSCustomObject should have properties corresponding to the required system user fields, such as firstname, lastname, fullname, emailaddress1, and domainname. .INPUTS None. .OUTPUTS The response from the REST API as a PowerShell object. .EXAMPLE # Create a PSCustomObject with system user details New-D365SalesSystemUser -userDetails $userDetails #> [cmdletbinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [PSCustomObject]$userDetails ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { $response = Invoke-RestMethod -Method Post -Uri "$($Global:D365SalesAPIURI)/systemusers" -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } -Body ($userDetails | ConvertTo-Json) return $response } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Update-D365SalesSystemUser { <# .SYNOPSIS Updates an existing Dynamics 365 Sales system user. .DESCRIPTION The Update-D365SalesSystemUser function updates an existing Dynamics 365 Sales system user using the REST API. It requires a PSCustomObject containing the updated system user details as a mandatory parameter, along with the system user ID to identify the user to be updated. The function returns the response from the REST API. .PARAMETER userDetails (Mandatory) A PSCustomObject containing the updated system user details. The PSCustomObject should have properties corresponding to the updated fields, such as firstname, lastname, fullname, emailaddress1, and domainname. .PARAMETER systemuserid (Mandatory) The ID of the system user to update. .INPUTS None. .OUTPUTS The response from the REST API as a PowerShell object. .EXAMPLE # Create a PSCustomObject with updated system user details $userDetails = New-Object PSCustomObject -Property @{ firstname = "Jane" lastname = "Doe" fullname = "Jane Doe" } # Update the system user with ID "00000000-0000-0000-0000-000000000000" $systemuserid = "00000000-0000-0000-0000-000000000000" $response = Update-D365SalesSystemUser -userDetails $userDetails -systemuserid $systemuserid #> [cmdletbinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [PSCustomObject]$userDetails, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [PSCustomObject]$systemuserid ) # Refresh Token $Global:D365SalesToken = Get-D365SalesToken Try { $response = Invoke-RestMethod -Method Patch ` -Uri "$($Global:D365SalesAPIURI)/systemusers($($systemuserid))" ` -Headers @{Authorization = "Bearer $($D365SalesToken)"; "Content-Type" = "application/json" } ` -Body ($userDetails | ConvertTo-Json) return $response } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Get-MicrosoftGraphToken { [cmdletbinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [pscredential]$msgraphCredential, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$EntraIDTenantID, [Parameter(Mandatory = $false, ValueFromPipeline = $true, Position = 0)] [string]$RedirectUri = "https://localhost" ) <# .SYNOPSIS Obtains an access token for the Microsoft Graph API using EntraID authentication. .DESCRIPTION The Get-MicrosoftGraphToken function acquires an access token for the Microsoft Graph API by utilizing EntraID authentication. It requires the EntraID credentials, EntraID tenant ID, and optionally a redirect URI as mandatory parameters. The function returns the acquired access token. .Parameter msgraphCredential (Mandatory) The EntraID credentials for accessing the Microsoft Graph API. .Parameter EntraIDTenantID (Mandatory) The EntraID tenant ID associated with the Microsoft Graph API tenant. .Parameter RedirectUri (Optional) The redirect URI to be used during the authentication process. Defaults to "https://localhost". .INPUTS None. .OUTPUTS The acquired access token as a string. .EXAMPLE # Assuming $msgraphCredential is a PSCredential object containing EntraID credentials $EntraIDTenantID = "<EntraID_tenant_ID>" $msgraphAccessToken = Get-MicrosoftGraphToken -msgraphCredential $msgraphCredential -EntraIDTenantID $EntraIDTenantID - RedirectUri = "http://localhost" #> # Import-Module MSAL.PS Set-ExecutionPolicy Bypass Import-Module -Name $PSScriptRoot\Modules\MSAL.PS\4.37.0.0\MSAL.PS.psm1 $entraIDToken = Get-MsalToken -ClientId $Global:d365SalesCreds.UserName -ClientSecret $Global:d365SalesCreds.Password -RedirectUri "https://localhost" -TenantId $Global:EntraIDTenantID -ForceRefresh return $entraIDToken.AccessToken } Function Invoke-MicrosoftGraphPostRequest { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$URI, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$msgraphAccessToken, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$postBody ) <# .SYNOPSIS Executes a POST request to the Microsoft Graph API using the provided access token and post body. .DESCRIPTION The Invoke-MicrosoftGraphPostRequest function simplifies the process of making POST requests to the Microsoft Graph API. It requires the target URI, access token, and post body as mandatory parameters. The function returns the response from the REST API. .Parameter URI (Mandatory) The URI of the Microsoft Graph API endpoint to which to send the POST request. .Parameter msgraphAccessToken (Mandatory) The access token for accessing the Microsoft Graph API. .Parameter postBody (Mandatory) The JSON-formatted post body to be included in the POST request. .INPUTS None. .OUTPUTS The response from the REST API as a PowerShell object. .EXAMPLE $URI = "https://graph.microsoft.com/v1.0/users" $msgraphAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cm4iOiJ1cGVyOjM3ODQ1MTE1LTUwN2EtNDcwOS04YjEwLTU4ZTE2OGNmYjU1OSIsImlzcyI6IjE4YzE1ZDZhLWRmZGMtNDk4NC04YjY0LTU2MzI4OTk5YjE2MiIsInJvb2JpIjoidWNlcnJlZ2lvbi1zaGQifQ.4-hK-5jY2h7h9pK05h7r5_8y6-8-QzPq5-6Z5w9yM" $postBody = @{"displayName" = "John Doe"; "userPrincipalName" = "johndoe@example.com"} $response = Invoke-MicrosoftGraphPostRequest -URI $URI -msgraphAccessToken $msgraphAccessToken -postBody $postBody Write-Output $response #> try { $response = Invoke-RestMethod -Method Post ` -Uri $URI ` -Headers @{"Authorization" = "Bearer $($msgraphAccessToken)"; "Content-Type" = "application/json" } ` -Body $postBody return $response } catch { Write-Error $_ throw GetErrorMessage $_ } } Function Invoke-MicrosoftGraphGetRequest { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$URI, [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] [string]$msgraphAccessToken ) <# $URI = "https://graph.microsoft.com/v1.0/users" $msgraphAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cm4iOiJ1bGVrOjM3ODQ1MTE1LTUwN2EtNEcwOS04YjEwLTU4ZTE2OGNmYjU1OSIsImlzcyI6IjE4YzE1ZDZhLWRmZGMtNDk4NC04YjY0LTU2MzI4OTk5YjE2MiIsInJvb2JpIjoidWNlcnJlZ2lvbi1zaGQifQ.4-hK-5jY2h7h9pK05h7r5_8y6-8-QzPq5-6Z5w9yM" $postBody = @{"displayName" = "John Doe"; "userPrincipalName" = "johndoe@example.com"} $response = Invoke-MicrosoftGraphPostRequest -URI $URI -msgraphAccessToken $msgraphAccessToken -postBody $postBody Write-Output $response #> try { $response = Invoke-RestMethod -Method Get ` -Uri $URI ` -Headers @{"Authorization" = "Bearer $($msgraphAccessToken)"; "Content-Type" = "application/json" } return $response } catch { Write-Error $_ throw GetErrorMessage $_ } } function GetErrorMessage { param( [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)] $exception ) $streamReader = [System.IO.StreamReader]::new($exception.Exception.Response.GetResponseStream()) try { $streamReader.BaseStream.Position = 0 $ErrResp = $streamReader.ReadToEnd() | ConvertFrom-Json } finally { $streamReader.Close() } return $ErrResp.error.message } # SIG # Begin signature block # MIIoJQYJKoZIhvcNAQcCoIIoFjCCKBICAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCClGDHLYDeVZJnE # WLksdftpGldsPgmsG8zD8YcCecPSj6CCISgwggWNMIIEdaADAgECAhAOmxiO+dAt # 5+/bUOIIQBhaMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0yMjA4MDEwMDAwMDBa # Fw0zMTExMDkyMzU5NTlaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lD # ZXJ0IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC # ggIBAL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3E # MB/zG6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKy # unWZanMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsF # xl7sWxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU1 # 5zHL2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJB # MtfbBHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObUR # WBf3JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6 # nj3cAORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxB # YKqxYxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5S # UUd0viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+x # q4aLT8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjggE6MIIB # NjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTs1+OC0nFdZEzfLmc/57qYrhwP # TzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd823IDzAOBgNVHQ8BAf8EBAMC # AYYweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp # Y2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNv # bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwRQYDVR0fBD4wPDA6oDigNoY0 # aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENB # LmNybDARBgNVHSAECjAIMAYGBFUdIAAwDQYJKoZIhvcNAQEMBQADggEBAHCgv0Nc # Vec4X6CjdBs9thbX979XB72arKGHLOyFXqkauyL4hxppVCLtpIh3bb0aFPQTSnov # Lbc47/T/gLn4offyct4kvFIDyE7QKt76LVbP+fT3rDB6mouyXtTP0UNEm0Mh65Zy # oUi0mcudT6cGAxN3J0TU53/oWajwvy8LpunyNDzs9wPHh6jSTEAZNUZqaVSwuKFW # juyk1T3osdz9HNj0d1pcVIxv76FQPfx2CWiEn2/K2yCNNWAcAgPLILCsWKAOQGPF # mCLBsln1VWvPJ6tsds5vIy30fnFqI2si/xK4VC0nftg62fC2h5b9W9FcrBjDTZ9z # twGpn1eqXijiuZQwggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqG # SIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMx # GTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRy # dXN0ZWQgUm9vdCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMx # CzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMy # RGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcg # Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXH # JQPE8pE3qZdRodbSg9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMf # UBMLJnOWbfhXqAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w # 1lbU5ygt69OxtXXnHwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRk # tFLydkf3YYMZ3V+0VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYb # qMFkdECnwHLFuk4fsbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUm # cJgmf6AaRyBD40NjgHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP6 # 5x9abJTyUpURK1h0QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzK # QtwYSH8UNM/STKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo # 80VgvCONWPfcYd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjB # Jgj5FBASA31fI7tk42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXche # MBK9Rp6103a50g5rmQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB # /wIBADAdBgNVHQ4EFgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU # 7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoG # CCsGAQUFBwMIMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29j # c3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDig # NqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v # dEc0LmNybDAgBgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZI # hvcNAQELBQADggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd # 4ksp+3CKDaopafxpwc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiC # qBa9qVbPFXONASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl # /Yy8ZCaHbJK9nXzQcAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeC # RK6ZJxurJB4mwbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYT # gAnEtp/Nh4cku0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/ # a6fxZsNBzU+2QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37 # xJV77QpfMzmHQXh6OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmL # NriT1ObyF5lZynDwN7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0 # YgkPCr2B2RP+v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJ # RyvmfxqkhQ/8mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIG # sDCCBJigAwIBAgIQCK1AsmDSnEyfXs2pvZOu2TANBgkqhkiG9w0BAQwFADBiMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQw # HhcNMjEwNDI5MDAwMDAwWhcNMzYwNDI4MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEX # MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0 # ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMIICIjAN # BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1bQvQtAorXi3XdU5WRuxiEL1M4zr # PYGXcMW7xIUmMJ+kjmjYXPXrNCQH4UtP03hD9BfXHtr50tVnGlJPDqFX/IiZwZHM # gQM+TXAkZLON4gh9NH1MgFcSa0OamfLFOx/y78tHWhOmTLMBICXzENOLsvsI8Irg # nQnAZaf6mIBJNYc9URnokCF4RS6hnyzhGMIazMXuk0lwQjKP+8bqHPNlaJGiTUyC # EUhSaN4QvRRXXegYE2XFf7JPhSxIpFaENdb5LpyqABXRN/4aBpTCfMjqGzLmysL0 # p6MDDnSlrzm2q2AS4+jWufcx4dyt5Big2MEjR0ezoQ9uo6ttmAaDG7dqZy3SvUQa # khCBj7A7CdfHmzJawv9qYFSLScGT7eG0XOBv6yb5jNWy+TgQ5urOkfW+0/tvk2E0 # XLyTRSiDNipmKF+wc86LJiUGsoPUXPYVGUztYuBeM/Lo6OwKp7ADK5GyNnm+960I # HnWmZcy740hQ83eRGv7bUKJGyGFYmPV8AhY8gyitOYbs1LcNU9D4R+Z1MI3sMJN2 # FKZbS110YU0/EpF23r9Yy3IQKUHw1cVtJnZoEUETWJrcJisB9IlNWdt4z4FKPkBH # X8mBUHOFECMhWWCKZFTBzCEa6DgZfGYczXg4RTCZT/9jT0y7qg0IU0F8WD1Hs/q2 # 7IwyCQLMbDwMVhECAwEAAaOCAVkwggFVMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYD # VR0OBBYEFGg34Ou2O/hfEYb7/mF7CIhl9E5CMB8GA1UdIwQYMBaAFOzX44LScV1k # TN8uZz/nupiuHA9PMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcD # AzB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj # ZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t # L0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0 # cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmww # HAYDVR0gBBUwEzAHBgVngQwBAzAIBgZngQwBBAEwDQYJKoZIhvcNAQEMBQADggIB # ADojRD2NCHbuj7w6mdNW4AIapfhINPMstuZ0ZveUcrEAyq9sMCcTEp6QRJ9L/Z6j # fCbVN7w6XUhtldU/SfQnuxaBRVD9nL22heB2fjdxyyL3WqqQz/WTauPrINHVUHmI # moqKwba9oUgYftzYgBoRGRjNYZmBVvbJ43bnxOQbX0P4PpT/djk9ntSZz0rdKOtf # JqGVWEjVGv7XJz/9kNF2ht0csGBc8w2o7uCJob054ThO2m67Np375SFTWsPK6Wrx # oj7bQ7gzyE84FJKZ9d3OVG3ZXQIUH0AzfAPilbLCIXVzUstG2MQ0HKKlS43Nb3Y3 # LIU/Gs4m6Ri+kAewQ3+ViCCCcPDMyu/9KTVcH4k4Vfc3iosJocsL6TEa/y4ZXDlx # 4b6cpwoG1iZnt5LmTl/eeqxJzy6kdJKt2zyknIYf48FWGysj/4+16oh7cGvmoLr9 # Oj9FpsToFpFSi0HASIRLlk2rREDjjfAVKM7t8RhWByovEMQMCGQ8M4+uKIw8y4+I # Cw2/O/TOHnuO77Xry7fwdxPm5yg/rBKupS8ibEH5glwVZsxsDsrFhsP2JjMMB0ug # 0wcCampAMEhLNKhRILutG4UI4lkNbcoFUCvqShyepf2gpx8GdOfy1lKQ/a+FSCH5 # Vzu0nAPthkX0tGFuv2jiJmCG6sivqf6UHedjGzqGVnhOMIIGvDCCBKSgAwIBAgIQ # C65mvFq6f5WHxvnpBOMzBDANBgkqhkiG9w0BAQsFADBjMQswCQYDVQQGEwJVUzEX # MBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRydXN0 # ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBMB4XDTI0MDkyNjAw # MDAwMFoXDTM1MTEyNTIzNTk1OVowQjELMAkGA1UEBhMCVVMxETAPBgNVBAoTCERp # Z2lDZXJ0MSAwHgYDVQQDExdEaWdpQ2VydCBUaW1lc3RhbXAgMjAyNDCCAiIwDQYJ # KoZIhvcNAQEBBQADggIPADCCAgoCggIBAL5qc5/2lSGrljC6W23mWaO16P2RHxjE # iDtqmeOlwf0KMCBDEr4IxHRGd7+L660x5XltSVhhK64zi9CeC9B6lUdXM0s71EOc # Re8+CEJp+3R2O8oo76EO7o5tLuslxdr9Qq82aKcpA9O//X6QE+AcaU/byaCagLD/ # GLoUb35SfWHh43rOH3bpLEx7pZ7avVnpUVmPvkxT8c2a2yC0WMp8hMu60tZR0Cha # V76Nhnj37DEYTX9ReNZ8hIOYe4jl7/r419CvEYVIrH6sN00yx49boUuumF9i2T8U # uKGn9966fR5X6kgXj3o5WHhHVO+NBikDO0mlUh902wS/Eeh8F/UFaRp1z5SnROHw # SJ+QQRZ1fisD8UTVDSupWJNstVkiqLq+ISTdEjJKGjVfIcsgA4l9cbk8Smlzddh4 # EfvFrpVNnes4c16Jidj5XiPVdsn5n10jxmGpxoMc6iPkoaDhi6JjHd5ibfdp5uzI # Xp4P0wXkgNs+CO/CacBqU0R4k+8h6gYldp4FCMgrXdKWfM4N0u25OEAuEa3Jyidx # W48jwBqIJqImd93NRxvd1aepSeNeREXAu2xUDEW8aqzFQDYmr9ZONuc2MhTMizch # NULpUEoA6Vva7b1XCB+1rxvbKmLqfY/M/SdV6mwWTyeVy5Z/JkvMFpnQy5wR14GJ # cv6dQ4aEKOX5AgMBAAGjggGLMIIBhzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/ # BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAgBgNVHSAEGTAXMAgGBmeBDAEE # AjALBglghkgBhv1sBwEwHwYDVR0jBBgwFoAUuhbZbU2FL3MpdpovdYxqII+eyG8w # HQYDVR0OBBYEFJ9XLAN3DigVkGalY17uT5IfdqBbMFoGA1UdHwRTMFEwT6BNoEuG # SWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJTQTQw # OTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcmwwgZAGCCsGAQUFBwEBBIGDMIGAMCQG # CCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wWAYIKwYBBQUHMAKG # TGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFJT # QTQwOTZTSEEyNTZUaW1lU3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggIB # AD2tHh92mVvjOIQSR9lDkfYR25tOCB3RKE/P09x7gUsmXqt40ouRl3lj+8QioVYq # 3igpwrPvBmZdrlWBb0HvqT00nFSXgmUrDKNSQqGTdpjHsPy+LaalTW0qVjvUBhcH # zBMutB6HzeledbDCzFzUy34VarPnvIWrqVogK0qM8gJhh/+qDEAIdO/KkYesLyTV # OoJ4eTq7gj9UFAL1UruJKlTnCVaM2UeUUW/8z3fvjxhN6hdT98Vr2FYlCS7Mbb4H # v5swO+aAXxWUm3WpByXtgVQxiBlTVYzqfLDbe9PpBKDBfk+rabTFDZXoUke7zPgt # d7/fvWTlCs30VAGEsshJmLbJ6ZbQ/xll/HjO9JbNVekBv2Tgem+mLptR7yIrpaid # RJXrI+UzB6vAlk/8a1u7cIqV0yef4uaZFORNekUgQHTqddmsPCEIYQP7xGxZBIhd # mm4bhYsVA6G2WgNFYagLDBzpmk9104WQzYuVNsxyoVLObhx3RugaEGru+SojW4dH # PoWrUhftNpFC5H7QEY7MhKRyrBe7ucykW7eaCuWBsBb4HOKRFVDcrZgdwaSIqMDi # CLg4D+TPVgKx2EgEdeoHNHT9l3ZDBD+XgbF+23/zBjeCtxz+dL/9NWR6P2eZRi7z # cEO1xwcdcqJsyz/JceENc2Sg8h3KeFUCS7tpFk7CrDqkMIIHbTCCBVWgAwIBAgIQ # CcjsXDR9ByBZzKg16Kdv+DANBgkqhkiG9w0BAQsFADBpMQswCQYDVQQGEwJVUzEX # MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0 # ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExMB4XDTIz # MDMyOTAwMDAwMFoXDTI2MDYyMjIzNTk1OVowdTELMAkGA1UEBhMCQVUxGDAWBgNV # BAgTD05ldyBTb3V0aCBXYWxlczEUMBIGA1UEBxMLQ2hlcnJ5YnJvb2sxGjAYBgNV # BAoTEURhcnJlbiBKIFJvYmluc29uMRowGAYDVQQDExFEYXJyZW4gSiBSb2JpbnNv # bjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMesp+e1UZ5doOnpL+ep # m6Iq6GYiqK8ZNcz1XBe7M7eBXwVy4tYP5ByIa6NORYEselVWI9XmO1M+cPS6jRMr # pZb9xtUH+NpKZO+eSthgTAtnEO1dWaAK6Y7AH/ZVjmgOTWZXBVibjAE/JQKIfZyx # 4Hm5FOH6hq3bslA+RUQpo3NQxNv2AuzckKQwbW7AoXINudj0duYCiDYshn/9mHzz # gL0VpNYRpmgEa7WWgc1JH17V+SYlaf6qMWpYoWuODwuDltSH2p57qAI2/4J6rUYE # vns7QZ9sgIUdGlUr596fp0Y4juypyVGE7Rr0a8PtByLWUupyV7Z5kKPr/MRjerXA # mBnf6AdhI3kY6Gjz356fZkPA49UuCIXFgyTZT84Ao6Klw+0RqJ70JDt449Uky7hd # a+h8h2PiUdf7rXQamV57mY65+lHAmc4+UgTuWsnpwnTuNlkbZxRnCw2D+W3qto2a # BhDebciKZzivfiAWlWfTcHtCpy96gM5L+OB45ezDpU6KAH1hwRSjORUlW5yoFTXU # bPUBRflU3O2bZ0wdAJeyUYaHWAayNoyFfuKdrmCLtIx726O06dz9Kg+cJf+1ZdJ7 # KcUvZgR2d8F19FV5G1CVMnOzhMZR2dnIeJ5h0EgcOKNHl3hMKFdVRx4lhW8tcrQQ # N4ZT2EgGfI9fBc0i3GXTFA0xAgMBAAGjggIDMIIB/zAfBgNVHSMEGDAWgBRoN+Dr # tjv4XxGG+/5hewiIZfROQjAdBgNVHQ4EFgQUBTFWqXTuYnNp+d03es2KM9JdGUgw # DgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMIG1BgNVHR8Ega0w # gaowU6BRoE+GTWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0 # ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3JsMFOgUaBPhk1o # dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2ln # bmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDA+BgNVHSAENzA1MDMGBmeBDAEE # ATApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwgZQG # CCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy # dC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEu # Y3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQELBQADggIBAFhACWjPMrcafwDfZ5me # /nUrkv4yYgIi535cddPAm/2swGDTuzSVBVHIMBp8LWLmzXPA1GbxBOmA4L8vvDgj # EpQF9I9Ph5MNYgYhg0xSpAIp9/KAoc4OQnwlyRGPN+CjayY40xxTz4/hHohWg4rn # JMIuVEjkMtKnMdTbpnqU85w78AQlfD79v/gWQ2dL1T3n18HOEjTt8VSurxkEhQ5I # 3SH8Cr9YhUv94ObWIUbOKUt5SG7m/d+y2mfkKRSOmRluLSoYLPWbx35pArsYkaPp # jf5Yl5jiJPY3GQzEU/SRVW0rrwDAbtKSN0gKWtZxijPDbs8aQUYCijFfje6OWGF4 # RnmPSQh0Ff8AyzPQcx9LjQ/8W7gUELsE6IFuXP5bj2i6geLy65LRe46QZlYDq/bM # azUoZQTlje/hs6pkOL4f1Kv7tbJZmMENVVURJNmeDRejvNliHaaGEAv/iF0Zo7pq # vj4wCCCGG3j/sNR5WSRYnxf5xQ4r9i9gZqk4yjwk/DJCW2rmKNCUoxNIZWh2EIlM # SDzw3DMKk2ylZdiY/LAi5GmbCyGLt6sTz/IE1w1NYwrp/z6v4I91lDgdXg+fTkhh # xt47hWmjMOD3ZYVSFzQmg8al1iQ/+6RYKgfsww64tIky8JOOZX/3ss/uhxKUjPJx # YJkOwQwUyoAYzjcu/AE7By0rMYIGUzCCBk8CAQEwfTBpMQswCQYDVQQGEwJVUzEX # MBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0 # ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAJyOxc # NH0HIFnMqDXop2/4MA0GCWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAI # oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB # CzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFpG1WLo+BJkQYT2n0xJ # Q3QF7sRX0B1xm9ZxgQiXf5KwMA0GCSqGSIb3DQEBAQUABIICAImuUzgXc5mbKGN8 # ARRQNk0/3h0GeUmnnVNdR7hWPN/ByL3BcZ/cgSh5MKvdSTLLPq9XmMc3q7TGYd1U # Ui9ao45pbsndYnvCgblmPq2YY4Zdv+t9vkCHTbaQJw14UdAVl71Cr0aWX5Up95/C # IkCcavTE+WyGMUuAGlejkMyTP/1Q09k7LOTT9KTOW2vvxhOFPni28n+bUnW2Gmdg # AVuSWuiVKZZZ8oSMyUilDT2xVU867yqDzRMUtqRyY1yMuyl+3vV0FF3RvvNryOH6 # t7/NsPMOrH3QBzZapoTkn4IprjyVUe0n8Seqby221kmYNzBvCr51pI5DzMRUnZhl # JccDQbMB+aDNxuAg+wCoaysnFGA6iRt3ExsyXHLde1SmvKbBBkeXmPcgRZbbrAU7 # /5rATHNmBPK62UfJz3xM2Mzkk4dXEbszNnuni0AIjicKUNnVCH7o7e450q/kwN6c # OpRb+XK6mdb+Bd2/yfQ3NpkPotBt9Kcq3VzKdub01W0jie1ie5ViJft6s5Si8R7U # P+tihqCCMXeGg3hz2QqwGfMFmMmlxuJUogpwzJtqJxhJchCJexv1GMwbbtCgDbYi # Uvnsnx0bDiBMEv8hW2iPvxplpG3D/Nz31CP5FAHHQy3q2f0wSnyNMqeY8IVHyZUU # Gp/JxfaCRJiNd6dqkIFkp+DcAIunoYIDIDCCAxwGCSqGSIb3DQEJBjGCAw0wggMJ # AgEBMHcwYzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMTsw # OQYDVQQDEzJEaWdpQ2VydCBUcnVzdGVkIEc0IFJTQTQwOTYgU0hBMjU2IFRpbWVT # dGFtcGluZyBDQQIQC65mvFq6f5WHxvnpBOMzBDANBglghkgBZQMEAgEFAKBpMBgG # CSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI1MDMxOTAy # MjMyNFowLwYJKoZIhvcNAQkEMSIEIAwWNijhcTCG4gfrsuMonEttIBu3DmzIcfRZ # qoJfCOyOMA0GCSqGSIb3DQEBAQUABIICACBpCp1PVzUDLE0S8AOF/fwIJKs0Jaac # VT6b4YE1rE85wpNBeVQiUhcnh2Cm0pmTxS91Fav+plbeRwGFXjEvO7IzzWdkd2yf # epTsBjzbWEG3jkmNiVTocjn4DW6Qf4IkTQO8j8kSeVV1jSp683FiS/FxGQj9w/Om # uSrPXSxhc4g/QFTQv3hMAFJYIwB4oDBsi7Gxpetsfy4PtMkOPCxECHO+So8BbPeM # minyVXvsJuBsH+H+CtcyKHGnCbZe+LNsY8Um+jmKIhT2DdSaQUo0Gg1Rd+fO1/ac # TiSnEJ6/6lXWHa8YbpOkbtVGYJ9SJCvpIsFJsle1gIqEk8joFoOHO2GrZ58eeFsK # JL72D8iHn/G6tU3uc1pqiw/p3hS+4jHrvu+fVECsZyOE+Ug7dDzfo+ZSxvq7oU0P # CdD027mQu5ZzHuoV4WrdqM/gtpvyQKdMFnZPTdtpBiaAnWmRTR2919jCK8pCfYvz # bfmNNLBHkU4yj705m/bWb6LS0r5+aMmaTZTljdJd1aPF6JWgXV3f6Qngf8DgzaBV # L67cFH52N4iQnTPztRFMLr4m5VHWN9+i8E4VlOqyL+slh4HUy2rEnDpg2f2gMUtY # bMSy0pyM2cbE9JOg7xOh25v3VtZ7dfdoUXNuN5ZPMoCZiatGEKBNxt20HH/nO+x9 # gkCBINln/6SC # SIG # End signature block |