Reputation: 45
Hello :)
Hope you are doing fine today.
Well, I've been asked to pull out a report of all our Printers and the Drivers version they are utilizing (more than 1300 printers worldwide and 150+ Hosts).
At that point, I can retrieve most of the information I need.
Here's the code so far:
$ReportFileName = "c:\SAC_IS\printerreport.csv"
$PrintServersList="C:\SAC_IS\servlist_TEST.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="HostName";e={$server}} ,@{n="Driver Version";e={Get-WmiObject Win32_PrinterDriver -ComputerName $server | select @{n="Version";e={(Get-Item $_.DriverPath).VersionInfo.ProductVersion}}}}, Location,Comment,SpoolEnabled,Published
$allprinters += $printers
}
$allprinters | Export-CSV -Path $ReportFileName -Delimiter ";" -NoTypeInformation -Force -Encoding UTF8
My problem here is that I'm unable to retrieve the driver's version that the printer's using:
Running the script returns no errors at all :/
Can an hand be given please? :D
Subsidiary question, why the hell is it taking like 5 minutes per Host. Can't this be quicker?
Thanks a lot to everyone that can help :)
Upvotes: 0
Views: 4584
Reputation: 61028
Probably the main thing about your code is that, although you are working on remote machines, you use the local DriverPath to get the driver version and also do not specify the driver you are aiming for.
The code below uses a small helper function to get the driver version from the actual driver file on the server using the UNC path instead of the local path. Also, I think by using a function here can make the code more readable.
To try and speed things up, I'm using Get-CimInstance
instead of Get-WmiObject
and collect the objects without adding to a predefined array:
$ReportFileName = 'C:\SAC_IS\printerreport.csv'
$PrintServersList = 'C:\SAC_IS\servlist_TEST.txt'
function Get-PrinterProductVersion ($server, $printer) {
$prn = Get-CimInstance -ClassName Win32_PrinterDriver -ComputerName $server |
Where-Object { ($_.Name -split ',')[0] -eq $($printer.DriverName) }
if ($prn) {
# transform the local driver path into a UNC path
$path = Join-Path -Path "\\$server" -ChildPath ($prn.DriverPath -replace ':', '$')
(Get-Item $path).VersionInfo.ProductVersion
}
}
$allprinters = Get-Content -Path $PrintServersList | ForEach-Object {
# capture the server name in a self-defined variable
$server = $_
Write-Host "checking server $server ..."
Get-CimInstance -ClassName Win32_Printer -ComputerName $server |
Select-Object Name,Shared,ShareName,Local,DriverName,PortName,
@{Name = "HostName"; Expression = { $server }},
@{Name = "Driver Version"; Expression = { Get-PrinterProductVersion $server $_ }},
Location,Comment,SpoolEnabled,Published
}
# output on screen
$allprinters
# output to CSV file
$allprinters | Export-CSV -Path $ReportFileName -Delimiter ";" -NoTypeInformation -Force -Encoding UTF8
P.S. Personally, I wouldn't want a header with a space in its name like "Driver Version"
but that's up to you
I cannot test this myself, but perhaps you can speed this up if you let the servers themselves gather the wanted printer info.
Something like this:
$ReportFileName = 'C:\SAC_IS\printerreport.csv'
$PrintServersList = 'C:\SAC_IS\servlist_TEST.txt'
# create a scriptblock for each server to execute
$scriptBlock = {
function Get-PrinterProductVersion ($printer) {
# or try with 'Get-WmiObject -Class Win32_PrinterDriver' if Get-CimInstance not available
$prn = Get-CimInstance -ClassName Win32_PrinterDriver |
Where-Object { ($_.Name -split ',')[0] -eq $($printer.DriverName) }
if ($prn) { (Get-Item $prn.DriverPath).VersionInfo.ProductVersion }
}
# or try with 'Get-WmiObject -Class Win32_Printer' if Get-CimInstance not available
Get-CimInstance -ClassName Win32_Printer |
Select-Object Name,Shared,ShareName,Local,DriverName,PortName,
@{Name = "HostName"; Expression = { $env:COMPUTERNAME }},
@{Name = "Driver Version"; Expression = { Get-PrinterProductVersion $_ }},
Location,Comment,SpoolEnabled,Published
}
# create a list to gather all results from the servers
$allprinters = New-Object System.Collections.Generic.List[object]
Get-Content -Path $PrintServersList | ForEach-Object {
Write-Host "checking server $_ ..."
if (Test-Connection -ComputerName $_ -Count 1 -Quiet) {
$printers = Invoke-Command -ScriptBlock $scriptBlock -ComputerName $_
$allprinters.AddRange($printers)
}
else {
Write-Warning "Server $_ cannot be reached"
}
}
# output on screen
$allprinters
# output to CSV file
$allprinters | Export-CSV -Path $ReportFileName -Delimiter ";" -NoTypeInformation -Force -Encoding UTF8
Upvotes: 1
Reputation: 3923
Try it this way?
$servers | ForEach-Object {
$CurrentServer = $_
Write-Host "Checking $CurrentServer_ ..."
$Drivers = Get-PrinterDriver -ComputerName $CurrentServer | Select-Object Name, @{n="DriverVersion";e={ $ver = $_.DriverVersion;(3..0 | ForEach-Object { ($ver -shr ($_ * 16)) -band 0xffff }) -join '.'}}
Get-WmiObject -class Win32_Printer -Computername $CurrentServer | ForEach-Object {
$ThisPrintDriverName = $_.DriverName
$ThisDriver = $Drivers | Where-Object { $_.Name -eq $ThisPrintDriverName }
[pscustomobject]@{Name = $_.Name
Shared = $_.Shared
ShareName = $_.ShareName
Local = $_.Local
DriverName = $_.DriverName
PortName = $_.PortName
HostName = $CurrentServer
Location = $_.Location
Comment = $_.Comment
SpoolEnabled = $_.SpoolEnabled
Published = $_.Published
Driver = $ThisDriver.Name
Version = $ThisDriver.DriverVersion
}
}
}
Upvotes: 1