Search code examples
powershellwmiprinters

PowerShell Printer port property hostaddress not always populated


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?


Solution

  • 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.