Created
June 17, 2026 09:15
-
-
Save mikedixson/50322267a295f9d7b684c533bd4b8e8d to your computer and use it in GitHub Desktop.
PowerShell AWS EC2 lookup & connect toolkit — quickly find instances by name and connect via SSH, RDP or SSM across multiple accounts and regions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ================================ | |
| # AWS EC2 Lookup + Connectivity Toolkit | |
| # ================================ | |
| # Purpose: | |
| # Quickly find EC2 instances by Name tag and connect via: | |
| # - SSH | |
| # - RDP | |
| # - SSM (Session Manager) | |
| # | |
| # Features: | |
| # - Multi-region lookup (default: eu-west-2, eu-west-1) | |
| # - Optional multi-account search | |
| # - Automatic AWS SSO authentication | |
| # - Result caching for performance | |
| # - Interactive selection if multiple matches | |
| # - SSH auto-fallback to SSM | |
| # | |
| # To use add to your PowerShell Profile | |
| # ================================ | |
| # Examples: | |
| # | |
| # Lookup instances: | |
| # ec2 ukienat | |
| # ec2 uk -AllAccounts | |
| # ec2 uk -Profile DevAccount | |
| # | |
| # SSH: | |
| # ssh2 ukienat | |
| # ssh2 ukienat -User ubuntu | |
| # | |
| # SSM: | |
| # ssm2 ukienat | |
| # ssm2 uk -Profile AdminAccount | |
| # ssm2 uk -Region eu-west-1 | |
| # | |
| # RDP: | |
| # rdp2 winserver01 | |
| # | |
| # Force fresh lookup (skip cache): | |
| # ec2 ukienat -NoCache | |
| # | |
| # Notes: | |
| # - Partial name matching is supported (*uk* matches multiple hosts) | |
| # - If multiple matches are found, a selection prompt is shown | |
| # - SSH automatically falls back to SSM if connection fails | |
| # ================================ | |
| # In-memory cache (per PowerShell session) | |
| $Global:EC2LookupCache = @{} | |
| function Get-EC2Instance { | |
| [CmdletBinding()] | |
| param( | |
| # Name (or partial name) of EC2 instance (matches Name tag) | |
| [Parameter(Mandatory = $true)] | |
| [string]$Name, | |
| # Default AWS profile | |
| [string]$Profile = "ReadOnlyAccess-1234567890", | |
| # Regions to search (extendable) | |
| [string[]]$Regions = @("eu-west-2", "eu-west-1"), | |
| # Search all configured AWS CLI profiles | |
| [switch]$AllAccounts, | |
| # Bypass cache | |
| [switch]$NoCache | |
| ) | |
| # Проверка валидности AWS профиля (silent) | |
| function Test-AwsProfile { | |
| param($Profile) | |
| aws sts get-caller-identity --profile $Profile 1>$null 2>$null | |
| return ($LASTEXITCODE -eq 0) | |
| } | |
| # Ensure SSO login is active (auto-login if needed) | |
| function Ensure-AwsLogin { | |
| param($Profile) | |
| if (-not (Test-AwsProfile $Profile)) { | |
| Write-Host "SSO login required for '$Profile'..." -ForegroundColor Yellow | |
| aws sso login --profile $Profile | |
| # Re-check after login | |
| if (-not (Test-AwsProfile $Profile)) { | |
| Write-Warning "Login failed or still invalid for '$Profile'" | |
| return $false | |
| } | |
| } | |
| return $true | |
| } | |
| # Resolve target profiles | |
| if ($AllAccounts) { | |
| $profiles = aws configure list-profiles | |
| } else { | |
| $profiles = @($Profile) | |
| } | |
| $results = @() | |
| foreach ($p in $profiles) { | |
| # Skip profiles that fail auth | |
| if (-not (Ensure-AwsLogin $p)) { continue } | |
| foreach ($region in $Regions) { | |
| $cacheKey = "$p|$Name|$region" | |
| # Return cached result if available | |
| if (-not $NoCache -and $Global:EC2LookupCache.ContainsKey($cacheKey)) { | |
| $results += $Global:EC2LookupCache[$cacheKey] | |
| continue | |
| } | |
| try { | |
| # Query EC2 instances filtered by Name tag | |
| $data = aws ec2 describe-instances ` | |
| --profile $p ` | |
| --region $region ` | |
| --filters "Name=tag:Name,Values=*${Name}*" ` | |
| --query "Reservations[].Instances[].{ | |
| InstanceId:InstanceId, | |
| Name:Tags[?Key=='Name']|[0].Value, | |
| State:State.Name, | |
| PrivateIP:PrivateIpAddress, | |
| PublicIP:PublicIpAddress, | |
| AZ:Placement.AvailabilityZone | |
| }" ` | |
| --output json | ConvertFrom-Json | |
| if ($data) { | |
| foreach ($i in $data) { | |
| $obj = [PSCustomObject]@{ | |
| Name = $i.Name | |
| InstanceId = $i.InstanceId | |
| State = $i.State | |
| PrivateIP = $i.PrivateIP | |
| PublicIP = $i.PublicIP | |
| AZ = $i.AZ | |
| Region = $region | |
| Profile = $p | |
| } | |
| $results += $obj | |
| # Cache per profile/region/search | |
| if (-not $NoCache) { | |
| $Global:EC2LookupCache[$cacheKey] = $obj | |
| } | |
| } | |
| } | |
| } catch { | |
| Write-Warning "Failed $p / $region" | |
| } | |
| } | |
| } | |
| if (-not $results) { | |
| Write-Warning "No instances found matching '$Name'" | |
| } | |
| return $results | |
| } | |
| function Select-EC2Instance { | |
| param($instances) | |
| # No results | |
| if (-not $instances) { return $null } | |
| # Single result → return immediately | |
| if ($instances.Count -eq 1) { | |
| return $instances | |
| } | |
| # Prefer GUI picker if available (Out-GridView) | |
| if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { | |
| return $instances | Out-GridView -Title "Select EC2 instance" -PassThru | |
| } | |
| # Fallback to CLI selection menu | |
| Write-Host "Multiple instances found:" -ForegroundColor Yellow | |
| for ($i = 0; $i -lt $instances.Count; $i++) { | |
| $inst = $instances[$i] | |
| Write-Host "[$i] $($inst.Name) $($inst.InstanceId) $($inst.Region) $($inst.State)" | |
| } | |
| $choice = Read-Host "Select index" | |
| return $instances[$choice] | |
| } | |
| function ec2ssm { | |
| param( | |
| # Instance name lookup | |
| [Parameter(Mandatory = $true)] | |
| [string]$Name, | |
| # AWS profile | |
| [string]$Profile = "ReadOnlyAccess-442285748543", | |
| # Override region (optional) | |
| [string]$Region | |
| ) | |
| $instances = Get-EC2Instance -Name $Name -Profile $Profile | |
| $instance = Select-EC2Instance $instances | |
| if (-not $instance) { return } | |
| # Use explicit region if provided | |
| $targetRegion = if ($Region) { $Region } else { $instance.Region } | |
| Write-Host "SSM → $($instance.InstanceId) [$targetRegion/$($instance.Profile)]" -ForegroundColor Cyan | |
| # Start SSM session | |
| aws ssm start-session ` | |
| --target $($instance.InstanceId) ` | |
| --profile $($instance.Profile) ` | |
| --region $targetRegion | |
| } | |
| function ec2ssh { | |
| param( | |
| # Instance name lookup | |
| [Parameter(Mandatory = $true)] | |
| [string]$Name, | |
| # SSH username (default Linux AMIs) | |
| [string]$User = "ec2-user", | |
| # AWS profile | |
| [string]$Profile = "ReadOnlyAccess-442285748543" | |
| ) | |
| $instances = Get-EC2Instance -Name $Name -Profile $Profile | |
| $instance = Select-EC2Instance $instances | |
| if (-not $instance) { return } | |
| # Prefer public IP, fallback to private | |
| $ip = $instance.PublicIP | |
| if (-not $ip) { $ip = $instance.PrivateIP } | |
| Write-Host "SSH → $User@$ip ($($instance.InstanceId))" -ForegroundColor Green | |
| # Attempt SSH connection | |
| ssh "$User@$ip" | |
| # If SSH fails → fallback to SSM | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Warning "SSH failed, falling back to SSM..." | |
| ec2ssm -Name $instance.Name -Profile $instance.Profile -Region $instance.Region | |
| } | |
| } | |
| function ec2rdp { | |
| param( | |
| # Instance name lookup | |
| [Parameter(Mandatory = $true)] | |
| [string]$Name | |
| ) | |
| $instances = Get-EC2Instance -Name $Name | |
| $instance = Select-EC2Instance $instances | |
| if (-not $instance) { return } | |
| # Prefer public IP, fallback to private | |
| $ip = $instance.PublicIP | |
| if (-not $ip) { $ip = $instance.PrivateIP } | |
| Write-Host "RDP → $ip ($($instance.InstanceId))" | |
| # Launch Remote Desktop | |
| mstsc /v:$ip | |
| } | |
| # ================================ | |
| # Aliases (short commands) | |
| # ================================ | |
| Set-Alias ec2 Get-EC2Instance | |
| Set-Alias ssh2 ec2ssh | |
| Set-Alias rdp2 ec2rdp | |
| Set-Alias ssm2 ec2ssm |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment