Powershell Profile Snippets

30 November 2013

I have an admission to make - I’ve been a command line junkie for a long time now. When PowerShell first came along I had a healthy skepticism about how much care and feeding it would enjoy in the Windows GUI landscape. I said a couple of things to myself:

I’m so happy any doubts were proved unfounded and I haven’t ever looked back.

Since those early days of v1.0, PowerShell has grown into a mature and robust command line ecosystem. I find that it’s now an essential tool to get the job done. Batch files don’t cut it any longer for someone like me at the intersection of development and administration.

If you develop software or automate tasks on the Windows platform and haven’t tried it yet, go for it! The Windows PowerShell Survival Guide has just about every resource you could need to dive in.


Customising My Profile

No shell is perfect without a little customisation. I wouldn’t recommended using these snippets within PowerShell script files, but they do make the interactive experience much more pleasant.

Add these functions and aliases to your PowerShell profile if they look useful.

Filtering

These two functions quickly filter files or folders. More generally, they filter containers, which means that they will work the same way in the file system provider as they do in other providers (e.g. IIS:\ and SQLSERVER:\ drives from the WebAdministration and SQLPS modules respectively).

Since PowerShell v3, the Get-ChildItem (ls) cmdlet has -file and -directory switches so these functions aren’t as helpful as they once were, but when I’m thinking in terms of pipelines they’re still useful.

function Where-Container($Input) { 
    $Input | Where-Object {$_.PsIsContainer} 
}

function Where-NotContainer($Input) {
    $Input | Where-Object {-not $_.PsIsContainer}
}

Set-Alias whc Where-Container
Set-Alias whnc Where-NotContainer

e.g. Listing all folders, then all files:

>% ls C:\ | whc

Directory: C:\

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         9/02/2013     23:30            inetpub
d-r--        26/11/2013     18:00            Program Files
d-r--        29/11/2013     21:45            Program Files (x86)
d----        27/11/2013     22:27            Tools
d-r--        23/02/2013     23:33            Users
d----        24/11/2013     21:29            Windows


>% ls C:\ | whnc

Directory: C:\

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         7/10/2012     00:00       1024 .rnd

Selecting and Grouping

Sometimes I only want a small sample of the pipeline or quickly get the aggregation value of some property. The Measure-Object and Group-Object cmdlets are always available for complex scenarios, but these function cover some common use cases.

function Select-First([int] $n=10) {
    $Input | Select-Object -first $n
}

function Sum-Object([string] $property) {
    ($Input | Measure-Object $property -sum).Sum
}

function Count-Object($Input) {
	($Input | Measure-Object).Count
}

Set-Alias sf Select-First
Set-Alias sum Sum-Object
Set-Alias count Count-Object

e.g. Using Get-Process (ps), find the Top 3 processes by working memory. How much are they using in total? How many Chrome processes are running?

>% $p = ps | sort WorkingSet64 -desc | sf 3
>% $p | select Name,WorkingSet64 | ft

Name     WorkingSet64
----     ------------
sqlservr    233582592
chrome      185348096
chrome       80498688


>% $p | sum WorkingSet64
499429376

>% ps | where Name -eq 'chrome' | count
21

A few years ago it was sad to see the Google Desktop product shelved. The Ctrl-Ctrl hotkey was a tough habit to break. Now there’s quick Googling from the command line!

function Search-Google()
{
    $query = [System.Uri]::EscapeDataString($args);
    $url = "http://www.google.com/search?q=$query";
    start $url
}

function Search-GoogleLucky()
{
    $query = [System.Uri]::EscapeDataString($args); 
    $url = "http://www.google.com/search?q=$query&btnI=1"; 
    start $url
}

Set-Alias gg Search-Google
Set-Alias ggl Search-GoogleLucky

e.g.

>% ggl tagged powershell site:stackoverflow.com

Environment

My profile is used on a number of machines, some 32-bit, others 64-bit. I find that it’s useful to print a message when the session starts to indicate whether the 32 or 64 bit PowerShell executable has been launched.

function Get-CpuArch {
    $arch = if($env:Processor_Architecture -like '*64*') {'x64'} else {'x86'}
    Write-Output "Windows PowerShell ($arch)"
}
Write-Host (Get-CpuArch)

In addition to architecture portability some legacy snap-ins I use only support 32-bit PowerShell, or they may not be installed at all. They’re loaded on demand and only if available, as they’re used relatively infrequently.

# Import Available Snap-Ins
function Import-LegacySnapIns {
	$s = ('Microsoft.TeamFoundation.PowerShell','WebAdministration')
	Get-PsSnapin -registered | 
    	Where-Object { $_.Name -in $s } |
		ForEach-Object { Add-PsSnapin $_.Name }
}

Interactive Prompt

I prefer a minimalist approach to the actual prompt. Displaying the CPU architecture and current directory into the console title is handy as well, though doesn’t always work on non-standard applications hosting the PowerShell runspace:

function Prompt 
{
    if ($host.Name -in ('ConsoleHost','Windows PowerShell ISE Host')) {
        # Put the current directory into the window title
        $host.UI.RawUI.WindowTitle = "$(Get-CpuArch) -  $(Get-Location)"; 
    }
    ">% "
}

 PowerShell


comments powered by Disqus