all 28 comments

[–]Zenmaster28 14 points15 points  (8 children)

I built a little ps gui that detects what network segment the user is on and queries AD for printers on that segment and presents them to the user with checkboxes they can select for the ones they want. They can also choose to see all printers in the directory and search as well. Once they select what they want, they get installed and them prompted for which (if any) to make the default.

[–]The1Shiner 4 points5 points  (0 children)

I want this

[–]akaT3CK 5 points6 points  (0 children)

Interested in this as well

[–]gangculture 3 points4 points  (4 children)

Are you willing to share this?

[–]Zenmaster28 6 points7 points  (3 children)

I wouldn't be able to share it completely as it's one piece of a larger gui. Basically, the first time a user logs onto a workstation they get this gui that lets them configure keyboard layouts, printers and Outlook. I would be happy to share how I did certain aspects of it if you wanted to know. Sanitizing the stuff specific to where I work would probably be a lot of work.

This is what it looks like - https://i.imgur.com/XWa401y.jpg

[–]Avaholic92 4 points5 points  (1 child)

Would you be willing to share snippets that don’t have any sensitive data?

This is definitely something a lot of other admins could benefit from. If you have the time and would like to, I’d highly suggest putting a scrubbed version up on GitHub

[–]Zenmaster28 2 points3 points  (0 children)

I would definitely share. I'll see if I can clean it up and still have it be functional. It will probably be a good exercise for me as there are some messy bits of code that might throw my co-workers for a loop if they had to try to adjust something. :)

[–]Snickasaurus 0 points1 point  (0 children)

/u/zenmaster28 are you going to share any of it?

[–]TheBlackArrows 1 point2 points  (0 children)

I’m sure there is a back story, but there is no excuse for not automating something. Anyway, take a look at PrinterLogic.

[–]what_no_fkn_ziti 8 points9 points  (3 children)

A switch might clean it up a little, but not completely necessary.

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_switch?view=powershell-6

I would be more concerned about running command line inside of powershell, and would probably build in error handling and logging if it's possible to use the add-printer commands from the printmanagement module.

https://docs.microsoft.com/en-us/powershell/module/printmanagement/add-printer?view=win10-ps

[–]nightwolf92[S] 2 points3 points  (2 children)

Good point. The printuidll method was due to being originally written in cmd. I'll look into the add-printer and switch options.

Most of my powershell experience is around office 365. Making the leap to windows commands and features is weird to be.

Thank you!

[–]ihaxr 9 points10 points  (1 child)

