Running Azure PowerShell Workflows without Azure Automation

While developing some Workflows recently I was frustrated by something that was seemingly so simple to resolve. I’d log in to Azure and then run my parallel Workflow to perhaps start up a set of VMs in a Resource Group and get slammed with a boat load of errors.

This is the code I was running – it is specifically not designed to run in Azure Automation because I don’t want it to. Running this in Azure Automation requires a significant number of steps that I don’t want to perform so I’m not using the RunAs account. It’s a few lines of PowerShell designed to start up the VMs in a resource group quickly.

This would just blow up. The problem was clear enough, as a child of the parent, the parallel execution has no knowledge of my account being logged in and I just wasn’t sure how to resolve that. Many moons ago I tinkered with using Save-AzureRmProfile  to save me from having to log in every time I wanted to do something in Azure but I fell out of love with the solution since the saved profile never seemed to last very long. After some Googling, I happened upon an issue report in GitHub for Azure PowerShell that seemed relevant.

The issue report was answered by Mark Cowl who advised that the child job has no knowledge of the profile and, by passing in the profile to the child job in the right place by using Select-AzureRmProfile , you could work around the problem. The lightbulb came on and I altered my script and Workflow to:

Simple when you think about it.

You’ll notice in the foreach -parallel there is a throttlelimit set. I have my reasons for including this, yours may differ so feel free to remove the throttle altogether or alter it appropriately.



Set language, culture and timezone using PowerShell

As much as I’d like to say this is a perfect one-liner solution, it isn’t. It doesn’t actually count as PowerShell either, technically. This article is written for people deploying from Marketplace Azure images that always get the US locale, even though you need it to be GB – clearly if the image you deploy from has been customised or is already based on the en-GB image of your OS, then you probably won’t have these problems but when you deploy from the Marketplace image, you get en-US settings.

I’ve seen the cmdlets introduced in Windows 8 and Windows 2012 that allow you to set the language, culture and timezone but these are lacking. The primary issue is that they do not contain any method to affect the Default user account, so any time a new user logs on, they get en-US language settings, which for anyone in the UK is a huge pain. The other issue is compatibility. Not everyone is ready to deploy Windows Server 2016 or even Windows Server 2012 and so are stuck on Windows Server 2008 R2, for better or worse.

If you’re deploying in Azure, Microsoft provide a market place image that makes life very easy, instead of rolling your own image and deploying from that. While Managed Disks are the first step to removing the frustration with handling your own custom images, they’re brand new and with anything new, it takes time to bed in and become part of a well-honed process.

With all this background covered, there are, undoubtedly full PowerShell solutions that will achieve the same as I’m about to give but they are also unquestionably more complicated to deploy and maintain.

To resolve the issue of deploying from Azure Marketplace images that have en-US set as default across the board, I implement a CustomScriptExtension for every VM build. I won’t cover the detail of the approach here, but I will provide a link to an Azure article that I contributed to that covers using Custom Script Extensions, specifically with private Azure Blob Storage. – I sent the pull request to update the document about 5 days ago but it’s not been accepted yet. The PR is here if you cannot see any mention of my request in the article yet.

The solution I implement requires two files to be downloaded from private Blob Storage, one is a PowerShell script, the other, an XML file which is where the language settings are. The CustomScriptExtension then runs a command line which invokes the Powershell script and changes the language settings and timezone, among other things.

I’ve deployed thousands of Azure VMs and this CustomScriptExtension has been instrumental in saving days of manually changing settings. The following code is the PowerShell (well, OK, there’s some PowerShell in there) to initialise the VM with language, locale, culture and timezone as well as format/prepare any RAW data disks – which you might not want to do based on the requirement or not for Storage Spaces/striping.

You’ll notice that line 2 actually calls control.exe and imports an XML file called UKRegion.xml. Here’s the contents of that file – this is specifically coded for UK (en-GB) language, home location etc. so if you’re elsewhere in the world, you’ll need your own location’s codes and what not. Check out this MSDN article for more information.

If you’re not trying to automate Azure builds and tinkering with JSON ARM templates isn’t required, then you need only the PowerShell and XML as shown above. Simply copy the PowerShell code and XML code in to two separate files (named appropriately), drop them on to the system you want to update and run the PowerShell. If you don’t want the disk format section, remove it. I should warn you that you DO need a reboot to fully apply the settings to the whole system.

For those of you doing Azure based deployments and want to take advantage of the above during deployment using a CustomScriptExtension, the resource I use in my JSON Azure Resource Manager template looks similar to the following – I actually have all of my inputs parameterised but you’ll want to see the information I’m actually passing in so I’ve manually edited the resource below, substituting in the values that would be passed from the parameters section (which isn’t shown below!). There is also the Set-AzureRmCustomScriptExtension cmdlet if you’re building with Azure PowerShell.

“Why not use DSC!” I hear you scream. Absolutely, yes, you can definitely do that but I can tell you for free that you will reach a fully configured solution that you can log on to and start using far quicker with this method than you will if you use DSC which might have to install WMF, reboot, compile the MOF, configure LCM and then apply the config. It’s all about the right tool at the right time and for simple[?!] language settings and formatting disks, a CSE is the way to go as far as I’m concerned.