Testing a remote computer is online better test-connection

My sys admin experience is limited to a small enterprise and therefore there were no senior admins to learn from.
So I may have learned to do things wrongly, even though they work.
With that said,

  • Scenario and Question below -

Recently I had to change the contents of a certain html file on each desktop about 500 give or take. I did it with powershell. It worked out and the deed is done. But doesn’t hurt to ask how can i do things better.
In order to test for all the online desktops vs all records in AD I used a test-connection.
Is there a better way to test if the computer is online / exists? Because in AD we have more records desktops than we actually have.

Test-connection is a little slow.
In addition I used hard coded paths,
if the path existed,
and if the file existed within the path,
and if the string existed within the file,
modify it and write the changes.

I ran the script a few times to make sure I do not miss the people who turn off their desktops when they take off.
I am repeating the question here: Is there a better way to test if the computer is online / exists, than test-connection?
Thank you.

Any kind of live check is going to be slow, because you have to allow for a decent timeout. Test-Connection is just a ping; if you’re fairly confident of your network, you can limit it to one ping instead of the default four, to speed it up a bit - but you risk “missing” systems that are online and just a bit slow.

The most you can practically do to speed things up is to parallelize things a bit, using something like Worfklow or Remoting, or Invoke-Parallel (which is an open source project) or something.

Actually, I don’t think test-connection and test-netconnection are very useful for admins with their long timeouts, and they don’t work in powershell 6 anyway. But it’s very easy to roll your own with a little .net.

Function Get-Ping  {
  Param (
    [parameter(ValueFromPipeline)]
    [string[]]$Hostname='yahoo.com'
  )
  Begin {
    $Ping = New-Object System.Net.Networkinformation.ping
    $Timeout = 250 # ms                                                                                                                                    
  }
  Process {
    $hostname | foreach {
      $Ping.Send($_, $timeout) |
      Add-Member -passthru hostname $_ |
      select hostname,address,status,roundtriptime
    }
  }
}

PS /Users/js> get-ping yahoo.com,microsoft.com                                                                                                         

hostname      Address         Status RoundtripTime
--------      -------         ------ -------------
yahoo.com     206.190.39.42  Success            95
microsoft.com 0.0.0.0       TimedOut             0

Actually I usually use something like this. If it’s in osx port 22 will be live, in windows the rdp port 3389 is live.

function Get-Port {

  Param (
    [parameter(ValueFromPipeline)]
    [string[]]$Hostname='yahoo.com',
    [int[]]$ports=@(22,3389),
    [int]$timeout = 100 # ms
  )
  
  begin {   
    $ping = New-Object System.Net.Networkinformation.ping
  }

  process {
    $hostname | foreach {
      $openPorts = @()
  
      foreach ($port in $ports) {
        $client = New-Object System.Net.Sockets.TcpClient
        $beginConnect = $client.BeginConnect($_,$port,$null,$null)
        Start-Sleep -Milli $TimeOut
        if($client.Connected) { $openPorts += $port }
        $client.Close()
      }
  
      $result = $Ping.Send($_, $timeout) 
      $pingstatus = ($result.status -eq 'Success')

      New-Object -typename PSObject -Property @{
        HostName = $_
        Address = $result.address
        Port = $openPorts
        Ping = $pingstatus 
      } | select hostname,address,port,ping
    } # end foreach
  } # end process

}

PS C:\Windows\system32> get-port a001,a002

HostName Address     Port    Ping
-------- -------     ----    ----
arc001               {3389} False
arc002   1.1.1.1     {3389}  True