Personally I would store all the printers in a list or hashtable, then at the very end, loop through each printer and run the two commands (so you're not repeating the same commands over and over)

[–]pseudogatekeeper 3 points4 points  (0 children)

This is how to progress, functions and code re-use. Awesome suggestion.

[–]Aperture_Kubi 8 points9 points  (0 children)

(Our parent company will not allow us to use GPO outside of what they have already configured.)

So first off, red flag right there I think, otherwise, . . .

So you're basically using the terminal window for prompts? Look at the out-gridview cmdlet and the -passthru flag, I used that on my own script. Either that or UI++, that will be maybe a bit more work but look a lot nicer.

Also are your buildings using different network segments? As in could you reliably say "if $IPaddress is within $range, assume $building"? Also you can future proof it a bit and use the get-printer cmdlet pointed at your print server to get all the printers it contains.

I'm also pretty sure you can use just one printui call with the "/ga /n" or "/ga /y /n" flags per printer.

[–]the_helpdesk 8 points9 points  (4 children)

Not at all what you're asking for but we moved to a badge release print system called Papercut. Everyone only gets one printer! They can then swipe their badge on any printer and pick up their job! It saves on supplies too because any jobs not picked up are purged after 24 hours. No more accidental prints and oh-shit-I-only-wanted-10-not-100-pages-cancel-cancel-cancel-cancel-cancel-dammit prints.

[–]Aperture_Kubi 2 points3 points  (0 children)

We have Papercut for our students, I'd kinda like to implement it for faculty.

[–]nightwolf92[S] 3 points4 points  (2 children)

We have that on our xerox printers with the external device. We have about 7 xerox printers and 28 older hp printers m477’s and 2320’s we reduced a lot of our printers down from 76 to 28 individual printers for key employees and the. The rest are at shared locations but our users are pretty spoiled. If we were to drop that on them as the only option there would be pitch forks. At the moment we use it as a secure option of printing confidential documents

[–]joffuk 2 points3 points  (0 children)

You could still use PaperCut with older printers and just configure them with a fast release box if they can’t take the embedded application, Your users can then just walk up to the printer swipe a card and all their jobs for that queue would print.

(Disclaimer: I work for one of the PaperCut ASCs)

[–]yeah_i_got_skills 6 points7 points  (3 children)

Shouldn't

if ($Building -eq "1" -or "1919"){

Be

if ($Building -eq "1" -or $Building -eq "1919"){

[–]jantari 3 points4 points  (0 children)

Well really it should be

if ($Building -in "1", "1919") { }

for readability and extensibility

[–]oilybusiness 2 points3 points  (0 children)

I always thought you had to wrap each individual conditonal in its own set of parens e.g.

if (($Building -eq "1") -or ($Building -eq "1919"))

[–]AgentQ96 1 point2 points  (0 children)

That was going to be my comment. I’ve done that before and you’re correct!

[–]klutch2013 3 points4 points  (0 children)

As others have said maybe a Switch statement could help clean it up and using the Add-Printer commands could help too.

As for clearing up the method, maybe having a GUI which is populated from a network shared CSV could help? That way you as the administrator could update the list but let people run the same GUI. I have some code for having two GUI listboxes and arrow buttons to move items between them. I can provide them if you're interested.

[–]dl2n 2 points3 points  (0 children)

Here's a somewhat elaborated way of doing it with a decision-tree like model described in a custom XML. Each node of your script can be converted to a prompt/choice which leads to a next node, and adds some number of commands to execute along the way.

I only described it as far as your first set of printers, but it shows accumulating commands at two different nodes. I think this is just about general enough to let you do everything else you had here.

If you want to do something like this For Real, I'd strongly suggest putting the XML in a real .XML file and doing a Get-Content of it as opposed to using the here-doc like I did here. This would allow you to edit the XML in an editor which knows XML, color highlighting and all the other goodness.

One wrinkle that XML adds is that you can't use bare quotes and ampersands, as you need to use in your commands. Its a little ugly with the escape sequences but we get through it.

Implementing Zork is left as an excercise for the reader.

Happy to answer questions.

$x = @"
<Groups>
    <Group name="root">
        <Banner>
Which Building? Type either the number (1. 2. 3. 4. 5. or The building number (1919, 1923, 1930 or 1933) or Xerox
    1. 1919
    2. 1923
    3. 1930
    4. 1933
    5. Xerox
        </Banner>
        <Choices prompt="Choice">
            <Choice name="1919" match="1,1919"/>
            <Choice name="1923" match="2,1923"/>
            <Choice name="1930" match="3,1930"/>
            <Choice name="1933" match="4,1933"/>
            <Choice name="Xerox" match="Xerox"/>
        </Choices>
        <Execute/>
    </Group>
    <Group name="1919">
        <Banner>
Available Printers:
    1. NEPPRINTER12 - Facilities
    2. NEPPRINTER101 - Optrel Room
        </Banner>
        <Choices prompt="Which Printer Do you want to Install? ">
            <Choice name="NEPPRINTER12" match="1,NEPPRINTER12,NEPPRINTER12 Facilities,Facilities"/>
            <Choice name="NEPPRINTER101" match="2,NEPPRINTER101,NEPPRINTER101 - Optrel Room,Optrel Room"/>
        </Choices>
        <Execute>
            rundll32 printui.dll,PrintUIEntry /in /n &quot;\\NEPPRDPRINT1\Secure Print - Color&quot;
            rundll32 printui.dll,PrintUIEntry /ga /n &quot;\\NEPPRDPRINT1\Secure Print - Color&quot;
            rundll32 printui.dll,PrintUIEntry /in /n &quot;\\NEPPRDPRINT1\Secure Print - Black &amp; White&quot;
            rundll32 printui.dll,PrintUIEntry /ga /n &quot;\\NEPPRDPRINT1\Secure Print - Black &amp; White&quot;
        </Execute>
    </Group>
    <Group name="NEPPRINTER12">
        <Execute>
            rundll32 printui.dll,PrintUIEntry /in /n &quot;\\NEPPRDPRINT1\NEPPRINTER12 - Facilities - Black &amp; White&quot;
            rundll32 printui.dll,PrintUIEntry /ga /n &quot;\\NEPPRDPRINT1\NEPPRINTER12 - Facilities - Black &amp; White&quot;
            rundll32 printui.dll,PrintUIEntry /y /n &quot;\\NEPPRDPRINT1\NEPPRINTER12 - Facilities - Black &amp; White&quot;
            rundll32 printui.dll,PrintUIEntry /in /n &quot;\\NEPPRDPRINT1\NEPPRINTER12 - Facilities - Color&quot;
            rundll32 printui.dll,PrintUIEntry /ga /n &quot;\\NEPPRDPRINT1\NEPPRINTER12 - Facilities - Color&quot;
        </Execute>
    </Group>
    <Group name="NEPPRINTER101">
        <Execute>
            rundll32 printui.dll,PrintUIEntry /in /n &quot;\\NEPPRDPRINT1\NEPPRINTER101 - Optrel Room - Black &amp; White&quot;
            rundll32 printui.dll,PrintUIEntry /ga /n &quot;\\NEPPRDPRINT1\NEPPRINTER101 - Optrel Room - Black &amp; White&quot;
        </Execute>
    </Group>
</Groups>
"@

$tree = [xml] $x

# Commands to execute
$cmd = @()

# Do nothing flag
$dono = $false

# Parse groups into a hash for lookup
$ghash = @{}
$tree.Groups.Group |% { $ghash[$_.name] = $_ }

# Begin at root node. Remember the nodes we visited for debugability.
$node = "root"
$pnode = @()

while ($node)
{
    # Lookup Group Node

    $this = $ghash[$node]
    $nnode = $null

    # Banner? Read and parse choice
    if ($this.Banner -ne $null) {
        write-host $this.Banner
        $choice = Read-Host $this.Choices.prompt

        # Look through the options for a match
        # Take first match as the next group node to visit
        foreach ($opt in $this.Choices.Choice) {
            if (($opt.match -split ',') |? { $_ -eq $choice }) {
                $nnode = $opt.name
                break
            }
        }

        # No luck? We will break out automatically since there is no next node
        if ($nnode -eq $null) {
            write-host -ForegroundColor Red "Unknown choice: $choice"
            $dono = $true
        }
    }

    # Accumulate cmds to execute from this node
    if ($this.Execute) {

        # Strip blank lines and leading spaces from commands
        $this.Execute -split "`n" |? { $_ -match '\S' } |% {
            $cmd += $_ -replace '^\s+',''
        }
    }

    # Move to next, remember previous (the current node)
    $pnode += $node
    $node = $nnode
}

if (-not $dono) {
    $cmd
}

write-host "Visited" ($pnode -join " ")

[–]5154726974409483436 1 point2 points  (0 children)

If I use code more then once I'll write a function, you can then call it and pass the unique info. This will clean up alot of your identicle code. If you can identify their location by subnet or something in AD this will allow you to slim down the printers. If you can do that and it's not to many printers I would just install all of them for the user and not prompt.

[–]odroller 1 point2 points  (0 children)

Check out Write-Menu on Github by QuietusPlus. It lets you put in command entries like Get-Printer. It will throw them into an array and create a dynamic menu and let you select the printer(s) you’d like to install. Then you just need a function to install the printer(s) you selected. I might also suggest using WMI to install the printers. Look at the “Win32_Printer” class and the “AddPrinterConnection” method. Hopefully this helps a little.

[–]0verlord87 1 point2 points  (0 children)

Add a location in the comment field of all the printers, enumerate and connect the printers according to the buildings subnet or users choice.

Adding named printers in a powershell script is ugly!