Scripting Office 365 licensing with disabled services

Have had a few clients request scripts to automatically set assign licenses to users in Office 365 – Generally pretty simple. Recently I had a client ask to disable a particular service within a license – again, not all that difficult – unless you want to actually check if a license/service is already configured and not make any changes. Took a little while to work out, so figured I’d share it with those interested!

 

Just to set a license for a user is a pretty simple process – all you need is the license ‘SkuId’ value. To get a list of the ones available in your tenant, run: Get-MsolAccountSku. You’ll get a list of the available license SkuId’s and how many are active/consumed. In this article we’ll use an example SkuId of “Contoso:STANDARDWOFFPACK_IW_STUDENT”. Once you have the SkuId, all you need to run to assign the license is:

Set-MsolUser -UserPrincipalName user@contoso.com -UsageLocation AU

Set-MsolUserLicense -UserPrincipalName user@contoso.com -AddLicenses “Contoso:STANDARDWOFFPACK_IW_STUDENT”

 

Note: in order to assign a license, you also need to first assign a usage location to the user. If that’s already assigned, you can skip that line.

 

What if you didn’t want to have all the applications available for the user? For example, the above license includes Yammer Education. In this case, we need to create a ‘License Options’ object first.

$LicenseOption = New-MsolLicenseOptions -AccountSkuId “Contoso:STANDARDWOFFPACK_IW_STUDENT” -DisabledPlans YAMMER_EDU

Set-MsolUserLicense -UserPrincipalName user@contoso.com –LicenseOptions $LicenseOption

 

So where did we get the “YAMMER_EDU” from? You can list the available services for a license by running:

(Get-MsolAccountSku | where {$_.AccountSkuId -eq ‘Contoso:STANDARDWOFFPACK_IW_STUDENT’}).ServiceStatus

 

What if we wanted to disable multiple services in the License Option? The “-DisabledPlans” option accepts a comma-separated list. For example:

$LicenseOption = New-MsolLicenseOptions -AccountSkuId “Contoso:STANDARDWOFFPACK_IW_STUDENT” -DisabledPlans YAMMER_EDU, SWAY

 

Ok, so now we know how to get the available licenses and related services – as well as how to assign the license to the user. What if we wanted to check if a license is assigned to a user first? Personally, I’m not a huge fan of just re-stamping settings each time you run a script – so I thought I’d look into it. The easiest method I’ve found is to try bind to the license, then check if it’s $null or not:

$User = Get-MsolUser -UserPrincipalName user@contoso.com

$License = $User.Licenses | Where{$_.AccountSkuId -ieq “Contoso:STANDARDWOFFPACK_IW_STUDENT”}

If ($License) {Write-Host “Found License”} else { Write-Host “Didn’t Find License”}

 

From there we can do whatever we want – if the license is found and that’s all you care about, you can skip – otherwise you can use the other commands to set the license.

So what if we also want to make sure YAMMER_EDU is disabled as well? That’s a little trickier. First we need to bind to the license like we did above, then we need to check the status of the relevant ‘ServicePlan’.

$User = Get-MsolUser -UserPrincipalName user@contoso.com

$License = $User.Licenses | Where{$_.AccountSkuId -ieq “Contoso:STANDARDWOFFPACK_IW_STUDENT”}

If($License)

{

If($License.ServiceStatus | Where{$_.ServicePlan.ServiceName -ieq “YAMMER_EDU” -and $_.ProvisioningStatus -ine “Disabled”})

{

Write-Host “YAMMER_EDU isn’t disabled”

}

}

 

At this point it’s probably a good idea to talk about the structure of these objects – you may not need to know it, but for anyone trying to modify these commands it might be helpful.

  • A ‘User’ object contains an attribute ‘Licenses’. This attribute is an array – as a user can have multiple licenses assigned.
  • A ‘License’ object contains two attributes relevant to this script; ‘AccountSkuID’ and ‘ServiceStatus’
    • AccountSkuId is the attribute that matches up with the AccountSkuId we’re using above
    • ServiceStatus is another array – it contains an array of objects representing the individual services available in that license – and their status.
  • The two attributes attached to a ‘ServiceStatus’ object that we care about are:
    • ServicePlan.ServiceName – this is the name to match the service above (eg: YAMMER_EDU)
    • ProvisioningStatus – this can be a bunch of values, but mostly ‘Success’, ‘Disabled’ or ‘PendingInput’. I’d assume there’s also ‘Provisioning’, but I’ve never seen it.

 

With this in mind, we can put together a script like the following – it reads the UPN and AccountSkuID from a CSV file, though you could use whatever source you like and update the script accordingly.

 

As with the previous scripts, you need the following:

 

You’ll also need to update the 6 variables at the top of the script (paths, etc).

 

 

#Input File

$File = “D:\_Temp\ExchangeOnline\Source.csv”

 

#Log Variables

$LogFile = “D:\_Temp\ExchangeOnline\SetLicenses_$((Get-Date).ToString(“yyyyMMdd”)).log”

$AuditFile = “D:\_Temp\ExchangeOnline\SetLicenses_Audit.log”

 

#Credentials

$AdminUser = “admin@contoso.com

$PasswordFile = “D:\_Temp\ExchangeOnline\EO_Password.txt”

$KeyFile = “D:\_Temp\ExchangeOnline\EO_AES.key”

 

Write-Output “$(Get-Date -format ‘G’) ========Script Started========” | Tee-Object $LogFile -Append

 

#Build the credentials object

Write-Output “$(Get-Date -format ‘G’) Creating credentials object” | Tee-Object $LogFile -Append

$key = Get-Content $KeyFile

$SecurePassword = Get-Content $PasswordFile | ConvertTo-SecureString -Key $key

$Creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AdminUser, $SecurePassword

 

#Import the MSOnline Module

IMport-Module MSOnline

 

#Connect to MSOnline

Write-Output “$(Get-Date -format ‘G’) Connecting to MSOnline” | Tee-Object $LogFile -Append

Connect-MsolService -Credential $Creds

 

#Grab the CSV contents

$CSV = Import-CSV $File

#Go through each entry

Foreach($Line in $CSV)

{

$samAccountName = $line.samAccountName

$UPN = $Line.UPN

$SKUID = $Line.license

 

Write-Output “$(Get-Date -format ‘G’) Processing User $UPN” | Tee-Object $LogFile -Append

 

#Make sure the user exists in MSOnline

If(Get-MsolUser -UserPrincipalName $UPN)

{

#Found in MSOnline. Put the user account into a variable

Write-Output “$(Get-Date -format ‘G’) – Located in MSOnline” | Tee-Object $LogFile -Append

$User = Get-MsolUser -UserPrincipalName $UPN

#Check the UsageLocation

If($User.UsageLocation -ine “AU”)

{

Write-Output “$(Get-Date -format ‘G’) – Location not set to AU. Updating…” | Tee-Object $LogFile -Append

#Update it

Set-MsolUser -UserPrincipalName $User.UserPrincipalName -UsageLocation AU

Write-Output “$(Get-Date -format ‘G’) $UPN Location set to AU” | Out-File $AuditFile -Append

}

 

#Check if the license is attached to the user

$SetLicense = $false

Write-Output “$(Get-Date -format ‘G’) – Checking for License: $SKUID” | Tee-Object $LogFile -Append

$License = $User.Licenses | Where{$_.AccountSkuId -ieq $SKUID}

If($License)

{

#License is attached. Check to make sure that any services to be disabled are actually disabled

Write-Output “$(Get-Date -format ‘G’) – License already attached. Checking if required services are disabled” | Tee-Object $LogFile -Append

If($License.ServiceStatus | Where{$_.ServicePlan.ServiceName -ieq “YAMMER_EDU” -and $_.ProvisioningStatus -ine “Disabled”})

{

Write-Output “$(Get-Date -format ‘G’) – YAMMER_EDU not disabled.” | Tee-Object $LogFile -Append

$SetLicense = $True

}

 

If($SetLicense){Write-Output “$(Get-Date -format ‘G’) – One or more services not disabled. License requires updating.” | Tee-Object $LogFile -Append}

}

Else

{

#License is not attached.

Write-Output “$(Get-Date -format ‘G’) – License is not attached. Will be attached.” | Tee-Object $LogFile -Append

$SetLicense = $True

}

 

If($SetLicense)

{

#License is not attached or not configured correctly. Build up the license with required options

$LicenseOption = New-MsolLicenseOptions -AccountSkuId $SKUID -DisabledPlans YAMMER_EDU

#Set the License

Write-Output “$(Get-Date -format ‘G’) – Setting/Updating license” | Tee-Object $LogFile -Append

Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName –LicenseOptions $LicenseOption

Write-Output “$(Get-Date -format ‘G’) $UPN License set/updated for SkuId: $SKUID” | Out-File $AuditFile -Append

}

else

{

Write-Output “$(Get-Date -format ‘G’) – No changes to license required” | Tee-Object $LogFile -Append

}

 

# Clear loop variables for the next run

$samAccountName = $Null

$UPN = $Null

$SKUID = $Null

$User = $Null

$License = $Null

$SetLicense = $Null

$LicenseOption = $Null

}

else

{

Write-Output “$(Get-Date -format ‘G’) – Error: User not found in MSOnline” | Tee-Object $LogFile -Append

}

 

}

 

Write-Output “$(Get-Date -format ‘G’) ========Script Complete========” | Tee-Object $LogFile -Append