AWS doesn’t provide stats on list of terminated EC2 instances across a single account or across every accounts in an organization. To get the list of terminated instances, we may need to use boto3 script and use EC2 instance client to get the list of terminated instances as shown below
Contents
- List of Terminated instances for a single account
- Terminated instances for every account in the organization
List of Terminated instances for a single account
Here is the Python boto3 script that will get list of terminated instances for a single account. You can execute this script from an EC2 instance that has the required IAM Role
import boto3
import csv
# Initialize EC2 client
ec2 = boto3.client('ec2')
# Describe instances with 'terminated' state
response = ec2.describe_instances(
Filters=[
{
'Name': 'instance-state-name',
'Values': ['terminated']
}
]
)
# Prepare CSV file
with open('terminated_instances.csv', mode='w', newline='') as file:
writer = csv.writer(file)
writer.writerow(['InstanceId', 'LaunchTime', 'State'])
# Extract and write terminated instance details
for reservation in response['Reservations']:
for instance in reservation['Instances']:
instance_id = instance['InstanceId']
launch_time = instance['LaunchTime']
state = instance['State']['Name']
writer.writerow([instance_id, launch_time, state])
print(f"ID: {instance_id}, Launched: {launch_time}, State: {state}")
print("\n✅ Terminated instance details written to 'terminated_instances.csv'")
Terminated instances for every account in the organization
The below script will get you the list of instances for every account in the organization and this script needs to be executed from a master account or by using a role that has access to every account across the organization
import boto3
import csv
from datetime import datetime
# Role to assume in each account
ROLE_NAME = 'OrganizationAccountAccessRole' # Replace if using a custom role name
# Output CSV file
csv_file = 'terminated_instances_by_account.csv'
# Initialize Organizations client in master account
org_client = boto3.client('organizations')
# Get list of accounts
accounts = org_client.list_accounts()['Accounts']
# Prepare CSV file
with open(csv_file, mode='w', newline='') as file:
writer = csv.writer(file)
writer.writerow(['AccountId', 'AccountName', 'InstanceId', 'InstanceName', 'LaunchTime', 'TerminationTime'])
for account in accounts:
account_id = account['Id']
account_name = account['Name']
# Skip suspended accounts
if account['Status'] != 'ACTIVE':
continue
# Assume role into target account
sts_client = boto3.client('sts')
try:
assumed_role = sts_client.assume_role(
RoleArn=f'arn:aws:iam::{account_id}:role/{ROLE_NAME}',
RoleSessionName='TerminatedInstanceAudit'
)
except Exception as e:
print(f"❌ Could not assume role in account {account_id} ({account_name}): {e}")
continue
creds = assumed_role['Credentials']
ec2 = boto3.client(
'ec2',
aws_access_key_id=creds['AccessKeyId'],
aws_secret_access_key=creds['SecretAccessKey'],
aws_session_token=creds['SessionToken']
)
# Get terminated instances
try:
response = ec2.describe_instances(
Filters=[{'Name': 'instance-state-name', 'Values': ['terminated']}]
)
except Exception as e:
print(f"⚠️ Error fetching EC2 data for account {account_id}: {e}")
continue
for reservation in response['Reservations']:
for instance in reservation['Instances']:
instance_id = instance['InstanceId']
launch_time = instance['LaunchTime']
state_transition_reason = instance.get('StateTransitionReason', '')
termination_time = None
# Extract termination time from state transition reason
if 'terminated at' in state_transition_reason:
try:
termination_time = state_transition_reason.split('terminated at ')[-1]
termination_time = datetime.strptime(termination_time, '%Y-%m-%dT%H:%M:%S.%fZ')
except:
termination_time = None
# Extract Name tag
name_tag = ''
for tag in instance.get('Tags', []):
if tag['Key'] == 'Name':
name_tag = tag['Value']
break
writer.writerow([
account_id,
account_name,
instance_id,
name_tag,
launch_time,
termination_time if termination_time else 'Unknown'
])
print(f"✅ Processed account {account_id} ({account_name})")
print(f"\n📄 All terminated instance data written to '{csv_file}'")