AWS EC2 - Run a Script on Instance Launch With Windows Server 2012 - amazon-web-services

I would like to run a script to clear out a folder (ie: C:/myfolder) on Windows Server 2012. I thought about adding an item to the Startup Scripts list under Edit Group Policy, but this would clear out my folder any time any of my servers rebooted. I only want the folder cleared out on a new instance launch from an existing AMI.
What's the best way to achieve this?

The best way to achieve this is EC2 User Data, which is essentially a user-defined script that is executed during instance launch. On Windows, you can run user data as cmd or powershell. User Data is provided when you make a request to launch a new instance.
The existing AMI needs to be configured to run user data at launch. This can be managed from the EC2 Config Service, which Amazon provides pre-installed on community AMIs of Windows Server 2012. By default, the EC2 Config Service will execute the user data during the first launch, and then set itself to not execute user data again unless you manually change it to do so.
Here's an example from the AWS documentation where the caller is invoking Rename-Computer via powershell:
To empty out the folder without deleting the folder itself, your script will probably look something like this:
<powershell>
Remove-Item "C:\myfolder\*" -Force -Recurse
</powershell>
When running user data, it is important to be aware of what the cmdlets you're executing do, and particularly when to use the -Force flag to skip interactive prompts. Some cmdlets will situationally ask the client for input, and when you're executing user data that will cause your script to hang because this is being executed by the system user during startup.

Related

AWS: Userdata block on EC2 launch template is not running the provided powershell script

I'm working on migrating a VM from azure to AWS. I have successfully migrated using a migration service and it boots up a VM on completion. I had created an AMI out of that VM which also turned out to be successful. But when I try creating a ec2 or a autoscale group out of this ami, im unable to curl http://169.254.169.254/ or any of the ec2 metadata. This is due to the fact that the ec2i is using the gateway from the previous config from azure to make any internal network calls. When I run the InitializeInstance.ps1 script that comes inside the ec2, the instance is able to facilitate the right gateway and external ip etc.
But since I'm going to run them as autoscale groups, I cannot run this script everytime ASG spins up a new ec2 based on load. Hence I tried executing the script on 'User Data' part of the launch template that this ASG uses. But that doesnt seem to deliver expected results. Help me out in finding a way to solve this.
Ec2 launch template -- UserData:
<powershell> C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeInstance.ps1 </powershell>
Im assuming that the ec2 pulls the userdata scripts from 'http://169.254.169.254/latest/user-data' and since this gives out a timeout, its not able to execute the user data script. Correct me if Im wrong
Executing the script through the shell of the VM, but this is exhaustive and not a great practice
Using the User data in the ec2 launch template, but that apparently is not executing the listed scripts since I even tried a simple powershell script to create a new file. The file was never created.
<powershell> $file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm") New-Item $file -ItemType file </powershell>

PowerShell Script to add EIP to instance via User Data

