Customers often call Microsoft Support for assistance with licensing in Office 365, so I'll discuss how to manage licenses using the Windows Azure Active Directory (AD) Module for Windows PowerShell. I'll start by showing you how to obtain basic information about the licenses in your tenant as well as the service status of each product in those licenses. I'll then show you how to obtain licensing information for users as well as how to assign licenses, remove licenses, and set custom license options. I'll even show you two ways to assign licenses to a group of users.

I'm assuming that you've already installed and set up the Windows Azure AD Module. If you haven't, go to the TechNet web page Manage Azure AD using Windows PowerShell for instructions on how to do so.

Connecting and Obtaining Basic Licensing Information

To begin, you need to use the Windows Azure AD Module to connect to your Office 365 tenant by running the commands:

Import-Module MSOnline
Connect-MsolService

You'll be prompted to provide a username and password. Make sure that you use a Global Administrator account.

There are several types of licenses based on which Office 365 plan your organization signed up for. To find out all the licenses available in your tenant, run the command:

$AccountSku = Get-MsolAccountSku

In this command, $AccountSku is a variable that stores the information returned from the Get-MsolAccountSku cmdlet. After the information is stored in the variable, you can run the following command to obtain the number of licenses in your tenant:

$AccountSku.Count

As the first command in Figure 1 shows, I have two licenses.

Figure 1: Obtaining Information About the Available Licenses

Get-MsolAccountSku returns an array, so you can enumerate the individual elements in that array by referencing their numbers. For example, because I have two licenses, I'd run the commands:

$AccountSku[0].AccountSkuId
$AccountSku[1].AccountSkuId

In the output, the account licenses will be listed in the format <tenant>:<SKU Name>. As the last two commands in Figure 1 show, my tenant has two licenses: POWER_BI_STANDALONE and ENTERPRISEPACK (i.e., the Office 365 Enterprise E3 plan). For security reasons, I replaced my tenant's ID with <tenant> in Figure 1. Note that if you only have one license in your tenant, you can simply run the command:

$AccountSku

Next, you need to find out what products are available in each license in your tenant. To get this information for your tenant, you can run commands like these:

$AccountSku[0].ServiceStatus
$AccountSku[1].ServiceStatus

Figure 2 shows the results for my tenant. The ProvisioningStatus column specifies whether the product is available for the tenant. When the product is available, this column shows a status of Success. A status of PendingInput means the product requires configuration, whereas a status of Disabled means the product is disabled.

Figure 2: Finding Out What Products Are Available in Each License

Getting Users' Licensing Information

Now that you have some basic information about the licenses in your tenant and the service status of each product in those licenses, you can obtain licensing information for users. You might want to begin by determining whether a user is licensed by using the Get-MsolUser cmdlet and querying the IsLicensed attribute. First, though, you need to create a variable to store the information returned from the Get-MsolUser cmdlet. For this example, the following command uses the Get-MsolUser cmdlet to get the information for user John Smith and stores the information in the $userLicenseTest variable:

$userLicenseTest = Get-MsolUser `
  -UserPrincipalName "JohnSmith@<tenant>.onmicrosoft.com"

Note that to use this command, you'll need to customize the user principal name (UPN), including replacing <tenant>.onmicrosoft.com with your tenant's ID.

After the information is stored in the variable, you can query the IsLicensed attribute:

$userLicenseTest.IsLicensed

This command returns a value of True if the user is licensed and False if the user isn't licensed.

If the user is licensed, you can query the user account's Licenses attribute to find out how many licenses the user has. (A user can be assigned multiple licenses.) The Licenses attribute returns an array that contains details about each license and its assigned products. By using the Count attribute with the Licenses array, you can output the number of licenses for the user:

$userLicenseTest.Licenses.Count 

In this case, let's say John Smith has two licenses available: Office 365 Enterprise E3 (ENTERPRISEPACK) and Power BI for Office 365 (POWER_BI_STANDALONE). You can use the ServiceStatus attribute with the Licenses array to get the details about the products available to this user:

$userLicenseTest.Licenses[0].ServiceStatus
$userLicenseTest.Licenses[1].ServiceStatus

Figure 3 shows sample results.

Figure 3: Finding Out What Products Are Available to a User

Here's how to write a foreach loop to retrieve this information:

$licensedetails = (Get-MsolUser -UserPrincipalName `
  "JohnSmith@<tenant>.onmicrosoft.com").Licenses
