0

We're trying to create a list of all the printers on a print server with their respective HostAddress for the shared port they use. To do this we created the following function:

Function Get-PrintersInstalledHC {
    Param (
        [Parameter(ValueFromPipeline)]
        [Object[]]$Servers
    )
    Process {
        foreach ($S in $Servers) {
            Try {
                if ($Printers = Get-Printer -ComputerName $S.Name -Full -EA Stop) {
                    $CimParams = @{
                        ClassName    = 'Win32_PrinterConfiguration'
                        ComputerName = $S.Name
                        Property     = '*'
                        ErrorAction  = 'Stop'
                    }                
                    $Details = Get-CimInstance @CimParams

                    $Ports = Get-CimInstance -ClassName Win32_TCPIPPrinterPort -ComputerName $S.Name -Property *

                    Foreach ($P in $Printers) {
                        Foreach($D in $Details) {
                            if ($P.Name -eq $D.Name) {
                                $Prop = @{
                                    PortHostAddress = $Ports | Where {$_.Name -eq $P.PortName} | 
                                                        Select -ExpandProperty HostAddress
                                    DriverVersion   = $D.DriverVersion
                                    Collate         = $D.Collate
                                    Color           = $D.Color
                                    Copies          = $D.Copies
                                    Duplex          = $D.Duplex
                                    PaperSize       = $D.PaperSize
                                    Orientation     = $D.Orientation
                                    PrintQuality    = $D.PrintQuality
                                    MediaType       = $D.MediaType
                                    DitherType      = $D.DitherType
                                    RetrievalDate   = (Get-Date -Format 'dd/MM/yyyy HH:mm')
                                }
                                $P | Add-Member -NotePropertyMembers $Prop -TypeName NoteProperty
                                Break
                            }
                        }
                    }
                    [PSCustomObject]@{
                        ComputerName   = $S.Name
                        ComputerStatus = 'Ok'
                        RetrievalDate  = (Get-Date -Format 'dd/MM/yyyy HH:mm')
                        Printers       = $Printers
                    }
                }
            }
            Catch {
                if (Test-Connection $S.Name -Count 2 -EA Ignore) {
                    [PSCustomObject]@{
                        ComputerName   = $S.Name
                        ComputerStatus = "ERROR: $($Error[0].Exception.Message)" 
                        RetrievalDate  = (Get-Date -Format 'dd/MM/yyyy HH:mm')
                        Printers       = $null
                    }
                }
                else {
                    [PSCustomObject]@{
                        ComputerName   = $S.Name
                        ComputerStatus = 'Offline'
                        RetrievalDate  = (Get-Date -Format 'dd/MM/yyyy HH:mm')
                        Printers       = $null
                    }
                }
            }
        }
    }
}

This function works fine in a mixed environment and gives us the full list of all the printers installed on a server with their properties. However, the property HostAddress (renamed to PortHostAddress in the function above) is not always populated.

This is also illustrated with the following code, as not all printers are in the output:

Get-WmiObject Win32_Printer -ComputerName $PrintServer | ForEach-Object { 
    $Printer = $_.Name
    $Port = $_.PortName
    Get-WmiObject Win32_TCPIpPrinterPort -ComputerName $PrintServer | where {$_.Name -eq $Port} | 
        select @{Name="PrinterName";Expression={$Printer}}, HostAddress 
}

For 90% of all printers the HostAddress can be found with this code. But sometimes it can't be found and the field stays empty because there is no match between the Name and the PortName.

Is there a better way of retrieving this property that works a 100% of the time?

DarkLite1
  • 13,637
  • 40
  • 117
  • 214
  • Hmm. Check what printers do not have a `HostAddress` populated, probably these are software-based printers like "Print to PDF" or similar. – Vesper Jul 03 '15 at 09:09
  • Solid advise Vesper, but I checked that already. These printers are normal printers, like say HP and Konica Minolta. On a list of over 500 printers we only have 12 that don't have the `PortHostAddress` populated. Other printers of the same brands on the same server don't have this problem. Very strange.. – DarkLite1 Jul 03 '15 at 10:27
  • 1
    Do they print anywhere? Do they have ports assigned? What are the types of those ports, if not IP_xxxx? (DOT_xxx, maybe, these use a WINS-type name resolution to find the printer) – Vesper Jul 03 '15 at 11:27
  • Great tip this one! Didn't think there would be different types of ports with regards to IP. The ones that don't have a `HostAddress` are the ones that don't have a `Standard TCP/IP Port` assigned but rather one of these types of port: `HP Standard TCP/IP Port`, `WSD Port`, `Local port`, `Advanced TCP/IP Port monitor`. So we found the culprit here :) How is it possible to retrieve these values? – DarkLite1 Jul 03 '15 at 11:46
  • Thank you Vesper. I think the best thing to do is to convert these to the `Microsoft Standard TCP/IP Port` as described [here](https://support.microsoft.com/nl-nl/kb/2411921). For now, I've updated the code as following: `$PortHostAddress = $Ports | Where {$_.Name -eq $P.PortName} | Select -ExpandProperty HostAddress $Prop = @{PortHostAddress = if($PortHostAddress){$PortHostAddress}else{"Not Standard TCP/IP Port"}` – DarkLite1 Jul 03 '15 at 12:03
  • If a port is of type "Local port" use the computer's IP address as host address (as these ports are purely software-based). For WSD ports, check here http://stackoverflow.com/questions/9089262/can-i-use-wmi-to-manage-wsd-devices-specifically-printers and for advanced ports, maybe convert em into standard ports as well (create new standard ports with same IP address+port combination, then reassign the printer to print through standard TCP/IP port and check if it works), if it won't work, try querying that type of ports for known attributes manually. – Vesper Jul 03 '15 at 12:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/82293/discussion-between-darklite1-and-vesper). – DarkLite1 Jul 03 '15 at 12:25

1 Answers1

1

Since the additional data states the problem ports are using drivers different from Microsoft's TCP/IP printer port driver, parsing these ports' addresses would require interacting with the drivers, this is dependant on the driver in question. So skip it, or convert a remote port to Microsoft's "Standard TCP/IP port" if possible. HP printers are easily converted, WSD printers can be converted by creating a TCP/IP port with the IP address of a WSD printer and assigning a static IP address on that printer, and about the same procedure could work with "Advanced TCP/IP port"s. The ports that are labeled "Local" ports are software-based, and you can use the host's IP address in place of missed PortHostAddress.

Vesper
  • 18,599
  • 6
  • 39
  • 61