Adding parameters to DefaultShell in Windows OpenSSH Server (e.g. powershell.exe -NoLogo)
I have Windows OpenSSH server installed and working properly. I can change the default shell that is ssh'd into using HKLM:\SOFTWARE\OpenSSH
and adding a DefaultShell
property as described here.
So let's go with the default example, since it works as-is on pretty much every Windows installation with the "normal" C:\Windows
path:
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
Now let's say that I want to add a parameter to it, perhaps "-NoLogo". This is just a for-instance. Ultimately, I'd want to be able to launch into a WSL distribution with options. But for now, let's go simple:
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo" -PropertyType String -Force
This not only doesn't work, it breaks the login in strange ways. With the first method (no arguments), my public key in ssh-agent is offered and accepted. When I add the -NoLogo
, I end up at a password prompt, which fails using my Windows password.
Running sshd.exe -ddd
shows:
User not allowed because shell c:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe -nologo does not exist
Okay, so that's not going to work, because OpenSSH checks to make sure the exact DefaultShell
string is an executable.
I see that there are two other registry settings, but neither seems to be what I'm looking for. One might think from its name that DefaultShellCommandOption
would be of some use here, but it is simply the option needed for the shell when a command is passed in, such as:
ssh hostname ls
Since one of the attempted answers here thought DefaultShellCommandOption
would do the trick, I did try it, and confirmed that it is only used when a command is passed in. I can also see in the OpenSSH source that shell_option is only used when there is a command, otherwise it only executes the shell by itself:
if (command) {
size_t len = strlen(shell) + 1 + strlen(shell_option) + 1 + strlen(command) + 1;
pty_cmd = calloc(1, len);
strcpy_s(pty_cmd, len, shell);
strcat_s(pty_cmd, len, " ");
strcat_s(pty_cmd, len, shell_option);
strcat_s(pty_cmd, len, " ");
strcat_s(pty_cmd, len, command);
} else {
pty_cmd = shell;
}
Is anyone aware of a way to add parameters/arguments to the DefaultShell
in Windows OpenSSH?
Potential Workaround
Once I noticed that OpenSSH was checking to make sure the DefaultShell
existed and was executable, I decided to just try creating a batch file wrapping the PowerShell options.
I created a directory and file C:\ProgramData\OpenSSH\ssh-shell.bat
:
@echo off
C:\Windows\System32\WindowsPowerShell/v1.0/powershell.exe -NoLogo %*
And changed my DefaultShell
to run that wrapper (from an elevated PowerShell):
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\ProgramData\OpenSSH\ssh-shell.bat" -PropertyType String -Force
That seems to work as desired, both for access to the shell itself as well as when running with a command (e.g. ssh hostname ls
).
It is also possible to launch directly into a specified WSL distribution this way:
@echo off
C:\Windows\System32\wsl.exe ~ -d Alpine %*
Note that this does require that the DefaultShellCommandOption
also be changed:
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShellCommandOption -Value "-e /bin/sh -c" -PropertyType String -Force
Security Implications
This feels like it is just as safe as the default OpenSSH DefaultShell
behavior, since it builds the commandline using the actual shell (plus my desired additional arguments), the DefaultShellCommandOption
(-c
by default), and the command(s) that are passed in.
But I'm open to suggestions on how this might be made more robust or secure, or if there are any security issues that one might see.