Created
May 27, 2016 22:20
-
-
Save cliv/2dade5ef0f3d17a0a3152ac1e3e7b874 to your computer and use it in GitHub Desktop.
AWS UserData to configure Windows EC2 instance using powershell from S3 Raw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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