Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Minimum Viable Windows

A Mostly usable Windows workstation for macOS or Linux users

Especially starting with Windows 10, it isn't all that bad to work on day to day. It just requires a bit of setup out of the box to make it behave better just like those other platforms, and is sufficiently different so as to be non obvious to experienced Linux or macOS users.

Pick and choose what to do from below that fits your needs.

Note: I use emacs, like emacs keybindings and do a bit of Chef development,

TL;DR

Run Powershell as admin and run these.

Update-Help
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
Find-PackageProvider -ForceBootstrap
Install-Module PSReadLine -Force
Install-Module posh-git -Force
Install-Module z -Force
Install-Module PSColor -Force
iwr -usebasic https://chocolatey.org/install.ps1 | iex
iwr -usebasic https://omnitruck.chef.io/install.ps1 | iex; install chefdk
New-Item -Type File -Force $PROFILE
notepad $PROFILE

Everyones secret favorite editor opens up.

Paste this into notepad to get a semi useful profile:

# Keybindings - https://github.com/lzybkr/PSReadLine
if(Get-Module -ListAvailable PSReadline){
    Import-Module PSReadLine
    Write-Verbose "Imported PSReadLine"
    # options
    Set-PSReadlineOption -EditMode Emacs
    Set-PSReadLineOption -HistorySearchCursorMovesToEnd
    # key handlers
    Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
    Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward
    Set-PSReadlineKeyHandler -Key Ctrl+p -Function PreviousHistory
    Set-PSReadlineKeyHandler -Key Ctrl+n -Function NextHistory
    Set-PSREadlinekeyhandler -Chord Ctrl+Shift+h -Function WhatIsKey
    # capture screen, really just highlight current line
    Set-PSReadlineKeyHandler -Chord 'Ctrl+X,Ctrl+S' -Function CaptureScreen
    # move by word
    Set-PSReadlineKeyHandler -Key Alt+D -Function ShellKillWord
    Set-PSReadlineKeyHandler -Key Ctrl+Backspace -Function ShellBackwardKillWord
    Set-PSReadlineKeyHandler -Key Alt+B -Function ShellBackwardWord
    Set-PSReadlineKeyHandler -Key Alt+F -Function ShellForwardWord
    Set-PSReadlineKeyHandler -Key Shift+Alt+B -Function SelectShellBackwardWord
    Set-PSReadlineKeyHandler -Key Shift+Alt+F -Function SelectShellForwardWord
    Write-Verbose "Set PSReadLine prefs"
}

# PSColors - https://github.com/Davlind/PSColor
if(Get-Module -ListAvailable PSColor){
    Import-Module PSColor
    Write-Verbose "Imported PSColor"
}

# Chef - https://github.com/chef/chef/blob/master/distro/powershell/chef/chef.psm1
if(Get-Module -ListAvailable chef){
    Import-Module chef -DisableNameChecking
    Write-Verbose "Imported chef"
    chef shell-init powershell|iex
    Write-Verbose "Ran chef shell initialization"
}

# Posh-Git - https://github.com/dahlbyk/posh-git
if(get-module -listavailable posh-git){
    Import-Module posh-git
    Write-Verbose "Imported posh-git"
    . (join-path $(Get-Module -listavailable posh-git).ModuleBase 'profile.example.ps1')
    Write-Verbose "Sourced posh git example profile"
    Start-SShAgent -Quiet
    Write-Verbose "Started ssh-agent"
}

# SSH Agent
if(get-command -ea 0 ssh-add){
    Write-Verbose "Running ssh-add for default keys"
    if((ssh-add -l) -eq 'The agent has no identities') {
        ls $HOME\.ssh\id* -Exclude "*.pub"|ForEach-Object{ssh-add $_}
    }
}

# Z autojump - https://github.com/vincpa/z
if(get-module -listavailable z){
    Import-Module z
    Write-Verbose "Imported z"
}

# Bash style: cd -
function bashCD {
    if ($args[0] -eq '-') {
        $pwd=$OLDPWD;
    } else {
        $pwd=$args[0];
    }

    $tmp=Get-Location;

    if ($pwd) {
        cdX $pwd;
    }

    Set-Variable -Name OLDPWD -Value $tmp -Scope global;

    if($global:DIRENV) {
        Load-Direnv
    }
}

if((get-command cd).CommandType -eq 'Alias'){
    remove-item alias:cd
}
Set-Item alias:cd -value 'bashCD'

# make this behave like linux
function which {
    param([string]$command)
    (get-command $command).path
}

# git
function g { git $Args }
function gpo { git push origin HEAD }
function gpu { git pull }
function gst { git status }
function gap { git add -p }

Close and relaunch powershell as admin to install some stuff with choco

choco install consolez -y
choco install git -y
choco install emacs64 -y
choco install googlechrome -y
choco install hab -y

Details

Some explanations for the above

Powershell first steps

Since most of the later steps are run from a Powershell prompt, a few basic setup steps for Powershell help first. When installing or updating software, run powershell as an Admin.

Powershell is definitely the go to shell to use. All that crippled cmd stuff can just be forgotten. All cmdlets have a pretty discoverable Verb-Noun syntax that makes it reasonable easy to start finding the commands you want right away. I usually start by searching for something using Get-Command, like: Get-Command -verb Set or Get-Command -noun Help

Update help

If you are actually used to using man pages you'll find Powershell has a decent set of builtin documentation but it helps to keep it up to date.

Update-Help

Execution Policy

Execution policies seem to be an attempt at providing some security policy with Powershell. All you really need to know for now is:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

Package management

Package management for Windows is actually improving. There's at least two aspects, 3rd party software handled most easily with Chocolatey and add on Powershell modules which can greatly improve on the out of box Powershell experience.

There are a number of Package Management commands to explore. These use a pluggable provider based approach to extend what types of packages can be installed.

One dependency of this tooling is nuget, which can be bootstrapped easily by running:

Find-PackageProvider

The provider 'nuget v2.8.5.204' is not installed.
nuget may be manually downloaded from
https://oneget.org/Microsoft.PackageManagement.NuGetProvider-2.8.5.204.dll and installed.
Would you like PackageManagement to automatically download and install 'nuget' now?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): Y

The specific nuget version may be different depending on the point release. Using this command with -ForceBootstrap option will script the prompt

Add on Powershell modules

It is easiest to install modules using the package management commands. Of course it's up to you to determine if you trust anything coming from the Powershell Gallery.

C:\> Find-Module PSReadLine

Version    Name                                Repository           Description
-------    ----                                ----------           -----------
1.2        PSReadline                          PSGallery            Great command line editing in the PowerShell console host

Then you can use Find-Module to search by name and Install-Module to install. These are the modules I always need:

Install-Module PSReadLine -Force
Install-Module posh-git -Force
Install-Module z -Force
Install-Module PSColor -Force

-Force again just bypasses the prompt.

Chocolatey

Chocolatey is a package manager for Windows.

First we do the Windows equivalent of curl|bash, taken from here:

iwr https://chocolatey.org/install.ps1 -UseBasicParsing | iex

Note: Some commands have short names, in this case Invoke-WebRequest and Invoke-Expression

When complete you should have a new choco command. You might need to launch a new powershell window for the $env:PATH settings to take effect.

Useful Software

My minimum useful 3rd party software these days

choco install consolez -y
choco install git -y
choco install emacs64 -y
choco install googlechrome -y
choco install hab -y

Chef Development Kit

On Windows the Chef Development Kit provides all the Ruby I need to get my work done.

iwr -usebasic https://omnitruck.chef.io/install.ps1 | iex; install chefdk

Powershell Profile

The Powershell profile lives at C:\Users\NAME\MyDocs\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 by default, the easiest way to start one is with:

New-Item -Type File -Force $PROFILE
notepad $PROFILE

Now to make use of all the modules we installed earlier. Add the following to your profile. It will safely include the available modules, initializing them if needed with a basic configuration. There's also some very minor helper functions near the end for some aliases..

# Keybindings - https://github.com/lzybkr/PSReadLine
if(Get-Module -ListAvailable PSReadline){
    Import-Module PSReadLine
    Write-Verbose "Imported PSReadLine"
    # options
    Set-PSReadlineOption -EditMode Emacs
    Set-PSReadLineOption -HistorySearchCursorMovesToEnd
    # key handlers
    Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
    Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward
    Set-PSReadlineKeyHandler -Key Ctrl+p -Function PreviousHistory
    Set-PSReadlineKeyHandler -Key Ctrl+n -Function NextHistory
    Set-PSREadlinekeyhandler -Chord Ctrl+Shift+h -Function WhatIsKey
    # capture screen
    Set-PSReadlineKeyHandler -Chord 'Ctrl+X,Ctrl+S' -Function CaptureScreen
    # move by word
    Set-PSReadlineKeyHandler -Key Alt+D -Function ShellKillWord
    Set-PSReadlineKeyHandler -Key Ctrl+Backspace -Function ShellBackwardKillWord
    Set-PSReadlineKeyHandler -Key Alt+B -Function ShellBackwardWord
    Set-PSReadlineKeyHandler -Key Alt+F -Function ShellForwardWord
    Set-PSReadlineKeyHandler -Key Shift+Alt+B -Function SelectShellBackwardWord
    Set-PSReadlineKeyHandler -Key Shift+Alt+F -Function SelectShellForwardWord
    Write-Verbose "Set PSReadLine prefs"
}

# PSColors - https://github.com/Davlind/PSColor
if(Get-Module -ListAvailable PSColor){
    Import-Module PSColor
    Write-Verbose "Imported PSColor"
}

# Chef - https://github.com/chef/chef/blob/master/distro/powershell/chef/chef.psm1
if(Get-Module -ListAvailable chef){
    Import-Module chef -DisableNameChecking
    Write-Verbose "Imported chef"
    chef shell-init powershell|iex
    Write-Verbose "Ran chef shell initialization"
}

# Posh-Git - https://github.com/dahlbyk/posh-git
if(get-module -listavailable posh-git){
    Import-Module posh-git
    Write-Verbose "Imported posh-git"
    . (join-path $(Get-Module -listavailable posh-git).ModuleBase 'profile.example.ps1')
    Write-Verbose "Sourced posh git example profile"
    Start-SShAgent -Quiet
    Write-Verbose "Started ssh-agent"
}

# SSH Agent
if(get-command -ea 0 ssh-add){
    Write-Verbose "Running ssh-add for default keys"
    if((ssh-add -l) -eq 'The agent has no identities') {
        ls $HOME\.ssh\id* -Exclude "*.pub"|ForEach-Object{ssh-add $_}
    }
}

# Z autojump - https://github.com/vincpa/z
if(get-module -listavailable z){
    Import-Module z
    Write-Verbose "Imported z"
}

# Bash style: cd -
function bashCD {
    if ($args[0] -eq '-') {
        $pwd=$OLDPWD;
    } else {
        $pwd=$args[0];
    }

    $tmp=Get-Location;

    if ($pwd) {
        cdX $pwd;
    }

    Set-Variable -Name OLDPWD -Value $tmp -Scope global;

    if($global:DIRENV) {
        Load-Direnv
    }
}

if((get-command cd).CommandType -eq 'Alias'){
    remove-item alias:cd
}
Set-Item alias:cd -value 'bashCD'

# make this behave like linux
function which {
    param([string]$command)
    (get-command $command).path
}

# git
function g { git $Args }
function gpo { git push origin HEAD }
function gpu { git pull }
function gst { git status }
function gap { git add -p }

Bonus level: Tiling WM

If you're one of those tiling WM folks (like me) bug.n does a pretty great job on Windows, but may not live up to XMonad or i3.

It's written using AutoHotkey and uses an ini based config format stored in your Roaming profile.

Here's mine:

Config_fontSize=8

;;; Statusbar
Config_readinCpu=0
Config_readinBat=1
Config_readinMemoryUsage=0
Config_readinDiskLoad=0
Config_readinVolume=0
Config_readinInterval=10000
Config_readinDateFormat=yyyy-MM-dd ddd

;;; Colors
;; Dark theme
;; <view>;<layout>;<title>;<shebang>;<time>;<date>;<anyText>;<batteryStatus>;<volumeLevel>
Config_backColor_#1=101010;603000;Black;603000;Black;603000;000060;76D7C4;080808
Config_backColor_#2=808080;;;;;;;202020;080808
Config_backColor_#3=;;;;;;;ff8040;
Config_foreColor_#1=404040;101010;Black;101010;Black;101010;Black;76D7C4;202020
Config_foreColor_#2=4040ff;;;;;;;0000ff;0000ff
Config_foreColor_#3=;;;;;;;010101;
Config_fontColor_#1=White;White;White;White;White;White;White;Black;808080
Config_fontColor_#2=Black;;;;;;;White;White
Config_fontColor_#3=;;;;;;;Black;

;;; Solarized light theme
; Config_backColor_#1=eee8d5;eee8d5;eee8d5;eee8d5;eee8d5;eee8d5;eee8d5;eee8d5;eee8d5
; Config_backColor_#2=073642;;;;;;;eee8d5;eee8d5
; Config_backColor_#3=;;;;;;;eee8d5;
; Config_foreColor_#1=268bd2;eee8d5;eee8d5;eee8d5;eee8d5;eee8d5;eee8d5;268bd2;073642
; Config_foreColor_#2=d33682;;;;;;;073642;073642
; Config_foreColor_#3=;;;;;;;d33682;
; Config_fontColor_#1=93a1a1;93a1a1;93a1a1;93a1a1;93a1a1;93a1a1;93a1a1;93a1a1;93a1a1
; Config_fontColor_#2=93a1a1;93a1a1;93a1a1;93a1a1;93a1a1;93a1a1;93a1a1;93a1a1;93a1a1
; Config_fontColor_#3=;;;;;;;d33682;

;; Window Management - mostly defaults
Config_hotkey=#j::View_activateWindow(0, +1)
Config_hotkey=#k::View_activateWindow(0, -1)
Config_hotkey=#+j::View_shuffleWindow(0, +1)
Config_hotkey=#+k::View_shuffleWindow(0, -1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment