Why Doesn’t My Pipeline Work?

talkbubble I saw a little discussion thread on Twitter this morning which I felt needed a little more room to explain. Plus since we’re in ScriptingGames season beginners might like a few pointers. I always talk about PowerShell, objects and the pipeline. But sometimes what looks like a pipelined expression in the PowerShell ISE doesn’t behave the way you might expect.

Here’s an example.

If you run this, you’ll see numbers 1 to 5 written to the pipeline. But if you try something like this it will fail.

You’ll get an error about an empty pipe. In fact, in the PowerShell ISE you’ll get a red squiggle under the | indicating this is not going to work. That’s because PowerShell isn’t writing to pipeline at the end of the scriptblock, but rather within in. Another way to think about it is at the While operator is not a cmdlet so the only thing writing objects to the pipeline is whatever commands are within the While loop.

What you can do is something like this:

Here, I’m capturing the pipeline output from the scriptblock and saving it to a variable. Then I have objects I can use. Or if you wanted to be clever, you could use a subexpression.

This same behavior also applies to Do and the ForEach enumerator. The latter trips people up all the time.

You think you’ll get the output of ForEach saved to the file, but you’ll run into the empty pipeline again. You could use a variable and then pipe the variable to the file or use a subexpression. Even better, use a pipelined expression.

Here I’m using the cmdlet ForEach-Object, which unfortunately has an alias of ForEach which confuses PowerShell beginners. So don’t assume that just because you see a set of { } that you get pipelined output. Remember, cmdlets write objects to the pipeline, not operators.

TechDays SF Presentations

TechDays_logo250 Last week I presented a number of sessions at TechDays in beautiful San Francisco. Met some great people and had a great time. I presented 4 talks, almost all of them PowerShell-related. Actually, they all had some type of PowerShell content. I’m happy to share my session slides and PowerShell demonstrations. Most of the demonstrations are not full-blown scripts but command examples, except for those things labeled as functions. If you did not attend TechDays, you are still welcome to download the material, although without the context of the live presentation some of it may not make sense. I hope you can make it next time.

File and Folders with Powershell 3
If you manage file servers and aren’t using PowerShell, you are working much too hard. Or if you are using PowerShell v2 you are still working pretty hard. Fortunately PowerShell v3 along with Windows 8 and Windows Server 2012 offer a much better solution. This session will demonstrate how to provision and manage folders, files and file shares using PowerShell from a Windows 8 client. With a little up-front work, you ‘ll be able to create provisioning scripts to deploy a new file share in seconds.

10 PowerShell mistakes, trip-ups and traps
Windows PowerShell is a language and management technology that many IT professionals, including developers, think they understand. Yet very often they get caught up in pre-conceptions and misinterpretations, usually based on prior experience with scripting or development. This session will explore the 10 most common mistakes and traps that people fall into with PowerShell and how to avoid them.

Troubleshooting Active Directory with PowerShell
Active Directory is one of those technologies that when it works, nobody notices. But when it doesn’t work, everyone does. Fortunately, Windows PowerShell and Windows Server 2012 make a terrific troubleshooting tool. In this session we’ll look at some common Active Directory problems, how to diagnose them and in some cases resolve, all with Windows PowerShell.

Building a Windows 8 Hyper-V lab
We all know the benefits of testing in a non-production environment. But sometimes resources are limited and having a test setup seems like a lot of work. But now that Windows 8 includes Hyper-V, you can setup a lab environment in very little time. This session will guide you through setting up a Hyper-V based test lab and how to get the most out of it using the PowerShell management tools.

If you didn’t catch me in San Francisco, I’ll be at TechMentor this fall in Las Vegas. More on that later. There’s a chance I’ll be back to the West coast later this year for more PowerShell goodness. Keep an eye on the blog for announcments. Or if your company is looking for training, let’s talk.

PowerShell PopUp

popupAt the recent PowerShell Summit I presented a session on adding graphical elements to your script without the need for WinForms or WPF. One of the items I demonstrated is a graphical popup that can either require the user to click a button or automatically dismiss after a set time period. If this sounds familiar, yes, it is our old friend VBScript and the Popup method of the Wscript.Shell object. Because PowerShell can create and use COM objects, why not take advantage of this?

All it really takes is two lines. One line to create the Wscript.Shell COM object and one to invoke the Popup method.ย ย (Yes, I’m sure you could do this in one line, but that’s not the point.)

The Popup method needs parameters for the message, title, a timeout value, and an integer value that represents a combination of buttons and icons.

popup2The challenging part has always been trying to remember the integer values. So I wrote a quick function called New-Popup.

The function lets you use text descriptions for the buttons and icons. In PowerShell 3.0 you will also get tab completion for the possible values. This makes it easy to create a command like this:

The function writes the value of the clicked button to the pipeline. I expect this is something you are more apt to use in a script. Perhaps to display an error message or even to prompt the user for an action. Maybe you’d like to use it in your PowerShell 3.0 profile:

The popup will automatically dismiss after 5 seconds unless I click Yes or No. You should be able to copy the function text from the listing above by toggling to plain code, select all and copy.

I hope you’ll let me know where you use this.

PowerShell Summit 2013 Kicks Off

I’m very excited to be in Redmond for a few days as part of the PowerShell Summit. I love catching up with old friends and making new ones all over PowerShell. If you couldn’t make it this year, and I know many of you will feel you are missing out, there’s always next year. We are making plans to accommodate more people in 2014.

