Use a PowerShell Logon Script To Update Printer Mappings

I was recently asked to come up with a PowerShell solution to re-map all of the printers in our domain from a 32 bit print server to a print server that was 64 bit. This had to be done at logon which meant that this needed to be a logon script. Fortunately we are running Windows 7 which means that this is a perfect candidate for a PowerShell logon script!

The requirements of this logon script are:

  • Requires no interaction by the user
  • Maps the same printer on the new server that was on the old server (the migrated servers kept the same printer name Old: \\Server1\B24-R New: \\Server2\B24-R)
  • Remove the old printer mapping
  • Write a logfile of the removal, adding and any errors encountered to a shared directory

The first requirement is pretty much a no-brainer. If you are writing a logon script, it had better not require any effort by the user. Luckily, we were able to take advantage of the feature in Windows 2008 R2 that allowed your Login Scripts for Group Policy to specify a PowerShell script as the logon script. This will automatically make sure that the script runs with the Bypass execution policy and runs it in a hidden window.

image

For the rest of the requirements, I will first show you the code and then explain how I met each requirement below.

Param (
    $newPrintServer = "Server2",
    $PrinterLog = "\\LogSVR\PrintMigration$\PrintMigration.csv"
)
<#
    #Header for CSV log file:
    "COMPUTERNAME,USERNAME,PRINTERNAME,RETURNCODE-ERRORMESSAGE,DATETIME,STATUS" | 
        Out-File -FilePath $PrinterLog -Encoding ASCII
#>

This part is the initial setup for the parameters to include the new print server and the log that will be used to track the mappings (meeting the requirement of the logging). The comment block is the code that should be ran first to setup the log file. Note: This script is assuming that you are running PowerShell V2. If running V3, you can skip this and actually update the Out-File commands with Export-Csv with the –Append parameter.

Try {
    Write-Verbose ("{0}: Checking for printers mapped to old print server" -f $Env:USERNAME)
    $printers = @(Get-WmiObject -Class Win32_Printer -Filter "SystemName='\\\\Server1'" -ErrorAction Stop)
    
    If ($printers.count -gt 0) {        
        ForEach ($printer in $printers) {
            Write-Verbose ("{0}: Replacing with new print server name: {1}" -f $Printer.Name,$newPrintServer)
            $newPrinter = $printer.Name -replace "Server1",$newPrintServer  
            $returnValue = ([wmiclass]"Win32_Printer").AddPrinterConnection($newPrinter).ReturnValue   

I first verify that there are still old print server mappings prior to proceeding with the logon script. Once that is done, I then iterate through each old printer mapping and do a –Replace of the old print server with a new one. This will then be used to attempt to map to the new print server.  I keep the returnvalue of the printer connection attempt using the Win32_Printer class and using the AddPrinterConnection() method. This is used in the next part of the script to determine the next action.

            If ($returnValue -eq 0) {
                "{0},{1},{2},{3},{4},{5}" -f $Env:COMPUTERNAME,
                                             $env:USERNAME,
                                             $newPrinter,
                                             $returnValue,
                                             (Get-Date),
                                             "Added Printer" | Out-File -FilePath $PrinterLog -Append -Encoding ASCII            
                Write-Verbose ("{0}: Removing" -f $printer.name)
                $printer.Delete()
                "{0},{1},{2},{3},{4},{5}" -f $Env:COMPUTERNAME,
                                             $env:USERNAME,
                                             $printer.Name,
                                             $returnValue,
                                             (Get-Date),
                                             "Removed Printer" | Out-File -FilePath $PrinterLog -Append -Encoding ASCII
            } Else {
                Write-Verbose ("{0} returned error code: {1}" -f $newPrinter,$returnValue) -Verbose
                "{0},{1},{2},{3},{4},{5}" -f $Env:COMPUTERNAME,
                                             $env:USERNAME,
                                             $newPrinter,
                                             $returnValue,
                                             (Get-Date),
                                             "Error Adding Printer" | Out-File -FilePath $PrinterLog -Append -Encoding ASCII
            }
        }
    }
} Catch {
    "{0},{1},{2},{3},{4},{5}" -f $Env:COMPUTERNAME,
                                 $env:USERNAME,
                                 "WMIERROR",
                                 $_.Exception.Message,
                                 (Get-Date),
                                 "Error Querying Printers" | Out-File -FilePath $PrinterLog -Append -Encoding ASCII
}

The rest of the code handles what happens based on the returnvalue. If the value is 0, that means that the connection was successful and logged. Anything else is considered a failure and will then be logged as such. With the successful connection, the removal of the other printer mapping is then performed. Once completed, that is then logged and the process continues until all of the printers have been taken care of. An example of the logfile is below:

image

Pretty simple but gets the job done with no user interaction and any errors, failures to map printers are kept away from the user and logged to the remote log file for future review/troubleshooting by the system administrators.

Feel free to take the code below and use/modify to your liking.

Full Code

<#
    .SYNOPSIS
        Logon Script to migrate printer mapping
    
    .DESCRIPTION
        Logon Script to migrate printer mappings
    
    .NOTES
        Author: Boe Prox
        Create: 09 NOV 2012
        Modified:
        Version 1.0 - Initial Script Creation
                1.1 Added Header Text for CSV file
#>
Param (
    $newPrintServer = "Server2",
    $PrinterLog = "\\LogSVR\PrintMigration$\PrintMigration.csv"
)
<#
    #Header for CSV log file:
    "COMPUTERNAME,USERNAME,PRINTERNAME,RETURNCODE-ERRORMESSAGE,DATETIME,STATUS" | 
        Out-File -FilePath $PrinterLog -Encoding ASCII
#>
Try {
    Write-Verbose ("{0}: Checking for printers mapped to old print server" -f $Env:USERNAME)
    $printers = @(Get-WmiObject -Class Win32_Printer -Filter "SystemName='\\\\Server1'" -ErrorAction Stop)
    
    If ($printers.count -gt 0) {        
        ForEach ($printer in $printers) {
            Write-Verbose ("{0}: Replacing with new print server name: {1}" -f $Printer.Name,$newPrintServer)
            $newPrinter = $printer.Name -replace "Server1",$newPrintServer  
            $returnValue = ([wmiclass]"Win32_Printer").AddPrinterConnection($newPrinter).ReturnValue                
            If ($returnValue -eq 0) {
                "{0},{1},{2},{3},{4},{5}" -f $Env:COMPUTERNAME,
                                             $env:USERNAME,
                                             $newPrinter,
                                             $returnValue,
                                             (Get-Date),
                                             "Added Printer" | Out-File -FilePath $PrinterLog -Append -Encoding ASCII            
                Write-Verbose ("{0}: Removing" -f $printer.name)
                $printer.Delete()
                "{0},{1},{2},{3},{4},{5}" -f $Env:COMPUTERNAME,
                                             $env:USERNAME,
                                             $printer.Name,
                                             $returnValue,
                                             (Get-Date),
                                             "Removed Printer" | Out-File -FilePath $PrinterLog -Append -Encoding ASCII
            } Else {
                Write-Verbose ("{0} returned error code: {1}" -f $newPrinter,$returnValue) -Verbose
                "{0},{1},{2},{3},{4},{5}" -f $Env:COMPUTERNAME,
                                             $env:USERNAME,
                                             $newPrinter,
                                             $returnValue,
                                             (Get-Date),
                                             "Error Adding Printer" | Out-File -FilePath $PrinterLog -Append -Encoding ASCII
            }
        }
    }
} Catch {
    "{0},{1},{2},{3},{4},{5}" -f $Env:COMPUTERNAME,
                                 $env:USERNAME,
                                 "WMIERROR",
                                 $_.Exception.Message,
                                 (Get-Date),
                                 "Error Querying Printers" | Out-File -FilePath $PrinterLog -Append -Encoding ASCII
}

About Boe Prox

Microsoft Cloud and Datacenter MVP working as a SQL DBA.
This entry was posted in powershell, scripts and tagged , , . Bookmark the permalink.

6 Responses to Use a PowerShell Logon Script To Update Printer Mappings

  1. Danish says:

    When I attempted to use the script, the print queues from the old print server still exists.

  2. Noah says:

    script works great, however it doesn’t reset the default printer back to what it was originally (if it was network mapped to the old server), here’s the code for that:

    #Store the value of the old default printer before the script runs, goes at the top of the script
    $defaultPrinter = gwmi win32_printer | where {$_.Default -eq $true}

    #This code runs after the inital if statement
    # Gets new list of printers that are pointed to newserver
    $newPrinterList = @(Get-WmiObject -Class Win32_Printer -Filter “SystemName=’\\newserver'” -ErrorAction Stop)
    # iterates through each new printer and compares the ShareName to the old ShareName that was the user’s default printer and sets it
    ForEach ($printer in $newPrinterList) {
    If ($printer.ShareName -eq $defaultPrinter.ShareName) {
    $printer.SetDefaultPrinter()
    }

    }

  3. Chris says:

    Great script! Works wonders. I’ve added two lines to give it the ability to keep the default printer.
    Added it to my wordpress site. Thanks again!

    http://chris-nullpayload.rhcloud.com/2014/06/powershell-login-script-to-update-printer-mappings-and-keep-the-default-printer/

  4. trentliffick says:

    How could you use this script to migrate the user’s default print queue? Sorry, I’m new to powershell and I’m struggling… I was hoping you could get me a nice push in the right direction.

    Thanks!

  5. Did you encounter any issues with printers that were mapped to the server via print server IP?

    • Boe Prox says:

      No issues with IPs only because no one was mapped via IP. But that does bring up a good point to add some more code to handle those users that are mapped to a printer via an IP address instead of hostname.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s