Update Printer Mappings And Keep The Default Printer

This topic contains 8 replies, has 4 voices, and was last updated by Profile photo of Michal Rejman Michal Rejman 1 year ago.

  • Author
    Posts
  • #16753
    Profile photo of Michael Burutzis
    Michael Burutzis
    Participant

    Hi all,

    I am a big time newbie with scripting in general and looking for some help.

    I have found the following script on another website to update printers and there is a part in that script that it is supposed to keep the default printer. The only error I get is the following:

    Exception calling "SetDefaultPrinter" with "1" argument(s): "There is no printer called "Lex-Finance"."

    At \\server1\SYSVOL\domain.org\scripts\remap-printers-printserver.ps1:70 char:67

    + (New-Object -ComObject WScript.Network).SetDefaultPrinter <<<< ($default.S hareName) + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ComMethodTargetInvocation Another question I had is how can I move multiple print servers in this script? I currently have 2 print servers and I am consolidating to 1 server. Can I add two old print server names? This script is run from the logon script and run on all users. Thank you very much for all help! Michael This is the script: —————————————————————————————– Param ( $newPrintServer = "svrprint1", $PrinterLog = "\\file\share\PrintMigration.csv" ) Try { Write-Verbose ("{0}: Checking for printers mapped to old print server" -f $Env:USERNAME) $default = Get-WmiObject -Class Win32_Printer -Filter "Default='True'" -ErrorAction Stop $printers = @(Get-WmiObject -Class Win32_Printer -Filter "SystemName='\\\\svrprint'" -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 "svrprint",$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 } (New-Object -ComObject WScript.Network).SetDefaultPrinter($default.ShareName) —————————————————————————————–

  • #16756
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    First, it's good you are giving Powershell a shot. If you are an administrator, it's a necessity to know some scripting, especially Powershell with products today.

    To answer your question directly, the .SetDefaultPrinter() method is looking for the Name of the printer, not the ShareName. You didn't mention what kind of numbers you have in your environment, but you are using a SINGLE log file for every computer running a login script. So, if you have 300 people in your environment and Monday @ 8:00 there are 100 people logging in, that file is going to open by someone and the script is going to try to access the log causing that computer to lose it's logging. You might get 80% logging, but 20% are going to get errors. A better practice is to create a log just for that computer (e.g. MYCOMPUTER_PrintMigration.csv) and then have another script compile all of the logs into a single CSV for review. (If you need assistance with that script, we can assist too, but you should at least give it a whack first 🙂 )

    By default, Powershell has the ability to Import, Export and even ConvertTo CSV format. It should be leveraged if you want to dump to a CSV, to generate a PSObject versus a string. So, I took a whack at updating your code to generate a custom PSObject. I added some columns to make it easier to filter your results. You can go into your Powershell console and just do:

    $csv = Import-CSV "\\file\share\Final_PrintMigration.csv" #final_ would be the compiled CSV of all logs
    $csv | Where{$_Added -ne $true} | Select ComputerName, UserName, Date, StatusMessage
    

    Viola! You have all entries that have failed. You could do Export-CSV and send to Desktop Support or run a script to re-mediate the issue you're having. As far as the default printer, what you need to do is check if the current printer ShareName you are processing is the same ShareName of the default printer you gathered and if it matches attempt to set it as the default printer. Take a look at the script below and give it a shot. I did not test it, but it should be close to what you are looking to do:

    Param (
        $newPrintServer = "svrprint1",
        $PrinterLog = "\\file\share\{0}_PrintMigration.csv" -f $Env:COMPUTERNAME
    )
    
    $log = @()
    
    if (Test-Path $PrinterLog) {
        #pull in the current log to 'Append' new logging
        $log += Import-CSV $printerLog
    }
    
    Try {
        Write-Verbose ("{0}: Checking for printers mapped to old print server" -f $Env:USERNAME)
        $printers = @(Get-WmiObject -Class Win32_Printer -Filter "SystemName='\\\\svrprint'" -ErrorAction Stop)
        $default = Get-WmiObject -Class Win32_Printer -Filter "Default='True'" -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 "svrprint",$newPrintServer
                $returnValue = ([wmiclass]"Win32_Printer").AddPrinterConnection($newPrinter).ReturnValue
                If ($returnValue -eq 0) {
                    try {
                        #Deleting the printer is usually the biggest issue
                        #when doing this type of migration.  You need to capture
                        #if the delete was successful during your testing if the
                        #event your code needs updated.  Many scripts use WMI to enumerate
                        #and WScript.Network to map and delete the old printer
                        $printer.Delete()
                        $deleted = $true
                    }
                    catch {
                        $deleted = $false
                    }
                    $added = $true
    
                    $defaultPrt = $null
                    if ($default.ShareName -eq $printer.ShareName) {
                        (New-Object -ComObject WScript.Network).SetDefaultPrinter($default.ShareName)
                        $defaultPrt = " [DEFAULT] "
                    }
    
                    $StatusMsg = $("Successfully added {0} {1} with return value {2}" -f $newPrinter,$defaultPrt,$returnValue)
                }
                Else {
                    Write-Verbose ("{0} returned error code: {1}" -f $newPrinter,$returnValue) -Verbose
                    $added = $false
                    $StatusMsg = $("Failed adding {0} with return value {1}" -f $newPrinter,$returnValue)
                } #if ret val
            } #if count
    
            $props = @{
                ComputerName=$Env:COMPUTERNAME
                UserName=$Env:USERNAME
                OldPrinter = $("\\{0}\{1}" -f $printer.SystemName, $printer.ShareName)
                Printer = $newPrinter
                Added = $added
                Deleted = $deleted
                StatusMessage = $StatusMsg
                Date = $(Get-Date)
            }
    
            $log += New-Object -TypeName PSObject -Property $props
        } #foreach printer
    }#try
    Catch {
        $props = @{
            ComputerName=$Env:COMPUTERNAME
            UserName=$Env:USERNAME
            OldPrinter = "N\A"
            Printer = "N\A"
            Added = "N\A"
            Deleted = "N\A"
            StatusMessage = $StatusMsg = "WMIERROR: {0}" -f $_.Exception.Message
            Date = $(Get-Date)
        }
            
        $log += New-Object -TypeName PSObject -Property $props
    }
    
    $log | Export-CSV $PrinterLog -Force -NoTypeInformation
    

    Edit: Updated $log = Import-CSV $printerLog to use +=

  • #16757
    Profile photo of Vern Anderson
    Vern Anderson
    Participant

    I wish I can help but I hate working with printers because of my years as a Citrix MetaFrame Administrator.

    Printers became a huge hassle.

    I can quickly offer this idea the "default" printer is a registry setting but because each driver creates a very different looking key I can't provide an example that would work every time for you. However I prefer to work with the PSProvider "HKLM:"

    [url]http://support.microsoft.com/kb/156212[/url]

    -VERN

  • #16758
    Profile photo of Vern Anderson
    Vern Anderson
    Participant

    [b]Get-PSProvider[/b]

  • #16762
    Profile photo of Michael Burutzis
    Michael Burutzis
    Participant

    Hello Rob,

    Thanks for the encouragement. I am trying to understand bit by bit how powershell works. When scripts get too evolved, I get totally lost.LOL. I tested the code you added and keep getting this error:
    ethod invocation failed because [System.Management.Automation.PSObject] doesn't contain a method named 'op_Addition'.
    t \\dc1\NETLOGON\remap-printers-all-printserver.ps1:79 char:12
    $log += <<<< New-Object -TypeName PSObject -Property $props + CategoryInfo : InvalidOperation: (op_Addition:String) [], RuntimeException Also, I have two print servers to migrate. Would it be a good idea to run 2 scripts each using 1 print server? As for the sizing of the environment, we have around 100 users in total. After running teh script, It removes all printers but does not reconnect them on the new print server. Any idea why? The code I had did remap them, but did not set the default printer. Let me know your thoughts, Michael

  • #16764
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    The issue with op_Addition was most likely caused by line 10 because I didn't have += to add to the empty object created on line 6. So, I have updated the script above.

    There is no reason one script cannot handle both print servers. That is the purpose of passing the parameters to the script. Are you consolidating two print servers into a single server? If a user had \\oldserver1\printer1 and \\oldserver2\printer1 mapped, you would have to handle deleting both and only mapping 1 server. So, would need to get details on logic, but yes it could be a single script (and should be).

    I did not actually update the code on line 21 or 22, which is your replace and .AddPrinterConnection. Did you update the "svrPrint" to the actual print server name and pass a parameter for $newPrintServer (or update the default) to reflect actual servers in your environment.

    As far as the default printer, even after I talked about using the wrong property (ShareName versus Name), I didn't update the code. Additionally, thinking about it, you would need to re-enumerate the printers collection to get the new printers actual name, so I updated the code to pull printers that match the share and new printserver name.

    Param (
        $newPrintServer = "svrprint1",
        $PrinterLog = "\\file\share\{0}_PrintMigration.csv" -f $Env:COMPUTERNAME
    )
    
    $log = @()
    
    if (Test-Path $PrinterLog) {
        #pull in the current log to 'Append' new logging
        $log += Import-CSV $printerLog
    }
    
    Try {
        Write-Verbose ("{0}: Checking for printers mapped to old print server" -f $Env:USERNAME)
        $printers = @(Get-WmiObject -Class Win32_Printer -Filter "SystemName='\\\\svrprint'" -ErrorAction Stop)
        $default = Get-WmiObject -Class Win32_Printer -Filter "Default='True'" -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 "svrprint",$newPrintServer
                $returnValue = ([wmiclass]"Win32_Printer").AddPrinterConnection($newPrinter).ReturnValue
                If ($returnValue -eq 0) {
                    try {
                        #Deleting the printer is usually the biggest issue
                        #when doing this type of migration.  You need to capture
                        #if the delete was successful during your testing if the
                        #event your code needs updated.  Many scripts use WMI to enumerate
                        #and WScript.Network to map and delete the old printer
                        $printer.Delete()
                        $deleted = $true
                    }
                    catch {
                        $deleted = $false
                    }
                    $added = $true
    
                    $defaultPrt = $null
                    if ($default.ShareName -eq $printer.ShareName) {
                        Get-WmiObject -Class Win32_Printer -Filter ("SystemName='\\\\{0}' And ShareName ='{0}' " -f $newPrintServer,$($printer.ShareName)) | foreach {
                            (New-Object -ComObject WScript.Network).SetDefaultPrinter($_.Name)
                        } #foreach 
                        $defaultPrt = " [DEFAULT] "
                    }
    
                    $StatusMsg = $("Successfully added {0} {1} with return value {2}" -f $newPrinter,$defaultPrt,$returnValue)
                }
                Else {
                    Write-Verbose ("{0} returned error code: {1}" -f $newPrinter,$returnValue) -Verbose
                    $added = $false
                    $StatusMsg = $("Failed adding {0} with return value {1}" -f $newPrinter,$returnValue)
                } #if ret val
            } #if count
    
            $props = @{
                ComputerName=$Env:COMPUTERNAME
                UserName=$Env:USERNAME
                OldPrinter = $("\\{0}\{1}" -f $printer.SystemName, $printer.ShareName)
                Printer = $newPrinter
                Added = $added
                Deleted = $deleted
                StatusMessage = $StatusMsg
                Date = $(Get-Date)
            }
    
            $log += New-Object -TypeName PSObject -Property $props
        } #foreach printer
    }#try
    Catch {
        $props = @{
            ComputerName=$Env:COMPUTERNAME
            UserName=$Env:USERNAME
            OldPrinter = "N\A"
            Printer = "N\A"
            Added = "N\A"
            Deleted = "N\A"
            StatusMessage = $StatusMsg = "WMIERROR: {0}" -f $_.Exception.Message
            Date = $(Get-Date)
        }
            
        $log += New-Object -TypeName PSObject -Property $props
    }
    
    $log | Export-CSV $PrinterLog -Force -NoTypeInformation
    
    
  • #16766
    Profile photo of Michael Burutzis
    Michael Burutzis
    Participant

    retested and still removes all printers. But in the csv it says it added the printers:
    Successfully added \\hqfp00\Lex-Finance [DEFAULT] with return value 0

  • #16778
    Profile photo of Michael Burutzis
    Michael Burutzis
    Participant

    I had changed the srvprintX for the new print server and the old print server names. I also changed the path for the log files

  • #31867
    Profile photo of Michal Rejman
    Michal Rejman
    Participant

    Hi There

    So, i ran your script and what i see on my end is
    – Printerlog created – csv file has been created but is blank
    – newPrintServer = added – \\printerservername\ didn't change when i checked print mapping under device and printers
    – no errors while running script

    How i can fix this?

    Thx, M

You must be logged in to reply to this topic.