Use PowerShell to Manage Office 365 Users

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to manage Office 365 users.

Microsoft Scripting Guy, Ed Wilson, is here. The weather here in Charlotte has been nearly perfect recently. I love spring. It offers hope, and it seems to be a time of renewed commitments. A quick trip to the garden center, and the Scripting Wife and I return with bundles of flowers and other stuff to plant. It is the very essence of hope. We hope they will thrive. We hope to enjoy their blooms in the future. We hope they will not overtake the rest of our garden. Ah, lots of hope.

     Note  This is the third in a series of Hey, Scripting Guy! Blog posts where I talk about using Windows PowerShell
     with Office 365.

  • In Getting Started with Office 365 and PowerShell, I talked about setting up a demo environment and installing the prerequisite software to enable Windows PowerShell management of the demo environment. I also walked through the installation of the management module.
  • In Use PowerShell to Explore Office 365 Installation, I talked about using Windows PowerShell to explore the settings and the capabilities of my Office 365 tenant installation.
  • In today’s post, I talk about finding unlicensed users, removing users, and modifying users.

In some respects, as IT pros, we invest in Office 365 technology in much the same way as I invest in flowers. We hope that in the future we will receive the promised benefit. We hope that Office 365 will be more stable, easier to manage, easier to maintain, and therefore provide a promised benefit to the bottom line. One of the keys to unlocking that promise is knowing how to use Windows PowerShell.

The first thing I need to do is to connect to Office 365. To do this, I am using the stored credential that I talked about in yesterday’s blog post, and then I use a cmdlet to make my connection to Office 365. The two commands are shown here:

$cred = Import-Clixml C:\fso\cred.xml

Connect-MsolService -Credential $cred

When I am connected, I like to user the Get-Command cmdlet to display available Windows PowerShell commands. This is shown in the image that follows:

Image of command output

Because this is Windows PowerShell, I can use standard Windows PowerShell techniques to discover commands that I need to use. Then when I have found the cmdlet, I can use Get-Help to find examples of use. Here are some ideas keep in mind:

  • Use Get-Command to find cmdlets. The main module to use is the MSOnline module.
  • Use Tab expansion to expand the names of cmdlets, and also the names of modules. Hit the Tab key, and it will cycle through available options.
  • To find Help, use the Get-Help cmdlet. If you are using Windows PowerShell 4.0 or Windows PowerShell 3.0, you need to first open the Windows PowerShell console with admin rights, and then use the Update-Help cmdlet to update all the Help for modules.
  • Use the Get-Member cmdlet to find object properties to use when filtering.
  • Use the Where-Object cmdlet to reduce or to filter returned information.
  • Use the Group-Object cmdlet to group returned objects by properties.
  • Use the Out-GridView to produce a usable control that permits filtering and sorting.
  • Use the Show-Command cmdlet to produce a floatable control that permits you to easily fill in options.
  • Use the Measure-Object cmdlet for counting.

Display and work with users

To display basic user information about the Office 365 users, use the Get-MsolUser cmdlet. To count the number of users, use the Measure-Object (measure is an alias) cmdlet. The use of these two cmdlets is shown in the image that follows:

Image of command output

It is pretty obvious from the previous image that I have 32 total users, but some are licensed and some are not. Therefore, I want to know how many of each type user exists. I can use the Group-Object cmdlet to figure this out. The best way to use Group-Object is to first sort the data and then group the data. The command is:

Get-MsolUser | Sort islicensed | group islicensed

This command displays the needed information, but the output is a bit clunky. This is because of the grouping information that says it is a bunch of user objects. I already knew that. Therefore, to clean up the list, I want to remove the element grouping information. To do that, I add the –noelement switch to the command. The output from the two commands is shown here:

Image of command output

I want to get a good list of users that are not licensed. I can do this by piping my list of users to Where-Object and filtering on the islicensed property. I come up with the following command:

Get-MsolUser | where {-not $_.islicensed}

But then I start thinking…

Dude, this is a lot of work. And not only that—it is inefficient. This is because it needs to get the list of users, and then filter them. So I use the Get-Command cmdlet, and I find that there is a switch parameter that I can use. The command is shown here:

Get-Command Get-MsolUser | select -expand Definition

The output from the command is shown here:

Image of command output

I re-run the command using the LicenseReconciliationNeededOnly switch parameter, and I see the output is exactly the same.

Note  The switch parameter is really long, so please do not fool with trying to type it. Use Tab expansion until it appears. This will ensure that it is spelled correctly, and save at least 30 seconds of typing.

The output from the two commands is shown here:

Image of command output

Remove unlicensed users

I know that I said Windows PowerShell is Windows PowerShell is Windows PowerShell. But not always…

Unfortunately, this is not always exactly true. For example, I would have expected the Remove-MsolUser cmdlet to implement ShouldProcess, so that I could use the –whatif parameter to see what a cmdlet would do. But unfortunately, it does not.

What the cmdlet does do, is default to using –confirm, but there is no –confirm parameter available either. So when I try to run the following command, it prompts for each of the user objects:

Get-MsolUser -LicenseReconciliationNeededOnly | Remove-MsolUser

This is no good for automation. So I try a couple of things, and I eventually find that the cmdlet actually uses the –Force parameter to suppress confirmation messages.

So, here is the command I ended up using:

Get-MsolUser -LicenseReconciliationNeededOnly | Remove-MsolUser –Force

Now I check to see if the command actually worked:

PS C:\> Get-MsolUser -LicenseReconciliationNeededOnly

PS C:\>

Yep, they are gone.

Luckily, Office 365 has a Recycle Bin, and it is easy to recover the deleted users via the admin tool. This is shown here:

Image of menu

There is also a Restore-MsolUser cmdlet, but unfortunately, there is no obvious way to find all the users in the Recycle Bin. Therefore, I would need to know each UPN to restore the users. In this case, for me, using the GUI is easier. If I had kept a log of the user objects that I deleted, I could have more easily reactivated the users.

That is all there is to using Office 365 cmdlets. Office 365 Week will continue tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Comments (13)

  1. isLicenced is a bool so Microsoft page:
    is not correct, it should read:
    Get-MsolUser | Where-Object { $_.isLicensed -eq $true }
    Get-MsolUser | Where-Object { $_.isLicensed -eq "TRUE" }

    Then you can use
    Get-MsolUser Where-Object { $_.isLicensed -eq $false }
    and it works!!!!

  2. Søren Granfeldt says:

    Nice overview. I combined this with the use of FIM2010 a few years back –

  3. sat says:

    Get-MsolUser -LicenseReconciliationNeededOnly | Remove-MsolUser –Force


    Get-MsolUser -All | Where-Object {$.isLicenced -ne "true" | Remove-MsolUser –Force

    – removes all users without license, without asking for verification on multiple deletes

    Get-MsolUser -ReturnDeletedUsers | Remove-MsolUser –RemoveFromRecycleBin –Force

    – gets around the 30 day Azure retention period.

  4. chris kelly says:

    use to restore users.
    one could pull the list of deleted users Get-MsolUser -ReturnDeletedUsers
    throw it in a for each loop and restore everyone or dump to txct and do a gc pull for the foreach

    easy peasy…. nice article btw

    so kind of
    Import-Module MSOnline
    $deluserlist = Get-MsolUser -MaxResults 30 -ReturnDeletedUsers
    foreach ($user in $deluserlist){
    Restore-MsolUser -userPrincipalName $user

    that of course would restore all users taht are in the deleted items folder

  5. chris kelly says:

    sorry the above will deleted 30 returned users… remove the "maxresults" switch to restore all

  6. Armando says:

    what if i just need the sign-in status list

  7. Derrick says:

    I’m looking to assign licensed to actual users and not rooms. Is this possible? Running the command Get-MsolUser -UnlicensedUsersOnly gives me both rooms and resources in addition to actual users(people) there are licensed. Is there a way to automate this?
    We are looking to automate this process daily so that only actual users are licensed for email use.

  8. pierre4 says:

    Hi. I know it is not the goal of this forum but should we expect something more graphical and then less prone to human error? I did a lot of MS-DOS early in my career and PowerShell is like getting back to those old days!

  9. Rob Godbey says:

    Can you please help me with a script?

    Email notifications are not working in our SharePoint 365. After some detective work we found that most of our users to not have their real email address in Work Email. We discovered that the few people that get SharePoint notifications have their email address
    in Work Email, SIP Address and User Name (we use email address for User Name).

    I need a script that goes through our employee list (active directory) and picks up the User Name field-value and replaces the Work Email and SIP address field-values with the User Name value.

    It looks like I should be able to do that with PowerShell, but I’m not sure how. You may email me directly at

    Thanks for any help.

  10. Casey Crockett says:

    For only Unlicensed users, the answer is next to the highlighted option in Scripting Guy’s screenshot, -UnlicensedUsersOnly.

  11. A nice tip for people who use Office365 powershell a lot:

    Add a new system-wide environment variable, like ‘ps365’ with the entire command as the value:
    import-pssession (New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri -Credential $UserCredential -Authentication Basic -AllowRedirection)

    Then, from any new powershell prompt:
    invoke-expression $env:ps365

    Then you never have to remember the syntax again!

    -Eriq VanBibber

  12. John Gingrich says:

    Hi to All,

    The following PowerShell script worked extremely well for me.


    #Import Active Directory Module
    Import-Module -Name ActiveDirectory
    #Loop through all users with as UPN domain
    Get-ADUser -Filter {userprincipalname -like "*"} -SearchBase ‘OU=Root,DC=Name,DC=MyName,DC=com’ | ForEach-Object -Process {
    #Construct SIP address based on UPN
    $SIPAddress = "sip:{0}" -f $_.UserPrincipalName
    #Populate the msRTCSIP-PrimaryUserAddress attribute with the constructed SIP Address
    Set-ADUser -Identity $_.SamAccountName `
    -Replace @{"msRTCSIP-PrimaryUserAddress"=$SIPAddress}


    In the above script. replace these two items with your own:
    1. *
    2. ‘OU=Root,DC=Name,DC=MyName,DC=com’ (Test the script on a test OU first, not the root of your OU or domain.)

    After running the script, all users in the Searchbase will have the AD Attribute msRTCSIP-PrimaryUserAddress populated. Example =
    This allowed for seamless login to O365.
    Note: "sip" needs to be in lower case.

    PoSH on!

Skip to main content