0

I recently answered a SO post about Test-Connection Powershell script: create loop for ResponseTime

When a Test-Connection cannot connect it will return a System.Net.NetworkInformation.PingException which is fine but I would like to record that as an empty object in output instead of skipping over it. I am aware that I could just select the properties I want and just create a custom object to output on the command line. That is how I approached the linked question but I feel I could do better.

My desire is to have output like this

Source        Destination     IPV4Address      IPV6Address                              Bytes    Time(ms) 
------        -----------     -----------      -----------                              -----    -------- 
WYVERN        localhost       127.0.0.1        ::1                                      32       0        
              failed host     169.254.158.1
WYVERN        localhost       127.0.0.1        ::1                                      32       0   

The two returns are proper from Test-Connection with a dummy line inserted. It has all the properties of a proper return from Test-Connection but, since it failed, only some of the properties have values. The only approach that I tried to accomplish this was to create another object of a similar type. Note (Test-Connection -Count 1 localhost).GetType().FullName returned System.Management.ManagementObject

$servers = "10.50.10.100","169.254.54.1"
$servers | ForEach-Object{
    Test-Connection $_ -Count 1 -ErrorAction SilentlyContinue
    If(!$testconnection){
        $blank = New-Object -TypeName System.Management.ManagementObject
        $blank.Destination = $_
    }
} 

Test-Connection returns more than just a basic System.Management.ManagementObject. So the problem is that a new-object will not have the same properties and, as a result, $blank.Destination = $_ will fail since "'Destination' cannot be found on this object". I also experimented with Test-Connection -Count 1 127.0.0.1 | gm -MemberType Property to try and create a property collection that I could use to build my blank object but that was not bearing an fruit. Most likely since I am not doing it right.

FYI

I am hoping to apply this logic in other places in my scripts. While test-connection is the cmdlet I am dwelling on in this question I am hunting for a broader solution.

Attempt

I have tried, unsuccessfully, something like this but the object are not being outputted together.

$props = @{}
Test-Connection -Count 1 127.0.0.1 | gm -MemberType Property | %{$props.($_.Name) = ""}
$props.destination = "FailedHostAddress"
New-Object -TypeName PSCustomObject -Property $props
Matt
  • 45,022
  • 8
  • 78
  • 119
  • have you tried the method suggested in my answer on the question you referenced? creating the properties and object inside the loop and adding it to an array? Also you can add Properties to psobjects with `Add-Member` – Paul Oct 23 '14 at 01:12
  • @TheMadTechnician Yes what you have done in the reference would work but dont feel it addresses what i was going for. you are making custom object which I tried to explain that is not what i was trying to do. How could manually add a result to a `Test-Connection` collection without actually running `test-connection`? Assuming it is even possible – Matt Oct 23 '14 at 01:33
  • @paul I think my response to you is the same as I did for Mad. `Add-Member` ,while it could work, would be an inefficient and not dynamic solution to my question. I think i need to make an edit to my question... just not sure what. – Matt Oct 23 '14 at 01:37
  • So the issue with your specific example is that Test-Connection actually runs a WMI query and kicks back a WMI object. That is not easily accessible. Any standard types in PowerShell are fairly easy to generate. For this specifically you could ping 'localhost' and save the result to a variable and edit the properties manually. The object this really returns is a WMI object 'Win32_PingStatus' which you can get with `Get-WMIObject Win32_PingStatus -Filter 'address="localhost"'` or a similar CIM command. – TheMadTechnician Oct 23 '14 at 01:58
  • @TheMadTechnician `Test-Connection` then might be a really bad example to use for what i was asking for.... perhaps i will delete the question then. Given that an object of information is returned i figured i could just created another one and blank out the values i wanted.....Perhaps i will experiment with that first. Thanks for trying. If you see my question what i did in the case was ping local host to get that information. Just though i could make another `System.Management.ManagementObject` – Matt Oct 23 '14 at 02:03
  • I can confirm that @TheMadTechnician is correct about the difficulty of fully mimicking a WMI object. Have a look at some of the things I did in this module: https://github.com/briantist/DnsCmdletFixes (you can also see how to control which properties get displayed by default). – briantist Oct 23 '14 at 02:20

2 Answers2

0

Not sure if this helps or not:

$base = Test-Connection 127.0.0.1 -Count 1 
$blank = $base | select *
foreach ($prop in $base.psobject.Properties.Name)
{$blank.$prop = $null}

The select * will keep all of the properties, but convert them to note properties so they will be writeable, and you can set they to whatever you want them to be.

mjolinor
  • 66,130
  • 7
  • 114
  • 135
  • This is more of what i was hoping for however it seems i cant really combine the output of a `$blank` with regular `test-connection` output. In hindsight, based on comments, using `test-connection` might be a bad example. What you do here does create another object with empty properties but i cant merge this output with that of `Test-Connection` without casting it first. If the output was not WMI related this answer would suit i think. i shall test first. – Matt Oct 23 '14 at 02:49
0

I would probably do something like this:

$servers = '10.50.10.100', '169.254.54.1', 'somehost'

$servers | % {
  $dst = $_
  try {
    Test-Connection $dst -Count 1 -ErrorAction Stop | % {
      $props = [ordered]@{
        'Source'      = $env:COMPUTERNAME
        'Destination' = $dst
        'IPv4Address' = $_.IPV4Address
        'IPv6Address' = $_.IPV6Address
        'Available'   = $true
      }
    }
  } catch {
    try {
      $addr = [ipaddress]$dst
      $props = [ordered]@{
        'Source'      = $env:COMPUTERNAME
        'Destination' = $dst
        'IPv4Address' = $addr.MapToIPv4()
        'IPv6Address' = $addr.MapToIPv6()
        'Available'   = $false
      }
    } catch {
      $props = [ordered]@{
        'Source'      = $env:COMPUTERNAME
        'Destination' = $dst
        'IPv4Address' = $null
        'IPv6Address' = $null
        'Available'   = $false
      }
    }
  }
  New-Object -Type PSObject -Property $props
}

The [ordered] hashes make the properties appear in the given order.

With PowerShell v3 or newer it can be simplified to this:

$servers | % {
  $dst = $_
  try {
    Test-Connection $dst -Count 1 -ErrorAction Stop | % {
      [PSCustomObject]@{
        'Source'      = $env:COMPUTERNAME
        'Destination' = $dst
        'IPv4Address' = $_.IPV4Address
        'IPv6Address' = $_.IPV6Address
        'Available'   = $true
      }
    }
  } catch {
    try {
      $addr = [ipaddress]$dst
      [PSCustomObject]@{
        'Source'      = $env:COMPUTERNAME
        'Destination' = $dst
        'IPv4Address' = $addr.MapToIPv4()
        'IPv6Address' = $addr.MapToIPv6()
        'Available'   = $false
      }
    } catch {
      [PSCustomObject]@{
        'Source'      = $env:COMPUTERNAME
        'Destination' = $dst
        'IPv4Address' = $null
        'IPv6Address' = $null
        'Available'   = $false
      }
    }
  }
}

The output will look somewhat like this:

Source  Destination   IPv4Address   IPv6Address                   Available
------  -----------   -----------   -----------                   ---------
WYVERN  10.50.10.100  10.50.10.100  fe80::3a8f:4854:248d:787f%11       True
WYVERN  169.254.54.1  169.254.54.1  ::ffff:169.254.54.1               False
WYVERN  somehost                                                      False
Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328