Blogroll

Search

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

November 13th, 2009 by Karl

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 in PS extended, Powershell | No Comments »

Print-File Function

November 10th, 2009 by Karl

Here is a simple function that will ask the associated program to print any file you pass in. It can work with a file as a parameter, or multiple files. How well this works, especially with multiple files at a time, depends on the associated application, first whether it supports the print verb, and secondly how it handles it – more importantly how it handles opening many files at once. I haven’t yet been brave enough to try it on PDFs with adobe reader.

function print-file($file)
{
 begin  {
    function internal-printfile($thefile)
    {
        if ($thefile -is [string]) {$filename = $thefile }
        else {
                if ($thefile.FullName -is [string] ) { $filename = $THEfile.FullName }
             }
        $start = new-object System.Diagnostics.ProcessStartInfo $filename
        $start.Verb = "print"
        [System.Diagnostics.Process]::Start($start)
    } 

if ($file -ne $null) {
                $filespecified = $true;
                internal-printfile $file
            }
       }
process{if (!$filespecified) { write-Host process ; internal-printfile $_ } } 

}

@poshcode | download

Here you can pass in a path to the file , or a fileobject that you get as a response from get-childitem (dir)

Here are a few examples

#look recursively through a folder and print all word documents
dir *.doc -r | print-file 

#print one particular pdf file
print-file c:\downloads\myfile.pdf

Warning, this isn’t up to being a shrink wrapped deliverable. It doesn’t do any error handling, isn’t a nice V2 advanced function or anything, but that’s a beauty of PowerShell, you can just hack out something that fits your needs in a few minutes. With V2 parameter binding, this would be more elegant and actually simpler as i have to do some duplication of logic in my function to get it to work accepting the file both through the pipeline and as a parameter.

-Enjoy.

Posted in PSV2, Powershell, script | 2 Comments »