Once again my employeer forces me to work from an inferior platform, so what are my options to get the best possible working environment? Heres some tips to what I’ve done so far.

The windows terminal is one of the better things produced by Microsoft the last couple of years. I have already written a bit about it before, so search for windows terminal, and you will get the other articles. Even though the terminal is nice, there are some minor annoyances, when you are used to work in a bash environment.

  1. No nice “inline” editor
  2. Does not obey ctrl-d to exit the session
  3. Does not have tab completion on entries in the ssh config file

To fix these three annoyances, we need to download vim from www.vim.org, install it and the rest is done creating and configuring a powershell profile, lets dive into it.

Not only do I have to work from a windows machine (my department does primarily FOSS solutions) I also don’t have any elevated permissions on my machine. IT proffesionlas are treated just the same as office workers 🙁

This means I cannot install any software, besides whats picked by the Windows admins. Luckily vim is not picky, and you can install it in your own home folder. So lauch the installer and change the install path accordingly.

When vim is installed, all we need to do is to create a powershell profile file. The file has to be named Microsoft.PowerShell_Profile.ps1 and has to be placed under $home\Documents\PowerShell\
When placed here it will be a user specific profile, you can also do system-wide profiles, take a look at $pshome.

The profile file I have created looks like this:

using namespace System.Management.Automation

# Set aliases

Set-Alias -name vim $home\Vim\vim90\vim.exe
Set-Alias -name vi $home\Vim\vim90\vim.exe

# Obey ctrl-d

Set-PSReadlineKeyHandler -Key ctrl+d -Function ViExit

# Enable ssh tab completion
# Credits to backerman and contributers at github for creating the code

Register-ArgumentCompleter -CommandName ssh,scp,sftp -Native -ScriptBlock {
param($wordToComplete, $commandAst, $cursorPosition)

function Get-SSHHostList($sshConfigPath) {
    Get-Content -Path $sshConfigPath `
    | Select-String -Pattern '^Host ' `
    | ForEach-Object { $_ -replace 'Host ', '' } `
    | ForEach-Object { $_ -split ' ' } `
    | Sort-Object -Unique `
    | Select-String -Pattern '^.*[*!?].*$' -NotMatch

function Get-SSHConfigFileList ($sshConfigFilePath) {
    $sshConfigDir = Split-Path -Path $sshConfigFilePath -Resolve -Parent

    $sshConfigFilePaths = @()
    $sshConfigFilePaths += $sshConfigFilePath

    $pathsPatterns = @()
    Get-Content -Path $sshConfigFilePath `
    | Select-String -Pattern '^Include ' `
    | ForEach-Object { $_ -replace 'Include ', '' }  `
    | ForEach-Object { $_ -replace '~', $Env:USERPROFILE } `
    | ForEach-Object { $_ -replace '\$Env:USERPROFILE', $Env:USERPROFILE } `
    | ForEach-Object { $_ -replace '\$Env:HOMEPATH', $Env:USERPROFILE } `
    | ForEach-Object { 
    $sshConfigFilePaths += $(Get-ChildItem -Path $sshConfigDir\$_ -File -ErrorAction SilentlyContinue -Force).FullName `
    | ForEach-Object { Get-SSHConfigFileList $_ } 

    if (($sshConfigFilePaths.Length -eq 1) -and ($sshConfigFilePaths.item(0) -eq $sshConfigFilePath) ) {
        return $sshConfigFilePath

    return $sshConfigFilePaths | Sort-Object -Unique

$sshPath = "$Env:USERPROFILE\.ssh"
$hosts = Get-SSHConfigFileList "$sshPath\config" `
| ForEach-Object { Get-SSHHostList $_ } `

# For now just assume it's a hostname.
$textToComplete = $wordToComplete
$generateCompletionText = {
if ($wordToComplete -match "^(?<user>[-\w/\\]+)@(?<host>[-.\w]+)$") {
    $textToComplete = $Matches["host"]
    $generateCompletionText = {
        $Matches["user"] + "@" + $hostname

$hosts `
| Where-Object { $_ -like "${textToComplete}*" } `
| ForEach-Object { [CompletionResult]::new((&$generateCompletionText($_)), $_, [CompletionResultType]::ParameterValue, $_) }}

Exit your terminal and lauch it again, hopefully you can be a bit more productive with the new “features”

One Responses

  1. Finally a decent terminal for Windows – www.nordal-lund.dk  14 January 2023

    […] Tip! Check out my new post about making the terminal great again here […]

Leave a Reply

Your email address will not be published. Required fields are marked *

Are you human? * Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.