Major Update to PowerShell Tools for Visual Studio

PowerShell tools for Visual Studio (poshtools) had a major release this month, the culmination of about six months of contributions from Microsoft employees. The highlights include:

  • 64-bit support.
  • Remote sessions.
  • Remote debugging.
  • IntelliSense improvements.

I switched from the Sapien Suite in early 2014 after changing jobs. Getting a new license wouldn’t have been difficult, but I was never thrilled with it and after re-examining the field of PowerShell editors it seemed like poshtools had crossed the “good enough” threshold. Plus I already was covered by a VS license. Score.

The only difficulty I’ve had during this time has been IntelliSense support: It was… particular. I don’t think it ever worked with Ctrl-Space and was instead triggered by - and $. I don’t think parameter hints for functions within a script ever worked. This release has fixed those things. Ctrl-Space works, and it works with script-defined functions and parameters. Hoorah!

If you need a good PowerShell editor, and you’re covered by a VS license or are eligible to use the Community Edition, now is a great time to take another look at poshtools. With a bunch of Microsoft employees making major contributions I expect it will be getting even better and at a much faster pace.

PowerShell Pitfalls

PowerShell has some very valuable features, but it is a mistake to believe that all those skills that you’ve derived from more conventional programming languages will transfer over to PowerShell. There are some pitfalls for the unwary. Michael Sorens warns abut the most common PowerShell pitfalls and explains how to avoid them.

Ashamed to admin that I only caught #4 on my initial read, and I missed #1 because I skimmed Write-Output as Write-Host.

Cheaping Out

While surfing the Reddits today I came across this image:

Purple Screen of Death points to USB Stick

Most likely a failing USB stick boot device. Why do so many IT deployments fall into this trap of making their ultra-expensive highly-available virtualization stacks fall over when a crappy $10 USB stick or SD card dies?

Carve up a tiny partition on your local storage. Carve out a tiny LUN on your SAN for diskless FC/FCoE nodes. Modern servers can usually boot from iSCSI using their onboard NICs. And there’s PXE, tho that can leave you in a really bad place if the vCenter and Auto Deploy servers become unavailable.

The underlying storage doesn’t need to be highly performant, it just needs to be more reliable than a shitty USB/SD device.

I have never and will never deploy VMware on a USB stick. Even my home lab boots from my FC SAN.

PowerShell Pipeline Buffering

Came across an interesting PowerShell question on Stack Overflow today, Powershell piping causes explosive memory usage. The post had a series of external executable commands being piped to each other, like a.exe | b.exe | c.exe, and observed that the executables were not being run simultaneously with each process’s STDOUT going straight to the next process’s to STDIN, but rather everything was being buffered and the executables were being run sequentially.

I posted an answer with some code to demonstrate that PowerShell is buffering STDIN for external processes until STDIN is closed; STDOUT is not buffered, nor is STDIN when native PowerShell commands / scripts are on the right side of the pipeline.

It’s an interesting side-effect of mixing PowerShell with non-PowerShell commands.

Is Write-Host really harmful?

Last January I left the world of scrappy Internet companies to join the Windows Automation team at a Fortune 500 firm. The group was just starting to warm up to PowerShell and one of my first tasks was to give a presentation on what “Good PowerShell” looks like. I took a few scripts we’d been working on and polished them up. Verb-Noun. Get-Help. -WhatIf. Parameterization. Discovering things from the environment instead of asking for them. Embracing the Pipeline. Error handling and using Exceptions. That sorta stuff.

And then I presented. This is how you do things, and this is why you do them. These are choices that I made, and this is why I chose them.

It went over well enough. But. My scripts put a fair amount of output on the console via Write-Host, and someone challenged that. In support of their argument they sent me several links, one of which was Write-Host Considered Harmful. By Jeffrey Snover. The guy responsible for PowerShell.


The meat of Jeffrey’s argument isn’t wrong. Write-Host is problematic in certain circumstances. This is entirely because Write-Host bypasses redirection within PowerShell. There is no way to capture Write-Host output within a single PowerShell session.

The upside is that Write-Host also bypasses the pipeline. So if a script is emitting objects to the pipeline, Write-Host will not stick a bunch of nasty text in the middle of your PSObject nirvana. This code:

Write-Host "Hello World." > .\out.txt

Doesn’t put anything in .\out.txt.

"Hello World." | Write-Host | ForEach-Object { Write-Host "Goodbye World." }
Hello World.

The above code never says Goodbye because Write-Host put nothing on the pipeline. This pattern is absolutely a misuse of Write-Host, and if you do that you will quickly discover your mistake and correct it.

Now, what happens when a function is called that uses Write-Host and returns objects?

function n { 
     Write-Host "Helpful Message."
     return "Useful Object." 

n | ForEach-Object { Write-Host ("Pipeline Received: " + $PSItem) }
Helpful Message.
Pipeline Received: Useful Object.

As we’ve already covered, Write-Host output doesn’t pollute the pipeline with text, so the pipeline has my Useful Object while the console got a Helpful Message. What’s wrong with that? Jeffrey says everything. I say it’s fine for nearly all use cases.

Neither of us are wrong.

To really understand Jeffrey’s position you need to read his original Monad Manifesto. In the traditional command-line world, when you write something like a | b | c, all of those subsequent steps are reading one program’s text output to find the information you need and do something useful with it. Sed, grep, regular expressions. Your local *nix geek loves these tools and does wonderful things with them, but in Jeffrey’s words acting on unstructured text is “clumsy, lossy, imprecise.” It would be much better if a could output its objects directly to b and c. That’s what PowerShell (Monad) delivered.

Jeffrey wants your scripts to emit objects and not fall back into the world of consuming unstructured text. A noble cause.

But Write-Host doesn’t produce text that other PowerShell scripts can consume.

And if your PowerShell scripts are being called by something that flattens Write-Host‘s output into STDOUT along with everything else, guess what? You’ve left the realm of objects and are back to unstructured text, Write-Host or not.

Now, I do believe that Write-Host should only be used in one place: the body of a script that is meant to be invoked by itself or as the final stage of a pipeline.

I don’t use Write-Host in modules, scripts meant to be dot-sourced, or functions within a stand-alone a script. My reasoning for this is that functions are intended to be called by other PowerShell scripts or commands and writing to the console should be purely the domain of the caller. My functions return objects, Throw errors, and use Write-Verbose, Write-Warning, Write-Debug, and Write-Progress for other information that might be useful.

When I’m writing a script that isn’t going to emit objects, because it’s being invoked by an automation system that can’t use them or by a person to perform a complex process, Write-Host is a perfectly reasonable thing to use, and I’m not going to apologize for it. Not even to Jeffrey “I invented PowerShell” Snover.

foreach ($i in $null)

It took me a long time to warm up to PowerShell. In the early days my team was writing scripts that had to run on Windows 2003, Windows 2003 R2, Windows 2008, and WinPE 2.x. Our tools of choice followed my Scripture of the Least Common Denominator:

  • Thou shalt write Batch.
  • Thou may write C# when warranted, but never VB.Net, and never for WinPE.
  • Thou may write VBscript when Batch is proveably insufficient and C# is too much.
  • Thou may use AutoIT as the tool of last resort.

We wrote a lot of Batch. A little C# here and there. A few VBscripts to handle complex logic. And I think we weaned ourselves down to one or two AutoIT scripts to deal with “silent installs” that weren’t entirely silent. But eventually I needed to do something that only PowerShell could do: manipulate a bunch of VMware VMs in order to completely automate our system image creation process. With a couple weeks development effort I took a process that was a painful burden for my team and made it something that anyone could kick off with a single command and have results within hours. Thus began my love of PowerShell. I left that team and came back. Went to another company, and another still. PowerShell has been a key tool along the way. What has pained me for years is that, despite the fact that PowerShell now runs everywhere, including WinPE, and while Microsoft has heavily invested in supporting PS automation, to the point that some configurations don’t even have GUIs… PowerShell has still not achieved Least Common Denominator status because feature support is so fragmented. PowerShell v3 introduced lots of great features, but dropped Windows 2003 support. At the time there was a lot of Windows 2003 still out there and even now I still have some in my current environment. PowerShell v4 dropped Windows 2008 pre-R2. And now PowerShell v5 is coming with no Windows 2008 R2 support. Know what I have very little of? Yeah, Windows 2012. I love it, don’t get me wrong, but the corporate world moves slowly. Windows 2008 R2 is the workhorse of my current environment. And sadly, many of those servers still don’t even have PowerShell v3. I try to carefully avoid writing code on my workstation that uses v3+ features that aren’t available on my servers but there are many Gotchas waiting to get you. Which brings me to the PowerShell “bug” that I encountered today in v2. For very technical reasons it is actually a “feature”, but the behavior was eventually modified in v3. What would you expect this code to do:

foreach ($i in $null) { Write-Host ($i -eq $NULL) }

If you said “Nothing”, you would be right in PowerShell v3+. In PowerShell prior to v3, however, the script will output True. This isn’t necessarily a problem in this contrived example, but many things you do in PowerShell are leveraging the .NET FrameWork to provide the underlying functionality, and many of those things will throw an exception if you pass a $null argument. The technical reason for this happening is that the PowerShell programmers wanted this behavior to work:

foreach ($i in "Hello World") { Write-Host $i }

In many languages this would throw an error because the value being passed is not an array, collection, or other enumerable type. When you consider this in the context of how PowerShell uses pipelines, throwing an error in this circumstance is probably not desirable, so the PS foreach implementation treats a single value as an array containing a single item. Now consider this code:

foreach ($i in @($null)) { Write-Host ($i -eq $null) }

That code outputs True in any version of PowerShell. foreach isn’t being passed $null, but rather an array whose only item is $null, and that’s a perfectly reasonable thing to do. So to wrap this up, in early versions PowerShell, foreach would treat single values as an array with a single value in order to match expectations. This created an edge case with $null, since PowerShell treats $null just like any other value. In PowerShell v3, foreach was modified to check for singular $null values and skip the loop. Circling back to how I tripped on this Gotcha, consider this code:

function n { }
Write-Host ( $o -eq $null )
Write-Host ( n -eq $null )
Write-Host ( n -ne $null )
Write-Host ( (n) -eq $null )

In any version of PowerShell, the middle two Write-Host lines will not output anything, but the other lines will output True. What’s happening here is that n doesn’t return anything. If you assign that “nothing” to a variable, PowerShell’s assignment operator converts it to $null because nothing doesn’t really exist in PowerShell. In the case of (n) you’ve effectively assigned n‘s output to a temporary variable so the same thing happens. And that’s how PowerShell tripped me up today. One of my calls didn’t return anything because a non-fatal error occurred, which caused a variable assignment to be converted to $null, which triggered the unexpected behavior of foreach in PowerShell v2. Luckily I was aware of this change in behavior between versions and as soon as I saw the error I knew what had gone wrong.