none
Get printer names, IP addresses and drivers from a computer using WMI. RRS feed

  • Question

  • Hello, 

    I want to create a list of printers and their corresponding ip addresses 

    I managed to get the information I need using the following two commands:

    get-wmiobject win32_printer | select name

    get-wmiobject win32_tcpipprinterport | select hostaddress

    And then manually combining the two. But I would like to merge the information using one output.

    I followed  the following guide from the link:

    https://blogs.technet.microsoft.com/heyscriptingguy/2013/07/16/query-multiple-wmi-classes-but-return-one-object-with-powershell/

    And tried the following commands:

    $printer = gwmi -class win32_printer
    $ip = gwmi -class win32_tcpipprinterport

    $properties = @{'name' = $printer.name ; 'driver'= $printer.drivername ; 'ip' = $ip.hostaddress}

     New-Object -TypeName PSCustomObject -Property $Properties

    The output I get looks like this:

    PS C:\temp> $printerinfo

    ip                                       name                                     driver
    --                                       ----                                     ------
    {10.154.24.22, 10.10.10.10.}             {printer2000, OKI B4350 PS (MS), prin... {Brother DCP-117C, OKI B4350 PS (MS)..

    The information seems to be correct but the format is wrong. 

    It needs to be in table format where the name corresponds to the ip address

    How do I get the correct format?




    • Edited by Nirwaiz Tuesday, February 23, 2016 3:50 PM
    Tuesday, February 23, 2016 3:43 PM

Answers

  • I think you are probably wanting something like this?


    # Collect port names and host addresses into hash table
    $hostAddresses = @{}
    Get-WmiObject Win32_TCPIPPrinterPort | ForEach-Object {
      $hostAddresses.Add($_.Name, $_.HostAddress)
    }
    
    Get-WmiObject Win32_Printer | ForEach-Object {
      New-Object PSObject -Property @{
        "Name" = $_.Name
        "DriverName" = $_.DriverName
        "HostAddress" = $hostAddresses[$_.PortName]
      }
    }
    


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by Nirwaiz Wednesday, February 24, 2016 8:19 AM
    Tuesday, February 23, 2016 4:48 PM
    Moderator

All replies

  • I think you are probably wanting something like this?


    # Collect port names and host addresses into hash table
    $hostAddresses = @{}
    Get-WmiObject Win32_TCPIPPrinterPort | ForEach-Object {
      $hostAddresses.Add($_.Name, $_.HostAddress)
    }
    
    Get-WmiObject Win32_Printer | ForEach-Object {
      New-Object PSObject -Property @{
        "Name" = $_.Name
        "DriverName" = $_.DriverName
        "HostAddress" = $hostAddresses[$_.PortName]
      }
    }
    


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by Nirwaiz Wednesday, February 24, 2016 8:19 AM
    Tuesday, February 23, 2016 4:48 PM
    Moderator
  • WMI is like a relational database. Her is how to get the associated port:

    gwmi win32_printer |%{$_.GetRelated('win32_tcpipprinterport')}

    Here is how to combine them:

    get-wmiobject win32_printer |
    	ForEach-Object{
    		$port = $_.GetRelated('win32_tcpipprinterport').hostaddress
    		$_ | Add-Member NoteProperty PortIPAddress $port -PassThru
    	}|
    	select Name, ShareName, PortIPAddress
    


    \_(ツ)_/

    Tuesday, February 23, 2016 5:51 PM
  • My computer has no associator class for Win32_Printer and Win32_TCPIPPrinterPort, so this returns no results for me:


    Get-WmiObject Win32_Printer | ForEach-Object {
      $_.GetRelated("Win32_TCPIPPrinterPort")
    }
    

    However I can collect the port names and host addresses in a hashtable and look them up manually as I demonstrated in my example.


    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 6:10 PM
    Moderator
  • My computer has no associator class for Win32_Printer and Win32_TCPIPPrinterPort, so this returns no results for me:


    Get-WmiObject Win32_Printer | ForEach-Object {
      $_.GetRelated("Win32_TCPIPPrinterPort")
    }
    

    However I can collect the port names and host addresses in a hashtable and look them up manually as I demonstrated in my example.


    -- Bill Stewart [Bill_Stewart]

    That I correct.  You cannot associate a TCPIP port to anything but a port enabled printer.  Locally attached printer shares will never have a port.  Printers like HP on Wireless may not have a port.  They will have a WDM: port type but n IP port.

    If you remote to a machine using the -computer parameter you can get the remote printers like this. You can also inspect the port type and get other kinds of ports.

    Using Associators Of can actually do it all in one crack because it can look at the inheritance ad attach to any class that is a "port" of any kind.


    \_(ツ)_/


    • Edited by jrv Tuesday, February 23, 2016 7:01 PM
    Tuesday, February 23, 2016 7:01 PM
  • What I am saying is that your code simply does not work at all on my computer: It returns nothing.

    The code I posted, however, works, for the reasons I already explained.


    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 7:38 PM
    Moderator
  • Do you have a directly attached TCPIP printer that is assigned a TCPIP port resource?

    \_(ツ)_/

    Tuesday, February 23, 2016 7:40 PM
  • gwmi win32_printer |select portname

    Port names for IP ports usually look like an IP.

    I have a printer that is IPed.  Here are the ports:

    nul:
    WSD-b49b0a2e-8a48-4352-8bba-e23aa707904d.0067
    PORTPROMPT:
    PORTPROMPT:
    LPT1:
    FOXIT_PDF:
    SHRFAX:

    Note that the WSD pronter (HP) does not use the IP port/


    \_(ツ)_/

    Tuesday, February 23, 2016 7:42 PM
  • Right, but the port name might not match its HostAddress. (Take a look at the Win32_TCPIPPrinterPort properties.)

    Take a look at my code, and you can see that I am already aware of the PortName property of Win32_Printer.

    This is why I gather all the TCP/IP ports by querying Win32_TCPIPPrinterPort first and create a hash table of the Name and HostAddress properties. This makes it easy to look up HostAddress for each printer using the hash table.


    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 7:49 PM
    Moderator
  • Sorry.  It has been a while nd I forgot which bits were connected.  Here is a usable bit.

    gwmi win32_printer -filter 'name = "hp test"' | 
    %{
    	$config=$_.GetRelated('Win32_PrinterConfiguration')
    	$port=gwmi Win32_TCPIPPrinterPort -Filter "Name = '$($_.portname)'"
    	$driver=$_.GetRelated('Win32_PrinterDriver')
    	$_|Add-Member NoteProperty TCPIpPort $port
    	$_ | Add-Member NoteProperty Driver $driver
    	$_|Add-Member NoteProperty Configuration $config -PassThru
    }
    

    I had to build one so I could test it.

    This brings back all related information.  To get only  ported printers we would do it backwards by pulling all ports and finding the relations back to the Win23_Printer object.


    \_(ツ)_/

    Tuesday, February 23, 2016 7:59 PM
  • Here is how to get only IP attached printers:

    Get-WMiObject Win32_tcpipprinterport |%{gwmi Win32_Printer -Filter "Portname='$($_.Name)'"}

    Combined:

    Get-WMiObject Win32_TCPIPPrinterPort | 
    %{ gwmi Win32_Printer -Filter "Portname='$($_.Name)'" } |
    %{
    	$config=$_.GetRelated('Win32_PrinterConfiguration')
    	$port=gwmi Win32_TCPIPPrinterPort -Filter "Name = '$($_.portname)'"
    	$driver=$_.GetRelated('Win32_PrinterDriver')
    	$_|Add-Member NoteProperty TCPIpPort $port
    	$_ | Add-Member NoteProperty Driver $driver
    	$_|Add-Member NoteProperty Configuration $config -PassThru
    }
    

    It is really nice having an editor that autocompletes on WMI classes methods and properties.


    \_(ツ)_/

    Tuesday, February 23, 2016 8:11 PM
  • Your query is getting Win32_TCPIPPrinterPort based on the PortName property of the Win32_Printer object. That might not match the HostAddress. It's also fairly inefficient because you are running a separate "Get-WmiObject Win32_TCPIPPrinterPort" query for every Win32_Printer instance (not in your example, since you are filtering for one object, but it will be slower if you don't limit your query).

    That's why I am doing this first:


    $hostAddresses = @{}
    Get-WmiObject Win32_TCPIPPrinterPort | ForEach-Object {
      $hostAddresses.Add($_.Name, $_.HostAddress)
    }
    



    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 8:12 PM
    Moderator
  • The portname matches the name of the tcpipprinterport instance.

     I was not saying you code was wrong only that using other methods makes gathering the data easier sometimes.  I just didn't remember that the port class is an outlier and nees to be linked manually.


    \_(ツ)_/

    Tuesday, February 23, 2016 8:26 PM
  • Correct, the port name matches the Win32_TCPIPPrinterPort instance.

    However, the PortName property of the Win32_TCPIPPrinterPort instance might not match the HostAddress property.

    To get the actual HostAddress property, you need to retrieve it from the Win32_TCPIPPrinterPort instance.

    One fast way to do that is to query Win32_TCPIPPrinterPort once and collect the Name and HostAddress property in a hash table, as in my example.

    Then you don't need to query Win32_TCPIPPrinterPort anymore. One and done. Just look up the host address from the hash table.


    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 8:34 PM
    Moderator
  • I didn't mean to imply that it would only that, by default, the name is based on the IP.  I believe I said  that it didn't have to be.  I was not in that for visuals so you could look for a printers with portnames that might be tcpip ports.  The solution I posted is the most reliable was to get all port attached printers.

    \_(ツ)_/

    Tuesday, February 23, 2016 8:43 PM
  • My example returns the HostAddress property, but yours does not. Your example returns the Name property of the Win32_TCPIPPrinterPort instances, but mine returns the HostAddress property, which is what the OP was wanting, I believe. My example will also run faster, particularly as the number of printers increases, because I am querying all Win32_TCPIPPrinterPort instances in one query, whereas your example runs multiple queries (one for each printer).

    Because of these differences, I believe that my example is closer to what the OP was looking for.


    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 9:10 PM
    Moderator
  • My example returns everything.

    Get-WMiObject Win32_TCPIPPrinterPort | 
    %{ gwmi Win32_Printer -Filter "Portname='$($_.Name)'" } |
    %{
    	$config=$_.GetRelated('Win32_PrinterConfiguration')
    	$port=gwmi Win32_TCPIPPrinterPort -Filter "Name = '$($_.portname)'"
    	$driver=$_.GetRelated('Win32_PrinterDriver')
    	$_|Add-Member NoteProperty TCPIpPort $port
    	$_ | Add-Member NoteProperty Driver $driver
    	$_|Add-Member NoteProperty Configuration $config -PassThru
    } 

    Notice I have returned the full objects.  Use computed properties to extract what you need.

    I also return all driver info and all configuration info.


    \_(ツ)_/


    • Edited by jrv Tuesday, February 23, 2016 9:16 PM
    Tuesday, February 23, 2016 9:15 PM
  • This shows how all bits can be retrieved very easily.

    function Get-TCPIpPrintrInfo{
    	param(
    		$computer=$env:COMPUTERNAME
    	)
    	Get-WMiObject Win32_TCPIPPrinterPort -ComputerName $computer| 
    	%{ gwmi Win32_Printer -Filter "Portname='$($_.Name)'" } |
    	%{
    		$config=$_.GetRelated('Win32_PrinterConfiguration')
    		$port=gwmi Win32_TCPIPPrinterPort -Filter "Name = '$($_.portname)'"
    		$driver=$_.GetRelated('Win32_PrinterDriver')
    		$_|Add-Member NoteProperty TCPIpPort $port
    		$_ | Add-Member NoteProperty Driver $driver
    		$_|Add-Member NoteProperty Configuration $config -PassThru
    	}
    }
    Get-TCPIpPrintrInfo |
    select *, @{ n = 'HostAddress'; e = { $_.TCPIpPort.HostAddress } },
        @{ n = 'DriverPath'; e = { $_.Driver.DriverPath } },
        @{ n = 'DriverVersion'; e = { $_.Driver.Version } }


    \_(ツ)_/


    • Edited by jrv Tuesday, February 23, 2016 9:42 PM
    Tuesday, February 23, 2016 9:39 PM
  • This way seems a bit shorter and more efficient...


    $hostAddresses = @{}
    Get-WmiObject Win32_TCPIPPrinterPort | ForEach-Object {
      $hostAddresses.Add($_.Name, $_.HostAddress)
    }
    
    Get-WmiObject Win32_Printer | ForEach-Object {
      $_ | Add-Member HostAddress $hostAddresses[$_.PortName] -PassThru
    } | Select-Object Name,DriverName,HostAddress
    



    -- Bill Stewart [Bill_Stewart]


    Tuesday, February 23, 2016 9:58 PM
    Moderator
  • Except you are missing half of what was asked for.

    \_(ツ)_/

    Tuesday, February 23, 2016 10:32 PM
  • Sorry; I don't see what you're talking about. The original question mentioned printer name, host address, and driver name.

    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 10:45 PM
    Moderator
  • Sorry; I don't see what you're talking about. The original question mentioned printer name, host address, and driver name.

    -- Bill Stewart [Bill_Stewart]

    Says "Drivers" which is more ambiguous.

    Like I said.  I am not saying thisi better or more efficient or sexier.  I am just showing how to get all of the info once and customize it as needed.  It is not a competition.


    \_(ツ)_/

    Tuesday, February 23, 2016 10:51 PM
  • Right; not a competition. But it's always fun to get the last word in, isn't it? <grin>


    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 10:59 PM
    Moderator
  • Right; not a competition. But it's always fun to get the last word in, isn't it? <grin>


    -- Bill Stewart [Bill_Stewart]


    Ok - you win. ;)

    \_(ツ)_/

    Tuesday, February 23, 2016 11:07 PM
  • I knew you wouldn't be able to resist. <grin>

    -- Bill Stewart [Bill_Stewart]

    Tuesday, February 23, 2016 11:10 PM
    Moderator
  • Thanks! your solutions were very helpful.
    Wednesday, February 24, 2016 8:22 AM
  • Hi Bill,

    Thank you for this. I am learning how to do more with the shell every day. Could you please advise how one would know the "[$_.PortName]" bit and how it fits with the variable/hash table (forgive incorrect name) and what importance the "-PassThru" part holds.

    Thank you in advance.

    Kind regards,

    G S Gill

    Wednesday, June 13, 2018 2:38 PM
  • In Case anyone needs it , this script takes a list of print servers an builds a CSV with some useful info like sharename,location, Comment, Device IP, Driver and some more info.

    $ReportFileName = "c:\temp\printerreport.csv" 
    $PrintServersList="c:\temp\PrintServersList.txt" 
    
    $servers =  Get-Content -Path $PrintServersList 
    $allprinters = @() 
    foreach( $server in $servers ){ 
    Write-Host "checking $server ..." 
    $printers = $null 
    $printers = Get-WmiObject -class Win32_Printer -computername $server | select Name,Shared,ShareName,Local, DriverName, PortName,@{n="PrinterIp";e={(((gwmi win32_tcpipprinterport -ComputerName $server -filter "name='$($_.PortName)'") | select HostAddress).HostAddress)}},@{n='PrintServer';e={$_.SystemName}}, Location,Comment,SpoolEnabled,Published
    $allprinters += $printers 
     } 
     Write-Host "exporting to printers.csv" 
    $allprinters | Export-CSV -Path $ReportFileName -NoTypeInformation -Force -Encoding UTF8
    Write-Host "Done!"

    Wednesday, January 30, 2019 7:52 AM