2

I am looking for a command (an IF test) that will run quickly to see if a computer can be connected to. I do one if-test and if it passes then I will run a slew of commands to pull the information I need. If the first test fails, then it does not run the commands as otherwise it would have to fail out on each test which would take a long time.

The following code works, but it is very slow and results in a "GUI (Not Responding)" if the computer is not on the network. I am looking for something to check quicker if it fails.

if (Test-Path "\\$PCNAME\c`$")
{
    # Slew of WMI commands go here.
}

I sometimes query large lists of computers and if a majority of them are off, the command above will take a ton of time to complete.

user3585839
  • 1,459
  • 3
  • 12
  • 18

6 Answers6

0

a much better solution which uses a port test based on: https://theolddogscriptingblog.wordpress.com/2012/05/11/wmi-hangs-and-how-to-avoid-them/

Here is a modified version of the script found there with an example of one wayt to use it:

function Test-Port {   
<#
.SYNOPSIS
Tests connection to port 135 on the SQL server, so I guess it is confined to M$ servers 
.DESCRIPTION
.PARAMETER server
computername or IP address
.PARAMETER port
port defaults to 135
.PARAMETER timeout
in milliseconds, defaults to 1000
.EXAMPLE
Test-Port myserver.com
#>
Param(    
    [string] $server,    
    $port=135,    
    $timeout=1000, # milliseconds    
    [switch]$verbose   
 )    
 # Does a TCP connection on specified port (135 by default)    
 # Create TCP Client  https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient(v=vs.110).aspx  
 $tcpclient = new-Object system.Net.Sockets.TcpClient    
 # Initiate an asynchronous request to machine on Port    
 $iar = $tcpclient.BeginConnect($server,$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   
    }    
} 
#Found from using for a similar purpose that checking port 49153 was more reliable than 135 
# also the test-connection is unnecessary and that very small timeouts, e.g., 10ms, worked on our network, which really speeds things up but you should test what works on your network
#Use like this
$computername = "myserver.com"
if (Test-Port -srv $computername -port 49153 -timeout 10) {
    # Slew of WMI commands go here.
} else {
    Write-Warning "Could ping $computername but NOT reach RPC port`n so can't use it for WMI"
}
sdjuan
  • 709
  • 6
  • 15
0

To boil down sdjuan's answer for a quick check that the PCNAME has a C$ Drive share, and is allowing WMI lookups:

If ( (Test-Path "\\$PCNAME\c`$") -and (Get-WmiObject win32_bios -ComputerName $PCNAME) ) {
# Slew of WMI commands go here.
}

However, it appears through my testing that CimInstance lookups are even faster, so :

Get-CimInstance win32_bios -ComputerName $PCNAME

May yield better results, but keep it consistent through the rest of the script.

ScriptMonkey
  • 191
  • 1
  • 3
  • 20
-1

You usually see Test-Connection used for this:

if (Test-Connection $PCNAME -Quiet -Count 1)
{
  # Slew of WMI commands go here.
}

Edit: I suspect you'd probably be much better off using CIM for this if the remote systems will support it. The implementation details will depend on whether remoting is enabled on the remote systems.

mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • I have seen this around as well. I switched this out in my code and it took ~45 seconds to tell me the connection failed. The method I used above only takes ~15 seconds to fail. But I am looking for something like if after 5 seconds no connection is made to report that it failed. – user3585839 Dec 29 '14 at 16:52
  • You can reduce the number of connection attempts before it fails using the -Count parameter. Updated the answer with example. – mjolinor Dec 29 '14 at 16:55
  • This is a bad test because sometimes you can `Test-Connection` a.k.a `ping` successfully but not `Get-WmiObject`. This is because `WMI` is a service that runs on the remote machine your are trying to reach – Kellen Stuart Apr 25 '17 at 22:52
-1

There are two easy ways to do this:

One is Test-Connection:

Test-Connection 192.168.0.2
Test-Connection -CompuetrName "SamsPC"

This can be used as a Boolean expression, or with the $? operator:

if (Test-Connection 192.168.0.1) {
 do stuff
}

or

Test-Connection 192.168.0.1
if ($?) {
 Do Stuff
}

The other approach uses .NET classes.

$Pinger = New-Object System.Net.NetworkInformation.Ping
$pResult = $Pinger.Send("192.168.0.1")

if ($pResult.Status -eq "Success") {
  Do stuff
}
Austin T French
  • 5,022
  • 1
  • 22
  • 40
-1

With only some minor modifications to the test-connection timeout script, you can test WMI function as well. Just replacing the test-connection with a get-wmiobject call will get you the complete results. Here is a modified function:

Function Get-WMI {
param(
    [Parameter(Mandatory = $True)]
    [Object]$computer
)
$timeoutSeconds = 1 # set your timeout value here
$j = Start-Job -ScriptBlock {
    # your commands here, e.g.
    Get-WmiObject win32_bios -ComputerName $args[0]
} -ArgumentList $computer
#"job id = " + $j.id # report the job id as a diagnostic only
Wait-Job $j -Timeout $timeoutSeconds | out-null
if ($j.State -eq "Completed")
{
#connection to PC has been verified and WMI commands can go here.
$Answer = "WMI call WAS SUCCESSFULL to $computer"
}
elseif ($j.State -eq "Running")
{
#After the timeout ($timeoutSeconds) has passed and the test is      
still running, I will assume the computer cannot be connected.
$Answer = "WMI is not running on or could not Connect to $computer"
}
return $Answer
}

I hope this helps someone.

Adam
  • 1
-2

I know this is way after the fact, but I found a solution. I was looking for an if test to try and test the connection, but when it would fail, it would take a long time to fail. When a connection was made it would go through right away.

$timeoutSeconds = 1 # set your timeout value here
$j = Start-Job -ScriptBlock {
    # your commands here, e.g.
    Test-Connection -ComputerName $args[0] -Count 1
} -ArgumentList $computer
#"job id = " + $j.id # report the job id as a diagnostic only
Wait-Job $j -Timeout $timeoutSeconds | out-null
if ($j.State -eq "Completed")
{
    #connection to PC has been verified and WMI commands can go here.
    $richtextbox1.Text = "Connection can be made to $computer"
}
elseif ($j.State -eq "Running")
{
    #After the timeout ($timeoutSeconds) has passed and the test is still running, I will assume the computer cannot be connected.
    $richtextbox1.Text = "Could not Connect to $computer"
}

I am not sure exactly where I got this code from. I think I used - adding a timeout to batch/powershell

I hope this helps someone in the future.

Community
  • 1
  • 1
user3585839
  • 1,459
  • 3
  • 12
  • 18
  • none of these solutions test if "WMI information can be pulled from a remote computer" FWIW: test-connection will return a positive result a for linux computer, which clearly won't do WMI even if you can ping it. – sdjuan Apr 07 '16 at 02:19
  • This is true, but I have not found a way to do exactly what I would have liked, so this will at least make the code not hang. If you find a solution to this, I would love to hear it as it would still be useful. – user3585839 Apr 11 '16 at 12:17
  • I put in a short answer with link to a way to test but did not realize stackoverflow rules required more than a link so a moderator has deleted my answer. I have submitted an expanded answer with an example and if it doesn't show up here in a day or two I'll re-write it as a separate answer – sdjuan Apr 11 '16 at 16:29
  • I tried to undelete my previous too short answer after expansion but it popped back that it could not be undeleted so I have posted the new expanded answer. Hope that helps. – sdjuan Apr 11 '16 at 16:39