DatacenterIntegration/Portal/PortalUserDataUtilities.psm1 (321 lines of code) (raw):

<################################################### # # # Copyright (c) Microsoft. All rights reserved. # # # ##################################################> $DefaultAdminSubscriptionName = "Default Provider Subscription" function Initialize-UserDataClearEnv { param ( # The directory tenant identifier of Azure Stack. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $AzsDirectoryTenantId, # The Azure Stack ARM endpoint URI. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Uri] $AzsArmEndpoint, # The subscription name [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [string] $SubscriptionName, # Optional: A credential used to authenticate with Azure Stack. Must support a non-interactive authentication flow. If not provided, the script will prompt for user credentials. [pscredential] $AutomationCredential = $null, [ValidateNotNullOrEmpty()] [string] $UserPrincipalName ) #requires -Version 4.0 #requires -Module "AzureRM.Profile" #requires -Module "Azs.Subscriptions.Admin" #requires -RunAsAdministrator $ErrorActionPreference = 'Stop' $VerbosePreference = 'Continue' Import-Module $PSScriptRoot\..\..\Identity\GraphAPI\GraphAPI.psm1 -Force Import-Module $PSScriptRoot\..\..\Identity\AzureStack.Identity.Common.psm1 -Force Write-Verbose "Login to Azure Stack ARM..." -Verbose $AzsAdminEnvironmentName = New-Guid $params = @{ ResourceManagerEndpoint = $AzsArmEndpoint EnvironmentName = $AzsAdminEnvironmentName } $adminArmEnv = Initialize-AzureRmEnvironment @params Write-Verbose "Created admin ARM env as $(ConvertTo-JSON $adminArmEnv)" -Verbose $params = @{ AzureEnvironment = $adminArmEnv DirectoryTenantId = $AzsDirectoryTenantId } if ($SubscriptionName) { $params.SubscriptionName = $SubscriptionName } if ($AutomationCredential) { $params.AutomationCredential = $AutomationCredential } $refreshToken = Initialize-AzureRmUserRefreshToken @params Write-Verbose "Login into ARM and got the refresh token." -Verbose $script:initializeGraphEnvParams = @{ RefreshToken = $refreshToken } if ($adminArmEnv.EnableAdfsAuthentication) { $script:initializeGraphEnvParams.AdfsFqdn = (New-Object Uri $adminArmEnv.ActiveDirectoryAuthority).Host $script:initializeGraphEnvParams.GraphFqdn = (New-Object Uri $adminArmEnv.GraphUrl).Host $script:queryParameters = @{ '$filter' = "userPrincipalName eq '$($UserPrincipalName.ToLower())'" } } else { $graphEnvironment = Resolve-GraphEnvironment -AzureEnvironment $adminArmEnv Write-Verbose "Resolve the graph env as '$graphEnvironment '" -Verbose $script:initializeGraphEnvParams.Environment = $graphEnvironment $script:queryParameters = @{ '$filter' = "userPrincipalName eq '$($UserPrincipalName.ToLower())' or startswith(userPrincipalName, '$($UserPrincipalName.Replace("@", "_").ToLower() + "#")')" } } Initialize-GraphEnvironment @script:initializeGraphEnvParams -DirectoryTenantId $AzsDirectoryTenantId $script:adminArmAccessToken = (Get-GraphToken -Resource $adminArmEnv.ActiveDirectoryServiceEndpointResourceId -UseEnvironmentData).access_token } <# .Synopsis Clear the portal user data #> function Clear-AzsUserDataWithUserPrincipalName { param ( # The directory tenant identifier of Azure Stack Administrator. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $AzsAdminDirectoryTenantId, # The Azure Stack ARM endpoint URI. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Uri] $AzsAdminArmEndpoint, # The user principal name of the account whoes user data should be cleared. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $UserPrincipalName, # Optional: The directory tenant identifier of account whoes user data should be cleared. # If it is not specified, it will delete user with principal name under all regitered directory tenants [Parameter(Mandatory=$false)] [ValidateNotNullOrEmpty()] [string] $DirectoryTenantId, # Optional: A credential used to authenticate with Azure Stack. Must support a non-interactive authentication flow. If not provided, the script will prompt for user credentials. [ValidateNotNull()] [pscredential] $AutomationCredential = $null ) $ErrorActionPreference = 'Stop' $VerbosePreference = 'Continue' $params = @{ AzsDirectoryTenantId = $AzsAdminDirectoryTenantId AzsArmEndpoint = $AzsAdminArmEndpoint AutomationCredential = $AutomationCredential UserPrincipalName = $UserPrincipalName SubscriptionName = $DefaultAdminSubscriptionName } Initialize-UserDataClearEnv @params if ($DirectoryTenantId) { $directoryTenantIdsArray = [string[]]$DirectoryTenantId } else { Write-Verbose "Input parameter 'DirectoryTenantId' is empty. Retrieving all the registered tenant directory..." -Verbose $directoryTenantIdsArray = (Get-AzsDirectoryTenant -Verbose).TenantId } Write-Host "Clearing the user data with input user principal name $UserPrincipalName and directory tenants '$DirectoryTenantIdsArray'..." $clearUserDataResults = @() # key is directory Id, value is clear response foreach ($dirId in $directoryTenantIdsArray) { Write-Verbose "Intializing graph env..." -Verbose Initialize-GraphEnvironment @script:initializeGraphEnvParams -DirectoryTenantId $dirId Write-Verbose "Intialized graph env" -Verbose Write-Verbose "Querying all users..." -Verbose $usersResponse = Invoke-GraphApi -ApiPath "/users" -QueryParameters $script:queryParameters Write-Verbose "Retrieved user object as $(ConvertTo-JSON $usersResponse.value)" -Verbose $userObjectId = $usersResponse.value.objectId Write-Verbose "Retrieved user object Id as $userObjectId" -Verbose if (-not $userObjectId) { Write-Warning "There is no user '$UserPrincipalName' under directory tenant Id $dirId." $clearUserDataResult += [pscustomobject]@{ DirectoryTenantId = $dirId UserPrincipalName = $UserPrincipalName ErrorMessage = "User not found in directory." } continue } elseif (([string[]]$userObjectId).Length -gt 1) { Write-Warning "There is one more users retrieved with '$UserPrincipalName' under directory tenant Id $dirId." $clearUserDataResult += [pscustomobject]@{ DirectoryTenantId = $dirId UserPrincipalName = $UserPrincipalName ErrorMessage = "One more user accounts found in directory. User principal name may be incorrect. " } continue } else { $params = @{ AccessToken = $script:adminArmAccessToken UserObjectId = $userObjectId DirectoryTenantId = $dirId AzsAdminArmEndpoint = $AzsAdminArmEndpoint } $curResult = Clear-SinglePortalUserData @params $clearUserDataResult += @( $curResult ) } } return $clearUserDataResult } <# .Synopsis Clear the portal user data #> function Clear-AzsUserDataWithUserObjectId { param ( # The directory tenant identifier of Azure Stack Administrator. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $AzsAdminDirectoryTenantId, # The Azure Stack ARM endpoint URI. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Uri] $AzsAdminArmEndpoint, # The user object Id of the account whoes user data should be cleared. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $UserObjectId, # The directory tenant identifier of account whoes user data should be cleared. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $DirectoryTenantId, # Optional: A credential used to authenticate with Azure Stack. Must support a non-interactive authentication flow. If not provided, the script will prompt for user credentials. [ValidateNotNull()] [pscredential] $AutomationCredential = $null ) $ErrorActionPreference = 'Stop' $VerbosePreference = 'Continue' $params = @{ AzsDirectoryTenantId = $AzsAdminDirectoryTenantId AzsArmEndpoint = $AzsAdminArmEndpoint AutomationCredential = $AutomationCredential SubscriptionName = $DefaultAdminSubscriptionName } Initialize-UserDataClearEnv @params $params = @{ AccessToken = $script:adminArmAccessToken UserObjectId = $UserObjectId DirectoryTenantId = $DirectoryTenantId AzsAdminArmEndpoint = $AzsAdminArmEndpoint } Clear-SinglePortalUserData @params } function Get-UserObjectId { param ( # The directory tenant identifier of user account [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $DirectoryTenantId, # The Azure Stack ARM endpoint URI. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Uri] $AzsArmEndpoint, # The user principal name of the account whoes user data should be cleared. [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $UserPrincipalName, # Optional: A credential used to authenticate with Azure Stack. Must support a non-interactive authentication flow. If not provided, the script will prompt for user credentials. [ValidateNotNull()] [pscredential] $AutomationCredential = $null ) $params = @{ AzsDirectoryTenantId = $DirectoryTenantId AzsArmEndpoint = $AzsArmEndpoint AutomationCredential = $AutomationCredential UserPrincipalName = $UserPrincipalName } Initialize-UserDataClearEnv @params Write-Verbose "Intializing graph env..." -Verbose Initialize-GraphEnvironment @script:initializeGraphEnvParams -DirectoryTenantId $DirectoryTenantId Write-Verbose "Intialized graph env" -Verbose Write-Verbose "Querying all users..." -Verbose $usersResponse = Invoke-GraphApi -ApiPath "/users" -QueryParameters $script:queryParameters Write-Verbose "Retrieved user object as $(ConvertTo-JSON $usersResponse.value)" -Verbose return $usersResponse.value.objectId } function Clear-SinglePortalUserData { param ( # The user credential with which to acquire an access token targeting Graph. [Parameter(Mandatory=$true)] [ValidateNotNull()] [string] $AccessToken, [Parameter(Mandatory=$true)] [ValidateNotNull()] [string] $UserObjectId, [Parameter(Mandatory=$true)] [ValidateNotNull()] [string] $DirectoryTenantId, # The Azure Stack ARM endpoint URI. [Parameter(Mandatory=$true)] [ValidateNotNull()] [Uri] $AzsAdminArmEndpoint ) try { $adminSubscriptionId = (Get-AzureRmSubscription -Verbose | where { $_.Name -ieq $DefaultAdminSubscriptionName }).Id Write-Verbose "Get default Admin subscription id $adminSubscriptionId." -Verbose $clearUserDataEndpoint = "$AzsAdminArmEndpoint/subscriptions/$adminSubscriptionId/providers/Microsoft.PortalExtensionHost.Providers/ClearUserSettings?api-version=2017-09-01-preview" $headers = @{ Authorization = "Bearer $accessToken" "Content-Type" = "application/json" } $payload = @{ UserObjectId = $UserObjectId DirectoryTenantId = $DirectoryTenantId } $httpPayload = ConvertTo-Json $payload -Depth 10 Write-Verbose "Clearing user data with URI '$clearUserDataEndpoint' and payload: `r`n$httpPayload..." -Verbose $clearUserDataResponse = $httpPayload | Invoke-RestMethod -Headers $headers -Method POST -Uri $clearUserDataEndpoint -TimeoutSec 120 -Verbose return [pscustomobject]@{ DirectoryTenantId = $DirectoryTenantId UserPrincipalName = $UserPrincipalName ResponseData = $clearUserDataResponse } } catch { if ($_.Exception.Response.StatusCode -eq [System.Net.HttpStatusCode]::NotFound -and (ConvertFrom-JSON $_.ErrorDetails.Message).error.code -eq "NoPortalUserData") { Write-Warning "No user data with user object Id and directory tenant Id" return [pscustomobject]@{ DirectoryTenantId = $DirectoryTenantId UserPrincipalName = $UserPrincipalName ErrorMessage = "No portal user data" } } else { Write-Warning "Exception when clear user data with user object Id and directory tenant Id: $_`r`n$($_.Exception)" return [pscustomobject]@{ DirectoryTenantId = $DirectoryTenantId UserPrincipalName = $UserPrincipalName ErrorMessage = "Exception when clearing user data" Exception = $_.Exception } } } } Export-ModuleMember -Function Get-UserObjectId Export-ModuleMember -Function Clear-AzsUserDataWithUserPrincipalName Export-ModuleMember -Function Clear-AzsUserDataWithUserObjectId