Powershell printer mapping script

Hello all, I am after some help/advice on some powershell writing.

I am trying to move our company away from GPP printers to a powershell script with csv lookup.

Numerous reasons but mainly GPP (on users) when mapping printers it can slow logins if a particular printer that a user/device maps is offline.

Base script so far

$csv = "C:\temp\printers.csv"
$addprinters = Import-Csv $csv

foreach ($Computer in $addprinters){
If ($Computer.pcname -eq $env:computername) {
$Printers = ($Computer.printers).split(";")
foreach ($Printer in $Printers) {Add-Printer -connectionname $Printer -ErrorAction SilentlyContinue}

(New-Object -ComObject WScript.Network).SetDefaultPrinter("$($Computer.defaultprinter)")
}
}

CSV info

name, printers, defaultprinter

X-Client-01, \\servername\printer1

X-Client-02, \\servername\printer1

Y-Client-01, \\servername\printer1

Y-Client-02, \\servername\printer1

Y-Client-01, \\servername\printer1

Y-Client-01, \\servername\printer2

Y-Client-01, \\servername\printer3

It doesn’t go as far as I would like to and now as tidy i am going in circles with it

I would prefer the device name to be condensed example if it was an if statement in vbs if(left(ucase(computername),9) = “Y-Client-”

So for example that any client that starts y-client- will be mapped the printer specified in the printers tab, then one step further so that multiple printers can be added to those devices or to a single device but based on just one line in the csv.

Example

X-Client-02 gets \server\printer1, \server\printer2, \server\printer3, with a default being \server\printer2

any device named like Y-Client- gets \server\printer4,\server\printer1,\server\printer6, default being \server\printer1

 

many thanks

Based on your post, here are my assumptions. Please correct me if I’m wrong:

  1. Each computer will run this script.
  2. Each computer will lookup it's partial computername (first part minus the sequenced number) in the csv. Should match only one line in csv.
  3. Once the script finds it's partial computername, it will map the corresponding printers in the csv.
With those assumptions, I would probably do something like this:
#find and select the corresponding object. assumes only one line in the csv will match
$printerconfig = Import-Csv "C:\temp\printers.csv" |
                    Where-Object {$env:COMPUTERNAME -like "$($_.pcname)*" }

#map each printer
$printerconfig.printers -split “;” |
ForEach-Object {Add-Printer -connectionname $_ -ErrorAction SilentlyContinue}

#set default printer
(New-Object -ComObject WScript.Network).SetDefaultPrinter(“$($printerconfig.defaultprinter)”)


 

Hi Mike R.

Yes you assume correctly, each computer will run this script at user logon, find its one corresponding line and map multiple printers or possibly a singular printer, set one of them to default and that could be based on full hostname or partial hostname, as we could use both.

Thank you for your script, I seem to have issue with the line adding the printers. Cannot validate argument on parameter ‘ConnectionName’. The argument is null or empty.

ForEach-Object {Add-Printer -connectionname $_ -ErrorAction SilentlyContinue}

Many thanks again

The example CSV has only one client / printer per line, rather the one client / mulitple printers serperated by a “;”. So I’m not sure what this line;

$printerconfig.printers -split “;”

would be returning as there is nothing to be split.

 

Richgardener42, sorry i clarified the multiple mappings lower down on my post with an example. X-Client-02 gets \server\printer1, \server\printer2, \server\printer3, with a default being \server\printer2

There are more than one on each row in the CSV

I think the Split may have been a typo. Should have been a comma for the separator.

I am a bit confused i am using the provided code below, but i receive the errors mentioned, the x3 printers seem to add successfully on my on client test but still produce the -connection null or empty return, and the default doesn’t set even though its typed correctly for one of the printers it has just mapped.

In that example the csv is.

pcname, printers, defaultprinters

client1 \\server\printer1;\\server\printer2;\\server\printer3 \\server\printer1
 

$printerconfig = Import-Csv “C:\temp\printers.csv” | Where-Object {$env:computername -like "$($.pcname)*"}
$printerconfig.printers -split “;” | ForEach-Object {Add-Printer -ConnectionName $
-ErrorAction SilentlyContinue}
(New-Object -ComObject WScript.Network).SetDefaultPrinter(“$($printerconfig.defaultprinter)”)

 

Add-Printer : Cannot validate argument on parameter ‘ConnectionName’. The argument is null or empty. Provide an argument
that is not null or empty, and then try the command again.
At line:3 char:82

  • … s -split “;” | ForEach-Object {Add-Printer -ConnectionName $_ -ErrorA …
  • ~~
  • CategoryInfo : InvalidData: (:slight_smile: [Add-Printer], ParameterBindingValidationException
  • FullyQualifiedErrorId : ParameterArgumentValidationError,Add-Printer

There is no printer called " \server\printer1".
At line:5 char:62

  • … bject WScript.Network).SetDefaultPrinter(“$($printerconfig.defaultprinter)”)
  • CategoryInfo : OperationStopped: (:slight_smile: , COMException
  • FullyQualifiedErrorId : System.Runtime.InteropServices.COMException

Have you verified $printerconfig only contains one object and is not an array or empty? Run your first line (import-csv) and then check the value of $printerconfig to see if there is no objects or more than one object. The next step I would do to troubleshoot assuming there is only one object is check the value of $printerconfig.printers and $printconfig.printers -split “;”. Finally, I would check “$($printerconfig.defaultprinter)” Hopefully that will uncover the issue.

It’s a bit dangerous to search for something and pipe to a command with a mandatory parameter. Take a look at the following:

$printerconfig = Import-Csv “C:\temp\printers.csv” | 
                 Where-Object {$env:computername -like “$($_.pcname)*”}

if ($printerconfig) {
    $printerList = $printerconfig.printers -split “,” | 
                   Where-Object -FilterScript {$_}
 
    if ($printerList) {
        foreach ($printer in $printerList){
            Add-Printer -ConnectionName $printer -ErrorAction SilentlyContinue
        }

        (New-Object -ComObject WScript.Network).SetDefaultPrinter(“$($printerconfig.defaultprinter)”)
    }
    else {
        'No printer list found for computer {0}' -f $env:computername
    }
}
else {
    'Computer {0} not found in csv' -f $env:computername
}

Mike R.

Yes following what you said, the issue seems to be identified when checking “$($printerconfig.defaultprinter)”

This is producing an extra space at beginning of any printer that listed on any row for the defaultprinter

 

 

That should be pretty simple to fix. Either remove the space in your csv or you can remove it in your code. String objects have a Trim method that will remove leading and trailing spaces.

“$($printerconfig.defaultprinter)”.Trim()

 

Mike R. the trim method helped solve it, it was strange as there wasn’t any leading spaces in my csv file.

Thanks for all the help/guide/scripts.

I think from trying the script I still have a hang in the running of the script if a printer is turned off. Like with group policy it seems to try multiple times to contact the printer before ‘force’ adding as offline therefore slowing it down.

So i am looking at adding to it so that i can force it to give up if the printer does not respond within a second or two.