Skip to content

Instantly share code, notes, and snippets.

@cliv
Created May 27, 2016 22:20
Show Gist options
  • Select an option

  • Save cliv/2dade5ef0f3d17a0a3152ac1e3e7b874 to your computer and use it in GitHub Desktop.

Select an option

Save cliv/2dade5ef0f3d17a0a3152ac1e3e7b874 to your computer and use it in GitHub Desktop.

Revisions

  1. cliv created this gist May 27, 2016.
    82 changes: 82 additions & 0 deletions userdata.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,82 @@
    <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>