Skip to content

Instantly share code, notes, and snippets.

@cliv
Created May 27, 2016 22:20
Show Gist options
  • Save cliv/2dade5ef0f3d17a0a3152ac1e3e7b874 to your computer and use it in GitHub Desktop.
Save cliv/2dade5ef0f3d17a0a3152ac1e3e7b874 to your computer and use it in GitHub Desktop.
AWS UserData to configure Windows EC2 instance using powershell from S3 Raw
<powershell>
######
# Charlie Livingston <[email protected]>
# MIT Licensed - Do whatever you like with this.
#
# Simple code for a windows machine to grab a set of .ps1 files off of S3 and
# run them locally depengind on how a machine is tagged in EC2
#
# The xml-ish <powershell></powershell> tags in the script make the file invalid powershell to run directly in a machine
# but are required by EC2Config when passed into the instance as userdata
#
# Please note:
# - Instance requires access to this bucket - Probably via IAM Roles
# - Use the EC2 tag defined in configStepsTag and use a comma separated list of directories to grab steps from
# - Slack hook is defined below in PostToSlack because powershell and global variables are meh.
#
####
# Configure bucket and tag here
#
$bucketName = "myCrazyBucket"
$configStepsTag = "additionalConfigSteps'
# Make sure powershell can execute any and all files - if you want to enable script signing, go ahead and disable it..
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass -Force
# Helper function to post updates on server status to slack
function PostToSlack {
Param([string]$message)
$wc = New-Object net.webclient
$wc.UploadString("https://hooks.slack.com/services/xxx/xxx/xxxx", (ConvertTo-Json @{ text = ("$message") }))
}
# Get Initial instance Info from AWS' super-sweet Instance MetaData URL
$instanceIdentity = (New-Object net.webclient).DownloadString('http://169.254.169.254/latest/dynamic/instance-identity/document') | ConvertFrom-Json
# Let everyone know the machine is online
PostToSlack ($instanceIdentity.instanceId + " has come online, running config steps. (IP: "+ $instanceIdentity.privateIp +")" )
# Check for spot instance and copy tags - This may no longer be nessecary, but when I did it before, the tags from a spot
# spot request didn't appear in the instance that request launched.
$spotId = (Get-EC2Instance -Instance $instanceIdentity.instanceId -Region $instanceIdentity.region).Instances.SpotInstanceRequestId
if(![string]::IsNullOrEmpty($spotId)) {
$tags = (Get-EC2SpotInstanceRequest -SpotInstanceRequestId $spotId -Region $instanceIdentity.region).Tags
New-EC2Tag -Region $instanceIdentity.region -Resource $instanceIdentity.instanceId -Tag $tags
}
# Figure out the list of config steps we need to process from the s3 BucketName
#
# We always execute AllServers, everything else is read as CSV from $configStepsTag
# - Steps are all downloaded at once then run in alphabetical order
#
# An Example bucket with config files would look like this:
# myconfigbucket/AllServers/000-ConfigureServer.ps1
# myconfigbucket/AllServers/999-PostInstallCleanup.ps1
# myconfigBucket/IIS/001-InstallIIS.ps1
# myconfigBucket/IIS/002-DeletePrimaryIISSite.ps1
# myconfigBucket/NewRelic/800-InstallNewRelic.ps1
#
$configSteps = @()
# Look in AllServers for First scripts
$configSteps += (Get-S3Bucket -BucketName $bucketName | Get-S3Object -Key 'AllServers/' | Where-Object {$_.Key -match "\.ps1$"} | Sort-Object -Property "Key")
# Get scripts from additional step directories
$additionalConfig = (Get-EC2Tag -Region $instanceIdentity.region | ? { $_.ResourceID -eq $instanceIdentity.instanceId -and $_.Key -eq $configStepsTag}).Value
foreach($step in $additionalConfig.Split(",")) {
$stepKey = $step + '/'
$configSteps += (Get-S3Bucket -BucketName $bucketName | Get-S3Object -Key $stepKey | Where-Object {$_.Key -match "\.ps1$"} | Sort-Object -Property "Key")
}
# Take the array of steps, sort it and run the powershell scripts in alphabetical order (hence the suggested numbering above)
foreach($step in ($configSteps | Sort-Object @{Expression={$_.Key | split-path -leaf};})) {
PostToSlack ($instanceIdentity.instanceId + " - Running Remote Configuration Script " + $step.Key.ToString())
$url = Get-S3PresignedURL -BucketName $bucketName -Key $step.Key.ToString() -Expire (Get-Date).AddMinutes(10)#
(iex ((new-object net.webclient).DownloadString($url)))>$null 2>&1
}
# Mark Complete and reboot
PostToSlack ($instanceIdentity.instanceId + " - Custom Instance Configuration Complete, Rebooting")
Restart-Computer
</powershell>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment