As of Windows 10 (or Server 2019), Microsoft has basically added built-in support for OpenSSH as both a client and a host. Of course, it being #Windows, it's sometimes non-obvious and sub-par.
== Server setup ==
Open up an elevated Powershell session (ex. right-click on any Powershell icon/listing and choose {nav Run as Administrator}), and then run the following:
```
name=Elevated Powershell session, lang=Powershell
# Install the actual component. Can also be done via the "Features" listing in Windows.
Add-WindowsCapability -Online -Name OpenSSH.Server
# Make sure the services are set to automatically start, since they often aren't
Set-Service ssh-agent -StartupType Automatic
Set-Service sshd -StartupType Automatic
# Manually start the services so they're running without rebooting, because we're using SSH because we're trying to *not* be all Windows-y about things
Start-Service ssh-agent
Start-Service sshd
# This will optionally install some utilities, but they don't actually work well last I checked, so you can skip this if you want
Install-Module -Force OpenSSHUtils
```
Voila! You should now be able to SSH into your Windows machine from any SSH client.
== Client Setup ==
```
lang=powershell, name=Non-Elevated Powershell session
# Create and enter .ssh directory for your user.
cd $env:USERPROFILE; mkdir .ssh; cd .ssh
# Generate identity keys, by default this will be `id_rsa` and `id_rsa.pub`
ssh-keygen.exe
# Create an authorized_keys file starting with your local public key
copy id_rsa.pub authorized_keys
# open an Explorer window in the current location, because I haven't yet bothered to figure out how to do the next portion with Powershell
start .
```
=== Using SSH keys ===
In the GUI:
# Right click {nav authorized_keys}, then {nav Properties > Security > Advanced}
# {nav icon=check-square, name=Disable Inheritance}
# Choose "Convert inherited permissions into explicit permissions on this object" when prompted
# Remove all permissions on file except for `SYSTEM` and //yourself//. There must be exactly two permission entries on the file.
Or [[ https://winscp.net/eng/docs/ui_login_authentication#private_key | using WinSCP ]] (ewww).
Or on the commandline, https://superuser.com/questions/1451241/command-to-copy-client-public-key-to-windows-openssh-sftp-ssh-server-authorized has some details. See also the official docs at https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement.
=== I wanna be admin ===
[[ https://github.com/PowerShell/Win32-OpenSSH/issues/962#issuecomment-608067310 | One rando's comment ]] claims to the solution is to set [[ https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-gpsb/341747f5-6b5d-4d30-85fc-fa1cc04038d4 | ConsentPromptBehaviorAdmin ]], in `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System`. This is probably the right way to do it, but you'd still have to elevate via `runas` or such.
Conversely, the older [[ https://web.archive.org/web/20190119194648/https://support.microsoft.com/en-us/help/942817/how-to-change-the-remote-uac-localaccounttokenfilterpolicy-registry-se | since-redacted ]] Microsoft documentation cited earlier in the same GitHub issue suggests using the key `LocalAccountTokenFilterPolicy`, and this is probably less safe but means all SSH logins will be elevated, which is lazily nice.
```
name=Microsoft-suggested one-liner for adding key and value
cmd /c reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\system /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f
```
----
=== Different default shell than old cmd.exe ===
You can set the shell using a registry value pointing towards the executable.
```
lang=powershell, name="For example, for PowerShell"
New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
```
Note: I changed this to "cmd.exe" once and it oddly worked at first but then started responding with "permission denied" to every login attempt, so if you want to change it back to using `cmd.exe` just wipe out the registry key rather than changing it (or maybe use an absolute path).
----
Additional stuff that should maybe be on this page:
* https://stackoverflow.com/a/50502015/2808933
* http://code.kliu.org/misc/elevate/
* [[ https://www.reddit.com/r/PowerShell/comments/pcsyu4/comment/iu6ijt6/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button | this random Reddit comment about creating a PowerShell session that can then be attached to ]]
Official docs:
* https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh-server-configuration
* https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement