Skip to content

Instantly share code, notes, and snippets.

@vkuprin
Created January 26, 2026 14:21
Show Gist options
  • Select an option

  • Save vkuprin/653994e70fc382a9899c539063968716 to your computer and use it in GitHub Desktop.

Select an option

Save vkuprin/653994e70fc382a9899c539063968716 to your computer and use it in GitHub Desktop.
#!/bin/bash
# SSH Profile Manager - Easy switching between SSH configurations
SSH_PROFILES_DIR="$HOME/.ssh-profiles"
CURRENT_SSH="$HOME/.ssh"
CURRENT_PROFILE_MARKER="$SSH_PROFILES_DIR/.current"
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
init_profiles() {
if [ ! -d "$SSH_PROFILES_DIR" ]; then
mkdir -p "$SSH_PROFILES_DIR"
echo -e "${GREEN}Created SSH profiles directory: $SSH_PROFILES_DIR${NC}"
fi
}
list_profiles() {
init_profiles
echo -e "${BLUE}Available SSH profiles:${NC}"
current_profile=$(cat "$CURRENT_PROFILE_MARKER" 2>/dev/null || echo "unknown")
if [ -d "$CURRENT_SSH" ]; then
echo -e " ${GREEN}* active${NC} (currently in use)"
fi
for profile in "$SSH_PROFILES_DIR"/*; do
if [ -d "$profile" ]; then
profile_name=$(basename "$profile")
if [ "$profile_name" == "$current_profile" ]; then
echo -e " ${GREEN}* $profile_name${NC} (current)"
else
echo " $profile_name"
fi
fi
done
}
switch_profile() {
local profile_name="$1"
local profile_path="$SSH_PROFILES_DIR/$profile_name"
if [ -z "$profile_name" ]; then
echo -e "${RED}Error: Please specify a profile name${NC}"
echo "Usage: ssh-profile switch <profile-name>"
return 1
fi
if [ ! -d "$profile_path" ]; then
echo -e "${RED}Error: Profile '$profile_name' does not exist${NC}"
echo "Available profiles:"
list_profiles
return 1
fi
# Backup current .ssh if it exists and is not a symlink
if [ -d "$CURRENT_SSH" ] && [ ! -L "$CURRENT_SSH" ]; then
local timestamp=$(date +%Y%m%d_%H%M%S)
local backup_name="backup_$timestamp"
echo -e "${YELLOW}Backing up current .ssh to profile: $backup_name${NC}"
mv "$CURRENT_SSH" "$SSH_PROFILES_DIR/$backup_name"
elif [ -L "$CURRENT_SSH" ]; then
rm "$CURRENT_SSH"
fi
echo -e "${GREEN}Switching to profile: $profile_name${NC}"
cp -R "$profile_path" "$CURRENT_SSH"
chmod 700 "$CURRENT_SSH"
find "$CURRENT_SSH" -type f -name "id_*" -o -name "*_rsa" -o -name "*_ed25519" | xargs -I {} chmod 600 {}
echo "$profile_name" > "$CURRENT_PROFILE_MARKER"
echo -e "${GREEN}✓ Switched to profile: $profile_name${NC}"
}
save_profile() {
local profile_name="$1"
if [ -z "$profile_name" ]; then
echo -e "${RED}Error: Please specify a profile name${NC}"
echo "Usage: ssh-profile save <profile-name>"
return 1
fi
init_profiles
local profile_path="$SSH_PROFILES_DIR/$profile_name"
if [ -d "$profile_path" ]; then
read -p "Profile '$profile_name' already exists. Overwrite? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Cancelled."
return 1
fi
rm -rf "$profile_path"
fi
if [ ! -d "$CURRENT_SSH" ]; then
echo -e "${RED}Error: No .ssh directory found${NC}"
return 1
fi
cp -R "$CURRENT_SSH" "$profile_path"
echo "$profile_name" > "$CURRENT_PROFILE_MARKER"
echo -e "${GREEN}✓ Saved current .ssh as profile: $profile_name${NC}"
}
current_profile() {
if [ -f "$CURRENT_PROFILE_MARKER" ]; then
local profile=$(cat "$CURRENT_PROFILE_MARKER")
echo -e "${GREEN}Current profile: $profile${NC}"
else
echo -e "${YELLOW}No profile is currently active${NC}"
fi
}
delete_profile() {
local profile_name="$1"
local profile_path="$SSH_PROFILES_DIR/$profile_name"
if [ -z "$profile_name" ]; then
echo -e "${RED}Error: Please specify a profile name${NC}"
echo "Usage: ssh-profile delete <profile-name>"
return 1
fi
if [ ! -d "$profile_path" ]; then
echo -e "${RED}Error: Profile '$profile_name' does not exist${NC}"
return 1
fi
read -p "Delete profile '$profile_name'? (y/N) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
rm -rf "$profile_path"
echo -e "${GREEN}✓ Deleted profile: $profile_name${NC}"
fi
}
show_help() {
echo "SSH Profile Manager - Easily manage multiple SSH configurations"
echo ""
echo "Usage: ssh-profile <command> [arguments]"
echo ""
echo "Commands:"
echo " list List all saved profiles"
echo " switch <name> Switch to a different profile"
echo " save <name> Save current .ssh as a profile"
echo " current Show current active profile"
echo " delete <name> Delete a saved profile"
echo " help Show this help message"
echo ""
echo "Examples:"
echo " ssh-profile save amazon # Save current .ssh as 'amazon'"
echo " ssh-profile save personal # Save current .ssh as 'personal'"
echo " ssh-profile list # List all profiles"
echo " ssh-profile switch amazon # Switch to 'amazon' profile"
}
case "$1" in
list|ls)
list_profiles
;;
switch|use)
switch_profile "$2"
;;
save|add)
save_profile "$2"
;;
current)
current_profile
;;
delete|rm)
delete_profile "$2"
;;
help|--help|-h|"")
show_help
;;
*)
echo -e "${RED}Unknown command: $1${NC}"
show_help
exit 1
;;
esac
@vkuprin
Copy link
Author

vkuprin commented Jan 30, 2026

    # SSH Profile Manager - Easy switching between SSH configurations

    $SSH_PROFILES_DIR = Join-Path $env:USERPROFILE ".ssh-profiles"
    $CURRENT_SSH = Join-Path $env:USERPROFILE ".ssh"
    $CURRENT_PROFILE_MARKER = Join-Path $SSH_PROFILES_DIR ".current"

    function Initialize-Profiles {
        if (-not (Test-Path $SSH_PROFILES_DIR)) {
            New-Item -ItemType Directory -Path $SSH_PROFILES_DIR -Force | Out-Null
            Write-Host "Created SSH profiles directory: $SSH_PROFILES_DIR" -ForegroundColor
  Green
        }
    }

    function Show-Profiles {
        Initialize-Profiles
        Write-Host "Available SSH profiles:" -ForegroundColor Blue

        $currentProfile = "unknown"
        if (Test-Path $CURRENT_PROFILE_MARKER) {
            $currentProfile = Get-Content $CURRENT_PROFILE_MARKER -Raw -ErrorAction
  SilentlyContinue
            $currentProfile = $currentProfile.Trim()
        }

        if (Test-Path $CURRENT_SSH) {
            Write-Host "  * active" -ForegroundColor Green -NoNewline
            Write-Host " (currently in use)"
        }

        Get-ChildItem -Path $SSH_PROFILES_DIR -Directory | ForEach-Object {
            $profileName = $_.Name
            if ($profileName -eq $currentProfile) {
                Write-Host "  * $profileName" -ForegroundColor Green -NoNewline
                Write-Host " (current)"
            } else {
                Write-Host "    $profileName"
            }
        }
    }

    function Switch-Profile {
        param([string]$ProfileName)

        if ([string]::IsNullOrWhiteSpace($ProfileName)) {
            Write-Host "Error: Please specify a profile name" -ForegroundColor Red
            Write-Host "Usage: ssh-profile.ps1 switch <profile-name>"
            return
        }

        $profilePath = Join-Path $SSH_PROFILES_DIR $ProfileName

        if (-not (Test-Path $profilePath)) {
            Write-Host "Error: Profile '$ProfileName' does not exist" -ForegroundColor Red
            Write-Host "Available profiles:"
            Show-Profiles
            return
        }

        # Backup current .ssh if it exists and is not a symlink
        if (Test-Path $CURRENT_SSH) {
            $isSymlink = (Get-Item $CURRENT_SSH -Force).Attributes -band
  [System.IO.FileAttributes]::ReparsePoint

            if (-not $isSymlink) {
                $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
                $backupName = "backup_$timestamp"
                Write-Host "Backing up current .ssh to profile: $backupName" -ForegroundColor
  Yellow
                Move-Item -Path $CURRENT_SSH -Destination (Join-Path $SSH_PROFILES_DIR
  $backupName) -Force
            } else {
                Remove-Item -Path $CURRENT_SSH -Force -Recurse
            }
        }

        Write-Host "Switching to profile: $ProfileName" -ForegroundColor Green
        Copy-Item -Path $profilePath -Destination $CURRENT_SSH -Recurse -Force

        # Set permissions (Windows equivalent - remove inheritance and set explicit 
  permissions)
        $acl = Get-Acl $CURRENT_SSH
        $acl.SetAccessRuleProtection($true, $false)
        $username = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
        $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($username,
  "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")
        $acl.SetAccessRule($accessRule)
        Set-Acl -Path $CURRENT_SSH -AclObject $acl

        # Set permissions for private keys
        Get-ChildItem -Path $CURRENT_SSH -File -Recurse | Where-Object {
            $_.Name -like "id_*" -or $_.Name -like "*_rsa" -or $_.Name -like "*_ed25519"
        } | ForEach-Object {
            $keyAcl = Get-Acl $_.FullName
            $keyAcl.SetAccessRuleProtection($true, $false)
            $keyAccessRule = New-Object
  System.Security.AccessControl.FileSystemAccessRule($username, "FullControl", "Allow")
            $keyAcl.SetAccessRule($keyAccessRule)
            Set-Acl -Path $_.FullName -AclObject $keyAcl
        }

        Set-Content -Path $CURRENT_PROFILE_MARKER -Value $ProfileName

        Write-Host "✓ Switched to profile: $ProfileName" -ForegroundColor Green
    }

    function Save-Profile {
        param([string]$ProfileName)

        if ([string]::IsNullOrWhiteSpace($ProfileName)) {
            Write-Host "Error: Please specify a profile name" -ForegroundColor Red
            Write-Host "Usage: ssh-profile.ps1 save <profile-name>"
            return
        }

        Initialize-Profiles
        $profilePath = Join-Path $SSH_PROFILES_DIR $ProfileName

        if (Test-Path $profilePath) {
            $response = Read-Host "Profile '$ProfileName' already exists. Overwrite? (y/N)"
            if ($response -ne 'y' -and $response -ne 'Y') {
                Write-Host "Cancelled."
                return
            }
            Remove-Item -Path $profilePath -Recurse -Force
        }

        if (-not (Test-Path $CURRENT_SSH)) {
            Write-Host "Error: No .ssh directory found" -ForegroundColor Red
            return
        }

        Copy-Item -Path $CURRENT_SSH -Destination $profilePath -Recurse -Force
        Set-Content -Path $CURRENT_PROFILE_MARKER -Value $ProfileName
        Write-Host "✓ Saved current .ssh as profile: $ProfileName" -ForegroundColor Green
    }

    function Show-CurrentProfile {
        if (Test-Path $CURRENT_PROFILE_MARKER) {
            $profile = (Get-Content $CURRENT_PROFILE_MARKER -Raw).Trim()
            Write-Host "Current profile: $profile" -ForegroundColor Green
        } else {
            Write-Host "No profile is currently active" -ForegroundColor Yellow
        }
    }

    function Remove-Profile {
        param([string]$ProfileName)

        if ([string]::IsNullOrWhiteSpace($ProfileName)) {
            Write-Host "Error: Please specify a profile name" -ForegroundColor Red
            Write-Host "Usage: ssh-profile.ps1 delete <profile-name>"
            return
        }

        $profilePath = Join-Path $SSH_PROFILES_DIR $ProfileName

        if (-not (Test-Path $profilePath)) {
            Write-Host "Error: Profile '$ProfileName' does not exist" -ForegroundColor Red
            return
        }

        $response = Read-Host "Delete profile '$ProfileName'? (y/N)"
        if ($response -eq 'y' -or $response -eq 'Y') {
            Remove-Item -Path $profilePath -Recurse -Force
            Write-Host "✓ Deleted profile: $ProfileName" -ForegroundColor Green
        }
    }

    function Show-Help {
        Write-Host "SSH Profile Manager - Easily manage multiple SSH configurations"
        Write-Host ""
        Write-Host "Usage: ssh-profile.ps1 <command> [arguments]"
        Write-Host ""
        Write-Host "Commands:"
        Write-Host "  list                  List all saved profiles"
        Write-Host "  switch <name>         Switch to a different profile"
        Write-Host "  save <name>           Save current .ssh as a profile"
        Write-Host "  current               Show current active profile"
        Write-Host "  delete <name>         Delete a saved profile"
        Write-Host "  help                  Show this help message"
        Write-Host ""
        Write-Host "Examples:"
        Write-Host "  .\ssh-profile.ps1 save amazon         # Save current .ssh as 'amazon'"
        Write-Host "  .\ssh-profile.ps1 save personal       # Save current .ssh as 'personal'"
        Write-Host "  .\ssh-profile.ps1 list                # List all profiles"
        Write-Host "  .\ssh-profile.ps1 switch amazon       # Switch to 'amazon' profile"
    }

    # Main script logic
    $command = $args[0]
    $argument = $args[1]

    switch ($command) {
        { $_ -in "list", "ls" } {
            Show-Profiles
        }
        { $_ -in "switch", "use" } {
            Switch-Profile -ProfileName $argument
        }
        { $_ -in "save", "add" } {
            Save-Profile -ProfileName $argument
        }
        "current" {
            Show-CurrentProfile
        }
        { $_ -in "delete", "rm" } {
            Remove-Profile -ProfileName $argument
        }
        { $_ -in "help", "--help", "-h", $null } {
            Show-Help
        }
        default {
            Write-Host "Unknown command: $command" -ForegroundColor Red
            Show-Help
            exit 1
        }
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment