Skip to content

Instantly share code, notes, and snippets.

@phil-blain
Last active December 9, 2022 15:15
Show Gist options
  • Save phil-blain/2e5a294b79ec26a1729aedab010a9369 to your computer and use it in GitHub Desktop.
Save phil-blain/2e5a294b79ec26a1729aedab010a9369 to your computer and use it in GitHub Desktop.
Generate Windows Terminal profiles for each host in your SSH config
#!/usr/bin/env python
import os
import uuid
import json
import urllib.request
import paramiko
# Watch out for https://github.com/paramiko/paramiko/pull/1991
# Parse OpenSSH config file
cfg = paramiko.SSHConfig.from_path(os.path.join(os.environ['USERPROFILE'], os.path.normpath(".ssh/config")))
# Filter out wildcards and negated patterns
hosts = [h for h in cfg.get_hostnames() if '*' not in h and '!' not in h]
# The Windows Terminal namespace GUID for custom profiles & fragments
terminalNamespaceGUID = uuid.UUID("{f65ddb7e-706b-4499-8a50-40313caf510a}")
# The Application Namespace GUID
appName = "OpenSSH_for_Windows"
appNamespaceGUID = uuid.uuid5(terminalNamespaceGUID, appName.encode("UTF-16LE").decode("ASCII"))
# Create the fragments directory
fragmentsDir = os.path.join(os.environ['LOCALAPPDATA'], os.path.normpath("Microsoft/Windows Terminal/Fragments/" + appName))
os.makedirs(fragmentsDir, exist_ok=True)
# Download the OpenSSH logo
openSSHGitHubOrgID = "2387206"
iconPath = os.path.join(fragmentsDir, "openssh.png")
urllib.request.urlretrieve("https://avatars.githubusercontent.com/u/" + openSSHGitHubOrgID, iconPath)
profiles = []
fragment = {}
fragment["profiles"] = profiles
for host in hosts:
# Calculate the GUID for this profile
profileGUID = uuid.uuid5(appNamespaceGUID, host.encode("UTF-16LE").decode("ASCII"))
profile = {"guid": f"{{{profileGUID}}}"}
profile["name"] = "SSH " + host
# TODO: hack powershell's history (if possible) so that up arrow yields 'ssh host'
# In the meantime: add the content in 'profile.ps1' (below) to your PowerShell profile
profile["commandline"] = f"powershell -NoExit -Command \"ssh {host}\""
profile["startingDirectory"] = "%USERPROFILE%"
profile["icon"] = iconPath
fragment["profiles"].append(profile)
fragmentFile = os.path.join(fragmentsDir, "profiles.json")
with open(fragmentFile, 'w') as f:
json.dump(fragment, f, indent=4)
# Add custom key binding to access built-in Powershell history (not PSReadLine's)
$parameters = @{
key = 'ctrl+uparrow'
briefdescription = 'PreviousBuiltinHistory'
longdescription = 'Replace entry with previous builtin history entry'
scriptblock = {
param($key, $arg) # the arguments are ignored in this example
# Get previous builtin history entry
$hist = Get-History
$previous = $hist[-1].commandline
# Insert it
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
[Microsoft.PowerShell.PSConsoleReadLine]::Replace(0, $line.length, $previous)
}
}
Set-PSReadLineKeyHandler @parameters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment