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:
This is a computer policy located at Computer Configuration –> Windows Settings –> Printers –> Point and Print Restrictions