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,
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
Some explanations for the above
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
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 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 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
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 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
andInvoke-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.
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
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
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 }
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)