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