Skip to content

Instantly share code, notes, and snippets.

@AstroTom
Last active March 9, 2026 15:35
Show Gist options
  • Select an option

  • Save AstroTom/a09fe36b94d8b23b2d1530d662603f3d to your computer and use it in GitHub Desktop.

Select an option

Save AstroTom/a09fe36b94d8b23b2d1530d662603f3d to your computer and use it in GitHub Desktop.
create and optionally close an AWS Organizations account in one flow

create-account.sh

A script to create, move to OU, and optionally close an AWS Organizations account in one flow.

Prerequisites

  • AWS CLI installed and configured with a default profile that has Organizations admin permissions

Configuration

Edit the global variables at the top of the script before running:

Variable Description
DEST_OU The target OU ID where the new account will be moved
BASE_NAME Prefix used for the account name and email
E_DOMAIN Email domain for the account's root email address

A random number is appended to BASE_NAME to ensure unique account names and emails on each run.

What it does

  1. Creates a new AWS account under the organization using a generated name and email
  2. Polls until account creation succeeds or fails
  3. Creates a local AWS CLI profile for the new account using OrganizationAccountAccessRole
  4. Moves the account to the configured destination OU
  5. Waits 30 seconds, then closes the account unless cancelled

Cancelling account closure

After the account is created and moved, the script gives you a 30-second window to cancel the closure step. Press any key within that window to keep the account open.

Notes

  • Account emails must be globally unique across all AWS accounts
  • Account closure is irreversible — the account enters a suspended state for 90 days before permanent deletion
  • The OrganizationAccountAccessRole is created automatically by AWS Organizations in new member accounts
#!/usr/bin/env bash
#
# create-account.sh
# - create and optionally close an AWS Organizations account in one flow.
# - This is to demonstrate steps and permissions needed to create an AWS account
# - must be run from the AWS Org management account.
#
## Configuration
#
# Edit the global variables at the top of the script before running:
#
# | Variable | Description |
# |----------|-------------|
# | DEST_OU | The target OU ID where the new account will be moved |
# | BASE_NAME | Prefix used for the account name and email |
# | E_DOMAIN | Email domain for the account's root email address |
#
# A random number is appended to `BASE_NAME` to ensure unique account names and emails on each run.
#
## What it does
#
# 1. Creates a new AWS account under the organization using a generated name and email
# 2. Polls until account creation succeeds or fails
# 3. Creates a local AWS CLI profile for the new account using `OrganizationAccountAccessRole`
# 4. Moves the account to the configured destination OU
# 5. Waits 30 seconds, then closes the account unless cancelled
#
#
# Set Global Variables
#
# modify these:
DEST_OU=ou-tbjl-c9ih5yjt ## The OU where you want the new account
BASE_NAME=user1 ## this should be a real email user
E_DOMAIN=example.com ## a real email domain
# Generate account name and email
RAND=$RANDOM
EMAIL=${BASE_NAME}+${RAND}@${E_DOMAIN}
ACCOUNT_NAME=${BASE_NAME}-${RAND}
# our org root id
ROOT_ID=$(aws organizations list-roots --query 'Roots[0].Id' --output text)
#
# Create new account
#
REQUEST_ID=$(aws organizations create-account \
--email "$EMAIL" \
--account-name "$ACCOUNT_NAME" \
--query 'CreateAccountStatus.Id' \
--output text)
echo "Request ID: $REQUEST_ID"
while true; do
STATE=$(aws organizations describe-create-account-status \
--create-account-request-id "$REQUEST_ID" \
--query 'CreateAccountStatus.State' \
--output text)
echo "State: $STATE"
if [ "$STATE" = "SUCCEEDED" ]; then
NEW_ACCOUNT_ID=$(aws organizations describe-create-account-status \
--create-account-request-id "$REQUEST_ID" \
--query 'CreateAccountStatus.AccountId' \
--output text)
echo "New account ID: $NEW_ACCOUNT_ID"
break
elif [ "$STATE" = "FAILED" ]; then
FAILURE=$(aws organizations describe-create-account-status \
--create-account-request-id "$REQUEST_ID" \
--query 'CreateAccountStatus.FailureReason' \
--output text)
echo "Failed: $FAILURE"
exit 1
fi
sleep 10
done
echo "New account $ACCOUNT_NAME $NEW_ACCOUNT_ID created"
#
# create profile for the new account to assume a role for testing and configuration
#
echo "Creating profile $ACCOUNT_NAME for account $NEW_ACCOUNT_ID"
aws configure set role_arn arn:aws:iam::$NEW_ACCOUNT_ID:role/OrganizationAccountAccessRole --profile $ACCOUNT_NAME
aws configure set source_profile default --profile $ACCOUNT_NAME
#
# Using the new profile, you can run any needed setup/gurdrails in the new account
#
# sample command in the new account
aws sts get-caller-identity --profile $ACCOUNT_NAME
#
# Move account to desired OU
#
aws organizations move-account --account-id $NEW_ACCOUNT_ID --source-parent-id $ROOT_ID --destination-parent-id $DEST_OU
# confirm org moved
aws organizations list-parents --child-id $NEW_ACCOUNT_ID --query 'Parents[0].Id' --output text
echo "Account $ACCOUNT_NAME moved to OU $DEST_OU"
#
# Close account
#
CLOSE_TIMEOUT=30
echo "Account will be closed in $CLOSE_TIMEOUT seconds. Press any key to cancel..."
if ! read -t $CLOSE_TIMEOUT -n 1; then
echo -e "\nProceeding with account closure..."
aws organizations close-account --account-id $NEW_ACCOUNT_ID
# confirm State is "CLOSED"
FINAL_STATE=$(aws organizations describe-account --account-id $NEW_ACCOUNT_ID --query 'Account.State' --output text)
echo "The state of account $NEW_ACCOUNT_ID is now $FINAL_STATE"
else
echo -e "\nCancelled."
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment