In the previous tip, we used the UPnP.UPnPDeviceFinder to discover smart devices hooked up to your network. Today, let’s take a closer look at the objects returned.
$UPnPFinder = New-Object -ComObject UPnP.UPnPDeviceFinder $result = $UPnPFinder.FindByType("upnp:rootdevice", 0)
When you run a search (which can take some time to complete), you get back a lot of information, but some properties return just ‘System.__ComObject’. How can you find out what’s hidden in them?
Let’s pick one of the objects returned. In my case, by looking at $result, I noticed an object from “NetGear” which caught my attention. Below, I am using Where-Object to access it.
The objects available in your case obviously vary, depending on the devices you use in your network, so you will have to adjust the filter expression to match one of your returned objects.
PS> $switch = $result | Where-Object ManufacturerName -like *NetGear* PS> $switch IsRootDevice : True RootDevice : System.__ComObject ParentDevice : HasChildren : True Children : System.__ComObject UniqueDeviceName : uuid:4d696e69-444c-164e-9d42-3894ed0e1db5 FriendlyName : RBR50 (Gateway) Type : urn:schemas-upnp-org:device:InternetGatewayDevice:1 PresentationURL : http://www.orbilogin.net/ ManufacturerName : NETGEAR, Inc. ManufacturerURL : http://www.netgear.com/ ModelName : NETGEAR Orbi Desktop AC3000 Router ModelNumber : RBR50 Description : http://www.netgear.com/home/products/wirelessrouters ModelURL : http://www.netgear.com/orbi UPC : RBR50 SerialNumber : 5R21945T06DA4 Services : System.__ComObject
Most properties use regular data types like string or integer. For example, “UniqueDeviceName” returns the unique name of a device (which becomes important in a moment). Some properties, however, simply return “System.__ComObject”. Let’s take a look at these:
Each PnP device can be part of a chain which always starts at a root device. Since we searched for root devices in the first place, the property “RootDevice” is always identical to the returned object:
PS> $switch -eq $switch.RootDevice True
To find out which devices are chained to a root device, look at “HasChildren” and “Children”: “HasChildren” is a simple Boolean value. “Children” however is a “System.__ComObject” and contains the info we are after:
PS> if ($switch.HasChildren) { $switch.Children.Count } else { 'no children' } 1
Obviously, “Children” seems to be some sort of array. After all, a root device can have many children. By accessing the property, PowerShell automatically turns the “System.__ComObjects” into readable .NET objects, so here are the children of my NetGear device:
PS> $switch.Children IsRootDevice : False RootDevice : System.__ComObject ParentDevice : System.__ComObject HasChildren : True Children : System.__ComObject UniqueDeviceName : uuid:4d696e69-444c-164e-9d43-3894ed0e1db5 FriendlyName : WAN Device Type : urn:schemas-upnp-org:device:WANDevice:1 PresentationURL : ManufacturerName : NETGEAR ManufacturerURL : http://www.netgear.com/ ModelName : NETGEAR Orbi Desktop AC3000 Router ModelNumber : RBR50 Description : WAN Device on NETGEAR RBR50 Orbi Router ModelURL : http://www.netgear.com/ UPC : RBR50 SerialNumber : 5R21945T06DA4 Services : System.__ComObject
This child in turn has children again. However, digging any deeper and listing the children of a child seems to fail:
PS> # works: PS> $switch.Children | Select-Object HasChildren, Children HasChildren Children ----------- -------- True System.__ComObject PS> # fails: PS> $switch.Children.HasChildren PS> $switch.Children.Children PS> $switch.Children[0].HasChildren Value does not fall within the expected range. PS> $switch.Children[0].Children Value does not fall within the expected range.
The reason for this is an oddity with COM arrays. They use an unusual enumerator that differs from regular object arrays, so PowerShell cannot directly access the array elements. An easy workaround is to use Foreach-Object:
PS> $child = $switch.Children PS> $child | ForEach-Object { $_.Children } IsRootDevice : False RootDevice : System.__ComObject ParentDevice : System.__ComObject HasChildren : False Children : System.__ComObject UniqueDeviceName : uuid:4d696e69-444c-164e-9d44-3894ed0e1db5 FriendlyName : WAN Connection Device Type : urn:schemas-upnp-org:device:WANConnectionDevice:1 PresentationURL : ManufacturerName : NETGEAR ManufacturerURL : http://www.netgear.com/ ModelName : NETGEAR Orbi Desktop AC3000 Router ModelNumber : RBR50 Description : WANConnectionDevice on NETGEAR RBR50 Orbi Router ModelURL : http://www.netgear.com/ UPC : 606449084528 SerialNumber : 5R21945T06DA4 Services : System.__ComObject
The same applies to “ParentDevice” and “Services”. Let’s find out more about the services of my NetGear device. This time, I want to access my NetGear device directly (which is much faster than enumerating all devices). You do need to know its unique device name, though. In my case, the property “UniqueDeviceName” exposed “uuid:4d696e69-444c-164e-9d42-3894ed0e1db5”:
$UPnPFinder = New-Object -ComObject UPnP.UPnPDeviceFinder # the UDN is unique, so you need to find out the UDN for your device first # you cannot use the UDN I used $myNetgearSwitch = $UPnPFinder.FindByUDN('uuid:4d696e69-444c-164e-9d42-3894ed0e1db5') $myNetgearSwitch
This time, my device was identified almost momentarily. To list its services, I simply dump its property “Services”, and Powershell automatically turns the COM object into visible properties:
PS> $myNetgearSwitch.Services ServiceTypeIdentifier Id LastTransportStatus --------------------- -- ------------------- urn:schemas-upnp-org:service:Layer3Forwarding:1 urn:upnp-org:serviceId:L3Forwarding1 0