Jorge's Quest For Knowledge!

All About Identity And Security On-Premises And In The Cloud – It's Just Like An Addiction, The More You Have, The More You Want To Have!

Archive for the ‘Azure AD Administrative Units’ Category

(2021-10-22) Azure AD Administrative Units – Dynamically Managing AU Assignments – Part 6

Posted by Jorge on 2021-10-22


Find PART 5 of this series HERE

[AD.6 – An Automation Account with a scheduled PowerShell Runbook for subsequent processing assignments]

To automate all this coolness you need an automation account that processes everything on a regular basis!

To create an automation account with all that is required, you can use the code below. Make sure to replace the parts corresponding to your own environment and requirements

Invoke-Command -ScriptBlock {
	Function retrieveTenantIDFromTenantFDQN () {
		Param (
			[string]$tenantFQDN
		)

		# Specify The Tenant Specific Discovery Endpoint URL
		$oidcConfigDiscoveryURL = $null
		$oidcConfigDiscoveryURL = "https://login.microsoftonline.com/$tenantFQDN/v2.0/.well-known/openid-configuration"
		$oidcConfigDiscoveryResult = $null

		# Retrieve The Information From The Discovery Endpoint URL
		$tenantID = $null
		$oidcConfigDiscoveryResult = $null
		Try {
			$oidcConfigDiscoveryResult = Invoke-RestMethod -Uri $oidcConfigDiscoveryURL -ErrorAction Stop
		}
		Catch {
			# Placeholder
		}

		# If There Is A Result Determine The Tenant ID
		If ($null -ne $oidcConfigDiscoveryResult) {
			$tenantID = $oidcConfigDiscoveryResult.authorization_endpoint.Split("/")[3]
		}

		Return $tenantID
	}

	Clear-Host

	# Tenant Details
	$tenantFQDN = "<SPECIFY YOUR TENANT FQDN>" # e.g. "<TENANT NAME>.ONMICROSOFT.COM"
	$tenantID = retrieveTenantIDFromTenantFDQN -tenantFQDN $tenantFQDN

	# Application Details
	$msftGraphMgmtAppApplicationID = "<SPECIFY YOUR APPLICATION ID>" # e.g. "56a7b6fe-06f9-5635-9e93-7e5ccacdc08e"

	# Private Key/Certificate Details
	$subjectName = "<SPECIFY THE SUBJECT NAME OF THE CERTIFICATE TO ACCES THE REGISTERED APPLICATION>" # e.g. "mgmt-Admin-Units-MSFT-Graph"
	$exportFolderPath = "<SPECIFY THE EXPORT FOLDER FOR THE PFX FILE>" # e.g. "C:\TEMP"
	$pfxOutputPath = Join-Path $exportFolderPath "$subjectName.pfx"
	$pfxPassword = '<SPECIFY THE PASSWORD PROTECTING THE PFX FILE>' # e.g. 'gLOPeVPMw93YaarLItOLFMF3Y5b6G90jehC1psMOfuZsyj04nElKc2yXrzf6YvHz'
	$pfxPasswordSecure = $(ConvertTo-SecureString $pfxPassword -AsPlainText -Force)

	# Connect Using Azure Automation
	Connect-AzAccount -TenantId $tenantID
	Get-AzSubscription -TenantId $tenantID
	Set-AzContext -Subscription $(Read-Host "Subscription ID...")
	
	# Details For The Automation Account And Runbook
	$displayName = "<SPECIFY THE DISPLAY NAME OF THE AUTOMATION ACCOUNT>" # e.g. "Managing-Admin-Unit-Assignments"
	$automationAccountDisplayName = "AutmationAccount-$displayName"
	$automationAccountLocation = "<SPECIFY THE AZURE LOCATION TO HOST THE AUTOMATION ACCOUNT>" # e.g. "West Europe"
	$automationAccountResourceGroup = "<SPECIFY THE RESOURCE GROUP NAME FOR THE AUTOMATION ACCOUNT>" # e.g. "RG-Automation"
	$automationAccountRunbookFilePath = "<SPECIFY THE FULL PATH TO THE POWERSHELL CODE FOR THE RUNBOOK>" # e.g. "<FULL FOLDER PATH>\AAD-Automated-Administrative-Unit-Assignment_Auto-Account-Runbook.ps1"

	# Create The Automation Account
	New-AzAutomationAccount -Name $automationAccountDisplayName -Location $automationAccountLocation -ResourceGroupName $automationAccountResourceGroup

	# Upload The PFX File Into The Automation Account
	New-AzAutomationCertificate -AutomationAccountName $automationAccountDisplayName -Name $subjectName -Path $pfxOutputPath -Password $pfxPasswordSecure -ResourceGroupName $automationAccountResourceGroup

	# Create The Required Variables
	New-AzAutomationVariable -AutomationAccountName $automationAccountDisplayName -Name "tenantFQDN" -Encrypted $False -Value $tenantFQDN -ResourceGroupName $automationAccountResourceGroup
	New-AzAutomationVariable -AutomationAccountName $automationAccountDisplayName -Name "appClientID" -Encrypted $False -Value $msftGraphMgmtAppApplicationID -ResourceGroupName $automationAccountResourceGroup

	# Import The PowerShell Script Into The Runbook Of The Automation Account And Publish It
	$runBookMgmtAUAssignments = Import-AzAutomationRunbook -Name "Runbook-$displayName" -Path $automationAccountRunbookFilePath -ResourceGroup $automationAccountResourceGroup -AutomationAccountName $automationAccountDisplayName -Type PowerShell -Published

	# Define A Schedule In The Automation Account
	$timeOfDayForRunbookToExec = "<SPECIFY THE TIME FOR THE RUNBOOK TO EXECUTE>" # e.g. "21:00:00"
	$startTime = (Get-Date $timeOfDayForRunbookToExec).AddHours(24)
	$autoAccountSchedule = New-AzAutomationSchedule -AutomationAccountName $automationAccountDisplayName -Name "Schedule-$displayName" -StartTime $startTime -DayInterval 1 -ResourceGroupName $automationAccountResourceGroup

	# Register The Previous Schedule For The Runbook To Execute
	Register-AzAutomationScheduledRunbook -RunbookName $($runBookMgmtAUAssignments.Name) -ResourceGroupName $automationAccountResourceGroup -AutomationAccountName $automationAccountDisplayName -ScheduleName $($autoAccountSchedule.Name)
}

Figure 1: Creation Of The Automation Account In Azure
Figure 2a: Configured Properties Of The Automation Account – Runbook
Figure 2b: Configured Properties Of The Automation Account – Schedule
Figure 2c: Configured Properties Of The Automation Account – Private Key And Certificate
Figure 2d: Configured Properties Of The Automation Account – Variables

You can now wait until the runbook executes manually, or you can start it on-demand if you wish!. Just make sure that when you start the runbook manually it completes, before it starts automatically.

Have fun and enjoy!

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided “AS IS” with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/

————————————————————————————————————————————————————-
########################### IAMTEC | Jorge’s Quest For Knowledge ##########################
#################### http://JorgeQuestForKnowledge.wordpress.com/ ###################

————————————————————————————————————————————————————

IAMTEC

Identity | Security | Recovery

————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, Azure AD Connect, Microsoft Graph, PowerShell, Tooling/Scripting, Windows Azure Active Directory | 1 Comment »

(2021-10-20) Azure AD Administrative Units – Dynamically Managing AU Assignments – Part 5

Posted by Jorge on 2021-10-20


Find PART 4 of this series HERE

[AD.5 – A PowerShell script for the initial processing assignment]