$licensedetails.Count;
# If there's a license, show the details.
# Otherwise, the output is blank.
if ($licensedetails.Count -gt 0){
  foreach ($i in $licensedetails){
    $i.ServiceStatus
  }
}

This code stores the information from the Licenses attribute in the $licensedetails variable. It then checks to see whether the license count is greater than 0. If the count is greater than 0, it cycles though each element of the array and gets the licensing details. Figure 4 shows the results.

Figure 4: Examining the Results from Using a foreach Loop to Find Out What Products Are Available to a User

Note that PowerShell will also automatically list all elements in an array if you simply run $licensedetails. For more information about how to work with arrays, see "Windows PowerShell Tip of the Week: Accessing Values in an Array."

If you need to find out all the user accounts that aren't licensed, you can run the command:

Get-MsolUser -All |
  where {$_.IsLicensed -eq "false" } |
  Format-List UserPrincipalName

Depending on the number of users in your tenant, it might take a few minutes for this command to run.

Assigning a License to a User

You can assign a license to a user using the Set-MsolUserLicense cmdlet with the -AddLicenses parameter. However, before doing so, you must set the user's UsageLocation attribute. This attribute requires a two-letter code representing the user's country. Assuming user John Smith is located in the United States, you can run the following command to set the UsageLocation attribute:

Set-MsolUser -UserPrincipalName `
  "JohnSmith@<tenant>.onmicrosoft.com" -UsageLocation US

Afterward, you can use the Set-MsolUserLicense cmdlet with the -AddLicenses parameter to assign the license, like this:

Set-MsolUserLicense -UserPrincipalName `
  "JohnSmith@<tenant>.onmicrosoft.com" `
  -AddLicenses <tenant>:ENTERPRISEPACK

You can then check to see the products available to this user with the ServiceStatus attribute:

userLicenseTest.Licenses[0].ServiceStatus

As you can see in Figure 5, the status of each product is listed as PendingInput. That's because the license was just assigned to the user and the products are being provisioned.

Figure 5: Checking the Status of the Products After Assigning a License to a User

Removing a License from a User

You can remove a user's assigned license by using the Set-MsolUserLicense cmdlet with the -RemoveLicenses parameter:

Set-MsolUserLicense `
  -UserPrincipalName JohnSmith@<tenant>.onmicrosoft.com `
  -RemoveLicenses <tenant>:ENTERPRISEPACK

Although this is a simple operation to perform, it's very important to keep in mind the following: When you remove a license from a user, the user will lose his or her data, which can't be recovered.

When you want to assign a new license to a user who is already licensed, the correct method is to replace the existing license by first assigning a new license, then removing the old license. Here's an example of how to do this:

Set-MsolUserLicense `
  -UserPrincipalName "JohnSmith@<tenant>.onmicrosoft.com" `
  -AddLicenses <tenant>:POWER_BI_STANDALONE `
  -RemoveLicenses <tenant>:ENTERPRISEPACK

In this command, note the order of the -AddLicenses and -RemoveLicenses parameters. The -AddLicenses parameter must be placed before the -RemoveLicenses parameter. If you reverse the order (i.e., first remove the old license with -RemoveLicenses, then add a new license with -AddLicenses), the user might lose his or her data because the user would be in an unlicensed state after the removal of the license.

Setting Custom License Options

Sometimes you might want to license users for only specific products, instead of enabling all the products in the license. To do so, you can use the New-MsolLicenseOptions cmdlet to set custom license options. This cmdlet takes two parameters: -AccountSkuId (required) and -DisabledPlans (optional). The -DisabledPlans parameter is used to disable specific products. It takes comma-separated list of the products to be disabled. To get the specific product names, you can use the ServiceStatus attribute.

For example, suppose you need to disable Windows Azure Active Directory Rights (RMS_S_ENTERPRISE), Office Web Apps (SHAREPOINTWAC), and SharePoint Online (SHAREPOINTENTERPRISE) for user Jane Doe. To do so, you'd first use the New-MsolLicenseOptions cmdlet to assign the custom license options to a variable:

$myO365Sku1 = New-MsolLicenseOptions `
  -AccountSkuId <tenant>:ENTERPRISEPACK -DisabledPlans `
  RMS_S_ENTERPRISE,SHAREPOINTENTERPRISE,SHAREPOINTWAC

After you set Jane Doe's UsageLocation attribute and assign her a license, you can set the custom license options for her:

Set-MsolUserLicense `
  -UserPrincipalName JaneDoe@<tenant>.onmicrosoft.com `
  -LicenseOptions $myO365Sku1

