Enumerate UPNP devices

At home I have a Sonos system. It’s probably the best of any device that I have owned in terms of quality, usability and sheer happiness. The Sonos system has been working just fine for many years. It just works!

Recently I was fortunate enough to get a direct fiber into my house. Needless to say this triggered me to update my home network. Part of this upgrade was to install Ubiquiti long range access points for better performance and coverage as well as a new firewall. After this network upgrade Sonos system then started to behave strangely which brings me to the reason for this post!

I had to troubleshoot the Sonos system, a good start would be to see that all the devices were available and OK. A quick google search found a few PowerShell examples for how to use the UPnP.UPnPDeviceFinder COM object. Here’s one example that I found:

$finder = New-Object -ComObject UPnP.UPnPDeviceFinder;
$devices = $finder.FindByType("upnp:rootdevice", 0)
foreach($device in $devices)
    Write-Host ---------------------------------------------
    Write-Host Device Name: $device.FriendlyName
    Write-Host Unique Device Name: $device.UniqueDeviceName
    Write-Host Description: $device.Description
    Write-Host Model Name: $device.ModelName
    Write-Host Model Number: $device.ModelNumber
    Write-Host Serial Number: $device.SerialNumber
    Write-Host Manufacturer Name: $device.ManufacturerName
    Write-Host Manufacturer URL: $device.ManufacturerURL
    Write-Host Type: $device.Type

If you run this you get what you want, here’s a partial output:

Device Name: BUBBA
Unique Device Name: uuid:4d696e69-444c-164e-6b41-101f743be078
Description: MiniDLNA on Debian
Model Name: Windows Media Connect compatible (MiniDLNA)
Model Number: 1
Serial Number: 12345678
Manufacturer Name: Justin Maggard
Manufacturer URL: http://www.debian.org/
Type: urn:schemas-upnp-org:device:MediaServer:1
Device Name: - Sonos CONNECT:AMP
Unique Device Name: uuid:RINCON_000E5726C94601400
Description: Sonos CONNECT:AMP
Model Name: Sonos CONNECT:AMP
Model Number: ZP120
Serial Number:
Manufacturer Name: Sonos, Inc.
Manufacturer URL: http://www.sonos.com/
Type: urn:schemas-upnp-org:device:ZonePlayer:1

This output is fine but it is not done in a PowerShell way. Newcomers to PowerShell often make things needlessly complex. While the above script works it is not the best way do list all UPnP devices. Let’s make the above code easier and more importantly, more useful:

$finder = New-Object -ComObject UPnP.UPnPDeviceFinder;
$devices = $finder.FindByType("upnp:rootdevice", 0)

This script will give the same output but much more useful. Line one instatiates the UPnP COM object, line two tells the oject to find all ‘root’ UPnP devices on our local network and store the result in the $devices variable. The third line is a bit of PowerShell magic. Since the variable $devices is really an object PowerShell understands that it contains many objects inside itself. So by simply stating the variable name $devices on a single line PowerShell will output the object properties like this:

IsRootDevice     : True
RootDevice       : System.__ComObject
ParentDevice     :
HasChildren      : False
Children         : System.__ComObject
UniqueDeviceName : uuid:4d696e69-444c-164e-9d41-101f743be078
FriendlyName     : BUBBA
Type             : urn:schemas-upnp-org:device:MediaServer:1
PresentationURL  :
ManufacturerName : Justin Maggard
ManufacturerURL  : http://www.debian.org/
ModelName        : Windows Media Connect compatible (MiniDLNA)
ModelNumber      : 1
Description      : MiniDLNA on Debian
ModelURL         : http://www.debian.org/
UPC              :
SerialNumber     : 12345678
Services         : System.__ComObject

IsRootDevice     : True
RootDevice       : System.__ComObject
ParentDevice     :
HasChildren      : True
Children         : System.__ComObject
UniqueDeviceName : uuid:RINCON_000E5836C94601400
FriendlyName     : - Sonos CONNECT:AMP
Type             : urn:schemas-upnp-org:device:ZonePlayer:1
PresentationURL  :
ManufacturerName : Sonos, Inc.
ManufacturerURL  : http://www.sonos.com/
ModelName        : Sonos CONNECT:AMP
ModelNumber      : ZP120
Description      : Sonos CONNECT:AMP
ModelURL         : http://www.sonos.com/products/zoneplayers/ZP120
UPC              :
SerialNumber     :
Services         : System.__ComObject

Admittedly this doesn’t look as pretty as the output from the first script. But, the result is a true objectand much more useful. In order to see what information is available, issue the most useful PowerShell command of all, Get-Member:

$devices | Get-Member

   TypeName: System.__ComObject#{3d44d0d1-98c9-4889-acd1-f9d674bf2221}

Name             MemberType Definition
----             ---------- ----------
IconURL          Method     string IconURL (string, int, int, int)
Children         Property   IUPnPDevices Children () {get}
Description      Property   string Description () {get}
FriendlyName     Property   string FriendlyName () {get}
HasChildren      Property   bool HasChildren () {get}
IsRootDevice     Property   bool IsRootDevice () {get}
ManufacturerName Property   string ManufacturerName () {get}
ManufacturerURL  Property   string ManufacturerURL () {get}
ModelName        Property   string ModelName () {get}
ModelNumber      Property   string ModelNumber () {get}
ModelURL         Property   string ModelURL () {get}
ParentDevice     Property   IUPnPDevice ParentDevice () {get}
PresentationURL  Property   string PresentationURL () {get}
RootDevice       Property   IUPnPDevice RootDevice () {get}
SerialNumber     Property   string SerialNumber () {get}
Services         Property   IUPnPServices Services () {get}
Type             Property   string Type () {get}
UniqueDeviceName Property   string UniqueDeviceName () {get}
UPC              Property   string UPC () {get}

As you can see in the above output we get a number of properties and one method, IconURL. Now you can pick and choose which properties you want and you can do magic with them. Let’s say you want the FriendlyName, ModelName and the ManufacturerName. Try this:

$devices | Select-Object FriendlyName, ModelName, ManufacturerName

The great thing here is that you can pick and choose exactly the output you want. In a later post I will show you what you can do with this.