In general you would not need this initial processing script. However, that really depends on the size (i.e. amount of objects that need to be processed and assigned to AUs. In my test environment, I tried what is described in AD.6 initially and that worked. But because I was working with 100000+ objects that needed to be assigned to AUs, after 3 hours Azure AD stopped the script due to fair use policy.

I saw the following error message:

Stopped
The job has been stopped because it reached the fair share limit of job execution more than 3 hours. For long-running jobs, it’s recommended to use a Hybrid Runbook Worker. Hybrid Runbook Workers don’t have a limitation on how long a runbook can execute. Refer https://docs.microsoft.com/en-us/azure/automation/automation-runbook-execution#fair-share for more details.

Of course I could restarted the runbook or just wait until the schedule would kick in until it was stopped again. This happened at least 3 times. For long running runbooks, Microsoft suggest to use Hybrid Worker Runbooks. So, that’s why I decided to updated the script to be used from an on-premises computer/laptop/server/workstation after connecting to Azure AD. OK, that still takes quite some hours but, it was able to finish without being stopped after some hours of execution due to some limit. The script can be downloaded from HERE.

$tenantFQDN = "<SPECIFY YOUR TENANT FQDN>" # e.g. "<TENANT NAME>.ONMICROSOFT.COM"
$appClientID = "<SPECIFY THE APPLICATION CLIENT ID OF THE APP PREVIOUSLY CREATED>"
$pfxOutputPath = "<SPECIFY HERE THE FULL PATH TO THE PFX FILE>"
$pfxPassword = '<SPECIFY HERE THE PASSWORD PROTECTING THE PFX FILE>'

.\AAD-Automated-Administrative-Unit-Assignment.ps1 -tenantFQDN $tenantFQDN -appClientID $appClientID -pfxFilePath $pfxOutputPath -pfxPassword $pfxPassword

Figure 1a: The PowerShell Script Performing The Initial Assignment Of User And group Objects
Figure 1b: The PowerShell Script Performing The Initial Assignment Of User And group Objects
Figure 1c: The PowerShell Script Performing The Initial Assignment Of User And group Objects
Figure 1d: The PowerShell Script Performing The Initial Assignment Of User And group Objects

The whole processing will be visible in the Azure AD Audit Logs

Figure 2: All User And Group Assignments Or Unassignments Visible In The Azure AD Audit Logs

To be continued in PART 6 of this series.

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided “AS IS” with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/

————————————————————————————————————————————————————-
########################### IAMTEC | Jorge’s Quest For Knowledge ##########################
#################### http://JorgeQuestForKnowledge.wordpress.com/ ###################

————————————————————————————————————————————————————

IAMTEC

Identity | Security | Recovery

————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, Azure AD Connect, Microsoft Graph, PowerShell, Tooling/Scripting, Windows Azure Active Directory | 2 Comments »

(2021-10-18) Azure AD Administrative Units – Dynamically Managing AU Assignments – Part 4

Posted by Jorge on 2021-10-18


Find PART 3 of this series HERE

[AD.4 – A registered application with the correct permissions to manage the AU assignments]

To be able to assign objects (users and groups) in an automatic manner to Administrative Units, a registered application is needed with the correct application permissions (not delegated permissions) to assign the objects that match the filter to the corresponding Administrative Unit.

The following permissions are required:

  • Group.Read.All
  • User.Read.All
  • AdministrativeUnit.ReadWrite.All

After configuring the permissions, those permissions also need to be consented before you can actually use them.

To control the application in a secure authenticated manner, either a client secret can be used or a certificate. I those to use a certificate as that requires possession (private key) and knowledge (password for private key) instead of just knowledge (secret).

The code below will create a self-signed certificate on your local computer, export that to a CER and PFX (protected with a password) and then delete the certificate and private key from the local computer store. It will also present the password on screen for you to copy it to a secure location! Make sure to store the PFX file and its corresponding password in a secure place.

Invoke-Command -ScriptBlock {
	Clear-Host
	
	# The Subject Name
	$subjectName = "<SPECFIFY THE SUBJECT NAME FOR THE CERTIFICATE>" # e.g. "mgmt-Admin-Units-MSFT-Graph"

	# Tenant Details
	$tenantFQDN = "<SPECFIFY YOUR TENANT FQDN>" # e.g. "<TENANT NAME>.ONMICROSOFT.COM"

	# Certificate Store Location
	$certStoreLocation = "Cert:\CurrentUser\My"

	# Where To Export The Certificate And The Private Key
	$exportFolderPath = "<Folder Path To Export The Certificate Data To>" # e.g. "C:\TEMP"
	$cerOutputPath = Join-Path $exportFolderPath "$subjectName.cer"
	$pfxOutputPath = Join-Path $exportFolderPath "$subjectName.pfx"

	# Splat For Readability
	$createCertificateSplat = @{
		Type				= "Custom"
		Subject				= $subjectName
		KeyFriendlyName		= $subjectName
		KeyDescription		= $subjectName
		FriendlyName		= $subjectName
		DnsName				= $tenantName
		CertStoreLocation	= $certStoreLocation
		Provider			= "Microsoft Enhanced RSA and AES Cryptographic Provider"
		KeySpec				= "KeyExchange"
		KeyUsage			= @("None")
		HashAlgorithm		= "SHA256"
		KeyAlgorithm		= "RSA"
		KeyLength			= 2048
		NotBefore			= $([datetime]::now.AddHours(-1))
		NotAfter			= $([datetime]::now.AddDays(1185)) # 3 Years and 3 months | This is to make sure the process always start in the same period as it otherwise will crawl back!
		KeyExportPolicy		= "Exportable"
	}

	# Create Certificate
	$certificate = New-SelfSignedCertificate @createCertificateSplat

	# Get Certificate Path
	$certificatePath = Join-Path -Path $certStoreLocation -ChildPath $certificate.Thumbprint

	# Generate A Password
	# This only contains numeric and alphanumeroc characters and not any special characters to prevent issues when uploading the private keys and certs.
	# The max length of the generated password depends on the number of available characters, hence repeating the list of characters to allow very long passwords if needed
	$pfxPassword = $(-join (48..57+65..90+97..122+48..57+65..90+97..122+48..57+65..90+97..122+48..57+65..90+97..122 | ForEach-Object {[char]$_} | Get-Random -Count 64))
	$pfxPasswordSecure = $(ConvertTo-SecureString $pfxPassword -AsPlainText -Force)

	# Export Certificate Without Private Key
	Export-Certificate -Cert $certificatePath -FilePath $cerOutputPath | Out-Null
	Export-PfxCertificate -Cert $certificatePath -FilePath $pfxOutputPath -Password $pfxPasswordSecure | Out-Null

	# Deleting The Private Key And Certificate
	Set-Location $certStoreLocation
	Get-ChildItem $($certificate.Thumbprint) | Remove-Item -DeleteKey -ErrorAction SilentlyContinue | Out-Null

	# Displaying The File Paths Of The Exported CER/PFX File
	Write-Host ""
	Write-Host " > File Path For Exported CER File...: '$cerOutputPath'" -ForegroundColor Yellow
	Write-Host " > File Path For Exported PFX File...: '$pfxOutputPath'" -ForegroundColor Yellow

	# Displaying The Password For 60 Seconds. After That The Screen And The Variables Are Cleared
	Write-Host ""
	Write-Host "! ! ! Store The Password Of The Private Key In A Safe Location ! ! !" -ForegroundColor Red
	Write-Host "WARNING: In 60 Seconds The Screen And Variables Will Be Cleared. Copy The Password Value A.S.A.P.!!!" -ForegroundColor White
	Write-Host " > 'PFX Password'.................: '$pfxPassword'" -ForegroundColor Yellow
	Write-Host "! ! ! Store The Password Of The Private Key In A Safe Location ! ! !" -ForegroundColor Red
	Write-Host ""
	Start-Sleep -s 60
	$certificate = $null
	$pfxPassword = $null
	$pfxPasswordSecure = $null
	Set-Location C:\
	Clear-Host
}
Figure 1: Creating A Self-Signed Certificate And Exporting It
– 

Now we can create the application, configure the required permissions, consent those and upload the certificate to the registered application. Consenting will be done in a semi-automated manner using the device code flow. Run this code in the previous PowerShell window where you already connected to Azure AD.

Invoke-Command -ScriptBlock {
	Function retrieveTenantIDFromTenantFDQN () {
		Param (
			[string]$tenantFQDN
		)

		# Specify The Tenant Specific Discovery Endpoint URL
		$oidcConfigDiscoveryURL = $null
		$oidcConfigDiscoveryURL = "https://login.microsoftonline.com/$tenantFQDN/v2.0/.well-known/openid-configuration"
		$oidcConfigDiscoveryResult = $null

		# Retrieve The Information From The Discovery Endpoint URL
		$tenantID = $null
		$oidcConfigDiscoveryResult = $null
		Try {
			$oidcConfigDiscoveryResult = Invoke-RestMethod -Uri $oidcConfigDiscoveryURL -ErrorAction Stop
		}
		Catch {
			# Placeholder
		}

		# If There Is A Result Determine The Tenant ID
		If ($null -ne $oidcConfigDiscoveryResult) {
			$tenantID = $oidcConfigDiscoveryResult.authorization_endpoint.Split("/")[3]
		}

		Return $tenantID
	}
	
	Clear-Host

	# Load Assembly To Use The URLEncode Function
	Add-Type -AssemblyName System.Web

	# Load Assembly To Use MessageBox
	Add-Type -assemblyName PresentationFramework

	# Generic Details
	$msftGraphFQDN = "graph.microsoft.com" # FQDN For Microsoft Graph

	# Tenant Details
	$tenantFQDN = "<SPECFIFY YOUR TENANT FQDN>" # e.g. "<TENANT NAME>.ONMICROSOFT.COM"
	$tenantID = retrieveTenantIDFromTenantFDQN -tenantFQDN $tenantFQDN
	$tenantName = "<SPECFIFY YOUR TENANT NAME>"

	# Where To Import The Certificate From
	$subjectName = "<SPECFIFY THE SUBJECT NAME FOR THE CERTIFICATE>" # e.g. "mgmt-Admin-Units-MSFT-Graph"
	$exportFolderPath = "<Folder Path To Export The Certificate Data To>" # e.g. "C:\TEMP"
	$cerOutputPath = Join-Path $exportFolderPath "$subjectName.cer"
	$pfxOutputPath = Join-Path $exportFolderPath "$subjectName.pfx"

	# Azure AD Device Code Request Endpoint URL
	$aadDeviceCodeRequestEndpointURL = "https://login.microsoftonline.com/$tenantID/oauth2/devicecode"

	# Device Code Approval Endpoint URL
	$deviceCodeApprovalEndpointURL = "https://www.microsoft.com/devicelogin"

	# Application Details
	$msftGraphMgmtAppDisplayName = "<SPECIFY THE APPLICATION DISPLAY NAME OF THE REGISTERED APPLICATION>" # Example: "<TENANT NAME>: Mgmt App - Managing Automatic AU Assignments"
	$msftGraphMgmtAppIdentifierURI = "https://$tenantName.onmicrosoft.com/$($msftGraphMgmtAppDisplayName.Replace(" ","-").Replace("---","-").Replace(":-","-"))"
	$msftGraphMgmtAppReplyURL = "https://$($msftGraphMgmtAppDisplayName.Replace(" ","-").Replace("---","-").Replace(":-","-"))"

	# Required Resource Access, In Other Words The Required Permissions
	$requiredResourceAccessPSObjectListMSFTGraphMgmtApp = @(
		[PSCustomObject]@{
			resourceAppId = "00000003-0000-0000-c000-000000000000"	# MSFT Graph => (Get-AzureADServicePrincipal -filter "DisplayName eq 'Microsoft Graph'")
			resourceAccess = @(
				@{
					id = "5eb59dd3-1da2-4329-8733-9dabdc435916"		# AdministrativeUnit.ReadWrite.All => (Get-AzureADServicePrincipal -filter "DisplayName eq 'Microsoft Graph'").AppRoles | ?{$_.Value -eq "AdministrativeUnit.ReadWrite.All"}
					type = "Role"
				},
				@{
					id = "5b567255-7703-4780-807c-7be8301ae99b"		# Group.Read.All => (Get-AzureADServicePrincipal -filter "DisplayName eq 'Microsoft Graph'").AppRoles | ?{$_.Value -eq "Group.Read.All"}
					type = "Role"
				},
				@{
					id = "df021288-bdef-4463-88db-98f22de89214"		# User.Read.All => (Get-AzureADServicePrincipal -filter "DisplayName eq 'Microsoft Graph'").AppRoles | ?{$_.Value -eq "User.Read.All"}
					type = "Role"
				}
			)
		}
	)
	$requiredResourceAccessListMSFTGraphMgmtApp = @()
	ForEach($resourceApp in $requiredResourceAccessPSObjectListMSFTGraphMgmtApp) {
		$requiredResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
		$requiredResourceAccess.ResourceAppId = $resourceApp.resourceAppId
		ForEach($resourceAccess in $resourceApp.resourceAccess) {
			$requiredResourceAccess.resourceAccess += New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList $resourceAccess.Id,$resourceAccess.type
		}
		$requiredResourceAccessListMSFTGraphMgmtApp += $requiredResourceAccess
	}

	# Creating The App Registration
	$msftGraphMgmtApp = New-AzureADApplication -DisplayName $msftGraphMgmtAppDisplayName -IdentifierUris $msftGraphMgmtAppIdentifierURI -ReplyUrls @($msftGraphMgmtAppReplyURL) -RequiredResourceAccess $requiredResourceAccessListMSFTGraphMgmtApp
	$msftGraphMgmtAppObjectID = $msftGraphMgmtApp.ObjectID
	$msftGraphMgmtAppApplicationID = $msftGraphMgmtApp.AppId
	Start-Sleep -s 10

	# Creating The Service Principal
	$msftGraphMgmtSvcPrinc = New-AzureADServicePrincipal -DisplayName $msftGraphMgmtAppDisplayName -AppId $msftGraphMgmtAppApplicationID -AccountEnabled $true -AppRoleAssignmentRequired $false
	$msftGraphMgmtSvcPrincObjectID = $msftGraphMgmtSvcPrinc.ObjectID
	$msftGraphMgmtSvcPrincApplicationID = $msftGraphMgmtSvcPrinc.AppId
	Start-Sleep -s 10

	# Uploading The Certificate To The Application Registration
	$msftGraphMgmtCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
	$msftGraphMgmtCert.Import($cerOutputPath)
	$msftGraphMgmtCertRawData = $msftGraphMgmtCert.GetRawCertData()
	$msftGraphMgmtCertCERBase64 = [System.Convert]::ToBase64String($msftGraphMgmtCertRawData) # Base64 Encode The Public Key
	$msftGraphMgmtCertHash = $msftGraphMgmtCert.GetCertHash() # Get The Custom Key Identifier
	$msftGraphMgmtCertCustomKeyIdentifier = [System.Convert]::ToBase64String($msftGraphMgmtCertHash)
	$msftGraphMgmtCertNotBeforeISO8601Format = (Get-Date $($msftGraphMgmtCert.NotBefore)).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") # Date In ISO8601Format
	$msftGraphMgmtCertNotAfterISO8601Format = (Get-Date $($msftGraphMgmtCert.NotAfter)).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ") # Date In ISO8601Format
	New-AzureADApplicationKeyCredential -ObjectId $msftGraphMgmtAppObjectID -Type AsymmetricX509Cert -Usage Verify -CustomKeyIdentifier $msftGraphMgmtCertCustomKeyIdentifier  -Value $msftGraphMgmtCertCERBase64 -StartDate $msftGraphMgmtCertNotBeforeISO8601Format -EndDate $msftGraphMgmtCertNotAfterISO8601Format | Out-Null

	# Grant Consent To The Required Permissions - Build The Request Body To Request A Device/User Code From MSFT Graph
	$msftGraphDeviceCodeRequestBody = @()
	$msftGraphDeviceCodeRequestBody += "resource=$([System.Web.HttpUtility]::UrlEncode($('https://' + $msftGraphFQDN + '/')))"
	$msftGraphDeviceCodeRequestBody += "&client_id=$msftGraphMgmtAppApplicationID"
	$deviceTokenRequestResponse = Invoke-RestMethod -uri $aadDeviceCodeRequestEndpointURL -ContentType "application/x-www-form-urlencoded" -Method POST -Body $msftGraphDeviceCodeRequestBody -ErrorAction Stop
	$msftGraphDeviceCodeResponseUserCode = $deviceTokenRequestResponse.user_code

	# Grant Consent To The Required Permissions - Put The User Code In The Clipboard To Paste It Later As Needed
	Set-Clipboard -Value $msftGraphDeviceCodeResponseUserCode

	# Grant Consent To The Required Permissions - Present A Notification On What To Do Next
	[System.Windows.MessageBox]::Show("A device code has been requested from Azure AD. For this device code the corresponding user code ($msftGraphDeviceCodeResponseUserCode) has been copied to the clipboard. After clicking [OK] an authentication screen will be opened. On that new screen just paste the user code by pressing [CTRL]+[V] and then click [NEXT] to authenticate with your Global Admin Credentials for the AAD Tenant:`n`nTenant FQDN....: '$tenantFQDN'`nTenant ID..........: '$tenantID'`nUser Code.........: '$msftGraphDeviceCodeResponseUserCode'", "Device Code Authentication - Please Read Carefully", 0, 64) | Out-Null

	# Grant Consent To The Required Permissions - Navigate To The Device Approcal URL For The Actual Consent
	[System.Diagnostics.Process]::Start($deviceCodeApprovalEndpointURL)
}
Figure 2: After Requesting The Device Code And User Code To Consent The Application Permissions
– 
Figure 3: Specifying The User Code To Continue Authentication Followed By Consent Of Application Permissions
– 
Figure 4: Signing-In Before Consenting The Required Permissions For The Registered App
– 
Figure 5: Reviewing The Required Permissions For The Registered App
– 
Figure 6: Reviewing The Required Permissions For The Registered App
Figure 7: The Configured Certificate For The Registered App Managing The Automatic AU Assignments
Figure 8: The Configured And Consented Permissions For The Registered App Managing The Automatic AU Assignments

To be continued in PART 5 of this series.

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided “AS IS” with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/

————————————————————————————————————————————————————-
########################### IAMTEC | Jorge’s Quest For Knowledge ##########################
#################### http://JorgeQuestForKnowledge.wordpress.com/ ###################

————————————————————————————————————————————————————

IAMTEC

Identity | Security | Recovery

————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, Azure AD Connect, Microsoft Graph, PowerShell, Tooling/Scripting, Windows Azure Active Directory | 2 Comments »

(2021-10-16) Azure AD Administrative Units – Dynamically Managing AU Assignments – Part 3

Posted by Jorge on 2021-10-16


Find PART 2 of this series HERE

[AD.3 – Administrative Units with logic to support some kind of query rules]

Now the data ended up in Azure AD, it is time to start configuring Azure (AD) to support the dynamic assignment for AUs. But first I needed to create the AUs in Azure AD, and although not needed for this exercise I also configured delegation along the way! For that I first created Azure AD security groups that could be assigned role, and then after creating the AU and the groups I assigned the group for the AU the corresponding role for that AU also. 

Dynamic groups in Azure AD contain the property with the filter that looks for user objects matching that filter. In other words, the filter itself is stored on the object that needs and uses that filter. With that thought in mind I had to implement something similar for AUs. Unfortunately it appeared not to be possible to extend the Azure AD schema for “AdministrativeUnit” objects. That would have been the best option for this exercise. Therefore I had to reuse an existing attribute that I have control over. That list of attributes is not that big. I had “DisplayName” and “Description”. In this case I chose to (mis)use the “Description” attribute of the AdministrativeUnit object.

I came up with the following structure for the “Description” attribute:

”<real description|filter:user=<filter targeting user objects>|filter:group=<filter targeting user objects>”

Example: “All Test Accounts For AT – Austria|filter:user=Department eq ‘SampleData’ and Country eq ‘Austria’|filter:group=extension_b3d7ffeca7f24ab6bf35bb6ff4918986_department eq ‘SampleData’ and extension_b3d7ffeca7f24ab6bf35bb6ff4918986_location eq ‘Austria’

If you look at the code you see some sleep timers. I had to implement those to make sure that Azure AD had completely instantiated the group so that it could be used in the role assignment.

Invoke-Command -ScriptBlock {
	Function retrieveTenantIDFromTenantFDQN () {
		Param (
			[string]$tenantFQDN
		)

		# Specify The Tenant Specific Discovery Endpoint URL
		$oidcConfigDiscoveryURL = $null
		$oidcConfigDiscoveryURL = "https://login.microsoftonline.com/$tenantFQDN/v2.0/.well-known/openid-configuration"
		$oidcConfigDiscoveryResult = $null

		# Retrieve The Information From The Discovery Endpoint URL
		$tenantID = $null
		$oidcConfigDiscoveryResult = $null
		Try {
			$oidcConfigDiscoveryResult = Invoke-RestMethod -Uri $oidcConfigDiscoveryURL -ErrorAction Stop
		}
		Catch {
			# Placeholder
		}

		# If There Is A Result Determine The Tenant ID
		If ($null -ne $oidcConfigDiscoveryResult) {
			$tenantID = $oidcConfigDiscoveryResult.authorization_endpoint.Split("/")[3]
		}

		Return $tenantID
	}

	Clear-Host

	# Tenant Details
	$tenantFQDN = "<SPECFIFY YOUR TENANT FQDN>"
	$tenantID = retrieveTenantIDFromTenantFDQN -tenantFQDN $tenantFQDN

	# Connect To Azure AD
	Connect-AzureAD -TenantId $tenantID

	# Get The Required Azure AD Roles For The AU Delegation
	$aadDirectoryRoles = Get-AzureADDirectoryRole
	$adminRoleGroups = $aadDirectoryRoles | Where-Object { $_.DisplayName -eq "Groups Administrator" }
	$adminRoleAuthN = $aadDirectoryRoles | Where-Object { $_.DisplayName -eq "Authentication Administrator" }
	$adminRoleHelpdesk = $aadDirectoryRoles | Where-Object { $_.DisplayName -eq "Helpdesk Administrator" }
	$adminRoleUsers = $aadDirectoryRoles | Where-Object { $_.DisplayName -eq "User Administrator" }

	# Build A List Of Data To Create And Configure AUs
	$auData = @()
	$auData += "AT|Austria"
	$auData += "AU|Australia"
	$auData += "BE|Belgium"
	$auData += "BR|Brazil"
	$auData += "CA|Canada"
	$auData += "CH|Switzerland"
	$auData += "CY|Cyprus (Anglicized)"
	$auData += "CZ|Czech Republic"
	$auData += "DE|Germany"
	$auData += "DK|Denmark"
	$auData += "EE|Estonia"
	$auData += "ES|Spain"
	$auData += "FI|Finland"
	$auData += "FR|France"
	$auData += "GB|United Kingdom"
	$auData += "GL|Greenland"
	$auData += "HU|Hungary"
	$auData += "IS|Iceland"
	$auData += "IT|Italy"
	$auData += "NL|Netherlands"
	$auData += "NO|Norway"
	$auData += "NZ|New Zealand"
	$auData += "PL|Poland"
	$auData += "PT|Portugal"
	$auData += "SE|Sweden"
	$auData += "SI|Slovenia"
	$auData += "TN|Tunisia"
	$auData += "US|United States"
	$auData += "UY|Uruguay"
	$auData += "ZA|South Africa"
	$auData += "HIST1|HISTORY1"
	$auData += "HIST2|HISTORY2"
	$auData += "EDUC|EDUCATIONAL"
	$auData += "EMPL|EMPLOYEES"
	$auData += "CONT|CONTRACTORS"

	Write-Host ""
	Write-Host "Creating Administrative Units In The Azure AD Tenant..." -ForegroundColor Cyan
	$auData | ForEach-Object {
		$au = $_
		$auCountryCode = $au.Split("|")[0]
		$auCountry = $au.Split("|")[1]
		
		# Creating The AU
		Write-Host " > Creating Administrative Unit 'Accounts - Test - $auCountryCode - $auCountry'..." -ForegroundColor Magenta
		If ($auCountryCode.Length -eq 2) {
			$auObject = New-AzureADMSAdministrativeUnit -DisplayName "Accounts - Test - $auCountryCode - $auCountry" -Description "All Test Accounts For $auCountryCode - $auCountry|filter:user=Department eq 'SampleData' and Country eq '$auCountry'|filter:group=extension_b3d7ffeca7f24ab6bf35bb6ff4918986_department eq 'SampleData' and extension_b3d7ffeca7f24ab6bf35bb6ff4918986_location eq '$auCountry'"
		}
		Else {
			$auObject = New-AzureADMSAdministrativeUnit -DisplayName "Accounts - Test - $auCountryCode - $auCountry" -Description "All Test Accounts For $auCountryCode - $auCountry|filter:user=extension_b3d7ffeca7f24ab6bf35bb6ff4918986_employeeType eq '$auCountry'|filter:group=NA"
		}
		Start-Sleep -s 5
		
		# Creating Admin Groups For The AU
		Write-Host "   # Creating Admin Group 'cld-AAD-Mgmt-AU-$auCountryCode-$auCountry-Groups-Admin' For The AU..." -ForegroundColor Yellow
		$adminGroups = New-AzureADMSGroup -DisplayName "cld-AAD-Mgmt-AU-$auCountryCode-$auCountry-Groups-Admin" -Description "Groups Admins For AU: Accounts - Test - $auCountryCode - $auCountry" -MailEnabled $false -MailNickName $( -join (48..57 + 65..90 + 97..122 | ForEach-Object { [char]$_ } | Get-Random -Count 10)) -SecurityEnabled $true -IsAssignableToRole $true
		
		Write-Host "   # Creating Admin Group 'cld-AAD-Mgmt-AU-$auCountryCode-$auCountry-AuthN-Admin' For The AU..." -ForegroundColor Yellow
		$adminAuthN = New-AzureADMSGroup -DisplayName "cld-AAD-Mgmt-AU-$auCountryCode-$auCountry-AuthN-Admin" -Description "AuthN Admins For AU: Accounts - Test - $auCountryCode - $auCountry" -MailEnabled $false -MailNickName $( -join (48..57 + 65..90 + 97..122 | ForEach-Object { [char]$_ } | Get-Random -Count 10)) -SecurityEnabled $true -IsAssignableToRole $true
		
		Write-Host "   # Creating Admin Group 'cld-AAD-Mgmt-AU-$auCountryCode-$auCountry-Helpdesk-Admin' For The AU..." -ForegroundColor Yellow
		$adminHelpdesk = New-AzureADMSGroup -DisplayName "cld-AAD-Mgmt-AU-$auCountryCode-$auCountry-Helpdesk-Admin" -Description "Helpdesk Admins For AU: Accounts - Test - $auCountryCode - $auCountry" -MailEnabled $false -MailNickName $( -join (48..57 + 65..90 + 97..122 | ForEach-Object { [char]$_ } | Get-Random -Count 10)) -SecurityEnabled $true -IsAssignableToRole $true
		
		Write-Host "   # Creating Admin Group 'cld-AAD-Mgmt-AU-$auCountryCode-$auCountry-Users-Admin' For The AU..." -ForegroundColor Yellow
		$adminUsers = New-AzureADMSGroup -DisplayName "cld-AAD-Mgmt-AU-$auCountryCode-$auCountry-Users-Admin" -Description "Users Admins For AU: Accounts - Test - $auCountryCode - $auCountry" -MailEnabled $false -MailNickName $( -join (48..57 + 65..90 + 97..122 | ForEach-Object { [char]$_ } | Get-Random -Count 10)) -SecurityEnabled $true -IsAssignableToRole $true
		Start-Sleep -s 20
		
		# Configure Admin Role Assignment For The AU
		Write-Host "   # Assigning The Role '$($adminRoleGroups.DisplayName)' To The Group '$($adminGroups.DisplayName)'..." -ForegroundColor Yellow
		$adminGroupsRoleInfo = New-Object -TypeName Microsoft.Open.MSGraph.Model.MsRoleMemberInfo -Property @{Id = $adminGroups.Id }
		Add-AzureADMSScopedRoleMembership -RoleId $adminRoleGroups.ObjectId -Id $auObject.Id -RoleMemberInfo $adminGroupsRoleInfo | Out-Null
		
		Write-Host "   # Assigning The Role '$($adminRoleAuthN.DisplayName)' To The Group '$($adminAuthN.DisplayName)'..." -ForegroundColor Yellow
		$adminAuthNRoleInfo = New-Object -TypeName Microsoft.Open.MSGraph.Model.MsRoleMemberInfo -Property @{Id = $adminAuthN.Id }
		Add-AzureADMSScopedRoleMembership -RoleId $adminRoleAuthN.ObjectId -Id $auObject.Id -RoleMemberInfo $adminAuthNRoleInfo | Out-Null
		
		Write-Host "   # Assigning The Role '$($adminRoleHelpdesk.DisplayName)' To The Group '$($adminHelpdesk.DisplayName)'..." -ForegroundColor Yellow
		$adminHelpdeskRoleInfo = New-Object -TypeName Microsoft.Open.MSGraph.Model.MsRoleMemberInfo -Property @{Id = $adminHelpdesk.Id }
		Add-AzureADMSScopedRoleMembership -RoleId $adminRoleHelpdesk.ObjectId -Id $auObject.Id -RoleMemberInfo $adminHelpdeskRoleInfo | Out-Null
		
		Write-Host "   # Assigning The Role '$($adminRoleUsers.DisplayName)' To The Group '$($adminUsers.DisplayName)'..." -ForegroundColor Yellow
		$adminUsersRoleInfo = New-Object -TypeName Microsoft.Open.MSGraph.Model.MsRoleMemberInfo -Property @{Id = $adminUsers.Id }
		Add-AzureADMSScopedRoleMembership -RoleId $adminRoleUsers.ObjectId -Id $auObject.Id -RoleMemberInfo $adminUsersRoleInfo | Out-Null
		
		Write-Host ""
	}
}
Figure 1: Creating The AUs, The Delegation Groups And Configuring The Delegation Roles In Azure AD
– 

To be continued in PART 4 of this series.

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided “AS IS” with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/

————————————————————————————————————————————————————-
########################### IAMTEC | Jorge’s Quest For Knowledge ##########################
#################### http://JorgeQuestForKnowledge.wordpress.com/ ###################

————————————————————————————————————————————————————

IAMTEC

Identity | Security | Recovery

————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, Azure AD Connect, Microsoft Graph, PowerShell, Tooling/Scripting, Windows Azure Active Directory | 2 Comments »

(2021-10-14) Azure AD Administrative Units – Dynamically Managing AU Assignments – Part 2

Posted by Jorge on 2021-10-14


Find PART 1 of this series HERE

[AD.2 – Azure AD Connect configuration to sync the required data to Azure AD]

Hybrid Scenario ONLY

Azure AD Connect is THE TOOL to sync data between AD and Azure AD and vice versa as supported. You need to check if the data you need in Azure AD from AD is already being synched or not. If it is not synched already because no sync rules exists, see if those attribute can be configured in sync rules (Inbound Sync from AD and Outbound Sync to Azure AD). If you cannot create a sync rule from existing attributes you need to update the Azure AD Connect configuration by either selecting the required attribute or use the Directory Extension Attribute Sync feature.

To do this start the Azure AD Connect Wizard and choose the option “Customize Synchronization Options”. When reaching the “Optional Features” section, if the option “Directory Extension Attribute Sync” feature is not yet checked, do not check it for now. Click [Next]

Figure 1: Azure AD Connect Configuration Wizard – Optional Features Section

When reaching the “Azure AD Attributes” section, see if the required attribute is already selected or not. If it is not yet selected, selected it. If the attribute is not listed, then go back to the “Optional Features” section and check the option “Directory Extension Attribute Sync” feature if it was not yet selected. If it was already checked, then continue by clicking [Next].

Figure 2: Azure AD Connect Configuration Wizard – Azure AD Attributes Section

When reaching the “Directory Extensions” section, select the attributes for which Azure AD Connect should create a new extension in the Azure AD schema for the scoped object. Continue by clicking [Next] and completing the wizard until the end.

Figure 3: Azure AD Connect Configuration Wizard – Directory Extensions Section

Azure AD Connect implements the “Directory Extension Attribute Sync” feature by creating a app registration in Azure AD called “Tenant Schema Extension App”. That’s the app that stores all Azure AD Connect configured schema extensions for Azure AD. Looking up the app you can fond all the extensions (mine has more than needed for this exercise, but that’s due to different tests)

Get-AzureADApplication -SearchString "Tenant Schema Extension App" | Get-AzureADApplicationExtensionProperty | FL
Figure 4: Extensions In The Azure AD Schema Implemented By Azure AD Connect

After this, you need to create the sync rules. That is done by the Azure AD Connect Sync Rule Editor. For this exercise “Department” and “Country” for user objects was already being synched because during my initial installation I selected all the Azure AD Attributes (Figure 1 and 2). I only had to add sync rules for the extension attributes

WARNING: As soon as you edit any sync rule, during the next sync cycle, Azure AD Connect will perform a Ful Sync end-to-end. If you have many objects being synched this might take some time and because of that it may require planning!

Start the Azure AD Connect Sync Rule Editor.

Select the appropriate custom AD inbound sync for user objects and add the attributes that need to be synched. If no custom rule exists, select the appropriate default AD inbound sync rule for user objects and clone it. Then edit the clone.

Select the appropriate custom AD inbound sync for groups objects and add the attributes that need to be synched. If no custom rule exists, select the appropriate default AD inbound sync rule for group objects and clone it. Then edit the clone.

Select the appropriate custom AAD outbound sync for user objects and add the attributes that need to be synched.If no custom rule exists, select the appropriate default AAD outbound sync rule for user objects and clone it. Then edit the clone.

Select the appropriate custom AAD outbound sync for group objects and add the attributes that need to be synched.If no custom rule exists, select the appropriate default AAD outbound sync rule for group objects and clone it. Then edit the clone.

If you used the “Directory Extension Attribute Sync” feature then Azure AD Connect already updated the appropriate sync rules. Check for the sync rules for users and groups, inbound and outbound, that contain the word “DirectoryExtension”

Figure 5: Attribute Flow Transformation In The AD Inbound Sync Rule For User Objects And Directory Extensions
Figure 6: Attribute Flow Transformation In The AAD Outbound Sync Rule For User Objects And Directory Extensions
Figure 7: Attribute Flow Transformation In The AD Inbound Sync Rule For Group Objects And Directory Extensions
Figure 8: Attribute Flow Transformation In The AAD Outbound Sync Rule For Group Objects And Directory Extensions
Figure 9: Attribute Flow Transformation In The AD Inbound Sync Rule For Group Objects And Directory Extensions
Figure 10: Attribute Flow Transformation In The AAD Outbound Sync Rule For Group Objects And Directory Extensions

After having this configured, I enabled the sync schedule again to allow Azure AD Connect perform a Full Sync

To be continued in PART 3 of this series.

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided “AS IS” with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/

————————————————————————————————————————————————————-
########################### IAMTEC | Jorge’s Quest For Knowledge ##########################
#################### http://JorgeQuestForKnowledge.wordpress.com/ ###################

————————————————————————————————————————————————————

IAMTEC

Identity | Security | Recovery

————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, Azure AD Connect, Microsoft Graph, PowerShell, Tooling/Scripting, Windows Azure Active Directory | 2 Comments »

(2021-10-12) Azure AD Administrative Units – Dynamically Managing AU Assignments – Part 1

Posted by Jorge on 2021-10-12


Quite some time ago I blogged about Azure AD Administrative Units (AU). The details can be found in the found through the following blog posts:

And more recently:

Microsoft documentation: https://docs.microsoft.com/en-us/azure/active-directory/roles/administrative-units

In my most recent article about Administrative Units I already summarized how interesting it is to use Administrative Units in those scenarios where delegation of admin is required. Nevertheless, I think one of the very interesting features is unfortunately not (yet) supported!

Figure 1: Administrative Units In Azure AD – Management Supported/Unsupported Options

Automating assigning user and group objects to specific Administrative Units would seriously have a lot of manual work. Unless you have something external to Azure AD regarding the logic and execution leveraging the Microsoft graph, by default Azure AD does not support that, today. Hopefully it will be soon, as I think many want to get rid of the manual burden or any custom solution. Until automatic assignment is supported/possible by Azure AD itself, you may be able to use what is in this post. Please be aware this is an example and that if you want to use this for your own environment, you need to customize the filters/configurations to that data in your Azure AD tenant!

Interesting enough, I have found a way to automatically assign user/groups, based upon attributes of those objects, to specific administrative units. This blog is fully dedicated to that! So please hang on, keep reading and in the end you might end up with a solution that might work for you!

DISCLAIMER: please make sure to test this in a TEST environment/tenant first and improve where needed!

For all this to work we need the following components:

  1. Objects with attributes and values in those attributes to be able to use in filters
    1. Hybrid scenario
    2. Cloud only scenario
  2. Azure AD Connect configuration to sync the required data to Azure AD
    1. Hybrid scenario ONLY
  3. Administrative Units with logic to support some kind of query rules
  4. A registered application with the correct permissions to manage the AU assignments
  5. A PowerShell script for the initial processing assignment
  6. An Automation Account with a scheduled PowerShell Runbook for subsequent processing assignments

So, let’s get started!

[AD.1 – Objects with attributes and values in those attributes to be able to use in filters]

Hybrid Scenario

In my on-premises test and demo AD I have about 100000+ user objects and also lots of groups. For this exercise I needed a data set of users and groups. For that I chose the objects in the 5 category OUs and the objects in the country OUs. For every of the yellow marked OUs, an AU will be created in Azure AD. In the country OUs both users and groups are (already) being synched to Azure AD. In the category OUs only users are being synched to Azure AD. In both cases Azure AD Connect is doing the synching,

Figure 2: OUs In AD With Objects Being Synched To Azure AD

The AUs in Azure AD need to have objects assigned automatically based upon some data to be queried in filters. So you need to think about the AUs you want to create and how to decide, which objects will go into which AUs and what data will be used to make those decisions. If the data is not there (yet) you need to populate that data in AD from some system that has it.

In this example scenario I made the following decisions:

  • user objects in the country OUs
    • “department” attribute being equal to the fixed string “SampleData”
    • “country” attribute being equal to the string “<country name>” (e.g. Netherlands)
  • group objects in the country OUs
    • “department” attribute being equal to the fixed string “SampleData”
    • “location” attribute being equal to the string “<country name>” (e.g. Netherlands)
  • user objects in the category OUs
    • “employeeType” attribute being equal to the string “<employee category>” (e.g. CONTRACTORS)
  • group objects in the category OUs
    • N.A. (not being synched)
Figure 3: Sample Data For User Objects In The Country OUs
Figure 4: Sample Data For Group Objects In The Country OUs
Figure 5: Sample Data For User Objects In The Category OUs

Cloud Scenario

For objects authoritatively created in Azure AD, you will have to make sure those objects (users and groups) have the required data stored in some attribute. You may even need to extend the Azure AD schema to store the data if no attribute contains the data you require.

To read more about extending the Azure AD schema, please check out the following posts:

To be continued in PART 2 of this series.

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided “AS IS” with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER: https://jorgequestforknowledge.wordpress.com/disclaimer/

————————————————————————————————————————————————————-
########################### IAMTEC | Jorge’s Quest For Knowledge ##########################
#################### http://JorgeQuestForKnowledge.wordpress.com/ ###################

————————————————————————————————————————————————————

IAMTEC

Identity | Security | Recovery

————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, Azure AD Connect, Microsoft Graph, PowerShell, Tooling/Scripting, Windows Azure Active Directory | 1 Comment »

(2021-09-11) Azure AD Administrative Units – Delegating Scoped Admin Tasks In Azure AD

Posted by Jorge on 2021-09-11


Quite some time ago I blogged about Azure AD Administrative Units (AU). The details can be found in the found through the following blog posts:

Microsoft documentation: https://docs.microsoft.com/en-us/azure/active-directory/roles/administrative-units

Since then many things have changed, and today it is a valuable feature to delegate management of a set of objects to other groups of people. It is different than OUs in Active Directory (AD). OUs in AD are for delegating management and applying policy. AUs in Azure AD are for delegating management only.

image

Figure 1: Administrative Units In Azure AD – From The Administrative Unit Perspective

Objects

Today AUs only support user and group objects, both cloud native and hybrid/synched. Those objects are not actually child objects of an AU. The objects are assigned to one or more AUs. The assignment basically behaves like a group membership. By allowing objects being assigned to multiple AUs, multiple groups of admins can manage the same set of objects.

Objects can be assigned to an AU

  • …from the AU perspective => select AU, then add member object

OR

  • …from the object perspective => select object, then assign an AU

image

Figure 2: User Objects Member Of A Certain Administrative Unit

image

Figure 3: Group Objects Member Of A Certain Administrative Unit

image

Figure 4: Administrative Units In Azure AD – From The Object (In This Case: User) Perspective

Administration

The main and only goal of AUs is the delegation of administration of user and group objects. At tenant level, Azure AD supports many administrative roles. Some of those roles, that focus on user and group objects throughout the complete Azure AD tenant, can therefore also be scoped at AU level allowing to perform the tasks supported by the administrative role on the objects that are assigned to the AU. In figure 5 you can see the administrative roles currently supported by an AU.

image

Figure 5: Administrative Units In Azure AD – Available Delegation Roles For Each Administrative Unit

This does not mean, delegation is configured by default. No, you still need to configure that by either assigning users and/or groups the respective role scoped for the corresponding AU. In terms of users you can assign any user the supported roles scoping the AU. With regards to groups, you can only assign groups only the supported Azure AD roles, if those groups have been created to support Azure AD role assignments. That support cannot be changed after the creation of the group. it must be configured when creating the group.

When looking at a specific Azure AD administrative role, you will be able to see what the scope of management is and which object (group or user) has been configured for that specific scope.

Assigning Objects To AUs

It is possible to add or remove assignments of individual objects, through either the Azure AD Portal, PowerShell or the Microsoft graph. Additionally, through the Azure AD Portal it is possible to bulk add or remove objects to/from the AU. When deleting an AU, only the AU, the delegating configuration (role assignment scoped to the AU, not the role itself) and the assignment of objects (users and groups, but not the objects themselves) will be deleted with it.

image

Figure 6: Administrative Units In Azure AD – Supported Bulk Operations

Another thing that would be very interesting is auto assigning users and groups to Administrative Units instead of all the current manual work that is needed. Dynamic assignment similar to dynamic groups would be very welcome and definitely a serious win!

Nevertheless, if you have something that can either leverage the Azure AD PowerShell module or the Microsoft Graph API, dynamic assignment is possible as long as you have something external to Azure AD (IAM System?) to determine the logic of adding or removing objects to/from AUs. More about these thoughts in a next blog post! Make sure to read that one! Smile

PowerShell

The Azure AD PowerShell module supports CMDlets to manage AUs through either the Azure AD graph (deprecated!) (*-AzureADAdministrativeUnit*) or the Microsoft graph (preferred!) (*-AzureADMSAdministrativeUnit*)

 

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################

IAMTEC

Identity | Security | Recovery

https://iamtec.eu/
————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, Azure AD Graph, Microsoft Graph, Windows Azure Active Directory | 1 Comment »

(2019-07-11) Creating A List Of Role Members Within Azure AD Administrative Units

Posted by Jorge on 2019-07-11


Do you need to create a list of role members that have been delegated one or more roles to administrative units? Then look no further. See the example below

image

Figure 3: The Administrative Units And Its Scoped Role Members

The script can be downloaded from the script gallery here.

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, PowerShell, Tooling/Scripting, Windows Azure Active Directory | Leave a Comment »

(2019-07-09) Creating A List Of Users Within Azure AD Administrative Units

Posted by Jorge on 2019-07-09


Do you need to create a list of users that are a members of administrative units? Then look no further. See the example below

image

Figure 1: The Administrative Units And Its AU Members

The script can be downloaded from the script gallery here.

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, PowerShell, Tooling/Scripting, Windows Azure Active Directory | Leave a Comment »

(2019-07-07) Azure AD Delegation Through Roles And Administrative Units – The Good, The Bad And The Ugly (Part 2)

Posted by Jorge on 2019-07-07


When I started this quest, my initial thoughts on all this were to delegate the “Reset of the MFA Profile” to other service desks for a scoped list of users in AAD when something happened to the users’ mobile device/phone. That could be: lost, broken or stolen device/phone. With that in mind I tried the following roles “Privileged Authentication Administrator” and “Authentication Administrator”. Before continuing I first read a few things to understand what had changed since the last time I looked at it. I can tell you that was quite some time ago!

In summary I saw the following:

  • Still in preview!
  • Managing Administrative Units and everything around that through PowerShell
  • Requires AzureADPreview Module!
  • Resources can only be users!

My investigation started by first creating some users in AAD that used native AAD Authentication, no federation or anything special like that to keep it as simple as possible. My idea was to create 5 regular users per AU and for each AU also create 1 admin for 4 unique AAD roles. I used the following PowerShell CMDlets:

# Create Users In AAD

$tenantDomain = "<AAD Tenant Domain>" # Replace this with your own value

$mobile = "<Mobile Phone Number>" # Replace this with your own value

$pwdProfileAM = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile

$pwdProfileAM.Password = ‘<Some Text String As Password>‘ # Replace this with your own value

New-AzureADUser -DisplayName "John Doe (AM 1)" -GivenName "John" -Surname "Doe (AM 1)" -PasswordProfile $pwdProfileAM -UserPrincipalName "john.doe.am1@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Finance" -JobTitle "Accountant" -Mobile $mobile -MailNickName "john.doe.am1" -UsageLocation "US"

New-AzureADUser -DisplayName "John Doe (AM 2)" -GivenName "John" -Surname "Doe (AM 2)" -PasswordProfile $pwdProfileAM -UserPrincipalName "john.doe.am2@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Finance" -JobTitle "Accountant" -Mobile $mobile -MailNickName "john.doe.am2" -UsageLocation "US"

New-AzureADUser -DisplayName "John Doe (AM 3)" -GivenName "John" -Surname "Doe (AM 3)" -PasswordProfile $pwdProfileAM -UserPrincipalName "john.doe.am3@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Finance" -JobTitle "Accountant" -Mobile $mobile -MailNickName "john.doe.am3" -UsageLocation "US"

New-AzureADUser -DisplayName "John Doe (AM 4)" -GivenName "John" -Surname "Doe (AM 4)" -PasswordProfile $pwdProfileAM -UserPrincipalName "john.doe.am4@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Finance" -JobTitle "Accountant" -Mobile $mobile -MailNickName "john.doe.am4" -UsageLocation "US"

New-AzureADUser -DisplayName "John Doe (AM 5)" -GivenName "John" -Surname "Doe (AM 5)" -PasswordProfile $pwdProfileAM -UserPrincipalName "john.doe.am5@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Finance" -JobTitle "Accountant" -Mobile $mobile -MailNickName "john.doe.am5" -UsageLocation "US"

New-AzureADUser -DisplayName "Admin Priv AuthN (AM Admin)" -GivenName "Admin" -Surname "Priv AuthN (AM Admin)" -PasswordProfile $pwdProfileAM -UserPrincipalName "admin.priv.authn.am@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Operations" -JobTitle "DevOpsAdmin – PrivAuthN" -Mobile $mobile -MailNickName "admin.priv.authn.am" -UsageLocation "US"

New-AzureADUser -DisplayName "Admin AuthN (AM Admin)" -GivenName "Admin" -Surname "AuthN (AM Admin)" -PasswordProfile $pwdProfileAM -UserPrincipalName "admin.authn.am@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Operations" -JobTitle "DevOpsAdmin – AuthN" -Mobile $mobile -MailNickName "admin.authn.am" -UsageLocation "US"

New-AzureADUser -DisplayName "Admin Helpdesk (AM Admin)" -GivenName "Admin" -Surname "Helpdesk (AM Admin)" -PasswordProfile $pwdProfileAM -UserPrincipalName "admin.helpdesk.am@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Operations" -JobTitle "DevOpsAdmin – Helpdesk" -Mobile $mobile -MailNickName "admin.helpdesk.am" -UsageLocation "US"

New-AzureADUser -DisplayName "Admin User Account (AM Admin)" -GivenName "Admin" -Surname "User Account (AM Admin)" -PasswordProfile $pwdProfileAM -UserPrincipalName "admin.user.account.am@$tenantDomain" -AccountEnabled $true -City "New York" -Country "United States Of America" -Department "Operations" -JobTitle "DevOpsAdmin – UserAccount" -Mobile $mobile -MailNickName "admin.user.account.am" -UsageLocation "US"

$pwdProfileEU = New-Object -TypeName Microsoft.Open.AzureAD.Model.PasswordProfile

$pwdProfileEU.Password = ‘<Some Text String As Password>‘ # Replace this with your own value

New-AzureADUser -DisplayName "Jan Janssen (EU 1)" -GivenName "Jan" -Surname "Janssen (EU 1)" -PasswordProfile $pwdProfileEU -UserPrincipalName "jan.janssen.eu1@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "ICT" -JobTitle "Engineer" -Mobile $mobile -MailNickName "jan.janssen.eu1" -UsageLocation "NL"

New-AzureADUser -DisplayName "Jan Janssen (EU 2)" -GivenName "Jan" -Surname "Janssen (EU 2)" -PasswordProfile $pwdProfileEU -UserPrincipalName "jan.janssen.eu2@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "ICT" -JobTitle "Engineer" -Mobile $mobile -MailNickName "jan.janssen.eu2" -UsageLocation "NL"

New-AzureADUser -DisplayName "Jan Janssen (EU 3)" -GivenName "Jan" -Surname "Janssen (EU 3)" -PasswordProfile $pwdProfileEU -UserPrincipalName "jan.janssen.eu3@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "ICT" -JobTitle "Engineer" -Mobile $mobile -MailNickName "jan.janssen.eu3" -UsageLocation "NL"

New-AzureADUser -DisplayName "Jan Janssen (EU 4)" -GivenName "Jan" -Surname "Janssen (EU 4)" -PasswordProfile $pwdProfileEU -UserPrincipalName "jan.janssen.eu4@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "ICT" -JobTitle "Engineer" -Mobile $mobile -MailNickName "jan.janssen.eu4" -UsageLocation "NL"

New-AzureADUser -DisplayName "Jan Janssen (EU 5)" -GivenName "Jan" -Surname "Janssen (EU 5)" -PasswordProfile $pwdProfileEU -UserPrincipalName "jan.janssen.eu5@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "ICT" -JobTitle "Engineer" -Mobile $mobile -MailNickName "jan.janssen.eu5" -UsageLocation "NL"

New-AzureADUser -DisplayName "Admin Priv AuthN (EU Admin)" -GivenName "Admin" -Surname "Priv AuthN (EU Admin)" -PasswordProfile $pwdProfileEU -UserPrincipalName "admin.priv.authn.eu@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "Operations" -JobTitle "DevOpsAdmin – PrivAuthN" -Mobile $mobile -MailNickName "admin.priv.authn.eu" -UsageLocation "NL"

New-AzureADUser -DisplayName "Admin AuthN (EU Admin)" -GivenName "Admin" -Surname "AuthN (EU Admin)" -PasswordProfile $pwdProfileEU -UserPrincipalName "admin.authn.eu@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "Operations" -JobTitle "DevOpsAdmin – AuthN" -Mobile $mobile -MailNickName "admin.authn.eu" -UsageLocation "NL"

New-AzureADUser -DisplayName "Admin Helpdesk (EU Admin)" -GivenName "Admin" -Surname "Helpdesk (EU Admin)" -PasswordProfile $pwdProfileEU -UserPrincipalName "admin.helpdesk.eu@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "Operations" -JobTitle "DevOpsAdmin – Helpdesk" -Mobile $mobile -MailNickName "admin.helpdesk.eu" -UsageLocation "NL"

New-AzureADUser -DisplayName "Admin User Account (EU Admin)" -GivenName "Admin" -Surname "User Account (EU Admin)" -PasswordProfile $pwdProfileEU -UserPrincipalName "admin.user.account.eu@$tenantDomain" -AccountEnabled $true -City "Amsterdam" -Country "The Netherlands" -Department "Operations" -JobTitle "DevOpsAdmin – UserAccount" -Mobile $mobile -MailNickName "admin.user.account.eu" -UsageLocation "NL"

After this I had to create some administrative units in AAD. 2 AUs was more than enough

# Create Administrative Units In AAD

New-AzureADAdministrativeUnit -Description "AM Region – City Of New York" -DisplayName "AM Region – NYC"

New-AzureADAdministrativeUnit -Description "EU Region – City Of Amsterdam" -DisplayName "EU Region – AMS"

Before being able to continue and configure things I needed to retrieve the objects that were created in AAD

# Get individual AUs

$auAMNYC = $aUs | ?{$_.Displayname -eq "AM Region – NYC"}

$auEUAMS = $aUs | ?{$_.Displayname -eq "EU Region – AMS"}

# Get List Of Candidate Users Using SOME Filter

$usersAMNYC = Get-AzureADUser -Filter "(City eq ‘New York’)"

$usersEUAMS = Get-AzureADUser -Filter "(City eq ‘Amsterdam’)"

Now I needed to add the previously created users to the previously created AUs

# Add Users To AUs

$usersAMNYC | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

    Add-AzureADAdministrativeUnitMember -ObjectId $auAMNYC.ObjectId -RefObjectId $userObjectID

}

