I have a pretty cool job. When my team isn't putting out fires in our production environment, we're working on ways to automate future deployments to production and even non-production environments. Part of that is spinning up new VMs inside AWS. If you're just setting up one VM, working through the AWS Console isn't too bad. If you're setting up more than that, it's an irritatingly repetitive process. I installed the AWS CLI utilities originally to just pull down existing inventory data, but then realized that I can do a whole lot more than just that. I found that you can easily launch VMs from the command line by passing a JSON file to the aws cli utility. You can print out an empty JSON skeleton by running the following command:

$ aws ec2 run-instances --generate-cli-skeleton
{
"DryRun": true,
"ImageId": "",
"MinCount": 0,
"MaxCount": 0,
"KeyName": "",
"SecurityGroups": [
""
],
"SecurityGroupIds": [
""
],
"UserData": "",
"InstanceType": "",
"Placement": {
"AvailabilityZone": "",
"GroupName": "",
"Tenancy": ""
},
"KernelId": "",
"RamdiskId": "",
"BlockDeviceMappings": [
{
"VirtualName": "",
"DeviceName": "",
"Ebs": {
"SnapshotId": "",
"VolumeSize": 0,
"DeleteOnTermination": true,
"VolumeType": "",
"Iops": 0,
"Encrypted": true
},
"NoDevice": ""
}
],
"Monitoring": {
"Enabled": true
},
"SubnetId": "",
"DisableApiTermination": true,
"InstanceInitiatedShutdownBehavior": "",
"PrivateIpAddress": "",
"ClientToken": "",
"AdditionalInfo": "",
"NetworkInterfaces": [
{
"NetworkInterfaceId": "",
"DeviceIndex": 0,
"SubnetId": "",
"Description": "",
"PrivateIpAddress": "",
"Groups": [
""
],
"DeleteOnTermination": true,
"PrivateIpAddresses": [
{
"PrivateIpAddress": "",
"Primary": true
}
],
"SecondaryPrivateIpAddressCount": 0,
"AssociatePublicIpAddress": true
}
],
"IamInstanceProfile": {
"Arn": "",
"Name": ""
},
"EbsOptimized": true
}

You can then trim out what you don't need and go from there. Mine ended up looking something like this:

{
    "DryRun": false,
    "ImageId": "ami-12345",
    "MinCount": 1,
    "MaxCount": 1,
    "KeyName": "MyLinuxKey",
    "SecurityGroupIds": [
        "sg-12345","123456"
    ],
    "InstanceType": "t2.small",
    "Placement": {
        "AvailabilityZone": "us-west-1b",
        "GroupName": "",
        "Tenancy": "default"
    },
    "Monitoring": {
        "Enabled": true
    },
    "SubnetId": "subnet-12345",
    "DisableApiTermination": true,
    "NetworkInterfaces": [
        {
            "DeviceIndex":0,
            "AssociatePublicIpAddress": true
        }
    ],
    "EbsOptimized": false
}

I was then able to run the instance with this command:

$ aws --region us-east-1 ec2 run-instances --cli-input-json file://AWS_Instance.json
I should note that my instance is part of a VPC. If your instance isn't, you might need to modify this to suit your environment.

If you need to tag the instances, you can run a command like this:

$ aws ec2 --region us-east-1 create-tags --resources i12345 --tags Key=Name,Value="Server Name Tag"

where i12345 is your instance ID.

You can read more about the launching instances and generating the JSON skeleton here and here respectively.