As a check, you can use the ServiceStatus attribute to see the products available to her:

(Get-MsolUser -UserPrincipalName `
  "JaneDoe@<tenant>.onmicrosoft.com").Licenses.ServiceStatus

As Figure 6 shows, RMS_S_ENTERPRISE, SHAREPOINTWAC, and SHAREPOINTENTERPRISE are disabled.

Figure 6: Setting Custom License Options

Assigning Licenses to a Group of Users

So far, I've shown you how to assign licenses to one user at a time. You can also assign licenses to groups of users. I'll walk you through two scenarios. First, I'll show you how to search for users based on several criteria and assign licenses to them. Then, I'll show you how to read a list of UPNs from a file and replace those users' existing licenses with new licenses.

Scenario 1. Suppose you need to assign licenses with custom license options to all unlicensed users in the Accounting department who work in either the Dallas or Seattle office. The first task is to create a list of users that meet the specified criteria. Assuming that the Department and City fields for these users are populated in Azure Active Directory, you can use the following command to create this user list:

$unlicenseduserList = Get-MsolUser -All |
  where {$_.IsLicensed -eq $false `
  -and $_.Department -eq "Accounting" `
  -and ($_.City -eq "Dallas" -or $_.City -eq "Seattle")}

As you can see, this command is using -and and -or, which are the logical "And" and "Or" operators in PowerShell. It's also using -eq, which is the "Equal to" comparison operator. Finally, $false and $true are built-in values for Boolean attributes.

Next, you need to create the variable that specifies the custom license options. In this case, you want to disable Windows Azure Active Directory Rights (RMS_S_ENTERPRISE) and Office Web Applications (SHAREPOINTWAC), so you run the command:

$myO365Sku2 = New-MsolLicenseOptions `
  -AccountSkuId <tenant>:ENTERPRISEPACK `
  -DisabledPlans RMS_S_ENTERPRISE, SHAREPOINTWAC

Finally, you can use a foreach loop to set the UsageLocation attribute, assign the license, and set the custom license options for each user:

foreach ($eachuser in $unlicenseduserList){
  Set-MsolUser `
    -UserPrincipalName $eachuser.UserPrincipalName `
    -UsageLocation "US"
  Set-MsolUserLicense `
    -UserPrincipalName $eachuser.UserPrincipalName `
    -AddLicenses <tenant>:ENTERPRISEPACK
  Set-MsolUserLicense `
    -UserPrincipalName $eachuser.UserPrincipalName `
    -LicenseOptions $myO365Sku2
}

Scenario 2. Suppose that a few months later you need to replace the licenses for the licensed users in the Accounting department in the Dallas and Seattle offices. For this scenario, let's create a comma-separated value (CSV) file that lists those users' UPNs, read the UPNs into an array, and replace those users' existing licenses with new licenses.

Writing to a CSV file is simple. You just need to use the Out-File cmdlet. Here's the code to obtain the list of licensed users in the Account department in the Dallas and Seattle offices, retrieve their UPNs, and write those UPNs to a file named LicensedUsers-Accounting.csv:

$licensedAccountinguserList = Get-MsolUser -All |
  where {$_.IsLicensed -eq $true `
  -and $_.Department -eq "Accounting" `
  -and ($_.City -eq "Dallas" -or $_.City -eq "Seattle")}

$outFile="C:\temp\LicensedUsers-Accounting.csv"
foreach ($eachuser in $licensedAccountinguserList){
  $lineOut = $eachuser.UserPrincipalName
  Out-File -FilePath $outfile -Append -NoClobber `
   -InputObject $lineOut
}

Note that before you run this code, you need to make sure the path C:\temp exists or replace it with another path.

Next, you can use the Get-Content cmdlet to read the contents of the LicensedUsers-Accounting.csv file into the $readFile array, like so:

$readFile = `
  Get-Content "C:\temp\LicensedUsers-Accounting.csv"

Finally, you can enumerate through the UPNs in the $readFile array. For each UPN, you need to first assign a new license, then remove the old one, like so:

foreach($removeLicense in $readFile){
    Set-MsolUserLicense `
      -UserPrincipalName $removeLicense `
      -AddLicenses <tenant>:POWER_BI_STANDALONE `
      -RemoveLicenses <tenant>:ENTERPRISEPACK
}

Take Advantage of the Windows Azure AD Module

Using the Windows Azure AD Module to manage licenses in an Office 365 tenant is straightforward once you understand the basic concepts. The examples I've shown you demonstrate these basic concepts.