MCPMag.com

Sign up for our newsletter.

I agree to this site's Privacy Policy.

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 a Microsoft MVP in Windows PowerShell, Microsoft Certified Trainer and an IT veteran with over 20 years of experience, much of it spent as an IT consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He works today as an independent author, trainer and consultant. Jeff writes the popular Prof. PowerShell column for MPCMag.com and is a regular contributor to the Petri IT Knowledgebase and 4SysOps. If he isn't writing, then he's most likely recording training videos for companies like TrainSignal or hanging out in the forums at PowerShell.org. Jeff's latest books are Learn PowerShell 3 in a Month of Lunches, Learn PowerShell Toolmaking in a Month of Lunches and PowerShell in Depth: An Administrators Guide. You can keep up with Jeff at his blog http://jdhitsolutions.com/blog, on Twitter at twitter.com/jeffhicks and on Google Plus (http:/gplus.to/JeffHicks)

comments powered by Disqus

Reader Comments:

Sat, Feb 2, 2013 Veronic Buy Lipitor

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.

Fri, Jan 25, 2013 Ytitke Buy Lipitor

Are you trying to crash PowerShell or is there something else you are trying to do?

Fri, Oct 5, 2012 Jeffery Hicks United States

Well then don't do that. :-) Actually on Windows 8 I get an error message that it could destablize the runtime. Are you trying to crash PowerShell or is there something else you are trying to do?

Wed, Oct 3, 2012 Johnny Wild work

Great article but found a way to crash powershell everytime by accident. Using the one of your ps commands: $procpaths=get-process | where {$_.path} | select -ExpandProperty Path -Unique And then this command: $procpaths.Address(1) will crash ps everytime! The is a crlf since this comment does not accept them...

Add Your Comment Now:

Your Name:(optional)
Your Email:(optional)
Your Location:(optional)
Comment:
Please type the letters/numbers you see above