Assign O365 product licence only where not already assigned

Hi,

I have a project to assign licenses to users within O365. I’m fine with the process of adding, removing, configuring etc. but would like to make this a little tidier.

Basically I have the below code which configures an already enabled licence (ENTERPRISEPACK) and enables another (EMS):

$TargetUsers = Get-ADUser -Filter * -SearchBase "OU=To Migrate,OU=Department,OU=Company,DC=Domain,DC=local"

$O365EntE3 = New-MsolLicenseOptions -AccountSkuId tenent:ENTERPRISEPACK #-DisabledPlans MCOSTANDARD
$EMSE3 = New-MsolLicenseOptions -AccountSkuId tenent:EMS

#Loop through the found users and set required licenses. 
$TargetUsers | ForEach-Object {
    Set-MsolUserLicense -UserPrincipalName $_.UserPrincipalName -LicenseOptions $O365EntE3
    Set-MsolUserLicense -UserPrincipalName $_.UserPrincipalName -AddLicenses callcreditgroup:EMS
    }

This works fine but where an EMS licence is already assigned, it will error on subsequent runs with the following error:

Set-MsolUserLicense : Unable to assign this license because it is invalid. Use the Get-MsolAccountSku cmdlet to retrieve a list of valid licenses.

The following Technet article mentions this in the security note just past half way down the page but not how to address it: https://technet.microsoft.com/en-us/library/dn771770.aspx

Is there a way to run this command only the product unlicensed?

My thinking is along the lines of:

Where-Object {$_.IsLicensed -eq "false"} | set-MsolUserLicense -UserPrincipalName $_.UserPrincipalName -AddLicenses callcreditgroup:EMS

but this isn’t specifying the product before the pipe so obviously won’t work. Any way to do this or am I doomed to just accept the error?

Cheers
Jamie

If it’s an error you can anticipate and deal with, or ignore, why not just handle the error? As in, a Try/Catch?

Hi Don,

Yes that would be a good solution. Not something I’ve really used in my scripts before so will have a little read up but suppose I was hoping that I could address this with a “where” cmdlet or “If” conditional logic etc.

Thanks for the advice.

Jamie

OK, so the following works nicely:

#Currently setting all services within this plan
$O365EntE3 = New-MsolLicenseOptions -AccountSkuId tenent:ENTERPRISEPACK #-DisabledPlans MCOSTANDARD
#Currently setting all services within this plan
$EMSE3 = New-MsolLicenseOptions -AccountSkuId tenent:EMS

#Loop through the found users and set required licenses. 
$TargetUsers | ForEach-Object { 
    Set-MsolUserLicense -UserPrincipalName $_.UserPrincipalName -LicenseOptions $O365EntE3
        Try
        {
            Set-MsolUserLicense -UserPrincipalName $_.UserPrincipalName -AddLicenses tenent:EMS -ErrorAction Stop
        }
        Catch
        {
            Write-Warning "EMS Licence already assigned"
        }
    }

But would like the output message to include each username that that may already have this. Adding $TargetUsers to the message just lists all users in one line regardless of whether they already have the license or not.

Cheers
Jamie

Jamie,

Try to add the $_.DisplayName (or the property that you want) instead of $TargetUsers on the warning message.

Hi Vandrey,

I did already try along those lines but $_ in this instance returns the error “Unable to assign this license because it is invalid. Use the Get-MsolAccountSku cmdlet to retrieve a list of valid licenses.” rather than user it’s working with

I did try another route:

#Currently setting all services within this plan
$O365EntE3 = New-MsolLicenseOptions -AccountSkuId tenent:ENTERPRISEPACK #-DisabledPlans MCOSTANDARD
#Currently setting all services within this plan
$EMSE3 = New-MsolLicenseOptions -AccountSkuId tenent:EMS

#Loop through the found users and set required licenses. 
ForEach ($TargetUser in $TargetUsers) { 
    Set-MsolUserLicense -UserPrincipalName $_.UserPrincipalName -LicenseOptions $O365EntE3
        Try
        {
            Set-MsolUserLicense -UserPrincipalName $_.UserPrincipalName -AddLicenses tenent:EMS -ErrorAction Stop
        }
        Catch
        {
            Write-Warning "EMS Licence already assigned to $TargetUser"
        }
    }

but this just fails all commands and returns:

Set-MsolUserLicense : Cannot bind argument to parameter 'UserPrincipalName' because it is null. At line:50 char:44 + ... Set-MsolUserLicense -UserPrincipalName $_.UserPrincipalName -Licens ... + ~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidData: (:) [Set-MsolUserLicense], ParameterBindingValidationException + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.Online.Administration.Automation.SetUserLicense

Cheers
Jamie

Jamie,

You need to write the property “$TargetUser.PrimarySmtpAddress”
Only use “$_.Property” when using the Foreach-Object loop.
On the “foreach ($TargetUser in $TargetUsers)” loop, you need to use “$TargetUser.Property”

Try this:

ForEach ($TargetUser in $TargetUsers) { 
    Set-MsolUserLicense -UserPrincipalName $TargetUser.PrimarySmtpAddress -LicenseOptions $O365EntE3
        Try
        {
            Set-MsolUserLicense -UserPrincipalName $TargetUser.PrimarySmtpAddress -AddLicenses tenent:EMS -ErrorAction Stop
        }
        Catch
        {
            Write-Warning "EMS Licence already assigned to TargetUser.PrimarySmtpAddress"
        }
    }

You beat me to it…I’ve been having a play around and the figured out the following works which is pretty much exactly what you said!:

foreach ($User in $TargetUsers) {
    Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -LicenseOptions $O365EntE3
    Write-Information -MessageData "All Office 365 Enterprise E3 services enabled for $($User.UserPrincipalName)" -InformationAction Continue
        Try
        {
            Set-MsolUserLicense -UserPrincipalName $User.UserPrincipalName -AddLicenses tenent:EMS -ErrorAction Stop            
            Write-Information -MessageData "EMS Product enabled for $($SUser.UserPrincipalName)" -InformationAction Continue
        }
        Catch
        {
            Write-Warning "EMS Licence already assigned to $($User.UserPrincipalName)"
        }
    }

Noted of when to use the $_.Property. Thanks for the advice.

Great! Glad that it worked! :smiley: