Prof. Powershell

Working with Values and Variables in PowerShell

One object or many, PowerShell hands you control. This week's tip is a good example.

If you've been following me for any length of time you have probably heard me mention that PowerShell is all about the objects. Working with objects in the pipeline is what makes PowerShell such an awesome automation engine. But sometimes, we need to work with a single object and even then sometimes just a single property of that object. It can be tricky for PowerShell protégés to figure this out.

Let's say you've retrieved a service object and saved it to a variable:

PS C:\> $s=get-service bits

To display just the displayname, you can easily access it by the property name:

PS C:\> $s.DisplayName
Background Intelligent Transfer Service

A problem you can run into is when you want to include that property, say, in a message. Your first inclination might be something like this:

PS C:\> Write-Host "Analyzing $s.displayname" -foreground Green
Analyzing System.ServiceProcess.ServiceController.displayname

Hardly the result you were expecting. There are several ways you could fix this. You could create a separate variable:

PS C:\> $display=$s.DisplayName
PS C:\> Write-Host "Analyzing $display" -Foreground Green
Analyzing Background Intelligent Transfer Service

You might use the -f operator, which is a great way for really complex messages:

PS C:\> $msg="Analyzing {0}" -f $s.DisplayName
PS C:\> Write-Host $msg -Foreground Green
Analyzing Background Intelligent Transfer Service

Or you can use a sub-expression:

PS C:\> Write-Host "Analyzing $($s.displayname)" -foreground Green
Analyzing Background Intelligent Transfer Service

The sub-expression wraps the object, $s.displayname, in a set of parentheses which tells PowerShell to evaluate the expression. The $ in front of the parentheses then tells PowerShell to treat the whole thing as a variable, so that variable expansion works.

These techniques work fine for building strings based on individual object properties. Here's another variable value scenario:

PS C:\> get-process | sort Workingset | select -last 1 path

Path
----
C:\Users\Jeff\AppData\Local\Google\Chrome\Application\chrome.exe

But what I really want is to save just the path to a variable.

PS C:\> $proc=get-process | sort Workingset | select -last 1 path
PS C:\> get-item $proc
get-item : Cannot find drive. A drive with the name '@{Path=C' does not exist.
At line:1 char:9
+ get-item <<<< $proc
  + CategoryInfo : ObjectNotFound:
    (@{Path=C:String) [Get-Item], DriveNotFoundException
  + FullyQualifiedErrorId :
    DriveNotFound,Microsoft.PowerShell.Commands.GetItemCommand

Why didn't that work? Well, look at $proc:

PS C:\> $proc

Handles  NPM(K)   PM(K)   WS(K)  VM(M)  CPU(s)    Id ProcessName
-------  ------   -----   -----  -----  ------    -- -----------
    131      24  111196  112544    253  444.96  2544 chrome

I actually have the full object. Knowing this, I could get by with:

PS C:\> get-item $proc.path

Directory: C:\Users\Jeff\AppData\Local\Google\Chrome\Application

Mode          LastWriteTime    Length  Name
----          -------------    ------  ----
-a---    8/29/2012 10:58 PM   1229848  chrome.exe

Or if I truly want just the path property, I can use the -ExpandProperty parameter with Select-Object. This has the effect of retrieving the value only:

PS C:\> $proc=get-process | sort Workingset | select -last 1 -ExpandProperty Path
PS C:\> $proc

C:\Users\Jeff\AppData\Local\Google\Chrome\Application

Note that you can only use ExpandProperty on a single property. But this is a great way to build an array of values from a set of object properties:

PS C:\> $procpaths=get-process | where {$_.path} | select -ExpandProperty Path -Unique

The array, $procpaths, is now a collection of strings which makes it easier to do something like this:

PS C:\> $procpaths | group {Split-Path $_} | Select -expand name | out-file c:\work\procpathparents.txt

Ideally, you will be using PowerShell cmdlets to work with objects and their properties in bulk, but should the need arise to give values and variables some special care, these are the techniques I suggest.

About the Author

Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.

comments powered by Disqus
Most   Popular