Run an SSM Command against a set of EC2 Instances

A quick script today to run an SSM Command against a set of EC2 Instances. You can selectively target instance based on a TAG.

import boto3
import os
from time import sleep

lambda_func_name = os.getenv("AWS_LAMBDA_FUNCTION_NAME", "")

if lambda_func_name == "":  # We are not running in AWS
    boto3.setup_default_session(profile_name='<profile_name>')

ec2_client = boto3.client('ec2', region_name='ap-southeast-2')
ssm_client = boto3.client('ssm', region_name='ap-southeast-2')  # use region code in which you are working

sleep_duration = 2

def get_instances(os):

    instances = []

    # Check running or stopped instances
    response = ec2_client.describe_instances(
        Filters=[
            {
                'Name': 'instance-state-name',
                'Values': ['running']
            }
        ])

    # Iterate over instance(s)
    for r in response['Reservations']:
        for inst in r['Instances']:
            inst_id = inst['InstanceId']
            tags = inst['Tags']

            ins_tag = ""

            for tag in tags:
                if "OSFamily" in tag['Key']:
                    ins_tag = (tag['Value'])
                    break
                else:
                    ins_tag = "NA"

            if ins_tag == os:
                instances.append(inst_id)

    return instances

def ssm_run_command(instance_id, cmd, os_family):

    document = "AWS-RunPowerShellScript"

    if (os_family == "Linux"):
        document = "AWS-RunShellScript"

    response = ssm_client.send_command(
        InstanceIds=[
            instance_id  # use instance id on which you want to execute, even multiple is allowed
        ],
        DocumentName=document,
        Parameters={
            'commands': [
                cmd
            ]
        },
    )

    #print(response)

    sleep(sleep_duration)  # Seconds to wait for command to execute

    command_id = response['Command']['CommandId']
    output = ssm_client.get_command_invocation(CommandId = command_id, InstanceId = instance_id)

    return output['StandardOutputContent']

def check_time_zone_windows():

    os_family = "Windows"

    instances = get_instances(os_family)
    command = "[System.TimeZone]::CurrentTimeZone.StandardName"

    instances_with_wrong_tz = []

    for instance in instances:
        print("Checking instance: " + instance)
        time_zone = ssm_run_command(instance, command, os_family)
        #print(time_zone)

        if ( time_zone[0:3] != "AUS"):
            instances_with_wrong_tz.append(instance)

    result_str = ""

    if (len(instances_with_wrong_tz) > 0):

        result_str = "Following " + os_family + " instances have wrong Timezone:\n\n"

        for instance in instances_with_wrong_tz:
            result_str = result_str + instance + "\n\n"

    return result_str

def check_time_zone_linux():
    os_family = "Linux"

    instances = get_instances(os_family)
    command = 'date +"%Z"'

    instances_with_wrong_tz = []

    for instance in instances:
        print("Checking instance: " + instance)
        time_zone = ssm_run_command(instance, command, os_family)
        #print(time_zone)

        if (time_zone[0:2] != "AE"):
            instances_with_wrong_tz.append(instance)

    result_str = ""

    if (len(instances_with_wrong_tz) > 0):

        result_str = "Following " + os_family + " instances have wrong Timezone:\n\n"

        for instance in instances_with_wrong_tz:
            result_str = result_str + instance + "\n\n"

    return result_str

def lambda_handler(event, context):

    result_lin = check_time_zone_linux()
    result_win = check_time_zone_windows()

    result = result_lin + "\n\n" + result_win

    print(result)

if __name__ == "__main__":
    lambda_handler(0, 0)