Going forward, the Azure AD PowerShell Module will not be updated, and Microsoft has stated that it is the Microsoft.Graph PowerShell Module that will be used. This makes sense, as this is auto-generated based on the Microsoft Graph Odata, not requiring Microsoft to maintain several things. However, right now, some of the PowerShell verbs are not really following best practices. Anyway, here is how to do some simple things π
Ensure the latest version of Microsoft.Graph is installed
The below code can be used in top of a script, in order to ensure Microsoft.Graph is installed and up to date.
Write-Verbose "Loading Microsoft.Graph module"
$connectCommand = Get-Command Connect-MgGraph -ErrorAction SilentlyContinue
if(!$connectCommand) {
Write-Warning "Could not find Microsoft.Graph module, trying to install..."
Install-Module Microsoft.Graph -Scope CurrentUser -ErrorAction Stop
} else {
$latest = Find-Module Microsoft.Graph
if($latest.Version -gt $connectCommand.Module.Version) {
Write-Warning "Microsoft.Graph module version $($connectCommand.Module.Version) installed, trying to update to version $($latest.Version)"
Update-Module Microsoft.Graph -ErrorAction Stop
}
}
Connecting using interactive signin
The Connect-MgGraph cmdlet can be used to sign in. What is nice about this cmdlet, is that you can limit the scopes, but it also means that you need to define exactly what you want to do:
$connectResult = Connect-MgGraph -Scopes "User.ReadWrite.All","Application.ReadWrite.All","Domain.Read.All","RoleManagement.ReadWrite.Directory" -ErrorAction Stop
When running this, a browser window will appear, with regular Azure AD signin. You need permissions to consent the required scopes, in order to sign in.
If you need to sign into a tenant using a B2B guest account, you need to provide the -Tenant option, in order to tell Azure AD which tenant to sign into.
Connecting using access token
Let’s say you already have an access token, such as using ROPC or other means of signing in, this can be provided to Connect-MgGraph using the -AccessToken option. To demo this, you can use a token from the Microsoft Graph Explorer:

Connect-MgGraph -AccessToken 'eyJ0eXAiOiJKV1QiLCJub25-------t1WM1mKbxHx3UAA'
Create user
In order to create a user, many of the same parameters as New-AzureADUser is needed, such as UserPrincipalName, DisplayName etc. Notice that PasswordProfile is provided as a hashmap:
$PasswordProfile = @{}
$PasswordProfile["Password"]= ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?.;,._".ToCharArray() | Get-random -Count 50) -join ""
$PasswordProfile["ForceChangePasswordNextSignIn"] = $false
$user = New-MgUser -UserPrincipalName "test.user@M365x866897.OnMicrosoft.com" -AccountEnabled:$true -DisplayName "Test User" -MailNickname "test.user" -PasswordPolicies DisablePasswordExpiration -PasswordProfile $PasswordProfile
Onboard unused Azure AD roles
In this scenario, we want to use Global reader, Security reader, SharePoint Administrator and Authentication Policy Administrator, so we need to onboard them using New-MgDirectoryRole:
# Global reader, Security reader, SharePoint Administrator and Authentication Policy Administrator
$requiredRoleTemplates = Get-MgDirectoryRoleTemplate | Where-Object Id -in "f2ef992c-3afb-46b9-b7cf-a126ee74c451","5d6b6bb7-de71-4623-b4af-96380a352509","f28a1f50-f6e7-4571-818b-6a12f2af6b6c","0526716b-113d-4c15-b2c8-68e3c22b9f80"
# Get all roles
$aadRoles = Get-MgDirectoryRole
# Onboard any unused role that we need
$requiredRoleTemplates |
Where-Object {!($aadRoles | Where-Object RoleTemplateId -eq $_.Id)} |
ForEach-Object {
Write-Verbose "Role template '$($_.DisplayName)' with template id $($_.Id) has never been used in this tenant. Onboarding the role before use." -Verbose
New-MgDirectoryRole -RoleTemplateId $_.Id
} |
Out-Null
Add user to role
The following is an example on how to add a user to a role – which may seem cryptic. And it is… Essentially, we are oroviding the raw body to the New-MgDirectoryRoleMemberByRef cmdlet, as documented here. Hopefully this experience will be improved at some point in the future, as this really is not how an SDK should behave π
# Get all roles again
$aadRoles = Get-MgDirectoryRole
$requiredRoleTemplates |
ForEach-Object {
$aadRoles | Where-Object RoleTemplateId -eq $_.Id
} | ForEach-Object {
$Members = Get-MgDirectoryRoleMember -DirectoryRoleId $_.Id
if($User.Id -notin $Members.Id) {
Write-Verbose "Adding user to Azure AD role '$($_.DisplayName)'" -Verbose
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $_.Id -BodyParameter @{"@odata.id" = "https://graph.microsoft.com/v1.0/directoryObjects/$($user.Id)"}
}
}
So there you have it – a quick and dirty howto on assigning an Azure AD role to a user. Notice that this does not use the PIM API, and I may write another post about how to do that.
Thank you ! Do you also know how to remove a user from a role?
It seems you actually need to use Invoke-MgGraphRequest for this currently, as there is no Remove-command apparently. Using Invoke-MgGraphRequest, you can invoke a DELETE towards something like https://graph.microsoft.com/v1.0/directoryRoles/f8e85ed8-f66f-4058-b170-3efae8b9c6e5/members/bb165b45-151c-4cf6-9911-cd7188912848/$ref, where the first guid is the ID of youir role and the last guid is the ID of your principal (user or service principal)
This helps a lot! I did not know that command and I think it might just be easier to use that one for so many requests.