Add Printer Script Unique Print Drivers

For an automated installation it was necessary to have an up to date list of the printer drivers. As print manufactorers occassionally add a dozen printer drivers into one setup we wanted to have a script that connects to all on duty print servers. I used the function Add-PrinterDriver for this cause. In the RES Automation Manager script there was some code necessary to first add a feature if it wasn’t present:

Import-Module ServerManager
$RSATADPowerShell = Get-WindowsFeature -Name "RSAT-AD-PowerShell"
If ($RSATADPowerShell.Installed -match "False"){
Add-WindowsFeature RSAT-AD-PowerShell}

Then I added the function in another script:

Import-Module ActiveDirectory
#Functie Add-PrinterDriver
function Add-PrinterDriver { 
 [CmdletBinding()] 
         Param( 
              [Parameter(Mandatory=$true)] 
              [string] $PrintServer, 
              [switch] $Clean 
             ) 

#Collecting all shared printer objects from the specified print server 
$allprinters = @(Get-WmiObject win32_printer -ComputerName $PrintServer -Filter 'shared=true') 
#Defining all unique printer drivers from the specified print server 
$drivers = @($allprinters | Select-Object drivername -Unique) 
#Defining a collection containing the first printer object using a unique printer driver 
$printers = @() 
foreach ($item in $drivers){ 
$printers += @($allprinters | Where-Object {$_.drivername -eq $item.drivername})[0] 
} 

#Collecting locally installed drivers 
$localdrivers = @() 
foreach ($driver in (Get-WmiObject Win32_PrinterDriver)){ 
$localdrivers += @(($driver.name -split ",")[0]) 
} 

#Initializing the CurrentPrinter variable for use with Write-Progress 
$CurrentPrinter = 1 

#Looping through the printer objects collection, installing those who are not already installed on the local computer 
foreach ($printer in $printers) { 

Write-Progress -Activity "Installing printers..." -Status "Current printer: $($printer.name)" -Id 1 -PercentComplete (($CurrentPrinter/$printers.count) * 100) 

#Create hash-table for output object 
$outputobject = @{} 
$outputobject.drivername = $printer.drivername 

$locallyinstalled = $localdrivers | Where-Object {$_ -eq $printer.drivername} 
if (-not $locallyinstalled) { 
Write-Verbose "$($printer.drivername) is not installed locally" 
$AddPrinterConnection = Invoke-WmiMethod -Path Win32_Printer -Name AddPrinterConnection -ArgumentList ([string]::Concat('\', $printer.__SERVER, '', $printer.ShareName)) -EnableAllPrivileges 
$outputobject.returncode = $AddPrinterConnection.ReturnValue 
} 
else 
{ 
Write-Verbose "$($printer.drivername) is already installed locally" 
$outputobject.returncode = "Already installed" 
} 

#Create a new object for each driver, based on the outputobject hash-table 
New-Object -TypeName PSObject -Property $outputobject 

$CurrentPrinter ++ 

} 

#Deletes all printer connections for the current user 
if ($clean) { 
$printers = Get-WmiObject Win32_Printer -EnableAllPrivileges -Filter network=true 
if ($printers) { 
foreach ($printer in $printers) { 
$printer.Delete() 
} 
} 
} 
}

$OS = (Get-WmiObject Win32_OperatingSystem).Caption.replace("Microsoft ","").Replace("Standard ","Standard").Replace("Enterprise ","Enterprise").Replace("Datacenter ","Datacenter")
$ADPrintservers = Get-ADComputer -Filter * -Property * |Where {$_.name -like "PR*"} | select DNSHostName,OperatingSystem
$Pingable =@()
foreach ($computer in $ADPrintservers){
if (Test-Connection $Computer.DNSHostName -quiet) { $Pingable += $Computer}}
foreach ($Computer in $Pingable){
If ($OS -contains $Computer.OperatingSystem){
Add-PrinterDriver -Printserver $Computer.DNSHostName}}

The script above enumerates all servers starting with PR*. Next this script test whether the server is pingable or not. You could enter credentials if you disabled pinging to the Test-Connection command. Next it validates if the server has the same OS as the print server. Some print servers are around for the 32 bit environment. You can also add a filter for that. At the end it deletes the space that is somehow added to the replace part of OS variable.  The bare function is like this:

function Add-PrinterDriver { 
 [CmdletBinding()] 
         Param( 
              [Parameter(Mandatory=$true)] 
              [string] $PrintServer, 
              [switch] $Clean 
             ) 

#Collecting all shared printer objects from the specified print server 
$allprinters = @(Get-WmiObject win32_printer -ComputerName $PrintServer -Filter 'shared=true') 
#Defining all unique printer drivers from the specified print server 
$drivers = @($allprinters | Select-Object drivername -Unique) 
#Defining a collection containing the first printer object using a unique printer driver 
$printers = @() 
foreach ($item in $drivers){ 
$printers += @($allprinters | Where-Object {$_.drivername -eq $item.drivername})[0] 
} 

#Collecting locally installed drivers 
$localdrivers = @() 
foreach ($driver in (Get-WmiObject Win32_PrinterDriver)){ 
$localdrivers += @(($driver.name -split ",")[0]) 
} 

#Initializing the CurrentPrinter variable for use with Write-Progress 
$CurrentPrinter = 1 

#Looping through the printer objects collection, installing those who are not already installed on the local computer 
foreach ($printer in $printers) { 

Write-Progress -Activity "Installing printers..." -Status "Current printer: $($printer.name)" -Id 1 -PercentComplete (($CurrentPrinter/$printers.count) * 100) 

#Create hash-table for output object 
$outputobject = @{} 
$outputobject.drivername = $printer.drivername 

$locallyinstalled = $localdrivers | Where-Object {$_ -eq $printer.drivername} 
if (-not $locallyinstalled) { 
Write-Verbose "$($printer.drivername) is not installed locally" 
$AddPrinterConnection = Invoke-WmiMethod -Path Win32_Printer -Name AddPrinterConnection -ArgumentList ([string]::Concat('\', $printer.__SERVER, '', $printer.ShareName)) -EnableAllPrivileges 
$outputobject.returncode = $AddPrinterConnection.ReturnValue 
} 
else 
{ 
Write-Verbose "$($printer.drivername) is already installed locally" 
$outputobject.returncode = "Already installed" 
} 

#Create a new object for each driver, based on the outputobject hash-table 
New-Object -TypeName PSObject -Property $outputobject 

$CurrentPrinter ++ 

} 

#Deletes all printer connections for the current user 
if ($clean) { 
$printers = Get-WmiObject Win32_Printer -EnableAllPrivileges -Filter network=true 
if ($printers) { 
foreach ($printer in $printers) { 
$printer.Delete() 
} 
} 
} 
}

This function lets powershell connect to the printserver. It does a query on all shared printers. Then it sorts the results to unique values. At last it connects to that printer which causes the driver to be installed. There is a group policy necessary for this to work. The following policy settings are mandatory:

PointAndPrintRestrictions

 

This is a computer policy located at Computer Configuration –> Windows Settings –> Printers –> Point and Print Restrictions