Skip to content

Instantly share code, notes, and snippets.

@Shoozza
Last active April 20, 2022 02:45
Show Gist options
  • Save Shoozza/8fe8b0c85fa89cd3b1c4 to your computer and use it in GitHub Desktop.
Save Shoozza/8fe8b0c85fa89cd3b1c4 to your computer and use it in GitHub Desktop.
Make Cmder work with ssh-agent
@ECHO OFF
SETLOCAL
GOTO:MAIN
REM
REM Info functions start
REM
REM Display version and copyright information
:VERSION
ECHO,Agent 1.0.0.0 (ssh-agent script for MSYS2)
ECHO,
ECHO,Copyright (C^) 2014-2021 Gregor A. Cieslak.
ECHO,
ECHO,License GPLv3+: GNU GPL version 3 or later ^<https://gnu.org/licenses/gpl.html^>.
ECHO,This is free software: you are free to change and redistribute it.
ECHO,There is NO WARRANTY, to the extent permitted by law.
GOTO:EOF
REM Display usage information
:USAGE
ECHO,Adds missing ssh-keys to an instance of ssh-agent.
ECHO,Starts a new instance if ssh-agent is not running or sock file is invalid.
ECHO,Use with MSYS2 command line tools (https://www.msys2.org/^).
ECHO,
ECHO,Requirements:
ECHO, %%HOME%%\.ssh folder with ssh keys in any of the following formats:
ECHO, rsa, dsa, ecdsa, ecdsa_sk, ed25519, ed25519_sk
ECHO, MSYS2 installation with following command line tools:
ECHO, cygpath, rm, sed, awk, grep, ps, ssh-add, ssh-keygen, ssh-agent
ECHO,
ECHO,Usage: agent [OPTION]
ECHO,
ECHO,OPTION:
ECHO, -c, --check check requirements
ECHO, -h, --help display this help text
ECHO, -k, --kill kill all ssh-agent processes
ECHO, -v, --verbose verbose mode
ECHO, -V --version display version
GOTO:EOF
REM
REM Info functions end
REM
REM
REM Entry point start
REM
:MAIN
REM Parse command line arguments
IF NOT "%~2" == "" GOTO:USAGE
IF "%~1" == "-h" GOTO:USAGE
IF "%~1" == "--help" GOTO:USAGE
IF "%~1" == "-k" GOTO:KILLSSHAGENT
IF "%~1" == "--kill" GOTO:KILLSSHAGENT
IF "%~1" == "-c" GOTO:CHECKREQUIREMENTS
IF "%~1" == "--check" GOTO:CHECKREQUIREMENTS
IF "%~1" == "-V" GOTO:VERSION
IF "%~1" == "--version" GOTO:VERSION
REM Check for verbose output
SET "VERBOSE="
IF "%~1" == "-v" (
SET "VERBOSE=true"
) ELSE IF "%~1" == "--verbose" (
SET "VERBOSE=true"
) ELSE IF NOT "%~1" == "" GOTO:USAGE
CALL:LOG "[INFO] Adding missing ssh keys:"
CALL:LOG "-------------------------------------------"
REM Set default sock file if missing
SET "DEFAULT_AUTH_SOCK=/tmp/ssh-agent.sock"
IF "%SSH_AUTH_SOCK%" == "" GOTO:SETDEFAULTSOCK
IF "%SSH_AUTH_SOCK%" == "%DEFAULT_AUTH_SOCK%" GOTO:SETDEFAULTSOCK
CALL:LOG "[INFO] Checking preexisting ssh-agent sock file"
GOTO:CHECKSOCKFILE
:SETDEFAULTSOCK
SET "SSH_AUTH_SOCK=%DEFAULT_AUTH_SOCK%"
CALL:LOG "[INFO] Checking default ssh-agent sock file"
:CHECKSOCKFILE
REM Check if path to socket file is available
FOR /f "tokens=*" %%I IN ('cygpath -w "%SSH_AUTH_SOCK%"') DO SET "VAR=%%I"
IF "%SSH_AUTH_SOCK%" == "%DEFAULT_AUTH_SOCK%" (
IF NOT EXIST "%VAR%" GOTO:RUNAGENT
) ELSE (
IF NOT EXIST "%VAR%" GOTO:SETDEFAULTSOCK
)
CALL:LOG "[INFO] Found ssh-agent sock file"
REM Check if an ssh-agent is running
FOR /f "tokens=*" %%I IN ('ps ^| grep ssh-agent ^| sed "s/^ *\([0-9]\+\) .*/\1/"') DO SET "VAR=%%I"
IF "%SSH_AUTH_SOCK%" == "%DEFAULT_AUTH_SOCK%" (
IF "%VAR%" == "" GOTO:RUNAGENT
) ELSE (
IF "%VAR%" == "" GOTO:CHECKDEFAULTSOCK
)
CALL:LOG "[INFO] Found ssh-agent process"
REM Check if socket file is valid
ssh-add -l 1> NUL 2>&1
IF ERRORLEVEL 1 (
CALL:LOG "[INFO] Failed to validate sock file"
IF "%SSH_AUTH_SOCK%" == "%DEFAULT_AUTH_SOCK%" (
GOTO:RUNAGENT
) ELSE (
GOTO:SETDEFAULTSOCK
)
)
CALL:LOG "[INFO] Found valid sock file"
GOTO:ADDKEYS
:RUNAGENT
CALL:LOG "[INFO] Starting new ssh-agent"
REM Don't delete %%SSH_AUTH_SOCK%% - could be set to a dangerous path
IF NOT "%SSH_AUTH_SOCK%" == "%DEFAULT_AUTH_SOCK%" GOTO:SKIPDELETESOCK
REM Remove old default socket file if available
FOR /f "tokens=*" %%I IN ('cygpath -w "%DEFAULT_AUTH_SOCK%"') DO SET "VAR=%%I"
IF EXIST "%VAR%" rm -f -- "%DEFAULT_AUTH_SOCK%"
SET "SSH_AUTH_SOCK=%DEFAULT_AUTH_SOCK%"
:SKIPDELETESOCK
REM Run ssh-agent and save (last) PID in VAR
SET "VAR="
FOR /f "tokens=*" %%J IN ('ssh-agent -a "%SSH_AUTH_SOCK%"') DO FOR /f "tokens=*" %%K IN ('ECHO,%%J ^| grep "SSH_AGENT_PID" ^| sed "s/^SSH_AGENT_PID=\([0-9]\+\); .*/\1/"') DO SET "VAR=%%K"
:ADDKEYS
SET "SSH_AGENT_PID=%VAR%"
REM Check if ssh keys are known
SET "KEYS="
SET /A "KEYCOUNT=0"
FOR /f "tokens=*" %%I IN ('DIR /B "%HOME%\.ssh\*_rsa" "%HOME%\.ssh\*_dsa" "%HOME%\.ssh\*_ecdsa" "%HOME%\.ssh\*_ecdsa_sk" "%HOME%\.ssh\*_ed25519" "%HOME%\.ssh\*_ed25519_sk" 2^> NUL') DO CALL:CHECKKEY %%I
REM Print ssh key count
IF %KEYCOUNT% == 1 (
CALL:LOG "[INFO] Found %KEYCOUNT% ssh key"
) ELSE (
CALL:LOG "[INFO] Found %KEYCOUNT% ssh keys"
)
REM Add all missing ssh keys
IF NOT "%KEYS%" == "" (
CALL:LOG "[INFO] Adding ssh keys"
ssh-add %KEYS%
) ELSE (
CALL:LOG "[INFO] All ssh keys already added"
)
CALL:LOG "==========================================="
CALL:LOG "[INFO] Done"
ENDLOCAL & SET "SSH_AGENT_PID=%SSH_AGENT_PID%" & SET "SSH_AUTH_SOCK=%SSH_AUTH_SOCK%"
GOTO:EOF
REM
REM Entry point end
REM
REM
REM Functions start
REM
REM Check if ssh key has to be added
:CHECKKEY
SET /A "KEYCOUNT=KEYCOUNT+1"
SET "FINGERPRINT="
FOR /f "tokens=*" %%J IN ('ssh-keygen -lf "%HOME%\.ssh\%1" 2^>nul ^| awk "{print $2}"') DO SET "FINGERPRINT=%%J"
IF "%FINGERPRINT%" == "" GOTO:EOF
SET "VAR="
FOR /f "tokens=*" %%J IN ('ssh-add -l 2^>nul ^| awk "{print $2}" ^| grep "%FINGERPRINT%"') DO SET "VAR=%%J"
IF "%VAR%" == "" SET "KEYS='%HOME%\.ssh\%1' %KEYS%"
GOTO:EOF
REM Output text in verbose mode
:LOG
IF "%VERBOSE%" == "" GOTO:EOF
ECHO,%~1
GOTO:EOF
REM Check if required command line tools, folders and ssh keys are available
:CHECKREQUIREMENTS
SET "FAILED="
ECHO,[INFO] Checking requirements...
ECHO,-------------------------------------------
CALL:CHECKPROGEXISTS cygpath
IF NOT "%FAILED%"=="" GOTO:SKIPTMPPATHCHECK
FOR /f "tokens=*" %%I IN ('cygpath -w /tmp') DO SET "TMPPATH=%%I"
IF EXIST "%TMPPATH%" (
ECHO,[OK] found /tmp folder
) ELSE (
ECHO,[FAIL] missing /tmp folder
SET "FAILED=true"
)
:SKIPTMPPATHCHECK
IF EXIST "%HOME%\.ssh\" (
ECHO,[OK] found %%HOME%%\.ssh folder
) ELSE (
ECHO,[FAIL] missing %%HOME%%\.ssh folder
SET "FAILED=true"
)
CALL:CHECKPROGEXISTS rm
CALL:CHECKPROGEXISTS sed
CALL:CHECKPROGEXISTS awk
CALL:CHECKPROGEXISTS grep
CALL:CHECKPROGEXISTS ps
CALL:CHECKPROGEXISTS ssh-add
CALL:CHECKPROGEXISTS ssh-keygen
CALL:CHECKPROGEXISTS ssh-agent
SET "KEYS="
SET /A "KEYCOUNT=0"
FOR /f "tokens=*" %%I IN ('DIR /B "%HOME%\.ssh\*_rsa" "%HOME%\.ssh\*_dsa" "%HOME%\.ssh\*_ecdsa" "%HOME%\.ssh\*_ecdsa_sk" "%HOME%\.ssh\*_ed25519" "%HOME%\.ssh\*_ed25519_sk" 2^> NUL') DO CALL:CHECKKEY %%I
IF NOT %KEYCOUNT% == 0 (
IF %KEYCOUNT% == 1 (
ECHO,[OK] found %KEYCOUNT% ssh key
) ELSE (
ECHO,[OK] found %KEYCOUNT% ssh keys
)
) ELSE (
ECHO,[FAIL] missing ssh keys
SET "FAILED=true"
)
ECHO,===========================================
IF "%FAILED%"=="" (
ECHO,[OK] Success! All requirements are met
) ELSE (
ECHO,[FAIL] Failure! Some requirements are not met!
)
GOTO:EOF
REM Check if programm is in path
:CHECKPROGEXISTS
WHERE /q %1
IF ERRORLEVEL 1 (
ECHO,[FAIL] missing %1 in PATH
SET "FAILED=true"
) ELSE (
ECHO,[OK] found %1
)
GOTO:EOF
REM Kills all ssh-agent processes
:KILLSSHAGENT
SET /A "KILLCOUNT=0"
FOR /f "tokens=*" %%I IN ('ps ^| grep ssh-agent ^| awk "{print $1}"') DO (
IF NOT "%%I" == "" (
KILL %%I
SET /A "KILLCOUNT=KILLCOUNT+1"
)
)
ECHO,[INFO] killed %KILLCOUNT% ssh-agent processes
GOTO:EOF
REM
REM Functions end
REM
@Shoozza
Copy link
Author

Shoozza commented Sep 22, 2021

Hey everyone since this script is not really necessary for cmder,
I decided to fix and update this script to work with MSYS2 (and possibly cygwin).
Cmder provides a start-ssh-agent script from git-for-windows by default.

Updated and extended the script:
Add license
Add kill command
Add verbose output
Add help/usage info
Add version/license info
Add dependency check support
Add support for adding all kinds of ssh keys
Add comments
Add support for checking already set SSH_AUTH_SOCK before using DEFAULT_AUTH_SOCK
Modify use ECHO, for faster output
Fix don't leak/overwrite environment variables except SSH_AUTH_SOCK and SSH_AGENT_PID if successfull
Fix check for the sock file in the correct folder (/tmp != %TEMP%)
Fix valid sock file check needs to check with fingerprint instead of non working path

Have fun ;)

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