Share via


How can I suppress an error from Get-WmiObject cmdlet? -ErrorAction SilentlyContinue does not work

Question

Monday, January 2, 2012 4:21 PM

I have the following function:

 

function Get-LoggedOnUsers {
    [CmdletBinding()]
    param(
        [Parameter(
            Mandatory=$true
        )]
        $computerName
    )
    
    Try {
        Get-WmiObject -ComputerName $computerName -Class Win32_LoggedOnUser | Select-Object @{Expression={$_.__SERVER}; Name="Server"}, @{Expression={$_.Antecedent.ToString().Split("=")[2].Replace("`"","")};Name="User"} -ErrorAction SilentlyContinue;
    }
    Catch {
        Write-Output "$computerName was not accessible.";
    }
}

 

When I attempt to access multiple machines, some of which are inaccessible, I get RPC errors.  

 

# http://technet.microsoft.com/en-us/library/ff730959.aspx

$strFilter = "computer"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.SearchScope = "Subtree" 
$objSearcher.PageSize = 1000 

$objSearcher.Filter = "(objectCategory=$strFilter)"
$colResults = $objSearcher.FindAll()

# Create empty arrays for storing results
$errored = $results = $null;

# Return logged on users based on computer name
foreach ($i in $colResults) {
    Write-Output "Processing $($i.GetDirectoryEntry().Name)";
    Try {
        $results += Get-LoggedOnUsers -computerName $i.GetDirectoryEntry().Name;
    }
    Catch {
        $errored += $i.GetDirectoryEntry().Name
    }
}

Write-Output "Successfully processed machines:"
$results;
Write-Output "Failed attempts:"
$failed;

My intent was to prevent the error from appearing, but, I get this instead:

 

 

Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)
At line:10 char:22
+         Get-WmiObject <<<<  -ComputerName $computerName -Class Win32_LoggedOnUser | Select-Object @{Expression={$_._
SERVER}; Name="Server"}, @{Expression={$_.Antecedent.ToString().Split("=")[2].Replace("`"","")};Name="User"} -ErrorAct
on SilentlyContinue;
    + CategoryInfo          : InvalidOperation: (:) [Get-WmiObject], COMException
    + FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

 

All replies (12)

Monday, January 2, 2012 4:30 PM ✅Answered

From the script center repository:

http://gallery.technet.microsoft.com/scriptcenter/97119ed6-6fb2-446d-98d8-32d823867131

Run that against port 135 on the target machine before you try a get-wmiobject.

[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "


Monday, January 2, 2012 4:34 PM ✅Answered | 1 vote

Change this:

-ErrorAction SilentlyContinue

to

-ErrorAction Stop

([string](0..9|%{[char][int](32+("39826578846355658268").substring(($_*2),2))})).replace(' ','')

What's new in Powershell 3.0 (Technet Wiki)


Monday, January 2, 2012 5:06 PM

The following works except for stale entries in AD.  I have two machines that seem to exist in the domain, but, which are not still online.  One more check I guess:

function Get-LoggedOnUsers {
    [CmdletBinding()]
    param(
        [Parameter(
            Mandatory=$true
        )]
        $computerName
    )
    
    Try {
        Get-WmiObject -ComputerName $computerName -Class Win32_LoggedOnUser | Select-Object @{Expression={$_.__SERVER}; Name="Server"}, @{Expression={$_.Antecedent.ToString().Split("=")[2].Replace("`"","")};Name="User"} -ErrorAction Stop;
    }
    Catch {
        Write-Output "$computerName was not accessible.";
    }
}

function Test-Port {
    Param(
        [string] $srv,
        $port=135,
        $timeout=3000,
        [switch]$verbose
    )
     
    # Test-Port.ps1
    # Does a TCP connection on specified port (135 by default)
     
    $ErrorActionPreference = "SilentlyContinue"
     
    # Create TCP Client
    $tcpclient = new-Object system.Net.Sockets.TcpClient
     
    # Tell TCP Client to connect to machine on Port
    $iar = $tcpclient.BeginConnect($srv,$port,$null,$null)
     
    # Set the wait time
    $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
     
    # Check to see if the connection is done
    if(!$wait)
    {
        # Close the connection and report timeout
        $tcpclient.Close()
        if($verbose){Write-Host "Connection Timeout"}
        Return $false
    }
    else
    {
        # Close the connection and report the error if there is one
        $error.Clear()
        $tcpclient.EndConnect($iar) | out-Null
        if(!$?){if($verbose){write-host $error[0]};$failed = $true}
        $tcpclient.Close()
    }
     
    # Return $true if connection Establish else $False
    if($failed){
        return $false
    } else {
        return $true
    }
}

# http://technet.microsoft.com/en-us/library/ff730959.aspx

$strFilter = "computer"
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.SearchScope = "Subtree" 
$objSearcher.PageSize = 1000 

$objSearcher.Filter = "(objectCategory=$strFilter)"
$colResults = $objSearcher.FindAll()

# Create empty arrays for storing results
$errored = $results = $null;

# Return logged on users based on computer name
foreach ($i in $colResults) {
    Write-Output "Processing $($i.GetDirectoryEntry().Name)";
    if(Test-Port -srv $i.GetDirectoryEntry().Name) {
        Try {
            $results += Get-LoggedOnUsers -computerName $i.GetDirectoryEntry().Name;
        }
        Catch {
            $errored += $i.GetDirectoryEntry().Name
        }
    } else {
        Write-Output "$($i.GetDirectoryEntry().Name) cannot be accessed over port 135.";
    }
}

# Output results.
Write-Output "Successfully processed machines:"
$results;

Tuesday, January 3, 2012 2:11 AM

I didn't immediately see the difference.  Thanks for the clarification on this one.


Tuesday, January 3, 2012 3:43 AM

Sure thing, Will.  I didn't think you were interested, so I deleted it, as it seemed out of context. 

You can also set the automatic variable $ErrorActionPreference for a whole scriptblock instead of doing and -Erroraction for each command.

([string](0..9|%{[char][int](32+("39826578846355658268").substring(($_*2),2))})).replace(' ','')

What's new in Powershell 3.0 (Technet Wiki)


Tuesday, January 3, 2012 3:46 AM

What's weird is that I got your reply, but, in my current session, I don't see the comment.  My eyes are swirling from the overly long weekend.  Maybe the whole 3 day weekend had its side effects.

Being more specific: when you issue a Stop preference in this scenario, it simply kills that instance of the GWmi Query (after it errors), but, resumes iteration at the next item in the collection.  Is that correct?


Tuesday, January 3, 2012 3:55 AM

Yes, your eyes are not playing tricks. I deleted it because mj's answer seemed to be the right one, and mine seemed out of context.  Sorry!

Yes, you are correct:  That particular iteration of GWMI will cause the Catch block to execute, if the call to WMI fails and the erroraction is set to Stop.  Then iteration will continue as before.

The only practical use for Stop really is to invoke the Catch block.  I've never seen it used in any other situation.

 

([string](0..9|%{[char][int](32+("39826578846355658268").substring(($_*2),2))})).replace(' ','')

What's new in Powershell 3.0 (Technet Wiki)


Tuesday, January 3, 2012 3:57 AM

You're right about the EA setting being wrong. 

In a situation where you know it's possible some of the hosts may be unreachable, it's best to test connectivity before attempting the wmi connection, because of the long timeout before it will throw an error.

Using the port-test on port 135 verifies that the host is reachable, and you can connect to the rpc port mapper before you commit to waiting for that timeout to expire to find out it's not going to work.

[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "


Tuesday, January 3, 2012 4:14 AM

Rob, I wouldn't go so far as to say I was "wrong".  In fact, I think I was exactly right.  Will's Catch block wasn't executing, and that was why.

The fact is, he decided to go with your method of checking the port first, so that's when I pulled out of the discussion, because the -Erroraction preference no longer was important.

 

([string](0..9|%{[char][int](32+("39826578846355658268").substring(($_*2),2))})).replace(' ','')

What's new in Powershell 3.0 (Technet Wiki)


Tuesday, January 3, 2012 4:23 AM

Rob, I wouldn't go so far as to say I was "wrong".  In fact, I think I was exactly right.  Will's Catch block wasn't executing, and that was why.

That's what I meant when I said:

"You're right about the EA setting being wrong. "

Maybe I should have phrased that differently.

[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "


Tuesday, January 3, 2012 4:27 AM

Ok, same wavelength attained!  Cheers.([string](0..9|%{[char][int](32+("39826578846355658268").substring(($_*2),2))})).replace(' ','')

What's new in Powershell 3.0 (Technet Wiki)


Tuesday, January 3, 2012 4:35 AM

OT, but grist for your PS v3 ISE mill.

http://mjolinor.wordpress.com/2011/12/31/clip-toarray-for-ps-v3-ise/

[string](0..33|%{[char][int](46+("686552495351636652556262185355647068516270555358646562655775 0645570").substring(($_*2),2))})-replace " "