0

I'm using the following code to give me output on the status of a batch of computers:

$Win2k8r2Computers = "Server1", "Server2", "Server3", "Server4"

$results = Invoke-Command -ComputerName $Win2k8r2Computers { #}
    $props = @{}
    Try {
        <#If ($PSVersionTable.PSVersion.Major -eq "2") {
            $props.Add('Message',"Server (Win2008r2) is currently running an incompatible version of PowerShell (v2.1)")
            }#>
        If (Get-Service | Where-Object { $_.Name -eq "W3SVC" } -ErrorAction Stop) {
            $props.Add('Message', "IIS is installed (Win2008r2)")
        }
        Else {
            $props.Add('Message', "IIS is NOT installed (Win2008r2)")
        }
    }
    catch {
        $props.Add('Message', 'Error: {0}' -f $_)
    }
    New-Object -Type PSObject -Prop $Props
}

It's working as expected other than the catch not appearing to actually catch and return errors to the $results variable. What am I missing?

Sage Pourpre
  • 9,932
  • 3
  • 27
  • 39
jshizzle
  • 467
  • 1
  • 11
  • 23
  • Is the goal to throw an error if `W3SVC` service is not found? So you want a message of `IIS is NOT installed (Win2008r2)` ***and*** the error message from searching for that service? – AdminOfThings Dec 09 '20 at 16:21
  • No, it's to throw an error if connection cannot be made to the server. I realize now that the -ErrrorAction was completely in the wrong place now however. – jshizzle Dec 10 '20 at 11:05

1 Answers1

1

In your current code, you are passing parameter -ErrorAction only to Where-Object. So you would only catch errors of the Where-Object cmdlet. Get-Service woud still run with the default ErrorAction value of Continue.

To turn errors of both Get-Service and Where-Object into terminating errors that can be catched, either pass -ErrorAction 'Stop' to both of them...

If (Get-Service -ErrorAction Stop | Where-Object { $_.Name -eq "W3SVC" } -ErrorAction Stop)

... or (more efficiently) set the $ErrorActionPreference variable at the beginning of the script and remove the -ErrorAction parameter:

$Win2k8r2Computers = "Server1", "Server2", "Server3", "Server4"

$results = Invoke-Command -ComputerName $Win2k8r2Computers { #}
    $props = @{}
    Try {
        $ErrorActionPreference = 'Stop'

        <#If ($PSVersionTable.PSVersion.Major -eq "2") {
            $props.Add('Message',"Server (Win2008r2) is currently running an incompatible version of PowerShell (v2.1)")
            }#>
        If (Get-Service | Where-Object { $_.Name -eq "W3SVC" }) {
            $props.Add('Message', "IIS is installed (Win2008r2)")
        }
        Else {
            $props.Add('Message', "IIS is NOT installed (Win2008r2)")
        }
    }
    catch {
        $props.Add('Message', 'Error: {0}' -f $_)
    }
    New-Object -Type PSObject -Prop $Props
}

Caveat:

$ErrorActionPreference is ignored by cmdlets in PowerShell script modules, unless they take special care of handling it. See this answer for some insight.

In this case it works though, because both cmdlets are implemented in C# modules.

zett42
  • 25,437
  • 3
  • 35
  • 72
  • Thanks zett42, I don't know how I missed that the -ErrorAction was not in the right place and have rectified this now as per your suggestion, however, the errors still don't appear to be caught in the $result output regardless. – jshizzle Dec 10 '20 at 11:07
  • @jshizzle Works for me on local machine. Try to insert `Write-Error 'myerror'` after the `$ErrorActionPreference` line. Does this get added to the `$result`? – zett42 Dec 10 '20 at 11:45
  • Same again, when I run it (With computers that produce a connection error), the output is shown in the console but not when calling $results. I've used another method since to get the information and manipulate it outside of the Invoke-Command block but am still interested in how to get the above working at some point as think it could be useful as an alternative and has its place. – jshizzle Dec 10 '20 at 16:31
  • @jshizzle _With computers that produce a connection error_ - what exactly do you mean by that? Do you mean when the `Invoke-Command` gets interrupted because the connection to the remote machine is lost in the middle of execution? – zett42 Dec 10 '20 at 16:59
  • I mean when initial remote management connection is attempted and fails. I'm filtering through computers to check if IIS is installed but want to catch computers that cannot be reached due to connection errors. – jshizzle Dec 14 '20 at 10:51
  • @jshizzle For this you have to handle the error outside of the script block, e. g. : `Try { $results = Invoke-Command -ErrorAction Stop ... } catch { ... }` – zett42 Dec 14 '20 at 11:08