Finding Printers on Remote Computers

Recently I was working on creating new Group Policies to assign printers to users. When working on these kinds of things it’s of course very advantageous to know who is currently using which printer, so in order to determine who was using what, I wrote the script below.

Function Get-UserPrinter
{
    <# .SYNOPSIS
       This script is used to get a list of printers for each user on one or more computers

       .DESCRIPTION
       This will use PSRemoting to talk computers throughout the domain to find which printers are located in the registry for each user 

       .PARAMETER ComputerName
       One or more computers 

       .EXAMPLE
       Get-Printer -ComputerName Computer1 
       This will get the printers for the computer Computer1 
    #>
    param(
        [Parameter(Position=1,ValueFromPipeline=$True,Mandatory=$True)][String[]]$ComputerName,
        [PSCredential]$Credential
    )

    Begin { }

    Process
    {
        # Create a scriptblock that will be run on target computer
        $ScriptBlock =
        {
            # For each user select their name
            Foreach ($UserSID in $(Get-ChildItem Registry::HKEY_USERS -Exclude ".Default","*Classes*" | Select-Object Name -ExpandProperty Name))
            {
                # Get the user's SID
                $UserSID = $UserSID.SubString(11)
        
                # Convert the SID into a username
                $Username = (New-Object System.Security.Principal.SecurityIdentifier($UserSID)).Translate([System.Security.Principal.NTAccount]) `
                            | Select -ExpandProperty Value

                # Check if they have the printer connections key
                If (Test-Path -Path "Registry::HKEY_USERS\$UserSID\Printers\Connections") 
                {           
                    # Get a list of printers
                    $Printers = (Get-ChildItem "Registry::HKEY_USERS\$UserSID\Printers\Connections" | Select -ExpandProperty Name)

                    # If they have printers
                    If ($Printers)
                    {   
                        # Create an array to hold their printers
                        $PrinterNames = @()

                        Foreach ($Printer in $Printers)
                        {
                            # Get a list of their printers
                            $PrinterNames += $Printer.ToString().Substring($Printer.LastIndexOf("\") + 1).Replace(",","\")
                        }

                        # If they have a default printer
                        If (Test-Path -Path "Registry::HKEY_USERS\$UserSID\Software\Microsoft\Windows NT\CurrentVersion\Windows") 
                        {   
                            # Get the default printer string
                            $Default = Get-ChildItem "Registry::HKEY_USERS\$UserSID\Software\Microsoft\Windows NT\CurrentVersion" `
                                       | Get-ItemProperty | Where-Object {$_.Device} | Select-Object -ExpandProperty Device

                            # Trim it to get the value we want
                            $Default = $Default.SubString(0, $Default.IndexOf(","))
                        }

                        # Create a hashtable containg the user's name, the printers they have, and which is the default
                        $Properties = @{'Username'=$Username;
                                        'Printers'=$PrinterNames;
                                        'Default'=$Default}

                        # Create an object with the above properties
                        $Object = New-Object -TypeName PSObject -Property $Properties
                    
                        # Output the object
                        Write-Output $Object
                    }
                }
            }
        }

        If ($Credential)
        {
            # Run the above script block on the passed computers
            Invoke-Command -ComputerName $ComputerName -ScriptBlock $ScriptBlock -Credential $Credential
        }

        Else
        {
            # Run the above script block on the passed computers
            Invoke-Command -ComputerName $ComputerName -ScriptBlock $ScriptBlock
        }
    }

    End { }
}

Some tips while running this. In order to query every computer in the domain:

Get-UserPrinter -ComputerName $((Get-ADComputer -Filter *).Name)

Or for a specific OU:

Get-UserPrinter -ComputerName $((Get-ADComputer -Filter * -SearchBase "OU=HeadOffice,DC=<Domain>,DC=<TLD>).Name)

Also, while working with the output, format it with:

Get-UserPrinter -ComputerName $((Get-ADComputer -Filter *).Name) | Sort-Object Default | Format-Table PSComputerName, Username, Default, Printers

Leave a Reply

Your email address will not be published. Required fields are marked *