Amazon EC2 custom AMI not running bootstrap (user-data)

Update 4/15/2017: For EC2Launch and Windows Server 2016 AMIs

Per AWS documentation for EC2Launch, Windows Server 2016 users can continue using the persist tags introduced in EC2Config 2.1.10:

For EC2Config version 2.1.10 and later, or for EC2Launch, you can use true in the user data to enable the plug-in after user data execution.

User data example:

<powershell>
    insert script here 
</powershell> 
<persist>true</persist>

For subsequent boots:

Windows Server 2016 users must additionally enable configure and enable EC2Launch instead of EC2Config. EC2Config was deprecated on Windows Server 2016 AMIs in favor of EC2Launch.

Run the following powershell to schedule a Windows Task that will run the user data on next boot:

C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeInstance.ps1 –Schedule

By design, this task is disabled after it is run for the first time. However, using the persist tag causes Invoke-UserData to schedule a separate task via Register-FunctionScheduler, to persist your user data on subsequent boots. You can see this for yourself at C:\ProgramData\Amazon\EC2-Windows\Launch\Module\Scripts\Invoke-Userdata.ps1.

Further troubleshooting:

If you're having additional issues with your user data scripts, you can find the user data execution logs at C:\ProgramData\Amazon\EC2-Windows\Launch\Log\UserdataExecution.log for instances sourced from the WS 2016 base AMI.


Original Answer: For EC2Config and older versions of Windows Server

User data execution is automatically disabled after the initial boot. When you created your image, it is probable that execution had already been disabled. This is configurable manually within C:\Program Files\Amazon\Ec2ConfigService\Settings\Config.xml.

The documentation for "Configuring a Windows Instance Using the EC2Config Service" suggests several options:

  • Programmatically create a scheduled task to run at system start using schtasks.exe /Create, and point the scheduled task to the user data script (or another script) at C:\Program Files\Amazon\Ec2ConfigServer\Scripts\UserScript.ps1.

  • Programmatically enable the user data plug-in in Config.xml.

Example, from the documentation:

<powershell>
$EC2SettingsFile="C:\Program Files\Amazon\Ec2ConfigService\Settings\Config.xml"
$xml = [xml](get-content $EC2SettingsFile)
$xmlElement = $xml.get_DocumentElement()
$xmlElementToModify = $xmlElement.Plugins

foreach ($element in $xmlElementToModify.Plugin)
{
    if ($element.name -eq "Ec2SetPassword")
    {
        $element.State="Enabled"
    }
    elseif ($element.name -eq "Ec2HandleUserData")
    {
        $element.State="Enabled"
    }
}
$xml.Save($EC2SettingsFile)
</powershell>
  • Starting with EC2Config version 2.1.10, you can use <persist>true</persist> to enable the plug-in after user data execution.

Example, from the documentation:

<powershell>
    insert script here
</powershell>
<persist>true</persist>

Another solution that worked for me is to run Sysprep with EC2Launch.

The issue is that AWS doesn't reestablish the route to the profile service (169.254.169.254) in your custom AMI. See response by SanjitPatel in this post. So when I tried to use my custom AMI to create spot requests, my new instances were failing to find user data.

Shutting down with Sysprep, essentially forces AWS re-do all setup work on the instance, as if it were run for the first time. So when you create your instance, shut it down with Sysprep and then create your custom AMI, AWS will setup the profile service route correctly for the new instances and execute your user data. This also avoids manually changing Windows Tasks and executing user data on subsequent boots, as persist tag does.

Here is a quick step-by-step:

  1. Create an instance using one of the AWS Windows AMIs (Windows Server 2016 Nano Server doesn't support Sysprep) and passing your desired user data (this may be optional, but good to make sure AWS wires setup scripts correctly to handle user data).
  2. Customize your instance as needed.
  3. Shut down your instance with Sysprep. Just open EC2LaunchSettings application and click "Shutdown with Sysprep". Full instructions here.
  4. Create your custom AMI from the instance you just shut down.
  5. Use your custom AMI to create other instances, passing user data on instance creation. User data will be executed on instance launch. In my case, I used Spot Request screen, which had a User Data text box.

Hope this helps!


At the end of initial bootstrap (UserData) script, just append persist tag as shown below. Works perfectly.

<powershell>
    insert script here
</powershell>
<persist>true</persist>

For those people that got here from Google and are running a Server 2016 instance, it seems that this is no longer possible.

Server2016 doesn't have ec2config service and so you can't use the persist flag.

<persist>true</persist>

Described in Anthony Neace's post.

Server 2016 uses EC2Launch and I haven't yet seen how it's possible to run a script at every boot. You can run a script on the first boot, but subsequent boots will not run it.