In AWS, we can utilize the UserData section in EC2 to run PowerShell against our EC2 instances at launch. I’ve said it before; I love this option. As someone that speaks PowerShell with what likely amounts to first language fluency, there’s so much I do to automate my machine builds with CloudFormation, UserData, and PowerShell.
I’ve begun to have a need to do various pieces of automation at different times. This is to say I need to have multiple instance restarts, as an instance is coming online, in order to separate different pieces of configuration and installation. You’ll figure out when you need that, too. And, when you do, you can use what I’ve dubbed the “multiple run framework for AWS.” But really, you call it what you want. That hardly matters.
We have to remember, that by default, UserData only runs once. It’s when the EC2 instance launches for the first time. In the below example, we’re going to do three restarts and four separate code runs.
Our UserData section first needs to add a function to memory. I’ve called it Set-SystemForNextRun
and its purpose is to (1) create what I call a “passfile” to help indicate where we are in the automation process, (2) enable UserData to run the next time the service is restarted (this happens at instance restart, obviously), and (3) restart the EC2 instance. Let’s have a look. Its three parameters and three If
statements; simple stuff.
Function Set-SystemForNextRun { Param ( [string]$PassFile, [switch]$UserData, [switch]$Restart ) If ($PassFile) { [System.Void](New-Item -Path "$env:SystemDrive\passfile$PassFile.txt" -ItemType File) } If ($UserData) { $Path = "$env:ProgramFiles\Amazon\Ec2ConfigService\Settings\config.xml" [xml]$ConfigXml = Get-Content -Path $Path ($ConfigXml.Ec2ConfigurationSettings.Plugins.Plugin | Where-Object -Property Name -eq 'Ec2HandleUserData').State = 'Enabled' $ConfigXml.Save($Path) } If ($Restart) { Restart-Computer -Force } }
The above function accepts three parameters: PassFile, UserData, and Restart. PassFile accepts a string value. You’ll see how this works in the upcoming If-ElseIf
example. UserData and Restart are switch parameters. If they’re included when the function is invoked, they’re True ($true
), and if they’re not included, they’re False ($false
).
Each of the three parameters has its own If
statement within the Set-SystemforNextRun
function. If PassFile is included, it creates a text file called C:\passfile<ValuePassedIn>.txt
. If UserData is included, it resets UserData to enabled (it effectively, checks the check box in the Ec2Config GUI). If Restart is included, it restarts the instance, right then and there.
Now let’s take a look at the If-ElseIf
statement that completes four code runs and three restarts. We’ll discuss it further below, but before we do, a little reminder. Our CloudFormation UserData PowerShell is going to contain the above Set-SystemForNextRun
function, and something like you’ll see below after you’ve edited it for your needs.
If (-Not(Test-Path -Path "$env:SystemDrive\passfile1.txt")) { # Place code here (1). # Invoke Set-SystemForNextRun function. Set-SystemForNextRun -PassFile '1' -UserData -Restart } ElseIf (-Not(Test-Path -Path "$env:SystemDrive\passfile2.txt")) { # Place code here (2). # Invoke Set-SystemForNextRun function. Set-SystemForNextRun -PassFile '2' -UserData -Restart } ElseIf (-Not(Test-Path -Path "$env:SystemDrive\passfile3.txt")) { # Place code here (3). # Invoke Set-SystemForNextRun function. Set-SystemForNextRun -PassFile '3' -UserData -Restart } ElseIf (-Not(Test-Path -Path "$env:SystemDrive\passfile4.txt")) { # Place code here (4). # Invoke Set-SystemForNextRun function. Set-SystemForNextRun -PassFile '4' }
In line 1, we test whether or not the file C:\passfile1.txt
exists. If it doesn’t exist, we run the code in the If
portion. This will run whatever PowerShell we add to that section. Then it’ll pass 1 to the Set-SystemForNextRun
function to have C:\passfile01.txt
created. Additionally, because the UserData and Restart parameters are included, it’ll reset UserData to enabled, and restart the EC2 instance. Because the C:\passfile1.txt
file now exists, the next time the UserData runs, it’ll skip the If
portion and evaluate the first ElseIf
statement.
This ElseIf
statement determines whether or not the C:\passfile2.txt
file exists, or not. If it doesn’t, and it won’t after the first restart, then the code in this ElseIf
will run. When it’s done, it’ll create the passfile2.txt
file, reset UserData, and restart the instance. It’ll do this for the second ElseIf
(third code run), and the final ElseIf
(fourth code run), as well. Notice that the final invocation of the Set-SystemForNextRun
function doesn’t enable UserData or Restart the instance. Be sure to add those if you need either completed after the final ElseIf
completes.
And that’s it. At this point in time, I always use my Set-SystemForNextRun
function and a properly written If-ElseIf
statement to separate the configuration and installation around the necessary amount of instance restarts. In closing, keep in mind that deleting those pass files from the root of the C:\
drive is not something you’ll likely want to do. In time, I may do a rewrite that stores entries in the Registry perhaps, so there’s less probability that one of these files might be removed by someone.
Either way, I hope this is helpful for someone! If you’re in this space—AWS, CloudFormation, UserData, and PowerShell—then chances are good that at some point you’re going to want to restart an instance, and then continue to configure it.