O365Essentials.psm1
function Join-UriQuery { <# .SYNOPSIS Provides ability to join two Url paths together including advanced querying .DESCRIPTION Provides ability to join two Url paths together including advanced querying which is useful for RestAPI/GraphApi calls .PARAMETER BaseUri Primary Url to merge .PARAMETER RelativeOrAbsoluteUri Additional path to merge with primary url (optional) .PARAMETER QueryParameter Parameters and their values in form of hashtable .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' -QueryParameter @{ page = 1 per_page = 20 search = 'SearchString' } .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz/wp-json/wp/v2/posts' -QueryParameter @{ page = 1 per_page = 20 search = 'SearchString' } .EXAMPLE Join-UriQuery -BaseUri 'https://evotec.xyz' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .NOTES General notes #> [alias('Join-UrlQuery')] [CmdletBinding()] param ([parameter(Mandatory)][uri] $BaseUri, [parameter(Mandatory = $false)][uri] $RelativeOrAbsoluteUri, [Parameter()][System.Collections.IDictionary] $QueryParameter) if ($BaseUri -and $RelativeOrAbsoluteUri) { $Url = Join-Uri -BaseUri $BaseUri -RelativeOrAbsoluteUri $RelativeOrAbsoluteUri } else { $Url = $BaseUri } if ($QueryParameter) { $Collection = [System.Web.HttpUtility]::ParseQueryString([String]::Empty) foreach ($key in $QueryParameter.Keys) { $Collection.Add($key, $QueryParameter.$key) } } $uriRequest = [System.UriBuilder] $Url if ($Collection) { $uriRequest.Query = $Collection.ToString() } return $uriRequest.Uri.AbsoluteUri } function Remove-EmptyValue { [alias('Remove-EmptyValues')] [CmdletBinding()] param([alias('Splat', 'IDictionary')][Parameter(Mandatory)][System.Collections.IDictionary] $Hashtable, [string[]] $ExcludeParameter, [switch] $Recursive, [int] $Rerun, [switch] $DoNotRemoveNull, [switch] $DoNotRemoveEmpty, [switch] $DoNotRemoveEmptyArray, [switch] $DoNotRemoveEmptyDictionary) foreach ($Key in [string[]] $Hashtable.Keys) { if ($Key -notin $ExcludeParameter) { if ($Recursive) { if ($Hashtable[$Key] -is [System.Collections.IDictionary]) { if ($Hashtable[$Key].Count -eq 0) { if (-not $DoNotRemoveEmptyDictionary) { $Hashtable.Remove($Key) } } else { Remove-EmptyValue -Hashtable $Hashtable[$Key] -Recursive:$Recursive } } else { if (-not $DoNotRemoveNull -and $null -eq $Hashtable[$Key]) { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmpty -and $Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmptyArray -and $Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } } } else { if (-not $DoNotRemoveNull -and $null -eq $Hashtable[$Key]) { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmpty -and $Hashtable[$Key] -is [string] -and $Hashtable[$Key] -eq '') { $Hashtable.Remove($Key) } elseif (-not $DoNotRemoveEmptyArray -and $Hashtable[$Key] -is [System.Collections.IList] -and $Hashtable[$Key].Count -eq 0) { $Hashtable.Remove($Key) } } } } if ($Rerun) { for ($i = 0; $i -lt $Rerun; $i++) { Remove-EmptyValue -Hashtable $Hashtable -Recursive:$Recursive } } } function Select-Properties { <# .SYNOPSIS Allows for easy selecting property names from one or multiple objects .DESCRIPTION Allows for easy selecting property names from one or multiple objects. This is especially useful with using AllProperties parameter where we want to make sure to get all properties from all objects. .PARAMETER Objects One or more objects .PARAMETER Property Properties to include .PARAMETER ExcludeProperty Properties to exclude .PARAMETER AllProperties All unique properties from all objects .PARAMETER PropertyNameReplacement Default property name when object has no properties .EXAMPLE $Object1 = [PSCustomobject] @{ Name1 = '1' Name2 = '3' Name3 = '5' } $Object2 = [PSCustomobject] @{ Name4 = '2' Name5 = '6' Name6 = '7' } Select-Properties -Objects $Object1, $Object2 -AllProperties #OR: $Object1, $Object2 | Select-Properties -AllProperties -ExcludeProperty Name6 -Property Name3 .EXAMPLE $Object3 = [Ordered] @{ Name1 = '1' Name2 = '3' Name3 = '5' } $Object4 = [Ordered] @{ Name4 = '2' Name5 = '6' Name6 = '7' } Select-Properties -Objects $Object3, $Object4 -AllProperties $Object3, $Object4 | Select-Properties -AllProperties .NOTES General notes #> [CmdLetBinding()] param([Array][Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] $Objects, [string[]] $Property, [string[]] $ExcludeProperty, [switch] $AllProperties, [string] $PropertyNameReplacement = '*') Begin { function Select-Unique { [CmdLetBinding()] param([System.Collections.IList] $Object) $New = $Object.ToLower() | Select-Object -Unique $Selected = foreach ($_ in $New) { $Index = $Object.ToLower().IndexOf($_) if ($Index -ne -1) { $Object[$Index] } } $Selected } $ObjectsList = [System.Collections.Generic.List[Object]]::new() } Process { foreach ($Object in $Objects) { $ObjectsList.Add($Object) } } End { if ($ObjectsList.Count -eq 0) { Write-Warning 'Select-Properties - Unable to process. Objects count equals 0.' return } if ($ObjectsList[0] -is [System.Collections.IDictionary]) { if ($AllProperties) { [Array] $All = foreach ($_ in $ObjectsList) { $_.Keys } $FirstObjectProperties = Select-Unique -Object $All } else { $FirstObjectProperties = $ObjectsList[0].Keys } if ($Property.Count -gt 0 -and $ExcludeProperty.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($Property -contains $_ -and $ExcludeProperty -notcontains $_) { $_ continue } } } elseif ($Property.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($Property -contains $_) { $_ continue } } } elseif ($ExcludeProperty.Count -gt 0) { $FirstObjectProperties = foreach ($_ in $FirstObjectProperties) { if ($ExcludeProperty -notcontains $_) { $_ continue } } } } elseif ($ObjectsList[0].GetType().Name -match 'bool|byte|char|datetime|decimal|double|ExcelHyperLink|float|int|long|sbyte|short|string|timespan|uint|ulong|URI|ushort') { $FirstObjectProperties = $PropertyNameReplacement } else { if ($Property.Count -gt 0 -and $ExcludeProperty.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property $Property -ExcludeProperty $ExcludeProperty } elseif ($Property.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property $Property } elseif ($ExcludeProperty.Count -gt 0) { $ObjectsList = $ObjectsList | Select-Object -Property '*' -ExcludeProperty $ExcludeProperty } if ($AllProperties) { [Array] $All = foreach ($_ in $ObjectsList) { $_.PSObject.Properties.Name } $FirstObjectProperties = Select-Unique -Object $All } else { $FirstObjectProperties = $ObjectsList[0].PSObject.Properties.Name } } $FirstObjectProperties } } function Join-Uri { <# .SYNOPSIS Provides ability to join two Url paths together .DESCRIPTION Provides ability to join two Url paths together .PARAMETER BaseUri Primary Url to merge .PARAMETER RelativeOrAbsoluteUri Additional path to merge with primary url .EXAMPLE Join-Uri 'https://evotec.xyz/' '/wp-json/wp/v2/posts' .EXAMPLE Join-Uri 'https://evotec.xyz/' 'wp-json/wp/v2/posts' .EXAMPLE Join-Uri -BaseUri 'https://evotec.xyz/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .EXAMPLE Join-Uri -BaseUri 'https://evotec.xyz/test/' -RelativeOrAbsoluteUri '/wp-json/wp/v2/posts' .NOTES General notes #> [alias('Join-Url')] [cmdletBinding()] param([parameter(Mandatory)][uri] $BaseUri, [parameter(Mandatory)][uri] $RelativeOrAbsoluteUri) return ($BaseUri.OriginalString.TrimEnd('/') + "/" + $RelativeOrAbsoluteUri.OriginalString.TrimStart('/')) } function Convert-AzureRole { [cmdletbinding()] param( [string[]] $RoleID ) $Roles = [ordered] @{ '729827e3-9c14-49f7-bb1b-9608f156bbb8' = 'Helpdesk admin' '62e90394-69f5-4237-9190-012177145e10' = 'Global Administrator' } foreach ($Role in $RoleID) { $RoleName = $Roles[$Role] if ($RoleName) { $RoleName } else { $Role } } } function Convert-ContractType { [cmdletbinding()] param( [string[]] $ContractType ) $ContractTypeInformation = [ordered] @{ '3' = 'Reseller' } foreach ($Contract in $ContractType) { $ContractName = $ContractTypeInformation[$Contract] if ($ContractName) { $ContractName } else { $Contract } } } function Get-O365BillingInvoices { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/commerceapi/my-org/legacyInvoices(startDate=2021-06-01,endDate=2021-08-20)" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365BillingProfile { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/commerceMgmt/moderncommerce/checkaccess/bulk?api-version=3.0" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } 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-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/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 #> $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/news/options" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output # WARNING: Invoke-O365Admin - Error JSON: Response status code does not indicate success: 400 (Bad Request). An API version is required, but was not specified. } 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-O365SearchIntelligenceBingConfigurations { [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-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 Set-O365CommunicationToUsers { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][bool] $ServiceEnabled ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/EndUserCommunications" $Body = @{ ServiceEnabled = $ServiceEnabled } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body #-WhatIf:$WhatIfPreference.IsPresent $Output } function Set-O365MultiFactorAuthentication { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .PARAMETER AccountLockoutDurationMinutes Minutes until account is automatically unblocked .PARAMETER AccountLockoutResetMinutes Minutes until account lockout counter is reset .PARAMETER AccountLockoutThreshold Number of MFA denials to trigger account lockout .PARAMETER AllowPhoneMenu Parameter description .PARAMETER BlockForFraud Automatically block users who report fraud .PARAMETER CallerId MFA caller ID number (US phone number only) .PARAMETER DefaultBypassTimespan Default one-time bypass seconds .PARAMETER EnableFraudAlert Allow users to submit fraud alerts .PARAMETER FraudCode Code to report fraud during initial greeting .PARAMETER FraudNotificationEmailAddresses Recipient's Email Address .PARAMETER OneTimeBypassEmailAddresses Parameter description .PARAMETER PinAttempts Number of PIN attempts allowed per call .PARAMETER SayExtensionDigits Parameter description .PARAMETER SmsTimeoutSeconds Two-way text message timeout seconds .PARAMETER Caches Parameter description .PARAMETER Notifications Parameter description .PARAMETER NotificationEmailAddresses Parameter description .PARAMETER Greetings Parameter description .PARAMETER BlockedUsers Parameter description .PARAMETER BypassedUsers Parameter description .EXAMPLE An example .NOTES Based on: https://portal.azure.com/#blade/Microsoft_AAD_IAM/MultifactorAuthenticationMenuBlade/GettingStarted/fromProviders/ #> [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[int]] $AccountLockoutDurationMinutes, [nullable[int]] $AccountLockoutResetMinutes, [nullable[int]] $AccountLockoutThreshold, #$AllowPhoneMenu, [nullable[bool]] $BlockForFraud, #$CallerId, #$DefaultBypassTimespan, [nullable[bool]] $EnableFraudAlert, [nullable[int]] $FraudCode #$FraudNotificationEmailAddresses, #$OneTimeBypassEmailAddresses, #$PinAttempts, #$SayExtensionDigits, #$SmsTimeoutSeconds, #$Caches, #$Notifications, #$NotificationEmailAddresses #$Greetings , #$BlockedUsers , #$BypassedUsers ) #$Uri = "https://main.iam.ad.ext.azure.com/api/MultiFactorAuthentication/GetOrCreateExpandedTenantModel?tenantName=Evotec" # $Uri = "https://main.iam.ad.ext.azure.com/api/MultiFactorAuthentication/GetOrCreateExpandedTenantModel" # Whatever I do, doesn't work! $Uri = "https://main.iam.ad.ext.azure.com/api/MultiFactorAuthentication/TenantModel" $Body = [ordered] @{ #tenantId = $CurrentSettings #: ceb371f6 #licenseKey = $CurrentSettings #: #customerId = $CurrentSettings #: AccountLockoutDurationMinutes = $accountLockoutDurationMinutes #: AccountLockoutResetMinutes = $accountLockoutResetMinutes #: AccountLockoutThreshold = $accountLockoutThreshold #: AllowPhoneMenu = $allowPhoneMenu #: False BlockForFraud = $BlockForFraud #: False CallerId = $callerId #: 8553308653 DefaultBypassTimespan = $defaultBypassTimespan #: 300 EnableFraudAlert = $EnableFraudAlert #: True FraudCode = $fraudCode #: 0 FraudNotificationEmailAddresses = $fraudNotificationEmailAddresses #: OneTimeBypassEmailAddresses = $oneTimeBypassEmailAddresses #: PinAttempts = $pinAttempts #: SayExtensionDigits = $sayExtensionDigits #: False SmsTimeoutSeconds = $smsTimeoutSeconds #: 60 #caches = $caches #: {} Notifications = $notifications #: NotificationEmailAddresses = $notificationEmailAddresses #: {} #greetings = $greetings #: {} #blockedUsers = $blockedUsers #: {} #bypassedUsers = $bypassedUsers #: {} #groups = $groups #etag = $etag } Remove-EmptyValue -Hashtable $Body $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PATCH -Body $Body $Output } <# /api/MultiFactorAuthentication/TenantModel?licenseKey= PATCH https://main.iam.ad.ext.azure.com/api/MultiFactorAuthentication/TenantModel?licenseKey= HTTP/1.1 Host: main.iam.ad.ext.azure.com Connection: keep-alive Content-Length: 67 x-ms-client-session-id: 9fb6b21894f14f5786814508d7462a51 Accept-Language: en etag: 1629994960.340884_c0565cb3 Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyIsImtpZCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyJ9.eyJhdWQiOiI3NDY1ODEzNi0xNGVjLTQ2MzAtYWQ5Yi0yNmUxNjBmZjBmYzYiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9jZWIzNzFmNi04NzQ1LTQ4NzYtYTA0MC02OWYyZDEwYTlkMWEvIiwiaWF0IjoxNjI5OTk3MTgwLCJuYmYiOjE2Mjk5OTcxODAsImV4cCI6MTYzMDAwMTA4MCwiYWNyIjoiMSIsImFpbyI6IkFWUUFxLzhUQUFBQTYrNGZseVJBNU5PdUxBQSt3czI2Y0M3WG1STmhwVW1LajJjWjhDalhTK2thcjN5YytyUXEvOHQ1eXFBT0Rxa2EwMXR3M0Zkc0RSQW9UQ0trb1lIdUQzRWYvZTh3NjdVNHFJMlFkU1FEWEl3PSIsImFtciI6WyJyc2EiLCJtZmEiXSwiYXBwaWQiOiJjNDRiNDA4My0zYmIwLTQ5YzEtYjQ3ZC05NzRlNTNjYmRmM2MiLCJhcHBpZGFjciI6IjIiLCJkZXZpY2VpZCI6IjNhZTIyNzI2LWRmZDktNGFkNy1hODY1LWFhMmI1MWM2ZTBmZiIsImZhbWlseV9uYW1lIjoiS8WCeXMiLCJnaXZlbl9uYW1lIjoiUHJ6ZW15c8WCYXciLCJpcGFkZHIiOiI4OS43Ny4xMDIuMTciLCJuYW1lIjoiUHJ6ZW15c8WCYXcgS8WCeXMiLCJvaWQiOiJlNmE4ZjFjZi0wODc0LTQzMjMtYTEyZi0yYmY1MWJiNmRmZGQiLCJvbnByZW1fc2lkIjoiUy0xLTUtMjEtODUzNjE1OTg1LTI4NzA0NDUzMzktMzE2MzU5ODY1OS0xMTA1IiwicHVpZCI6IjEwMDMwMDAwOTQ0REI4NEQiLCJyaCI6IjAuQVM4QTluR3p6a1dIZGtpZ1FHbnkwUXFkR29OQVM4U3dPOEZKdEgyWFRsUEwzend2QUM4LiIsInNjcCI6InVzZXJfaW1wZXJzb25hdGlvbiIsInN1YiI6ImVvU3lzNXlDNmJvWmQ5a21YRXVNSWl5YUxhX1g1VTdmSWZJck1DV0hORjQiLCJ0ZW5hbnRfcmVnaW9uX3Njb3BlIjoiRVUiLCJ0aWQiOiJjZWIzNzFmNi04NzQ1LTQ4NzYtYTA0MC02OWYyZDEwYTlkMWEiLCJ1bmlxdWVfbmFtZSI6InByemVteXNsYXcua2x5c0Bldm90ZWMucGwiLCJ1cG4iOiJwcnplbXlzbGF3LmtseXNAZXZvdGVjLnBsIiwidXRpIjoiT0VwOHBwUl93RWFLZGxUMmpUTWlBQSIsInZlciI6IjEuMCIsIndpZHMiOlsiNjJlOTAzOTQtNjlmNS00MjM3LTkxOTAtMDEyMTc3MTQ1ZTEwIiwiYjc5ZmJmNGQtM2VmOS00Njg5LTgxNDMtNzZiMTk0ZTg1NTA5Il0sInhtc190Y2R0IjoxNDQ0ODQ1NTQ0fQ.OMVGz1zvr_IzPoa13Pb-uVWG6-ov87D2rQjCGYLgiWQl4_lcuFN9p9Z5kUW7ej8f1Dqw27WRvVFLDd_M682FI7skkddafUgDPuerMuMENiQYWeaEjylnlgEPgGk3t95Haf1OoHCOQZz8rR1wovAJnMABA5UZwuIkvn0Dl3l_Co7Aj8AE4-7BANUnqAUxEc97UhUejvwmldmOQN-KESwsthGa6ayjloMkh2ME0En_ME1QBJ_hpdAGFlpcsrSOCPUjnqemZwxXH1ceGdyb9HRky_oQIqNlnn073Cyoa48vJ33n3BCyWcYwhpC8NLWJSTnh2oOisdnwUBkaw5BVUDAP7w x-ms-effective-locale: en.en-us Content-Type: application/json Accept: */* x-ms-client-request-id: 983affdb-0b06-4095-b652-048e18d8d010 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.78 Origin: https://portal.azure.com Sec-Fetch-Site: same-site Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Accept-Encoding: gzip, deflate, br {"AccountLockoutResetMinutes":5,"AccountLockoutDurationMinutes":20} #> function Connect-O365Admin { [cmdletbinding(DefaultParameterSetName = 'Credential')] param( [parameter(ParameterSetName = 'Credential')][PSCredential] $Credential, [parameter(ParameterSetName = 'Headers', DontShow)][alias('Authorization')][System.Collections.IDictionary] $Headers, [int] $ExpiresIn = 3600, [int] $ExpiresTimeout = 30, [switch] $ForceRefresh, [alias('TenantID')][string] $Tenant, [string] $DomainName, [string] $Subscription ) if ($Headers) { if ($Headers.ExpiresOnUTC -gt [datetime]::UtcNow -and -not $ForceRefresh) { Write-Verbose -Message "Connect-O365Admin - Using cache for connection $($Headers.UserName)" return $Headers } else { # if header is expired, we need to use it's values to try and push it for refresh $Credential = $Headers.Credential $Tenant = $Headers.Tenant $Subscription = $Headers.Subscription } } elseif ($Script:AuthorizationO365Cache) { if ($Script:AuthorizationO365Cache.ExpiresOnUTC -gt [datetime]::UtcNow -and -not $ForceRefresh) { Write-Verbose -Message "Connect-O365Admin - Using cache for connection $($Script:AuthorizationO365Cache.UserName)" return $Script:AuthorizationO365Cache } else { $Credential = $Script:AuthorizationO365Cache.Credential $Tenant = $Script:AuthorizationO365Cache.Tenant $Subscription = $Script:AuthorizationO365Cache.Subscription } } if ($DomainName) { Write-Verbose -Message "Connect-O365Admin - Querying tenant to get domain name" $Tenant = Get-O365TenantID -DomainName $DomainName } try { $connectAzAccountSplat = @{ Credential = $Credential ErrorAction = 'Stop' TenantId = $Tenant Subscription = $Subscription } Remove-EmptyValue -Hashtable $connectAzAccountSplat if ($Credential) { Write-Verbose -Message "Connect-O365Admin - Connecting to Office 365 using Connect-AzAccount ($($Credential.UserName))" } else { Write-Verbose -Message "Connect-O365Admin - Connecting to Office 365 using Connect-AzAccount" } $AzConnect = (Connect-AzAccount @connectAzAccountSplat -WarningVariable warningAzAccount -WarningAction SilentlyContinue ) } catch { if ($_.CategoryInfo.Reason -eq 'AzPSAuthenticationFailedException') { if ($Credential) { Write-Warning -Message "Connect-O365Admin - Tenant most likely requires MFA. Please drop credential parameter, and just let the Connect-O365Admin prompt you for them." } else { Write-Warning -Message "Connect-O365Admin - Please provide DomainName or TenantID parameter." } } else { Write-Warning -Message "Connect-O365Admin - Error: $($_.Exception.Message)" } return } $Context = $AzConnect.Context try { Write-Verbose -Message "Connect-O365Admin - Establishing tokens for O365" $AuthenticationO365 = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate( $Context.Account, $Context.Environment, $Context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Auto, $null, 'https://admin.microsoft.com' ) } catch { Write-Warning -Message "Connect-O365Admin - Authentication failure. Error: $($_.Exception.Message)" return } try { Write-Verbose -Message "Connect-O365Admin - Establishing tokens for Azure" $AuthenticationAzure = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate( $Context.Account, $Context.Environment, $Context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Auto, $null, "74658136-14ec-4630-ad9b-26e160ff0fc6" ) } catch { Write-Warning -Message "Connect-O365Admin - Authentication failure. Error: $($_.Exception.Message)" return } try { Write-Verbose -Message "Connect-O365Admin - Establishing tokens for Graph" $AuthenticationGraph = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate( $Context.Account, $Context.Environment, $Context.Tenant.Id.ToString(), $null, [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Auto, $null, "https://graph.microsoft.com" ) } catch { Write-Warning -Message "Connect-O365Admin - Authentication failure. Error: $($_.Exception.Message)" return } Write-Verbose -Message "Connect-O365Admin - Disconnecting from O365 using Disconnect-AzAccount" $null = Disconnect-AzAccount -AzureContext $Context $Script:AuthorizationO365Cache = [ordered] @{ 'Credential' = $Credential 'UserName' = $Context.Account 'Environment' = $Context.Environment 'Subscription' = $Subscription 'Tenant' = $Context.Tenant.Id 'ExpiresOnUTC' = ([datetime]::UtcNow).AddSeconds($ExpiresIn - $ExpiresTimeout) # This authorization is used for admin.microsoft.com 'AuthenticationO365' = $AuthenticationO365 'AccessTokenO365' = $AuthenticationO365.AccessToken 'HeadersO365' = [ordered] @{ "Content-Type" = "application/json; charset=UTF-8" ; "Authorization" = "Bearer $($AuthenticationO365.AccessToken)" 'X-Requested-With' = 'XMLHttpRequest' 'x-ms-client-request-id' = [guid]::NewGuid() 'x-ms-correlation-id' = [guid]::NewGuid() } # This authorization is used for azure stuff 'AuthenticationAzure' = $AuthenticationAzure 'AccessTokenAzure' = $AuthenticationAzure.AccessToken 'HeadersAzure' = [ordered] @{ "Content-Type" = "application/json; charset=UTF-8" ; "Authorization" = "Bearer $($AuthenticationAzure.AccessToken)" 'X-Requested-With' = 'XMLHttpRequest' 'x-ms-client-request-id' = [guid]::NewGuid() 'x-ms-correlation-id' = [guid]::NewGuid() #'x-ms-client-session-id' = [guid]::NewGuid() } 'AuthenticationGraph' = $AuthenticationGraph 'AccessTokenGraph' = $AuthenticationGraph.AccessToken 'HeadersGraph' = [ordered] @{ "Content-Type" = "application/json; charset=UTF-8" ; "Authorization" = "Bearer $($AuthenticationGraph.AccessToken)" 'X-Requested-With' = 'XMLHttpRequest' 'x-ms-client-request-id' = [guid]::NewGuid() 'x-ms-correlation-id' = [guid]::NewGuid() } } $Script:AuthorizationO365Cache } function Get-O365AzureADConnect { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE Get-O365AzureADConnect -Verbose .NOTES https://portal.azure.com/#blade/Microsoft_AAD_IAM/PassThroughAuthenticationConnectorsBlade #> [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://main.iam.ad.ext.azure.com/api/Directories/GetPasswordSyncStatus" $Output3 = Invoke-O365Admin -Uri $Uri -Headers $Headers #$Output3 | Format-Table $Uri = "https://main.iam.ad.ext.azure.com/api/Directories/ADConnectStatus" $Output4 = Invoke-O365Admin -Uri $Uri -Headers $Headers [PSCustomObject] @{ passwordSyncStatus = $Output3 verifiedDomainCount = $Output4.verifiedDomainCount #: 3 verifiedCustomDomainCount = $Output4.verifiedCustomDomainCount #: 2 federatedDomainCount = $Output4.federatedDomainCount #: 0 numberOfHoursFromLastSync = $Output4.numberOfHoursFromLastSync #: 0 dirSyncEnabled = $Output4.dirSyncEnabled #: True dirSyncConfigured = $Output4.dirSyncConfigured #: True passThroughAuthenticationEnabled = $Output4.passThroughAuthenticationEnabled #: True seamlessSingleSignOnEnabled = $Output4.seamlessSingleSignOnEnabled #: True } } function Get-O365AzureADConnectPTA { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE Get-O365ModernAuthentication -Verbose .NOTES https://portal.azure.com/#blade/Microsoft_AAD_IAM/PassThroughAuthenticationConnectorsBlade #> [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://main.iam.ad.ext.azure.com/api/Directories/PassThroughAuthConnectorGroups" $Output1 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output1 } function Get-O365AzureADConnectSSO { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE Get-O365AzureADConnect -Verbose .NOTES https://portal.azure.com/#blade/Microsoft_AAD_IAM/PassThroughAuthenticationConnectorsBlade #> [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://main.iam.ad.ext.azure.com/api/Directories/GetSeamlessSingleSignOnDomains" $Output2 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output2 } function Get-O365AzureSpeechServices { [cmdletbinding()] param( [parameter()][alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/azurespeechservices" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers [PSCustomobject] @{ AllowTheOrganizationWideLanguageModel = $Output.IsTenantEnabled } } function Get-O365BillingAccounts { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/commerceMgmt/moderncommerce/accountGraph?api-version=3.0" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365BillingNotifications { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/commerceMgmt/mgmtsettings/invoicePreference?api-version=1.0 " $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365BillingNotificationsList { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/commerceMgmt/mgmtsettings/billingNotificationUsers?api-version=1.0" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } <# Not working function Get-O365BillingNotificationsList { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/Users/ListBillingNotificationsUsers" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST $Output } Get-O365BillingNotificationsList #> function Get-O365BillingPaymentMethods { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/commerceapi/my-org/paymentInstruments('ObnETQAAAAABAACA')/unsettledCharges" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365BingDataCollection { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/security/bingdatacollection" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } 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 { <# .SYNOPSIS Gets status of Briefing emails. .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE An example .NOTES General notes #> [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 if ($Output) { [PSCustomObject] @{ IsMailEnabled = $Output.IsMailEnabled IsSubscribedByDefault = $Output.IsSubscribedByDefault } } } function Get-O365CalendarSharing { <# .SYNOPSIS Let your users share their calendars with people outside of your organization who have Office 365 or Exchange .DESCRIPTION Let your users share their calendars with people outside of your organization who have Office 365 or Exchange .PARAMETER Headers Authentication Token along with additional information that is created with Connect-O365Admin. If heaaders are not provided it will use the default token. .EXAMPLE Get-O365CalendarSharing .NOTES General notes #> [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-O365ConsiergeAll { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/api/concierge/GetConciergeConfigAll" $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-O365CustomThemes { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/Settings/company/theme/v2" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output.ThemeData } function Get-O365DataLocation { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/tenant/datalocation" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365DirectorySync { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/dirsync" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365DirectorySyncErrors { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/dirsyncerrors/listdirsyncerrors" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST if ($Output.ObjectsWithErrorsList) { $Output.ObjectsWithErrorsList } } function Get-O365DirectorySyncManagement { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/DirsyncManagement/manage" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365Domain { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) #$Uri = "https://admin.microsoft.com/admin/api/Domains/List?filter=&searchText=&computeDomainRegistrationData=true" $Uri = "https://admin.microsoft.com/admin/api/Domains/List" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365DomainDependencies { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][string] $DomainName, [string][ValidateSet('All', 'Users', 'TeamsAndGroups', 'Apps')] $Type = 'All' ) $Uri = "https://admin.microsoft.com/admin/api/Domains/Dependencies" $Types = @{ 'All' = 0 'Users' = 1 'Groups' = 2 'Apps' = 4 } $QueryParameter = @{ 'domainName' = $DomainName 'kind' = $Types[$Type] } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter -Method POST if ($Output.Succeeded) { $Output.Data.Dependencies } else { [PSCustomObject] @{ DomainName = $DomainName Status = $false Message = $Output.Message } } } function Get-O365DomainHealth { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][string] $DomainName ) $Uri = "https://admin.microsoft.com/admin/api/Domains/CheckDnsHealth" $QueryParameter = @{ 'domainName' = $DomainName 'overrideSkip' = $true 'canRefreshCache' = $true 'dnsHealthCheckScenario' = 2 } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter $Output } <# function Get-O365DomainRegistrarsInformation { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers #, # [parameter(Mandatory)][string] $DomainName ) $Uri = "https://admin.microsoft.com/admin/api/Domains/GetRegistrarsHelpInfo" $QueryParameter = @{ #'domainName' = $DomainName #'overrideSkip' = $true #'canRefreshCache' = $true #'dnsHealthCheckScenario' = 2 } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter $Output } #> function Get-O365DomainRecords { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][string] $DomainName ) $Uri = "https://admin.microsoft.com/admin/api/Domains/Records" $QueryParameter = @{ 'domainName' = $DomainName } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter $Output } function Get-O365DomainTroubleshooting { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][string] $DomainName ) $Uri = "https://admin.microsoft.com/admin/api/Domains/CheckIsTroubleshootingAllowed" $QueryParameter = @{ 'domainName' = $DomainName #'overrideSkip' = $true 'canRefreshCache' = $true #'dnsHealthCheckScenario' = 2 } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter $Output } function Get-O365Dynamics365ConnectionGraph { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://admin.microsoft.com/admin/api/settings/apps/dcg' $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-O365ExternalCollaborationSettings { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) #$Uri = 'https://graph.microsoft.com/beta/policies/authorizationPolicy' $Uri = 'https://graph.microsoft.com/v1.0/policies/authorizationPolicy' Invoke-O365Admin -Uri $Uri -Headers $Headers } 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-O365Group { [cmdletBinding(DefaultParameterSetName = 'Default')] param( [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'EmailAddress')] [parameter(ParameterSetName = 'DisplayName')] [parameter(ParameterSetName = 'Id')] [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(ParameterSetName = 'Id')][string] $Id, [parameter(ParameterSetName = 'DisplayName')][string] $DisplayName, [alias('Mail')][parameter(ParameterSetName = 'EmailAddress')][string] $EmailAddress, [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'EmailAddress')] [parameter(ParameterSetName = 'DisplayName')] [parameter(ParameterSetName = 'Id')] [string[]] $Property, [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')][string] $Filter, [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [string] $OrderBy ) if ($DisplayName) { $Uri = 'https://graph.microsoft.com/v1.0/groups' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "displayName eq '$DisplayName'" } } elseif ($EmailAddress) { $Uri = 'https://graph.microsoft.com/v1.0/groups' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "mail eq '$EmailAddress'" } } elseif ($ID) { # Query a single group $Uri = "https://graph.microsoft.com/v1.0/groups/$ID" $QueryParameter = @{ '$Select' = $Property -join ',' } } else { # Query multiple groups $Uri = 'https://graph.microsoft.com/v1.0/groups' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = $Filter '$orderby' = $OrderBy } } Remove-EmptyValue -Hashtable $QueryParameter Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter } function Get-O365GroupMember { [cmdletBinding()] param( [parameter()][alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][string] $Id, [string] $Search, [string[]] $Property ) if ($ID) { # Query a single group $Uri = "https://graph.microsoft.com/v1.0/groups/$ID/members" $QueryParameter = @{ '$Select' = $Property -join ',' '$Search' = $Search } if ($QueryParameter.'$Search') { # This is required for search to work # https://developer.microsoft.com/en-us/identity/blogs/build-advanced-queries-with-count-filter-search-and-orderby/ $Headers['ConsistencyLevel'] = 'eventual' } Remove-EmptyValue -Hashtable $QueryParameter Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter } } function Get-O365HelpdeskInformation { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/Settings/company/helpdesk" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } 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-O365LicensesAutoClaim { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/m365licensing/v1/policies/autoclaim" $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 { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE Get-O365ModernAuthentication -Verbose .NOTES https://admin.microsoft.com/#/Settings/Services/:/Settings/L1/ModernAuthentication #> [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-O365MultiFactorAuthentication { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE An example .NOTES Based on: https://portal.azure.com/#blade/Microsoft_AAD_IAM/MultifactorAuthenticationMenuBlade/GettingStarted/fromProviders/ #> [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) #$Uri = "https://main.iam.ad.ext.azure.com/api/MultiFactorAuthentication/GetOrCreateExpandedTenantModel?tenantName=Evotec" $Uri = "https://main.iam.ad.ext.azure.com/api/MultiFactorAuthentication/GetOrCreateExpandedTenantModel" $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-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-O365OrganizationInformation { [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-O365OrgM365Groups { <# .SYNOPSIS Choose how guests from outside your organization can collaborate with your users in Microsoft 365 Groups. Learn more about guest access to Microsoft 365 Groups .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE An example .NOTES General notes #> [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 [PSCustomObject] @{ #AllowGuestAccess = $Output1.AllowGuestAccess #AllowGuestInvitations = $Output1.AllowGuestInvitations #SitesSharingEnabled = $Output1.SitesSharingEnabled AllowGuestsAsMembers = $Output2.AllowGuestsAsMembers AllowGuestAccess = $Output2.AllowGuestAccess } } function Get-O365OrgPlanner { [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 if ($Output) { [PSCustomObject] @{ id = $Output.id # : 1 isPlannerAllowed = $Output.isPlannerAllowed # : True allowCalendarSharing = $Output.allowCalendarSharing # : True allowTenantMoveWithDataLoss = $Output.allowTenantMoveWithDataLoss # : False allowRosterCreation = $Output.allowRosterCreation # : True allowPlannerMobilePushNotifications = $Output.allowPlannerMobilePushNotifications # : True } } } function Get-O365OrgUserConsentApps { [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-O365OrgUserOwnedApps { [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-O365OrgUserSettings { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://main.iam.ad.ext.azure.com/api/Directories/Properties" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method GET if ($Output) { [PSCustomObject] @{ objectId = $Output.objectId #: ceb371f6 - 8745 - 4876-a040 - 69f2d10a9d1a displayName = $Output.displayName #: Evotec usersCanRegisterApps = $Output.usersCanRegisterApps #: True isAnyAccessPanelPreviewFeaturesAvailable = $Output.isAnyAccessPanelPreviewFeaturesAvailable #: False showMyGroupsFeature = $Output.showMyGroupsFeature #: False myGroupsFeatureValue = $Output.myGroupsFeatureValue #: myGroupsGroupId = $Output.myGroupsGroupId #: myGroupsGroupName = $Output.myGroupsGroupName #: showMyAppsFeature = $Output.showMyAppsFeature #: False myAppsFeatureValue = $Output.myAppsFeatureValue #: myAppsGroupId = $Output.myAppsGroupId #: myAppsGroupName = $Output.myAppsGroupName #: showUserActivityReportsFeature = $Output.showUserActivityReportsFeature #: False userActivityReportsFeatureValue = $Output.userActivityReportsFeatureValue #: userActivityReportsGroupId = $Output.userActivityReportsGroupId #: userActivityReportsGroupName = $Output.userActivityReportsGroupName #: showRegisteredAuthMethodFeature = $Output.showRegisteredAuthMethodFeature #: False registeredAuthMethodFeatureValue = $Output.registeredAuthMethodFeatureValue #: registeredAuthMethodGroupId = $Output.registeredAuthMethodGroupId #: registeredAuthMethodGroupName = $Output.registeredAuthMethodGroupName #: usersCanAddExternalUsers = $Output.usersCanAddExternalUsers #: False limitedAccessCanAddExternalUsers = $Output.limitedAccessCanAddExternalUsers #: False restrictDirectoryAccess = $Output.restrictDirectoryAccess #: False groupsInAccessPanelEnabled = $Output.groupsInAccessPanelEnabled #: False selfServiceGroupManagementEnabled = $Output.selfServiceGroupManagementEnabled #: True securityGroupsEnabled = $Output.securityGroupsEnabled #: False usersCanManageSecurityGroups = $Output.usersCanManageSecurityGroups #: office365GroupsEnabled = $Output.office365GroupsEnabled #: False usersCanManageOfficeGroups = $Output.usersCanManageOfficeGroups #: allUsersGroupEnabled = $Output.allUsersGroupEnabled #: False scopingGroupIdForManagingSecurityGroups = $Output.scopingGroupIdForManagingSecurityGroups #: scopingGroupIdForManagingOfficeGroups = $Output.scopingGroupIdForManagingOfficeGroups #: scopingGroupNameForManagingSecurityGroups = $Output.scopingGroupNameForManagingSecurityGroups #: scopingGroupNameForManagingOfficeGroups = $Output.scopingGroupNameForManagingOfficeGroups #: objectIdForAllUserGroup = $Output.objectIdForAllUserGroup #: allowInvitations = $Output.allowInvitations #: False isB2CTenant = $Output.isB2CTenant #: False restrictNonAdminUsers = $Output.restrictNonAdminUsers #: False toEnableLinkedInUsers = $Output.toEnableLinkedInUsers #: {} toDisableLinkedInUsers = $Output.toDisableLinkedInUsers #: {} # We try to make it the same as shown in Set-O365UserSettings linkedInAccountConnection = if ($Output.enableLinkedInAppFamily -eq 4) { $true } elseif ($Output.enableLinkedInAppFamily -eq 0) { $true } else { $false } linkedInSelectedGroupObjectId = $Output.linkedInSelectedGroupObjectId #: b6cdb9c3-d660 - 4558-bcfd - 82c14a986b56 linkedInSelectedGroupDisplayName = $Output.linkedInSelectedGroupDisplayName #: All Users } } } function Get-O365PartnerRelationship { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [string] $TenantID ) if (-not $TenantID) { if ($Headers.Tenant) { $TenantID = $Headers.Tenant } elseif ($Script:AuthorizationO365Cache.Tenant) { $TenantID = $Script:AuthorizationO365Cache.Tenant } } if ($TenantID) { $Uri = "https://admin.microsoft.com/fd/commerceMgmt/partnermanage/partners?customerTenantId=$TenantID&api-version=2.1" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output.partners) { [PSCustomObject] @{ id = $Output.partners.id #: c2248f0a name = $Output.partners.name #: aadRoles = Convert-AzureRole -RoleID $Output.partners.aadRoles companyType = $Output.partners.companyType #: 4 canRemoveDap = $Output.partners.canRemoveDap #: True contractTypes = Convert-ContractType -ContractType $Output.partners.contractTypes #: {3} partnerType = $Output.partners.partnerType #: 1 } } } else { Write-Warning -Message "Get-O365PartnerRelationship - TenantID was not found in headers. Skipping." } } function Get-O365PasswordExpirationPolicy { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/Settings/security/passwordpolicy" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365PasswordReset { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://main.iam.ad.ext.azure.com/api/PasswordReset/PasswordResetPolicies" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365PasswordResetIntegration { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) #$Uri = "https://main.iam.ad.ext.azure.com/api/PasswordReset/IsOnPremisesPasswordResetAvailable" $Uri = "https://main.iam.ad.ext.azure.com/api/PasswordReset/OnPremisesPasswordResetPolicies" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { [PSCustomObject] @{ PasswordWritebackSupported = $Output.passwordWritebackSupported # This one doesn't change and stays enabled all the time #AccountUnlockSupported = $Output.accountUnlockSupported AccountUnlockEnabled = $Output.accountUnlockEnabled } } } function Get-O365PrivacyProfile { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/Settings/security/privacypolicy" $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-O365ReleasePreferences { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/Settings/company/releasetrack" $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-O365SearchIntelligenceItemInsights { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/configgraphprivacy/ceb371f6-8745-4876-a040-69f2d10a9d1a/settings/ItemInsights" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365SearchIntelligenceMeetingInsights { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/ssms/api/v1.0/'3srecs'/Collection('meetinginsights')/Settings(Path=':',LogicalId='MeetingInsightsToggle')" $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-O365Sharing { [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 $Output1 | Format-Table $Uri = "https://admin.microsoft.com/admin/api/settings/apps/sitessharing" $Output2 = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output2 | Format-Table # $Uri = "https://admin.microsoft.co//admin/api/settings/security/o365guestuser" # $Output3 = Invoke-O365Admin -Uri $Uri -Headers $Headers # $Output3 | Format-Table [PSCustomObject] @{ AllowGuestAccess = $Output1.AllowGuestAccess AllowGuestInvitations = $Output1.AllowGuestInvitations SitesSharingEnabled = $Output1.SitesSharingEnabled AllowSharing = $Output2.AllowSharing SiteUrl = $Output2.SiteUrl AdminUri = $Output2.AdminUri RequireAnonymousLinksExpireInDays = $Output2.RequireAnonymousLinksExpireInDays CollaborationType = $Output2.CollaborationType } } 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)][alias('DomainName')][string] $Domain ) $Invoke = Invoke-RestMethod "https://login.windows.net/$Domain/.well-known/openid-configuration" -Method GET -Verbose:$false if ($Invoke) { $Invoke.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-O365User { [cmdletBinding(DefaultParameterSetName = "Default")] param( [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'GuestsOnly')] [parameter(ParameterSetName = 'EmailAddress')] [parameter(ParameterSetName = 'UserPrincipalName')] [parameter(ParameterSetName = 'Id')] [parameter()][alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(ParameterSetName = 'Id')][string] $Id, [parameter(ParameterSetName = 'UserPrincipalName')][string] $UserPrincipalName, [alias('Mail')][parameter(ParameterSetName = 'EmailAddress')][string] $EmailAddress, [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'GuestsOnly')] [parameter(ParameterSetName = 'EmailAddress')] [parameter(ParameterSetName = 'UserPrincipalName')] [parameter(ParameterSetName = 'Id')] [string[]] $Property, [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')][string] $Filter, [parameter(ParameterSetName = 'GuestsOnly')][switch] $GuestsOnly, [parameter(ParameterSetName = 'GuestsOnly')] [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [string] $OrderBy ) if ($GuestsOnly) { $Uri = 'https://graph.microsoft.com/v1.0/users' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "userType eq 'Guest'" '$orderby' = $OrderBy } } elseif ($UserPrincipalName) { $Uri = 'https://graph.microsoft.com/v1.0/users' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "userPrincipalName eq '$UserPrincipalName'" } } elseif ($EmailAddress) { $Uri = 'https://graph.microsoft.com/v1.0/users' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "mail eq '$EmailAddress'" } } elseif ($ID) { # Query a single group $Uri = "https://graph.microsoft.com/v1.0/users/$ID" $QueryParameter = @{ '$Select' = $Property -join ',' } } else { # Query multiple groups $Uri = 'https://graph.microsoft.com/v1.0/users' $QueryParameter = @{ '$Select' = $Property -join ',' # https://docs.microsoft.com/en-us/graph/query-parameters#filter-parameter '$filter' = $Filter '$orderby' = $OrderBy } } Remove-EmptyValue -Hashtable $QueryParameter Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter } function Invoke-O365Admin { [cmdletBinding(SupportsShouldProcess)] param( [uri] $Uri, [alias('Authorization')][System.Collections.IDictionary] $Headers, [validateset('GET', 'DELETE', 'POST', 'PATCH', 'PUT')][string] $Method = 'GET', [string] $ContentType = "application/json; charset=UTF-8", [System.Collections.IDictionary] $Body, [System.Collections.IDictionary] $QueryParameter ) if (-not $Headers -and $Script:AuthorizationO365Cache) { # 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 -Headers $Headers } else { Write-Warning "Invoke-O365Admin - Not connected. Please connect using Connect-O365Admin." return } if (-not $Headers) { Write-Warning "Invoke-O365Admin - Authorization error. Skipping." return } $RestSplat = @{ Method = $Method ContentType = $ContentType } if ($Uri -like '*admin.microsoft.com*') { $RestSplat['Headers'] = $Headers.HeadersO365 } elseif ($Uri -like '*graph.microsoft.com*') { $RestSplat['Headers'] = $Headers.HeadersGraph } else { $RestSplat['Headers'] = $Headers.HeadersAzure } #$RestSplat.Headers."x-ms-mac-hosting-app" = 'M365AdminPortal' #$RestSplat.Headers."x-ms-mac-version" = 'host-mac_2021.8.16.1' #$RestSplat.Headers."sec-ch-ua" = '"Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92"' #$RestSplat.Headers."x-portal-routekey" = 'weu' #$RestSplat.Headers."x-ms-mac-appid" = 'feda2aab-4737-4646-a86c-98a7742c70e6' #$RestSplat.Headers."x-adminapp-request" = '/Settings/Services/:/Settings/L1/Whiteboard' #$RestSplat.Headers."x-ms-mac-target-app" = 'MAC' #$RestSplat.UserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36 Edg/92.0.902.73' #$RestSplat.Headers.Cookie = 'MC1=GUID=480c128a5ba04faea7df151a53bdfa9a&HASH=480c&LV=202107&V=4&LU=1627670649689' #$RestSplat.Headers."x-ms-mac-hosting-app" = 'M365AdminPortal' #$RestSplat.Headers."x-adminapp-request" = '/Settings/Services/:/Settings/L1/EndUserCommunications' #$RestSplat.Headers."Referer" = 'https://admin.microsoft.com/' #$RestSplat.Headers."AjaxSessionKey" = 'x5eAwqzbVehBOP7QHfrjpwr9eYtLiHJt7TZFj0uhUMUPQ2T7yNdA7rEgOulejHDHYM1ZyCT0pgXo96EwrfVpMA==' #$RestSplat.Headers."etag" = '1629993527.826253_3ce8143d' if ($Body) { $RestSplat['Body'] = $Body | ConvertTo-Json -Depth 5 } $RestSplat.Uri = Join-UriQuery -BaseUri $Uri -QueryParameter $QueryParameter if ($RestSplat['Body']) { $WhatIfInformation = "Invoking [$Method] " + [System.Environment]::NewLine + $RestSplat['Body'] + [System.Environment]::NewLine } else { $WhatIfInformation = "Invoking [$Method] " } try { Write-Verbose "Invoke-O365Admin - $($WhatIfInformation)over URI $($RestSplat.Uri)" if ($Method -eq 'GET') { # We use separate check because WHATIF would sometimes trigger when GET was used inside a SET $OutputQuery = Invoke-RestMethod @RestSplat -Verbose:$false if ($null -ne $OutputQuery) { if ($OutputQuery -is [array]) { $Properties = $OutputQuery | Select-Properties -ExcludeProperty '@odata.context', '@odata.id', '@odata.type', 'Length' $OutputQuery | Select-Object -Property $Properties } elseif ($OutputQuery -is [string]) { if ($OutputQuery) { $OutputQuery | Select-Properties -ExcludeProperty '@odata.context', '@odata.id', '@odata.type', 'Length' } } elseif ($OutputQuery -is [PSCustomObject]) { if ($OutputQuery.value) { $Properties = $OutputQuery.value | Select-Properties -ExcludeProperty '@odata.context', '@odata.id', '@odata.type', 'Length' $OutputQuery.value | Select-Object -Property $Properties } else { $Properties = $OutputQuery | Select-Properties -ExcludeProperty '@odata.context', '@odata.id', '@odata.type', 'Length' $OutputQuery | Select-Object -Property $Properties } } else { Write-Warning -Message "Invoke-O365Admin - Type $($OutputQuery.GetType().Name) potentially unsupported." $OutputQuery } } if ($OutputQuery -isnot [array]) { if ($OutputQuery.'@odata.nextLink') { $RestSplat.Uri = $OutputQuery.'@odata.nextLink' if ($RestSplat.Uri) { $MoreData = Invoke-O365Admin @RestSplat if ($null -ne $MoreData) { $MoreData } } } } } else { if ($PSCmdlet.ShouldProcess($($RestSplat.Uri), $WhatIfInformation)) { #$CookieContainer = [System.Net.CookieContainer]::new() #$CookieContainer.MaxCookieSize = 8096 $OutputQuery = Invoke-RestMethod @RestSplat -Verbose:$false if ($Method -in 'POST', 'PUT') { if ($null -ne $OutputQuery) { $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(SupportsShouldProcess)] 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-O365BriefingEmail { <# .SYNOPSIS Let people in your organization receive Briefing Email .DESCRIPTION Let people in your organization receive Briefing Email .PARAMETER Headers Parameter description .PARAMETER SubscribeByDefault Subscribes or unsubscribes people in your organization to receive Briefing Email .EXAMPLE An example .NOTES Users will receive Briefing email by default, but can unsubscribe at any time from their Briefing email or Briefing settings page. Email is only sent to users if their Office 365 language is English or Spanish. #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, #[bool] $MailEnable, [bool] $SubscribeByDefault ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/briefingemail" $Body = @{ value = @{ IsSubscribedByDefault = $SubscribeByDefault } } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365CalendarSharing { <# .SYNOPSIS Let your users share their calendars with people outside of your organization who have Office 365 or Exchange .DESCRIPTION Let your users share their calendars with people outside of your organization who have Office 365 or Exchange .PARAMETER Headers Authentication Token along with additional information that is created with Connect-O365Admin. If heaaders are not provided it will use the default token. .PARAMETER EnableAnonymousCalendarSharing Enables or Disables anonymous calendar sharing .PARAMETER EnableCalendarSharing Enables or Disables calendar sharing .PARAMETER SharingOption Decide on how to share the calendar - Show calendar free/busy information with time only (CalendarSharingFreeBusySimple) - Show calendar free/busy information with time, subject and location (CalendarSharingFreeBusyDetail) - Show all calendar appointment information (CalendarSharingFreeBusyReviewer) .EXAMPLE Set-O365CalendarSharing -EnableCalendarSharing $false .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $EnableAnonymousCalendarSharing, [nullable[bool]] $EnableCalendarSharing, [string][ValidateSet('CalendarSharingFreeBusyDetail', 'CalendarSharingFreeBusySimple', 'CalendarSharingFreeBusyReviewer')] $SharingOption ) # 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-O365CalendarSharing -Headers $Headers $Body = [ordered] @{ ContractIdentity = $CurrentSettings.ContractIdentity EnableAnonymousCalendarSharing = $CurrentSettings.EnableAnonymousCalendarSharing EnableCalendarSharing = $CurrentSettings.EnableCalendarSharing SharingOption = $CurrentSettings.SharingOption } if ($null -ne $EnableAnonymousCalendarSharing) { $Body.EnableAnonymousCalendarSharing = $EnableAnonymousCalendarSharing } if ($null -ne $EnableCalendarSharing) { $Body.EnableCalendarSharing = $EnableCalendarSharing } if ($SharingOption) { $Body.SharingOption = $SharingOption } $Uri = "https://admin.microsoft.com/admin/api/settings/apps/calendarsharing" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365Cortana { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .PARAMETER Enabled Parameter description .EXAMPLE An example .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [bool] $Enabled ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/cortana" $Body = @{ Enabled = $Enabled } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365Dynamics365ConnectionGraph { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][bool] $ServiceEnabled, [string] $ConnectionGraphUsersExclusionGroup ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/dcg" $Body = @{ ServiceEnabled = $ServiceEnabled ConnectionGraphUsersExclusionGroup = $ConnectionGraphUsersExclusionGroup } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365Dynamics365SalesInsights { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][bool] $ServiceEnabled ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/dci" $Body = @{ ServiceEnabled = $ServiceEnabled } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365Forms { [cmdletbinding(SupportsShouldProcess)] 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-O365ModernAuthentication { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .PARAMETER EnableModernAuth Parameter description .PARAMETER SecureDefaults Parameter description .PARAMETER DisableModernAuth Parameter description .PARAMETER AllowBasicAuthActiveSync Parameter description .PARAMETER AllowBasicAuthImap Parameter description .PARAMETER AllowBasicAuthPop Parameter description .PARAMETER AllowBasicAuthWebServices Parameter description .PARAMETER AllowBasicAuthPowershell Parameter description .PARAMETER AllowBasicAuthAutodiscover Parameter description .PARAMETER AllowBasicAuthMapi Parameter description .PARAMETER AllowBasicAuthOfflineAddressBook Parameter description .PARAMETER AllowBasicAuthRpc Parameter description .PARAMETER AllowBasicAuthSmtp Parameter description .PARAMETER AllowOutlookClient Parameter description .EXAMPLE Set-O365ModernAuthentication -AllowBasicAuthImap $true -AllowBasicAuthPop $true -WhatIf .EXAMPLE Set-O365ModernAuthentication -AllowBasicAuthImap $false -AllowBasicAuthPop $false -Verbose -WhatIf .NOTES https://admin.microsoft.com/#/Settings/Services/:/Settings/L1/ModernAuthentication #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $EnableModernAuth, #: True [nullable[bool]] $SecureDefaults, #: False [nullable[bool]] $DisableModernAuth, #: False [nullable[bool]] $AllowBasicAuthActiveSync, #: True [nullable[bool]] $AllowBasicAuthImap, #: True [nullable[bool]] $AllowBasicAuthPop, #: True [nullable[bool]] $AllowBasicAuthWebServices, #: True [nullable[bool]] $AllowBasicAuthPowershell, #: True [nullable[bool]] $AllowBasicAuthAutodiscover, #: True [nullable[bool]] $AllowBasicAuthMapi, #: True [nullable[bool]] $AllowBasicAuthOfflineAddressBook , #: True [nullable[bool]] $AllowBasicAuthRpc, #: True [nullable[bool]] $AllowBasicAuthSmtp, #: True [nullable[bool]] $AllowOutlookClient #: ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/modernAuth" $CurrentSettings = Get-O365ModernAuthentication -Headers $Headers if (-not $CurrentSettings) { Write-Warning -Message "Set-O365ModernAuthentication - Couldn't gather current settings. Skipping setting anything." return } $Body = [ordered] @{ EnableModernAuth = $CurrentSettings.EnableModernAuth #: True SecureDefaults = $CurrentSettings.SecureDefaults #: False DisableModernAuth = $CurrentSettings.DisableModernAuth #: False AllowBasicAuthActiveSync = $CurrentSettings.AllowBasicAuthActiveSync #: True AllowBasicAuthImap = $CurrentSettings.AllowBasicAuthImap #: False AllowBasicAuthPop = $CurrentSettings.AllowBasicAuthPop #: False AllowBasicAuthWebServices = $CurrentSettings.AllowBasicAuthWebServices #: True AllowBasicAuthPowershell = $CurrentSettings.AllowBasicAuthPowershell #: True AllowBasicAuthAutodiscover = $CurrentSettings.AllowBasicAuthAutodiscover #: True AllowBasicAuthMapi = $CurrentSettings.AllowBasicAuthMapi #: True AllowBasicAuthOfflineAddressBook = $CurrentSettings.AllowBasicAuthOfflineAddressBook #: True AllowBasicAuthRpc = $CurrentSettings.AllowBasicAuthRpc #: True AllowBasicAuthSmtp = $CurrentSettings.AllowBasicAuthSmtp #: True AllowOutlookClient = $CurrentSettings.AllowOutlookClient #: True } if ($null -ne $SecureDefaults) { $Body.SecureDefaults = $SecureDefaults } if ($null -ne $EnableModernAuth) { $Body.EnableModernAuth = $EnableModernAuth } if ($null -ne $DisableModernAuth) { $Body.DisableModernAuth = $DisableModernAuth } if ($null -ne $AllowBasicAuthActiveSync) { $Body.AllowBasicAuthActiveSync = $AllowBasicAuthActiveSync } if ($null -ne $AllowBasicAuthImap) { $Body.AllowBasicAuthImap = $AllowBasicAuthImap } if ($null -ne $AllowBasicAuthPop) { $Body.AllowBasicAuthPop = $AllowBasicAuthPop } if ($null -ne $AllowBasicAuthWebServices) { $Body.AllowBasicAuthWebServices = $AllowBasicAuthWebServices } if ($null -ne $AllowBasicAuthPowershell) { $Body.AllowBasicAuthPowershell = $AllowBasicAuthPowershell } if ($null -ne $AllowBasicAuthAutodiscover) { $Body.AllowBasicAuthAutodiscover = $AllowBasicAuthAutodiscover } if ($null -ne $AllowBasicAuthMapi) { $Body.AllowBasicAuthMapi = $AllowBasicAuthMapi } if ($null -ne $AllowBasicAuthOfflineAddressBook) { $Body.AllowBasicAuthOfflineAddressBook = $AllowBasicAuthOfflineAddressBook } if ($null -ne $AllowBasicAuthRpc) { $Body.AllowBasicAuthRpc = $AllowBasicAuthRpc } if ($null -ne $AllowBasicAuthSmtp) { $Body.AllowBasicAuthSmtp = $AllowBasicAuthSmtp } if ($null -ne $AllowOutlookClient) { $Body.AllowOutlookClient = $AllowOutlookClient } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365OrgM365Groups { <# .SYNOPSIS Choose how guests from outside your organization can collaborate with your users in Microsoft 365 Groups. Learn more about guest access to Microsoft 365 Groups .DESCRIPTION Choose how guests from outside your organization can collaborate with your users in Microsoft 365 Groups. Learn more about guest access to Microsoft 365 Groups .PARAMETER Headers Parameter description .PARAMETER AllowGuestAccess PLet group owners add people outside your organization to Microsoft 365 Groups as guests .PARAMETER AllowGuestsAsMembers Let guest group members access group content .EXAMPLE An example .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $AllowGuestAccess, [nullable[bool]] $AllowGuestsAsMembers ) $Uri = "https://admin.microsoft.com/admin/api/settings/security/o365guestuser" $CurrentSettings = Get-O365OrgM365Groups -Headers $Headers $Body = [ordered] @{ AllowGuestAccess = $CurrentSettings.AllowGuestAccess AllowGuestsAsMembers = $CurrentSettings.AllowGuestsAsMembers } if ($null -ne $AllowGuestAccess) { $Body.AllowGuestAccess = $AllowGuestAccess } if ($null -ne $AllowGuestsAsMembers) { $Body.AllowGuestsAsMembers = $AllowGuestsAsMembers } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365OrgPlanner { [cmdletbinding(SupportsShouldProcess)] 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 } function Set-O365OrgUserSettings { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .PARAMETER UsersCanRegisterApps Parameter description .PARAMETER RestrictNonAdminUsers Parameter description .PARAMETER LinkedInAccountConnection Parameter description .PARAMETER LinkedInSelectedGroupObjectId Parameter description .PARAMETER LinkedInSelectedGroupDisplayName Parameter description .EXAMPLE Set-O365UserSettings -RestrictNonAdminUsers $true -LinkedInAccountConnection $true -LinkedInSelectedGroupObjectId 'b6cdb9c3-d660-4558-bcfd-82c14a986b56' .EXAMPLE Set-O365UserSettings -RestrictNonAdminUsers $true -LinkedInAccountConnection $true -LinkedInSelectedGroupDisplayName 'All Users' .EXAMPLE Set-O365UserSettings -RestrictNonAdminUsers $true -LinkedInAccountConnection $false .EXAMPLE Set-O365UserSettings -RestrictNonAdminUsers $true .NOTES https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/UserSettings #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $UsersCanRegisterApps, [nullable[bool]] $RestrictNonAdminUsers, [nullable[bool]] $LinkedInAccountConnection, [string] $LinkedInSelectedGroupObjectId, [string] $LinkedInSelectedGroupDisplayName ) $Uri = "https://main.iam.ad.ext.azure.com/api/Directories/PropertiesV2" $Body = @{ usersCanRegisterApps = $UsersCanRegisterApps restrictNonAdminUsers = $RestrictNonAdminUsers } Remove-EmptyValue -Hashtable $Body if ($null -ne $LinkedInAccountConnection) { if ($LinkedInAccountConnection -eq $true -and $linkedInSelectedGroupObjectId) { $Body.enableLinkedInAppFamily = 4 $Body.linkedInSelectedGroupObjectId = $linkedInSelectedGroupObjectId } elseif ($LinkedInAccountConnection -eq $true -and $LinkedInSelectedGroupDisplayName) { $Body.enableLinkedInAppFamily = 4 $Body.linkedInSelectedGroupDisplayName = $LinkedInSelectedGroupDisplayName } elseif ($LinkedInAccountConnection -eq $true) { $Body.enableLinkedInAppFamily = 0 $Body.linkedInSelectedGroupObjectId = $null } elseif ($LinkedInAccountConnection -eq $false) { $Body.enableLinkedInAppFamily = 1 $Body.linkedInSelectedGroupObjectId = $null } } if ($Body.Keys.Count -gt 0) { $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PUT -Body $Body # $Output } } function Set-O365PasswordReset { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[int]] $EnablementType , # = $CurrentSettings.enablementType #: 1 [nullable[int]]$NumberOfAuthenticationMethodsRequired, # = $CurrentSettings.numberOfAuthenticationMethodsRequired #: 1 [nullable[bool]] $EmailOptionEnabled , # = $CurrentSettings.emailOptionEnabled #: True [nullable[bool]] $MobilePhoneOptionEnabled , # = $CurrentSettings.mobilePhoneOptionEnabled #: True [nullable[bool]] $OfficePhoneOptionEnabled , # = $CurrentSettings.officePhoneOptionEnabled #: False [nullable[bool]] $SecurityQuestionsOptionEnabled , # = $CurrentSettings.securityQuestionsOptionEnabled #: False [nullable[bool]] $MobileAppNotificationEnabled , # = $CurrentSettings.mobileAppNotificationEnabled #: False [nullable[bool]] $MobileAppCodeEnabled , # = $CurrentSettings.mobileAppCodeEnabled #: True [nullable[int]] $NumberOfQuestionsToRegister , # = $CurrentSettings.numberOfQuestionsToRegister #: 5 [nullable[int]] $NumberOfQuestionsToReset , # = $CurrentSettings.numberOfQuestionsToReset #: 3 [nullable[bool]] $RegistrationRequiredOnSignIn , # = $CurrentSettings.registrationRequiredOnSignIn #: True [nullable[int]]$RegistrationReconfirmIntevalInDays , # = $CurrentSettings.registrationReconfirmIntevalInDays #: 180 [nullable[bool]] $SkipRegistrationAllowed , # = $CurrentSettings.skipRegistrationAllowed #: True [nullable[int]] $SkipRegistrationMaxAllowedDays , # = $CurrentSettings.skipRegistrationMaxAllowedDays #: 7 [nullable[bool]] $CustomizeHelpdeskLink , # = $CurrentSettings.customizeHelpdeskLink #: False [string] $CustomHelpdeskEmailOrUrl , # = $CurrentSettings.customHelpdeskEmailOrUrl #: [nullable[bool]] $NotifyUsersOnPasswordReset , # = $CurrentSettings.notifyUsersOnPasswordReset #: True [nullable[bool]] $NotifyOnAdminPasswordReset , # = $CurrentSettings.notifyOnAdminPasswordReset #: True [string] $PasswordResetEnabledGroupIds , # = $CurrentSettings.passwordResetEnabledGroupIds #: {b6cdb9c3-d660-4558-bcfd-82c14a986b56} [string] $PasswordResetEnabledGroupName , # = $CurrentSettings.passwordResetEnabledGroupName #: # don't have details about those. needs investigations # $securityQuestions , # = $CurrentSettings.securityQuestions #: {} #$registrationConditionalAccessPolicies, # = $CurrentSettings.registrationConditionalAccessPolicies #: {} [nullable[bool]] $EmailOptionAllowed , # = $CurrentSettings.emailOptionAllowed #: True [nullable[bool]] $MobilePhoneOptionAllowed , # = $CurrentSettings.mobilePhoneOptionAllowed #: True [nullable[bool]] $OfficePhoneOptionAllowed , # = $CurrentSettings.officePhoneOptionAllowed #: True [nullable[bool]] $SecurityQuestionsOptionAllowed , # = $CurrentSettings.securityQuestionsOptionAllowed #: True [nullable[bool]] $MobileAppNotificationOptionAllowed , # = $CurrentSettings.mobileAppNotificationOptionAllowed #: True [nullable[bool]] $MobileAppCodeOptionAllowed # = $CurrentSettings.mobileAppCodeOptionAllowed #: True ) $Uri = "https://main.iam.ad.ext.azure.com/api/PasswordReset/PasswordResetPolicies" $CurrentSettings = Get-O365PasswordReset -Headers $Headers if ($CurrentSettings.objectId -ne 'default') { Write-Warning -Message "Set-O365PasswordReset - Getting current settings failed. Skipping changes." return } $Body = [ordered] @{ objectId = $CurrentSettings.objectId #: default enablementType = $CurrentSettings.enablementType #: 1 numberOfAuthenticationMethodsRequired = $CurrentSettings.numberOfAuthenticationMethodsRequired #: 1 emailOptionEnabled = $CurrentSettings.emailOptionEnabled #: True mobilePhoneOptionEnabled = $CurrentSettings.mobilePhoneOptionEnabled #: True officePhoneOptionEnabled = $CurrentSettings.officePhoneOptionEnabled #: False securityQuestionsOptionEnabled = $CurrentSettings.securityQuestionsOptionEnabled #: False mobileAppNotificationEnabled = $CurrentSettings.mobileAppNotificationEnabled #: False mobileAppCodeEnabled = $CurrentSettings.mobileAppCodeEnabled #: True numberOfQuestionsToRegister = $CurrentSettings.numberOfQuestionsToRegister #: 5 numberOfQuestionsToReset = $CurrentSettings.numberOfQuestionsToReset #: 3 registrationRequiredOnSignIn = $CurrentSettings.registrationRequiredOnSignIn #: True registrationReconfirmIntevalInDays = $CurrentSettings.registrationReconfirmIntevalInDays #: 180 skipRegistrationAllowed = $CurrentSettings.skipRegistrationAllowed #: True skipRegistrationMaxAllowedDays = $CurrentSettings.skipRegistrationMaxAllowedDays #: 7 customizeHelpdeskLink = $CurrentSettings.customizeHelpdeskLink #: False customHelpdeskEmailOrUrl = $CurrentSettings.customHelpdeskEmailOrUrl #: notifyUsersOnPasswordReset = $CurrentSettings.notifyUsersOnPasswordReset #: True notifyOnAdminPasswordReset = $CurrentSettings.notifyOnAdminPasswordReset #: True passwordResetEnabledGroupIds = $CurrentSettings.passwordResetEnabledGroupIds #: {b6cdb9c3-d660-4558-bcfd-82c14a986b56} passwordResetEnabledGroupName = $CurrentSettings.passwordResetEnabledGroupName #: securityQuestions = $CurrentSettings.securityQuestions #: {} registrationConditionalAccessPolicies = $CurrentSettings.registrationConditionalAccessPolicies #: {} emailOptionAllowed = $CurrentSettings.emailOptionAllowed #: True mobilePhoneOptionAllowed = $CurrentSettings.mobilePhoneOptionAllowed #: True officePhoneOptionAllowed = $CurrentSettings.officePhoneOptionAllowed #: True securityQuestionsOptionAllowed = $CurrentSettings.securityQuestionsOptionAllowed #: True mobileAppNotificationOptionAllowed = $CurrentSettings.mobileAppNotificationOptionAllowed #: True mobileAppCodeOptionAllowed = $CurrentSettings.mobileAppCodeOptionAllowed #: True } if ($null -ne $EnablementType) { $Body.enablementType = $EnablementType } if ($null -ne $NumberOfAuthenticationMethodsRequired) { $Body.numberOfAuthenticationMethodsRequired = $NumberOfAuthenticationMethodsRequired } if ($null -ne $EmailOptionEnabled) { $Body.emailOptionEnabled = $EmailOptionEnabled } if ($null -ne $MobilePhoneOptionEnabled) { $Body.mobilePhoneOptionEnabled = $MobilePhoneOptionEnabled } if ($null -ne $OfficePhoneOptionEnabled) { $Body.officePhoneOptionEnabled = $OfficePhoneOptionEnabled } if ($null -ne $SecurityQuestionsOptionEnabled) { $Body.securityQuestionsOptionEnabled = $SecurityQuestionsOptionEnabled } if ($null -ne $MobileAppNotificationEnabled) { $Body.mobileAppNotificationEnabled = $MobileAppNotificationEnabled } if ($null -ne $MobileAppCodeEnabled) { $Body.mobileAppCodeEnabled = $MobileAppCodeEnabled } if ($null -ne $NumberOfQuestionsToRegister) { $Body.numberOfQuestionsToRegister = $NumberOfQuestionsToRegister } if ($null -ne $NumberOfQuestionsToReset) { $Body.numberOfQuestionsToReset = $NumberOfQuestionsToReset } if ($null -ne $RegistrationRequiredOnSignIn) { $Body.registrationRequiredOnSignIn = $RegistrationRequiredOnSignIn } if ($null -ne $RegistrationReconfirmIntevalInDays) { $Body.registrationReconfirmIntevalInDays = $RegistrationReconfirmIntevalInDays } if ($null -ne $SkipRegistrationAllowed) { $Body.skipRegistrationAllowed = $SkipRegistrationAllowed } if ($null -ne $SkipRegistrationMaxAllowedDays) { $Body.skipRegistrationMaxAllowedDays = $SkipRegistrationMaxAllowedDays } if ($CustomizeHelpdeskLink) { $Body.customizeHelpdeskLink = $CustomizeHelpdeskLink } if ($null -ne $CustomHelpdeskEmailOrUrl) { $Body.customHelpdeskEmailOrUrl = $CustomHelpdeskEmailOrUrl } if ($null -ne $NotifyUsersOnPasswordReset) { $Body.notifyUsersOnPasswordReset = $NotifyUsersOnPasswordReset } if ($null -ne $NotifyOnAdminPasswordReset) { $Body.notifyOnAdminPasswordReset = $NotifyOnAdminPasswordReset } if ($PasswordResetEnabledGroupName) { # We should find an easy way to find ID of a group and set it here # Not implemented yet $Body.passwordResetEnabledGroupIds = @( # Query for group id from group name $PasswordResetEnabledGroupName ) throw 'PasswordResetEnabledGroupName is not implemented yet' } elseif ($PasswordResetEnabledGroupIds) { $Body.passwordResetEnabledGroupIds = @( $PasswordResetEnabledGroupIds ) # This seems like an empty value - always $Body.passwordResetEnabledGroupName = '' } if ($null -ne $SecurityQuestions) { $Body.securityQuestions = $SecurityQuestions } if ($null -ne $RegistrationConditionalAccessPolicies) { $Body.registrationConditionalAccessPolicies = $RegistrationConditionalAccessPolicies } if ($null -ne $EmailOptionAllowed) { $Body.emailOptionAllowed = $EmailOptionAllowed } if ($null -ne $MobilePhoneOptionAllowed) { $Body.mobilePhoneOptionAllowed = $MobilePhoneOptionAllowed } if ($null -ne $OfficePhoneOptionAllowed) { $Body.officePhoneOptionAllowed = $OfficePhoneOptionAllowed } if ($null -ne $SecurityQuestionsOptionAllowed) { $Body.securityQuestionsOptionAllowed = $SecurityQuestionsOptionAllowed } if ($null -ne $mobileAppNotificationOptionAllowed) { $Body.mobileAppNotificationOptionAllowed = $mobileAppNotificationOptionAllowed } if ($null -ne $mobileAppCodeOptionAllowed) { $Body.mobileAppCodeOptionAllowed = $mobileAppCodeOptionAllowed } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PUT -Body $Body } function Set-O365PasswordResetIntegration { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $PasswordWritebackSupported, [nullable[bool]] $AccountUnlockEnabled ) $Uri = "https://main.iam.ad.ext.azure.com/api/PasswordReset/OnPremisesPasswordResetPolicies" <# $Body = @{ passwordWriteBackSupported = $passwordWriteBackSupported accountUnlockEnabled = $AccountUnlockEnabled #accountUnlockSupported = $accountUnlockSupported - doesn't seem to be used/work, always enabled } Remove-EmptyValue -Hashtable $Body if ($Body.Keys.Count -gt 0) { $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PUT -Body $Body } #> # It seems you need to set this separatly for AccountUnlockEnabled to be picked up properly. # So we do it.. if ($null -ne $PasswordWritebackSupported) { $Body = @{ passwordWriteBackSupported = $passwordWriteBackSupported } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PUT -Body $Body } if ($null -ne $AccountUnlockEnabled) { $Body = @{ accountUnlockEnabled = $AccountUnlockEnabled } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PUT -Body $Body } } # Export functions and aliases as required Export-ModuleMember -Function @('Connect-O365Admin', 'Get-O365AzureADConnect', 'Get-O365AzureADConnectPTA', 'Get-O365AzureADConnectSSO', 'Get-O365AzureSpeechServices', 'Get-O365BillingAccounts', 'Get-O365BillingNotifications', 'Get-O365BillingNotificationsList', 'Get-O365BillingPaymentMethods', 'Get-O365BingDataCollection', 'Get-O365Bookings', 'Get-O365BriefingEmail', 'Get-O365CalendarSharing', 'Get-O365CommunicationToUsers', 'Get-O365CompanyInformation', 'Get-O365ConsiergeAll', 'Get-O365Cortana', 'Get-O365CustomThemes', 'Get-O365DataLocation', 'Get-O365DirectorySync', 'Get-O365DirectorySyncErrors', 'Get-O365DirectorySyncManagement', 'Get-O365Domain', 'Get-O365DomainDependencies', 'Get-O365DomainHealth', 'Get-O365DomainRecords', 'Get-O365DomainTroubleshooting', 'Get-O365Dynamics365ConnectionGraph', 'Get-O365Dynamics365CustomerVoice', 'Get-O365Dynamics365SalesInsights', 'Get-O365ExternalCollaborationSettings', 'Get-O365Forms', 'Get-O365GraphDataConnect', 'Get-O365Group', 'Get-O365GroupMember', 'Get-O365HelpdeskInformation', 'Get-O365InstallationOptions', 'Get-O365LicensesAutoClaim', 'Get-O365MicrosoftTeams', 'Get-O365ModernAuthentication', 'Get-O365MultiFactorAuthentication', 'Get-O365MyAnalytics', 'Get-O365OfficeOnTheWeb', 'Get-O365OfficeProductivity', 'Get-O365OrganizationInformation', 'Get-O365OrgM365Groups', 'Get-O365OrgPlanner', 'Get-O365OrgUserConsentApps', 'Get-O365OrgUserOwnedApps', 'Get-O365OrgUserSettings', 'Get-O365PartnerRelationship', 'Get-O365PasswordExpirationPolicy', 'Get-O365PasswordReset', 'Get-O365PasswordResetIntegration', 'Get-O365PrivacyProfile', 'Get-O365Project', 'Get-O365ReleasePreferences', 'Get-O365Reports', 'Get-O365SearchIntelligenceItemInsights', 'Get-O365SearchIntelligenceMeetingInsights', 'Get-O365SharePoint', 'Get-O365Sharing', 'Get-O365Sway', 'Get-O365TenantID', 'Get-O365ToDo', 'Get-O365User', 'Invoke-O365Admin', 'Set-O365AzureSpeechServices', 'Set-O365BriefingEmail', 'Set-O365CalendarSharing', 'Set-O365Cortana', 'Set-O365Dynamics365ConnectionGraph', 'Set-O365Dynamics365SalesInsights', 'Set-O365Forms', 'Set-O365ModernAuthentication', 'Set-O365OrgM365Groups', 'Set-O365OrgPlanner', 'Set-O365OrgUserSettings', 'Set-O365PasswordReset', 'Set-O365PasswordResetIntegration') -Alias @() # SIG # Begin signature block # MIIdWQYJKoZIhvcNAQcCoIIdSjCCHUYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUJdfNnnUvQBLbz4R1iiEH2kTP # k/egghhnMIIDtzCCAp+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 # CzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFKvTYzWF4nqvzj7pfigV # jgbqFyPNMA0GCSqGSIb3DQEBAQUABIIBAH0/VjVD3hIfT4H6eFRB1l6ZcfJ7uxFo # CRtIlu6+rncLoh2x3N5FPnL8j+trBzyBQs3q4a9Fcci3EPb5CdR+4hVReeGyBBTN # q9EGDemZCJkTUMcK+DegHmRduPlULLUHvzIUfQrg4zsxk+rtT5y61+inXaa1U9LX # pTsqbdENsEHvyjf+7ofSj1D3kThxOcULg86cvoAZRvUkXnSmv9Su8bHfu3C3TcI2 # w8ANwNw6BYI0+E0DAMyGMT7rP7pL4Ytbkqzi97AIFCrkA00e4wUSaGmRSXwpuyYA # /bo/jI2GvGDQXj/0u0smyMguy4Q21LaNcm1zZ9dXa7KrJi4ITVyKQfahggIwMIIC # LAYJKoZIhvcNAQkGMYICHTCCAhkCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNV # BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G # A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQQIQ # DUJK4L46iP9gQCHOFADw3TANBglghkgBZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzEL # BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIxMDgyNzA2MzI1MlowLwYJKoZI # hvcNAQkEMSIEIKghwp36tWEsyrCL/iDKQk8ySpF9nG6557rQ/J4XM2fCMA0GCSqG # SIb3DQEBAQUABIIBACyCWhe814UNGNZ0cHtuABJVVwWaq+oIP8nQdw4mBBeh7T3R # JLZEZE8o02XidWXTTN6g4P1EyRJItvHHq/oVRv4bTmu3hbSy8m1Hsv68ZbQsWdCF # OizZGGJ7pJJ24oIK2yWcKR8olXPpPeQFvzN4GnoMAN+/m0pS9Vp2CC28BH9rwCpl # 8C44gNmb7tWY8OI0fOWu7vAlW41SaGdqfZM8k4wiM6leOti7Crilq4l5jnHSzkOV # UQjiDii34YCtN5Uyz+PMRTgKZ2UG/RPwFVz3h9HeO799YJOhskBJl2PwsHLXMlTH # +Vba+7jxAg42QUvHiswo6TtKKxpB9Ve2wdyAwsA= # SIG # End signature block |