Re-mapping large number of printers with PowerShell

Recently, one of our bigger clients had request to migrate from old to new Print servers. This task also involved re-mapping printers on user side. So far the printers had been mapped manually and in the company with 10000+ users and over 1000 print queues spread over 3 Print servers this would be very difficult to accomplish withouth using some kind of automation process. I understand that some of you may ask why the printers are not being mapped properly through GPO + Security Goups process or why they just don`t use DNS CNAME option when they do the cutover to new Print server and I can assure you that it was part of discussion but customer decided to go with PowerShell and customer is always right.

Normal 0 false false false EN-US X-NONE X-NONE

So let`s see what are the challenges:

  • All the mappings are done manually so we need to automate the process of remapping
  • Figure out the way to deploy automation process (GPO or SCCM)
  • The client may also want to split one Print server in two and re-map users based on their AD attributes
  • There needs to be some kind of reporting implanted in the script for success\failure
  • Set the default printer the same as the old one but pointing to a different Print server
  • Remove old printer mappings from client workstation in the same process of re-mapping

After consultation, the client decided to go with the option of PowerShell script that will be deployed through GPO. This option had some drawbacks and here they are:

  • You will not be able to pull AD attributes directly from a client machine and that will prevent grouping users per their AD attributes and pointing them to desired Print server
  • Also, startup scripts do not execute over VPN during GPO processing
  • Using SCCM would be better option in this case since it would allow creation of collection based on AD attributes and better monitoring of script execution with less scripting

So finally, here is the basic script that we decided to use, it can easily be modified to suit your needs or if you want to expand it:

#Server name definition
$OldServerName1 = "prtserver1"
$NewServerName1 = "prtserver2"

$OldServerName2 = "prtserver3"
$NewServerName2 = "prtserver4"

$OldServerName3 = "prtserver5"
$NewServerName3 = "prtserver6 "

$DestinationPath = "c:\Temp\"
$FileName = "$ENV:ComputerName - $ENV:UserName.txt" 

#Create array

$OldServerNames = @(
    "$OldServerName1"
    "$OldServerName2"
    "$OldServerName3"
) 

$NewServerNames = @(
    "$NewServerName1"
    "$NewServerName2"
    "$NewServerName3"
)


#Get existing network printers
$CurrentPrinters = Get-WmiObject Win32_Printer |
Where-Object {($_.Network -eq "true") -and ($_.SystemName -eq "\\"+$OldServerName1 -or "\\"+$OldServerName2 -or "\\"+$OldServerName3)}

#Get default printer
$Defaultprinter = Get-WmiObject -Query " SELECT * FROM Win32_Printer WHERE Default=$true" | Select-Object -ExpandProperty ShareName

#Map the printers from a new server.
if ($CurrentPrinters | Select-Object -ExpandProperty Name | ForEach-Object {
$newprintername = $_ -Replace( "$OldServerName1", "$NewServerName1" ) -Replace( "$OldServerName2", "$NewServerName2" ) -Replace( "$OldServerName3", "$NewServerName3" )
Add-Printer -ConnectionName $newprintername

}){}
#Delete old printers
$CurrentPrinters | foreach{$_.delete()}

#Set default printer
(Get-WMIObject -ClassName win32_printer |Where-Object -Property ShareName -eq $Defaultprinter).SetDefaultPrinter()

#Get existing network printers for file output

$CurrentPrintersfileoutput = Get-WmiObject Win32_Printer | Where-Object {($_.Network -eq "true") -and ($_.SystemName -eq "\\"+$OldServerName1 -or "\\"+$OldServerName2 -or "\\"+$OldServerName3)}

#write file

if ($CurrentPrintersfileoutput.Systemname -match $OldServer)
{
    New-Item -Path $DestinationPath -Name $FileName -Force
    Add-Content -Path "$DestinationPath\$FileName" -Value $CurrentPrinters
}

As you can see it from a script, if you are deploying it through GPO you will most probably go with all the servers at once, while using SCCM would allow you to remove some parts of the scripts, og server by server, target groups of users based on their ad attirbutes (collection option in SCCM) and make it leaner.

Note: after some examintation and testing, everything executed correctly except reporting. It looks like because we use “replace” command in PowerShell that the variable is stored in the memory so it will create the report file regardles if the old server has been removed. Basically, it still creates report file, even if the script performs correctly and the old server is removed. I assume to tackle this you would have to clear all variables prior to reporting part of the script and define them again, and then let the reporting part of thescript run.

Let me know what you think in the comments, what would you do differently and make this script more efficent…

Authors

2 thoughts on “Re-mapping large number of printers with PowerShell

  1. Hi, some comments about the code
    – Delete old printers : could be added in the previous loop, after Add-Printer, for more efficiently
    – set default printer is based on that the legacy default printer share name will be the same. Perhaps, it could be better to do this in the previous foreach loop too. If the current printer is the default printer, then the NewPrinterName will be the new default printer.

    – I don’t understand $CurrentPrinterFIleOut. This get the list of network printers mapped from the Old Print Servers, but at this step the computer has no longer these network printers mapped. This coulb be $NewServerName1, ….

    – in the last if statement, you use a $oldserver var, but this one is not defined previoulsly in the script. If i understand what you need, you would add the New Printers in a log file. I’ll create output file before the main foreach loop, then, in the foreach loop i’ll add Add-Content -Path … -Value NewPrinterName

    What do you thnik about this suggest ?
    Regards
    Olivier

  2. Hi, they are all valid suggestions but there is some reasoning behind splitting things like deleting old printers to separate part of script. It`s easier to customer to manage script by themselves if they do not want to that part, or any other part for example.
    Regarding the part “$oldserver” var, I have typed it incorrectly. It should be the array “$OldServerNames” and it is meant to be a check if the old printers are still there (if the script has run successfully).