Office 365 Migration How-to: Identify and Manage Tenant Administrators

Easily Identify and Audit Admin Roles in Office 365

For our very first post in our Office 365 Migration How-to’s and Scripts, we have a very simple Powershell script which makes identifying and managing your Office 365 tenant admins very easy. We constantly run into this requirement because global admins are the ones who can authenticate and use many third-party integrations like Cloud FastPath. As a result, there may be many global admins in a large organization. Keeping them accounted for has critical security (and sanity) implications.

Gist is available here: Identify and Manage Office 365 Global Admins

Any comments? Reach out to us on Twitter or here

<# First, let's connect to Office 365. We're going to learn how to import modules 
and assign variables. The commands below are very common, and if successful, will
simply return you to an empty command prompt. 
The Azure AD (MSOnline) module is available here:

Import-Module MSOnline
$credentials = Get-Credential
Connect-MsolService -Credential $credentials

<# You'll need an account that is a member of the Company Administrators 
(a Global Administrator role in O365 portal) to authenticate external 
applications such as Cloud FastPath.
You can read more about roles here:
Let's get a better of understanding of where these roles come from (Azure AD), 
and who has them. Type in this cmdlet to get a full list of these roles: 


<# To narrow things down, let's enumerate through each row of the output,
then pass each into a code block. In this code block we're examining the 
Name property of each row, and returning only ones which match 
"Company Administrator." 

Get-MsolRole | where { $_.Name -eq "Company Administrator" }

<# PS C:\Users\Ian> Get-MsolRole | where { $_.Name -eq "Company Administrator" }
  ObjectId                               Name                             Description                                                                                                                        
  --------                               ----                             -----------                                                                                                                        
  62e90394-69b5-4237-9190-012177145e10   Company Administrator            Company Administrator role...

<# We could just stop here, and just paste in the ObjectId.
A better solution is to assign the ObjectId property to a variable,  
and pass it into `Get-MsolRoleMember -RoleObjectId $ourNewVariable`.
Let's pipe (|) this into the same `Where {}` code block syntax we used before. If you're coming from bash,
you'll notice that these commands are case-insensitive, but the pipe looks very familiar. 
If you're coming from an OO language, you'll notice what looks something like a closure, 
and should observe that these are indeed objects we are working with. 

$CompanyAdministratorRole = Get-MsolRole | Where {$ -eq "company administrator" }

# Then grab the ObjectId, a property of the object we just created above
$CompanyAdminRoleObjectId = $CompanyAdministratorRole.ObjectId

# And assign the output of our command to $companyAdministrators
$CompanyAdministrators = Get-MsolRoleMember -RoleObjectId $CompanyAdminRoleObjectId

# show me the Company Administrators!

<# PS C:\Users\Ian> $CompanyAdministrators
  RoleMemberType EmailAddress                    DisplayName       isLicensed
  -------------- ------------                    -----------       ----------
  User                  Jerry S           True      
  User                 George C          True      
  User                 Elaine B          False     
  User                 C Kramer          False  

<# Great, and now we can see all of the properties on any of these objects (our Company Admins).
We can use what we've learned above to dig into one of those users with PowerShell, which will
give us a much more in-depth view than the UI. 
PowerShell does not necessarily encourage long, one-liner commands, and these examples are
primarily to show you features rather than a template, which would be much more modular. If you
are doing one-off's, you may be able to shorten these examples, but if you are scripting out a
reusable solution, it is best to write more clearly, rather than concisely. 

$Jerry = $CompanyAdministrators | Where { $_.EmailAddress -eq "" }

# Let's take a look at all of Jerry's properties: 
Get-MsolUser -UserPrincipalName $Jerry.EmailAddress | Select-Object *

<# If we don't have any Global Administrators set up, we can easily create one. Microsoft
recommends using service accounts whenever possible, which the CFP team also recommends. 
Let's create a brand new service account and assign it a role:

# To make our code clearer, let's create a function we can use that will only add Global Admins:
function New-GlobalAdmin ($Email, $GlobalAdminRoleId) {
  Add-MsolRoleMember -RoleObjectId $($GlobalAdminRoleId) -RoleMemberEmailAddress $($Email)

# Creating a new user is easy, and only requires two parameter values:
$Svc = New-MsolUser -UserPrincipalName "" -DisplayName "Newman"

New-GlobalAdmin -Email $Svc.UserPrincipalName -GlobalAdminRoleId $CompanyAdminRoleObjectId

# If we try to confirm this by simply typing,
# will show the old results. Let's re-examine and re-assign that variable
$CompanyAdministrators = Get-MsolRoleMember -RoleObjectId $CompanyAdminRoleObjectId

# Now if we try again:

<# PS C:\Users\Ian> $CompanyAdministrators
RoleMemberType EmailAddress                    DisplayName       isLicensed
-------------- ------------                    -----------       ----------
User           Newman            False  
# To explore more of the cmdlets offered by the Azure AD module, simply enter:
Get-Command -Module msonline

Planning a content migration to Office 365? Read our migration guide.