Skip to content

Instantly share code, notes, and snippets.

@linktohack
Created January 18, 2026 23:14
Show Gist options
  • Select an option

  • Save linktohack/77adda04fcac7854003a4c32e194177e to your computer and use it in GitHub Desktop.

Select an option

Save linktohack/77adda04fcac7854003a4c32e194177e to your computer and use it in GitHub Desktop.
Ansible on Windows with Plink and shared connection
[defaults]
inventory = inventory.ini
host_key_checking = False
[ssh_connection]
ssh_executable = ./plink-wrapper.sh
transfer_method = piped
#!/usr/bin/env python3
"""Import OpenSSH config hosts into PuTTY sessions."""
import re
import os
import winreg
from pathlib import Path
from urllib.parse import quote
def parse_ssh_config(config_path=None):
"""Parse ~/.ssh/config and return list of host configurations."""
if config_path is None:
config_path = Path.home() / ".ssh" / "config"
hosts = []
current_host = None
with open(config_path, 'r') as f:
for line in f:
line = line.strip()
if not line or line.startswith('#'):
continue
match = re.match(r'^(\S+)\s+(.+)$', line)
if not match:
continue
key, value = match.groups()
key = key.lower()
if key == 'host':
if current_host and '*' not in current_host.get('host', ''):
hosts.append(current_host)
current_host = {'host': value}
elif current_host:
current_host[key] = value
# Don't forget the last host
if current_host and '*' not in current_host.get('host', ''):
hosts.append(current_host)
return hosts
def create_putty_session(host_config, dry_run=False):
"""Create a PuTTY session in the registry."""
session_name = host_config['host']
# PuTTY URL-encodes session names
session_key = quote(session_name, safe='')
reg_path = rf"Software\SimonTatham\PuTTY\Sessions\{session_key}"
# Map SSH config to PuTTY registry values
values = {}
# HostName
if 'hostname' in host_config:
values['HostName'] = host_config['hostname']
else:
values['HostName'] = host_config['host']
# User
if 'user' in host_config:
values['UserName'] = host_config['user']
# Port
if 'port' in host_config:
values['PortNumber'] = int(host_config['port'])
# IdentityFile (convert to Windows path and PuTTY format)
if 'identityfile' in host_config:
key_path = host_config['identityfile']
key_path = os.path.expanduser(key_path)
# Convert to .ppk if needed (PuTTY uses different key format)
values['PublicKeyFile'] = key_path.replace('/', '\\')
# ProxyJump -> PuTTY proxy command
if 'proxyjump' in host_config:
values['ProxyMethod'] = 6 # Local proxy command
proxy_host = host_config['proxyjump']
values['ProxyTelnetCommand'] = f'plink -batch -share {proxy_host} -nc %host:%port'
# Connection sharing
values['ConnectionSharing'] = 1
values['ConnectionSharingUpstream'] = 1
values['ConnectionSharingDownstream'] = 1
if dry_run:
print(f"\n[Session: {session_name}]")
for k, v in values.items():
print(f" {k} = {v}")
return
# Write to registry
try:
key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, reg_path)
for name, value in values.items():
if isinstance(value, int):
winreg.SetValueEx(key, name, 0, winreg.REG_DWORD, value)
else:
winreg.SetValueEx(key, name, 0, winreg.REG_SZ, str(value))
winreg.CloseKey(key)
print(f"Created session: {session_name}")
except Exception as e:
print(f"Error creating {session_name}: {e}")
def main():
import argparse
parser = argparse.ArgumentParser(description='Import SSH config to PuTTY')
parser.add_argument('--config', '-c', help='Path to SSH config file')
parser.add_argument('--dry-run', '-n', action='store_true',
help='Show what would be created without writing to registry')
args = parser.parse_args()
hosts = parse_ssh_config(args.config)
print(f"Found {len(hosts)} hosts in SSH config")
for host in hosts:
create_putty_session(host, dry_run=args.dry_run)
if not args.dry_run:
print("\nDone! Restart PuTTY to see the new sessions.")
print("Note: If you use SSH keys, convert them to .ppk format with PuTTYgen")
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment