Monday, November 22, 2021

User Profile Ramifications when Renaming Users on Azure AD-Joined Computers

I'm starting to work more with devices that are Azure AD-joined rather than domain-joined. One of my key questions was what happens to user profiles when an Azure AD user sign-in name (UPN) is changed. I was pleasantly surprised by how well it worked.

For my testing, I created an Azure AD user and signed in to create a profile. During sign-in, I created a PIN for authentication. While signed in, I also configured an Outlook profile and OneDrive. Then I tried changing the domain portion of the username and the userid portion of the username. The results were the same:

  • I could still sign in with the PIN.
  • I could sign in as the same user (username displayed on sign-in screen) with the password.
  • I could sign in with the new username (typed in) and password.

After signing in:

  • The workplace account was updated to the new username.
  • Outlook was still able to sign-in without user intervention and updated the account.
  • OneDrive continued to function without user intervention and updated the account.
  • The same Windows 10 user profile was retained.

 

Wednesday, November 17, 2021

Managing Microsoft 365 Licenses by using Microsoft Graph

Microsoft has announced that after June 2022, the MSOL and AzureAD cmdlets for managing user licenses in Microsoft 365 will cease working. These cmdlets rely on management functionality that is being retired. To manage licenses programmatically, you need to start using Microsoft Graph.

Here is the announcement:

Microsoft Graph is a web-API that you can use to manage Microsoft 365 users, groups, and services. If you're a programmer, then perhaps the idea of building a web request to perform administrative tasks sounds like a good idea. However, for an admin guy like me that typically uses PowerShell cmdlets for management tasks, building web requests is a bit painful. Fortunately, the Microsoft Graph PowerShell SDK has been released that provides PowerShell cmdlets to access Microsoft Graph features.

To get more information about the Microsoft Graph PowerShell SDK:

 Connecting with Microsoft Graph

Just like you use Connect-AzureAD or Connect-MsolService, for Microsoft Graph, you use Connect-MgGraph. When you connect, you need to specify a scope that defines your permissions. So, unlike previous versions, the connection does not automatically gain the full permissions based on your roles like Global Admin. I haven't experimented with exactly which scopes are required to manage user licenses. However, I can confirm that the following example does work.

Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.ReadWrite.All"

To get more information about Microsoft Graph scopes:

License Structure and Naming

If you've been managing licenses through the web interface in Microsoft 365 or the MSOL cmdlets, you're used to seeing license names such as Office 365 E3. When you manage licenses by using Microsoft Graph, you need to know the SkuId property of the licenses available in your tenant. You can obtain the SkuId for a license by using Get-MgSubscribedSku as shown in the following figure. The SkuPartNumber property is a more user friendly name that you can recognize.

Within each licenses type, there are also service plans. These correlate with apps provided by a license such as Exchange Online (Plan 2). To enable or disable the service plans, you need to use the ServicePlanId for a  service plan. If you place your subscribed SKUs in a variable, you can view the service plans included in the SKU as shown in the following figure.

To get a list of generally available SKUs and their service plans:

Viewing Assigned Licenses

You can view the licenses assigned to a user by using the Get-MgUserLicenseDetail cmdlet as shown in the following example:

Get-MgUserLicenseDetail -UserId user@domain.com

The results of this command return the users license assigned to the user. An array of licenses is returned if multiple licenses have been assigned. Within each license returned, you can view the ServicePlans property to see if any service plans have been disabled for a user.

You can also query assigned license information by using Get-MgUser. The licensing information isn't returned by default and you need to specify that the AssignedLicenses property will be retrieved as shown in the figure below. Notice that these results list the service plans that are disabled for a license.

Querying Users with Assigned Licenses

If you want to query all of the users with a specific license, you can do this by using Get-MgUser with a filter for a specific SkuId. The example below shows the syntax.

Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq 78e66a63-337a-4a9a-8959-41c6654dfb56)" -Property AssignedLicenses,UserPrincipalName,Id

When you are filtering based on AssignedLicenses there are some limitations on the results returned. By default, only 100 results are returned. If you use the PageSize parameter, you can specify up to 999 results are returned as shown below.

Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq 78e66a63-337a-4a9a-8959-41c6654dfb56)" -PageSize 999

If you have a larger tenant, and you try to use the All parameter to return results larger than these limits, you will be the following error Get-MgUser : The specified page token value has expired and can no longer be included in your request.To avoid this error, you need to query a list of all users and then filter by using Where-Object as shown below.

$allusers = Get-MgUser -All -Property AssignedLicenses,UserPrincipalName,Id,DisplayName
$A1plusUsers = $allusers | Where-Object {$_.AssignedLicenses.SkuId -contains "78e66a63-337a-4a9a-8959-41c6654dfb56"}

Modifying Assigned Licenses

To add or remove licenses for a user, you use the Set-MgUserLicense cmdlet. When you run the cmdlet, you need to provide the following parameters:

  • UserId. The user being modified. You can specify the user by the object Id or UserPrincipalName.
  • AddLicenses. A hash table that specifies the SkuId of a license being added and the ServicePlanId of any service plans that are being disabled.
  • RemoveLicenses. A string that identifies the SkuId of a license being removed.

The following code shows how to build a hash table for the AddLicenses parameter. This specifies a license SkuId and a service plan that's disabled in the license.

$A1FacultySku = @{
    SkuID = "94763226-9b3c-4e75-a931-5c89701abe66"
    DisabledPlans = "9aaf7827-d63c-4b61-89c3-182f06f82e5c"
}

The following code lists a SkuID that will be disabled.

$A1PlusFacultySku = "78e66a63-337a-4a9a-8959-41c6654dfb56"

The command that modifies the user license is below. Note that the UserId parameter will accept a UPN also.

Set-MgUserLicense -UserId $User.Id -AddLicenses $A1FacultySku -RemoveLicenses $A1PlusFacultySku

The RemoveLicenses and AddLicenses parameters are mandatory. If you don't provide an empty array, you'll get an error such as Set-MgUserLicense : One or more parameters of the function import 'assignLicense' are missing from the request payload. The missing parameters are: removeLicenses. If you don't want to remove any licenses, you need to provide an empty array for RemoveLicenses as shown below. If you are only removing licenses, you need to provide an empty array for the AddLicenses parameter.

Set-MgUserLicense -UserId $User.id -AddLicenses $A1FacultySku -RemoveLicenses @()

If you want to modify the disabled plans for a licenses, you build a new hash table with the license and all of the plans you want disabled. Then you apply the new hash table with the AddLicenses parameter. The new license assignment overwrites the existing license assignment.

If you want to add multiple licenses, you can provide a comma separated list of hash tables. I have not explicitly tested, but I think providing an array with the hash tables would also work.

If you want to remove multiple licenses, create an array with the SkuIDs that you want to remove.