O365Essentials.psm1
function Connect-O365Admin { [cmdletbinding()] param( [parameter(Mandatory, ParameterSetName = 'Credential')][PSCredential] $Credential, [int] $ExpiresIn = 3600, [int] $ExpiresTimeout = 30, [switch] $ForceRefresh ) if (-not $Script:AuthorizationO365Cache) { $Script:AuthorizationO365Cache = [ordered] @{} } $UserName = $Credential.UserName if ($Script:AuthorizationO365Cache[$UserName] -and -not $ForceRefesh) { if ($Script:AuthorizationO365Cache[$UserName].ExpiresOnUTC -gt [datetime]::UtcNow) { Write-Verbose "Connect-O365Admin - Using cache for $UserName" return $Script:AuthorizationO365Cache[$UserName] } } $Script:AuthorizationO365Cache['CurrentUsername'] = $UserName $AzConnect = (Connect-AzAccount -Credential $Credential -ErrorAction Stop) $Context = $AzConnect.Context $Authentication = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate( $Context.Account, $Context.Environment, $Context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never, $null, "https://admin.microsoft.com" ) $null = Disconnect-AzAccount -AzureContext $Context $Script:AuthorizationO365Cache[$UserName] = [ordered] @{ 'Credential' = $Credential 'UserName' = $Context.Account 'Environment' = $Context.Environment 'Tenant' = $Context.Tenant.Id 'Authentication' = $Authentication 'AccessToken' = $Authentication.AccessToken 'ExpiresOnUTC' = ([datetime]::UtcNow).AddSeconds($ExpiresIn - $ExpiresTimeout) 'Headers' = [ordered] @{ "Content-Type" = "application/json; charset=UTF-8" ; "Authorization" = "Bearer $($Authentication.AccessToken)" } } $Script:AuthorizationO365Cache[$UserName] } function Get-O365AzureSpeechServices { [cmdletbinding()] param( [parameter()][alias('Authorization')][System.Collections.IDictionary] $Headers ) if (-not $Headers -and $Script:AuthorizationO365Cache) { $Headers = $Script:AuthorizationO365Cache } $Uri = "https://admin.microsoft.com/admin/api/services/apps/azurespeechservices" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers [PSCustomobject] @{ AllowTheOrganizationWideLanguageModel = $Output.IsTenantEnabled } } function Get-O365Bookings { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/bookings" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365BriefingEmail { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/briefingemail" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365CalendarSharing { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://admin.microsoft.com/admin/api/settings/apps/calendarsharing' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365CommunicationToUsers { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://admin.microsoft.com/admin/api/settings/apps/EndUserCommunications' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365CompanyInformation { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/Settings/company/profile" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Cortana { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://admin.microsoft.com/admin/api/services/apps/cortana' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Dynamics365CustomerVoice { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://admin.microsoft.com/admin/api/settings/apps/officeformspro' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Dynamics365SalesInsights { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://admin.microsoft.com/admin/api/settings/apps/dci' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Forms { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://admin.microsoft.com/admin/api/settings/apps/officeforms/' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365GraphDataConnect { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/o365dataplan" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Groups { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/security/guestUserPolicy" $Output1 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Uri = "https://admin.microsoft.com/admin/api/settings/security/o365guestuser" $Output2 = Invoke-O365Admin -Uri $Uri -Headers $Headers <# same/similar properties on both objects $Object = [ordered] @{} foreach ($O in $Output1, $Output2) { foreach ($Key in $O.PSObject.Properties.Name) { $Object[$Key] = $O.$Key } } [PSCustomObject] $Object #> [PSCustomObject] @{ AllowGuestAccess = $Output1.AllowGuestAccess AllowGuestInvitations = $Output1.AllowGuestInvitations SitesSharingEnabled = $Output1.SitesSharingEnabled AllowGuestsAsMembers = $Output2.AllowGuestsAsMembers AllowGuestAccessO365 = $Output2.AllowGuestAccess } } function Get-O365InstallationOptions { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/usersoftware" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output.UserSoftwareSettings # Fix me <# $Uri = "https://admin.microsoft.com/fd/oacms/api/ReleaseManagement/admin?tenantId=29c50a66" $Output1 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Uri = "https://admin.microsoft.com/fd/oacms/api/MroDeviceManagement/TenantInfo?tenantId=29c50a66 " $Output2 = Invoke-O365Admin -Uri $Uri -Headers $Headers #> <# $Uri = "https://admin.microsoft.com/fd/oacms/api/mrodevicemanagement/?ffn=55336b82-a18d-4dd6-b5f6-9e5095c314a6" $Output3 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output3 #> #Office installation options # /fd/oacms/api/ReleaseManagement/admin?tenantId=ceb371f6 # /fd/oacms/api/MroDeviceManagement/TenantInfo?tenantId=ceb371f6- # /fd/oacms/api/mrodevicemanagement/?ffn=55336b82-a18d-4dd6-b5f6-9e5095c314a6 } function Get-O365MicrosoftSearch { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/configurations" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365MicrosoftTeams { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/skypeteams" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output <# IsSkypeTeamsLicensed : True TenantCategorySettings : {@{TenantSkuCategory=BusinessEnterprise; IsSkypeTeamsEnabled=; Meetups=; FunControl=; Messaging=}, @{TenantSkuCategory=Guest; IsSkypeTeamsEnabled=; Meetups=; FunControl=; Messaging=}} Bots : @{IsBotsEnabled=; IsSideLoadedBotsEnabled=; BotSettings=System.Object[]; IsExternalAppsEnabledByDefault=} Miscellaneous : @{IsOrganizationTabEnabled=; IsSkypeBusinessInteropEnabled=; IsTBotProactiveMessagingEnabled=} Email : @{IsEmailIntoChannelsEnabled=; RestrictedSenderList=System.Object[]} CloudStorage : @{Box=; Dropbox=; GoogleDrive=; ShareFile=} TeamsOwnedApps : @{TeamsOwnedAppSettings=System.Object[]} TenantOwnedApps : @{TenantOwnedAppSettings=System.Object[]} MigrationStates : @{EnableAppsMigration=; EnableClientSettingsMigration=; EnableMeetupsMigration=; EnableMessagingMigration=} #> } function Get-O365ModernAuthentication { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/modernAuth" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365MyAnalytics { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/myanalytics" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365News { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/news" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/news/options" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/news/options/Bing" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/news/industry/Bing" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/news/msbenabled/Bing" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365OfficeOnTheWeb { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/officeonline" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365OfficeProductivity { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/reports/productivityScoreCustomerOption" $Output1 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Uri = "https://admin.microsoft.com/admin/api/reports/productivityScoreConfig/GetProductivityScoreConfig" $Output2 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output2Json = $Output2.Output | ConvertFrom-Json $Output1Json = $Output1.Output | ConvertFrom-Json $Output = [PSCustomObject] @{ TenantId = $Output2Json.TenantId ProductivityScoreSignedup = $Output2Json.ProductivityScoreSignedup SignupUserPuid = $Output2Json.SignupUserPuid SignupTime = $Output2Json.SignupTime ReadyTime = $Output2Json.ReadyTime ProductivityScoreOptedIn = $Output1Json.ProductivityScoreOptedIn OperationUserPuid = $Output1Json.OperationUserPuid OperationTime = $Output1Json.OperationTime } $Output } function Get-O365Planner { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/planner" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Project { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/projectonline" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Reports { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/reports/config/GetTenantConfiguration" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $OutputFromJson = $Output.Output | ConvertFrom-Json $OutputFromJson } function Get-O365Scripts { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/officescripts" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365SharePoint { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/sitessharing" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Sway { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/Sway" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365TenantID { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Domain Parameter description .EXAMPLE Get-O365TenantID -Domain 'evotec.pl' .NOTES General notes #> [cmdletbinding()] param( [parameter(Mandatory)][string] $Domain ) (Invoke-RestMethod "https://login.windows.net/$Domain/.well-known/openid-configuration" -Method GET).userinfo_endpoint.Split("/")[3] } function Get-O365ToDo { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/todo" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365UserConsentApps { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/IntegratedApps" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365UserOwnedApps { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/store" $Output1 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Uri = "https://admin.microsoft.com/admin/api/storesettings/iwpurchaseallowed" $Output2 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Uri = 'https://admin.microsoft.com/fd/m365licensing/v1/policies/autoclaim' $Output4 = Invoke-O365Admin -Uri $Uri -Headers $Headers [PSCustomObject] @{ LetUsersAccessOfficeStore = $Output1 LetUsersStartTrials = $Output2 LetUsersAutoClaimLicenses = $Output4.tenantPolicyValue <# { "policyId": "Autoclaim", "tenantPolicyValue": "Enabled", "tenantId": "ceb371f6-" } #> } } function Get-O365Whiteboard { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://admin.microsoft.com/admin/api/settings/apps/whiteboard' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Invoke-O365Admin { [cmdletBinding(SupportsShouldProcess)] param( [uri] $Uri, [alias('Authorization')][System.Collections.IDictionary] $Headers, [validateset('GET', 'DELETE', 'POST', 'PATCH')][string] $Method = 'GET', [string] $ContentType = "application/json; charset=UTF-8", [System.Collections.IDictionary] $Body ) if (-not $Headers) { if ($Script:AuthorizationO365Cache -and $Script:AuthorizationO365Cache['CurrentUserName']) { $UserName = $Script:AuthorizationO365Cache['CurrentUsername'] if ($Script:AuthorizationO365Cache[$UserName]) { $Headers = $Script:AuthorizationO365Cache[$UserName] } } } if (-not $Headers) { Write-Warning "Invoke-O365Admin - Not connected. Please connect using Connect-O365Admin." return } if ($Headers) { # This forces a reconnect of session in case it's about to time out. If it's not timeouting a cache value is used $Headers = Connect-O365Admin -Credential $Headers.Credential } if ($Headers.Error) { Write-Warning "Invoke-O365Admin - Authorization error. Skipping." return } $RestSplat = @{ Headers = $Headers.Headers Method = $Method ContentType = $ContentType } if ($Body) { $RestSplat['Body'] = $Body | ConvertTo-Json -Depth 5 } $RestSplat.Uri = $Uri try { Write-Verbose "Invoke-O365Admin - Querying [$Method] $($RestSplat.Uri)" if ($PSCmdlet.ShouldProcess($($RestSplat.Uri), "Querying [$Method]")) { $OutputQuery = Invoke-RestMethod @RestSplat -Verbose:$false if ($Method -in 'GET') { if ($null -ne $OutputQuery) { $OutputQuery } if ($OutputQuery.'@odata.nextLink') { $RestSplat.Uri = $OutputQuery.'@odata.nextLink' $MoreData = Invoke-O365Admin @RestSplat -FullUri if ($MoreData) { $MoreData } } } elseif ($Method -in 'POST') { $OutputQuery } else { return $true } } } catch { $RestError = $_.ErrorDetails.Message if ($RestError) { try { $ErrorMessage = ConvertFrom-Json -InputObject $RestError -ErrorAction Stop # Write-Warning -Message "Invoke-Graph - [$($ErrorMessage.error.code)] $($ErrorMessage.error.message), exception: $($_.Exception.Message)" Write-Warning -Message "Invoke-O365Admin - Error JSON: $($_.Exception.Message) $($ErrorMessage.error.message)" } catch { Write-Warning -Message "Invoke-O365Admin - Error: $($RestError.Trim())" } } else { Write-Warning -Message "Invoke-O365Admin - $($_.Exception.Message)" } if ($_.ErrorDetails.RecommendedAction) { Write-Warning -Message "Invoke-O365Admin - Recommended action: $RecommendedAction" } if ($Method -notin 'GET', 'POST') { return $false } } } function Set-O365AzureSpeechServices { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [bool] $AllowTheOrganizationWideLanguageModel ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/azurespeechservices" $Body = @{ isTenantEnabled = $AllowTheOrganizationWideLanguageModel } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365Forms { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $BingImageSearchEnabled, [nullable[bool]] $ExternalCollaborationEnabled, [nullable[bool]] $ExternalSendFormEnabled, [nullable[bool]] $ExternalShareCollaborationEnabled, [nullable[bool]] $ExternalShareTemplateEnabled, [nullable[bool]] $ExternalShareResultEnabled, [nullable[bool]] $InOrgFormsPhishingScanEnabled, [nullable[bool]] $InOrgSurveyIncentiveEnabled, [nullable[bool]] $RecordIdentityByDefaultEnabled ) # We need to get current settings because it always requires all parameters # If we would just provide one parameter it would reset everything else $CurrentSettings = Get-O365Forms -Headers $Headers $Body = [ordered] @{ BingImageSearchEnabled = $CurrentSettings.BingImageSearchEnabled ExternalCollaborationEnabled = $CurrentSettings.ExternalCollaborationEnabled ExternalSendFormEnabled = $CurrentSettings.ExternalSendFormEnabled ExternalShareCollaborationEnabled = $CurrentSettings.ExternalShareCollaborationEnabled ExternalShareTemplateEnabled = $CurrentSettings.ExternalShareTemplateEnabled ExternalShareResultEnabled = $CurrentSettings.ExternalShareResultEnabled InOrgFormsPhishingScanEnabled = $CurrentSettings.InOrgFormsPhishingScanEnabled InOrgSurveyIncentiveEnabled = $CurrentSettings.InOrgSurveyIncentiveEnabled RecordIdentityByDefaultEnabled = $CurrentSettings.RecordIdentityByDefaultEnabled } if ($null -ne $BingImageSearchEnabled) { $Body.BingImageSearchEnabled = $BingImageSearchEnabled } if ($null -ne $ExternalCollaborationEnabled) { $Body.ExternalCollaborationEnabled = $ExternalCollaborationEnabled } if ($null -ne $ExternalSendFormEnabled) { $Body.ExternalSendFormEnabled = $ExternalSendFormEnabled } if ($null -ne $ExternalShareCollaborationEnabled) { $Body.ExternalShareCollaborationEnabled = $ExternalShareCollaborationEnabled } if ($null -ne $ExternalShareTemplateEnabled) { $Body.ExternalShareTemplateEnabled = $ExternalShareTemplateEnabled } if ($null -ne $ExternalShareResultEnabled) { $Body.ExternalShareResultEnabled = $ExternalShareResultEnabled } if ($null -ne $InOrgFormsPhishingScanEnabled) { $Body.InOrgFormsPhishingScanEnabled = $InOrgFormsPhishingScanEnabled } if ($null -ne $InOrgSurveyIncentiveEnabled) { $Body.InOrgSurveyIncentiveEnabled = $InOrgSurveyIncentiveEnabled } if ($null -ne $RecordIdentityByDefaultEnabled) { $Body.RecordIdentityByDefaultEnabled = $RecordIdentityByDefaultEnabled } $Uri = "https://admin.microsoft.com/admin/api/settings/apps/officeforms" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365Planner { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [bool] $AllowCalendarSharing ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/planner" $Body = @{ allowCalendarSharing = $AllowCalendarSharing id = "1" isPlannerAllowed = $true } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } # Export functions and aliases as required Export-ModuleMember -Function @('Connect-O365Admin', 'Get-O365AzureSpeechServices', 'Get-O365Bookings', 'Get-O365BriefingEmail', 'Get-O365CalendarSharing', 'Get-O365CommunicationToUsers', 'Get-O365CompanyInformation', 'Get-O365Cortana', 'Get-O365Dynamics365CustomerVoice', 'Get-O365Dynamics365SalesInsights', 'Get-O365Forms', 'Get-O365GraphDataConnect', 'Get-O365Groups', 'Get-O365InstallationOptions', 'Get-O365MicrosoftSearch', 'Get-O365MicrosoftTeams', 'Get-O365ModernAuthentication', 'Get-O365MyAnalytics', 'Get-O365News', 'Get-O365OfficeOnTheWeb', 'Get-O365OfficeProductivity', 'Get-O365Planner', 'Get-O365Project', 'Get-O365Reports', 'Get-O365Scripts', 'Get-O365SharePoint', 'Get-O365Sway', 'Get-O365TenantID', 'Get-O365ToDo', 'Get-O365UserConsentApps', 'Get-O365UserOwnedApps', 'Get-O365Whiteboard', 'Invoke-O365Admin', 'Set-O365AzureSpeechServices', 'Set-O365Forms', 'Set-O365Planner') -Alias @() # SIG # Begin signature block # MIIdWQYJKoZIhvcNAQcCoIIdSjCCHUYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUCKKKtrf5hv7tsGeaQCN0oGm7 # D1qgghhnMIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0B # AQUFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYD # VQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVk # IElEIFJvb3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQsw # CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu # ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg # Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg # +XESpa7cJpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lT # XDGEKvYPmDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5 # a3/UsDg+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g # 0I6QNcZ4VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1 # roV9Iq4/AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whf # GHdPAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0G # A1UdDgQWBBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLL # gjEtUYunpyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3 # cmbYMuRCdWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmr # EthngYTffwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+ # fT8r87cmNW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5Q # Z7dsvfPxH2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu # 838fYxAe+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw # 8jCCBP4wggPmoAMCAQICEA1CSuC+Ooj/YEAhzhQA8N0wDQYJKoZIhvcNAQELBQAw # cjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQ # d3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVk # IElEIFRpbWVzdGFtcGluZyBDQTAeFw0yMTAxMDEwMDAwMDBaFw0zMTAxMDYwMDAw # MDBaMEgxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEgMB4G # A1UEAxMXRGlnaUNlcnQgVGltZXN0YW1wIDIwMjEwggEiMA0GCSqGSIb3DQEBAQUA # A4IBDwAwggEKAoIBAQDC5mGEZ8WK9Q0IpEXKY2tR1zoRQr0KdXVNlLQMULUmEP4d # yG+RawyW5xpcSO9E5b+bYc0VkWJauP9nC5xj/TZqgfop+N0rcIXeAhjzeG28ffnH # bQk9vmp2h+mKvfiEXR52yeTGdnY6U9HR01o2j8aj4S8bOrdh1nPsTm0zinxdRS1L # sVDmQTo3VobckyON91Al6GTm3dOPL1e1hyDrDo4s1SPa9E14RuMDgzEpSlwMMYpK # jIjF9zBa+RSvFV9sQ0kJ/SYjU/aNY+gaq1uxHTDCm2mCtNv8VlS8H6GHq756Wwog # L0sJyZWnjbL61mOLTqVyHO6fegFz+BnW/g1JhL0BAgMBAAGjggG4MIIBtDAOBgNV # HQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcD # CDBBBgNVHSAEOjA4MDYGCWCGSAGG/WwHATApMCcGCCsGAQUFBwIBFhtodHRwOi8v # d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHwYDVR0jBBgwFoAU9LbhIB3+Ka7S5GGlsqIl # ssgXNW4wHQYDVR0OBBYEFDZEho6kurBmvrwoLR1ENt3janq8MHEGA1UdHwRqMGgw # MqAwoC6GLGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtdHMu # Y3JsMDKgMKAuhixodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVk # LXRzLmNybDCBhQYIKwYBBQUHAQEEeTB3MCQGCCsGAQUFBzABhhhodHRwOi8vb2Nz # cC5kaWdpY2VydC5jb20wTwYIKwYBBQUHMAKGQ2h0dHA6Ly9jYWNlcnRzLmRpZ2lj # ZXJ0LmNvbS9EaWdpQ2VydFNIQTJBc3N1cmVkSURUaW1lc3RhbXBpbmdDQS5jcnQw # DQYJKoZIhvcNAQELBQADggEBAEgc3LXpmiO85xrnIA6OZ0b9QnJRdAojR6OrktIl # xHBZvhSg5SeBpU0UFRkHefDRBMOG2Tu9/kQCZk3taaQP9rhwz2Lo9VFKeHk2eie3 # 8+dSn5On7UOee+e03UEiifuHokYDTvz0/rdkd2NfI1Jpg4L6GlPtkMyNoRdzDfTz # ZTlwS/Oc1np72gy8PTLQG8v1Yfx1CAB2vIEO+MDhXM/EEXLnG2RJ2CKadRVC9S0y # OIHa9GCiurRS+1zgYSQlT7LfySmoc0NR2r1j1h9bm/cuG08THfdKDXF+l7f0P4Tr # weOjSaH6zqe/Vs+6WXZhiV9+p7SOZ3j5NpjhyyjaW4emii8wggUwMIIEGKADAgEC # AhAECRgbX9W7ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVT # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j # b20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEw # MjIxMjAwMDBaFw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV # BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEi # MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7 # RZmxOttE9X/lqJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p # 0WfTxvspJ8fTeyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj # 6YgsIJWuHEqHCN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grk # V7tKtel05iv+bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHy # DxL0xY4PwaLoLFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMB # AAGjggHNMIIByTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjAT # BgNVHSUEDDAKBggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGG # GGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2Nh # Y2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCB # gQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lD # ZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNl # cnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgG # CmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQu # Y29tL0NQUzAKBghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1 # DlgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQEL # BQADggEBAD7sDVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q # 3yBVN7Dh9tGSdQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/ # kLEbBw6RFfu6r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dc # IFzZcbEMj7uo+MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6 # dGRrsutmQ9qzsIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT # +hKUGIUukpHqaGxEMrJmoecYpJpkUe8wggUxMIIEGaADAgECAhAKoSXW1jIbfkHk # Bdo2l8IVMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxE # aWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMT # G0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xNjAxMDcxMjAwMDBaFw0z # MTAxMDcxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0 # IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwggEiMA0GCSqGSIb3DQEB # AQUAA4IBDwAwggEKAoIBAQC90DLuS82Pf92puoKZxTlUKFe2I0rEDgdFM1EQfdD5 # fU1ofue2oPSNs4jkl79jIZCYvxO8V9PD4X4I1moUADj3Lh477sym9jJZ/l9lP+Cb # 6+NGRwYaVX4LJ37AovWg4N4iPw7/fpX786O6Ij4YrBHk8JkDbTuFfAnT7l3ImgtU # 46gJcWvgzyIQD3XPcXJOCq3fQDpct1HhoXkUxk0kIzBdvOw8YGqsLwfM/fDqR9mI # UF79Zm5WYScpiYRR5oLnRlD9lCosp+R1PrqYD4R/nzEU1q3V8mTLex4F0IQZchfx # FwbvPc3WTe8GQv2iUypPhR3EHTyvz9qsEPXdrKzpVv+TAgMBAAGjggHOMIIByjAd # BgNVHQ4EFgQU9LbhIB3+Ka7S5GGlsqIlssgXNW4wHwYDVR0jBBgwFoAUReuir/SS # y4IxLVGLp6chnfNtyA8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMC # AYYwEwYDVR0lBAwwCgYIKwYBBQUHAwgweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUF # BzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6 # Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5j # cnQwgYEGA1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwUAYDVR0gBEkw # RzA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2lj # ZXJ0LmNvbS9DUFMwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4IBAQBxlRLp # UYdWac3v3dp8qmN6s3jPBjdAhO9LhL/KzwMC/cWnww4gQiyvd/MrHwwhWiq3BTQd # aq6Z+CeiZr8JqmDfdqQ6kw/4stHYfBli6F6CJR7Euhx7LCHi1lssFDVDBGiy23UC # 4HLHmNY8ZOUfSBAYX4k4YU1iRiSHY4yRUiyvKYnleB/WCxSlgNcSR3CzddWThZN+ # tpJn+1Nhiaj1a5bA9FhpDXzIAbG5KHW3mWOFIoxhynmUfln8jA/jb7UBJrZspe6H # USHkWGCbugwtK22ixH67xCUrRwIIfEmuE7bhfEJCKMYYVs9BNLZmXbZ0e/VWMyIv # IjayS6JKldj1po5SMIIFPTCCBCWgAwIBAgIQBNXcH0jqydhSALrNmpsqpzANBgkq # hkiG9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT # SEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTIwMDYyNjAwMDAwMFoX # DTIzMDcwNzEyMDAwMFowejELMAkGA1UEBhMCUEwxEjAQBgNVBAgMCcWabMSFc2tp # ZTERMA8GA1UEBxMIS2F0b3dpY2UxITAfBgNVBAoMGFByemVteXPFgmF3IEvFgnlz # IEVWT1RFQzEhMB8GA1UEAwwYUHJ6ZW15c8WCYXcgS8WCeXMgRVZPVEVDMIIBIjAN # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv7KB3iyBrhkLUbbFe9qxhKKPBYqD # Bqlnr3AtpZplkiVjpi9dMZCchSeT5ODsShPuZCIxJp5I86uf8ibo3vi2S9F9AlfF # jVye3dTz/9TmCuGH8JQt13ozf9niHecwKrstDVhVprgxi5v0XxY51c7zgMA2g1Ub # +3tii0vi/OpmKXdL2keNqJ2neQ5cYly/GsI8CREUEq9SZijbdA8VrRF3SoDdsWGf # 3tZZzO6nWn3TLYKQ5/bw5U445u/V80QSoykszHRivTj+H4s8ABiforhi0i76beA6 # Ea41zcH4zJuAp48B4UhjgRDNuq8IzLWK4dlvqrqCBHKqsnrF6BmBrv+BXQIDAQAB # o4IBxTCCAcEwHwYDVR0jBBgwFoAUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHQYDVR0O # BBYEFBixNSfoHFAgJk4JkDQLFLRNlJRmMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUE # DDAKBggrBgEFBQcDAzB3BgNVHR8EcDBuMDWgM6Axhi9odHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vc2hhMi1hc3N1cmVkLWNzLWcxLmNybDA1oDOgMYYvaHR0cDovL2Ny # bDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwTAYDVR0gBEUw # QzA3BglghkgBhv1sAwEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNl # cnQuY29tL0NQUzAIBgZngQwBBAEwgYQGCCsGAQUFBwEBBHgwdjAkBggrBgEFBQcw # AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tME4GCCsGAQUFBzAChkJodHRwOi8v # Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEyQXNzdXJlZElEQ29kZVNp # Z25pbmdDQS5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAQEAmr1s # z4lsLARi4wG1eg0B8fVJFowtect7SnJUrp6XRnUG0/GI1wXiLIeow1UPiI6uDMsR # XPHUF/+xjJw8SfIbwava2eXu7UoZKNh6dfgshcJmo0QNAJ5PIyy02/3fXjbUREHI # NrTCvPVbPmV6kx4Kpd7KJrCo7ED18H/XTqWJHXa8va3MYLrbJetXpaEPpb6zk+l8 # Rj9yG4jBVRhenUBUUj3CLaWDSBpOA/+sx8/XB9W9opYfYGb+1TmbCkhUg7TB3gD6 # o6ESJre+fcnZnPVAPESmstwsT17caZ0bn7zETKlNHbc1q+Em9kyBjaQRcEQoQQNp # ezQug9ufqExx6lHYDjGCBFwwggRYAgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYD # VQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAv # BgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EC # EATV3B9I6snYUgC6zZqbKqcwCQYFKw4DAhoFAKB4MBgGCisGAQQBgjcCAQwxCjAI # oAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIB # CzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFE5OZGrRsQjsA7T7vqcd # 8HE6gTofMA0GCSqGSIb3DQEBAQUABIIBAEkwwgdbEYnUwBiYsE79ibj3LkfBYmnC # 8eLfYTZuLxwYrExoFAOFLq8cG0GdLnuc6T15eCdAenV2StIc+q7frotHE6e2Lnr2 # wPfWx/mO8Rsg+f0SOP8nznr/jPSBTlRBCAUIz7rX1+bC3EaL4mxbHlltWgFfnfDS # aUUdmJUV4/f38gOG+4y62VqNd1y6sUT8Hfmu4bFAuRikq3U4e5fBOfoZ5/8qWvPt # BPLsxct9CnXvduICQiLnI5cT4VmytfbZeVXAqJawAH1v1UjCAE1ZKewqb+gOEeu2 # jLV3GIvjOC53h2rMcu6/XfKh2AZxmdMTApfHj0d9sQGAJScOoGP0C+2hggIwMIIC # LAYJKoZIhvcNAQkGMYICHTCCAhkCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNV # BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G # A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQQIQ # DUJK4L46iP9gQCHOFADw3TANBglghkgBZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzEL # BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIxMDgxOTA4NTE1OVowLwYJKoZI # hvcNAQkEMSIEIABFzyXy2hregWo/xjFqTDOBjx2W+SjDwlMKJkKl2jNJMA0GCSqG # SIb3DQEBAQUABIIBAFe2WnUJNTp86u+wGzE3zH+8Bn+evYL9dZoWW4nPs5Wnw5Li # wmFzW0t/jVfBGZgjRnKv6Kyh6RyHwpmM5KVw0ImHtHOzCECCih0AmJTMizMN1zNB # Jnshy2nQ0d8PQRNC6aIhtxQ+/dRIp58ewg+tPiDMFY7/4VLAqT03nCltLlx8NfAs # ng0K0HfnFSk4YJ9h3Nl5iOCG5lREQQIeRHWVJadhHq6llAOOmkjsIthgXDuNuPcc # 0WLy6gAg+adnTSr9BTkPmVbzQaW/IpIYYOc1tGhc42N8gnG8qOpsIN1v606gwguL # FaBgw+UxXZB1WtNxlxS3pbXnbfCGTH7+jy/jpAE= # SIG # End signature block |