Force a reboot with DSC in ARM-template

When deploying an ARM-tempalate, the Azure Virtual Network got updated with the new DNS server. The Virtual machines deployed before this update, still got the old DNS client settings, before the VM gets rebooted. This becomes a bit of a challange, when trying to domain join the computer with Desired State Configuration (DSC), since it will not find the domain controller (if not the old DNS settings where already pointed to a current domain controller).

To force a reboot thru DSC can be achieved by the module xPendingReboot and DSC Script. xPendingReboot checks if there is a pending reboot of the machine and works in conjunction with the Local Configuration Manager (LCM). If LCM is set to RebootNodeIfNeeded=$true, it will reboot. However, a new machine got no pending reboot. To achieve this we will need to set DSCMachineStatus to 1 and write a small registry item. This will indicate there is a PendingReboot.

First we need to load the module (including the domainJoin as well)

Import-DscResource -ModuleName xPendingReboot, xDSCDomainjoin

Set the LCM RebootNodeIfNeeded to true

LocalConfigurationManager 
{
   RebootNodeIfNeeded = $true
}

Create a xPendingReboot resource

xPendingReboot Reboot
{
   Name = "Reboot"
}

Add our “fake” reboot.

Script Reboot
{
    TestScript = {
    return (Test-Path HKLM:\SOFTWARE\MyMainKey\RebootKey)
    }
    SetScript = {
			New-Item -Path HKLM:\SOFTWARE\MyMainKey\RebootKey -Force
			$global:DSCMachineStatus = 1 
        }
    GetScript = { return @{result = 'result'}}
}

and finally the domainjoin with a DependsOn so it will happend before domainjoin.

xDSCDomainjoin JoinDomain
{
  Domain = $DomainName
  Credential = $DomainCreds
  DependsOn = "[Script]Reboot"
}

Pass null conditions to JSON-template with Powershell – splat!

With Azure ARM templates we have the possibility to add conditions. Meaning that we can for example decide if we want to deploy a certain resource or not that is defined in the JSON-template. This gives us great flexibility when authoring ARM templates.

An example is that you might decide to have an option to create a VPN-Gateway for your Network template and want to option to say Yes or No as input. If in the deployment you choose No, you do not really want to enter all the other parameters required for VPN, even if they are defined in your ARM Template. The parameter file you can choose as input (and is created by default if you work with Visual Studio) handles this null values. So far so good.

However, sometimes, we want to solve this from Powershell and inject parameters directly, without needing a parameter file. To accomplish this, we will need to create a hash table with the relevant parameters. For example we have two parameters. VPN, that is yes or no. If we choose no, we do not really want enter a VPNSharedKey, since it will be not needed.

First we enter the input parameters to the PowerShell script. The script gives the operator the possibility to choose two answers on VPN, yes or No.

[Cmdletbinding()]
Param
(
    [Parameter(Mandatory=$true)]
    [ValidateSet('yes','no')]
    [string[]]$VPN,
    [Parameter(Mandatory=$false)]
    [String]$VPNSharedKey
)

Then we pass this variables into our hash table

$Parameters @{
VPN ="$VPN"
VPNSharedKey ="$VPNSharedKey"
}

Hence we can launch the Powershell script (Azuredeploy.json being our template file)

.\Deploy-ToAzure.ps1 -VPN no -TemplateFile C:\Azuredeploy.json

For further reading, see Microsoft documentation about splatting about_Splatting