Orange County, Tustin, CA 92780

Remap Printers to New Server Using Powershell and RMM

Recently, we had a client migrate printers to a new print server from Windows Server 2012 to Windows Server 2019. All their printer mappings on the clients needed to be updated; printer ports and printer names would remain the same, but the print server name would change.

Using group policy would not be an option because they work in a hybrid environment. We wanted to deploy a solution for both onsite and remote workers and not recreate the wheel using both Intune and Group Policy. Basically, they wanted to keep it clean and very transparent to the end-user. 

We had a PowerShell script that would remap a printer from past work, but we'd always give it to onsite IT staff. They would initiate remote assistance into each user's computer and run the script while they were logged on since the printer mappings are per user and not per computer. When you have a small number of employees, it's no big deal, but once you reach a certain threshold, then it becomes a nightmare of tracking them down and coordinating a time to do the work. 

Our task was to create a PowerShell script that could target all users and update their printer mappings using a Remote Monitor and Manage (RMM) tool to quickly accomplish the request. However, when using an RMM tool, we quickly learned that PowerShell is run as the System account on each computer, which wouldn't work. Out-of-the-box default configurations would not work and we had to find a way for PowerShell to run as the user.

As stated earlier, we had a script that we had modified and had worked for us, but in this case, additional work needed to be done for two reasons: (1) run as the logged-on user and (2) execute the script from an RMM tool.

To give credit where it's due, the original script we found can be located here: Re-mapping large number of printers with PowerShell. See that link for an explanation of how the script works. 

DangerDanger:

When running any of the scripts, make sure that both your old and new printer servers are up and reachable on the network. This script will not work if your old print server has been decommissioned or if you're attempting to remap the printers before your new print server is up. You could end up with all the printer mappings deleted, so make sure to have both servers up and test this with a small group of users.  

Our initial modified script is shown here prior to making the changes to run as the logged-on user

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned#Server name definition
$OldServerName1 = "printserver01"
$NewServerName1 = "printserver02"
$DestinationPath = "c:\Temp\"
$FileName = "$ENV:ComputerName - $ENV:UserName.txt"
 
#Create array
 
$OldServerNames = @(
 "$OldServerName1"
) 
 
$NewServerNames = @(
 "$NewServerName1"
)
 
 
#Get existing network printers
$CurrentPrinters = Get-WmiObject Win32_Printer |
Where-Object {($_.Network -eq "true") -and ($_.SystemName -eq "\\"+$OldServerName1)}
 
#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" )
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)}
 
#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, we only have one print server we're migrating from and the array values of "$OldServerName1" and "$NewServerName1" reflect that. If you have multiple servers you're migrating to, you'll add new variables with incremental values of 2, 3, etc...

Now it's time to update the script so that it can run as the logged-on user and run from our RMM migrate printers to new server.

 

install-module RunAsUser -force
$scriptblock = {
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
#Server name definition$OldServerName1 = "printserver01"$NewServerName1 = "printserver02" $DestinationPath = "c:\Temp\"$FileName = "$ENV:ComputerName - $ENV:UserName.txt" #Create array $OldServerNames = @(    "$OldServerName1") $NewServerNames = @(    "$NewServerName1")  #Get existing network printers$CurrentPrinters = Get-WmiObject Win32_Printer |Where-Object {($_.Network -eq "true") -and ($_.SystemName -eq "\\"+$OldServerName1)} #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" )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)} #write file if ($CurrentPrintersfileoutput.Systemname -match $OldServer){    New-Item -Path $DestinationPath -Name $FileName -Force    Add-Content -Path "$DestinationPath\$FileName" -Value $CurrentPrinters}}
invoke-ascurrentuser -scriptblock $scriptblock -UseWindowsPowerShell

The modified code is highlighted in lines 1, 4, 58, and 61.

Line 1 installs the necessary module named "RunAsUser" to run as the user and we use the "-force" switch to make sure it installs otherwise we got errors getting it to install and load properly.

Line 4 and 58 enclose our original script inside a variable called $scriptblock.

Line 61 calls the invoke-ascurrentuser cmdlet from the "RunAsUser" module, runs the scriptblock called $scriptblock, and the "-UseWindowsPowerShell" switch is only necessary if it won't run properly with your RMM. 

Now all you have to do is test it using your RMM tool and if there are no issues, upload it to your script library to run against multiple computers.

 

Byron Zepeda

Byron Zepeda is a Senior Systems Engineer in Orange County, California, working with VMware vSphere, Citrix Virtual Apps, backups, and storage. As cloud technologies and automation become first-class citizens within IT organizations, he desires to share everything he learns and pass it on to others.