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-AzureEnterpriseAppsUserConsent { [cmdletbinding()] param( [Array] $PermissionsGrantPoliciesAssigned, [switch] $Reverse ) $StringToProcess = $PermissionsGrantPoliciesAssigned[0] if (-not $Reverse) { $TranslatePermissions = @{ 'ManagePermissionGrantsForSelf.microsoft-user-default-legacy' = 'AllowUserConsentForApps' 'ManagePermissionGrantsForSelf.microsoft-user-default-low' = 'AllowUserConsentForSelectedPermissions' } if ($StringToProcess -and $TranslatePermissions[$StringToProcess]) { $TranslatePermissions[$StringToProcess] } else { 'DoNotAllowUserConsent' } } else { $TranslatePermissions = @{ 'AllowUserConsentForApps' = 'ManagePermissionGrantsForSelf.microsoft-user-default-legacy' 'AllowUserConsentForSelectedPermissions' = 'ManagePermissionGrantsForSelf.microsoft-user-default-low' 'DoNotAllowUserConsent' = '' } $TranslatePermissions[$StringToProcess] } } function Convert-AzureRole { [cmdletbinding()] param( [string[]] $RoleID, [switch] $All ) $Roles = [ordered] @{ '62e90394-69f5-4237-9190-012177145e10' = 'Global Administrator' # True '10dae51f-b6af-4016-8d66-8c2a99b929b3' = 'Guest User' # True '2af84b1e-32c8-42b7-82bc-daa82404023b' = 'Restricted Guest User' # True '95e79109-95c0-4d8e-aee3-d01accf2d47b' = 'Guest Inviter' # True 'fe930be7-5e62-47db-91af-98c3a49a38b1' = 'User Administrator' # True '729827e3-9c14-49f7-bb1b-9608f156bbb8' = 'Helpdesk Administrator' # True 'f023fd81-a637-4b56-95fd-791ac0226033' = 'Service Support Administrator' # True 'b0f54661-2d74-4c50-afa3-1ec803f12efe' = 'Billing Administrator' # True 'a0b1b346-4d3e-4e8b-98f8-753987be4970' = 'User' # True '4ba39ca4-527c-499a-b93d-d9b492c50246' = 'Partner Tier1 Support' # True 'e00e864a-17c5-4a4b-9c06-f5b95a8d5bd8' = 'Partner Tier2 Support' # True '88d8e3e3-8f55-4a1e-953a-9b9898b8876b' = 'Directory Readers' # True '9360feb5-f418-4baa-8175-e2a00bac4301' = 'Directory Writers' # True '29232cdf-9323-42fd-ade2-1d097af3e4de' = 'Exchange Administrator' # True 'f28a1f50-f6e7-4571-818b-6a12f2af6b6c' = 'SharePoint Administrator' # True '75941009-915a-4869-abe7-691bff18279e' = 'Skype for Business Administrator' # True 'd405c6df-0af8-4e3b-95e4-4d06e542189e' = 'Device Users' # True '9f06204d-73c1-4d4c-880a-6edb90606fd8' = 'Azure AD Joined Device Local Administrator' # True '9c094953-4995-41c8-84c8-3ebb9b32c93f' = 'Device Join' # True 'c34f683f-4d5a-4403-affd-6615e00e3a7f' = 'Workplace Device Join' # True '17315797-102d-40b4-93e0-432062caca18' = 'Compliance Administrator' # True 'd29b2b05-8046-44ba-8758-1e26182fcf32' = 'Directory Synchronization Accounts' # True '2b499bcd-da44-4968-8aec-78e1674fa64d' = 'Device Managers' # True '9b895d92-2cd3-44c7-9d02-a6ac2d5ea5c3' = 'Application Administrator' # True 'cf1c38e5-3621-4004-a7cb-879624dced7c' = 'Application Developer' # True '5d6b6bb7-de71-4623-b4af-96380a352509' = 'Security Reader' # True '194ae4cb-b126-40b2-bd5b-6091b380977d' = 'Security Administrator' # True 'e8611ab8-c189-46e8-94e1-60213ab1f814' = 'Privileged Role Administrator' # True '3a2c62db-5318-420d-8d74-23affee5d9d5' = 'Intune Administrator' # True '158c047a-c907-4556-b7ef-446551a6b5f7' = 'Cloud Application Administrator' # True '5c4f9dcd-47dc-4cf7-8c9a-9e4207cbfc91' = 'Customer LockBox Access Approver' # True '44367163-eba1-44c3-98af-f5787879f96a' = 'Dynamics 365 Administrator' # True 'a9ea8996-122f-4c74-9520-8edcd192826c' = 'Power BI Administrator' # True 'b1be1c3e-b65d-4f19-8427-f6fa0d97feb9' = 'Conditional Access Administrator' # True '4a5d8f65-41da-4de4-8968-e035b65339cf' = 'Reports Reader' # True '790c1fb9-7f7d-4f88-86a1-ef1f95c05c1b' = 'Message Center Reader' # True '7495fdc4-34c4-4d15-a289-98788ce399fd' = 'Azure Information Protection Administrator' # True '38a96431-2bdf-4b4c-8b6e-5d3d8abac1a4' = 'Desktop Analytics Administrator' # True '4d6ac14f-3453-41d0-bef9-a3e0c569773a' = 'License Administrator' # True '7698a772-787b-4ac8-901f-60d6b08affd2' = 'Cloud Device Administrator' # True 'c4e39bd9-1100-46d3-8c65-fb160da0071f' = 'Authentication Administrator' # True '7be44c8a-adaf-4e2a-84d6-ab2649e08a13' = 'Privileged Authentication Administrator' # True 'baf37b3a-610e-45da-9e62-d9d1e5e8914b' = 'Teams Communications Administrator' # True 'f70938a0-fc10-4177-9e90-2178f8765737' = 'Teams Communications Support Engineer' # True 'fcf91098-03e3-41a9-b5ba-6f0ec8188a12' = 'Teams Communications Support Specialist' # True '69091246-20e8-4a56-aa4d-066075b2a7a8' = 'Teams Administrator' # True 'eb1f4a8d-243a-41f0-9fbd-c7cdf6c5ef7c' = 'Insights Administrator' # True 'ac16e43d-7b2d-40e0-ac05-243ff356ab5b' = 'Message Center Privacy Reader' # True '6e591065-9bad-43ed-90f3-e9424366d2f0' = 'External ID User Flow Administrator' # True '0f971eea-41eb-4569-a71e-57bb8a3eff1e' = 'External ID User Flow Attribute Administrator' # True 'aaf43236-0c0d-4d5f-883a-6955382ac081' = 'B2C IEF Keyset Administrator' # True '3edaf663-341e-4475-9f94-5c398ef6c070' = 'B2C IEF Policy Administrator' # True 'be2f45a1-457d-42af-a067-6ec1fa63bc45' = 'External Identity Provider Administrator' # True 'e6d1a23a-da11-4be4-9570-befc86d067a7' = 'Compliance Data Administrator' # True '5f2222b1-57c3-48ba-8ad5-d4759f1fde6f' = 'Security Operator' # True '74ef975b-6605-40af-a5d2-b9539d836353' = 'Kaizala Administrator' # True 'f2ef992c-3afb-46b9-b7cf-a126ee74c451' = 'Global Reader' # True '0964bb5e-9bdb-4d7b-ac29-58e794862a40' = 'Search Administrator' # True '8835291a-918c-4fd7-a9ce-faa49f0cf7d9' = 'Search Editor' # True '966707d0-3269-4727-9be2-8c3a10f19b9d' = 'Password Administrator' # True '644ef478-e28f-4e28-b9dc-3fdde9aa0b1f' = 'Printer Administrator' # True 'e8cef6f1-e4bd-4ea8-bc07-4b8d950f4477' = 'Printer Technician' # True '0526716b-113d-4c15-b2c8-68e3c22b9f80' = 'Authentication Policy Administrator' # True 'fdd7a751-b60b-444a-984c-02652fe8fa1c' = 'Groups Administrator' # True '11648597-926c-4cf3-9c36-bcebb0ba8dcc' = 'Power Platform Administrator' # True 'e3973bdf-4987-49ae-837a-ba8e231c7286' = 'Azure DevOps Administrator' # True '8ac3fc64-6eca-42ea-9e69-59f4c7b60eb2' = 'Hybrid Identity Administrator' # True '2b745bdf-0803-4d80-aa65-822c4493daac' = 'Office Apps Administrator' # True 'd37c8bed-0711-4417-ba38-b4abe66ce4c2' = 'Network Administrator' # True '31e939ad-9672-4796-9c2e-873181342d2d' = 'Insights Business Leader' # True '3d762c5a-1b6c-493f-843e-55a3b42923d4' = 'Teams Devices Administrator' # True 'c430b396-e693-46cc-96f3-db01bf8bb62a' = 'Attack Simulation Administrator' # True '9c6df0f2-1e7c-4dc3-b195-66dfbd24aa8f' = 'Attack Payload Author' # True '75934031-6c7e-415a-99d7-48dbd49e875e' = 'Usage Summary Reports Reader' # True 'b5a8dcf3-09d5-43a9-a639-8e29ef291470' = 'Knowledge Administrator' # True '744ec460-397e-42ad-a462-8b3f9747a02c' = 'Knowledge Manager' # True '8329153b-31d0-4727-b945-745eb3bc5f31' = 'Domain Name Administrator' # True '31392ffb-586c-42d1-9346-e59415a2cc4e' = 'Exchange Recipient Administrator' # True '45d8d3c5-c802-45c6-b32a-1d70b5e1e86e' = 'Identity Governance Administrator' # True '892c5842-a9a6-463a-8041-72aa08ca3cf6' = 'Cloud App Security Administrator' # True '32696413-001a-46ae-978c-ce0f6b3620d2' = 'Windows Update Deployment Administrator' # True } if ($All) { $Roles.Values } else { foreach ($Role in $RoleID) { $RoleName = $Roles[$Role] if ($RoleName) { $RoleName } else { $Role } } } } function Convert-CompanyType { [cmdletbinding()] param( [string[]] $CompanyType ) $CompanyTypeInformation = [ordered] @{ '5' = 'Indirect reseller' '4' = 'Reseller' } foreach ($Company in $CompanyType) { $CompanyName = $CompanyTypeInformation[$Company] if ($CompanyName) { $CompanyName } else { $Company } } } function Convert-ContractType { [cmdletbinding()] param( [string[]] $ContractType ) $ContractTypeInformation = [ordered] @{ '3' = 'Reseller' } foreach ($Contract in $ContractType) { $ContractName = $ContractTypeInformation[$Contract] if ($ContractName) { $ContractName } else { $Contract } } } function Convert-SKUToLicense { [cmdletbinding()] param( [parameter()][string] $SKU ) $ServicePlans = Get-O365AzureLicenses -LicenseSKUID $SKU -ServicePlans -IncludeLicenseDetails if ($ServicePlans) { $ServicePlans } } function Find-EnabledServicePlan { [cmdletbinding()] param( [Array] $ServicePlans, [Array] $DisabledServicePlans ) $CachePlan = @{} foreach ($Plan in $ServicePlans) { $CachePlan[$Plan.serviceName] = $Plan } $Plans = [ordered] @{ Enabled = $null Disabled = $null } if ($DisabledServicePlans.Count -gt 0) { [Array] $Plans['Enabled'] = foreach ($Plan in $ServicePlans) { if ($Plan.serviceName -notin $DisabledServicePlans) { $Plan } } } else { [Array] $Plans['Enabled'] = $ServicePlans } [Array] $Plans['Disabled'] = foreach ($Plan in $DisabledServicePlans) { $CachePlan[$Plan] } $Plans } function Get-O365PrivateUserOrSPN { [cmdletBinding()] param( [string] $PrincipalID ) $OutputUser = Get-O365User -Id $PrincipalID -WarningAction SilentlyContinue -WarningVariable varWarning if ($OutputUser) { $OutputUser } else { $OutputService = Get-O365ServicePrincipal -Id $PrincipalID -WarningAction SilentlyContinue -WarningVariable +varWarning if ($OutputService) { $OutputService } } if (-not $OutputService -and -not $OutputUser) { foreach ($Warning in $VarWarning) { Write-Warning -Message $Warning } } } 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() } '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 ConvertFrom-JSONWebToken { <# .SYNOPSIS Converts JWT token to PowerShell object allowing for easier analysis. .DESCRIPTION Converts JWT token to PowerShell object allowing for easier analysis. .PARAMETER Token Provide Token to convert to PowerShell object .PARAMETER IncludeHeader Include header as part of ordered dictionary .EXAMPLE ConvertFrom-JSONWebToken -Token ..... .NOTES Based on https://www.michev.info/Blog/Post/2140/decode-jwt-access-and-id-tokens-via-powershell Basically does what: https://jwt.ms/ and https://jwt.io/ do for you online #> [cmdletbinding()] param( [Parameter(Mandatory = $true)][string]$Token, [switch] $IncludeHeader ) # Validate as per https://tools.ietf.org/html/rfc7519 # Access and ID tokens are fine, Refresh tokens will not work if (!$Token.Contains(".") -or !$Token.StartsWith("eyJ")) { Write-Warning -Message "ConvertFrom-JSONWebToken - Wrong token. Skipping." return } # Extract header and payload $tokenheader, $tokenPayload = $Token.Split(".").Replace('-', '+').Replace('_', '/')[0..1] # Fix padding as needed, keep adding "=" until string length modulus 4 reaches 0 while ($tokenheader.Length % 4) { $tokenheader += "=" } # Invalid length for a Base-64 char array or string, adding = while ($tokenPayload.Length % 4) { $tokenPayload += "=" } # Convert header from Base64 encoded string to PSObject all at once $header = [System.Text.Encoding]::UTF8.GetString([system.convert]::FromBase64String($tokenheader)) | ConvertFrom-Json # Convert payload to string array $tokenArray = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($tokenPayload)) # Convert from JSON to PSObject $TokenObject = $tokenArray | ConvertFrom-Json # Signature foreach ($i in 0..2) { $Signature = $Token.Split('.')[$i].Replace('-', '+').Replace('_', '/') switch ($Signature.Length % 4) { 0 { break } 2 { $Signature += '==' } 3 { $Signature += '=' } } } $TokenObject | Add-Member -Type NoteProperty -Name "signature" -Value $Signature # Convert Expire time to PowerShell DateTime $DateZero = (Get-Date -Year 1970 -Month 1 -Day 1 -Hour 0 -Minute 0 -Second 0 -Millisecond 0) $TimeZone = Get-TimeZone $UTC = $DateZero.AddSeconds($TokenObject.exp) $Offset = $TimeZone.GetUtcOffset($(Get-Date)).TotalMinutes $LocalTime = $UTC.AddMinutes($Offset) Add-Member -Type NoteProperty -Name "expires" -Value $LocalTime -InputObject $TokenObject # Time to Expire $TimeToExpire = ($LocalTime - (Get-Date)) Add-Member -Type NoteProperty -Name "timeToExpire" -Value $TimeToExpire -InputObject $TokenObject if ($IncludeHeader) { [ordered] @{ Header = $header Token = $TokenObject } } else { $TokenObject } } 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-O365AzureADRoles { [cmdletBinding()] param( ) #https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments&$filter=roleDefinitionId eq ‘<object-id-or-template-id-of-role-definition>’ #$Uri = 'https://main.iam.ad.ext.azure.com/api/Roles/User/e6a8f1cf-0874-4323-a12f-2bf51bb6dfdd/RoleAssignments?scope=undefined' $Uri = 'https://graph.microsoft.com/v1.0/roleManagement/directory/roleDefinitions' <# $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = $Filter '$orderby' = $OrderBy } #> <# GET https://graph.microsoft.com/beta/roleManagement/directory/roleDefinitions?$filter=DisplayName eq 'Conditional Access Administrator'&$select=rolePermissions #> Write-Verbose -Message "Get-O365AzureADRoles - Getting all Azure AD Roles" $Script:AzureADRolesList = [ordered] @{} $Script:AzureADRolesListReverse = [ordered] @{} $RolesList = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter -Method GET $Script:AzureADRoles = $RolesList foreach ($Role in $RolesList) { $Script:AzureADRolesList[$Role.id] = $Role $Script:AzureADRolesListReverse[$Role.displayName] = $Role } $RolesList } <# Invoke-WebRequest -Uri "https://main.iam.ad.ext.azure.com/api/Roles/User/e6a8f1cf-0874-4323-a12f-2bf51bb6dfdd/RoleAssignments?scope=undefined" ` -Method "OPTIONS" ` -Headers @{ "Accept"="*/*" "Access-Control-Request-Method"="GET" "Access-Control-Request-Headers"="authorization,content-type,x-ms-client-request-id,x-ms-client-session-id,x-ms-effective-locale" "Origin"="https://portal.azure.com" "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.84" "Sec-Fetch-Mode"="cors" "Sec-Fetch-Site"="same-site" "Sec-Fetch-Dest"="empty" "Accept-Encoding"="gzip, deflate, br" "Accept-Language"="en-US,en;q=0.9,pl;q=0.8" } #> <# GET https://admin.exchange.microsoft.com/beta/RoleGroup? HTTP/1.1 Host: admin.exchange.microsoft.com Connection: keep-alive sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92" x-ms-mac-hostingapp: M365AdminPortal AjaxSessionKey: x5eAwqzbVehBOP7QHfrjpwr9eYtLiHJt7TZFj0uhUMUPQ2T7yNdA7rEgOulejHDHYM1ZyCT0pgXo96EwrfVpMA== x-adminapp-request: /rbac/exchange sec-ch-ua-mobile: ?0 Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyIsImtpZCI6Im5PbzNaRHJPRFhFSzFqS1doWHNsSFJfS1hFZyJ9.eyJhdWQiOiI0OTdlZmZlOS1kZjcxLTQwNDMtYThiYi0xNGNmNzhjNGI2M2IiLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9jZWIzNzFmNi04NzQ1LTQ4NzYtYTA0MC02OWYyZDEwYTlkMWEvIiwiaWF0IjoxNjMwMjYwMjMxLCJuYmYiOjE2MzAyNjAyMzEsImV4cCI6MTYzMDI2NDEzMSwiYWNyIjoiMSIsImFpbyI6IkFWUUFxLzhUQUFBQXBtQ1F1b2lIR3lpYTd0dFB0czFZOEpIWUpleTB1Zndzb2oycUFvSEJKWjhQclowWlJONmhQSW5BblZHRld2cXp1R0xtbXNyS1Vaak12ZVBwNDJsQXhHY0d1bk5ZNTNNMmdWbE9uSXRhcHBrPSIsImFtciI6WyJyc2EiLCJtZmEiXSwiYXBwaWQiOiIwMDAwMDAwNi0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDAiLCJhcHBpZGFjciI6IjIiLCJkZXZpY2VpZCI6IjNhZTIyNzI2LWRmZDktNGFkNy1hODY1LWFhMmI1MWM2ZTBmZiIsImZhbWlseV9uYW1lIjoiS8WCeXMiLCJnaXZlbl9uYW1lIjoiUHJ6ZW15c8WCYXciLCJpcGFkZHIiOiI4OS43Ny4xMDIuMTciLCJuYW1lIjoiUHJ6ZW15c8WCYXcgS8WCeXMiLCJvaWQiOiJlNmE4ZjFjZi0wODc0LTQzMjMtYTEyZi0yYmY1MWJiNmRmZGQiLCJvbnByZW1fc2lkIjoiUy0xLTUtMjEtODUzNjE1OTg1LTI4NzA0NDUzMzktMzE2MzU5ODY1OS0xMTA1IiwicHVpZCI6IjEwMDMwMDAwOTQ0REI4NEQiLCJyaCI6IjAuQVM4QTluR3p6a1dIZGtpZ1FHbnkwUXFkR2dZQUFBQUFBUEVQemdBQUFBQUFBQUF2QUM4LiIsInNjcCI6InVzZXJfaW1wZXJzb25hdGlvbiIsInNpZCI6ImJkYjU3MmNiLTNkMzgtNGZlZi1iNjg2LTlmODhjNWRkNWQyNSIsInN1YiI6ImRranZjSlpIWjdjWkZPbnlSZkxZaDVLeHBUalVWdEVBLTVNSl81aF9GLWMiLCJ0aWQiOiJjZWIzNzFmNi04NzQ1LTQ4NzYtYTA0MC02OWYyZDEwYTlkMWEiLCJ1bmlxdWVfbmFtZSI6InByemVteXNsYXcua2x5c0Bldm90ZWMucGwiLCJ1cG4iOiJwcnplbXlzbGF3LmtseXNAZXZvdGVjLnBsIiwidXRpIjoiekxXUTdvUmc4ay0yVmlJV1dQNG1BQSIsInZlciI6IjEuMCIsIndpZHMiOlsiNjJlOTAzOTQtNjlmNS00MjM3LTkxOTAtMDEyMTc3MTQ1ZTEwIiwiYjc5ZmJmNGQtM2VmOS00Njg5LTgxNDMtNzZiMTk0ZTg1NTA5Il19.nzALEBEAAQBJddeeyt7Gn5sgy7y1Z1z_jfpLdjsPjgNSEOlHLPHqeyOx9QuHaEywK6es2pobYfhFtUvx1d09nz0qBI0b1wIRMX2W2-XaQOmg0FRTDQvTcC9d4Kum_hXmpTt8WgIpjKLKE0wmW8ZtsHbmh-JH3m9Y8j-9zktiRFtNbEyEa1uCTD7Wph9Ow_PAc6M9mWrERCb_XzaYDuwZWbfA_Ls2Bv8MGQsfkQh9RBsa-TgeuU1hhhGgcSaHPFAytJVQBq6QuMdqnO1pCevECf_OI2K54CcpISAUAPXW_gZXcj1waXzRRQfm85vCCh14oXvEj-Q94RsSq_5c_8cEFA client-request-id: 64d0ca10-08f4-11ec-ad6e-f9fb25a685f4 Accept: application/json, text/plain, */* x-ms-mac-version: host-mac_2021.8.19.4 x-portal-routekey: weu x-ms-mac-appid: 86d5ab1a-7f52-418c-b62d-a33841f2c949 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.84 x-ms-mac-target-app: EAC Origin: https://admin.microsoft.com Sec-Fetch-Site: same-site Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://admin.microsoft.com/ Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9,pl;q=0.8 GET https://admin.microsoft.com/admin/api/rbac/deviceManagement/roles HTTP/1.1 Host: admin.microsoft.com Connection: keep-alive sec-ch-ua: "Chromium";v="92", " Not A;Brand";v="99", "Microsoft Edge";v="92" x-ms-mac-hostingapp: M365AdminPortal AjaxSessionKey: x5eAwqzbVehBOP7QHfrjpwr9eYtLiHJt7TZFj0uhUMUPQ2T7yNdA7rEgOulejHDHYM1ZyCT0pgXo96EwrfVpMA== x-adminapp-request: /rbac/deviceManagement sec-ch-ua-mobile: ?0 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.84 Accept: application/json, text/plain, */* x-ms-mac-version: host-mac_2021.8.19.4 x-portal-routekey: weu x-ms-mac-appid: 86d5ab1a-7f52-418c-b62d-a33841f2c949 x-ms-mac-target-app: MAC Sec-Fetch-Site: same-origin Sec-Fetch-Mode: cors Sec-Fetch-Dest: empty Referer: https://admin.microsoft.com/ Accept-Encoding: gzip, deflate, br Accept-Language: en-US,en;q=0.9,pl;q=0.8 Cookie: MC1=GUID=480c128a5ba04faea7df151a53bdfa9a&HASH=480c&LV=202107&V=4&LU=1627670649689; x-portal-routekey=weu; p.BDId=00ab552e-0bd2-44f6-afb9-cbec94cb4051; s.AjaxSessionKey=x5eAwqzbVehBOP7QHfrjpwr9eYtLiHJt7TZFj0uhUMUPQ2T7yNdA7rEgOulejHDHYM1ZyCT0pgXo96EwrfVpMA%3D%3D; s.cachemap=22; s.BrowserIDe6a8f1cf-0874-4323-a12f-2bf51bb6dfdd=00ab552e-0bd2-44f6-afb9-cbec94cb4051; s.classic=False; s.CURedir=True; s.DisplayCulture=en-US; s.MFG=True; p.UtcOffset=-120; market=US; mslocale={'u':'pl-pl'}; LPVID=JjZDkxOGFjNzI3ZTFlZmY5; s.Cart={"BaseOffers":null,"Frequency":0,"IWPurchaseUserId":null,"PromotionCodes":null,"IsOfferTransition":false}; s.InNewAdmin=True; at_check=true; p.FirstLoginDateTimeUtc=id=-172832015&value=Oct_14_2015; s.ImpressionId=9c5222af-0f0a-4464-886a-ebc7eee1b188; p.FirstBillingYear=id=-172832015&value=2015; s.DefaultBillingMonth=08/20/2021 20:04:06; s.DCLoc=weuprod; p.TenantCulture=ceb371f6-8745-4876-a040-69f2d10a9d1a::pl-PL; mbox=PC#7383f384d21f43ef9a0d9d5c273578ed.37_0#1664248950|session#020faa6548144c6486e3597fd3298e30#1630064111; LPSID-60270350=HKOY_Iw3QjSJ9ijUKJt52Q; s.SessID=8798a6f9-b245-4f5e-99ed-1b78809d75a1; RootAuthToken=AwAAABoxMS8yNi8yMDIxIDE5OjA1OjU2ICswMDowMOoLMC5BUzhBOW5HenprV0hka2lnUUdueTBRcWRHZ1lBQUFBQUFQRVB6Z0FBQUFBQUFBQXZBQzguQWdBQkFBQUFBQUQtLURMQTNWTzdRcmRkZ0pnN1dldnJBZ0RzX3dRQTlQOHJfczBGMDYxZ053MTBrZllsVmtYOHZnYVZIbWFUWUVDbXltT2dzMWlGTFRsQXZ4VS1lYjdScjg2U2QwYXZSY05tNGpIcWhlMDBrYmJuWUh3NEtURnVHalN4cklQRTZjamlUUXJKYmRMMXNzcVpBVTZpUE94eVM1aHQzNEN0M1p0bWV1Y1BXaWNsZFdUNmlwVDJtT3JNS2RDaVZLUS1iRGctSHRjUjc3R094eU1hM2pIclBWOXZkOVFqdEdBY1g0azNqalZtRHJhODVFWFRKRjk3TFFEVUxGcWw1SUhyTy1ROHVfQ1RneUFjeHdjVml0anNBRllyUVFwTTFZM3hJRTFxcF9BXzZzeUZuRUFQVm9kUDIzSkUwLWtHaWNvYUowOXhRSlpvMEdTM2IwSzJtUWdFMTYybUUzRGdDQ3lna01qRjlBNko2b0otY09pZ25JOFVLNGg0MnAzVDlSeEdEbVZrTEM4LVJUbHVBUkVNS1JmTElsbFNXZVota1JHU1pZVExLY3IxUG5NN2pVSjBGZDZUODl5LTE1cFVSaWdFdHZKLTJtUms0S2s0ejUwTUtEUzIwejQzMHV3b19Ra1N6el81QnpyeFU5dnY1aGZGai1aOU5TSC16eEtKWHpaUUxua2toMElMd2NVc0xQVmdDVndPa3ZYTlRLazdNWmNUdHcyLVBOVFV2bTJha0p0ZjNQM3hIZExNX3RzdFlZUmxjVUlSOVBWWGFOeXpRTWlvX0kxU1lCanh6bUtpM2tfdVBvdXd1bzYycDltZlFOeUlrOWotX2ctQ2RlSVA4WVBsOHRnekhNMXJWTGlBWjdLUVlDZHpBNXRBMll5LVFFZEYyYi1VcDZqblFmeExoRnJBM3ZleWpRck1MUmJCdVVGVUxscUVMODZSRE16eld1eENoSGh1eEdzSTZaYnFPek9BdUJBSHpjRGxuNHN1MEpEQ3hmc3hidWhocTk4RHNHdWQ4MnhJNU1zYWtEZlZfYUN4ZXV0NzRPR1A2SnkyVGtaLVRJNWcyc2xpM2hEOW14VWRVNmVNdG1HQTVXeWs4dG9JaG1oMXVtMWNNVTBsblpFOUhOZDJKMzJHbk1LaU5Mejg4dktfeW5Va1llY2NwOEcwNUR4aUtpSGkzVUZqNm01eXFBSnVneFRTYTZ6SHBGWHF0SVFfNXZjTHJjM2JhR1paMm4xWjdBTEhZd3hxN3NSSmFNUTROZnFpRnNlT2pqR1JaNjI1VU5kdWxFTGJaLUp1aFpiS05uTG1wQlB5UkNSMEp2czlpekdRRU1ReXhhMzJKWHEzaGduQi1TcGd5N1lLS1dmYXN2MmVhV0hibUctR1hxQ2N4THZKbUV4WHM5VXVBd2NzLU1pc19wUmNzNTdlWmxHZ0xPTlpNUGxvNGQ5Vmh1b0tLanQ4dHdlRDA1VXZ5VGIzaFhjSjFBVG41aVhQampwaEFVaEhPNS01ZXg0cDkyakVmcy13SUhRV2ZURE1aZy1Ca0diVU85LUQtd0NSVExqVm1QV0k2TUFpM0h3cWxvZXZ2M3doWE80bm9NQmVMQlRsNHRiT2QyZXZocXlPaTNudHpNTzVBMFoxbzFDZ1NCMkozVkxRbFpDR2ZocHdHd1kwT3JGb25kVExIcG5LUnBLOE1YdkRLdldSd0tqUl9CSEVPU0IxNlVQOHg2SERZV1BUaGRWRDJFamVtbWpZWmgxaVF0cnZobjBFYTJiRE1yekVHcjFNTlFROGlPVENnLXlVWk1YeVVobXJYMklra05rVExZWWYzRU1ndHBGRUhDWHRTZWpueVphZ1JvcGh0M05yUTJ2MWFXOFE4Q1pfR21XcGs5dkE2MXR4MUhKZHExY3FldE1GM3FpbFAxSTJjd09RZFdNZy1OT2cA; s.LoginUserTenantId=kyHaNehhz9jpR+09ZPKS4DynUHwzw7PquEHQY+SZE6vRWhg+ZenTYDg29pApIbkUamgN9MVhZ/VbADv3Wr2Xnn3vQCRp3hHGvLU4EDcKBxLdi/J1UCSJ5YS6JobJ+hPsanTiHrdOwR5fSMI4rt1cJg==; UserIndex=H4sIAAAAAAAEAGNkYGBgBGI2IGYCsfWBBINkQVFVam5lcU5iuV52TmWxQ2pZfklqsl5BDjNQVtjIwMhQ18BC18gyxNDCysDUytSCBaSNFYTdEnOKU0HGqSSlJJmaGyUn6RqnGFvomqSlpukmmVmY6VqmWVgkm6akmKYYmYK0AQDFS8PlhAAAAA%3D%3D; OIDCAuthCookie=%2BSKNwKbOp3tUWr2%2BSTWrgME8BQoKkh7P55ishMUl3EwwalLmRnorz031%2FWXRh2gszg0uE20Nfdak8qB1vtHFOz%2FF24zwiQa0THjlt6pnBbz9vyhA4iuJNzvwt3XjSmId3Da9X8P4nQ%2FUJE%2BssHTASvNOEnPrMWvrBm1z0222f3GgiWQ2v9ArrbeXOxWvV8Me%2BUPnQ%2FEDui%2B940hO6htSDcG3h46GZJBbFSysbtE5dgQgPhixil29dQE7npcsCycLBgv%2FwypJXh%2BKq5mD%2BpfJwtNbDmvuxz9eQYZUBPWvriBHva6on%2FRXp19xAX8K%2BMwukPVYtCbqeaLP5LCK%2B1pQAFFa4GtKOY1OxVmIUcTSg88Jf0DGWYkR8CzFINgWxNhsVXRV%2BIWjz2OF6irsv%2F3L18zNFxluVlL41uzho5gqlI%2BTmgwtO%2FtWwMDqfZkdVYaufr%2B6DF6alJHFTGEb67sTmlMGeBI1w%2BeHc9Z3alFqLqcBVxg8XB88pUxzF6Dj7CGySByFC2lg%2FZaZeNgFx4BYYUa4o2rYpWhjVhYcXxixSOmFaqZhEEOCdrgB5qoTdoGMPCpoj22C9g6yow1l51GANTK9ujTRGS5LYLFA7R%2BSIcQNM50zDU1wAgoAl%2BnWQUjzK5D9XlBMhSovq7Dd4hXFW%2BnsQp2xKJL1AcE89FVKhlC3LKiwNHKSmDz2mlvYHyVRasm1jbel1BY0dKd%2F1ZMd5aKg94GEXeMdwpyyyg573HuFbCnPBd4TYdeMPg6siaMj%2Bwt%2BcZfZGbm6A9xfaq82vzUP3AU0lmz%2BYxaPT3e4fqmQVNxw0FvfPoIjy3SHaQryqseAP0LVwC6GXFOH4yEGtC63Y%2F%2FVOaE0LXbhhN10ejkQbwZGDtpUiO3%2FBihlUTVAEvYlWEnNd1Mjnr1uRl0JPknEUsbFe4gQNi7UIZo4T7vjDeNGom53bp%2BFryaNb9jCQi3jp1f9CU2xli%2B6pH%2B%2BuFvnODrDE5tJUHE3v13LljzGCbLXO%2B91K17KzIfiAoKAYnZPWNsFvgp2iUPbNRqax%2FBBtF7Zv%2ByofRex3OxXAR1kQCUcmxzItYeLBMNkTKY4B6L8w84U8Cmem%2Fnets2xdzNcYnu30qJkwHIckG7M5A4bpObrscZQ34XOiZ3%2FaLb3nAt8GhOgRe51XbzqVX86NeE9iDBhis%2FBG0JY2Ux3LZO%2B1FwKMjLO2a60OnJIRgORbjSaJV3aJiCkBlbpQ4PX5zXji41h4wSlVzYNsy2QlGJVpDfqbfqWl2DAH5JQKobBmlcp7bn3l6GGXR0XUcJJ6Qi4ZmXzofMLlc6zRhKe15cBp0zmzAlTd4%2BH6kbcduITep6h3NdjDmwFoTz96XY%2BzCE3HxgL1zrVW8qr6WYqSGbaaSqVMNKoM6Z33CRB%2BFUoVpZjHRl2kAxVdvRc3zLSI10M23PELrDur56TDDpgfi2ERY1DjNnS8BaucCs5Rqh35QQPLGmumMRprtrURFitfRlLgl7ZSyOW62ScyxxclityxBeY8NA%2Fi8IPFGrWSSrSVjAtTsJVjRUX5GHIANuZL9YImsVnrShvbyrbxMmSxfJ45pAo8mqX%2FGwnOg7V8TabzvYWuWZvUwpM%2BFktbNaQ960iRoR00UYI0IhC4hnoAAnlKeguUGq8aHuEUywllI%2FwYyjlRCXkx7znLCMj%2FuG7x7acGAStDg%2F97Q8ImojZWT9y9oD6QIPQLI7%2B4vqxBht2ZHxZMxr2WsoAUn1cB7WvPtIyJA43T36AL%2F64X0rg8Kj0nMsC3eQzoJGaWB9XSJzogLtCZAQ1W5%2BLPCIpsWL3IsL9J2gjivl%2BKNH8kDxckxpTFB69Rkau0%2BgjXXiyHEQEd6%2FDtOeRMI3MOWg%2FGzjVbVNxMJock%2B%2FpoAf%2FPgtkV8w%3D; s.DmnHQT=08/29/2021 18:06:00; s.DmnRQT=08/29/2021 18:06:07; s.DmnSOQT=08/29/2021 18:06:07; p.LastLoginDateTimeUtc=Aug_29_2021_18_06_00; MicrosoftApplicationsTelemetryDeviceId=f7e3a469-8044-4a21-ad55-69ce7f6b4086; MicrosoftApplicationsTelemetryFirstLaunchTime=2021-08-29T18:10:03.226Z #> function Get-O365AzureADRolesMember { [cmdletBinding(DefaultParameterSetName = 'Role')] param( [Parameter(Mandatory, ParameterSetName = 'Role')][Array] $RoleName, [Parameter(ParameterSetName = 'Filter')][string] $Filter, [Parameter(ParameterSetName = 'Role')] [Parameter(ParameterSetName = 'Filter')] [Parameter(ParameterSetName = 'All')] [string[]] $Property, [Parameter(ParameterSetName = 'Role')] [Parameter(ParameterSetName = 'Filter')] [Parameter(ParameterSetName = 'All')] [string] $OrderBy, [Parameter(ParameterSetName = 'All')][switch] $All ) $Uri = "https://graph.microsoft.com/v1.0/roleManagement/directory/roleAssignments" $QueryParameter = @{ '$Select' = $Property -join ',' '$orderby' = $OrderBy } $RolesList = [ordered] @{} if ($RoleName -or $All) { # in case user wanted all roles, we get it to him if ($All) { # we either use cache, or we ask for it if (-not $Script:AzureADRoles) { $RoleName = (Get-O365AzureADRoles).displayName } else { $RoleName = $Script:AzureADRoles.displayName } } # We want to get one or more roles at the same time foreach ($Role in $RoleName) { $RoleID = $null # We find the ID based on the cache or we ask Graph API to provide the list the first time if ($Script:AzureADRolesListReverse) { $TranslatedRole = $Script:AzureADRolesListReverse[$Role] } else { $null = Get-O365AzureADRoles $TranslatedRole = $Script:AzureADRolesListReverse[$Role] } if ($TranslatedRole) { # Once we have ID we query graph API $RoleID = $TranslatedRole.id $QueryParameter['$filter'] = "roleDefinitionId eq '$RoleID'" } else { Write-Warning -Message "Get-O365AzureADRolesMember - Couldn't gather roles because the ID translation didn't work for $Role" continue } Remove-EmptyValue -Hashtable $QueryParameter # We query graph API Write-Verbose -Message "Get-O365AzureADRolesMember - requesting role $Role ($RoleID)" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter -Method GET # if we asked for just one role we return the results directly if ($RoleName.Count -eq 1) { Write-Verbose -Message "Get-O365AzureADRolesMember - requesting users for $Role ($RoleID)" foreach ($User in $Output) { Get-O365PrivateUserOrSPN -PrincipalID $User.principalId } } else { # if we asked for more than one role we add the results to the list Write-Verbose -Message "Get-O365AzureADRolesMember - requesting users for $Role ($RoleID)" $RolesList[$Role] = foreach ($User in $Output) { Get-O365PrivateUserOrSPN -PrincipalID $User.principalId } } } if ($RoleName.Count -gt 1) { # if we asked for more than one role we return the list $RolesList } } elseif ($Filter) { $QueryParameter['$filter'] = $Filter Remove-EmptyValue -Hashtable $QueryParameter $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter -Method GET foreach ($User in $Output) { Get-O365PrivateUserOrSPN -PrincipalID $User.principalId } } } $Script:AzureRolesScriptBlock = { param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) #Convert-AzureRole -All | Where-Object { $_ -like "*$wordToComplete*" } if (-not $Script:AzureADRoles) { $AzureRoles = Get-O365AzureADRoles } else { $AzureRoles = $Script:AzureADRoles } ($AzureRoles | Where-Object { $_.displayName -like "*$wordToComplete*" }).displayName } Register-ArgumentCompleter -CommandName Get-O365AzureADRolesMember -ParameterName RoleName -ScriptBlock $Script:AzureRolesScriptBlock <# https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments&$filter=roleDefinitionId eq ‘<object-id-or-template-id-of-role-definition>’ #> #https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments&$filter=roleDefinitionId eq ‘<object-id-or-template-id-of-role-definition>’ #$Uri = 'https://main.iam.ad.ext.azure.com/api/Roles/User/e6a8f1cf-0874-4323-a12f-2bf51bb6dfdd/RoleAssignments?scope=undefined' <# GET https://graph.microsoft.com/beta/rolemanagement/directory/roleAssignments?$filter=principalId eq '55c07278-7109-4a46-ae60-4b644bc83a31' GET https://graph.microsoft.com/beta/groups?$filter=displayName+eq+'Contoso_Helpdesk_Administrator' GET https://graph.microsoft.com/beta/roleManagement/directory/roleAssignments?$filter=principalId eq #> <# Invoke-WebRequest -Uri "https://api.azrbac.mspim.azure.com/api/v2/privilegedAccess/aadroles/roleAssignments?`$expand=linkedEligibleRoleAssignment,subject,scopedResource,roleDefinition(`$expand=resource)&`$count=true&`$filter=(roleDefinition/resource/id%20eq%20%27ceb371f6-8745-4876-a040-69f2d10a9d1a%27)+and+(roleDefinition/id%20eq%20%275d6b6bb7-de71-4623-b4af-96380a352509%27)+and+(assignmentState%20eq%20%27Eligible%27)&`$orderby=roleDefinition/displayName&`$skip=0&`$top=10" -Headers @{ "x-ms-client-session-id"="3049c4c42d944f68bb7423154f7a1da5" "Accept-Language"="en" "Authorization"="Bearer ." "x-ms-effective-locale"="en.en-us" "Accept"="application/json, text/javascript, */*; q=0.01" #"Referer"="" "x-ms-client-request-id"="b0a543fc-ca4c-4ac6-aef6-5ceb09ad9003" "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.84" } #> function Get-O365AzureEnterpriseAppsGroupConsent { # https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/configure-user-consent?tabs=azure-portal [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = 'https://graph.microsoft.com/beta/settings' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { if ($NoTranslation) { ($Output | Where-Object { $_.displayName -eq 'Consent Policy Settings' }).values } else { $ConsentPolicy = $Output | Where-Object { $_.displayName -eq 'Consent Policy Settings' } if ($ConsentPolicy) { $Object = [PSCustomObject] @{ EnableGroupSpecificConsent = ($ConsentPolicy.values | Where-Object { $_.name -eq 'EnableGroupSpecificConsent' } | Select-Object -ExpandProperty value) BlockUserConsentForRiskyApps = $ConsentPolicy.values | Where-Object { $_.name -eq 'BlockUserConsentForRiskyApps' } | Select-Object -ExpandProperty value EnableAdminConsentRequests = $ConsentPolicy.values | Where-Object { $_.name -eq 'EnableAdminConsentRequests' } | Select-Object -ExpandProperty value ConstrainGroupSpecificConsentToMembersOfGroupId = $ConsentPolicy.values | Where-Object { $_.name -eq 'ConstrainGroupSpecificConsentToMembersOfGroupId' } | Select-Object -ExpandProperty value } if ($Object.EnableGroupSpecificConsent -eq 'true') { $Object.EnableGroupSpecificConsent = $true } else { $Object.EnableGroupSpecificConsent = $false } if ($Object.BlockUserConsentForRiskyApps -eq 'true') { $Object.BlockUserConsentForRiskyApps = $true } else { $Object.BlockUserConsentForRiskyApps = $false } if ($Object.EnableAdminConsentRequests -eq 'true') { $Object.EnableAdminConsentRequests = $true } else { $Object.EnableAdminConsentRequests = $false } $Object } } } } function Get-O365AzureEnterpriseAppsUserConsent { # https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/configure-user-consent?tabs=azure-portal # https://portal.azure.com/#blade/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/UserSettings [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = 'https://graph.microsoft.com/v1.0/policies/authorizationPolicy?$select=defaultUserRolePermissions' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { if ($NoTranslation) { $Output } else { [PSCustomObject] @{ allowedToCreateApps = $Output.defaultUserRolePermissions.allowedToCreateApps allowedToCreateSecurityGroups = $Output.defaultUserRolePermissions.allowedToCreateSecurityGroups allowedToReadOtherUsers = $Output.defaultUserRolePermissions.allowedToReadOtherUsers permissionGrantPoliciesAssigned = Convert-AzureEnterpriseAppsUserConsent -PermissionsGrantPoliciesAssigned $Output.defaultUserRolePermissions.permissionGrantPoliciesAssigned } } } } function Get-O365AzureEnterpriseAppsUserSettings { # https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/configure-user-consent?tabs=azure-portal # https://portal.azure.com/#blade/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/UserSettings # https://portal.azure.com/#blade/Microsoft_AAD_IAM/StartboardApplicationsMenuBlade/UserSettings/menuId/ [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = 'https://main.iam.ad.ext.azure.com/api/EnterpriseApplications/UserSettings' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { if ($NoTranslation) { $Output } else { [PSCustomObject] @{ UsersCanConsentAppsAccessingData = $Output.usersCanAllowAppsToAccessData UsersCanAddGalleryAppsToMyApp = $Output.usersCanAddGalleryApps UsersCanOnlySeeO365AppsInPortal = $Output.hideOffice365Apps } } } } function Get-O365AzureEnterpriseAppsUserSettingsAdmin { # https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/configure-user-consent?tabs=azure-portal # https://portal.azure.com/#blade/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/UserSettings # https://portal.azure.com/#blade/Microsoft_AAD_IAM/StartboardApplicationsMenuBlade/UserSettings/menuId/ [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = 'https://main.iam.ad.ext.azure.com/api/RequestApprovals/V2/PolicyTemplates?type=AdminConsentFlow' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { if ($NoTranslation) { $Output } else { [PSCustomObject] @{ requestExpiresInDays = $Output.requestExpiresInDays notificationsEnabled = $Output.notificationsEnabled remindersEnabled = $Output.remindersEnabled approvers = $Output.approvers approversV2 = $Output.approversV2 } } } } function Get-O365AzureEnterpriseAppsUserSettingsPromoted { # https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/configure-user-consent?tabs=azure-portal # https://portal.azure.com/#blade/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/UserSettings # https://portal.azure.com/#blade/Microsoft_AAD_IAM/StartboardApplicationsMenuBlade/UserSettings/menuId/ [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://main.iam.ad.ext.azure.com/api/workspaces/promotedapps' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365AzureExternalCollaborationFlows { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE An example .NOTES WARNING: Invoke-O365Admin - Error JSON: Response status code does not indicate success: 403 (Forbidden). The application does not have any of the required delegated permissions (Policy.Read.All, Policy.ReadWrite.AuthenticationFlows) to access the resource. #> [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = 'https://graph.microsoft.com/v1.0/policies/authenticationFlowsPolicy' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365AzureExternalCollaborationSettings { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $ReverseGuestRole = @{ 'a0b1b346-4d3e-4e8b-98f8-753987be4970' = 'User' '10dae51f-b6af-4016-8d66-8c2a99b929b3' = 'GuestUser' '2af84b1e-32c8-42b7-82bc-daa82404023b' = 'RestrictedUser' } $Uri = 'https://graph.microsoft.com/v1.0/policies/authorizationPolicy' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { [PSCustomObject] @{ #id = $Output.id # : authorizationPolicy allowInvitesFrom = $Output.allowInvitesFrom # : adminsAndGuestInviters allowedToSignUpEmailBasedSubscriptions = $Output.allowedToSignUpEmailBasedSubscriptions # : True allowedToUseSSPR = $Output.allowedToUseSSPR # : True allowEmailVerifiedUsersToJoinOrganization = $Output.allowEmailVerifiedUsersToJoinOrganization # : False blockMsolPowerShell = $Output.blockMsolPowerShell # : False displayName = $Output.displayName # : Authorization Policy description = $Output.description # : Used to manage authorization related settings across the company. guestUserRoleId = $ReverseGuestRole[$Output.guestUserRoleId] # : a0b1b346-4d3e-4e8b-98f8-753987be4970 defaultUserRolePermissions = $Output.defaultUserRolePermissions # : } } } <# $o = Invoke-WebRequest -Uri "https://graph.microsoft.com/beta/policies/authenticationFlowsPolicy" -Headers @{ "x-ms-client-session-id" = "a2f6c5f9b1b8450dbb0116f95ffbe9b2" "Accept-Language" = "en" "Authorization" = "Bearer . "x-ms-effective-locale" = "en.en-us" "Accept" = "*/*" #"Referer"="" "x-ms-client-request-id" = "d4bc027d-339c-46c2-ba96-c07f53fc5002" "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.84" } $o.content $p = Invoke-WebRequest -Uri "https://graph.microsoft.com/beta/policies/authorizationPolicy" -Headers @{ "x-ms-client-session-id" = "a2f6c5f9b1b8450dbb0116f95ffbe9b2" "Accept-Language" = "en" "Authorization" = "Bearer .. "x-ms-effective-locale" = "en.en-us" "Accept" = "*/*" #"Referer" = "" "x-ms-client-request-id" = "d4bc027d-339c-46c2-ba96-c07f53fc5001" "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.84" } $p.COntent $g = Invoke-WebRequest -Uri "https://main.iam.ad.ext.azure.com/api/B2B/b2bPolicy" ` -Headers @{ "x-ms-client-session-id" = "02ca6867073543de9a89b767ad581135" "Accept-Language" = "en" "Authorization" = "Bearer " "x-ms-effective-locale" = "en.en-us" "Accept" = "*/*" #"Referer" = "" "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.84" "x-ms-client-request-id" = "cf957d13-fc12-415d-a86a-1d74507d9003" } ` -ContentType "application/json" $g.content #> function Get-O365AzureExternalIdentitiesEmail { # https://portal.azure.com/#blade/Microsoft_AAD_IAM/CompanyRelationshipsMenuBlade/IdentityProviders [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = 'https://graph.microsoft.com/beta/policies/authenticationmethodspolicy/authenticationMethodConfigurations/email' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { if ($NoTranslation) { $Output } else { $Output } } } <# Requires scp : AccessReview.ReadWrite.All AuditLog.Read.All Directory.AccessAsUser.All Directory.Read.All Directory.ReadWrite.All email EntitlementManagement.Read.All Group.ReadWrite.All IdentityProvider.ReadWrite.All IdentityRiskEvent.ReadWri te.All IdentityUserFlow.Read.All openid Policy.Read.All Policy.ReadWrite.AuthenticationFlows Policy.ReadWrite.AuthenticationMethod Policy.ReadWrite.ConditionalAccess profile Reports.Read.All RoleManagement.ReadWrite.Directory Se curityEvents.ReadWrite.All TrustFrameworkKeySet.Read.All User.Export.All User.ReadWrite.All UserAuthenticationMethod.ReadWrite.All #> function Get-O365AzureExternalIdentitiesPolicies { # https://portal.azure.com/#blade/Microsoft_AAD_IAM/CompanyRelationshipsMenuBlade/IdentityProviders [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = 'https://main.iam.ad.ext.azure.com/api/B2B/b2bPolicy' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { if ($NoTranslation) { $Output } else { $Output } } } function Get-O365AzureGroupExpiration { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = 'https://main.iam.ad.ext.azure.com/api/Directories/LcmSettings' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method Get if ($Output) { if ($NoTranslation) { $Output } else { if ($Output.expiresAfterInDays -eq 0) { $GroupLifeTime = '180' } elseif ($Output.expiresAfterInDays -eq 1) { $GroupLifeTime = '365' } elseif ($Output.expiresAfterInDays -eq 2) { $GroupLifeTime = $Output.groupLifetimeCustomValueInDays } if ($Output.managedGroupTypes -eq 2) { $ExpirationEnabled = 'None' } elseif ($Output.managedGroupTypes -eq 1) { $ExpirationEnabled = 'Selected' } elseif ($Output.managedGroupTypes -eq 0) { $ExpirationEnabled = 'All' } else { $ExpirationEnabled = 'Unknown' } <# expiresAfterInDays : 2 groupLifetimeCustomValueInDays : 185 managedGroupTypesEnum : 0 managedGroupTypes : 0 adminNotificationEmails : przemyslaw.klys@evotec.pl groupIdsToMonitorExpirations : {} policyIdentifier : 6f843b54-8fa0-4837-a8e7-b01d00d25892 #> [PSCustomObject] @{ GroupLifeTime = $GroupLifeTime AdminNotificationEmails = $Output.adminNotificationEmails ExpirationEnabled = $ExpirationEnabled ExpirationGroups = $Output.groupIdsToMonitorExpirations } } } } function Get-O365AzureLicenses { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .PARAMETER LicenseName Parameter description .PARAMETER ServicePlans Parameter description .PARAMETER LicenseSKUID Parameter description .EXAMPLE $Licenses = Get-O365AzureLicenses $Licenses | Format-Table .EXAMPLE $ServicePlans = Get-O365AzureLicenses -ServicePlans -LicenseName 'Enterprise Mobility + Security E5' -Verbose $ServicePlans | Format-Table .EXAMPLE $ServicePlans = Get-O365AzureLicenses -ServicePlans -LicenseSKUID 'EMSPREMIUM' -Verbose $ServicePlans | Format-Table .EXAMPLE $ServicePlans = Get-O365AzureLicenses -ServicePlans -LicenseSKUID 'evotecpoland:EMSPREMIUM' -Verbose $ServicePlans | Format-Table .EXAMPLE $ServicePlans = Get-O365AzureLicenses -ServicePlans -LicenseSKUID 'evotecpoland:EMSPREMIUM' -IncludeLicenseDetails -Verbose $ServicePlans | Format-Table .NOTES General notes #> [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [string] $LicenseName, [switch] $ServicePlans, [switch] $ServicePlansComplete, [string] $LicenseSKUID, [switch] $IncludeLicenseDetails ) # Maybe change it to https://docs.microsoft.com/en-us/graph/api/subscribedsku-list?view=graph-rest-1.0&tabs=http # Or maybe not because it doesn't contain exactly same data missing displayName from service plans # $Uri = "https://graph.microsoft.com/v1.0/subscribedSkus" $Uri = "https://main.iam.ad.ext.azure.com/api/AccountSkus" $QueryParameter = @{ backfillTenants = $false } if (-not $Script:AzureLicensesList) { Write-Verbose -Message "Get-O365AzureLicenses - Querying for Licenses SKU" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter # We build a list of all the licenses, for caching purposes if ($Output) { $Script:AzureLicensesList = $Output } } else { Write-Verbose -Message "Get-O365AzureLicenses - Reusing cache for Licenses SKU" $Output = $Script:AzureLicensesList } # If license name or license id is provided we filter thjings out if ($LicenseName) { $Output = $Output | Where-Object { $_.Name -eq $LicenseName } } elseif ($LicenseSKUID) { $Output = $Output | Where-Object { $TempSplit = $_.AccountSkuId -split ':' $TempSplit[1] -eq $LicenseSKUID -or $_.AccountSkuId -eq $LicenseSKUID } } # we then based on ServicePlans request only display service plans if ($ServicePlans) { foreach ($O in $Output) { if ($IncludeLicenseDetails) { foreach ($Plan in $O.serviceStatuses.servicePlan) { [PSCustomObject] @{ LicenseName = $O.Name LicenseSKUID = $O.AccountSkuId ServiceDisplayName = $Plan.displayName ServiceName = $Plan.serviceName ServicePlanId = $Plan.servicePlanId ServiceType = $Plan.serviceType } } } else { $O.serviceStatuses.servicePlan } } } elseif ($ServicePlansComplete) { # or display everything foreach ($O in $Output) { [PSCustomObject] @{ Name = $O.Name AccountSkuID = $O.AccountSkuId ServicePlan = $O.serviceStatuses.servicePlan AvailableUnits = $o.availableUnits TotalUnits = $O.totalUnits ConsumedUnits = $O.consumedUnits WarningUnits = $O.warningUnits } } } else { $Output } } # https://main.iam.ad.ext.azure.com/api/AccountSkus/UserAssignments?accountSkuID=evotecpoland%3AEMSPREMIUM&nextLink=&searchText=&columnName=&sortOrder=undefined # https://main.iam.ad.ext.azure.com/api/AccountSkus/UserAssignments?accountSkuID=evotecpoland%3AEMSPREMIUM&nextLink=&searchText=&columnName=&sortOrder=undefined # https://main.iam.ad.ext.azure.com/api/AccountSkus/GroupAssignments?accountSkuID=evotecpoland%3AEMSPREMIUM&nextLink=&searchText=&sortOrder=undefined function Get-O365AzureMultiFactorAuthentication { <# .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-O365AzureUserSettings { [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-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-O365BillingInvoices { <# .SYNOPSIS Gets all invoices from Office 365. If no StartDate and EndDate are specified last 6 months are used. .DESCRIPTION Gets all invoices from Office 365. If no StartDate and EndDate are specified last 6 months are used. .PARAMETER Headers Parameter description .PARAMETER StartDate Provide StartDate for the invoices to be retrieved. If not specified, StartDate is set to 6 months ago. .PARAMETER EndDate Provide EndDate for the invoices to be retrieved. If not specified, EndDate is set to current date. .EXAMPLE An example .NOTES General notes #> [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [DateTime] $StartDate, [DateTime] $EndDate ) if (-not $StartDate) { $StartDate = (Get-Date).AddMonths(-6) } if (-not $EndDate) { $EndDate = Get-Date } $StartDateText = $StartDate.ToString("yyyy-MM-dd") $EndDateText = $EndDate.ToString("yyyy-MM-dd") $Uri = "https://admin.microsoft.com/fd/commerceapi/my-org/legacyInvoices(startDate=$StartDateText,endDate=$EndDateText)" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365BillingLicenseAutoClaim { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) if ($Headers) { $TentantID = $Headers.Tenant } else { $TentantID = $Script:AuthorizationO365Cache.Tenant } $Uri = "https://admin.microsoft.com/fd/m365licensing/v1/tenants/$TentantID/licenseddevicesassets" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output.items } function Get-O365BillingLicenseRequests { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) if ($Headers) { $TentantID = $Headers.Tenant } else { $TentantID = $Script:AuthorizationO365Cache.Tenant } $Uri = "https://admin.microsoft.com/fd/m365licensing/v1/tenants/$TentantID/self-service-requests" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output.items } 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-O365BillingProfile { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/fd/commerceMgmt/moderncommerce/checkaccess/bulk?api-version=3.0&accountId=91e58......." $Body = @{ "permissionId" = "40000000-aaaa-bbbb-ccc............" "organizationId" = "19419c1b-1bf1-41...." "commerceObjectType" = "BillingGroup" "commerceObjectId" = "6YPQ-QFKZ....." } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Get-O365BillingSubscriptions { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [string[]]$Property, [string] $OrderBy ) #$Uri = "https://admin.microsoft.com/fd/commerceapi/my-org/subscriptions?`$filter=parentId%20eq%20null&`$expand=subscribedsku&optional=cspsubscriptions,price,actions,transitiondetails,quickstarttag" $Uri = "https://admin.microsoft.com/fd/commerceapi/my-org/subscriptions" $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = 'parentId eq null' '$orderby' = $OrderBy 'expand' = 'subscribedsku' 'optional' = "cspsubscriptions,price,actions,transitiondetails,quickstarttag" } Remove-EmptyValue -Hashtable $QueryParameter $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -QueryParameter $QueryParameter $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-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 if ($Output.Succeeded) { $Output.Data } else { $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-O365Group { [cmdletBinding(DefaultParameterSetName = 'Default')] param( [parameter(ParameterSetName = 'UnifiedGroupsOnly')] [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 = 'UnifiedGroupsOnly')] [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 = 'UnifiedGroupsOnly')] [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [string] $OrderBy, [parameter(ParameterSetName = 'UnifiedGroupsOnly')] [switch] $UnifiedGroupsOnly ) 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 ',' } } elseif ($UnifiedGroupsOnly) { $Uri = "https://graph.microsoft.com/v1.0/groups" $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "groupTypes/any(c: c eq 'Unified')" '$orderby' = $OrderBy } } 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-O365GroupAdministrativeUnit { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter()][string] $GroupID = '75233998-a950-41de-97d0-6c259d0580a7' ) if ($GroupID) { $Group = $GroupID } elseif ($GroupDisplayName) { $Group = $GroupDisplayName } #$Uri = "https://graph.microsoft.com/beta/groups/$Group/memberOf/microsoft.graph.administrativeUnit" $Uri = "https://graph.microsoft.com/v1.0/groups/$Group/memberOf/microsoft.graph.administrativeUnit" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365GroupLicenses { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter()][string] $GroupID, [parameter()][alias('GroupName')][string] $GroupDisplayName, [switch] $ServicePlans, [switch] $NoTranslation ) if ($GroupID) { $Group = $GroupID } elseif ($GroupDisplayName) { $GroupSearch = Get-O365Group -DisplayName $GroupDisplayName if ($GroupSearch.id) { $Group = $GroupSearch.id } } if ($Group) { $Uri = "https://main.iam.ad.ext.azure.com/api/AccountSkus/Group/$Group" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { if ($NoTranslation) { $Output } else { foreach ($License in $Output.licenses) { $SP = Convert-SKUToLicense -SKU $License.accountSkuID if ($SP) { $ServicePlansPrepared = Find-EnabledServicePlan -ServicePlans $SP -DisabledServicePlans $License.disabledServicePlans [PSCustomObject] @{ License = $SP[0].LicenseName LicenseSKUID = $SP[0].LicenseSKUID Enabled = $ServicePlansPrepared.Enabled.ServiceDisplayName Disabled = $ServicePlansPrepared.Disabled.ServiceDisplayName EnabledPlan = $ServicePlansPrepared.Enabled DisabledPlan = $ServicePlansPrepared.Disabled } } } } } } } 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-O365OrgAzureSpeechServices { [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-O365OrgBingDataCollection { [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-O365OrgBookings { [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-O365OrgBriefingEmail { <# .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-O365OrgCalendarSharing { <# .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-O365OrgCommunicationToUsers { [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-O365OrgCompanyInformation { [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-O365OrgCortana { [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-O365OrgCustomerLockbox { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/settings/security/dataaccess" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365OrgCustomThemes { [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-O365OrgDataLocation { [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-O365OrgDynamics365ConnectionGraph { [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-O365OrgDynamics365CustomerVoice { [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-O365OrgDynamics365SalesInsights { [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-O365OrgForms { [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-O365OrgGraphDataConnect { [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-O365OrgHelpdeskInformation { [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-O365OrgInstallationOptions { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Branches = @{ "0" = 'Not applicable' "1" = "CurrentChannel" "3" = 'MonthlyEnterpriseChannel' "2" = 'SemiAnnualEnterpriseChannel' } $Uri = "https://admin.microsoft.com/admin/api/settings/apps/usersoftware" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($NoTranslation) { $Output.UserSoftwareSettings } else { if ($Output.UserSoftwareSettings) { [PSCustomObject] @{ WindowsBranch = $Branches[$($Output.UserSoftwareSettings[0].Branch.ToString())] WindowsClient = $Output.UserSoftwareSettings[0].ClientVersion WindowsLastUpdate = $Output.UserSoftwareSettings[0].BranchLastUpdateTime WindowsOffice = $Output.UserSoftwareSettings[0].ServiceStatusMap.'Office (includes Skype for Business),MicrosoftOffice_ClientDownload' WindowsSkypeForBusiness = $Output.UserSoftwareSettings[0].ServiceStatusMap.'Skype for Business (Standalone),MicrosoftCommunicationsOnline'; MacBranch = $Branches[$($Output.UserSoftwareSettings[1].Branch.ToString())] MacClient = $Output.UserSoftwareSettings[1].ClientVersion MacLastUpdate = $Output.UserSoftwareSettings[1].BranchLastUpdateTime MacOffice = $Output.UserSoftwareSettings[1].ServiceStatusMap.'Office,MicrosoftOffice_ClientDownload' MacSkypeForBusiness = $Output.UserSoftwareSettings[1].LegacyServiceStatusMap.'Skype for Business (X EI Capitan 10.11 or higher),MicrosoftCommunicationsOnline' } } } } function Get-O365OrgLicensesAutoClaim { [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-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-O365OrgMicrosoftSearch { [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-O365OrgMicrosoftTeams { [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-O365OrgModernAuthentication { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .EXAMPLE Get-O365OrgModernAuthentication -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-O365OrgMyAnalytics { [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 if ($Output) { [PSCustomObject] @{ EnableInsightsDashboard = -not $Output.IsDashboardOptedOut EnableWeeklyDigest = -not $Output.IsEmailOptedOut EnableInsightsOutlookAddIn = -not $Output.IsAddInOptedOut # IsNudgesOptedOut : False # IsWindowsSignalOptedOut : False # MeetingEffectivenessSurvey : Unavailable } } } function Get-O365OrgNews { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/news/options/Bing" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($NoTranslation) { $Output } else { If ($Output) { [PSCustomObject] @{ ContentOnNewTabEnabled = $Output.NewsOptions.EdgeNTPOptions.IsOfficeContentEnabled CompanyInformationAndIndustryEnabled = $Output.NewsOptions.EdgeNTPOptions.IsShowCompanyAndIndustry } } } } function Get-O365OrgOfficeOnTheWeb { [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-O365OrgOfficeProductivity { [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-O365OrgOrganizationInformation { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = "https://admin.microsoft.com/admin/api/Settings/company/profile" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($NoTranslation) { $Output } else { $Output } } function Get-O365OrgPasswordExpirationPolicy { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = "https://admin.microsoft.com/admin/api/Settings/security/passwordpolicy" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($NoTranslation) { $Output } else { [PSCustomObject] @{ PasswordNeverExpires = $Output.NeverExpire DaysBeforePasswordExpires = $Output.ValidityPeriod DaysBeforeUserNotified = $Output.NotificationDays # not shown in the GUI # MinimumValidityPeriod : 14 # MinimumNotificationDays : 1 # MaximumValidityPeriod : 730 # MaximumNotificationDays : 30 } } } 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] @{ # Thos are always the same #id = $Output.id # : 1 #isPlannerAllowed = $Output.isPlannerAllowed # : True allowCalendarSharing = $Output.allowCalendarSharing # : True # GUI doesn't show that # allowTenantMoveWithDataLoss = $Output.allowTenantMoveWithDataLoss # : False # allowRosterCreation = $Output.allowRosterCreation # : True # allowPlannerMobilePushNotifications = $Output.allowPlannerMobilePushNotifications # : True } } } function Get-O365OrgPrivacyProfile { [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-O365OrgPrivilegedAccess { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Uri = "https://admin.microsoft.com/admin/api/Settings/security/tenantLockbox" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers $Output } function Get-O365OrgProject { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/projectonline" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($NoTranslation) { $Output } else { if ($Output) { [PSCustomObject] @{ RoadmapEnabled = $Output.IsRoadmapEnabled ProjectForTheWebEnabled = $Output.IsModProjEnabled } } } } function Get-O365OrgReports { [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-O365OrgScripts { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $Status = @{ '0' = 'Disabled' '1' = 'Everyone' '2' = 'SpecificGroup' } $Uri = "https://admin.microsoft.com/admin/api/settings/apps/officescripts" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { [PSCustomObject] @{ # we don't show those options as they have no values # we also don't show them as there is no option in GUI #OfficeScriptsEnabled = $Output.OfficeScriptsEnabled # : #OfficeScriptsPreviewEnabled = $Output.OfficeScriptsPreviewEnabled # : EnabledOption = $Status[$($Output.EnabledOption).ToString()] # : 1 EnabledGroup = $Output.EnabledGroup # : EnabledGroupDetail = $Output.EnabledGroupDetail # : ShareOption = $Status[$($Output.ShareOption).ToString()] # : 1 ShareGroup = $Output.ShareGroup # : ShareGroupDetail = $Output.ShareGroupDetail # : UnattendedOption = $Status[$($Output.UnattendedOption).ToString()] # : 0 UnattendedGroup = $Output.UnattendedGroup # : UnattendedGroupDetail = $Output.UnattendedGroupDetail # : #TenantId = $Output.TenantId # : } } } function Get-O365OrgSharePoint { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers ) $TranslateCollaboration = @{ '2' = 'NewAndExistingGuestsOnly' '16' = 'Anyone' '32' = 'ExistingGuestsOnly' '1' = 'OnlyPeopleInYourOrganization' } $Uri = "https://admin.microsoft.com/admin/api/settings/apps/sitessharing" $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($Output) { [PSCustomObject] @{ AllowSharing = $Output.AllowSharing SiteUrl = $Output.SiteUrl AdminUrl = $Output.AdminUrl RequireAnonymousLinksExpireInDays = $Output.RequireAnonymousLinksExpireInDays CollaborationType = $TranslateCollaboration[$Output.CollaborationType.ToString()] } } } function Get-O365OrgSharing { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $Uri = "https://admin.microsoft.com/admin/api/settings/security/guestUserPolicy" $Output1 = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($NoTranslation) { $Output1 } else { # In fiddler we coudld see additional queries, but in edge/chrome not so much #$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 if ($Output1) { [PSCustomObject] @{ # GUI doesn't show them, so mayne lets not show them eiter #AllowGuestAccess = $Output1.AllowGuestAccess LetUsersAddNewGuests = $Output1.AllowGuestInvitations #SitesSharingEnabled = $Output1.SitesSharingEnabled #AllowSharing = $Output2.AllowSharing #SiteUrl = $Output2.SiteUrl #AdminUri = $Output2.AdminUri #RequireAnonymousLinksExpireInDays = $Output2.RequireAnonymousLinksExpireInDays #CollaborationType = $Output2.CollaborationType } } } } function Get-O365OrgSway { [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-O365OrgToDo { [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-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 if ($null -ne $Output) { [PSCustomObject] @{ UserConsentToAppsEnabled = $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 = if ($Output4.tenantPolicyValue -eq 'Disabled') { $false } elseif ($Output4.tenantPolicyValue -eq 'Enabled') { $true } else { $null } <# { "policyId": "Autoclaim", "tenantPolicyValue": "Enabled", "tenantId": "ceb371f6-" } #> } } function Get-O365OrgWhiteboard { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [switch] $NoTranslation ) $TranslateTelemetry = @{ '0' = 'Neither' '1' = 'Required' '2' = 'Optional' } $Uri = 'https://admin.microsoft.com/admin/api/settings/apps/whiteboard' $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers if ($NoTranslation) { $Output } else { if ($Output) { [PSCustomObject] @{ WhiteboardEnabled = $Output.IsEnabled DiagnosticData = $TranslateTelemetry[$Output.TelemetryPolicy.ToString()] OptionalConnectedExperiences = $Output.AreConnectedServicesEnabled BoardSharingEnabled = $Output.IsClaimEnabled OneDriveStorageEnabled = $Output.IsSharePointDefault # Not sure what this does NonTenantAccess = $Output.NonTenantAccess #LearnMoreUrl = $Output.LearnMoreUrl #ProductUrl = $Output.ProductUrl #TermsOfUseUrl = $Output.TermsOfUseUrl } } } } 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) { foreach ($Partner in $Output.partners) { [PSCustomObject] @{ id = $Partner.id #: c2248f0a name = $Partner.name #: aadRoles = Convert-AzureRole -RoleID $Partner.aadRoles # i am not 100% sure on the conversion types on different numbers so i'll disable them for now companyType = $Partner.companyType #Convert-CompanyType -CompanyType $Partner.companyType #: 4 canRemoveDap = $Partner.canRemoveDap #: True contractTypes = $Partner.contractTypes # Convert-ContractType -ContractType $Partner.contractTypes #: {3} partnerType = $Partner.partnerType #: 1 } } } } else { Write-Warning -Message "Get-O365PartnerRelationship - TenantID was not found in headers. Skipping." } } 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-O365OrgReleasePreferences { [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-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-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-O365ServicePrincipal { [cmdletBinding(DefaultParameterSetName = "Default")] param( [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'GuestsOnly')] [parameter(ParameterSetName = 'ServicePrincipalType')] [parameter(ParameterSetName = 'AppDisplayName')] [parameter(ParameterSetName = 'Id')] [parameter()][alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(ParameterSetName = 'Id')][string] $Id, [parameter(ParameterSetName = 'AppDisplayName')][string] $DisplayName, [ValidateSet('Application', 'Legacy', 'SocialIdp')][parameter(ParameterSetName = 'servicePrincipalType')][string] $ServicePrincipalType, [parameter(ParameterSetName = 'Default')] [parameter(ParameterSetName = 'Filter')] [parameter(ParameterSetName = 'GuestsOnly')] [parameter(ParameterSetName = 'ServicePrincipalType')] [parameter(ParameterSetName = 'AppDisplayName')] [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/servicePrincipals' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "userType eq 'Guest'" '$orderby' = $OrderBy } } elseif ($DisplayName) { $Uri = 'https://graph.microsoft.com/v1.0/servicePrincipals' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "displayName eq '$DisplayName'" } } elseif ($ServicePrincipalType) { $Uri = 'https://graph.microsoft.com/v1.0/servicePrincipals' $QueryParameter = @{ '$Select' = $Property -join ',' '$filter' = "servicePrincipalType eq '$ServicePrincipalType'" } } elseif ($ID) { # Query a single group $Uri = "https://graph.microsoft.com/v1.0/servicePrincipals/$ID" $QueryParameter = @{ '$Select' = $Property -join ',' } } else { # Query multiple groups $Uri = 'https://graph.microsoft.com/v1.0/servicePrincipals' $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 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-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 } if ($PSVersionTable.PSVersion.Major -eq 5) { $CookieContainer = [System.Net.CookieContainer]::new() $CookieContainer.MaxCookieSize = 1048576 $Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new() $Session.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36 Edg/93.0.961.38" $Session.Cookies = $CookieContainer $RestSplat['WebSession'] = $Session } #$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 [bool]) { $OutputQuery } elseif ($OutputQuery -is [array]) { $Properties = $OutputQuery | Select-Properties -ExcludeProperty '@odata.context', '@odata.id', '@odata.type', 'Length' -WarningAction SilentlyContinue -WarningVariable varWarning if (-not $varWarning) { $OutputQuery | Select-Object -Property $Properties } } elseif ($OutputQuery -is [string]) { if ($OutputQuery) { $Properties = $OutputQuery | Select-Properties -ExcludeProperty '@odata.context', '@odata.id', '@odata.type', 'Length' -WarningAction SilentlyContinue -WarningVariable varWarning if (-not $varWarning) { $OutputQuery | Select-Object -Property $Properties } } } elseif ($OutputQuery -is [PSCustomObject]) { if ($OutputQuery.PSObject.Properties.Name -contains 'value') { $Properties = $OutputQuery.value | Select-Properties -ExcludeProperty '@odata.context', '@odata.id', '@odata.type', 'Length' -WarningAction SilentlyContinue -WarningVariable varWarning if (-not $varWarning) { $OutputQuery.value | Select-Object -Property $Properties } } else { $Properties = $OutputQuery | Select-Properties -ExcludeProperty '@odata.context', '@odata.id', '@odata.type', 'Length' -WarningAction SilentlyContinue -WarningVariable varWarning if (-not $varWarning) { $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 New-O365License { <# .SYNOPSIS Helper cmdlet to create a new O365 license that is used in Set-O365AzureGroupLicenses cmdlet. .DESCRIPTION Helper cmdlet to create a new O365 license that is used in Set-O365AzureGroupLicenses cmdlet. .PARAMETER LicenseName LicenseName to assign. Can be used instead of LicenseSKUID .PARAMETER LicenseSKUID LicenseSKUID to assign. Can be used instead of LicenseName .PARAMETER EnabledServicesDisplayName Parameter description .PARAMETER EnabledServicesName Parameter description .PARAMETER DisabledServicesDisplayName Parameter description .PARAMETER DisabledServicesName Parameter description .EXAMPLE Set-O365GroupLicenses -GroupDisplayName 'Test-Group-TestEVOTECPL' -Licenses @( New-O365License -LicenseName 'Office 365 E3' -Verbose New-O365License -LicenseName 'Enterprise Mobility + Security E5' -Verbose ) -Verbose -WhatIf .EXAMPLE Set-O365GroupLicenses -GroupDisplayName 'Test-Group-TestEVOTECPL' -Licenses @( New-O365License -LicenseName 'Office 365 E3' -Verbose -DisabledServicesDisplayName 'Microsoft Kaizala Pro', 'Whiteboard (Plan 2)' New-O365License -LicenseName 'Enterprise Mobility + Security E5' -Verbose -EnabledServicesDisplayName 'Azure Information Protection Premium P2', 'Microsoft Defender for Identity' ) -Verbose -WhatIf .NOTES General notes #> [cmdletbinding(DefaultParameterSetName = 'ServiceDisplayNameEnable')] param( [string] $LicenseName, [string] $LicenseSKUID, [Parameter(ParameterSetName = 'ServiceDisplayNameEnable')][string[]] $EnabledServicesDisplayName, [Parameter(ParameterSetName = 'ServiceNameEnable')][string[]] $EnabledServicesName, [Parameter(ParameterSetName = 'ServiceDisplayNameDisable')][string[]] $DisabledServicesDisplayName, [Parameter(ParameterSetName = 'ServiceNameDisable')][string[]] $DisabledServicesName ) if ($LicenseName) { $ServicePlans = Get-O365AzureLicenses -ServicePlans -IncludeLicenseDetails -LicenseName $LicenseName } elseif ($LicenseSKUID) { $ServicePlans = Get-O365AzureLicenses -ServicePlans -IncludeLicenseDetails -LicenseSKUID $LicenseSKUID } else { return } if ($ServicePlans) { if ($EnabledServicesDisplayName -or $EnabledServicesName -or $DisabledServicesDisplayName -or $DisabledServicesName) { [Array] $DisabledServicePlans = foreach ($Plan in $ServicePlans) { if ($EnabledServicesDisplayName) { if ($Plan.ServiceDisplayName -notin $EnabledServicesDisplayName) { $Plan.serviceName } } elseif ($EnabledServicesName) { if ($Plan.ServiceName -notin $EnabledServicesName) { $Plan.serviceName } } elseif ($DisabledServicesDisplayName) { if ($Plan.ServiceDisplayName -in $DisabledServicesDisplayName) { $Plan.serviceName } } elseif ($DisabledServicesName) { if ($Plan.ServiceName -in $DisabledServicesName) { $Plan.serviceName } } } } else { $DisabledServicePlans = @() } if ($ServicePlans[0].LicenseSKUID) { [ordered] @{ accountSkuId = $ServicePlans[0].LicenseSKUID disabledServicePlans = if ($DisabledServicePlans.Count -eq 0) { , @() } else { $DisabledServicePlans } } } else { Write-Warning "New-O365License - No LicenseSKUID found. Skipping" } } } function Set-O365AzureEnterpriseAppsGroupConsent { # https://portal.azure.com/#blade/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/UserSettings [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter()][bool] $EnableGroupSpecificConsent, [Parameter()][string] $GroupId, [Parameter()][string] $GroupName, # Other options [Parameter()][bool] $BlockUserConsentForRiskyApps, [Parameter()][bool] $EnableAdminConsentRequests ) $Uri = 'https://graph.microsoft.com/beta/settings/e0953218-a490-4c92-a975-ab724a6cfb07' $CurrentSettings = Get-O365AzureEnterpriseAppsGroupConsent -Headers $Headers if ($CurrentSettings) { [string] $EnableSpecific = if ($PSBoundParameters.ContainsKey('EnableGroupSpecificConsent')) { $EnableGroupSpecificConsent.ToString().ToLower() } else { $CurrentSettings.EnableGroupSpecificConsent.ToString().ToLower() } if ($PSBoundParameters.ContainsKey('EnableGroupSpecificConsent')) { # We only set group if EnableGroupSpecificConsent is used if ($GroupId) { $Group = $GroupId } elseif ($GroupName) { $AskForGroup = Get-O365Group -DisplayName $GroupName -Headers $Headers if ($AskForGroup.Id) { $Group = $AskForGroup.Id if ($Group -isnot [string]) { Write-Warning -Message "Set-O365AzureEnterpriseAppsGroupConsent - GroupName couldn't be translated to single ID. " foreach ($G in $AskForGroup) { Write-Warning -Message "Group DisplayName: $($G.DisplayName) | Group ID: $($G.ID)" } return } } else { Write-Warning -Message "Set-O365AzureEnterpriseAppsGroupConsent - GroupName couldn't be translated to ID. Skipping." return } } else { $Group = '' } } else { # We read the current group $Group = $CurrentSettings.ConstrainGroupSpecificConsentToMembersOfGroupId } [string] $BlockUserConsent = if ($PSBoundParameters.ContainsKey('BlockUserConsentForRiskyApps')) { $BlockUserConsentForRiskyApps.ToString().ToLower() } else { $CurrentSettings.BlockUserConsentForRiskyApps.ToString().ToLower() } [string] $AdminConsent = if ($PSBoundParameters.ContainsKey('EnableAdminConsentRequests')) { $EnableAdminConsentRequests.ToString().ToLower() } else { $CurrentSettings.EnableAdminConsentRequests.ToString().ToLower() } $Body = @{ values = @( [ordered] @{ "name" = "EnableGroupSpecificConsent"; "value" = $EnableSpecific } [ordered] @{ "name" = "BlockUserConsentForRiskyApps"; "value" = $BlockUserConsent } [ordered] @{ "name" = "EnableAdminConsentRequests"; "value" = $AdminConsent } [ordered] @{ "name" = "ConstrainGroupSpecificConsentToMembersOfGroupId"; value = $Group } ) } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PATCH -Body $Body } } function Set-O365AzureEnterpriseAppsUserConsent { # https://portal.azure.com/#blade/Microsoft_AAD_IAM/ConsentPoliciesMenuBlade/UserSettings [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][string][ValidateSet('AllowUserConsentForApps', 'AllowUserConsentForSelectedPermissions', 'DoNotAllowUserConsent')] $PermissionGrantPoliciesAssigned ) $Uri = 'https://graph.microsoft.com/v1.0/policies/authorizationPolicy' $Convert = Convert-AzureEnterpriseAppsUserConsent -PermissionsGrantPoliciesAssigned $PermissionGrantPoliciesAssigned -Reverse $Body = @{ defaultUserRolePermissions = [ordered] @{ permissionGrantPoliciesAssigned = if ($Convert) { , @($Convert) } else { , @() } } } if ($Body) { $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PATCH -Body $Body } } function Set-O365AzureEnterpriseAppsUserSettings { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .PARAMETER UsersCanConsentAppsAccessingData Parameter description .PARAMETER UsersCanAddGalleryAppsToMyApp Parameter description .PARAMETER UsersCanOnlySeeO365AppsInPortal Parameter description .EXAMPLE An example .NOTES Please keep in mind that: - Users can consent to apps accessing company data for the groups they own -> can be set using Set-O3465AzureEnterpriseAppsGroupConsent #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $UsersCanConsentAppsAccessingData, [nullable[bool]] $UsersCanAddGalleryAppsToMyApp, [nullable[bool]] $UsersCanOnlySeeO365AppsInPortal ) $Uri = 'https://main.iam.ad.ext.azure.com/api/EnterpriseApplications/UserSettings' # contrary to most of the cmdlets it seem if you provide null as values not filled in, nothing is changed # Body "{`"usersCanAllowAppsToAccessData`":false,`"usersCanAddGalleryApps`":null,`"hideOffice365Apps`":null}" $Body = @{ usersCanAllowAppsToAccessData = $UsersCanConsentAppsAccessingData usersCanAddGalleryApps = $UsersCanAddGalleryAppsToMyApp hideOffice365Apps = $UsersCanOnlySeeO365AppsInPortal } # But we're going to remove those empty entries anyways Remove-EmptyValue -Hashtable $Body if ($Body.Keys.Count -gt 0) { $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PATCH -Body $Body } } function Set-O365AzureEnterpriseAppsUserSettingsAdmin { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][bool] $UserConsentToAppsEnabled ) $Uri = "https://main.iam.ad.ext.azure.com/api/RequestApprovals/V2/PolicyTemplates" #-Body "{`"id`":null,`"requestExpiresInDays`":30,`"notificationsEnabled`":true,` #"remindersEnabled`":true,`"approversV2`":{`"user`":[`"e6a8f1cf-0874-4323-a12f-2bf51bb6dfdd`"],`"group`":[],`"role`":[]}}" #$Body = @{ # Enabled = $UserConsentToAppsEnabled #} #$null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365AzureExternalCollaborationSettings { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [ValidateSet('none', 'adminsAndGuestInviters', 'adminsGuestInvitersAndAllMembers', 'everyone')][string] $AllowInvitesFrom, [System.Nullable[bool]] $AllowedToSignUpEmailBasedSubscriptions, [System.Nullable[bool]] $AllowedToUseSSPR, [System.Nullable[bool]] $AllowEmailVerifiedUsersToJoinOrganization, [System.Nullable[bool]] $BlockMsolPowerShell, [string] $DisplayName, [string] $Description, [ValidateSet('User', 'GuestUser', 'RestrictedUser')][string] $GuestUserRole, [System.Nullable[bool]] $AllowedToCreateApps, [System.Nullable[bool]] $AllowedToCreateSecurityGroups, [System.Nullable[bool]] $AllowedToReadOtherUsers, [Array] $PermissionGrantPoliciesAssigned ) $GuestUserRoleIDs = @{ 'User' = 'a0b1b346-4d3e-4e8b-98f8-753987be4970' 'GuestUser' = '10dae51f-b6af-4016-8d66-8c2a99b929b3' 'RestrictedUser' = '2af84b1e-32c8-42b7-82bc-daa82404023b' } if ($GuestUserRole) { $GuestUserRoleID = $GuestUserRoleIDs[$GuestUserRole] } if ($AllowInvitesFrom) { # This translation is to make sure the casing is correct as it may be given by user in different way if ($AllowInvitesFrom -eq 'none') { $AllowInvitesFrom = 'none' } elseif ($AllowInvitesFrom -eq 'adminsAndGuestInviters') { $AllowInvitesFrom = 'adminsAndGuestInviters' } elseif ($AllowInvitesFrom -eq 'adminsGuestInvitersAndAllMembers') { $AllowInvitesFrom = 'adminsGuestInvitersAndAllMembers' } elseif ($AllowInvitesFrom -eq 'everyone') { $AllowInvitesFrom = 'everyone' } } $Uri = 'https://graph.microsoft.com/v1.0/policies/authorizationPolicy' $Body = @{ allowInvitesFrom = $AllowInvitesFrom # : adminsAndGuestInviters allowedToSignUpEmailBasedSubscriptions = $AllowedToSignUpEmailBasedSubscriptions # : True allowedToUseSSPR = $AllowedToUseSSPR # : True allowEmailVerifiedUsersToJoinOrganization = $AllowEmailVerifiedUsersToJoinOrganization # : False blockMsolPowerShell = $BlockMsolPowerShell # : False displayName = $DisplayName # : Authorization Policy description = $Description # : Used to manage authorization related settings across the company. guestUserRoleId = $GuestUserRoleId # : a0b1b346-4d3e-4e8b-98f8-753987be4970 defaultUserRolePermissions = [ordered] @{ allowedToCreateApps = $AllowedToCreateApps allowedToCreateSecurityGroups = $AllowedToCreateSecurityGroups allowedToReadOtherUsers = $AllowedToReadOtherUsers permissionGrantPoliciesAssigned = $PermissionGrantPoliciesAssigned } } Remove-EmptyValue -Hashtable $Body -Recursive -Rerun 2 if ($Body) { $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PATCH -Body $Body #$Output } } function Set-O365AzureGroupExpiration { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[int]] $GroupLifeTime, [string][ValidateSet('None', 'Selected', 'All')] $ExpirationEnabled, [string] $AdminNotificationEmails, [Array] $ExpirationGroups, [Array] $ExpirationGroupsID ) $Uri = 'https://main.iam.ad.ext.azure.com/api/Directories/LcmSettings' $CurrentSettings = Get-O365AzureGroupExpiration -Headers $Headers -NoTranslation if ($null -ne $GroupLifeTime) { # if group lifetime is defined we need to build 2 values if ($GroupLifeTime -eq 180) { $expiresAfterInDays = 0 $groupLifetimeCustomValueInDays = 0 } elseif ($GroupLifeTime -eq 365) { $expiresAfterInDays = 1 $groupLifetimeCustomValueInDays = 0 } else { $expiresAfterInDays = 2 $groupLifetimeCustomValueInDays = $GroupLifeTime } } else { # if it's not defined we need to get current values $expiresAfterInDays = $CurrentSettings.expiresAfterInDays $groupLifetimeCustomValueInDays = $CurrentSettings.groupLifetimeCustomValueInDays } if ($ExpirationEnabled -eq 'None') { $ManagedGroupTypes = 2 } elseif ($ExpirationEnabled -eq 'Selected') { $ManagedGroupTypes = 1 } elseif ($ExpirationEnabled -eq 'All') { $ManagedGroupTypes = 0 } else { $ManagedGroupTypes = $CurrentSettings.managedGroupTypes } if (-not $AdminNotificationEmails) { $AdminNotificationEmails = $CurrentSettings.adminNotificationEmails } if ($ExpirationGroups) { [Array] $GroupsID = foreach ($Ex in $ExpirationGroups) { $GroupFound = Get-O365Group -DisplayName $Ex -Headers $Headers if ($GroupFound.Id) { $GroupFound.Id } } if ($GroupsID.Count -gt 0) { $groupIdsToMonitorExpirations = if ($GroupsID.Count -in 0, 1) { , @($GroupsID) } else { $GroupsID } } else { Write-Warning -Message "Set-O365AzureGroupExpiration - Couldn't find any groups provided in ExpirationGroups. Skipping" return } } elseif ($ExpirationGroupsID) { $groupIdsToMonitorExpirations = if ($ExpirationGroupsID.Count -in 0, 1) { , @($ExpirationGroupsID) } else { $ExpirationGroupsID } } else { $groupIdsToMonitorExpirations = if ($CurrentSettings.groupIdsToMonitorExpirations.count -in 0, 1) { , @($CurrentSettings.groupIdsToMonitorExpirations) } else { $CurrentSettings.groupIdsToMonitorExpirations } } $Body = [ordered] @{ expiresAfterInDays = $expiresAfterInDays groupLifetimeCustomValueInDays = $groupLifetimeCustomValueInDays managedGroupTypesEnum = $CurrentSettings.managedGroupTypesEnum managedGroupTypes = $ManagedGroupTypes adminNotificationEmails = $AdminNotificationEmails groupIdsToMonitorExpirations = $groupIdsToMonitorExpirations policyIdentifier = $CurrentSettings.policyIdentifier } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PUT -Body $Body } function Set-O365AzureMultiFactorAuthentication { <# .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(SupportsShouldProcess)] 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 . 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 Set-O365AzureUserSettings { <# .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-O365BillingNotifications { <# .SYNOPSIS Sets settijngs for Billing notifications (Invoice PDF ON/OFF) .DESCRIPTION Sets settijngs for Billing notifications (Invoice PDF ON/OFF) .PARAMETER Headers Parameter description .PARAMETER SendInvoiceEmails Parameter description .EXAMPLE An example .NOTES Sets settings for Billing notifications https://admin.microsoft.com/#/BillingNotifications #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][bool] $SendInvoiceEmails ) $Uri = "https://admin.microsoft.com/fd/commerceMgmt/mgmtsettings/invoicePreference?api-version=1.0" $Body = @{ sendInvoiceEmails = $SendInvoiceEmails } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body if ($Output.setInvoicePreferenceSuccessful -eq $true) { } } function Set-O365GroupLicenses { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter()][string] $GroupID, [parameter()][alias('GroupName')][string] $GroupDisplayName, [Array] $Licenses ) $Uri = "https://main.iam.ad.ext.azure.com/api/AccountSkus/assignUpdateRemove" if ($GroupID) { $Group = $GroupID #$GroupSearch = Get-O365Group -Id $GroupID #if ($GroupSearch.id) { # $GroupName = $GroupSearch.displayName #} } elseif ($GroupDisplayName) { $GroupSearch = Get-O365Group -DisplayName $GroupDisplayName if ($GroupSearch.id) { $Group = $GroupSearch.id #$GroupName = $GroupSearch.displayName } } if ($Group) { $CurrentLicenses = Get-O365GroupLicenses -GroupID $Group -NoTranslation if ($CurrentLicenses.objectid) { # we cache it for better use of search $CacheLicenses = [ordered] @{} foreach ($License in $CurrentLicenses.licenses) { $CacheLicenses[$License.accountSkuId] = $License } <# accountSkuId disabledServicePlans hasErrors errorCount ------------ -------------------- --------- ---------- evotecpoland:FLOW_FREE {} 0 evotecpoland:POWER_BI_STANDARD {} 0 evotecpoland:POWER_BI_PRO {} 0 evotecpoland:ENTERPRISEPACK {POWER_VIRTUAL_AGENTS_O365_P2, PROJECT_O365_P2} 0 #> $AddLicenses = [System.Collections.Generic.List[System.Collections.IDictionary]]::new() $RemoveLicenses = [System.Collections.Generic.List[string]]::new() $UpdateLicenses = [System.Collections.Generic.List[System.Collections.IDictionary]]::new() foreach ($License in $Licenses) { if ($CacheLicenses[$License.accountSkuId]) { if (-not (Compare-Object -ReferenceObject $License.disabledServicePlans -DifferenceObject $CacheLicenses[$License.accountSkuId].disabledServicePlans)) { # We do nothing, because the licenses have the same disabled service plans are the same } else { $UpdateLicenses.Add($License) } } else { $AddLicenses.Add($License) } } foreach ($License in $CurrentLicenses.licenses) { if ($License.accountSkuId -notin $Licenses.accountSkuId) { #$PrepareForRemoval = New-O365License -DisabledServicesName $License.disabledServicePlans -LicenseSKUID $License.accountSkuId #if ($PrepareForRemoval) { $RemoveLicenses.Add($License.accountSkuId) #} } } $Body = [ordered] @{ assignments = @( [ordered] @{ objectId = $Group #displayName = $GroupName isUser = $false addLicenses = $AddLicenses removeLicenses = $RemoveLicenses updateLicenses = $UpdateLicenses } ) } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } else { Write-Warning -Message "Set-O365GroupLicenses - Querying for current group licenses failed. Skipping." } } else { Write-Error -Message "Set-O365GroupLicenses - Couldn't find group. Skipping." } } function Set-O365OrgAzureSpeechServices { [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-O365OrgBingDataCollection { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $IsBingDataCollectionConsented ) $Uri = "https://admin.microsoft.com/admin/api/settings/security/bingdatacollection" $Body = [ordered] @{ IsBingDataCollectionConsented = $IsBingDataCollectionConsented } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365OrgBookings { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $Enabled, [nullable[bool]] $ShowPaymentsToggle, [nullable[bool]] $PaymentsEnabled, [nullable[bool]] $ShowSocialSharingToggle, [nullable[bool]] $SocialSharingRestricted, [nullable[bool]] $ShowBookingsAddressEntryRestrictedToggle, [nullable[bool]] $BookingsAddressEntryRestricted, [nullable[bool]] $ShowBookingsAuthEnabledToggle, [nullable[bool]] $BookingsAuthEnabled, [nullable[bool]] $ShowBookingsCreationOfCustomQuestionsRestrictedToggle, [nullable[bool]] $BookingsCreationOfCustomQuestionsRestricted, [nullable[bool]] $ShowBookingsExposureOfStaffDetailsRestrictedToggle, [nullable[bool]] $BookingsExposureOfStaffDetailsRestricted, [nullable[bool]] $ShowBookingsNotesEntryRestrictedToggle, [nullable[bool]] $BookingsNotesEntryRestricted, [nullable[bool]] $ShowBookingsPhoneNumberEntryRestrictedToggle, [nullable[bool]] $BookingsPhoneNumberEntryRestricted, [nullable[bool]] $ShowStaffApprovalsToggle, [nullable[bool]] $StaffMembershipApprovalRequired ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/bookings" $CurrentSettings = Get-O365OrgBookings -Headers $Headers if ($CurrentSettings) { $Body = @{ Enabled = $CurrentSettings.Enabled #: True ShowPaymentsToggle = $CurrentSettings.ShowPaymentsToggle #: False PaymentsEnabled = $CurrentSettings.PaymentsEnabled #: False ShowSocialSharingToggle = $CurrentSettings.ShowSocialSharingToggle #: True SocialSharingRestricted = $CurrentSettings.SocialSharingRestricted #: False ShowBookingsAddressEntryRestrictedToggle = $CurrentSettings.ShowBookingsAddressEntryRestrictedToggle #: False BookingsAddressEntryRestricted = $CurrentSettings.BookingsAddressEntryRestricted #: False ShowBookingsAuthEnabledToggle = $CurrentSettings.ShowBookingsAuthEnabledToggle #: False BookingsAuthEnabled = $CurrentSettings.BookingsAuthEnabled #: False ShowBookingsCreationOfCustomQuestionsRestrictedToggle = $CurrentSettings.ShowBookingsCreationOfCustomQuestionsRestrictedToggle #: False BookingsCreationOfCustomQuestionsRestricted = $CurrentSettings.BookingsCreationOfCustomQuestionsRestricted #: False ShowBookingsExposureOfStaffDetailsRestrictedToggle = $CurrentSettings.ShowBookingsExposureOfStaffDetailsRestrictedToggle #: False BookingsExposureOfStaffDetailsRestricted = $CurrentSettings.BookingsExposureOfStaffDetailsRestricted #: False ShowBookingsNotesEntryRestrictedToggle = $CurrentSettings.ShowBookingsNotesEntryRestrictedToggle #: False BookingsNotesEntryRestricted = $CurrentSettings.BookingsNotesEntryRestricted #: False ShowBookingsPhoneNumberEntryRestrictedToggle = $CurrentSettings.ShowBookingsPhoneNumberEntryRestrictedToggle #: False BookingsPhoneNumberEntryRestricted = $CurrentSettings.BookingsPhoneNumberEntryRestricted #: False ShowStaffApprovalsToggle = $CurrentSettings.ShowStaffApprovalsToggle #: True StaffMembershipApprovalRequired = $CurrentSettings.StaffMembershipApprovalRequired #: False } if ($null -ne $Enabled) { $Body.Enabled = $Enabled } if ($null -ne $ShowPaymentsToggle) { $Body.ShowPaymentsToggle = $ShowPaymentsToggle } if ($null -ne $PaymentsEnabled) { $Body.PaymentsEnabled = $PaymentsEnabled } if ($null -ne $ShowSocialSharingToggle) { $Body.ShowSocialSharingToggle = $ShowSocialSharingToggle } if ($null -ne $SocialSharingRestricted) { $Body.SocialSharingRestricted = $SocialSharingRestricted } if ($null -ne $ShowBookingsAddressEntryRestrictedToggle) { $Body.ShowBookingsAddressEntryRestrictedToggle = $ShowBookingsAddressEntryRestrictedToggle } if ($null -ne $BookingsAddressEntryRestricted) { $Body.BookingsAddressEntryRestricted = $BookingsAddressEntryRestricted } if ($null -ne $ShowBookingsAuthEnabledToggle) { $Body.ShowBookingsAuthEnabledToggle = $ShowBookingsAuthEnabledToggle } if ($null -ne $BookingsAuthEnabled) { $Body.BookingsAuthEnabled = $BookingsAuthEnabled } if ($null -ne $ShowBookingsCreationOfCustomQuestionsRestrictedToggle) { $Body.ShowBookingsCreationOfCustomQuestionsRestrictedToggle = $ShowBookingsCreationOfCustomQuestionsRestrictedToggle } if ($null -ne $BookingsCreationOfCustomQuestionsRestricted) { $Body.BookingsCreationOfCustomQuestionsRestricted = $BookingsCreationOfCustomQuestionsRestricted } if ($null -ne $ShowBookingsExposureOfStaffDetailsRestrictedToggle) { $Body.ShowBookingsExposureOfStaffDetailsRestrictedToggle = $ShowBookingsExposureOfStaffDetailsRestrictedToggle } if ($null -ne $BookingsExposureOfStaffDetailsRestricted) { $Body.BookingsExposureOfStaffDetailsRestricted = $BookingsExposureOfStaffDetailsRestricted } if ($null -ne $ShowBookingsNotesEntryRestrictedToggle) { $Body.ShowBookingsNotesEntryRestrictedToggle = $ShowBookingsNotesEntryRestrictedToggle } if ($null -ne $BookingsNotesEntryRestricted) { $Body.BookingsNotesEntryRestricted = $BookingsNotesEntryRestricted } if ($null -ne $ShowBookingsPhoneNumberEntryRestrictedToggle) { $Body.ShowBookingsPhoneNumberEntryRestrictedToggle = $ShowBookingsPhoneNumberEntryRestrictedToggle } if ($null -ne $BookingsPhoneNumberEntryRestricted) { $Body.BookingsPhoneNumberEntryRestricted = $BookingsPhoneNumberEntryRestricted } if ($null -ne $ShowStaffApprovalsToggle) { $Body.ShowStaffApprovalsToggle = $ShowStaffApprovalsToggle } if ($null -ne $StaffMembershipApprovalRequired) { $Body.StaffMembershipApprovalRequired = $StaffMembershipApprovalRequired } Remove-EmptyValue -Hashtable $Body $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } } function Set-O365OrgBriefingEmail { <# .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-O365OrgCalendarSharing { <# .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-O365OrgCalendarSharing -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-O365OrgCommunicationToUsers { [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-O365OrgCortana { <# .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, [Parameter(Mandatory)][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-O365OrgCustomerLockbox { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][bool] $RequireApproval ) $Uri = "https://admin.microsoft.com/admin/api/settings/security/dataaccess" $Body = @{ RequireApproval = $RequireApproval } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365OrgDynamics365ConnectionGraph { [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-O365OrgDynamics365SalesInsights { [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-O365OrgForms { [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-O365OrgForms -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-O365OrgGraphDataConnect { <# .SYNOPSIS Short description .DESCRIPTION Long description .PARAMETER Headers Parameter description .PARAMETER ServiceEnabled Parameter description .PARAMETER TenantLockBoxApproverGroup Group provided in form of email address. The email address must exists! Otherwise the api will break cmdlet .PARAMETER Force Forces the operation to run ignoring current settings. Useful to overwrite settings after breaking tenant :-) .EXAMPLE An example .NOTES General notes #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $ServiceEnabled, [string] $TenantLockBoxApproverGroup, [switch] $Force ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/o365dataplan" if ($TenantLockBoxApproverGroup -and $TenantLockBoxApproverGroup -notlike "*@*") { Write-Warning -Message "Set-O365OrgGraphDataConnect - TenantLockBoxApproverGroup must be given in email format, and it must exists." return } if (-not $Force) { $CurrentSettings = Get-O365OrgGraphDataConnect -Headers $Headers if ($CurrentSettings) { $Body = @{ "ServiceEnabled" = $CurrentSettings.ServiceEnabled "TenantLockBoxApproverGroup" = $CurrentSettings.TenantLockBoxApproverGroup } if ($null -ne $ServiceEnabled) { $Body.ServiceEnabled = $ServiceEnabled } if ($TenantLockBoxApproverGroup) { $Body.TenantLockBoxApproverGroup = $TenantLockBoxApproverGroup } } } else { $Body = @{ "ServiceEnabled" = $ServiceEnabled "TenantLockBoxApproverGroup" = $TenantLockBoxApproverGroup } } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365OrgInstallationOptions { <# .SYNOPSIS Choose how often users get feature updates and the Microsoft apps that users can install on their own devices. .DESCRIPTION Choose how often users get feature updates and the Microsoft apps that users can install on their own devices. .PARAMETER Headers Parameter description .PARAMETER WindowsBranch Enable/Disable Windows .PARAMETER WindowsOffice Parameter description .PARAMETER WindowsSkypeForBusiness Parameter description .PARAMETER MacOffice Parameter description .PARAMETER MacSkypeForBusiness Parameter description .EXAMPLE An example .NOTES It takes a while for GUI to report these changes. Be patient. #> [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [string][ValidateSet('CurrentChannel', 'MonthlyEnterpriseChannel', 'SemiAnnualEnterpriseChannel')] $WindowsBranch, [nullable[bool]] $WindowsOffice, [nullable[bool]] $WindowsSkypeForBusiness, [nullable[bool]] $MacOffice, [nullable[bool]] $MacSkypeForBusiness ) $ReverseBranches = @{ "CurrentChannel" = 1 "MonthlyEnterpriseChannel" = 3 "SemiAnnualEnterpriseChannel" = 2 } $Uri = "https://admin.microsoft.com/admin/api/settings/apps/usersoftware" $CurrentSettings = Get-O365OrgInstallationOptions -NoTranslation -Headers $Headers if ($CurrentSettings) { $Body = @{ UserSoftwareSettings = $CurrentSettings } if ($WindowsBranch) { $Body.UserSoftwareSettings[0].Branch = $ReverseBranches[$WindowsBranch] # we probably should update "BranchLastUpdateTime": "2021-09-02T21:54:02.953Z", # but I am not sure if it matters } if ($null -ne $WindowsOffice) { $Body.UserSoftwareSettings[0].ServiceStatusMap.'Office (includes Skype for Business),MicrosoftOffice_ClientDownload' = $WindowsOffice } if ($null -ne $WindowsSkypeForBusiness) { $Body.UserSoftwareSettings[0].ServiceStatusMap.'Skype for Business (Standalone),MicrosoftCommunicationsOnline' = $WindowsSkypeForBusiness } if ($null -ne $MacOffice) { $Body.UserSoftwareSettings[1].ServiceStatusMap.'Office,MicrosoftOffice_ClientDownload' = $MacOffice } if ($null -ne $MacSkypeForBusiness) { $Body.UserSoftwareSettings[1].LegacyServiceStatusMap.'Skype for Business (X EI Capitan 10.11 or higher),MicrosoftCommunicationsOnline' = $MacSkypeForBusiness } $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-O365OrgMicrosoftTeams { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][bool] $AllowCalendarSharing ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/skypeteams" $Body = Get-O365OrgMicrosoftTeams -Headers $Headers # It seems every time you check https://admin.microsoft.com/#/Settings/Services/:/Settings/L1/SkypeTeams # and you enable just 1 or two settings you need to reapply everything! so i'll # leave it for now - as it needs more investigation # $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body # $Output } function Set-O365OrgModernAuthentication { <# .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-O365OrgModernAuthentication -AllowBasicAuthImap $true -AllowBasicAuthPop $true -WhatIf .EXAMPLE Set-O365OrgModernAuthentication -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-O365OrgModernAuthentication -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-O365OrgMyAnalytics { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $EnableInsightsDashboard, [nullable[bool]] $EnableWeeklyDigest, [nullable[bool]] $EnableInsightsOutlookAddIn ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/myanalytics" $CurrentSettings = Get-O365OrgMyAnalytics -Headers $Headers if ($CurrentSettings) { $Body = @{ value = @{ IsDashboardOptedOut = $CurrentSettings.EnableInsightsDashboard IsEmailOptedOut = $CurrentSettings.EnableWeeklyDigest IsAddInOptedOut = $CurrentSettings.EnableInsightsOutlookAddIn } } if ($null -ne $EnableInsightsDashboard) { $Body.value.IsDashboardOptedOut = -not $EnableInsightsDashboard } if ($null -ne $EnableWeeklyDigest) { $Body.value.IsEmailOptedOut = -not $EnableWeeklyDigest } if ($null -ne $EnableInsightsOutlookAddIn) { $Body.value.IsAddInOptedOut = -not $EnableInsightsOutlookAddIn } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } } function Set-O365OrgNews { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $ContentOnNewTabEnabled, [nullable[bool]] $CompanyInformationAndIndustryEnabled ) $Uri = "https://admin.microsoft.com/admin/api/searchadminapi/news/options" $CurrentSettings = Get-O365OrgNews -Headers $Headers -NoTranslation if ($CurrentSettings) { $Body = [ordered] @{ ServiceType = 'Bing' NewsOptions = $CurrentSettings.NewsOptions } if ($null -ne $ContentOnNewTabEnabled) { $Body.NewsOptions.EdgeNTPOptions.IsOfficeContentEnabled = $ContentOnNewTabEnabled } if ($null -ne $CompanyInformationAndIndustryEnabled) { $Body.NewsOptions.EdgeNTPOptions.IsShowCompanyAndIndustry = $CompanyInformationAndIndustryEnabled } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PUT -Body $Body $Output } } function Set-O365OrgOfficeOnTheWeb { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][bool] $Enabled ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/officeonline" $Body = @{ Enabled = $Enabled } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365OrgOrganizationInformation { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [string] $Name, [string] $StreetAddress, [string] $ApartmentOrSuite, [string] $City, [string] $State, [string] $PostalCode, #[string] $Country, #[string] $CountryCode, #[string] $PossibleStatesOrProvinces, [string] $PhoneNumber, [string] $TechnicalContactEmail ) $Uri = "https://admin.microsoft.com/admin/api/Settings/company/profile" $CurrentSettings = Get-O365OrgOrganizationInformation -Headers $Headers if ($CurrentSettings) { $Body = @{ Name = $CurrentSettings.Name ## : Evotec Address1 = $CurrentSettings.Address1 ## : Address2 = $CurrentSettings.Address2 ## : #Address3 = $CurrentSettings.Address3 ## : #Address4 = $CurrentSettings.Address4 ## : City = $CurrentSettings.City ## : KATOWICE State = $CurrentSettings.State ## : Śląskie PostalCode = $CurrentSettings.PostalCode ## : 40- Country = $CurrentSettings.Country ## : Poland #CountryCode = $CurrentSettings.CountryCode ## : PL #PossibleStatesOrProvinces = $CurrentSettings.PossibleStatesOrProvinces ## : PhoneNumber = $CurrentSettings.PhoneNumber ## : +4 TechnicalContactEmail = $CurrentSettings.TechnicalContactEmail ## : p #DefaultDomain = $CurrentSettings.DefaultDomain ## : Language = $CurrentSettings.Language ## : en #MSPPID = $CurrentSettings.MSPPID ## : #SupportUrl = $CurrentSettings.SupportUrl ## : #SupportEmail = $CurrentSettings.SupportEmail ## : #SupportPhone = $CurrentSettings.SupportPhone ## : SupportedLanguages = $CurrentSettings.SupportedLanguages ## : {@{ID=en; Name=English; Default=True; DefaultCulture=en-US; PluralFormRules=IsOne}, @{ID=pl; Name=polski; Default=False; DefaultCulture=pl-PL; PluralFormRules=IsOne,EndsInTwoThruFourNotTweleveThruFourteen}} } if ($PSBoundParameters.ContainsKey('Name')) { $Body.Name = $Name } if ($PSBoundParameters.ContainsKey('StreetAddress')) { $Body.Address1 = $StreetAddress } if ($PSBoundParameters.ContainsKey('ApartmentOrSuite')) { $Body.Address2 = $ApartmentOrSuite } if ($PSBoundParameters.ContainsKey('City')) { $Body.City = $City } if ($PSBoundParameters.ContainsKey('State')) { $Body.State = $State } if ($PSBoundParameters.ContainsKey('PostalCode')) { $Body.PostalCode = $PostalCode } #if ($PSBoundParameters.ContainsKey('Country')) { # $Body.Country = $Country #} #if ($PSBoundParameters.ContainsKey('CountryCode')) { # $Body.CountryCode = $CountryCode #} if ($PSBoundParameters.ContainsKey('PhoneNumber')) { $Body.PhoneNumber = $PhoneNumber } if ($PSBoundParameters.ContainsKey('TechnicalContactEmail')) { $Body.TechnicalContactEmail = $TechnicalContactEmail } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } } function Set-O365OrgPasswordExpirationPolicy { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter()][nullable[bool]] $PasswordNeverExpires, [Parameter()][nullable[int]] $DaysBeforePasswordExpires, [Parameter()][nullable[int]] $DaysBeforeUserNotified ) $Uri = "https://admin.microsoft.com/admin/api/Settings/security/passwordpolicy" $CurrentSettings = Get-O365OrgPasswordExpirationPolicy -Headers $Headers -NoTranslation if ($CurrentSettings) { $Body = @{ ValidityPeriod = $CurrentSettings.ValidityPeriod #: 90 NotificationDays = $CurrentSettings.NotificationDays #: 14 NeverExpire = $CurrentSettings.NeverExpire #: True } if ($null -ne $DaysBeforeUserNotified) { $Body.NotificationDays = $DaysBeforeUserNotified } if ($null -ne $DaysBeforePasswordExpires) { $Body.ValidityPeriod = $DaysBeforePasswordExpires } if ($null -ne $PasswordNeverExpires) { $Body.NeverExpire = $PasswordNeverExpires } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } } function Set-O365OrgPlanner { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][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-O365OrgPrivacyProfile { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter()][uri] $PrivacyUrl, [parameter()][string] $PrivacyContact ) $Uri = "https://admin.microsoft.com/admin/api/Settings/security/privacypolicy" $Body = @{ PrivacyStatement = $PrivacyUrl PrivacyContact = $PrivacyContact } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365OrgPrivilegedAccess { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $TenantLockBoxEnabled, [string] $AdminGroup ) $Uri = "https://admin.microsoft.com/admin/api/Settings/security/tenantLockbox" $Body = @{ EnabledTenantLockbox = $TenantLockBoxEnabled AdminGroup = $AdminGroup Identity = $null } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365OrgProject { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $RoadmapEnabled, [nullable[bool]] $ProjectForTheWebEnabled ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/projectonline" $CurrentSettings = Get-O365OrgProject -Headers $Headers -NoTranslation if ($CurrentSettings) { $Body = @{ IsRoadmapEnabled = $CurrentSettings.IsRoadmapEnabled #: True IsModProjEnabled = $CurrentSettings.IsModProjEnabled #: True RoadmapAvailabilityError = $CurrentSettings.RoadmapAvailabilityError #: 0 ModProjAvailabilityStatus = $CurrentSettings.ModProjAvailabilityStatus #: 0 } if ($null -ne $RoadmapEnabled) { $Body.IsRoadmapEnabled = $RoadmapEnabled } if ($null -ne $ProjectForTheWebEnabled) { $Body.IsModProjEnabled = $ProjectForTheWebEnabled } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } } function Set-O365OrgReleasePreferences { [cmdletbinding()] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][ValidateSet('FirstRelease', 'StagedRollout', 'None')] $ReleaseTrack ) $Uri = 'https://admin.microsoft.com/admin/api/Settings/company/releasetrack' $Body = [ordered] @{ ReleaseTrack = $ReleaseTrack ShowCompass = $false } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365OrgReports { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter()][nullable[bool]] $PrivacyEnabled, [Parameter()][nullable[bool]] $PowerBiEnabled ) $Uri = "https://admin.microsoft.com/admin/api/reports/config/SetTenantConfiguration" $Body = @{ PrivacyEnabled = $PrivacyEnabled PowerBiEnabled = $PowerBiEnabled } Remove-EmptyValue -Hashtable $Body $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365OrgScripts { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter()][string][ValidateSet('Disabled', 'Everyone', 'SpecificGroup')] $LetUsersAutomateTheirTasks, [Parameter()][string] $LetUsersAutomateTheirTasksGroup, [Parameter()][string] $LetUsersAutomateTheirTasksGroupID, [Parameter()][string][ValidateSet('Disabled', 'Everyone', 'SpecificGroup')] $LetUsersShareTheirScripts, [Parameter()][string] $LetUsersShareTheirScriptsGroup, [Parameter()][string] $LetUsersShareTheirScriptsGroupID, [Parameter()][string][ValidateSet('Disabled', 'Everyone', 'SpecificGroup')] $LetUsersRunScriptPowerAutomate, [Parameter()][string] $LetUsersRunScriptPowerAutomateGroup, [Parameter()][string] $LetUsersRunScriptPowerAutomateGroupID ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/officescripts" $Body = [ordered] @{} if ($LetUsersAutomateTheirTasks -eq 'Disabled') { # if the user wants to disable the LetUsersAutomateTheirTasks, then we need to disable all other options as well $Body.EnabledOption = 0 $Body.ShareOption = 0 $Body.UnattendedOption = 0 } else { if ($LetUsersAutomateTheirTasks -or $LetUsersAutomateTheirTasksGroup -or $LetUsersAutomateTheirTasksGroupID) { # We check for the presence of option, but also if the user just provided a group name or ID we then assume the user wants specific group if ($LetUsersAutomateTheirTasks -eq 'SpecificGroup' -or $LetUsersAutomateTheirTasksGroup -or $LetUsersAutomateTheirTasksGroupID) { if ($LetUsersAutomateTheirTasksGroup) { # we find the id of the group from the name $Group = Get-O365Group -DisplayName $LetUsersAutomateTheirTasksGroup -Headers $Headers if ($Group.Id) { $Body.EnabledOption = 2 $Body.EnabledGroup = $Group.Id } else { Write-Warning -Message "Set-O365Scripts - LetUsersAutomateTheirTasksGroup couldn't be translated to ID. Skipping." return } } elseif ($LetUsersAutomateTheirTasksGroupID) { # we use direct ID $Body.EnabledOption = 2 $Body.EnabledGroup = $LetUsersAutomateTheirTasksGroupID } else { Write-Warning -Message "Set-O365Scripts - LetUsersAutomateTheirTasksGroup/LetUsersAutomateTheirTasksGroupID not provided. Please provide group." return } } elseif ($LetUsersAutomateTheirTasks -eq 'Everyone') { $Body.EnabledOption = 1 } elseif ($LetUsersAutomateTheirTasks -eq 'Disabled') { $Body.EnabledOption = 0 } } if ($LetUsersShareTheirScripts -or $LetUsersShareTheirScriptsGroup -or $LetUsersShareTheirScriptsGroupID) { # We check for the presence of option, but also if the user just provided a group name or ID we then assume the user wants specific group if ($LetUsersShareTheirScripts -eq 'SpecificGroup' -or $LetUsersShareTheirScriptsGroup -or $LetUsersShareTheirScriptsGroupID) { if ($LetUsersShareTheirScriptsGroup) { # we find the id of the group from the name $Group = Get-O365Group -DisplayName $LetUsersShareTheirScriptsGroup -Headers $Headers if ($Group.Id) { $Body.ShareOption = 2 $Body.ShareGroup = $Group.Id } else { Write-Warning -Message "Set-O365Scripts - LetUsersAutomateTheirTasksGroup couldn't be translated to ID. Skipping." return } } elseif ($LetUsersShareTheirScriptsGroupID) { # we use direct ID $Body.ShareOption = 2 $Body.ShareGroup = $LetUsersShareTheirScriptsGroupID } else { Write-Warning -Message "Set-O365Scripts - LetUsersShareTheirScriptsGroup/LetUsersShareTheirScriptsGroupID not provided. Please provide group." return } } elseif ($LetUsersShareTheirScripts -eq 'Everyone') { $Body.ShareOption = 1 } elseif ($LetUsersShareTheirScripts -eq 'Disabled') { $Body.ShareOption = 0 } } if ($LetUsersRunScriptPowerAutomate -or $LetUsersRunScriptPowerAutomateGroup -or $LetUsersRunScriptPowerAutomateGroupID) { # We check for the presence of option, but also if the user just provided a group name or ID we then assume the user wants specific group if ($LetUsersRunScriptPowerAutomate -eq 'SpecificGroup' -or $LetUsersRunScriptPowerAutomateGroup -or $LetUsersRunScriptPowerAutomateGroupID) { if ($LetUsersRunScriptPowerAutomateGroup) { # we find the id of the group from the name $Group = Get-O365Group -DisplayName $LetUsersRunScriptPowerAutomateGroup -Headers $Headers if ($Group.Id) { $Body.UnattendedOption = 2 $Body.UnattendedGroup = $Group.Id } else { Write-Warning -Message "Set-O365Scripts - LetUsersRunScriptPowerAutomateGroup couldn't be translated to ID. Skipping." return } } elseif ($LetUsersRunScriptPowerAutomateGroupID) { # we use direct ID $Body.UnattendedOption = 2 $Body.UnattendedGroup = $LetUsersRunScriptPowerAutomateGroupID } else { Write-Warning -Message "Set-O365Scripts - LetUsersShareTheirScriptsGroup/LetUsersRunScriptPowerAutomateGroupID not provided. Please provide group." return } } elseif ($LetUsersRunScriptPowerAutomateGroup -eq 'Everyone') { $Body.UnattendedOption = 1 } elseif ($LetUsersRunScriptPowerAutomateGroup -eq 'Disabled') { $Body.UnattendedOption = 0 } } } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } function Set-O365OrgSharePoint { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][ValidateSet('OnlyPeopleInYourOrganization', 'ExistingGuestsOnly', 'NewAndExistingGuestsOnly', 'Anyone')][string] $CollaborationType ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/sitessharing" $ReverseTranslateCollaboration = @{ 'NewAndExistingGuestsOnly' = 2 'Anyone' = 16 'ExistingGuestsOnly' = 32 'OnlyPeopleInYourOrganization' = 1 } $Body = @{ AllowSharing = if ($CollaborationType -eq 'OnlyPeopleInYourOrganization') { $false } else { $true } CollaborationType = $ReverseTranslateCollaboration[$CollaborationType] } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365OrgSharing { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [Parameter(Mandatory)][bool] $LetUsersAddNewGuests ) $Uri = "https://admin.microsoft.com/admin/api/settings/security/guestUserPolicy" $Body = @{ AllowGuestInvitations = $LetUsersAddNewGuests } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365OrgSway { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $ExternalSharingEnabled, [nullable[bool]] $PeoplePickerSearchEnabled, [nullable[bool]] $FlickrEnabled, [nullable[bool]] $PickitEnabled, [nullable[bool]] $WikipediaEnabled, [nullable[bool]] $YouTubeEnabled ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/Sway" $CurrentSettings = Get-O365OrgSway -Headers $Headers if ($CurrentSettings) { $Body = [ordered] @{ ExternalSharingEnabled = $CurrentSettings.ExternalSharingEnabled # : True PeoplePickerSearchEnabled = $CurrentSettings.PeoplePickerSearchEnabled # : True FlickrEnabled = $CurrentSettings.FlickrEnabled # : True PickitEnabled = $CurrentSettings.PickitEnabled # : True WikipediaEnabled = $CurrentSettings.WikipediaEnabled # : True YouTubeEnabled = $CurrentSettings.YouTubeEnabled # : True } if ($null -ne $ExternalSharingEnabled) { $Body.ExternalSharingEnabled = $ExternalSharingEnabled } if ($null -ne $FlickrEnabled) { $Body.FlickrEnabled = $FlickrEnabled } if ($null -ne $PickitEnabled) { $Body.PickitEnabled = $PickitEnabled } if ($null -ne $WikipediaEnabled) { $Body.WikipediaEnabled = $WikipediaEnabled } if ($null -ne $YouTubeEnabled) { $Body.YouTubeEnabled = $YouTubeEnabled } if ($null -ne $PeoplePickerSearchEnabled) { $Body.PeoplePickerSearchEnabled = $PeoplePickerSearchEnabled } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } } function Set-O365OrgTodo { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $ExternalJoinEnabled, [nullable[bool]] $PushNotificationEnabled, [nullable[bool]] $ExternalShareEnabled ) $Uri = "https://admin.microsoft.com/admin/api/services/apps/todo" $CurrentSettings = Get-O365OrgToDo -Headers $Headers if ($CurrentSettings) { $Body = @{ IsExternalJoinEnabled = $CurrentSettings.IsExternalJoinEnabled IsPushNotificationEnabled = $CurrentSettings.IsPushNotificationEnabled IsExternalShareEnabled = $CurrentSettings.IsExternalShareEnabled } if ($null -ne $ExternalJoinEnabled) { $Body.IsExternalJoinEnabled = $ExternalJoinEnabled } if ($null -ne $PushNotificationEnabled) { $Body.IsPushNotificationEnabled = $PushNotificationEnabled } if ($null -ne $ExternalShareEnabled) { $Body.IsExternalShareEnabled = $ExternalShareEnabled } $Output = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body $Output } } function Set-O365OrgUserConsentApps { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [parameter(Mandatory)][bool] $UserConsentToAppsEnabled ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/IntegratedApps" $Body = @{ Enabled = $UserConsentToAppsEnabled } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } function Set-O365OrgUserOwnedApps { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $LetUsersAccessOfficeStore, [nullable[bool]] $LetUsersStartTrials, [nullable[bool]] $LetUsersAutoClaimLicenses ) if ($null -ne $LetUsersAccessOfficeStore) { $Uri = "https://admin.microsoft.com/admin/api/settings/apps/store" $Body = @{ Enabled = $LetUsersAccessOfficeStore } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } if ($null -ne $LetUsersStartTrials) { $TrialState = $LetUsersStartTrials.ToString().ToLower() $Uri = "https://admin.microsoft.com/admin/api/storesettings/iwpurchase/$TrialState" $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method PUT #-Body $Body } if ($null -ne $LetUsersAutoClaimLicenses) { $Uri = "https://admin.microsoft.com/fd/m365licensing/v1/policies/autoclaim" $Body = @{ policyValue = if ($LetUsersAutoClaimLicenses -eq $true) { 'Enabled' } else { 'Disabled' } } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } } function Set-O365OrgWhiteboard { [cmdletbinding(SupportsShouldProcess)] param( [alias('Authorization')][System.Collections.IDictionary] $Headers, [nullable[bool]] $WhiteboardEnabled, [ValidateSet('Neither', 'Required', 'Optional')]$DiagnosticData, [nullable[bool]] $OptionalConnectedExperiences, [nullable[bool]] $BoardSharingEnabled, [nullable[bool]] $OneDriveStorageEnabled ) $Uri = "https://admin.microsoft.com/admin/api/settings/apps/whiteboard" $CurrentSettings = Get-O365OrgWhiteboard -Headers $Headers -NoTranslation $Body = [ordered] @{ IsEnabled = $CurrentSettings.IsEnabled # : True IsClaimEnabled = $CurrentSettings.IsClaimEnabled #: True IsSharePointDefault = $CurrentSettings.IsSharePointDefault #: False # This always seems to be 0, but i'll let it read it from Get-O365OrgWhiteboard NonTenantAccess = $CurrentSettings.NonTenantAccess #: 0 TelemetryPolicy = $CurrentSettings.TelemetryPolicy #: 2 AreConnectedServicesEnabled = $CurrentSettings.AreConnectedServicesEnabled #: True } if ($null -ne $WhiteboardEnabled) { $Body.IsEnabled = $WhiteboardEnabled } if ($DiagnosticData) { $ReverseTranslateTelemetry = @{ 'Neither' = 0 'Required' = 1 'Optional' = 2 } $Body.TelemetryPolicy = $ReverseTranslateTelemetry[$DiagnosticData] } if ($null -ne $OptionalConnectedExperiences) { $Body.AreConnectedServicesEnabled = $OptionalConnectedExperiences } if ($null -ne $BoardSharingEnabled) { $Body.IsClaimEnabled = $BoardSharingEnabled } if ($null -ne $OneDriveStorageEnabled) { $Body.IsSharePointDefault = $OneDriveStorageEnabled } $null = Invoke-O365Admin -Uri $Uri -Headers $Headers -Method POST -Body $Body } 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', 'ConvertFrom-JSONWebToken', 'Get-O365AzureADConnect', 'Get-O365AzureADConnectPTA', 'Get-O365AzureADConnectSSO', 'Get-O365AzureADRoles', 'Get-O365AzureADRolesMember', 'Get-O365AzureEnterpriseAppsGroupConsent', 'Get-O365AzureEnterpriseAppsUserConsent', 'Get-O365AzureEnterpriseAppsUserSettings', 'Get-O365AzureEnterpriseAppsUserSettingsAdmin', 'Get-O365AzureEnterpriseAppsUserSettingsPromoted', 'Get-O365AzureExternalCollaborationFlows', 'Get-O365AzureExternalCollaborationSettings', 'Get-O365AzureExternalIdentitiesEmail', 'Get-O365AzureExternalIdentitiesPolicies', 'Get-O365AzureGroupExpiration', 'Get-O365AzureLicenses', 'Get-O365AzureMultiFactorAuthentication', 'Get-O365AzureUserSettings', 'Get-O365BillingAccounts', 'Get-O365BillingInvoices', 'Get-O365BillingLicenseAutoClaim', 'Get-O365BillingLicenseRequests', 'Get-O365BillingNotifications', 'Get-O365BillingNotificationsList', 'Get-O365BillingPaymentMethods', 'Get-O365BillingProfile', 'Get-O365BillingSubscriptions', 'Get-O365ConsiergeAll', 'Get-O365DirectorySync', 'Get-O365DirectorySyncErrors', 'Get-O365DirectorySyncManagement', 'Get-O365Domain', 'Get-O365DomainDependencies', 'Get-O365DomainHealth', 'Get-O365DomainRecords', 'Get-O365DomainTroubleshooting', 'Get-O365Group', 'Get-O365GroupAdministrativeUnit', 'Get-O365GroupLicenses', 'Get-O365GroupMember', 'Get-O365OrgAzureSpeechServices', 'Get-O365OrgBingDataCollection', 'Get-O365OrgBookings', 'Get-O365OrgBriefingEmail', 'Get-O365OrgCalendarSharing', 'Get-O365OrgCommunicationToUsers', 'Get-O365OrgCompanyInformation', 'Get-O365OrgCortana', 'Get-O365OrgCustomerLockbox', 'Get-O365OrgCustomThemes', 'Get-O365OrgDataLocation', 'Get-O365OrgDynamics365ConnectionGraph', 'Get-O365OrgDynamics365CustomerVoice', 'Get-O365OrgDynamics365SalesInsights', 'Get-O365OrgForms', 'Get-O365OrgGraphDataConnect', 'Get-O365OrgHelpdeskInformation', 'Get-O365OrgInstallationOptions', 'Get-O365OrgLicensesAutoClaim', 'Get-O365OrgM365Groups', 'Get-O365OrgMicrosoftSearch', 'Get-O365OrgMicrosoftTeams', 'Get-O365OrgModernAuthentication', 'Get-O365OrgMyAnalytics', 'Get-O365OrgNews', 'Get-O365OrgOfficeOnTheWeb', 'Get-O365OrgOfficeProductivity', 'Get-O365OrgOrganizationInformation', 'Get-O365OrgPasswordExpirationPolicy', 'Get-O365OrgPlanner', 'Get-O365OrgPrivacyProfile', 'Get-O365OrgPrivilegedAccess', 'Get-O365OrgProject', 'Get-O365OrgReleasePreferences', 'Get-O365OrgReports', 'Get-O365OrgScripts', 'Get-O365OrgSharePoint', 'Get-O365OrgSharing', 'Get-O365OrgSway', 'Get-O365OrgToDo', 'Get-O365OrgUserConsentApps', 'Get-O365OrgUserOwnedApps', 'Get-O365OrgWhiteboard', 'Get-O365PartnerRelationship', 'Get-O365PasswordReset', 'Get-O365PasswordResetIntegration', 'Get-O365SearchIntelligenceBingConfigurations', 'Get-O365SearchIntelligenceItemInsights', 'Get-O365SearchIntelligenceMeetingInsights', 'Get-O365ServicePrincipal', 'Get-O365TenantID', 'Get-O365User', 'Invoke-O365Admin', 'New-O365License', 'Set-O365AzureEnterpriseAppsGroupConsent', 'Set-O365AzureEnterpriseAppsUserConsent', 'Set-O365AzureEnterpriseAppsUserSettings', 'Set-O365AzureEnterpriseAppsUserSettingsAdmin', 'Set-O365AzureExternalCollaborationSettings', 'Set-O365AzureGroupExpiration', 'Set-O365AzureMultiFactorAuthentication', 'Set-O365AzureUserSettings', 'Set-O365BillingNotifications', 'Set-O365GroupLicenses', 'Set-O365OrgAzureSpeechServices', 'Set-O365OrgBingDataCollection', 'Set-O365OrgBookings', 'Set-O365OrgBriefingEmail', 'Set-O365OrgCalendarSharing', 'Set-O365OrgCommunicationToUsers', 'Set-O365OrgCortana', 'Set-O365OrgCustomerLockbox', 'Set-O365OrgDynamics365ConnectionGraph', 'Set-O365OrgDynamics365SalesInsights', 'Set-O365OrgForms', 'Set-O365OrgGraphDataConnect', 'Set-O365OrgInstallationOptions', 'Set-O365OrgM365Groups', 'Set-O365OrgMicrosoftTeams', 'Set-O365OrgModernAuthentication', 'Set-O365OrgMyAnalytics', 'Set-O365OrgNews', 'Set-O365OrgOfficeOnTheWeb', 'Set-O365OrgOrganizationInformation', 'Set-O365OrgPasswordExpirationPolicy', 'Set-O365OrgPlanner', 'Set-O365OrgPrivacyProfile', 'Set-O365OrgPrivilegedAccess', 'Set-O365OrgProject', 'Set-O365OrgReleasePreferences', 'Set-O365OrgReports', 'Set-O365OrgScripts', 'Set-O365OrgSharePoint', 'Set-O365OrgSharing', 'Set-O365OrgSway', 'Set-O365OrgTodo', 'Set-O365OrgUserConsentApps', 'Set-O365OrgUserOwnedApps', 'Set-O365OrgWhiteboard', 'Set-O365PasswordReset', 'Set-O365PasswordResetIntegration') -Alias @() # SIG # Begin signature block # MIIdWQYJKoZIhvcNAQcCoIIdSjCCHUYCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUI8LDkMQdtUGI+/q6NHzOPuCW # JZ+gghhnMIIDtzCCAp+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 # CzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFA0es54yYNE9/2E7NOfj # 9VXBRDRxMA0GCSqGSIb3DQEBAQUABIIBAIrNtJFXzTsEgkoZQPBA+Ldyny/b/1qr # yFRN+el9HbX+NzRjaWZerG+kREes01iWckKbyuvUeE0jwKmK3ivux18RdCNRG+ex # GTurqPCkmHiYMMfGgkUscNexZQ94DjwxHTmeQ1XNZR+W9nDjvhpYdPKMTlpK8mZX # 8kSAlImAd5LxI39cez+8nnUquUT+CPfNghzEOvLFCKvbI1NrRv62qvd52CW+Yn/t # LXFlBBohkzisnP8v8pIZzXyVxSz4IDurq4EI5eh+dTU9qleIDl+w3YXkI6Cp2/BZ # ghfLXHm0eIzsiWU20Gq1fBKc/UivWrbBwtlBbUZxwS8C4I3yrE50J+2hggIwMIIC # LAYJKoZIhvcNAQkGMYICHTCCAhkCAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNV # BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G # A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQQIQ # DUJK4L46iP9gQCHOFADw3TANBglghkgBZQMEAgEFAKBpMBgGCSqGSIb3DQEJAzEL # BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTIxMDkxMDA5MzU0M1owLwYJKoZI # hvcNAQkEMSIEIMZBfNJ7nSJWTCR4RtmIE0ti4Pn+RlIzWqwdcEZ+6paSMA0GCSqG # SIb3DQEBAQUABIIBAE3CqA16unSN3zP+S2SoiBTmgl0uHFGUudWyj6bAI33Cu4jv # 6UT4zDQrwNqAdY+GqcvHjMescxCgKFkxy03N4oGMkbzsTU+X8rVkoE3WBUpRfydT # f+74KOsK4ZUn6ftvpOaVT3EQMT/1zYHLtvqwAaY9yc/o7qj7e9/xTH0zcsofrc7d # ACSAQpkX7eoFsUkPxKUFZPn6cICJWRARgEJS4Oe9geN8bTuhZ4xqxbKZaHGd1OXP # SLODzjk/nZtRyzdEhGG8nmEWvHLhYv0NVKU9t/VV/KkHbL+I7kLH1RYTabM5hWWG # dqF61Wzg99nJQtNz1Q67yOx0TylhBA7BDf1t3FA= # SIG # End signature block |