I’ll also be trying to tweet and blog what I can over the next few days.

Friday Fun PowerShell Commands by Noun

One of PowerShell’s greatest strength’s is discoverability. Once you know how, it is very easy to discover what ย you can do with PowerShell and how. One reason this works is because PowerShell commands follow a consistent verb-noun naming convention. With this in mind, you can see all of the commands organized by noun.

This will work in both v2 and v3.

get-command-noun-01In PowerShell 3.0, this will display commands from all modules, even those not currently loaded. If you want to limit your display to only those modules currently imported use this:

Or you can use this same idea to organize cmdlets in a specific module.

get-command-noun-02Now that you know what you can do, go forth and do it!

Friday Fun: Get-Anniversary

Recently I celebrated a wedding anniversary. Even though I didn’t forget I could have used a little help. So I figured since I’m in PowerShell all the time anyway, it could help. I built a little script to remind me of important dates. Let me walk you through the key steps.

First, I’ll define a variable for the anniversary date.

I picked a date coming up. Next, it isn’t too difficult to calculate the number of days between two dates. But what I needed to do is find May 6th for this year. Here’s how I did it:

$thisYear is now May 6, 2013. Excellent, because now I can get the number of days until that date.

$when is a TimeSpan object.

I can use the Days property in my message. Although the other item of information I wanted is the number of years for the anniversary. Very important. Again, because we’re working with objects all I need to do is subtract the Year properties between the anniversary date and today.

At this point I could simply display a message that tells me how many days are remaining until anniversary #X. But let’s go a step further. How about displaying the number of years as an ordinal? For example, 5th or 23rd anniversary. To do that I did a quick search to see if someone had already figured this out, since there is no .NET specific method to accomplish this. I found some code samples and converted them into a PowerShell function.

Basically you take the number and perform a modulo operation. Based on the result I know what suffix to use and the function writes the ordinal string to the pipeline, like 1st or 7th. ย With that, all that is left to do is display my message.

Let me show you the complete script.

The only other special feature of this script is that if the number of days is greater than one, the message is display using Write-Host in green.

get-anniversary

BUT, if you are down to 1 day or less you get the message in red AND your browser will open up to a Google search for Florists. I’m trying to help you out as much as I can. You could call this script from your PowerShell profile and (hopefully) never forget another anniversary or important date. Or you might simply take away some tidbits about datetime objects, timespans and splatting. Either way I think you come out ahead.

Enjoy.

UPDATE April 16, 2013
I realized my original code had a problem: if the anniversary date was next year you would get a negative result. For example if the anniversary was yesterday, the script would say your anniversary was in -1 days. That won’t work. So I added some code to test the anniversary date compared to the current date. If it is less than today, meaning it has already passed, then I need to add a year.

Now when I calculate the difference between $thisYear and today, I’ll get a positive number. I suppose I should rename the variables because $thisYear, in this case, is actually the date for the anniversary next year. I’m also incrementing the value of the number of years is updated.

The other thing to take away from this, and something that I neglected to do (shame on me) is to test based on data that will fail as well as succeed. For this script, I neglected to test for dates that have already passed.

Get CIMInstance from PowerShell 2.0

I love the new CIM cmdlets in PowerShell 3.0. Querying WMI is a little faster because the CIM cmdlets query WMI using the WSMAN protocol instead of DCOM. The catch is that remote computers must be running PowerShell 3 which includes the latest version of the WSMAN protocol and the WinRM service. But if your computers are running 3.0 then you can simply run a command like this:

However, if one of the computers is running PowerShell 2.0, you’ll get an error.

get-ciminstance-error

In this example, CHI-DC02 is not running PowerShell 3.0. The solution is to create a CIMSession using a CIMSessionOption for DCOM.

get-ciminstance-dcom

So there is a workaround, but you have to know ahead of time which computers are not running PowerShell 3.0. When you use Get-CimInstance and specify a computername, the cmdlet setups up a temporary CIMSession. So why not create the temporary CIMSession with the DCOM option if it is needed? So I wrote a “wrapper” function called Get-MyCimInstance to do just that.

The heart of the function is a nested function to test if a remote computer is running WSMAN 3.0.

The function uses Test-WSMan and a regular expression to get the remoting version. If it is 3.0 the function returns True. In Get-MyCIMInstance I test each computer and if not running 3.0, create the CIMSession option and include it when creating the temporary CIMSession.

I’m using a Try/Catch block because if the computer is offline, my test function will throw an exception which I can catch.

Otherwise, all is good and ย I can pass the rest of the parameters to Get-CimInstance.

At the end of the process, I remove the temporary CIMSession. With this, now I can query both v2 and v3 computers.
get-myciminstance01
Notice for CHI-DC02 I’m creating the DCOM option. Here’s the command without all the verboseness.
get-myciminstance02
I could have created a proxy function for Get-CimInstance, but not only are they more complicated, I didn’t want that much transparency. I wanted to know that I’m querying using my function and not Get-CimInstance. Here’s the complete script.

I hope you’ll let me know what you think and if you find this useful.

UPDATE: I’ve revised this script and article since it’s original posting to better handle errors if you can’t test WSMAN. I also added support for alternate credentials, which is something you can’t do with Get-CimInstance.