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