Monthly Archives: December 2016

ADFS Customization – Branding per domain for Azure AD/Office 365

Branding your services can be very important for many reasons where recognizability and company profile are the most common ones. Making the marketing department happy is not a bad thing either.
With ADFS in Server 2016, the capability to do branding on a relying party basis was added. This was something that you in 2012 R2 needed to use JavaScript to achieve. Please note that the customizations in this post works both in 2012R2 and 2016.

While the default branding options above fit most customer needs, I recently had a customer case where two municipalities were onboarding to Office 365. Since they were sharing the same AD domain, they also shared their ADFS environment. You can probably guess where we are going now… They want continue using the same ADFS environment but have different branding depending on the login domain in Office 365 / Azure AD. I have got this request before, but have usually talked out the customers of going that path and instead agree upon common branding, but not this time. Not the most evergreen solution, but all for the customers, right? 🙂

There is a uservoice for the same request using managed domains directly in Azure AD – so clearly this is not the first time this has come up.

OVERVIEW
We will customize onload.js to apply different branding depending on the Office 365 / Azure AD domain used to login.
If browsing /idpinitiatedsignon directly or using another RP than Azure AD/Office 365, the default branding should apply. In my example, I will use the domains dom1.365lab.net and dom2.365lab.net. I assume that basic branding/webtheme already is in place.

The branding will apply in the following scenarios:

UPLOAD LOGO AND ILLUSTRATION
Upload the logos and illustrations as in my example script below. For performance and looks, follow the recommendation on sizes etc. on this TechNet page. If you have many domains, using some kind of naming convention might also be a good idea ;-).

$WebThemeName = "365lab"
#The pictures to upload
$UploadData = @{
  logo = @('C:\temp\Branding\dom1.365lab.net_logo.png',
           'C:\temp\Branding\dom2.365lab.net_logo.png')
  illustration = @('C:\temp\Branding\dom1.365lab.net_illustration.jpg',
                  'C:\temp\Branding\dom2.365lab.net_illustration.jpg')
}                                                                                                              
#Loop through the image HT and upload the files accordingly
foreach ($ImageType in $UploadData.Keys) {
  $UploadData[$ImageType] | ForEach-Object -Process {
    $FileName = $_.Split('\')[-1]
    Set-AdfsWebTheme -TargetName $WebThemeName `
                      -AdditionalFileResource @{
                        Uri = '/adfs/portal/{0}/{1}' -f $ImageType,$FileName
                        Path = $_.ToString() 
                      } 
  }                  
}                                                                                                                                                                                                                               

CUSTOMIZATION OF ONLOAD.JS
The JavaScript basically loops through an array and checks if the request has been referred from any of the domains in scope for customizations. In the example, the username placeholder and the login message are customized based on the “domainconfig” data as well. If you don’t know how to export/import onload.js to ADFS, looking in to this article prior doing any changes might be a good idea.

//Variables
var locationUrl = window.location.href.toLowerCase(),
	referrerUrl = document.referrer.toLowerCase(),
    logoDomain = document.getElementById('header'),
    loginMessage = document.getElementById('loginMessage'),
    userNameInput = document.getElementById('userNameInput'),
    domainconfig = [
        {domain:"dom1.365lab.net", companyName: "365lab Domain 1", logo:"dom1.365lab.net_logo.png", illustration:"dom1.365lab.net_illustration.jpg"},
        {domain:"dom2.365lab.net", companyName: "365lab Domain 2", logo:"dom2.365lab.net_logo.png", illustration:"dom2.365lab.net_illustration.jpg"}
    ];

function checkUrlForDomain(domainName) {
  return locationUrl.indexOf(domainName) > -1 || referrerUrl.indexOf(domainName) > -1;
}

for (var j = 0; j < domainconfig.length; j++){
  var domainName = domainconfig[j].domain;
  if (checkUrlForDomain(domainName)) {
     var logo = domainconfig[j].logo;
     var illustration = domainconfig[j].illustration;
     var companyName = domainconfig[j].companyName;

     //for troubleshooting purposes
     //console.log(domainName); 
     //console.log(logo);
     //console.log(illustration);

     //Change Logo
     logoDomain.innerHTML = "<img class='logoImage' src='/adfs/portal/logo/" + logo +"' alt='" + domainName + "'" +">"
     //Change illustration
     document.getElementsByTagName('style')[0].innerHTML = ".illustrationClass {background-image:url(/adfs/portal/illustration/" + illustration + ");}"; 
     //Change login message
     loginMessage.innerHTML = "<h2>Sign in with your " + companyName + " account </h2>" ;
     //Change username placeholder
     userNameInput.placeholder = "firstname.lastname@" + domainName ;
  }
}

After updated onload.js with your code, upload the changes to your webtheme with the following PowerShell cmdlet.

$WebThemeName = "365lab"
Set-AdfsWebTheme -TargetName $WebThemeName `
                 -AdditionalFileResource @{
                    Uri="/adfs/portal/script/onload.js"
                    path="C:\temp\script\onload.js"
                  }

RESULTS
Voila! We now have different branding in our ADFS depending on the domain suffix entered in Office 365 / Azure AD. Note that the code won’t change branding if you change the domain suffix in the username field after hitting the ADFS farm.

idpInitiatedSignOn
2016-12-30_11-00-39
Browsing outlook.com/dom1.365lab.net
2016-12-30_10-59-33
Browsing outlook.com/dom2.365lab.net
2016-12-30_11-00-16

Good luck with your branding and as always, let me know if you have feedback!

Happy new year!

/Johan

Advertisements

Assign individual parts of licenses with Azure AD PowerShell V2.0

Azure AD PowerShell V2 has been in GA for almost a month now. Even though some features (like converting a domain to federated) are missing as of now, it is really time to start to rewrite all those old MSOnline module scripts as AAD PS PM Rob de Jong reminded me of this thursday.

Since licensing still is the most important task to automate in customer environments I thought it was a good idea to share some of the basics on how to licensing works in V2.0. Some day, when ‘Azure AD Group Based licensing’ is in place, we can get rid of most of these these licensing scripts.

Since most of my customers rarely roll out all services at once, I thought it was a good idea to show you how to roll out a few serviceplans at a time with Azure AD PowerShell V2.0. If you want to look in to the basics, fellow MVP Simon Wåhlin wrote a great post about this a month ago.

Find your LicenseSku’s and ServicePlans:
Luckily enough, the equivalent to Get-MsolAccountSku, Get-AzureADSubscribedSku gives us pretty much the same information as its predecessor.
aadsku
As seen in the screenshot, we can still identify the licenses with their partnumber even though we need the SkuId’s when assigning the licenses later which is really helpful converting your old scripts.

Finding the individual services is as easy, you only need to look in to the ServicePlans property instead of ServiceStatus. As with the base license, you’ll need to use the ServicePlanId of the specific plan if you want to disable it.
serviceplans

Putting it together and assign individual ServicePlans of a license:
In my example, I will enable a non-licensed user an E3 that has Exchange Online, Skype for Business and Office 365 ProPlus enabled. In staged onboarding cases usually choose the ones to enable in my scripts instead of hard coding the disabled ones, since Microsoft tend to add new serviceplans from time to time (Teams, PowerApps, Flow etc.). You can of course do it the other way around if that fits your organization better.
Note that it is still a requirement to assign the UsageLocation on the user before assigning the license.

#The user that will get a license
$UserToLicense = Get-AzureADUser -ObjectId "johan@365lab.net"

#Define the plans that will be enabled (Exchange Online, Skype for Business and Office 365 ProPlus )
$EnabledPlans = 'EXCHANGE_S_ENTERPRISE','MCOSTANDARD','OFFICESUBSCRIPTION'
#Get the LicenseSKU and create the Disabled ServicePlans object
$LicenseSku = Get-AzureADSubscribedSku | Where-Object {$_.SkuPartNumber -eq 'ENTERPRISEPACK'} 
#Loop through all the individual plans and disable all plans except the one in $EnabledPlans
$DisabledPlans = $LicenseSku.ServicePlans | ForEach-Object -Process { 
  $_ | Where-Object -FilterScript {$_.ServicePlanName -notin $EnabledPlans }
}

#Create the AssignedLicense object with the License and DisabledPlans earlier created
$License = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicense
$License.SkuId = $LicenseSku.SkuId
$License.DisabledPlans = $DisabledPlans.ServicePlanId

#Create the AssignedLicenses Object 
$AssignedLicenses = New-Object -TypeName Microsoft.Open.AzureAD.Model.AssignedLicenses
$AssignedLicenses.AddLicenses = $License
$AssignedLicenses.RemoveLicenses = @()

#Assign the license to the user
Set-AzureADUserLicense -ObjectId $UserToLicense.ObjectId -AssignedLicenses $AssignedLicenses

In the latest preview version of the module (2.0.0.44) that I used when writing the post, I didn’t manage to assign a license to a new user without defining the RemoveLicenses property of the AssignedLicenses object.
2016-12-25_13-21-58

Verifying the licenses in the portal (yeah, could of course have done that with PowerShell as well.), it looks just as expected. If I wanted to enable more plans for the user I could just change the EnabledPlans array and run the script again.
2016-12-25_13-30-16

Summary
Azure AD PowerShell V2.0 gives us all needed functionality to keep automating our license assignment in Azure AD. It might take you a bit longer to learn it since it is somewhat more “PowerShelly” with the different objects used to assign the licenses but apart from that, I really like it. I have not done any scientific tests (might do), but it seems like it is also much faster using the Graph API endpoints than the old endpoints doing different actions against Azure AD.
I will follow this post up with hopefully new and updated versions of my larger and more advanced scripts built on the old module.

Let me know if you have questions!

/Johan