Check If Connected to SPOService in Script

SCENARIO
When executing SharePoint Online scripts you need to be connected to your “admin” site or the script will just fail if you’re not.

PROBLEM
When writing a script you can’t assume that you’re already connected to your SPO tenant and unlike the “msolservice” connect call you need to specify your “admin” URL which can be quite long. But sometimes you’re already connected in the Powershell session.

SOLUTION
Writing this little thing in the start of your script will check if you’re connected to the admin site and if not will call the connect-sposervice command with the URL already set.

# First we reset the sitecheck to avoid having an old result
$sitecheck=""
# This is the address of your SPO admin site
$adminurl = "https://[your tenant name]-admin.sharepoint.com"
# Now we try to get the SPOSITE info for the admin site
Try { $sitecheck = get-sposite $adminurl }
# If we get this server exception for any reason, the service isn't available and we need to take action, in this case
# write it to the console and then connect to the SPO service.
Catch [Microsoft.SharePoint.Client.ServerException]
{
Write-Host -foreground Yellow "You are not connected!"
connect-sposervice $adminurl
}

Get Users With Multiple Licenses

SCENARIO
You’re managing a large O365 tenant and you want to make sure there are no users that have multiple licenses assigned.

PROBLEM
The original problem is that you actually can assign a user with a F1, E1 and E3 license and end up paying three times for a user! Next problem comes with how license information is stored and retrieved with Powershell.

SOLUTION
Here is little code that will read out all your users and go through each one to make sure they don’t have more than one of the licenses assigned. It should work as long as Microsoft doesn’t change the _actual_ names for licenses!

$allusers = Get-MsolUser -All
foreach($msoluser in $allusers)
{
    $userpn = $msoluser.userprincipalname
    $userlicense = Get-MsolUser -UserPrincipalName $userpn | select Licenses
    if($userlicense.Licenses.AccountSkuId -like "*ENTERPRISEPACK*" -and $userlicense.Licenses.AccountSkuId -like "*DESKLESSPACK*" -and $userlicense.Licenses.AccountSkuId -like "*STANDARDPACK*")
    { 
        write-host -Foregroundcolor Red "$userpn has both E1 and E3 and F1"
    }
    elseif($userlicense.Licenses.AccountSkuId -like "*ENTERPRISEPACK*" -and $userlicense.Licenses.AccountSkuId -like "*STANDARDPACK*")
    { 
        write-host -Foregroundcolor Yellow "$userpn has both E3 and E1"
    }
    elseif($userlicense.Licenses.AccountSkuId -like "*STANDARDPACK*" -and $userlicense.Licenses.AccountSkuId -like "*DESKLESSPACK*")
    { 
        write-host -Foregroundcolor Yellow "$userpn has both E1 and F1"
    }
    elseif($userlicense.Licenses.AccountSkuId -like "*ENTERPRISEPACK*" -and $userlicense.Licenses.AccountSkuId -like "*DESKLESSPACK*")
    { 
        write-host -Foregroundcolor Yellow "$userpn has both E3 and F1"
    }
}

The script can ofcourse be enhanced to write a log or even mail a log to an admin if you want.

Get All MSOLRoleMembers

This is a small little script I wrote for going through all administrator roles in your O365 tenant and listing out the members of each. This can be handy if you feel like you’re losing control over who has what permission in the tenant or someone says the classic “I want what he has”.

$DateStamp = Get-Date -Format "yyyy-MM-dd-HH-mm"
$LogFile = ("C:\temp\get_all_msolrolemembers-" + $DateStamp + ".csv")

# Defining the log function
Function LogWrite
{
	Param ([string]$logstring)
	Add-content $Logfile -value $logstring
}
LogWrite ("msolrole;email;displayname;islicensed")

$msolroles = get-msolrole
foreach($role in $msolroles)
{
	$rolemembers = get-msolrolemember -roleobjectid $role.objectid
	foreach($rolemember in $rolemembers)
	{
		LogWrite ($role.name + ";" + $rolemember.emailaddress + ";" + $rolemember.DisplayName + ";" + $rolemember.islicensed +";")
	}
}

New-MSOLUserPrincipalName

SCENARIO
You’re changing the e-mail domain of a user or even a bunch of users. After that you also need to set their UPN’s to reflect the change.

PROBLEM
The problem is that Azure AD Connect service doesn’t currently support changing domain of a UPN of an object that is already synced! So you have to run a powershell command to change it. But it get’s even more complicated because you can’t change the UPN from one federated domain to another without making it “unfederated” first.

SOLUTION
Enter New-MSOLUserPrincipalName, which is a function that will take the user with the current UPN ($UserPrincipalName), change it to a temporary UPN with the domain extension “@[your tenant].onmicrosoft.com” and change it to the new UPN ($NewUserPrincipalName).

function New-MSOLUserPrincipalName {
  param (
    $UserPrincipalName,
    $NewUserPrincipalName
  )
  $TempUPN = "{0}@[your tenantname].onmicrosoft.com" -f $UserPrincipalName.split("@")
  Set-MsolUserPrincipalName -UserPrincipalName $UserPrincipalName -NewUserPrincipalName $TempUPN | Out-Null
  Set-MsolUserPrincipalName -UserPrincipalName $TempUPN -NewUserPrincipalName $NewUserPrincipalName
  Write-Output -InputObject "Successfully changed UPN from $UserPrincipalName to $NewUserPrincipalName"
}   

Thanx to Johan Dahlbom for this one!

Download PS1 from Dropbox

Download PS1 from Dropbox

Remove User Mailbox Permissions

SCENARIO
A user has alot of mailbox permissions to other mailboxes that needs to be revoked.

PROBLEM
The problem is that the GUI, even in an on-prem interface, forces you to remove the permissions on the destination so you have to go to every mailbox he/she has access to, remove the permission and then go to the next. This is very time consuming, one wish you could open the user and remove the permissions to other mailboxes that way, but it doesn’t work like that unfortunately.

SOLUTION
This little script solves this problem. It goes through all mailboxes in your mailenvironment and checks all the boxes that the [USER] has access to and prompts to remove them one by one. I still feel a prompt is necessary because sometimes you get the request to “remove everything except these”, so by prompting we can chose which ones to remove. Alot faster than going to every mailbox in the list! For better performance, I suggest you specify a “-servername EXCHANGESERVER” in the “get-mailbox” command, otherwise it’ll go through the entire Exchange org.

$user = "[USER]"
$permissions = Get-Mailbox -resultsize unlimited | Get-MailboxPermission -User $user
foreach($permission in $permissions)
{
$identity = $permission.identity
$accessright = $permission.accessrights
write-host "Removing permission for $user on $identity"
remove-mailboxpermission -Identity $identity -User $user -Accessrights $accessright
}

Download PS1 from Dropbox

Download PS1 from Dropbox

Change Something On Users From File

SCENARIO
You’re the administrator of an Office 365 tenant and/or on-prem Exchange and Active Directory and you need to make bulk changes to a group of people and you have a list with UPNs ready to use.

PROBLEM
There really is no problem but it may be very repetetive tasks.

SOLUTION
This script will read the file “C:\temp\list_of_upns.txt“, which is just a list of UPN’s, and iterate through them making the change you want. Since I make alot of the same changes to different users depending on what I need. I simply un-comment by removing the “#” for whatever I need to script to change on the user. And remember to put the “#” back in to comment if you want it to do something else or you may end up doing unwanted things on the objects (like converting a bunch of on-prem mailboxes to Room mailboxes, true story!)

# Written by : Kristoffer Strom ([email protected])
# Date: 2017-02-20
#
#Starting the loop
ForEach ($user in $(Get-Content C:\temp\list_of_upns.txt ))
{
write-host $user
#Set-Mailbox $user -Type shared
#$userdn = get-aduser  -Filter{UserPrincipalName -eq $user} -properties DistinguishedName
#$DN = Get-ADUser -Filter { UserPrincipalName -Eq $user }
#set-aduser $DN -Replace @{extensionAttribute1 = "REPLACEMENTTEXT"}
#set-aduser $DN -clear extensionAttribute1, extensionAttribute1, AdminDisplayname, AdminDescription
#remove-adgroupmember -Identity "ADGROUP" -Member $DN
#Set-MsolUserLicense -UserPrincipalName $user -RemoveLicenses "XXXXXXXXXX:ENTERPRISEPACK"
#Set-MsolUserLicense -UserPrincipalName $user -RemoveLicenses "XXXXXXXXXX:POWER_BI_STANDARD"
}

Download PS1 from Dropbox

Download PS1 from Dropbox

Get User Serviceplans

SCENARIO
You’re the administrator of Office 365 and you want to programmatically extract information about what serviceplans (features) a specific user has access to and which he or she doesn’t have access to.

PROBLEM
Microsoft’s way of storing the information regarding licenses and features/plans isn’t quite logical sometimes for unitiated people so this might sound like a very complicated thing to do with Powershell and you’re left to do it through the portal instead.

SOLUTION
This little snippet of code will help you. You can add exporting features to it if you want, or input a user.txt file, but this is the stuff that displays the information. But if you want to get a complete dump of all information for all users, you should use this script instead which does that magic alot better.

#
# Written by : Kristoffer Strom ([email protected])
# Date: 2017-02-20
#
# Here we define what user we're querying:
$upn = "[INSERT UPN HERE]"
# Here we set the index to 0
$i = 0
# Run the query to get user info
$user = get-msoluser -userprincipalname $upn
# Store the license array
$features = $user.licenses
# Just an empty row
write-host ""
# Running the loop to show info on all licenses
while($i -lt $features.count)
{
    $AccountSkuId = $features[$i].AccountSkuId
    Write-host -NoNewline -ForegroundColor Cyan "Features for $AccountSkuId"
    $features[$i].servicestatus | ft
    $i++
}

Download PS1 from Dropbox

Download PS1 from Dropbox

UPDATE: Apparently the new Powershell moduled for MSOL handled this differently so the output became quite different. Rather than type out one plan at a time it bunched them together so there was no way of seeing which feature belonged to which plan. So I re-wrote this with a “while” loop and “format table” command to force it to seperate the output. (seriously, remove the “ | ft” part and see what that does to this snippet!)

Set UsageLocation Where Empty

SCENARIO
You’re the administrator of a large tenant with several different e-mail domains for people in different countries. Manually setting a UsageLocation, which is required for license activation, for them all individually is unrealistic.

PROBLEM
The problem here is we need some way of filtering out who is actually where. The perfect solution is ofcourse to have the AD property (“msExchUsageLocation”) since Azure AD Connect syncs it out of the box. But not everyone has that luxury, especially if it’s a domain you’re not even in charge of. And the get-msoluser cmdlet with -domain filter will not only catch the ones that have the domain as their primary e-mail, but also the ones that have it as secondary so as a filter it won’t work.

SOLUTION
In comes this little bit of code! It loads all users, filters out everyone that has a license and everyone that doesn’t have a UPN matching the domain (in this example “test.se” and for the rest sets the UsageLocation to whatever you want, in this example “SE“. This way, we only get the ones that don’t have a license yet and only the ones with this specific domain as their primary e-mail (which should match UPN). So if your company’s name is “test” and everyone has a “test.com” address as a secondary, but the Swedish employees have “test.se” as their primary you can easily set their usagelocations like this. And then just change it around for the rest of the company.

#
# Written by : Kristoffer Strom ([email protected])
# Date: 2017-02-10
#
# Credit to Reditor bearxor (https://www.reddit.com/user/bearxor)
#
# We check all users for users with no UsageLocation set and matches a e-mail domain (test.se) and sets the UsageLocation SE (=Sweden)
Get-MsolUser -All | where{$_.UsageLocation -eq $null -and $_.userprincipalname -like "*@test.se"} | foreach{set-msoluser -UserPrincipalName $_.UserPrincipalName -UsageLocation "SE"}

Download PS1 from Dropbox

Download PS1 from Dropbox

Powershell to Exchange Online

SCENARIO
You’re used to having your Exchange server in your own environment and Powershelling to it and run all these scripts you’ve collected over the years.

PROBLEM
Now that the mailboxes are in a database you have no control of on a server somewhere at Microsoft how are you supposed to run those Exchange Powershells?

SOLUTION
This is the MS way of executing Powershell against Exchange Online using Powershell commands you’d usually use on an on-premise Exchange environment. This is very basic stuff, but if you’re just getting started with Office 365, this is essential to manage users in Exchange Online!

$UserCredential = Get-Credential
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri https://outlook.office365.com/powershell-liveid/ -Credential $UserCredential -Authentication Basic -AllowRedirection
Import-PSSession $Session

Basically what this does is connects you to Exchange Online and starts a remote Powershell session on Microsoft’s server. This unfortunately means that you are limited to the automation limits, which means sometimes when you do really, really heavy stuff you’ll run into throttling errors from “Microsoft.Online.Administration.Automation.MicrosoftOnlineException”. Usually that’s just an error saying you need to code better with more filters!