2017-03-04 03:59:51 +03:00
# Copyright (c) Microsoft Corporation. All rights reserved.
# See LICENSE.txt in the project root for license information.
2017-03-04 10:23:55 +03:00
<#
. Synopsis
Get the Guid of the directory tenant
. DESCRIPTION
This function fetches the OpenID configuration metadata from the identity system and parses the Directory TenantID out of it .
Azure Stack AD FS is configured to be a single tenanted identity system with a TenantID .
. EXAMPLE
2017-06-15 03:17:38 +03:00
Get-AzsDirectoryTenantIdentifier -authority https : / / login . windows . net / microsoft . onmicrosoft . com
2017-03-04 10:23:55 +03:00
. EXAMPLE
2017-06-15 03:17:38 +03:00
Get-AzsDirectoryTenantIdentifier -authority https : / / adfs . local . azurestack . external / adfs
2017-03-04 10:23:55 +03:00
#>
2017-06-15 03:17:38 +03:00
function Get-AzsDirectoryTenantidentifier {
2017-03-04 10:23:55 +03:00
[ CmdletBinding ( ) ]
Param
(
2018-12-20 22:29:44 +03:00
# The Authority of the identity system, e.g. "https://login.windows.net/microsoft.onmicrosoft.com"
2017-04-04 02:23:31 +03:00
[ Parameter ( Mandatory = $true ,
Position = 0 ) ]
2017-03-04 10:23:55 +03:00
$Authority
)
2017-04-04 02:23:31 +03:00
2017-03-04 10:23:55 +03:00
return $ ( Invoke-RestMethod $ ( " {0}/.well-known/openid-configuration " -f $authority . TrimEnd ( '/' ) ) ) . issuer . TrimEnd ( '/' ) . Split ( '/' ) [ -1 ]
}
2017-03-04 03:59:51 +03:00
<#
. Synopsis
2017-10-25 10:28:54 +03:00
This function is used to create a Service Principal on the AD Graph in an AD FS topology
2017-03-04 03:59:51 +03:00
. DESCRIPTION
The command creates a certificate in the cert store of the local user and uses that certificate to create a Service Principal in the Azure Stack Stamp Active Directory .
. EXAMPLE
2017-10-12 00:46:42 +03:00
$servicePrincipal = New-AzsAdGraphServicePrincipal -DisplayName " myapp12 " -AdminCredential $ ( Get-Credential ) -Verbose
#>
2017-06-15 03:17:38 +03:00
function New-AzsAdGraphServicePrincipal {
2017-04-04 02:23:31 +03:00
[ CmdletBinding ( ) ]
Param
(
# Display Name of the Service Principal
[ ValidatePattern ( " [a-zA-Z0-9-]{3,} " ) ]
[ Parameter ( Mandatory = $true ,
Position = 0 ) ]
$DisplayName ,
2017-03-04 03:59:51 +03:00
2017-10-12 00:46:42 +03:00
# PEP Machine name
2017-04-04 02:23:31 +03:00
[ string ]
2017-10-12 00:46:42 +03:00
$ERCSMachineName = " Azs-ERCS01 " ,
2017-04-04 02:23:31 +03:00
# Domain Administrator Credential to create Service Principal
[ Parameter ( Mandatory = $true ,
Position = 2 ) ]
[ System.Management.Automation.PSCredential ]
2017-10-12 00:46:42 +03:00
$AdminCredential
2017-04-04 02:23:31 +03:00
)
2017-10-12 00:46:42 +03:00
$ApplicationGroupName = $DisplayName
$computerName = $ERCSMachineName
$cloudAdminCredential = $AdminCredential
$domainAdminSession = New-PSSession -ComputerName $computerName -Credential $cloudAdminCredential -configurationname privilegedendpoint -Verbose
$GraphClientCertificate = New-SelfSignedCertificate -CertStoreLocation " cert:\CurrentUser\My " -Subject " CN= $ApplicationGroupName " -KeySpec KeyExchange
$graphRedirectUri = " https://localhost/ " . ToLowerInvariant ( )
$ApplicationName = $ApplicationGroupName
$application = Invoke-Command -Session $domainAdminSession -Verbose -ErrorAction Stop `
2018-02-09 23:50:57 +03:00
-ScriptBlock { New-GraphApplication -Name $using : ApplicationName -ClientRedirectUris $using : graphRedirectUri -ClientCertificates $using : GraphClientCertificate }
2017-04-04 02:23:31 +03:00
2017-10-12 00:46:42 +03:00
return $application
2017-04-04 02:23:31 +03:00
}
2017-05-06 03:00:17 +03:00
# Exposed Functions
2017-04-04 02:23:31 +03:00
<#
2018-02-09 23:50:57 +03:00
. Synopsis
Adds a Guest Directory Tenant to Azure Stack .
. DESCRIPTION
Running this cmdlet will add the specified directory tenant to the Azure Stack whitelist .
. EXAMPLE
$adminARMEndpoint = " https://adminmanagement.local.azurestack.external "
$azureStackDirectoryTenant = " <homeDirectoryTenant>.onmicrosoft.com "
$guestDirectoryTenantToBeOnboarded = " <guestDirectoryTenant>.onmicrosoft.com "
Register-AzsGuestDirectoryTenant -AdminResourceManagerEndpoint $adminARMEndpoint -DirectoryTenantName $azureStackDirectoryTenant -GuestDirectoryTenantName $guestDirectoryTenantToBeOnboarded
2017-04-04 02:23:31 +03:00
#>
2017-06-15 03:17:38 +03:00
2017-06-28 00:06:54 +03:00
function Register-AzsGuestDirectoryTenant {
2017-04-04 02:23:31 +03:00
[ CmdletBinding ( ) ]
param
(
# The endpoint of the Azure Stack Resource Manager service.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNull ( ) ]
[ ValidateScript ( { $_ . Scheme -eq [ System.Uri ] :: UriSchemeHttps } ) ]
[ uri ] $AdminResourceManagerEndpoint ,
# The name of the home Directory Tenant in which the Azure Stack Administrator subscription resides.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $DirectoryTenantName ,
2017-05-06 03:00:17 +03:00
# The names of the guest Directory Tenants which are to be onboarded.
2017-04-04 02:23:31 +03:00
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
2017-05-06 03:00:17 +03:00
[ string[] ] $GuestDirectoryTenantName ,
2017-04-04 02:23:31 +03:00
2017-05-06 03:00:17 +03:00
# The location of your Azure Stack deployment.
2018-02-09 23:50:57 +03:00
[ Parameter ( Mandatory = $true ) ]
2017-04-04 02:23:31 +03:00
[ ValidateNotNullOrEmpty ( ) ]
2017-05-06 03:00:17 +03:00
[ string ] $Location ,
2017-04-04 02:23:31 +03:00
# The identifier of the Administrator Subscription. If not specified, the script will attempt to use the set default subscription.
[ ValidateNotNull ( ) ]
[ string ] $SubscriptionId = $null ,
# The display name of the Administrator Subscription. If not specified, the script will attempt to use the set default subscription.
[ ValidateNotNull ( ) ]
[ string ] $SubscriptionName = $null ,
2017-10-12 00:18:12 +03:00
# The name of the resource group in which the directory tenant registration resource should be created (resource group must already exist).
2018-02-09 23:50:57 +03:00
[ Parameter ( Mandatory = $true ) ]
2017-04-04 02:23:31 +03:00
[ ValidateNotNullOrEmpty ( ) ]
2017-10-12 00:18:12 +03:00
[ string ] $ResourceGroupName = $null ,
2017-04-04 02:23:31 +03:00
2017-05-06 03:00:17 +03:00
# 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.
2017-04-04 02:23:31 +03:00
[ Parameter ( ) ]
2017-05-06 03:00:17 +03:00
[ ValidateNotNull ( ) ]
[ pscredential ] $AutomationCredential = $null
2017-04-04 02:23:31 +03:00
)
2017-10-12 00:18:12 +03:00
2017-04-04 02:23:31 +03:00
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
2018-02-09 23:50:57 +03:00
Import-Module 'AzureRm.Profile' -Verbose: $false 4 > $null
2017-05-06 03:00:17 +03:00
2018-02-09 23:50:57 +03:00
function Invoke-Main {
2017-10-12 00:18:12 +03:00
# Initialize the Azure PowerShell module to communicate with Azure Stack. Will prompt user for credentials.
$azureEnvironment = Initialize-AzureRmEnvironment 'AzureStackAdmin'
2018-02-09 23:50:57 +03:00
$azureAccount = Initialize-AzureRmUserAccount $azureEnvironment
2017-10-12 00:18:12 +03:00
2018-02-09 23:50:57 +03:00
foreach ( $directoryTenantName in $GuestDirectoryTenantName ) {
2017-10-12 00:18:12 +03:00
# Resolve the guest directory tenant ID from the name
$directoryTenantId = ( New-Object uri ( Invoke-RestMethod " $( $azureEnvironment . ActiveDirectoryAuthority . TrimEnd ( '/' ) ) / $directoryTenantName /.well-known/openid-configuration " ) . token_endpoint ) . AbsolutePath . Split ( '/' ) [ 1 ]
2017-04-04 02:23:31 +03:00
2017-10-12 00:18:12 +03:00
# Add (or update) the new directory tenant to the Azure Stack deployment
$params = @ {
ApiVersion = '2015-11-01'
ResourceType = " Microsoft.Subscriptions.Admin/directoryTenants "
ResourceGroupName = $ResourceGroupName
ResourceName = $directoryTenantName
Location = $Location
Properties = @ { tenantId = $directoryTenantId }
}
2018-02-09 23:53:55 +03:00
# Check if resource group exists, create it if it doesn't
$rg = Get-AzureRmResourceGroup -Name $ResourceGroupName -Location $Location -ErrorAction SilentlyContinue
if ( $rg -eq $null ) {
New-AzureRmResourceGroup -Name $ResourceGroupName -Location $Location -ErrorAction SilentlyContinue | Out-Null
}
2017-10-12 00:18:12 +03:00
$directoryTenant = New-AzureRmResource @params -Force -Verbose -ErrorAction Stop
Write-Verbose -Message " Directory Tenant onboarded: $( ConvertTo-Json $directoryTenant ) " -Verbose
}
}
2018-02-09 23:50:57 +03:00
function Initialize-AzureRmEnvironment([string]$environmentName ) {
2017-10-12 00:18:12 +03:00
$endpoints = Invoke-RestMethod -Method Get -Uri " $( $AdminResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /metadata/endpoints?api-version=2015-01-01 " -Verbose
Write-Verbose -Message " Endpoints: $( ConvertTo-Json $endpoints ) " -Verbose
# resolve the directory tenant ID from the name
$directoryTenantId = ( New-Object uri ( Invoke-RestMethod " $( $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) ) / $DirectoryTenantName /.well-known/openid-configuration " ) . token_endpoint ) . AbsolutePath . Split ( '/' ) [ 1 ]
$azureEnvironmentParams = @ {
Name = $environmentName
ActiveDirectoryEndpoint = $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) + " / "
ActiveDirectoryServiceEndpointResourceId = $endpoints . authentication . audiences [ 0 ]
AdTenant = $directoryTenantId
2018-02-09 23:50:57 +03:00
ResourceManagerEndpoint = $AdminResourceManagerEndpoint
2017-10-12 00:18:12 +03:00
GalleryEndpoint = $endpoints . galleryEndpoint
GraphEndpoint = $endpoints . graphEndpoint
GraphAudience = $endpoints . graphEndpoint
}
2017-04-04 02:23:31 +03:00
2017-10-12 00:18:12 +03:00
$azureEnvironment = Add-AzureRmEnvironment @azureEnvironmentParams -ErrorAction Ignore
$azureEnvironment = Get-AzureRmEnvironment -Name $environmentName -ErrorAction Stop
return $azureEnvironment
}
2017-04-04 02:23:31 +03:00
2018-02-09 23:50:57 +03:00
function Initialize-AzureRmUserAccount([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment ) {
2017-04-04 02:23:31 +03:00
$params = @ {
2017-10-12 00:18:12 +03:00
EnvironmentName = $azureEnvironment . Name
TenantId = $azureEnvironment . AdTenant
2017-04-04 02:23:31 +03:00
}
2017-10-12 00:18:12 +03:00
2018-02-09 23:50:57 +03:00
if ( $AutomationCredential ) {
2017-10-12 00:18:12 +03:00
$params + = @ { Credential = $AutomationCredential }
}
# Prompts the user for interactive login flow if automation credential is not specified
#$DebugPreference = "Continue"
$azureAccount = Add-AzureRmAccount @params
2018-02-09 23:50:57 +03:00
if ( $SubscriptionName ) {
2017-10-12 00:18:12 +03:00
Select-AzureRmSubscription -SubscriptionName $SubscriptionName | Out-Null
}
2018-02-09 23:50:57 +03:00
elseif ( $SubscriptionId ) {
2017-10-12 00:18:12 +03:00
Select-AzureRmSubscription -SubscriptionId $SubscriptionId | Out-Null
2017-04-04 02:23:31 +03:00
}
2017-10-12 00:18:12 +03:00
return $azureAccount
2017-04-04 02:23:31 +03:00
}
2017-10-12 00:18:12 +03:00
Invoke-Main
2017-04-04 02:23:31 +03:00
}
2019-04-24 19:45:00 +03:00
<#
. Synopsis
Gets the health report of identity application in the Azure Stack home and guest directories
. DESCRIPTION
Gets the health report for Azure Stack identity applications in the home directory as well as guest directories of Azure Stack . Any directories with an unhealthy status need to have their permissions updated .
. EXAMPLE
$adminResourceManagerEndpoint = " https://adminmanagement.local.azurestack.external "
$homeDirectoryTenantName = " <homeDirectoryTenant>.onmicrosoft.com "
Get-AzsHealthReport -AdminResourceManagerEndpoint $adminResourceManagerEndpoint `
-DirectoryTenantName $homeDirectoryTenantName -Verbose
#>
function Get-AzsHealthReport {
[ CmdletBinding ( ) ]
param
(
# The endpoint of the Azure Stack Resource Manager service.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNull ( ) ]
[ ValidateScript ( { $_ . Scheme -eq [ System.Uri ] :: UriSchemeHttps } ) ]
[ uri ] $AdminResourceManagerEndpoint ,
# The name of the home Directory Tenant in which the Azure Stack Administrator subscription resides.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $DirectoryTenantName ,
# 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.
[ Parameter ( ) ]
[ ValidateNotNull ( ) ]
[ pscredential ] $AutomationCredential = $null
)
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
# Install-Module AzureRm
Import-Module 'AzureRm.Profile' -Verbose: $false 4 > $null
Import-Module " $PSScriptRoot \GraphAPI\GraphAPI.psm1 " -Verbose: $false 4 > $null
function Invoke-Main {
# Initialize the Azure PowerShell module to communicate with the Azure Resource Manager in the public cloud corresponding to the Azure Stack Graph Service. Will prompt user for credentials.
Write-Host " Authenticating user... "
$azureStackEnvironment = Initialize-AzureRmEnvironment 'AzureStackAdmin'
$refreshToken = Initialize-AzureRmUserAccount $azureStackEnvironment
# Initialize the Graph PowerShell module to communicate with the correct graph service
$graphEnvironment = Resolve-GraphEnvironment $azureStackEnvironment
Initialize-GraphEnvironment -Environment $graphEnvironment -DirectoryTenantId $DirectoryTenantName -RefreshToken $refreshToken
# Call Azure Stack Resource Manager to retrieve the list of registered applications which need to be initialized in the onboarding directory tenant
Write-Host " Acquiring an access token to communicate with Resource Manager... "
$armAccessToken = Get-ArmAccessToken $azureStackEnvironment
$defaultProviderSubscription = Get-AzureRmSubscription -SubscriptionName " Default Provider Subscription "
$healthReportUrl = " $( $AdminResourceManagerEndpoint . AbsoluteUri ) /subscriptions/ $( $defaultProviderSubscription . SubscriptionId ) /providers/Microsoft.Subscriptions.Admin/checkIdentityHealth?api-version=2018-05-01 "
$headers = @ { " Authorization " = " Bearer $armAccessToken " }
$healthReport = ( Invoke-WebRequest -Headers $headers -Uri $healthReportUrl -Method Post -UseBasicParsing -TimeoutSec 40 ) . Content | ConvertFrom-Json
return $healthReport
}
function Initialize-AzureRmEnvironment([string]$environmentName ) {
$endpoints = Invoke-RestMethod -Method Get -Uri " $( $AdminResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /metadata/endpoints?api-version=2015-01-01 " -Verbose
Write-Verbose -Message " Endpoints: $( ConvertTo-Json $endpoints ) " -Verbose
# resolve the directory tenant ID from the name
$directoryTenantId = ( New-Object uri ( Invoke-RestMethod " $( $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) ) / $DirectoryTenantName /.well-known/openid-configuration " ) . token_endpoint ) . AbsolutePath . Split ( '/' ) [ 1 ]
$azureEnvironmentParams = @ {
Name = $environmentName
ActiveDirectoryEndpoint = $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) + " / "
ActiveDirectoryServiceEndpointResourceId = $endpoints . authentication . audiences [ 0 ]
AdTenant = $directoryTenantId
ResourceManagerEndpoint = $AdminResourceManagerEndpoint
GalleryEndpoint = $endpoints . galleryEndpoint
GraphEndpoint = $endpoints . graphEndpoint
GraphAudience = $endpoints . graphEndpoint
}
$azureEnvironment = Add-AzureRmEnvironment @azureEnvironmentParams -ErrorAction Ignore
$azureEnvironment = Get-AzureRmEnvironment -Name $environmentName -ErrorAction Stop
return $azureEnvironment
}
function Initialize-AzureRmUserAccount([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureStackEnvironment ) {
$params = @ {
EnvironmentName = $azureStackEnvironment . Name
TenantId = $azureStackEnvironment . AdTenant
}
if ( $AutomationCredential ) {
$params + = @ { Credential = $AutomationCredential }
}
# Prompts the user for interactive login flow if automation credential is not specified
$azureStackAccount = Add-AzureRmAccount @params
# Retrieve the refresh token
$tokens = @ ( )
$tokens + = try { [ Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache ] :: DefaultShared . ReadItems ( ) } catch { }
$tokens + = try { [ Microsoft.Azure.Commands.Common.Authentication.AzureSession ] :: Instance . TokenCache . ReadItems ( ) } catch { }
$refreshToken = $tokens |
Where Resource -EQ $azureStackEnvironment . ActiveDirectoryServiceEndpointResourceId |
Where IsMultipleResourceRefreshToken -EQ $true |
Where DisplayableId -EQ $azureStackAccount . Context . Account . Id |
Sort ExpiresOn |
Select -Last 1 -ExpandProperty RefreshToken |
ConvertTo-SecureString -AsPlainText -Force
# Workaround due to regression in AzurePowerShell profile module which fails to populate the response object of "Add-AzureRmAccount" cmdlet
if ( -not $refreshToken ) {
if ( $tokens . Count -eq 1 ) {
Write-Warning " Failed to find target refresh token from Azure PowerShell Cache; attempting to reuse the single cached auth context... "
$refreshToken = $tokens [ 0 ] . RefreshToken | ConvertTo-SecureString -AsPlainText -Force
}
else {
throw " Unable to find refresh token from Azure PowerShell Cache. Please try the command again in a fresh PowerShell instance after running 'Clear-AzureRmContext -Scope CurrentUser -Force -Verbose'. "
}
}
return $refreshToken
}
function Resolve-GraphEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment ) {
$graphEnvironment = switch ( $azureEnvironment . ActiveDirectoryAuthority ) {
'https://login.microsoftonline.com/' { 'AzureCloud' }
'https://login.chinacloudapi.cn/' { 'AzureChinaCloud' }
'https://login-us.microsoftonline.com/' { 'AzureUSGovernment' }
'https://login.microsoftonline.de/' { 'AzureGermanCloud' }
Default { throw " Unsupported graph resource identifier: $_ " }
}
return $graphEnvironment
}
function Get-ArmAccessToken([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureStackEnvironment ) {
$armAccessToken = $null
$attempts = 0
$maxAttempts = 12
$delayInSeconds = 5
do {
try {
$attempts + +
$armAccessToken = ( Get-GraphToken -Resource $azureStackEnvironment . ActiveDirectoryServiceEndpointResourceId -UseEnvironmentData -ErrorAction Stop ) . access_token
}
catch {
if ( $attempts -ge $maxAttempts ) {
throw
}
Write-Verbose " Error attempting to acquire ARM access token: $_ `r `n $( $_ . Exception ) " -Verbose
Write-Verbose " Delaying for $delayInSeconds seconds before trying again... (attempt $attempts / $maxAttempts ) " -Verbose
Start-Sleep -Seconds $delayInSeconds
}
}
while ( -not $armAccessToken )
return $armAccessToken
}
$logFile = Join-Path -Path $PSScriptRoot -ChildPath " $DirectoryTenantName . $( Get-Date -Format MM-dd_HH -mm -ss_ms ) .log "
Write-Verbose " Logging additional information to log file ' $logFile ' " -Verbose
$logStartMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Beginning invocation of ' $( $MyInvocation . InvocationName ) ' with parameters: $( ConvertTo-Json $PSBoundParameters -Depth 4 ) "
$logStartMessage > > $logFile
try {
# Redirect verbose output to a log file
Invoke-Main 4 > > $logFile
$logEndMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Script completed successfully. "
$logEndMessage > > $logFile
}
catch {
$logErrorMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Script terminated with error: $_ `r `n $( $_ . Exception ) "
$logErrorMessage > > $logFile
Write-Warning " An error has occurred; more information may be found in the log file ' $logFile ' " -WarningAction Continue
throw
}
}
2018-12-20 22:29:44 +03:00
<#
. Synopsis
Consents to any missing permissions for Azure Stack identity applications in the home directory of Azure Stack .
. DESCRIPTION
Consents to any missing permissions for Azure Stack identity applications in the home directory of Azure Stack . This is needed to complete the " installation " of new Resource Provider identity applications in Azure Stack .
. EXAMPLE
$adminResourceManagerEndpoint = " https://adminmanagement.local.azurestack.external "
$homeDirectoryTenantName = " <homeDirectoryTenant>.onmicrosoft.com "
Update-AzsHomeDirectoryTenant -AdminResourceManagerEndpoint $adminResourceManagerEndpoint `
-DirectoryTenantName $homeDirectoryTenantName -Verbose
#>
function Update-AzsHomeDirectoryTenant {
[ CmdletBinding ( ) ]
param
(
# The endpoint of the Azure Stack Resource Manager service.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNull ( ) ]
[ ValidateScript ( { $_ . Scheme -eq [ System.Uri ] :: UriSchemeHttps } ) ]
[ uri ] $AdminResourceManagerEndpoint ,
# The name of the home Directory Tenant in which the Azure Stack Administrator subscription resides.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $DirectoryTenantName ,
# 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.
[ Parameter ( ) ]
[ ValidateNotNull ( ) ]
[ pscredential ] $AutomationCredential = $null
)
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
Import-Module 'AzureRm.Profile' -Verbose: $false 4 > $null
Import-Module " $PSScriptRoot \GraphAPI\GraphAPI.psm1 " -Verbose: $false 4 > $null
function Invoke-Main {
# Initialize the Azure PowerShell module to communicate with the Azure Resource Manager in the public cloud corresponding to the Azure Stack Graph Service. Will prompt user for credentials.
Write-Host " Authenticating user... "
$azureStackEnvironment = Initialize-AzureRmEnvironment 'AzureStackAdmin'
$refreshToken = Initialize-AzureRmUserAccount $azureStackEnvironment
# Initialize the Graph PowerShell module to communicate with the correct graph service
$graphEnvironment = Resolve-GraphEnvironment $azureStackEnvironment
Initialize-GraphEnvironment -Environment $graphEnvironment -DirectoryTenantId $DirectoryTenantName -RefreshToken $refreshToken
# Call Azure Stack Resource Manager to retrieve the list of registered applications which need to be initialized in the onboarding directory tenant
Write-Host " Acquiring an access token to communicate with Resource Manager... "
$armAccessToken = Get-ArmAccessToken $azureStackEnvironment
Write-Host " Looking-up the registered identity applications which need to be installed in your directory... "
$applicationRegistrationParams = @ {
Method = [ Microsoft.PowerShell.Commands.WebRequestMethod ] :: Get
Headers = @ { Authorization = " Bearer $armAccessToken " }
Uri = " $( $AdminResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /applicationRegistrations?api-version=2014-04-01-preview "
}
$applicationRegistrations = Invoke-RestMethod @applicationRegistrationParams | Select -ExpandProperty value
# Identify which permissions have already been granted to each registered application and which additional permissions need to be granted
$permissions = @ ( )
$count = 0
foreach ( $applicationRegistration in $applicationRegistrations ) {
# Initialize the service principal for the registered application
$count + +
$applicationServicePrincipal = Initialize-GraphApplicationServicePrincipal -ApplicationId $applicationRegistration . appId
Write-Host " Installing Application... ( $( $count ) of $( $applicationRegistrations . Count ) ): $( $applicationServicePrincipal . appId ) ' $( $applicationServicePrincipal . appDisplayName ) ' "
# WORKAROUND - the recent Azure Stack update has a missing permission registration; temporarily "inject" this permission registration into the returned data
if ( $applicationServicePrincipal . servicePrincipalNames | Where { $_ -like 'https://deploymentprovider.*/*' } )
{
Write-Verbose " Adding missing permission registrations for application ' $( $applicationServicePrincipal . appDisplayName ) ' ( $( $applicationServicePrincipal . appId ) )... " -Verbose
$graph = Get-GraphApplicationServicePrincipal -ApplicationId ( Get-GraphEnvironmentInfo ) . Applications . WindowsAzureActiveDirectory . Id
$applicationRegistration . appRoleAssignments = @ (
[ pscustomobject ] @ {
resource = ( Get-GraphEnvironmentInfo ) . Applications . WindowsAzureActiveDirectory . Id
client = $applicationRegistration . appId
roleId = $graph . appRoles | Where value -EQ 'Directory.Read.All' | Select -ExpandProperty id
} ,
[ pscustomobject ] @ {
resource = ( Get-GraphEnvironmentInfo ) . Applications . WindowsAzureActiveDirectory . Id
client = $applicationRegistration . appId
roleId = $graph . appRoles | Where value -EQ 'Application.ReadWrite.OwnedBy' | Select -ExpandProperty id
}
)
}
# Initialize the necessary tags for the registered application
if ( $applicationRegistration . tags ) {
Update-GraphApplicationServicePrincipalTags -ApplicationId $applicationRegistration . appId -Tags $applicationRegistration . tags
}
# Lookup the permission consent status for the *application* permissions (either to or from) which the registered application requires
foreach ( $appRoleAssignment in $applicationRegistration . appRoleAssignments ) {
$params = @ {
ClientApplicationId = $appRoleAssignment . client
ResourceApplicationId = $appRoleAssignment . resource
PermissionType = 'Application'
PermissionId = $appRoleAssignment . roleId
}
$permissions + = New-GraphPermissionDescription @params -LookupConsentStatus
}
# Lookup the permission consent status for the *delegated* permissions (either to or from) which the registered application requires
foreach ( $oauth2PermissionGrant in $applicationRegistration . oauth2PermissionGrants ) {
$resourceApplicationServicePrincipal = Initialize-GraphApplicationServicePrincipal -ApplicationId $oauth2PermissionGrant . resource
foreach ( $scope in $oauth2PermissionGrant . scope . Split ( ' ' ) ) {
$params = @ {
ClientApplicationId = $oauth2PermissionGrant . client
ResourceApplicationServicePrincipal = $resourceApplicationServicePrincipal
PermissionType = 'Delegated'
PermissionId = ( $resourceApplicationServicePrincipal . oauth2Permissions | Where value -EQ $scope ) . id
}
$permissions + = New-GraphPermissionDescription @params -LookupConsentStatus
}
}
}
# Trace the permission status
Write-Verbose " Current permission status: $( $permissions | ConvertTo-Json -Depth 4 ) " -Verbose
$permissionFile = Join-Path -Path $PSScriptRoot -ChildPath " $DirectoryTenantName .permissions.json "
$permissionContent = $permissions | Select -Property * -ExcludeProperty isConsented | ConvertTo-Json -Depth 4 | Out-String
$permissionContent > $permissionFile
# Display application status to user
$permissionsByClient = $permissions | Select * , @ { n = 'Client' ; e = { '{0} {1}' -f $_ . clientApplicationId , $_ . clientApplicationDisplayName } } | Sort clientApplicationDisplayName | Group Client
$readyApplications = @ ( )
$pendingApplications = @ ( )
foreach ( $client in $permissionsByClient ) {
if ( $client . Group . isConsented -Contains $false ) {
$pendingApplications + = $client
}
else {
$readyApplications + = $client
}
}
Write-Host " "
if ( $readyApplications ) {
Write-Host " Applications installed and configured: "
Write-Host " `t $( $readyApplications . Name -join " `r `n `t " ) "
}
if ( $readyApplications -and $pendingApplications ) {
Write-Host " "
}
if ( $pendingApplications ) {
Write-Host " Applications waiting to be configured: "
Write-Host " `t $( $pendingApplications . Name -join " `r `n `t " ) "
}
Write-Host " "
# Grant any missing permissions for registered applications
if ( $permissions | Where isConsented -EQ $false | Select -First 1 ) {
Write-Host " Configuring applications... (this may take up to a few minutes to complete) "
Write-Host " "
$permissions | Where isConsented -EQ $false | Grant-GraphApplicationPermission
}
Write-Host " All applications installed and configured! Your home directory ' $DirectoryTenantName ' has been successfully updated to be used with Azure Stack! "
Write-Host " "
Write-Host " A more detailed description of the applications installed and with what permissions they have been configured can be found in the file ' $permissionFile '. "
Write-Host " Run this script again at any time to check the status of the Azure Stack applications in your directory. "
Write-Warning " If your Azure Stack Administrator installs new services or updates in the future, you may need to run this script again. "
}
function Initialize-AzureRmEnvironment([string]$environmentName ) {
$endpoints = Invoke-RestMethod -Method Get -Uri " $( $AdminResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /metadata/endpoints?api-version=2015-01-01 " -Verbose
Write-Verbose -Message " Endpoints: $( ConvertTo-Json $endpoints ) " -Verbose
# resolve the directory tenant ID from the name
$directoryTenantId = ( New-Object uri ( Invoke-RestMethod " $( $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) ) / $DirectoryTenantName /.well-known/openid-configuration " ) . token_endpoint ) . AbsolutePath . Split ( '/' ) [ 1 ]
$azureEnvironmentParams = @ {
Name = $environmentName
ActiveDirectoryEndpoint = $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) + " / "
ActiveDirectoryServiceEndpointResourceId = $endpoints . authentication . audiences [ 0 ]
AdTenant = $directoryTenantId
ResourceManagerEndpoint = $AdminResourceManagerEndpoint
GalleryEndpoint = $endpoints . galleryEndpoint
GraphEndpoint = $endpoints . graphEndpoint
GraphAudience = $endpoints . graphEndpoint
}
$azureEnvironment = Add-AzureRmEnvironment @azureEnvironmentParams -ErrorAction Ignore
$azureEnvironment = Get-AzureRmEnvironment -Name $environmentName -ErrorAction Stop
return $azureEnvironment
}
function Initialize-AzureRmUserAccount([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureStackEnvironment ) {
$params = @ {
EnvironmentName = $azureStackEnvironment . Name
TenantId = $azureStackEnvironment . AdTenant
}
if ( $AutomationCredential ) {
$params + = @ { Credential = $AutomationCredential }
}
# Prompts the user for interactive login flow if automation credential is not specified
$azureStackAccount = Add-AzureRmAccount @params
# Retrieve the refresh token
$tokens = @ ( )
$tokens + = try { [ Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache ] :: DefaultShared . ReadItems ( ) } catch { }
$tokens + = try { [ Microsoft.Azure.Commands.Common.Authentication.AzureSession ] :: Instance . TokenCache . ReadItems ( ) } catch { }
$refreshToken = $tokens |
Where Resource -EQ $azureStackEnvironment . ActiveDirectoryServiceEndpointResourceId |
Where IsMultipleResourceRefreshToken -EQ $true |
Where DisplayableId -EQ $azureStackAccount . Context . Account . Id |
Sort ExpiresOn |
Select -Last 1 -ExpandProperty RefreshToken |
ConvertTo-SecureString -AsPlainText -Force
# Workaround due to regression in AzurePowerShell profile module which fails to populate the response object of "Add-AzureRmAccount" cmdlet
if ( -not $refreshToken ) {
if ( $tokens . Count -eq 1 ) {
Write-Warning " Failed to find target refresh token from Azure PowerShell Cache; attempting to reuse the single cached auth context... "
$refreshToken = $tokens [ 0 ] . RefreshToken | ConvertTo-SecureString -AsPlainText -Force
}
else {
throw " Unable to find refresh token from Azure PowerShell Cache. Please try the command again in a fresh PowerShell instance after running 'Clear-AzureRmContext -Scope CurrentUser -Force -Verbose'. "
}
}
return $refreshToken
}
function Resolve-GraphEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment ) {
$graphEnvironment = switch ( $azureEnvironment . ActiveDirectoryAuthority ) {
'https://login.microsoftonline.com/' { 'AzureCloud' }
'https://login.chinacloudapi.cn/' { 'AzureChinaCloud' }
'https://login-us.microsoftonline.com/' { 'AzureUSGovernment' }
'https://login.microsoftonline.de/' { 'AzureGermanCloud' }
Default { throw " Unsupported graph resource identifier: $_ " }
}
return $graphEnvironment
}
function Get-ArmAccessToken([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureStackEnvironment ) {
$armAccessToken = $null
$attempts = 0
$maxAttempts = 12
$delayInSeconds = 5
do {
try {
$attempts + +
$armAccessToken = ( Get-GraphToken -Resource $azureStackEnvironment . ActiveDirectoryServiceEndpointResourceId -UseEnvironmentData -ErrorAction Stop ) . access_token
}
catch {
if ( $attempts -ge $maxAttempts ) {
throw
}
Write-Verbose " Error attempting to acquire ARM access token: $_ `r `n $( $_ . Exception ) " -Verbose
Write-Verbose " Delaying for $delayInSeconds seconds before trying again... (attempt $attempts / $maxAttempts ) " -Verbose
Start-Sleep -Seconds $delayInSeconds
}
}
while ( -not $armAccessToken )
return $armAccessToken
}
$logFile = Join-Path -Path $PSScriptRoot -ChildPath " $DirectoryTenantName . $( Get-Date -Format MM-dd_HH -mm -ss_ms ) .log "
Write-Verbose " Logging additional information to log file ' $logFile ' " -Verbose
$logStartMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Beginning invocation of ' $( $MyInvocation . InvocationName ) ' with parameters: $( ConvertTo-Json $PSBoundParameters -Depth 4 ) "
$logStartMessage > > $logFile
try {
# Redirect verbose output to a log file
Invoke-Main 4 > > $logFile
$logEndMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Script completed successfully. "
$logEndMessage > > $logFile
}
catch {
$logErrorMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Script terminated with error: $_ `r `n $( $_ . Exception ) "
$logErrorMessage > > $logFile
Write-Warning " An error has occurred; more information may be found in the log file ' $logFile ' " -WarningAction Continue
throw
}
}
2017-04-04 02:23:31 +03:00
<#
. Synopsis
Consents to the given Azure Stack instance within the callers ' s Azure Directory Tenant .
. DESCRIPTION
Consents to the given Azure Stack instance within the callers 's Azure Directory Tenant. This is needed to propagate Azure Stack applications into the user' s directory tenant .
. EXAMPLE
$tenantARMEndpoint = " https://management.local.azurestack.external "
$myDirectoryTenantName = " <guestDirectoryTenant>.onmicrosoft.com "
2017-06-15 03:17:38 +03:00
Register-AzsWithMyDirectoryTenant -TenantResourceManagerEndpoint $tenantARMEndpoint `
2017-04-04 02:23:31 +03:00
-DirectoryTenantName $myDirectoryTenantName -Verbose -Debug
#>
2017-06-15 03:17:38 +03:00
function Register-AzsWithMyDirectoryTenant {
2017-04-04 02:23:31 +03:00
[ CmdletBinding ( ) ]
param
(
# The endpoint of the Azure Stack Resource Manager service.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNull ( ) ]
[ ValidateScript ( { $_ . Scheme -eq [ System.Uri ] :: UriSchemeHttps } ) ]
[ uri ] $TenantResourceManagerEndpoint ,
# The name of the directory tenant being onboarded.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
2017-05-06 03:00:17 +03:00
[ string ] $DirectoryTenantName ,
# 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.
[ Parameter ( ) ]
[ ValidateNotNull ( ) ]
[ pscredential ] $AutomationCredential = $null
2017-04-04 02:23:31 +03:00
)
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
2018-02-09 23:50:57 +03:00
Import-Module 'AzureRm.Profile' -Verbose: $false 4 > $null
Import-Module " $PSScriptRoot \GraphAPI\GraphAPI.psm1 " -Verbose: $false 4 > $null
2017-04-04 02:23:31 +03:00
2018-02-09 23:50:57 +03:00
function Invoke-Main {
2017-10-12 00:18:12 +03:00
# Initialize the Azure PowerShell module to communicate with the Azure Resource Manager in the public cloud corresponding to the Azure Stack Graph Service. Will prompt user for credentials.
Write-Host " Authenticating user... "
$azureStackEnvironment = Initialize-AzureRmEnvironment 'AzureStack'
2018-02-09 23:50:57 +03:00
$azureEnvironment = Resolve-AzureEnvironment $azureStackEnvironment
$refreshToken = Initialize-AzureRmUserAccount $azureEnvironment $azureStackEnvironment . AdTenant
2017-10-12 00:18:12 +03:00
# Initialize the Graph PowerShell module to communicate with the correct graph service
$graphEnvironment = Resolve-GraphEnvironment $azureEnvironment
Initialize-GraphEnvironment -Environment $graphEnvironment -DirectoryTenantId $DirectoryTenantName -RefreshToken $refreshToken
# Initialize the service principal for the Azure Stack Resource Manager application
Write-Host " Installing Resource Manager in your directory (' $DirectoryTenantName ')... "
$resourceManagerServicePrincipal = Initialize-ResourceManagerServicePrincipal
# Authorize the Azure Powershell module to act as a client to call the Azure Stack Resource Manager in the onboarding directory tenant
Write-Host " Authorizing the Azure PowerShell module to communicate with Resource Manager in your directory... "
Initialize-GraphOAuth2PermissionGrant -ClientApplicationId ( Get-GraphEnvironmentInfo ) . Applications . PowerShell . Id -ResourceApplicationIdentifierUri $azureStackEnvironment . ActiveDirectoryServiceEndpointResourceId
# Call Azure Stack Resource Manager to retrieve the list of registered applications which need to be initialized in the onboarding directory tenant
Write-Host " Acquiring an access token to communicate with Resource Manager... (this may take up to a few minutes to complete) "
$armAccessToken = Get-ArmAccessToken $azureStackEnvironment
Write-Host " Looking-up the registered identity applications which need to be installed in your directory... "
$applicationRegistrationParams = @ {
Method = [ Microsoft.PowerShell.Commands.WebRequestMethod ] :: Get
Headers = @ { Authorization = " Bearer $armAccessToken " }
Uri = " $( $TenantResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /applicationRegistrations?api-version=2014-04-01-preview "
}
$applicationRegistrations = Invoke-RestMethod @applicationRegistrationParams | Select -ExpandProperty value
2017-04-04 02:23:31 +03:00
2017-10-12 00:18:12 +03:00
# Identify which permissions have already been granted to each registered application and which additional permissions need to be granted
$permissions = @ ( )
$count = 0
2018-02-09 23:50:57 +03:00
foreach ( $applicationRegistration in $applicationRegistrations ) {
2017-10-12 00:18:12 +03:00
# Initialize the service principal for the registered application
$count + +
$applicationServicePrincipal = Initialize-GraphApplicationServicePrincipal -ApplicationId $applicationRegistration . appId
Write-Host " Installing Application... ( $( $count ) of $( $applicationRegistrations . Count ) ): $( $applicationServicePrincipal . appId ) ' $( $applicationServicePrincipal . appDisplayName ) ' "
2017-04-04 02:23:31 +03:00
2017-10-12 00:18:12 +03:00
# Initialize the necessary tags for the registered application
2018-02-09 23:50:57 +03:00
if ( $applicationRegistration . tags ) {
2017-10-12 00:18:12 +03:00
Update-GraphApplicationServicePrincipalTags -ApplicationId $applicationRegistration . appId -Tags $applicationRegistration . tags
}
# Lookup the permission consent status for the *application* permissions (either to or from) which the registered application requires
2018-02-09 23:50:57 +03:00
foreach ( $appRoleAssignment in $applicationRegistration . appRoleAssignments ) {
2017-10-12 00:18:12 +03:00
$params = @ {
ClientApplicationId = $appRoleAssignment . client
ResourceApplicationId = $appRoleAssignment . resource
PermissionType = 'Application'
PermissionId = $appRoleAssignment . roleId
}
$permissions + = New-GraphPermissionDescription @params -LookupConsentStatus
}
# Lookup the permission consent status for the *delegated* permissions (either to or from) which the registered application requires
2018-02-09 23:50:57 +03:00
foreach ( $oauth2PermissionGrant in $applicationRegistration . oauth2PermissionGrants ) {
2017-10-12 00:18:12 +03:00
$resourceApplicationServicePrincipal = Initialize-GraphApplicationServicePrincipal -ApplicationId $oauth2PermissionGrant . resource
2018-02-09 23:50:57 +03:00
foreach ( $scope in $oauth2PermissionGrant . scope . Split ( ' ' ) ) {
2017-10-12 00:18:12 +03:00
$params = @ {
ClientApplicationId = $oauth2PermissionGrant . client
ResourceApplicationServicePrincipal = $resourceApplicationServicePrincipal
PermissionType = 'Delegated'
PermissionId = ( $resourceApplicationServicePrincipal . oauth2Permissions | Where value -EQ $scope ) . id
}
$permissions + = New-GraphPermissionDescription @params -LookupConsentStatus
}
}
}
# Trace the permission status
Write-Verbose " Current permission status: $( $permissions | ConvertTo-Json -Depth 4 ) " -Verbose
2018-02-09 23:50:57 +03:00
$permissionFile = Join-Path -Path $PSScriptRoot -ChildPath " $DirectoryTenantName .permissions.json "
2017-10-12 00:18:12 +03:00
$permissionContent = $permissions | Select -Property * -ExcludeProperty isConsented | ConvertTo-Json -Depth 4 | Out-String
$permissionContent > $permissionFile
# Display application status to user
2018-02-09 23:50:57 +03:00
$permissionsByClient = $permissions | Select * , @ { n = 'Client' ; e = { '{0} {1}' -f $_ . clientApplicationId , $_ . clientApplicationDisplayName } } | Sort clientApplicationDisplayName | Group Client
$readyApplications = @ ( )
2017-10-12 00:18:12 +03:00
$pendingApplications = @ ( )
2018-02-09 23:50:57 +03:00
foreach ( $client in $permissionsByClient ) {
if ( $client . Group . isConsented -Contains $false ) {
2017-10-12 00:18:12 +03:00
$pendingApplications + = $client
}
2018-02-09 23:50:57 +03:00
else {
2017-10-12 00:18:12 +03:00
$readyApplications + = $client
}
}
Write-Host " "
2018-02-09 23:50:57 +03:00
if ( $readyApplications ) {
2017-10-12 00:18:12 +03:00
Write-Host " Applications installed and configured: "
Write-Host " `t $( $readyApplications . Name -join " `r `n `t " ) "
}
2018-02-09 23:50:57 +03:00
if ( $readyApplications -and $pendingApplications ) {
2017-10-12 00:18:12 +03:00
Write-Host " "
}
2018-02-09 23:50:57 +03:00
if ( $pendingApplications ) {
2017-10-12 00:18:12 +03:00
Write-Host " Applications waiting to be configured: "
Write-Host " `t $( $pendingApplications . Name -join " `r `n `t " ) "
}
Write-Host " "
# Grant any missing permissions for registered applications
2018-02-09 23:50:57 +03:00
if ( $permissions | Where isConsented -EQ $false | Select -First 1 ) {
2017-10-12 00:18:12 +03:00
Write-Host " Configuring applications... (this may take up to a few minutes to complete) "
Write-Host " "
$permissions | Where isConsented -EQ $false | Grant-GraphApplicationPermission
}
2017-04-04 02:23:31 +03:00
2017-10-12 00:18:12 +03:00
Write-Host " All applications installed and configured! Your directory ' $DirectoryTenantName ' has been successfully onboarded and can now be used with Azure Stack! "
Write-Host " "
Write-Host " A more detailed description of the applications installed and with what permissions they have been configured can be found in the file ' $permissionFile '. "
Write-Host " Run this script again at any time to check the status of the Azure Stack applications in your directory. "
Write-Warning " If your Azure Stack Administrator installs new services or updates in the future, you may need to run this script again. "
}
2017-04-04 02:23:31 +03:00
2018-02-09 23:50:57 +03:00
function Initialize-AzureRmEnvironment([string]$environmentName ) {
2017-10-12 00:18:12 +03:00
$endpoints = Invoke-RestMethod -Method Get -Uri " $( $TenantResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /metadata/endpoints?api-version=2015-01-01 " -Verbose
Write-Verbose -Message " Endpoints: $( ConvertTo-Json $endpoints ) " -Verbose
# resolve the directory tenant ID from the name
$directoryTenantId = ( New-Object uri ( Invoke-RestMethod " $( $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) ) / $DirectoryTenantName /.well-known/openid-configuration " ) . token_endpoint ) . AbsolutePath . Split ( '/' ) [ 1 ]
$azureEnvironmentParams = @ {
Name = $environmentName
ActiveDirectoryEndpoint = $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) + " / "
ActiveDirectoryServiceEndpointResourceId = $endpoints . authentication . audiences [ 0 ]
AdTenant = $directoryTenantId
2018-02-09 23:50:57 +03:00
ResourceManagerEndpoint = $TenantResourceManagerEndpoint
2017-10-12 00:18:12 +03:00
GalleryEndpoint = $endpoints . galleryEndpoint
GraphEndpoint = $endpoints . graphEndpoint
GraphAudience = $endpoints . graphEndpoint
}
$azureEnvironment = Add-AzureRmEnvironment @azureEnvironmentParams -ErrorAction Ignore
$azureEnvironment = Get-AzureRmEnvironment -Name $environmentName -ErrorAction Stop
return $azureEnvironment
2017-05-06 03:00:17 +03:00
}
2018-02-09 23:50:57 +03:00
function Resolve-AzureEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureStackEnvironment ) {
2017-10-12 00:18:12 +03:00
$azureEnvironment = Get-AzureRmEnvironment |
Where GraphEndpointResourceId -EQ $azureStackEnvironment . GraphEndpointResourceId |
2018-02-09 23:50:57 +03:00
Where Name -In @ ( 'AzureCloud' , 'AzureChinaCloud' , 'AzureUSGovernment' , 'AzureGermanCloud' )
2017-05-06 03:00:17 +03:00
2017-10-12 00:18:12 +03:00
# Differentiate between AzureCloud and AzureUSGovernment
2018-02-09 23:50:57 +03:00
if ( $azureEnvironment . Count -ge 2 ) {
2017-10-12 00:18:12 +03:00
$name = if ( $azureStackEnvironment . ActiveDirectoryAuthority -eq 'https://login-us.microsoftonline.com/' ) { 'AzureUSGovernment' } else { 'AzureCloud' }
$azureEnvironment = $azureEnvironment | Where Name -EQ $name
}
2017-04-04 02:23:31 +03:00
2017-10-12 00:18:12 +03:00
return $azureEnvironment
2017-04-04 02:23:31 +03:00
}
2018-02-09 23:50:57 +03:00
function Initialize-AzureRmUserAccount([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment , [ string ] $directoryTenantId ) {
2017-10-12 00:18:12 +03:00
$params = @ {
EnvironmentName = $azureEnvironment . Name
TenantId = $directoryTenantId
}
2017-05-06 03:00:17 +03:00
2018-02-09 23:50:57 +03:00
if ( $AutomationCredential ) {
2017-10-12 00:18:12 +03:00
$params + = @ { Credential = $AutomationCredential }
2017-04-04 02:23:31 +03:00
}
2017-10-12 00:18:12 +03:00
# Prompts the user for interactive login flow if automation credential is not specified
$azureAccount = Add-AzureRmAccount @params
# Retrieve the refresh token
$tokens = @ ( )
$tokens + = try { [ Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache ] :: DefaultShared . ReadItems ( ) } catch { }
$tokens + = try { [ Microsoft.Azure.Commands.Common.Authentication.AzureSession ] :: Instance . TokenCache . ReadItems ( ) } catch { }
$refreshToken = $tokens |
Where Resource -EQ $azureEnvironment . ActiveDirectoryServiceEndpointResourceId |
Where IsMultipleResourceRefreshToken -EQ $true |
Where DisplayableId -EQ $azureAccount . Context . Account . Id |
Sort ExpiresOn |
Select -Last 1 -ExpandProperty RefreshToken |
ConvertTo-SecureString -AsPlainText -Force
2018-10-06 03:33:20 +03:00
# Workaround due to regression in AzurePowerShell profile module which fails to populate the response object of "Add-AzureRmAccount" cmdlet
if ( -not $refreshToken ) {
if ( $tokens . Count -eq 1 ) {
Write-Warning " Failed to find target refresh token from Azure PowerShell Cache; attempting to reuse the single cached auth context... "
$refreshToken = $tokens [ 0 ] . RefreshToken | ConvertTo-SecureString -AsPlainText -Force
}
else {
throw " Unable to find refresh token from Azure PowerShell Cache. Please try the command again in a fresh PowerShell instance after running 'Clear-AzureRmContext -Scope CurrentUser -Force -Verbose'. "
}
}
2017-10-12 00:18:12 +03:00
return $refreshToken
}
2018-02-09 23:50:57 +03:00
function Resolve-GraphEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment ) {
$graphEnvironment = switch ( $azureEnvironment . ActiveDirectoryAuthority ) {
'https://login.microsoftonline.com/' { 'AzureCloud' }
'https://login.chinacloudapi.cn/' { 'AzureChinaCloud' }
2017-10-12 00:18:12 +03:00
'https://login-us.microsoftonline.com/' { 'AzureUSGovernment' }
2018-02-09 23:50:57 +03:00
'https://login.microsoftonline.de/' { 'AzureGermanCloud' }
2017-10-12 00:18:12 +03:00
Default { throw " Unsupported graph resource identifier: $_ " }
2017-04-04 02:23:31 +03:00
}
2017-10-12 00:18:12 +03:00
return $graphEnvironment
}
2018-02-09 23:50:57 +03:00
function Initialize-ResourceManagerServicePrincipal {
2017-10-12 00:18:12 +03:00
$identityInfo = Invoke-RestMethod -Method Get -Uri " $( $TenantResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /metadata/identity?api-version=2015-01-01 " -Verbose
Write-Verbose -Message " Resource Manager identity information: $( ConvertTo-Json $identityInfo ) " -Verbose
$resourceManagerServicePrincipal = Initialize-GraphApplicationServicePrincipal -ApplicationId $identityInfo . applicationId -Verbose
return $resourceManagerServicePrincipal
}
2018-02-09 23:50:57 +03:00
function Get-ArmAccessToken([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureStackEnvironment ) {
2017-10-12 00:18:12 +03:00
$armAccessToken = $null
2018-02-09 23:50:57 +03:00
$attempts = 0
$maxAttempts = 12
2017-10-12 00:18:12 +03:00
$delayInSeconds = 5
2018-02-09 23:50:57 +03:00
do {
try {
2017-10-12 00:18:12 +03:00
$attempts + +
$armAccessToken = ( Get-GraphToken -Resource $azureStackEnvironment . ActiveDirectoryServiceEndpointResourceId -UseEnvironmentData -ErrorAction Stop ) . access_token
}
2018-02-09 23:50:57 +03:00
catch {
if ( $attempts -ge $maxAttempts ) {
2017-10-12 00:18:12 +03:00
throw
2017-05-06 03:00:17 +03:00
}
2017-10-12 00:18:12 +03:00
Write-Verbose " Error attempting to acquire ARM access token: $_ `r `n $( $_ . Exception ) " -Verbose
Write-Verbose " Delaying for $delayInSeconds seconds before trying again... (attempt $attempts / $maxAttempts ) " -Verbose
Start-Sleep -Seconds $delayInSeconds
2017-05-06 03:00:17 +03:00
}
2017-04-04 02:23:31 +03:00
}
2018-02-09 23:50:57 +03:00
while ( -not $armAccessToken )
2017-10-12 00:18:12 +03:00
return $armAccessToken
2017-04-04 02:23:31 +03:00
}
2017-05-06 03:00:17 +03:00
2017-10-12 00:18:12 +03:00
$logFile = Join-Path -Path $PSScriptRoot -ChildPath " $DirectoryTenantName . $( Get-Date -Format MM-dd_HH -mm -ss_ms ) .log "
Write-Verbose " Logging additional information to log file ' $logFile ' " -Verbose
2017-05-06 03:00:17 +03:00
2017-10-12 00:18:12 +03:00
$logStartMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Beginning invocation of ' $( $MyInvocation . InvocationName ) ' with parameters: $( ConvertTo-Json $PSBoundParameters -Depth 4 ) "
$logStartMessage > > $logFile
2018-02-09 23:50:57 +03:00
try {
2017-10-12 00:18:12 +03:00
# Redirect verbose output to a log file
Invoke-Main 4 > > $logFile
2017-05-06 03:00:17 +03:00
2017-10-12 00:18:12 +03:00
$logEndMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Script completed successfully. "
$logEndMessage > > $logFile
}
2018-02-09 23:50:57 +03:00
catch {
$logErrorMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Script terminated with error: $_ `r `n $( $_ . Exception ) "
$logErrorMessage > > $logFile
Write-Warning " An error has occurred; more information may be found in the log file ' $logFile ' " -WarningAction Continue
throw
}
}
<#
. Synopsis
Removes a Guest Directory Tenant from Azure Stack .
. DESCRIPTION
Running this cmdlet will remove the specified directory tenant from the Azure Stack whitelist .
Ensure an Admin of the directory tenant has already run " Unregister-AzsWithMyDirectoryTenant " or they will be unable to
complete that cleanup of their directory tenant ( this cmdlet will remove the permissions they need to query Azure Stack to determine what to delete ) .
. EXAMPLE
$adminARMEndpoint = " https://adminmanagement.local.azurestack.external "
$azureStackDirectoryTenant = " <homeDirectoryTenant>.onmicrosoft.com "
$guestDirectoryTenantToBeOnboarded = " <guestDirectoryTenant>.onmicrosoft.com "
Unregister-AzsGuestDirectoryTenant -AdminResourceManagerEndpoint $adminARMEndpoint -DirectoryTenantName $azureStackDirectoryTenant -GuestDirectoryTenantName $guestDirectoryTenantToBeOnboarded
#>
function Unregister-AzsGuestDirectoryTenant {
[ CmdletBinding ( ) ]
param
(
# The endpoint of the Azure Stack Resource Manager service.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNull ( ) ]
[ ValidateScript ( { $_ . Scheme -eq [ System.Uri ] :: UriSchemeHttps } ) ]
[ uri ] $AdminResourceManagerEndpoint ,
# The name of the home Directory Tenant in which the Azure Stack Administrator subscription resides.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $DirectoryTenantName ,
# The name of the guest Directory Tenant which is to be decommissioned.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $GuestDirectoryTenantName ,
# The name of the resource group in which the directory tenant resource was created.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $ResourceGroupName = $null ,
# The identifier of the Administrator Subscription. If not specified, the script will attempt to use the set default subscription.
[ Parameter ( ) ]
[ ValidateNotNull ( ) ]
[ string ] $SubscriptionId = $null ,
# The display name of the Administrator Subscription. If not specified, the script will attempt to use the set default subscription.
[ Parameter ( ) ]
[ ValidateNotNull ( ) ]
[ string ] $SubscriptionName = $null ,
# 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.
[ Parameter ( ) ]
[ ValidateNotNull ( ) ]
[ pscredential ] $AutomationCredential = $null
)
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
$ResourceManagerEndpoint = $AdminResourceManagerEndpoint
Import-Module 'AzureRm.Profile' -Verbose: $false 4 > $null
function Invoke-Main {
Write-DecommissionImplicationsWarning
# Initialize the Azure PowerShell module to communicate with Azure Stack. Will prompt user for credentials.
$azureEnvironment = Initialize-AzureRmEnvironment 'AzureStackAdmin'
$azureAccount = Initialize-AzureRmUserAccount $azureEnvironment
# Remove the new directory tenant to the Azure Stack deployment
$params = @ {
ResourceId = " /subscriptions/ $( $azureAccount . Context . Subscription . Id ) /resourceGroups/ $ResourceGroupName /providers/Microsoft.Subscriptions.Admin/directoryTenants/ $GuestDirectoryTenantName "
ApiVersion = '2015-11-01'
}
$output = Remove-AzureRmResource @params -Force -Verbose -ErrorAction Stop
Write-Verbose -Message " Directory Tenant decommissioned: $( $params . ResourceId ) " -Verbose
}
function Initialize-AzureRmEnvironment([string]$environmentName ) {
$endpoints = Invoke-RestMethod -Method Get -Uri " $( $ResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /metadata/endpoints?api-version=2015-01-01 " -Verbose
Write-Verbose -Message " Endpoints: $( ConvertTo-Json $endpoints ) " -Verbose
# resolve the directory tenant ID from the name
$directoryTenantId = ( New-Object uri ( Invoke-RestMethod " $( $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) ) / $DirectoryTenantName /.well-known/openid-configuration " ) . token_endpoint ) . AbsolutePath . Split ( '/' ) [ 1 ]
$azureEnvironmentParams = @ {
Name = $environmentName
ActiveDirectoryEndpoint = $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) + " / "
ActiveDirectoryServiceEndpointResourceId = $endpoints . authentication . audiences [ 0 ]
AdTenant = $directoryTenantId
ResourceManagerEndpoint = $ResourceManagerEndpoint
GalleryEndpoint = $endpoints . galleryEndpoint
GraphEndpoint = $endpoints . graphEndpoint
GraphAudience = $endpoints . graphEndpoint
}
$azureEnvironment = Add-AzureRmEnvironment @azureEnvironmentParams -ErrorAction Ignore
$azureEnvironment = Get-AzureRmEnvironment -Name $environmentName -ErrorAction Stop
return $azureEnvironment
}
function Initialize-AzureRmUserAccount([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment ) {
$params = @ {
EnvironmentName = $azureEnvironment . Name
TenantId = $azureEnvironment . AdTenant
}
if ( $AutomationCredential ) {
$params + = @ { Credential = $AutomationCredential }
}
# Prompts the user for interactive login flow if automation credential is not specified
$azureAccount = Add-AzureRmAccount @params
if ( $SubscriptionName ) {
Select-AzureRmSubscription -SubscriptionName $SubscriptionName | Out-Null
}
elseif ( $SubscriptionId ) {
Select-AzureRmSubscription -SubscriptionId $SubscriptionId | Out-Null
}
return $azureAccount
}
function Write-DecommissionImplicationsWarning {
$params = @ {
Message = ''
WarningAction = 'Inquire'
}
$params . Message + = 'You are removing a directory tenant from your Azure Stack deployment.'
$params . Message + = ' Users in this directory will be unable to access or manage any existing subscriptions (access to any existing resources may be impaired if they require identity integration).'
$params . Message + = " Additionally, you should first ensure that an Administrator of the directory ' $directoryTenantName ' has completed their decommissioning process before removing this access "
$params . Message + = ' (they will need to query your Azure Stack deployment to see which identities need to be removed from their directory).'
if ( $AutomationCredential ) {
$params . WarningAction = 'Continue'
}
else {
$params . Message + = " Would you like to proceed? "
}
Write-Warning @params
}
Invoke-Main
}
<#
. Synopsis
Removes the installed Azure Stack identity applications and their permissions within the callers ' s Azure Directory Tenant .
. DESCRIPTION
Removes the installed Azure Stack identity applications and their permissions within the callers ' s Azure Directory Tenant .
. EXAMPLE
$tenantARMEndpoint = " https://management.local.azurestack.external "
$myDirectoryTenantName = " <guestDirectoryTenant>.onmicrosoft.com "
Unregister-AzsWithMyDirectoryTenant -TenantResourceManagerEndpoint $tenantARMEndpoint `
-DirectoryTenantName $myDirectoryTenantName -Verbose -Debug
#>
function Unregister-AzsWithMyDirectoryTenant {
[ CmdletBinding ( ) ]
param
(
# The endpoint of the Azure Stack Resource Manager service.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNull ( ) ]
[ ValidateScript ( { $_ . Scheme -eq [ System.Uri ] :: UriSchemeHttps } ) ]
[ uri ] $TenantResourceManagerEndpoint ,
# The name of the directory tenant being onboarded.
[ Parameter ( Mandatory = $true ) ]
[ ValidateNotNullOrEmpty ( ) ]
[ string ] $DirectoryTenantName ,
# 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.
[ Parameter ( ) ]
[ ValidateNotNull ( ) ]
[ pscredential ] $AutomationCredential = $null
)
$ErrorActionPreference = 'Stop'
$VerbosePreference = 'Continue'
$ResourceManagerEndpoint = $TenantResourceManagerEndpoint
Import-Module 'AzureRm.Profile' -Verbose: $false 4 > $null
Import-Module " $PSScriptRoot \GraphAPI\GraphAPI.psm1 " -Verbose: $false 4 > $null
function Invoke-Main {
Write-DecommissionImplicationsWarning
# Initialize the Azure PowerShell module to communicate with the Azure Resource Manager in the public cloud corresponding to the Azure Stack Graph Service. Will prompt user for credentials.
Write-Host " Authenticating user... "
$azureStackEnvironment = Initialize-AzureRmEnvironment 'AzureStack'
$azureEnvironment = Resolve-AzureEnvironment $azureStackEnvironment
$refreshToken = Initialize-AzureRmUserAccount $azureEnvironment $azureStackEnvironment . AdTenant
# Initialize the Graph PowerShell module to communicate with the correct graph service
$graphEnvironment = Resolve-GraphEnvironment $azureEnvironment
Initialize-GraphEnvironment -Environment $graphEnvironment -DirectoryTenantId $DirectoryTenantName -RefreshToken $refreshToken
# Call Azure Stack Resource Manager to retrieve the list of registered applications which need to be removed from the directory tenant
Write-Host " Acquiring an access token to communicate with Resource Manager... (if you already decommissioned this directory you may get an error here which you can ignore) "
$armAccessToken = ( Get-GraphToken -Resource $azureStackEnvironment . ActiveDirectoryServiceEndpointResourceId -UseEnvironmentData -ErrorAction Stop ) . access_token
Write-Host " Looking-up the registered identity applications which need to be uninstalled from your directory... "
$applicationRegistrationParams = @ {
Method = [ Microsoft.PowerShell.Commands.WebRequestMethod ] :: Get
Headers = @ { Authorization = " Bearer $armAccessToken " }
Uri = " $( $ResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /applicationRegistrations?api-version=2014-04-01-preview "
}
$applicationRegistrations = Invoke-RestMethod @applicationRegistrationParams | Select -ExpandProperty value
# Delete the service principals for the registered applications
foreach ( $applicationRegistration in $applicationRegistrations ) {
if ( ( $applicationServicePrincipal = Get-GraphApplicationServicePrincipal -ApplicationId $applicationRegistration . appId -ErrorAction Continue ) ) {
Write-Verbose " Uninstalling service principal: $( ConvertTo-Json $applicationServicePrincipal ) " -Verbose
Remove-GraphObject -objectId $applicationServicePrincipal . objectId
Write-Host " Application ' $( $applicationServicePrincipal . appId ) ' ( $( $applicationServicePrincipal . appDisplayName ) ) was successfully uninstalled from your directory. "
}
else {
Write-Host " Application ' $( $applicationRegistration . appId ) ' is not installed or was already successfully uninstalled from your directory. "
}
}
Write-Host " All Azure Stack applications have been uninstalled! Your directory ' $DirectoryTenantName ' has been successfully decommissioned and can no-longer be used with Azure Stack. "
}
function Initialize-AzureRmEnvironment([string]$environmentName ) {
$endpoints = Invoke-RestMethod -Method Get -Uri " $( $ResourceManagerEndpoint . ToString ( ) . TrimEnd ( '/' ) ) /metadata/endpoints?api-version=2015-01-01 " -Verbose
Write-Verbose -Message " Endpoints: $( ConvertTo-Json $endpoints ) " -Verbose
# resolve the directory tenant ID from the name
$directoryTenantId = ( New-Object uri ( Invoke-RestMethod " $( $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) ) / $DirectoryTenantName /.well-known/openid-configuration " ) . token_endpoint ) . AbsolutePath . Split ( '/' ) [ 1 ]
$azureEnvironmentParams = @ {
Name = $environmentName
ActiveDirectoryEndpoint = $endpoints . authentication . loginEndpoint . TrimEnd ( '/' ) + " / "
ActiveDirectoryServiceEndpointResourceId = $endpoints . authentication . audiences [ 0 ]
AdTenant = $directoryTenantId
ResourceManagerEndpoint = $ResourceManagerEndpoint
GalleryEndpoint = $endpoints . galleryEndpoint
GraphEndpoint = $endpoints . graphEndpoint
GraphAudience = $endpoints . graphEndpoint
}
$azureEnvironment = Add-AzureRmEnvironment @azureEnvironmentParams -ErrorAction Ignore
$azureEnvironment = Get-AzureRmEnvironment -Name $environmentName -ErrorAction Stop
return $azureEnvironment
}
function Resolve-AzureEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureStackEnvironment ) {
$azureEnvironment = Get-AzureRmEnvironment |
Where GraphEndpointResourceId -EQ $azureStackEnvironment . GraphEndpointResourceId |
Where Name -In @ ( 'AzureCloud' , 'AzureChinaCloud' , 'AzureUSGovernment' , 'AzureGermanCloud' )
# Differentiate between AzureCloud and AzureUSGovernment
if ( $azureEnvironment . Count -ge 2 ) {
$name = if ( $azureStackEnvironment . ActiveDirectoryAuthority -eq 'https://login-us.microsoftonline.com/' ) { 'AzureUSGovernment' } else { 'AzureCloud' }
$azureEnvironment = $azureEnvironment | Where Name -EQ $name
}
return $azureEnvironment
}
function Initialize-AzureRmUserAccount([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment , [ string ] $directoryTenantId ) {
$params = @ {
EnvironmentName = $azureEnvironment . Name
TenantId = $directoryTenantId
}
if ( $AutomationCredential ) {
$params + = @ { Credential = $AutomationCredential }
}
# Prompts the user for interactive login flow if automation credential is not specified
$azureAccount = Add-AzureRmAccount @params
# Retrieve the refresh token
$tokens = @ ( )
$tokens + = try { [ Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache ] :: DefaultShared . ReadItems ( ) } catch { }
$tokens + = try { [ Microsoft.Azure.Commands.Common.Authentication.AzureSession ] :: Instance . TokenCache . ReadItems ( ) } catch { }
$refreshToken = $tokens |
Where Resource -EQ $azureEnvironment . ActiveDirectoryServiceEndpointResourceId |
Where IsMultipleResourceRefreshToken -EQ $true |
Where DisplayableId -EQ $azureAccount . Context . Account . Id |
Sort ExpiresOn |
Select -Last 1 -ExpandProperty RefreshToken |
ConvertTo-SecureString -AsPlainText -Force
2018-10-06 03:33:20 +03:00
# Workaround due to regression in AzurePowerShell profile module which fails to populate the response object of "Add-AzureRmAccount" cmdlet
if ( -not $refreshToken ) {
if ( $tokens . Count -eq 1 ) {
Write-Warning " Failed to find target refresh token from Azure PowerShell Cache; attempting to reuse the single cached auth context... "
$refreshToken = $tokens [ 0 ] . RefreshToken | ConvertTo-SecureString -AsPlainText -Force
}
else {
throw " Unable to find refresh token from Azure PowerShell Cache. Please try the command again in a fresh PowerShell instance after running 'Clear-AzureRmContext -Scope CurrentUser -Force -Verbose'. "
}
}
2018-02-09 23:50:57 +03:00
return $refreshToken
}
function Resolve-GraphEnvironment([Microsoft.Azure.Commands.Profile.Models.PSAzureEnvironment]$azureEnvironment ) {
$graphEnvironment = switch ( $azureEnvironment . ActiveDirectoryAuthority ) {
'https://login.microsoftonline.com/' { 'AzureCloud' }
'https://login.chinacloudapi.cn/' { 'AzureChinaCloud' }
'https://login-us.microsoftonline.com/' { 'AzureUSGovernment' }
'https://login.microsoftonline.de/' { 'AzureGermanCloud' }
Default { throw " Unsupported graph resource identifier: $_ " }
}
return $graphEnvironment
}
function Write-DecommissionImplicationsWarning {
$params = @ {
Message = ''
WarningAction = 'Inquire'
}
$params . Message + = 'You are removing access from an Azure Stack deployment to your directory tenant.'
$params . Message + = ' Users in your directory will be unable to access or manage any existing subscriptions in the Azure Stack deployment (access to any existing resources may be impaired if they require identity integration).'
if ( $AutomationCredential ) {
$params . WarningAction = 'Continue'
}
else {
$params . Message + = " Would you like to proceed? "
}
Write-Warning @params
}
$logFile = Join-Path -Path $PSScriptRoot -ChildPath " $DirectoryTenantName . $( Get-Date -Format MM-dd_HH -mm -ss_ms ) .log "
Write-Verbose " Logging additional information to log file ' $logFile ' " -Verbose
$logStartMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Beginning invocation of ' $( $MyInvocation . InvocationName ) ' with parameters: $( ConvertTo-Json $PSBoundParameters -Depth 4 ) "
$logStartMessage > > $logFile
try {
# Redirect verbose output to a log file
Invoke-Main 4 > > $logFile
$logEndMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Script completed successfully. "
$logEndMessage > > $logFile
}
catch {
2017-10-12 00:18:12 +03:00
$logErrorMessage = " [ $( Get-Date -Format 'hh:mm:ss tt' ) ] - Script terminated with error: $_ `r `n $( $_ . Exception ) "
$logErrorMessage > > $logFile
Write-Warning " An error has occurred; more information may be found in the log file ' $logFile ' " -WarningAction Continue
throw
}
2017-04-04 02:23:31 +03:00
}
2017-05-06 03:00:17 +03:00
Export-ModuleMember -Function @ (
2017-07-14 19:21:53 +03:00
" Register-AzsGuestDirectoryTenant " ,
2018-12-20 22:29:44 +03:00
" Update-AzsHomeDirectoryTenant " ,
2017-07-14 19:45:46 +03:00
" Register-AzsWithMyDirectoryTenant " ,
2018-02-09 23:50:57 +03:00
" Unregister-AzsGuestDirectoryTenant " ,
" Unregister-AzsWithMyDirectoryTenant " ,
2017-07-14 19:21:53 +03:00
" Get-AzsDirectoryTenantidentifier " ,
2019-04-24 19:45:00 +03:00
" Get-AzsHealthReport " ,
2017-07-05 01:23:06 +03:00
" New-AzsADGraphServicePrincipal "
2017-07-20 13:51:21 +03:00
)