Sick of an exception happening to just one item in the pipeline when you don’t care.

How many times have you had something like:

get-thousandsofitems | % { do-something $_ } | whatever

Only to have some exception happen in do-something and it throws the whole thing. When really you don’t care, you’d rather just be able to know what failed and have it move on. This happens a fair bit with Get-WMIobject etc, because one of the machines may be off, firewall blocked, some sort of permissions issues – things that bubble up even when you have the preference set to SilentyContinue.

So what do we normally do in this scenario. We either pipeline it and make it look like a VBscript, or ruin our beautiful single liner by making that script complicated with V1 traps and the likes, and we usually get the error handling wrong wrong a number of times along the way.

Well with PowerShell you can always adjust and expand the language. There is nothing particular special about the foreach-object Cmdlet. In its common use you can replicate it with a function as simple as the one below.

function myforeach-object([scriptblock]$process) { process { &$process } }

So how about making a looping function that deals with the exceptions for you, you say? Great Idea!, Now you are cooking. The following function is pretty much a simple V1 function, though it should really be completed and production readied into a V2 Advanced function with all the modern trimmings and trappings, however I DO use V2 TRY/CATCH syntax instead of V1 Trapping, because its more sane to us who don’t have a secret VBscript fetish.

function foreach-withexception ([scriptblock]$process,$outputexception)
{
  begin { $global:foreachex = @() }
  process { 
            try 
            {
            $local:inputitem = $_
            &$process 
            }
            catch
            {
            $local:exceptionitem = 1 | select-object object,exception
            $local:exceptionitem.object = $local:inputitem 
            $local:exceptionitem.exception = $_
            $global:foreachex += $local:exceptionitem
            }
          }
  end {}
}
set-alias %ex foreach-withexception

So i love my aliases , %ex for foreach with exceptions. Really I wish i could come up with a better name for the long function. I also keep a %i for my foreach-index function as well. Basically you use this just like foreach-object (though i haven’t implemented a begin and end area in this), and exceptions get eaten, but after the fact you can access the object that caused the error, and the error in the global $foreachex variable. At a later date i’m going to add an option paramter variable that if can put the exception in instead of a naughty global variable. But as Jeffrey Snover says “To ship is to choose” though for me it really means “this function does what i need it to now, i need to go back and solve the Real problem i’m solving that this function really helps with”

here is an example

100..-5 | %ex {  "yo $_" ;  1 / $_ }
$foreachex

Capture1

normally 0/0 would throw a fuss , and kill the whole thing, but it just works on , and you can check to see if there are any errors in $foreachex Normally the things that i need this for though are “loose web services”, WMI, or networking sort of things. but really it simplifies my one liners, and gets things done quicker.

@poshcode | Download

 


Posted Feb 13 2009, 09:59 AM by Karl Prosser
Filed under: ,
Concentrated Tech NSoftware Dell Compellent Sponsored by Idera and Concentrated Tech and NSoftware and Dell Compellent
Copyright 2011 PowerShell.com. All rights reserved.