Saltar a contenido

AWS-CLI.

Objetivo.

Vamos a crear una máquina EC2 con Windows Server e instalar el rol de AD, DNS, Impresión y de Compartición de Recursos.

La máquina EC2 tendrá las siguientes características:

  • Nombre: WindowsServerSOR
  • Tipo: t3.medium
  • Clave: vockey
  • Almacenamiento: 45GB (gp3)
  • Seguridad:

    ⚠️ Permitir el tráfico desde cualquier lugar del protocolo RDP.

    ⚠️ Permitir todo tipo de tráfico proveniente de la red interna de aws (VPC).

  • IP Elástica.

Averiguar cuál es la última versión de la cual dispone AWS.

aws ssm get-parameters-by-path --path /aws/service/ami-windows-latest –query "Parameters[].Name" | grep 2025 | grep English | grep Base

Script de AWS-CLI.

El siguiente script:

  • Crea una EC2 de Windows Server.

  • Modifica las opciones de DHCP para que los clientes tengan como DNS el servidor.

#!/bin/bash
#Se detiene si el script detecta algún error.
set -e
#Variables.
INSTANCE_NAME="WindowsServerSOR"
SG_NAME="WindowsServerSOR-SG"
KEY_NAME="vockey"
INSTANCE_TYPE="t3.medium"

echo "Obteniendo VPC por defecto..."

VPC_ID=$(aws ec2 describe-vpcs \
  --filters Name=isDefault,Values=true \
  --query "Vpcs[0].VpcId" \
  --output text)
#Obtiene el CIDR de la red para aplicarlo en el grupo de seguridad.
VPC_CIDR=$(aws ec2 describe-vpcs \
  --vpc-ids $VPC_ID \
  --query "Vpcs[0].CidrBlock" \
  --output text)

echo "VPC: $VPC_ID"
echo "CIDR: $VPC_CIDR"

echo "Obteniendo última AMI Windows Server 2025..."

AMI_ID=$(aws ssm get-parameters \
  --names /aws/service/ami-windows-latest/Windows_Server-2025-English-Full-Base \
  --query "Parameters[0].Value" \
  --output text)

echo "AMI: $AMI_ID"

echo "Comprobando si existe el Security Group..."

SG_ID=$(aws ec2 describe-security-groups \
  --filters Name=group-name,Values=$SG_NAME Name=vpc-id,Values=$VPC_ID \
  --query "SecurityGroups[0].GroupId" \
  --output text 2>/dev/null)

if [ "$SG_ID" != "None" ] && [ -n "$SG_ID" ]; then
  echo "El Security Group ya existe: $SG_ID"
else
  echo "Creando Security Group..."

  SG_ID=$(aws ec2 create-security-group \
    --group-name $SG_NAME \
    --description "SG para $INSTANCE_NAME" \
    --vpc-id $VPC_ID \
    --query "GroupId" \
    --output text)

  echo "Añadiendo reglas de seguridad..."

  # RDP desde cualquier lugar
  aws ec2 authorize-security-group-ingress \
    --group-id $SG_ID \
    --protocol tcp \
    --port 3389 \
    --cidr 0.0.0.0/0

  # Todo el tráfico dentro de la VPC
  aws ec2 authorize-security-group-ingress \
    --group-id $SG_ID \
    --protocol -1 \
    --cidr $VPC_CIDR

  echo "Security Group creado: $SG_ID"
fi

echo "Lanzando instancia EC2..."

aws ec2 run-instances \
  --image-id $AMI_ID \
  --instance-type $INSTANCE_TYPE \
  --key-name $KEY_NAME \
  --security-group-ids $SG_ID \
  --block-device-mappings '[{
      "DeviceName": "/dev/sda1",
      "Ebs": {
          "VolumeSize": 45,
          "VolumeType": "gp3",
          "DeleteOnTermination": true
      }
  }]' \
  --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=$INSTANCE_NAME}]" \
  --associate-public-ip-address
echo "Esperando a que esté en estado running..."

aws ec2 wait instance-running --instance-ids $INSTANCE_ID

echo "Comprobando si ya tiene Elastic IP asociada..."

EXISTING_EIP=$(aws ec2 describe-addresses \
  --filters Name=instance-id,Values=$INSTANCE_ID \
  --query "Addresses[0].PublicIp" \
  --output text)

if [ "$EXISTING_EIP" != "None" ] && [ -n "$EXISTING_EIP" ]; then
  echo "La instancia ya tiene Elastic IP: $EXISTING_EIP"
  PUBLIC_IP=$EXISTING_EIP
else
  echo "No tiene Elastic IP. Creando una nueva..."

  ALLOC_ID=$(aws ec2 allocate-address \
    --domain vpc \
    --query "AllocationId" \
    --output text)

  aws ec2 associate-address \
    --instance-id $INSTANCE_ID \
    --allocation-id $ALLOC_ID

  PUBLIC_IP=$(aws ec2 describe-addresses \
    --allocation-ids $ALLOC_ID \
    --query "Addresses[0].PublicIp" \
    --output text)

  echo "Elastic IP creada y asociada: $PUBLIC_IP"
fi
echo "Creando nuevas DHCP Options..."

# Comprobar si ya existe un DHCP Options Set con ese nombre
DHCP_ID=$(aws ec2 describe-dhcp-options \
  --filters Name=tag:Name,Values=sor-dhcp \
  --query "DhcpOptions[0].DhcpOptionsId" \
  --output text 2>/dev/null)

if [ "$DHCP_ID" != "None" ] && [ -n "$DHCP_ID" ]; then
  echo "DHCP Options ya existe: $DHCP_ID"
else
  echo "Creando DHCP Options sor-dhcp..."

  DHCP_ID=$(aws ec2 create-dhcp-options \
    --dhcp-configurations \
      Key=domain-name,Values=sor.com \
      Key=domain-name-servers,Values=$PUBLIC_IP,8.8.8.8 \
    --query "DhcpOptions.DhcpOptionsId" \
    --output text)

  # Añadir tag Name=sor-dhcp
  aws ec2 create-tags \
    --resources $DHCP_ID \
    --tags Key=Name,Value=sor-dhcp

  echo "DHCP Options creado: $DHCP_ID"
fi

echo "Asociando DHCP Options a la VPC..."

aws ec2 associate-dhcp-options \
  --dhcp-options-id $DHCP_ID \
  --vpc-id $VPC_ID

echo "DHCP Options aplicado a la VPC $VPC_ID"

Ejecutar PowerShell desde aws-cli (SSM).

Vamos a activar los roles de Windows Server desde AWS-CLI.

La manera correcta no es “inyectar” PowerShell por SSH/RDP, sino usar AWS Systems Manager (SSM).

  • Con SSM puedes ejecutar comandos remotamente en Windows usando la función AWS-RunPowerShellScript.

Activar el LabRole en el servidor Windows Server.

1️⃣ Modificamos Rol de la máquina servidora a LabRole.

2️⃣ Conectamos mediante SSM.

3️⃣ Comprobación de que funciona desde CloudShell.

aws ssm send-command   --instance-ids i-XXXXXXXXXXXXXXX   --document-name "AWS-RunPowerShellScript"   --parameters commands="Get-Service"

Cambiar el nombre del servidor.

Antes de Instalar los roles vamos a cambiar el nombre del servidor.

Este cambio requiere un reinicio, por lo que no será instantáneo.

COMMAND_ID=$(aws ssm send-command \
--instance-ids i-XXXXXXXX \
--document-name "AWS-RunPowerShellScript" \
--parameters 'commands=[
"Rename-Computer -NewName \"SORDC\" -Force -Restart"
]' --query "Command.CommandId" --output text)

Comprobación.

  • Podemos comprobar si el comando SSM se ha terminado de ejecutar con éxito.
aws ssm get-command-invocation \
  --command-id $COMMAND_ID \
  --instance-id i-XXXXXXXXXXXXXXXX
  • Cuando el Response devuelva 0 ya podemos proseguir con el siguiente script.
Estado
Código
En proceso -1
Terminado 0
Fallo Diferente de 0,-1

Insalar los roles.

COMMAND_ID=$(aws ssm send-command \
  --instance-ids i-XXXXXXXXXXXXX \
  --document-name "AWS-RunPowerShellScript" \
  --comment "Instalación AD DS + DNS + File + Print" \
  --parameters 'commands=[
"$DomainName = \"sor.local\"",
"$NetbiosName = \"SOR\"",
"$SafeModePassword = ConvertTo-SecureString \"P@ssw0rd123!\" -AsPlainText -Force",
"Install-WindowsFeature AD-Domain-Services -IncludeManagementTools",
"Install-WindowsFeature DNS -IncludeManagementTools",
"Install-WindowsFeature FS-FileServer",
"Install-WindowsFeature Print-Server",
"Install-ADDSForest -DomainName $DomainName -DomainNetbiosName $NetbiosName -SafeModeAdministratorPassword $SafeModePassword -InstallDNS -Force"
]' --query "Command.CommandId" --output text)

Comprobación.

  • Guardamos en una variable el ID del comando y consultamos su estado.
COMMAND_ID=$(aws ssm send-command ... --query "Command.CommandId" --output text)

#Consultar el estado.
aws ssm get-command-invocation \
  --command-id $COMMAND_ID \
  --instance-id i-XXXXXXXXXXXXXXX

Recuerda que este proceso conlleva un reinicio y por tanto en algún momento puede devolver un Timeout.