GraphAPI.ps1
# This script contains functions for Graph API at https://graph.windows.net # Office 365 / Azure AD v2, a.k.a. AzureAD module uses this API function Get-DynamicAbusableGroups { <# .SYNOPSIS Return Entra ID groups with dynamic membership rule that contains attributes that can be modified by users. Related articles: https://medium.com/r3d-buck3t/abusing-dynamic-groups-in-azuread-part-1-ff12e328c8c0 https://www.mnemonic.io/resources/blog/abusing-dynamic-groups-in-azure-ad-for-privilege-escalation/ .DESCRIPTION Return Entra ID groups with dynamic membership rule that contains attributes that can be modified by users using the given Access Token .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token .Example PS C:\>Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Get-AADIntDynamicAbusableGroups abusableRule groupId ------------ ------- (user.userType -eq "Member") -or (user.city -eq "Redmond") 69d8fc52-d45e-47a2-972a-6c99e057ead1 #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" $abusableCondsUser = @("ageGroup","jobTitle","city","givenName","displayName","companyName", "country","department","employeeType","mailNickname","mail","state") $results=Call-GraphAPI -AccessToken $AccessToken -Command groups $dynamicGroups = $results | Where-Object groupTypes -contains "DynamicMembership" $userReg = 'user\.(.+?)\s' $abusableGroupsOutput = @{} foreach($dynamicGroup in $dynamicGroups){ $abusable = $false $groupId = $dynamicGroup.objectId $groupTempList = @() $userMatches = $dynamicGroup.membershipRule | Select-String -Pattern $userReg -AllMatches foreach($userMatch in $userMatches.Matches) { $matchType = $userMatch.Groups[1] if($abusableCondsUser.Contains($matchType.value)) { $abusable = $true } } if($abusable) { $abusableGroupsOutput.Add($groupId,$dynamicGroup.membershipRule) } } $abusableGroupsOutput.keys | % { New-object psobject -Property @{ 'groupId' = $_ 'abusableRule' = $abusableGroupsOutput[$_] } } return $abusableGroupsOutput } } function Get-AADUsers { [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken, [Parameter(Mandatory=$False)] [String]$SearchString, [Parameter(Mandatory=$False)] [String]$UserPrincipalName ) Process { if(![string]::IsNullOrEmpty($SearchString)) { $queryString="`$filter=(startswith(displayName,'$SearchString') or startswith(userPrincipalName,'$SearchString'))" } elseif(![string]::IsNullOrEmpty($UserPrincipalName)) { $queryString="`$filter=userPrincipalName eq '$UserPrincipalName'" } $results=Call-GraphAPI -AccessToken $AccessToken -Command users -QueryString $queryString return $results } } # Gets the tenant details function Get-TenantDetails { <# .SYNOPSIS Extract tenant details using the given Access Token .DESCRIPTION Extract tenant details using the given Access Token .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Example PS C:\>$token=Get-AADIntAccessTokenForAADGraph PS C:\>Get-AADIntTenantDetails -AccessToken $token #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" # Call the API $response=Call-GraphAPI -AccessToken $AccessToken -Command tenantDetails # Verbose Write-Verbose "TENANT INFORMATION: $($response.value | Out-String)" # Return $response } } # Gets the tenant devices # Jun 24th 2020 function Get-Devices { <# .SYNOPSIS Extracts tenant devices using the given Access Token .DESCRIPTION Extracts tenant devices using the given Access Token .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Example PS C:\>$token=Get-AADIntAccessTokenForAADGraph PS C:\>Get-AADIntDevices -AccessToken $token #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" # Call the API $response=Call-GraphAPI -AccessToken $AccessToken -Command devices -QueryString "`$expand=registeredOwner" # Return $response } } # Gets detailed information about the given user # Jun 24th 2020 function Get-UserDetails { <# .SYNOPSIS Extracts detailed information of the given user .DESCRIPTION Extracts detailed information of the given user .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Parameter UserPrincipalName The user principal name of the user whose details is to be extracted .Example PS C:\>$token=Get-AADIntAccessTokenForAADGraph PS C:\>Get-AADIntUserDetails -AccessToken $token odata.type : Microsoft.DirectoryServices.User objectType : User objectId : cd5676ad-ba80-4782-bdcb-ff5de37fc347 deletionTimestamp : acceptedAs : acceptedOn : accountEnabled : True ageGroup : alternativeSecurityIds : {} signInNames : {user@company.com} signInNamesInfo : {} appMetadata : assignedLicenses : {@{disabledPlans=System.Object[]; skuId=c7df2760-2c81-4ef7-b578-5b5392b571df}, @{disabledPlans=System.Object[]; skuId=b05e124f-c7cc-45a0-a6aa-8cf78c946968}} assignedPlans : {@{assignedTimestamp=2019-12-02T07:41:59Z; capabilityStatus=Enabled; service=MultiFactorService; servicePlanId=8a256a2b-b617-496d-b51b-e76466e88db0}, @{assignedTimestamp=2019-12-02T07 :41:59Z; capabilityStatus=Enabled; service=exchange; servicePlanId=34c0d7a0-a70f-4668-9238-47f9fc208882}, @{assignedTimestamp=2019-12-02T07:41:59Z; capabilityStatus=Enabled; service=P owerBI; servicePlanId=70d33638-9c74-4d01-bfd3-562de28bd4ba}, @{assignedTimestamp=2019-12-02T07:41:59Z; capabilityStatus=Enabled; service=WhiteboardServices; servicePlanId=4a51bca5-1ef f-43f5-878c-177680f191af}...} city : cloudAudioConferencingProviderInfo : <acpList> <acpInformation default="true"> <tollNumber>18728886261</tollNumber> <participantPassCode>0</participantPassCode> <domain>resources.lync.com</domain> <name>Microsoft</name> <url>https://dialin.lync.com/c73270cd-afd0-4f70-8328-747f36508d85</url> </acpInformation> </acpList> cloudMSExchRecipientDisplayType : 1073741824 cloudMSRtcIsSipEnabled : True cloudMSRtcOwnerUrn : ... #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken, [Parameter(Mandatory=$True)] [String]$UserPrincipalName ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" # Url encode for external users, replace # with %23 $UserPrincipalName = $UserPrincipalName.Replace("#","%23") # Call the API $response=Call-GraphAPI -AccessToken $AccessToken -Command "users/$UserPrincipalName" # Return $response } } # Gets tenant's Azure AD settings # Jun 24th 2020 function Get-Settings { <# .SYNOPSIS Extracts Azure AD settings .DESCRIPTION Extracts Azure AD settings .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Example PS C:\>$token=Get-AADIntAccessTokenForAADGraph PS C:\>Get-AADIntSettings -AccessToken $token id displayName templateId values -- ----------- ---------- ------ 8b16b029-bb31-48c8-b4df-5ee419596688 Password Rule Settings 5cf42378-d67d-4f36-ba46-e8b86229381d {@{name=BannedPasswordCheckOnPremisesMode; value=Audit}, @{name=EnableBannedPasswordCheckOnPremises; value=True}, @{name=En... #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" # Call the API $response=Call-GraphAPI -AccessToken $AccessToken -Command "settings" # Return $response } } # Gets tenant's OAuth grants # Jun 24th 2020 function Get-OAuthGrants { <# .SYNOPSIS Extracts Azure AD OAuth grants .DESCRIPTION Extracts Azure AD OAuth grants .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Example PS C:\>$token=Get-AADIntAccessTokenForAADGraph PS C:\>Get-AADIntOAuthGrants -AccessToken $token id displayName templateId values -- ----------- ---------- ------ 8b16b029-bb31-48c8-b4df-5ee419596688 Password Rule Settings 5cf42378-d67d-4f36-ba46-e8b86229381d {@{name=BannedPasswordCheckOnPremisesMode; value=Audit}, @{name=EnableBannedPasswordCheckOnPremises; value=True}, @{name=En... #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" # Call the API $response=Call-GraphAPI -AccessToken $AccessToken -Command "oauth2PermissionGrants" # Return $response } } # Gets tenant's service principals # Jun 24th 2020 function Get-ServicePrincipals { <# .SYNOPSIS Extracts Azure AD service principals .DESCRIPTION Extracts Azure AD service principals. If client id(s) are provided, show detailed information. .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Parameter ClientIds List of client ids to get detailed information. .Example PS C:\>Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Get-AADIntServicePrincipals AccountEnabled : true Addresses : AppPrincipalId : d32c68ad-72d2-4acb-a0c7-46bb2cf93873 DisplayName : Microsoft Activity Feed Service ObjectId : 321e7bdd-d7b0-4a64-8eb3-38c259c1304a ServicePrincipalNames : ServicePrincipalNames TrustedForDelegation : false AccountEnabled : true Addresses : Addresses AppPrincipalId : 0000000c-0000-0000-c000-000000000000 DisplayName : Microsoft App Access Panel ObjectId : a9e03f2f-4471-41f2-96c5-589d5d7117bc ServicePrincipalNames : ServicePrincipalNames TrustedForDelegation : false AccountEnabled : true Addresses : AppPrincipalId : dee7ba80-6a55-4f3b-a86c-746a9231ae49 DisplayName : Microsoft AppPlat EMA ObjectId : ae0b81fc-c521-4bfd-9eaa-04c520b4b5fd ServicePrincipalNames : ServicePrincipalNames TrustedForDelegation : false AccountEnabled : true Addresses : Addresses AppPrincipalId : 65d91a3d-ab74-42e6-8a2f-0add61688c74 DisplayName : Microsoft Approval Management ObjectId : d8ec5b95-e5f6-416e-8e7c-c6c52ec5a11f ServicePrincipalNames : ServicePrincipalNames TrustedForDelegation : false #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken, [Parameter(Mandatory=$False)] [String[]]$ClientIds ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" # If client id(s) are provided, get only those (with extra information) if($ClientIds) { $body = @{ "appIds" = $ClientIds } # Call the API Call-GraphAPI -AccessToken $AccessToken -Command "getServicePrincipalsByAppIds" -Body ($body | ConvertTo-Json) -Method Post -QueryString "`$Select=" } else { # Call the Provisioning API Get-ServicePrincipals2 -AccessToken $AccessToken } } } # Gets tenant's conditional access policies # Apr 8th 2021 function Get-ConditionalAccessPolicies { <# .SYNOPSIS Shows conditional access policies. .DESCRIPTION Shows conditional access policies. .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Example PS C:\>Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Get-AADIntConditionalAccessPolicies odata.type : Microsoft.DirectoryServices.Policy objectType : Policy objectId : 1a6a3b84-7d6d-4398-9c26-50fab315be8b deletionTimestamp : displayName : Default Policy keyCredentials : {} policyType : 18 policyDetail : {{"Version":0,"State":"Disabled"}} policyIdentifier : 2022-11-18T00:16:20.2379877Z tenantDefaultPolicy : 18 odata.type : Microsoft.DirectoryServices.Policy objectType : Policy objectId : 7f6ac8e5-bd21-4091-ae4c-0e48e0f4db04 deletionTimestamp : displayName : Block NestorW keyCredentials : {} policyType : 18 policyDetail : {{"Version":1,"CreatedDateTime":"2022-11-18T00:16:19.461967Z","State":"Enabled ","Conditions":{"Applications":{"Include":[{"Applications":["None"]}]},"Users" :{"Include":[{"Users":["8ab3ed0d-6668-49f7-a108-c50bb230c870"]}]}},"Controls": [{"Control":["Block"]}],"EnforceAllPoliciesForEas":true,"IncludeOtherLegacyCli entTypeForEvaluation":true}} policyIdentifier : tenantDefaultPolicy : #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Process { # Return conditional access policies Get-AzureADPolicies -AccessToken $AccessToken | Where policyType -eq 18 } } # Gets tenant's Azure AD Policies # Nov 17th 2022 function Get-AzureADPolicies { <# .SYNOPSIS Shows Azure AD policies. .DESCRIPTION Shows Azure AD policies. .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Example PS C:\>Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Get-AADIntAzureADPolicies odata.type : Microsoft.DirectoryServices.Policy objectType : Policy objectId : e35e4cd3-53f8-4d65-80bb-e3279c2c1b71 deletionTimestamp : displayName : On-Premise Authentication Flow Policy keyCredentials : {**} policyType : 8 policyDetail : {**} policyIdentifier : tenantDefaultPolicy : 8 odata.type : Microsoft.DirectoryServices.Policy objectType : Policy objectId : 259b810f-fb50-4e57-925b-ec2292c17883 deletionTimestamp : displayName : 2/5/2021 5:53:07 AM keyCredentials : {} policyType : 10 policyDetail : {{"SecurityPolicy":{"Version":0,"SecurityDefaults":{"IgnoreBaselineProtectionPolicies":true,"I sEnabled":false}}}} policyIdentifier : tenantDefaultPolicy : 10 #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" # Call the API Call-GraphAPI -AccessToken $AccessToken -Command "policies" -Method Get } } # Gets tenant's Azure AD Policies # Nov 17th 2022 function Set-AzureADPolicyDetails { <# .SYNOPSIS Sets Azure AD policy details. .DESCRIPTION Sets Azure AD policy details. .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .PARAMETER ObjectId Object ID of the policy .PARAMETER PolicyDetail Policy details. .PARAMETER DisplayName New displayname of the policy .Example PS C:\>Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Set-AADIntAzureADPolicyDetail -ObjectId "e35e4cd3-53f8-4d65-80bb-e3279c2c1b71" -PolicyDetail '{{"SecurityPolicy":{"Version":0,"SecurityDefaults":{"IgnoreBaselineProtectionPolicies":true,"IsEnabled":false}}}}' .Example PS C:\>Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Set-AADIntAzureADPolicyDetail -ObjectId "e35e4cd3-53f8-4d65-80bb-e3279c2c1b71" -PolicyDetail '{{"SecurityPolicy":{"Version":0,"SecurityDefaults":{"IgnoreBaselineProtectionPolicies":true,"IsEnabled":false}}}}' -displayName "My Policy" #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken, [Parameter(Mandatory=$True)] [Guid]$ObjectId, [Parameter(Mandatory=$True)] [String]$PolicyDetail, [Parameter(Mandatory=$False)] [String]$DisplayName ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" $body = @{ "policyDetail" = @($PolicyDetail) } if(![string]::IsNullOrEmpty($DisplayName)) { $body["displayName"] = $DisplayName } # Call the API Call-GraphAPI -AccessToken $AccessToken -Command "policies/$($ObjectId)" -Method Patch -Body ($body | ConvertTo-Json) } } # Get Azure AD features # Aug 23 2023 function Get-AzureADFeatures { <# .SYNOPSIS Show the status of Azure AD features. .DESCRIPTION Show the status of Azure AD features using Azure AD Graph internal API. Requires Global Administrator role .Parameter AccessToken Access Token .Example Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Get-AADIntAzureADFeatures Feature Enabled ------- ------- AllowEmailVerifiedUsers True AllowInvitations True AllowMemberUsersToInviteOthersAsMembers False AllowUsersToChangeTheirDisplayName False B2CFeature False BlockAllTenantAuth False ConsentedForMigrationToPublicCloud False CIAMFeature False CIAMTrialFeature False CIAMTrialUpgrade False EnableExchangeDualWrite False EnableHiddenMembership False EnableSharedEmailDomainApis False EnableWindowsLegacyCredentials False EnableWindowsSupplementalCredentials False ElevatedGuestsAccessEnabled False ExchangeDualWriteUsersV1 False GuestsCanInviteOthersEnabled True InvitationsEnabled True LargeScaleTenant False TestTenant False USGovTenant False DisableOnPremisesWindowsLegacyCredentialsSync False DisableOnPremisesWindowsSupplementalCredentialsSync False RestrictPublicNetworkAccess False AutoApproveSameTenantRequests False RedirectPpeUsersToMsaInt False LegacyTlsExceptionForEsts False LegacyTlsBlockForEsts False TenantAuthBlockReasonFraud False TenantAuthBlockReasonLifecycle False TenantExcludeDeprecateAADLicenses False #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Begin { $features = @( "AllowEmailVerifiedUsers" "AllowInvitations" "AllowMemberUsersToInviteOthersAsMembers" "AllowUsersToChangeTheirDisplayName" "B2CFeature" "BlockAllTenantAuth" "ConsentedForMigrationToPublicCloud" "CIAMFeature" "CIAMTrialFeature" "CIAMTrialUpgrade" "EnableExchangeDualWrite" "EnableHiddenMembership" "EnableSharedEmailDomainApis" "EnableWindowsLegacyCredentials" "EnableWindowsSupplementalCredentials" "ElevatedGuestsAccessEnabled" "ExchangeDualWriteUsersV1" "GuestsCanInviteOthersEnabled" "InvitationsEnabled" "LargeScaleTenant" "TestTenant" "USGovTenant" "DisableOnPremisesWindowsLegacyCredentialsSync" "DisableOnPremisesWindowsSupplementalCredentialsSync" "RestrictPublicNetworkAccess" "AutoApproveSameTenantRequests" "RedirectPpeUsersToMsaInt" "LegacyTlsExceptionForEsts" "LegacyTlsBlockForEsts" "TenantAuthBlockReasonFraud" "TenantAuthBlockReasonLifecycle" "TenantExcludeDeprecateAADLicenses" ) } Process { # Get from cache if not provided $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" $retVal = @() # Loop through the features foreach($feature in $features) { try { $value = Get-AzureADFeature -AccessToken $AccessToken -Feature $feature $retVal += [pscustomobject][ordered]@{ "Feature" = $feature "Enabled" = $value } } catch { } } $retVal } } # Get Azure AD feature status # Aug 23 2023 function Get-AzureADFeature { <# .SYNOPSIS Show the status of given Azure AD feature. .DESCRIPTION Show the status of given Azure AD feature using Azure AD Graph internal API. Requires Global Administrator role .Parameter AccessToken Access Token .PARAMETER Feature The name of the feature. Should be one of: AllowEmailVerifiedUsers AllowInvitations AllowMemberUsersToInviteOthersAsMembers AllowUsersToChangeTheirDisplayName B2CFeature BlockAllTenantAuth ConsentedForMigrationToPublicCloud CIAMFeature CIAMTrialFeature CIAMTrialUpgrade EnableExchangeDualWrite EnableHiddenMembership EnableSharedEmailDomainApis EnableWindowsLegacyCredentials EnableWindowsSupplementalCredentials ElevatedGuestsAccessEnabled ExchangeDualWriteUsersV1 GuestsCanInviteOthersEnabled InvitationsEnabled LargeScaleTenant TestTenant USGovTenant DisableOnPremisesWindowsLegacyCredentialsSync DisableOnPremisesWindowsSupplementalCredentialsSync RestrictPublicNetworkAccess AutoApproveSameTenantRequests RedirectPpeUsersToMsaInt LegacyTlsExceptionForEsts LegacyTlsBlockForEsts TenantAuthBlockReasonFraud TenantAuthBlockReasonLifecycle TenantExcludeDeprecateAADLicenses .Example Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Get-AADIntAzureADFeature -Feature "B2CFeature" True #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken, [ValidateSet('AllowEmailVerifiedUsers','AllowInvitations','AllowMemberUsersToInviteOthersAsMembers','AllowUsersToChangeTheirDisplayName','B2CFeature','BlockAllTenantAuth','ConsentedForMigrationToPublicCloud','CIAMFeature','CIAMTrialFeature','CIAMTrialUpgrade','EnableExchangeDualWrite','EnableHiddenMembership','EnableSharedEmailDomainApis','EnableWindowsLegacyCredentials','EnableWindowsSupplementalCredentials','ElevatedGuestsAccessEnabled','ExchangeDualWriteUsersV1','GuestsCanInviteOthersEnabled','InvitationsEnabled','LargeScaleTenant','TestTenant','USGovTenant','DisableOnPremisesWindowsLegacyCredentialsSync','DisableOnPremisesWindowsSupplementalCredentialsSync','RestrictPublicNetworkAccess','AutoApproveSameTenantRequests','RedirectPpeUsersToMsaInt','LegacyTlsExceptionForEsts','LegacyTlsBlockForEsts','TenantAuthBlockReasonFraud','TenantAuthBlockReasonLifecycle','TenantExcludeDeprecateAADLicenses')] [Parameter(Mandatory=$True)] [String]$Feature ) Process { # Get from cache if not provided $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" $body = @{ "directoryFeature" = $feature } # Call the API try { $response = Call-GraphAPI -AccessToken $AccessToken -Command "isDirectoryFeatureEnabled" -Method Post -Body ($body | ConvertTo-Json) $enabled = $false; # For some reason True is returned as boolean but False as object with value attribute if($response -isnot [boolean]) { $enabled = $response.Value } else { $enabled = $response } return $enabled } catch { $stream = $_.Exception.Response.GetResponseStream() $responseBytes = New-Object byte[] $stream.Length $stream.Position = 0 $stream.Read($responseBytes,0,$stream.Length) | Out-Null $response = [text.encoding]::UTF8.GetString($responseBytes) | ConvertFrom-Json throw $response.'odata.error'.message.value } } } # Enable or Disable Azure AD feature # Aug 23 2023 function Set-AzureADFeature { <# .SYNOPSIS Enables or disables the given Azure AD feature. .DESCRIPTION Enables or disables the given Azure AD feature using Azure AD Graph internal API. Requires Global Administrator role .Parameter AccessToken Access Token .PARAMETER Feature The name of the feature. Should be one of: AllowEmailVerifiedUsers AllowInvitations AllowMemberUsersToInviteOthersAsMembers AllowUsersToChangeTheirDisplayName B2CFeature BlockAllTenantAuth ConsentedForMigrationToPublicCloud CIAMFeature CIAMTrialFeature CIAMTrialUpgrade EnableExchangeDualWrite EnableHiddenMembership EnableSharedEmailDomainApis EnableWindowsLegacyCredentials EnableWindowsSupplementalCredentials ElevatedGuestsAccessEnabled ExchangeDualWriteUsersV1 GuestsCanInviteOthersEnabled InvitationsEnabled LargeScaleTenant TestTenant USGovTenant DisableOnPremisesWindowsLegacyCredentialsSync DisableOnPremisesWindowsSupplementalCredentialsSync RestrictPublicNetworkAccess AutoApproveSameTenantRequests RedirectPpeUsersToMsaInt LegacyTlsExceptionForEsts LegacyTlsBlockForEsts TenantAuthBlockReasonFraud TenantAuthBlockReasonLifecycle TenantExcludeDeprecateAADLicenses .Example Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Set-AADIntAzureADFeature -Feature "B2CFeature" -Enable $true Feature Enabled ------- ------- B2CFeature True .Example Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Set-AADIntAzureADFeature -Feature "B2CFeature" -Enable $false Feature Enabled ------- ------- B2CFeature False #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken, [ValidateSet('AllowEmailVerifiedUsers','AllowInvitations','AllowMemberUsersToInviteOthersAsMembers','AllowUsersToChangeTheirDisplayName','B2CFeature','BlockAllTenantAuth','ConsentedForMigrationToPublicCloud','CIAMFeature','CIAMTrialFeature','CIAMTrialUpgrade','EnableExchangeDualWrite','EnableHiddenMembership','EnableSharedEmailDomainApis','EnableWindowsLegacyCredentials','EnableWindowsSupplementalCredentials','ElevatedGuestsAccessEnabled','ExchangeDualWriteUsersV1','GuestsCanInviteOthersEnabled','InvitationsEnabled','LargeScaleTenant','TestTenant','USGovTenant','DisableOnPremisesWindowsLegacyCredentialsSync','DisableOnPremisesWindowsSupplementalCredentialsSync','RestrictPublicNetworkAccess','AutoApproveSameTenantRequests','RedirectPpeUsersToMsaInt','LegacyTlsExceptionForEsts','LegacyTlsBlockForEsts','TenantAuthBlockReasonFraud','TenantAuthBlockReasonLifecycle','TenantExcludeDeprecateAADLicenses')] [Parameter(Mandatory=$True)] [String]$Feature, [Parameter(Mandatory=$True)] [bool]$Enabled ) Process { # Get from cache if not provided $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" $isEnabled = Get-AzureADFeature -Feature $feature -AccessToken $AccessToken if($Enabled) { # Check if already enabled if($isEnabled) { Write-Warning "Feature $feature is already enabled." return } $command = "enableDirectoryFeature" } else { # Check if already disabled if(!$isEnabled) { Write-Warning "Feature $feature is already disabled." return } $command = "disableDirectoryFeature" } $body = @{ "directoryFeature" = $feature } # Call the API try { Call-GraphAPI -AccessToken $AccessToken -Command $command -Method Post -Body ($body | ConvertTo-Json) } catch { $stream = $_.Exception.Response.GetResponseStream() $responseBytes = New-Object byte[] $stream.Length $stream.Position = 0 $stream.Read($responseBytes,0,$stream.Length) | Out-Null $response = [text.encoding]::UTF8.GetString($responseBytes) | ConvertFrom-Json throw $response.'odata.error'.message.value } [pscustomobject][ordered]@{ "Feature" = $feature "Enabled" = Get-AzureADFeature -AccessToken $AccessToken -Feature $feature } } } # Adds Microsoft.Azure.SyncFabric service principal # Dec 4th 2023 function Add-SyncFabricServicePrincipal { <# .SYNOPSIS Adds Microsoft.Azure.SyncFabric service principal needed to create BPRTs. .DESCRIPTION Adds Microsoft.Azure.SyncFabric service principal needed to create BPRTs. Requires Application Administrator, Cloud Application Administrator, Directory Synchronization Accounts, Hybrid Identity Administrator, or Global Administrator permissions. .Parameter AccessToken The Access Token. If not given, tries to use cached Access Token. .Example PS C:\>Get-AADIntAccessTokenForAADGraph -SaveToCache PS C:\>Add-AADIntSyncFabricServicePrincipal DisplayName AppId ObjectId ----------- ----- -------- Microsoft.Azure.SyncFabric 00000014-0000-0000-c000-000000000000 138018f7-6aa2-454c-a103-a7e682e17d6b #> [cmdletbinding()] Param( [Parameter(Mandatory=$False)] [String]$AccessToken ) Process { $AccessToken = Get-AccessTokenFromCache -AccessToken $AccessToken -ClientID "1b730954-1685-4b74-9bfd-dac224a7b894" -Resource "https://graph.windows.net" $body = @{ "accountEnabled" = "True" "appId" = "00000014-0000-0000-c000-000000000000" "appRoleAssignmentRequired" = $false "displayName" = "Microsoft.Azure.SyncFabric" "tags" = @( "WindowsAzureActiveDirectoryIntegratedApp" ) } # Call the API $result = Call-GraphAPI -AccessToken $AccessToken -Command "servicePrincipals" -Body ($body | ConvertTo-Json) -Method Post if($result) { [pscustomobject]@{ "DisplayName" = $result.displayName "AppId" = $result.appId "ObjectId" = $result.objectId } } } } |