I am fairly new to PowerShell!
What I am trying to do:
We have an auto-scaling group connecting to a 3rd party and they are only capable of IP whitelisting (I've suggested domain whitelisting to them), as such this is problem to auto-scaling instances. I am trying to assign free (unallocated) EIPs to auto-scaled instances.
I found this one: https://gist.github.com/cleydson/ff70493ef37cff03669e21ed37d90a8b
But I am not sure if there are any dependencies I need to install to the instance before I can start using it.
From what I've read so far, I need to:
Assign an IAM Role to the EC2 instance that allows it to perform the necessary EIP tasks
Put the powershell script inside an accessible directory in the instance
User Data script to call the powershell script inside the instance
Once all is working, I can then bake it into an AMI for use in auto-scaling.
Anyone can lead me further into the right direction? Thanks in advance!
EDIT UPDATE:
The script I found above was working properly when I ran inside the a PowerShell window inside the instance itself. So I made an AMI of the instance now, and have made a new Launch Config for the ASG.
My problem now is the user data doesn't seem to be called whenever a new instance is created. Below is my user data script:
<script>
PowerShell -ExecutionPolicy Bypass -Command c:\scripts\setEIP.ps1 "EIP1,EIP2,EIP3"
</script>
<persist>true</persist>
I put placers in for the EIPs. Any thoughts as to why the user data isn't called?
I finally solved it!
The reason why it was not being called was:
Initially "Enable UserData execution for next service start" was unchecked.
This is something to do with the EC2Config service installed inside the instance itself.
To summarize the solution:
Script above (https://gist.github.com/cleydson/ff70493ef37cff03669e21ed37d90a8b) was used and saved into the instance.
UserData execution was enabled inside the instance (C:\Program Files\Amazon\Ec2ConfigService\Ec2ConfigServiceSettings.exe)
UserData script to call the script inside, using -Command instead of the more popular -File
<script>
PowerShell -ExecutionPolicy Bypass -Command c:\scripts\setEIP.ps1 "EIP1,EIP2,EIP3"
</script>
<persist>true</persist>

Configure Amazon EC2 User-Data with specific code for instance launch and restart

I am creating a AWS EC2 launch template that includes commands within the User Data field to perform actions when the instance is first launched (package updates, install software, format EBS volumes, etc). In addition to this I also want to perform tasks on reboot or subsequent starting of the instance, such as mounting existing EBS volumes and configuring and mounting volatile SSD volumes. I see that I can use MIME-type to have code run when instance restarts here:
https://aws.amazon.com/premiumsupport/knowledge-center/execute-user-data-ec2/
So, I can clearly modify User Data after I initially launch the instance, but this is cumbersome as it likely needs manual intervention or requires waiting for the instance to have executed the initial User Data code that runs on initialization of the instance.
My question is:
Can the multi-part MIME format be configured to run code that will execute on initialization of the instance and other code that will run every time the instance restarts?
I understand that what you're trying to achieve is passing two sets of commands using Userdata. One set which will be executed on the instance creation and another set which should be executed every reboot. Please lemme know if I misunderstood it.
For the first part, you can use Userdata itself as you already know. For the commands that should run on every reboot, you can leverage rc.local .
The script /etc/rc.local is for use by the system administrator. It is traditionally executed after all the normal system services are started, at the end of the process of switching to a multiuser runlevel, etc. You might use it to start a custom service or for mounting additional Volumes.
To write into /etc/rc.local , you can download the command set from S3 and copy into the file or you can simply echo it. Example:
echo 'echo HelloWorld' >> /etc/rc.local
Hope this helps.

What is the use of view/change user data if that script is not run when we stop and then start the EC2 instance?

AWS console has the option to view/change user data where we can change the data when the instance is stopped. But what i am unable to understand is why is this option to edit provided if the script is not run when we stop and restart the instance.
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html
Because cloud-init is just one use for user data (and it came into existence after EC2).
Consider instead a pre-built AMI that is already configured to run a service. That service needs to be configured in some way, and user data is a great way to do that (especially prior to the introduction of AWS Systems Manager). For example, you could store a list of variable settings in user data, then have the service read those into its environment.
Using configuration in that way, it's very nice to be able to change user data and restart the service to pick up changes.

Autoscaling EC2: Launch Webserver on Spun-up Instance

I seem to not understand one central point of AWS Autoscaling:
I created an AMI of an (Ubuntu) EC2 instance having my web-server installed, and I use this AMI as the launch-configuration for my Autoscaling group.
But when Autoscaling decides to Spin up a new instance, how am I supposed to launch my webserver on that instance. Am I supposed to write some start-up scripts or what is best practice to start a process of a newly spun-up instance from Autoscaling?
When I deploy an application (PostgreSQL, Elasticsearch, whatever) to an EC2 instance, I usually do it intending on being able to repeat the process. So my first step is to create an initial deployment script which will do as much of the install and setup process as possible, without needing to know the IP address, hostname, amount of memory, number of processors, etc. Basically, as much as I can without needing to know anything that can change from one instance to the next or upon shutdown / restart.
Once that is stable, I create an AMI of it.
I then create an initialization script which I use in the launch-configuration and have it execute that script on the previously created AMI.
That's for highly configured applications. If you're just going with default settings (e.g. IP address = 0.0.0.0), than yes, I would simply set 'sudo update-rc.d <> defaults 95 10', so that it runs on startup.
Then create the AMI. When you create a new instance from that AMI, the webserver should startup by default. If it doesn't, I would look at whether or not you really set the init.d script to do so.
Launching a new instance from an AMI should be no different than booting up a previously shutdown instance.
By the way, as a matter of practice when creating these scripts, I also do a few things to make things much cleaner for me:
1) create modules in separate bash scripts (e.g. creating user accounts, set environment variables, etc) for repeatability
2) Each deployment script starts by downloading and installing the AWS CLI
3) Every EC2 instance is launched with an IAM role that has S3 read access, IAM SSH describe rights, EC2 Address allocation/association, etc.
4) Load all of the scripts onto S3 and then have the deployment / initialization scripts download the necessary bash module scripts, chmod +x and execute them. It's as close to OOP I can get without overdoing it, but it creates really clean bash scripts. The top level launch / initialization scripts for the most part just download individual scripts from S3 and execute them.
5) I source all of the modules instead of simply executing them. That way bash shares variables.
6) Make the linux account creation part of the initialization script (not the AMI). Using the CLI, you can query for users, grep for their public SSH key requested from AWS, create their accounts and have it ready for them to login automagically.
This way, when you need to change something (i.e. change the version of an application, change a configuration, etc.) you simply modify the module script and if it changes the AMI, re-launch and re-AMI. Otherwise, if it just just changes the instance-specifically, than just launch the AMI with the new initialization script.
Hope that helps...