I joined my third Windows project as a consultant in May 2014. Over the past five years I’ve become more dependent on shell. While many folks seem content to mouse their way around Windows or jump to cygwin, I found PowerShell capable of doing just about everything I needed to. Here is my guide to Useful PowerShell.
The Basics
Everything in PowerShell follows the same ‘Verb-Noun’ convention. Many common
commandlets are also aliased to their unix equivalents. For example,
Get-ChildItem
is aliased to ls
. If you’re interested in the aliases of a
known command, you can use Get-Alias
.
# known command
Get-Alias -Definition Get-ChildItem
# all defined aliases
Get-Alias
The Get-Help
commandlet is one of the most useful, especially if you prefer to
learn by example.
Get-Help Get-ChildItem -Examples
Everything native to PowerShell can tab-complete, including parameters. The
verbosity is not as bad as it seems. When it comes to reading scripts, it’s
actually kind of nice to get that clarity. It’s also a surefire laugh for folks
with unix shell backgrounds and a sense of humor. After all, who needs touch
when you have New-Item -Type File
?
The environment variable syntax is often confusing for new folks. We have access
to all of .NET, so there are multiple ways to get this done, but the easiest way
I’ve found is to just stick a $env:
on the front.
# Add something to the PATH for the current session only
$env:PATH += ";c:\tools\bin"
# show all environment variables, note there is no '$' and the ':' is required
Get-ChildItem env:
# using familiar aliases
ls env:
The Profile
It’s easy to customize bash by popping open ~/.bashrc
and proceeding to define
functions, choose the folder to start in, set environment variables, or
anything. PowerShell has the same thing going on, but it’s slightly more
difficult to get going.
PowerShell’s profile is at a really long path in a folder that doesn’t exist by default. To create a brand new profile on your system, you’ll first need to create it.
New-Item -Path $Profile -Type File -Force
This is nice because none of the directories have to exist before the command is
run. It reminds me of mkdir -p
on unix, and indeed behaves exactly the same
way for -Type Directory
.
After you have the profile created, you can edit it with any text editor on your system.
notepad $Profile
Any valid PowerShell command will be executed when the shell loads. This is
where I cd
into my code directory and define a few useful functions.
Useful Commands
These are some things I used just about every day.
tail
Get-Content myfile.log -Wait
find
# Where is git installed?
$results = Get-ChildItem -Path C:\ -Filter git.exe -Recurse -ErrorAction SilentlyContinue
$git = $results | % { $_.Directory } | Select-Object -First 1
Note: appending -ErrorAction SilentlyContinue
is not necessary, but often
produces better output. PowerShell will fill the screen with red errors when
searching folders the current user doesn’t have access to.
pbcopy
Useful for copying output from the command line. pbcopy is actually mac-specific, but similar tools exist for unix.
Get-Content '.\version.txt' | clip.exe
Previously Covered
Look Out!
Dot-separated properties do not work the same in PowerShell as cmd.exe. For
example, if you had a deploy task whose default http.port
could be overridden,
you’d find that this worked great in cmd.exe and failed silently in PowerShell.
ant deploy -Dhttp.port=8888
This can be dangerous when it is not immediately obvious the value wasn’t taken. To get the same thing working in PowerShell, you’d need to quote the entire define.
ant deploy -D'http.port=8888'
Importantly this is only for dot-separated properties, which are very common in ant. If your project has properties defined with hyphens (http-port), camelCase (httpPort), or most any other way, it’ll work without quotes in both PowerShell and cmd.exe.
Wrapping Up
I had a good time picking up a new skill set while in Windows. I still prefer unix, but it’s nice to know many of the tools I’ve come to depend on have native Windows equivalents. We were able to script lots of tasks that were formerly drag-and-drop with a tool that just worked on every machine. This saved us a ton of time over the course of a year.