$usersEUAMS | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

    Add-AzureADAdministrativeUnitMember -ObjectId $auEUAMS.ObjectId -RefObjectId $userObjectID

}

Now I needed to assign the roles to specific admins for specific AUs

# Retrieve Admin Accounts For AM – New York

$adminPrivAuthNAMNYC = Get-AzureADUser -Filter "(City eq ‘New York’) and (Department eq ‘Operations’) and (JobTitle eq ‘DevOpsAdmin – PrivAuthN’)"

$adminAuthNAMNYC = Get-AzureADUser -Filter "(City eq ‘New York’) and (Department eq ‘Operations’) and (JobTitle eq ‘DevOpsAdmin – AuthN’)"

$adminHelpdeskAMNYC = Get-AzureADUser -Filter "(City eq ‘New York’) and (Department eq ‘Operations’) and (JobTitle eq ‘DevOpsAdmin – Helpdesk’)"

$adminUserAccountAMNYC = Get-AzureADUser -Filter "(City eq ‘New York’) and (Department eq ‘Operations’) and (JobTitle eq ‘DevOpsAdmin – UserAccount’)"

# Retrieve Admin Accounts For EU – Amsterdam

$adminPrivAuthNEUAMS = Get-AzureADUser -Filter "(City eq ‘Amsterdam’) and (Department eq ‘Operations’) and (JobTitle eq ‘DevOpsAdmin – PrivAuthN’)"

$adminAuthNEUAMS = Get-AzureADUser -Filter "(City eq ‘Amsterdam’) and (Department eq ‘Operations’) and (JobTitle eq ‘DevOpsAdmin – AuthN’)"

$adminHelpdeskEUAMS = Get-AzureADUser -Filter "(City eq ‘Amsterdam’) and (Department eq ‘Operations’) and (JobTitle eq ‘DevOpsAdmin – Helpdesk’)"

$adminUserAccountEUAMS = Get-AzureADUser -Filter "(City eq ‘Amsterdam’) and (Department eq ‘Operations’) and (JobTitle eq ‘DevOpsAdmin – UserAccount’)"

# Prepare The Role Definitions And Enable As Needed

# ROLE: Privileged Authentication Administrator

$privAuthAdminRoleDisplayName = "Privileged Authentication Administrator"

$privAuthAdminRole = Get-AzureADDirectoryRole | ?{$_.DisplayName -eq $privAuthAdminRoleDisplayName} # Allowed to view, set and reset authentication method information for any user (admin or non-admin).

If (!$privAuthAdminRole) {

    $privAuthAdminRoleTemplate = $null

     $privAuthAdminRoleTemplate = Get-AzureADDirectoryRoleTemplate | ?{$_.DisplayName -eq $privAuthAdminRoleDisplayName}

    Enable-AzureADDirectoryRole -RoleTemplateId $privAuthAdminRoleTemplate.ObjectId

}

$privAuthAdminRoleObjectID = $privAuthAdminRole.ObjectId

# ROLE: Authentication Administrator

$authAdminRoleDisplayName = "Authentication Administrator"

$authAdminRole = Get-AzureADDirectoryRole | ?{$_.DisplayName -eq $authAdminRoleDisplayName} # Allowed to view, set and reset authentication method information for any non-admin user.

If (!$authAdminRole) {

    $authAdminRoleTemplate = $null

    $authAdminRoleTemplate = Get-AzureADDirectoryRoleTemplate | ?{$_.DisplayName -eq $authAdminRoleDisplayName}

    Enable-AzureADDirectoryRole -RoleTemplateId $authAdminRoleTemplate.ObjectId

}

$authAdminRoleObjectID = $authAdminRole.ObjectId

# ROLE: Helpdesk Administrator

$helpdeskAdminRoleDisplayName = "Helpdesk Administrator"

$helpdeskAdminRole = Get-AzureADDirectoryRole | ?{$_.DisplayName -eq $helpdeskAdminRoleDisplayName} # Can reset passwords for non-administrators and Helpdesk Administrators

If (!$helpdeskAdminRole) {

    $helpdeskAdminRoleTemplate = $null

    $helpdeskAdminRoleTemplate = Get-AzureADDirectoryRoleTemplate | ?{$_.DisplayName -eq $helpdeskAdminRoleDisplayName}

    Enable-AzureADDirectoryRole -RoleTemplateId $helpdeskAdminRoleTemplate.ObjectId

}

$helpdeskAdminRoleObjectID = $helpdeskAdminRole.ObjectId

# ROLE: User Account Administrator

$userAccountAdminRoleDisplayName = "User Account Administrator"

$userAccountAdminRole = Get-AzureADDirectoryRole | ?{$_.DisplayName -eq "User Account Administrator"} # Can manage all aspects of users and groups, including resetting passwords for limited admins

If (!$userAccountAdminRole) {

    $userAccountAdminRoleTemplate = $null

    $userAccountAdminRoleTemplate = Get-AzureADDirectoryRoleTemplate | ?{$_.DisplayName -eq $userAccountAdminRoleDisplayName}

    Enable-AzureADDirectoryRole -RoleTemplateId $userAccountAdminRoleTemplate.ObjectId

}

$userAccountAdminRoleObjectID = $userAccountAdminRole.ObjectId

# Role Delegation For AM – New York

$adminPrivAuthNAMNYC | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

    $userMemberInfo = $null

    $userMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ObjectId = $userObjectID}

    Add-AzureADScopedRoleMembership -ObjectId $auAMNYC.ObjectId -RoleObjectId $privAuthAdminRoleObjectID -RoleMemberInfo $userMemberInfo

}

$adminAuthNAMNYC | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

    $userMemberInfo = $null

    $userMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ObjectId = $userObjectID}

    Add-AzureADScopedRoleMembership -ObjectId $auAMNYC.ObjectId -RoleObjectId $authAdminRoleObjectID  -RoleMemberInfo $userMemberInfo

}

$adminHelpdeskAMNYC | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

     $userMemberInfo = $null

    $userMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ObjectId = $userObjectID}

    Add-AzureADScopedRoleMembership -ObjectId $auAMNYC.ObjectId -RoleObjectId $helpdeskAdminRoleObjectID -RoleMemberInfo $userMemberInfo

}

$adminUserAccountAMNYC | %{

     $userObjectID = $null

    $userObjectID = $_.ObjectId

    $userMemberInfo = $null

    $userMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ObjectId = $userObjectID}

    Add-AzureADScopedRoleMembership -ObjectId $auAMNYC.ObjectId -RoleObjectId $userAccountAdminRoleObjectID -RoleMemberInfo $userMemberInfo

}

# Role Delegation For EU – Amsterdam

$adminPrivAuthNEUAMS | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

    $userMemberInfo = $null

    $userMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ObjectId = $userObjectID}

    Add-AzureADScopedRoleMembership -ObjectId $auEUAMS.ObjectId -RoleObjectId $privAuthAdminRoleObjectID -RoleMemberInfo $userMemberInfo

}

$adminAuthNEUAMS | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

    $userMemberInfo = $null

    $userMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ObjectId = $userObjectID}

    Add-AzureADScopedRoleMembership -ObjectId $auEUAMS.ObjectId -RoleObjectId $authAdminRoleObjectID  -RoleMemberInfo $userMemberInfo

}

$adminHelpdeskEUAMS | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

    $userMemberInfo = $null

    $userMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ObjectId = $userObjectID}

    Add-AzureADScopedRoleMembership -ObjectId $auEUAMS.ObjectId -RoleObjectId $helpdeskAdminRoleObjectID -RoleMemberInfo $userMemberInfo

}

$adminUserAccountEUAMS | %{

    $userObjectID = $null

    $userObjectID = $_.ObjectId

    $userMemberInfo = $null

    $userMemberInfo = New-Object -TypeName Microsoft.Open.AzureAD.Model.RoleMemberInfo -Property @{ObjectId = $userObjectID}

    Add-AzureADScopedRoleMembership -ObjectId $auEUAMS.ObjectId -RoleObjectId $userAccountAdminRoleObjectID -RoleMemberInfo $userMemberInfo

}

While adding the “Privileged Authentication Administrator” AAD role I noticed the following

image

Figure 1: An Error Stating That Role Delegation For Administrative Units Is Only Possible For The “User Account Administrator” Role And The “Helpdesk Administrator” Role

Now this is a bummer! Damn!

The end result of all this is:

image

Figure 2: The Administrative Units And Its AU Members

image

Figure 3: The Administrative Units And Its Scoped Role Members

It should be obvious the “Privileged Authentication Administrator” is missing as that one failed as displayed in figure 1. It is weird though the configuration for that one failed, as the configuration for the “Authentication Administrator” role succeeded.

As in the previous post I started with the AAD Portal (https://portal.azure.com/) and I logged on with admin.authn.am@iamtec.onmicrosoft.com which was delegated the “Authentication Administrator” in the “AM Region – NYC” AU. Looking at my own Directory Role I saw the following

image

Figure 4: The Assigned Directory Role To The Admin Account In The Directory Role Section Of The User Account

Although the AAD Portal is able to see that I have the “Authentication Administrator” role assigned, on the main page of the AAD Portal it tells me I’m a regular user

image

Figure 5: The Assigned Directory Role To The Admin Account On The Main Overview Page

So is the AAD Portal having some role crisis regarding this user? Something else worth mentioning is that the AAD Portal unfortunately does not have a notion about AUs, at least I could not see anything about that when logged on with the delegated admin account.

Trying to reset the MFA profile for a scoped user….

image

Figure 6: Authentication Methods Section For A User Through The AAD Portal

Looking at that I see I can do something with the following because it is not greyed:

  • Edit Authentication Info
  • Revoke MFA sessions
  • Require Re-Register MFA
  • Reset Password

This time stuff was not as I expected. Almost everything was greyed out and I got the message that I did not have access to the requested data. In the end I thing that the AAD Portal overview page was indeed right. Just a regular user!

I did try the Password Reset as that was not greyed out, but it failed with an error saying: “The password can not be reset. This may be due to an incorrect level of administrative privilege or if trying to reset your own password

Let’s move on to the Office 365 Admin Center.

I logged on with admin.authn.am@iamtec.onmicrosoft.com and in the “Users – Active Users” section I could only see the users of the administrative unit I was had been assigned a role in. If I was assigned a role for multiple administrative units than the drop-down list would specify all applicable AUs and for each AU the AU members would be displayed below

image

Figure 7: List Of Users Within A Specific Administrative Unit The Admin Was Delegated To

In the Office 365 Admin Center I was not able to find a way to Reset the MFA profile or to revoke MFA sessions. Unfortunately that was disappointing as I was able to reset the password of the scoped users.

Moving to PowerShell using any of the following CMDlets:

Revoke-AzureADUserAllRefreshToken –ObjectId <Object ID Or UPN>

Reset-MsolStrongAuthenticationMethodByUpn -UserPrincipalName <UPN>

Set-MsolUserPassword -UserPrincipalName <UPN> -NewPassword ‘<Some Text String As Password>’

Set-AzureADUserPassword -ObjectId <Object ID Or UPN> -Password $(ConvertTo-SecureString -String ‘<Some Text String As Password>’ -AsPlainText -Force)

All CMDlets succeeded, except the one that I really needed!

image

Figure 8: Using PowerShell When Using Delegated AAD Roles For Administrative Units

As it looks, there appears to be no way in delegating the reset of an MFA profile for a scoped user. The AAD Portal does not really understand administrative Units, The O365 Admin Center does understand administrative Units, but has no option to reset the MFA profile for a scoped user when using AUs. Through PowerShell, the CMDlet “Reset-MsolStrongAuthenticationMethodByUpn -UserPrincipalName <UPN>” does not work when using delegated permissions for AUs.

Not much has changed unfortunately. As how I look at it right now, although it does support delegated tasks in the Office 365 Admin Center, it lacks the options to be able to do everything. With this in mind the administrative units feature is not yet enterprise ready, especially when the need exists to delegate parts to other regions/locations.

Hopefully Microsoft changes this soon

Cheers,

Jorge

————————————————————————————————————————————————————-
This posting is provided "AS IS" with no warranties and confers no rights!
Always evaluate/test everything yourself first before using/implementing this in production!
This is today’s opinion/technology, it might be different tomorrow and will definitely be different in 10 years!
DISCLAIMER:
https://jorgequestforknowledge.wordpress.com/disclaimer/
————————————————————————————————————————————————————-
########################### Jorge’s Quest For Knowledge ##########################
####################
http://JorgeQuestForKnowledge.wordpress.com/ ###################
————————————————————————————————————————————————————-

Posted in Azure AD Administrative Units, RBAC, Windows Azure Active Directory | 2 Comments »

 
%d bloggers like this: