Originally posted on Nivlesh’s blog @ nivleshc.wordpress.com
In this multi-part blog, I will be showing how to automatically install and configure a new ADFS Farm. We will accomplish this using Azure Resource Manager templates, Desired State Configuration scripts and Custom Script Extensions.
We will use Azure Resource Manager to create a virtual machine that will become our first ADFS Server. We will then use a desired state configuration script to join the virtual machine to our Active Directory domain and to install the ADFS role. Finally, we will use a Custom Script Extension to install our first ADFS Farm.
Install ADFS Role
We will be using the xActiveDirectory and xPendingReboot experimental DSC modules.
Download these from
After downloading, unzip the file and place the contents in the Powershell modules directory located at $env:ProgramFiles\WindowsPowerShell\Modules (unless you have changed your systemroot folder, this will be located at C:\ProgramFiles\WindowsPowerShell\Modules )
Open your Windows Powershell ISE and lets create a DSC script that will join our virtual machine to the domain and also install the ADFS role.
Copy the following into a new Windows Powershell ISE file and save it as a filename of your choice (I saved mine as InstallADFS.ps1)
In the above, we are declaring some mandatory parameters and some variables that will be used within the script
$MachineName is the hostname of the virtual machine that will become the first ADFS server
$DomainName is the name of the domain where the virtual machine will be joined
$AdminCreds contains the username and password for an account that has permissions to join the virtual machine to the domain
$RetryCount and $RetryIntervalSec hold values that will be used to check if the domain is available
We need to import the experimental DSC modules that we had downloaded. To do this, add the following lines to the DSC script
Import-DscResource -Module xActiveDirectory, xPendingReboot
Next, we need to convert the supplied $AdminCreds into a domain\username format. This is accomplished by the following lines (the converted value is held in $DomainCreds )
Next, we need to tell DSC that the command needs to be run on the local computer. This is done by the following line (localhost refers to the local computer)
We need to tell the LocalConfigurationManager that it should reboot the server if needed, continue with the configuration after reboot, and to just apply the settings only once (DSC can apply a setting and constantly monitor it to check that it has not been changed. If the setting is found to be changed, DSC can re-apply the setting. In our case we will not do this, we will apply the setting just once).
Next, we need to check if the Active Directory domain is ready. For this, we will use the xWaitForADDomain function from the xActiveDirectory experimental DSC module.
Once we know that the Active Directory domain is available, we can go ahead and join the virtual machine to the domain.
the JoinDomain function depends on xWaitForADDomain. If xWaitForADDomain fails, JoinDomain will not run
Once the virtual machine has been added to the domain, it needs to be restarted. We will use xPendingReboot function from the xPendingReboot experimental DSC module to accomplish this.
Next, we will install the ADFS role on the virtual machine
Our script has now successfully added the virtual machine to the domain and installed the ADFS role on it. Next, create a zip file with InstallADFS.ps1 and upload it to a location that Azure Resource Manager can access (I would recommend uploading to GitHub). Include the xActiveDirectory and xPendingReboot experimental DSC module directories in the zip file as well. Also add a folder called Certificates inside the zip file and put the ADFS certificate and the encrypted password files (discussed in the next section) inside the folder.
In the next section, we will configure the ADFS Farm.
The full InstallADFS.ps1 DSC script is pasted below
Create ADFS Farm
Once the ADFS role has been installed, we will use Custom Script Extensions (CSE) to create the ADFS farm.
One of the requirements to configure ADFS is a signed certificate. I used a 90 day trial certificate from Comodo.
There is a trick that I am using to make my certificate available on the virtual machine. If you bootstrap a DSC script to your virtual machine in an Azure Resource Manager template, the script along with all the non out-of-box DSC modules have to be packaged into a zip file and uploaded to a location that ARM can access. ARM then will download the zip file, unzip it, and place all directories inside the zip file to $env:ProgramFiles\WindowsPowerShell\Modules ( C:\ProgramFiles\WindowsPowerShell\Modules ) ARM assumes the directories are PowerShell modules and puts them in the appropriate directory.
I am using this feature to sneak my certificate on to the virtual machine. I create a folder called Certificates inside the zip file containing the DSC script and put the certificate inside it. Also, I am not too fond of passing plain passwords from my ARM template to the CSE, so I created two files, one to hold the encrypted password for the domain administrator account and the other to contain the encrypted password of the adfs service account. These two files are named adminpass.key and adfspass.key and will be placed in the same Certificates folder within the zip file.
I used the following to generate the encrypted password files
AdminPlainTextPassword and ADFSPlainTextPassword are the plain text passwords that will be encrypted.
$key is used to convert the secure string into an encrypted standard string. Valid key lengths are 16, 24, 32
For this blog, we will use
$Key = (3,4,2,3,56,34,254,222,1,1,2,23,42,54,33,233,1,34,2,7,6,5,35,43)
Open Windows PowerShell ISE and paste the following (save the file with a name of your choice. I saved mine as ConfigureADFS.ps1)
param ( $DomainName, $DomainAdminUsername, $AdfsSvcUsername )
These are the parameters that will be passed to the CSE
$DomainName is the name of the Active Directory domain
$DomainAdminUsername is the username of the domain administrator account
$AdfsSvcUsername is the username of the ADFS service account
Next, we will define the value of the Key that was used to encrypt the password and the location where the certificate and the encrypted password files will be placed
$localpath = "C:\Program Files\WindowsPowerShell\Modules\Certificates\" $Key = (3,4,2,3,56,34,254,222,1,1,2,23,42,54,33,233,1,34,2,7,6,5,35,43)
Now, we have to read the encrypted passwords from the adminpass.key and adfspass.key file and then convert them into a domain\username format
Next, we will import the certificate into the local computer certificate store. We will mark the certificate exportable and set the password same as the domain administrator password.
In the above after the certificate is imported, $cert is used to hold the certificate thumbprint
Next, we will configure the ADFS Farm
The ADFS Federation Service displayname is set to “Active Directory Federation Service” and the Federation Service Name is set to fs.adfsfarm.com
Upload the CSE to a location that Azure Resource Manager can access (I uploaded my script to GitHub)
The full ConfigureADFS.ps1 CSE is shown below
Azure Resource Manager Template Bootstrapping
Now that the DSC and CSE scripts have been created, we need to add them in our ARM template, straight after the virtual machine is provisioned.
To add the DSC script, create a DSC extension and link it to the DSC Package that was created to install ADFS. Below is an example of what can be used
The extension will run after the ADFS virtual machine has been successfully created (referred to as ADFS01VMName)
The MachineName, DomainName and domain administrator credentials are passed to the DSC extension.
Below are the variables that have been used in the json file for the DSC extension (I have listed my GitHub repository location)
Next, we have to create a Custom Script Extension to link to the CSE for configuring ADFS. Below is an example that can be used
The CSE depends on the ADFS virtual machine being successfully provisioned and the DSC extension that installs the ADFS role to have successfully completed.
The DomainName, Domain Administrator Username and the ADFS Service Username are passed to the CSE script
The following contains a list of the variables being used by the CSE (the example below shows my GitHub repository location)
"repoLocation": "https://raw.githubusercontent.com/nivleshc/arm/master/", "ConfigureADFSScriptUrl": "[concat(parameters('repoLocation'),'ConfigureADFS.ps1')]",
That’s it Folks! You now have an ARM Template that can be used to automatically install the ADFS role and then configure a new ADFS Farm.
In my next blog, we will explore how to add another node to the ADFS Farm and we will also look at how we can automatically create a Web Application Proxy server for our ADFS Farm.