Let me know what you think

This topic contains 2 replies, has 2 voices, and was last updated by Profile photo of Simon M Simon M 5 months, 1 week ago.

  • Author
    Posts
  • #60295
    Profile photo of Simon M
    Simon M
    Participant

    Hi all,
    although I have been playing around with Powershell for a while now, I never really got into it any deeper. After attending some inspiring sessions at Techmentor in Orlando last week (thanks Don!), I jumped on the first chance to create a script. The script is working and does exactly what I need it to do, but I'd be interested in getting some feedback if there is a better way to do it.

    Here was the challenge:
    We have around 40 print servers in AD that host various print queues. We try to follow some standards, but unfortunately, not all the admins adhere to them. I wanted to create a script that queries all print servers and identifies any non-standard printer ports. Our standard is that each print queues is associated with one printer port on its print server. The printer ports are supposed to be configured to have the same name as the printer. We require FQDNs and not IP address. So for printer1 on printserver1.domain.com, we should also have an associated printerport that is labeled as printer1.domain.com and its address is also printer1.domain.com.

    Here is the code:

    Function Get-NonStandardPrinterPorts {
        [CmdletBinding()]
        param(
            [Parameter(Mandatory=$True)]
            [string]$ComputerName
        )
    
        $nonstdports=@()    
        try {
            # Get all printer ports of printserver $computername
            $ports=Get-WMIObject -Class Win32_TcpIpPrinterPort -ComputerName $ComputerName -ErrorAction stop | Select Name,HostAddress
                
            # enumerate all ports and check if name or hostaddress are not following standard naming convention of printer.henkelgroup.net
            # if printer port does not follow standard, add to array $nonstdports
            foreach ($port in $ports) {
                if (($port.Name).ToLower() -notmatch "^\w+\.domain\.com" -or ($port.HostAddress).ToLower() -notmatch "^\w+\.domain\.com" ) {
                   $properties=@{'PortName'=$port.Name;'PortAddress'=$port.HostAddress}
                   $object=New-Object -TypeName PSObject -Property $properties
                   $nonstdports+=$object
                } # end of if
            } # end of foreach
    
        } # end of try
        
        Catch {
            # in case of error, throw exception message
            Write-Error $_.Exception.Message
        } # end of catch
        
        # return object 
        Write-Output $nonstdports
    } # end of function
    
    Function Get-PrinterPortAssignment {
        [CmdletBinding()]
        param (
            [Parameter(mandatory=$True)]
            [array]$PortName,
            [Parameter(mandatory=$True)]
            [array]$PrinterName,
            [Parameter(mandatory=$True)]
            [string]$ComputerName
        )
    
        $colPrinters=@()
            
        # enumerate all printer ports that were passed along in object with function call
        foreach ($port in $PortName) {
            
            $done=$false
    	#enumerate all printers that were passed along in object with function call
            foreach ($printer in $PrinterName) {            
                #compare if printer port and printer name match up, if they do add them to object
                if ($printer.PortName -eq $port.PortName) {                
                    $properties=@{'ComputerName'=$ComputerName;
                                  'PortName'=$port.PortName;
                                  'PortAddress'=$port.PortAddress; 
                                  'Printer'=$printer.name
                                 }
                    $printq=New-Object -TypeName PSObject -Property $properties            
                    $colPrinters += $printq
                    $done=$true
                    continue
                } # end of if
            } # end of foreach
    
            # if no matching printer was found for a printer port, add printer port to array, but mark printer as "n/a"
            if (!($done)) {  
                $properties=@{'ComputerName'=$ComputerName;
                              'PortName'=$port.PortName;
                              'PortAddress'=$port.PortAddress; 
                              'Printer'='n/a'
                             }
                $printq=New-Object -TypeName PSObject -Property $properties            
                $colPrinters += $printq
            } # end of if
        } # end of foreach
        
        # return object
        Write-Output $colPrinters
    }
    
    
    # grab list of printservers from AD
    $servers=Get-ADComputer -filter "name -like '*printserver*'" | Select name
    
    $endresult=@()
    
    # enumerate list of printservers
    foreach ($computername in $servers.name) {
        $printers=@()
            
        # Get all non-standard printer ports from printserver $computername
        $nonstdports=Get-NonStandardPrinterPorts -ComputerName $computername 
    
        # if non-standard printer ports were found, get a lost of all printers on server $computername
        if ($nonstdports) {
            $printers=Get-Printer -ComputerName $computername -ErrorAction Stop
        } # end of if
        
        # if printers were found on printserver $computername, get matching printer-printerport pairs
        if ($printers) {
            $result=Get-PrinterPortAssignment -PortName $nonstdports -PrinterName $printers -ComputerName $computername
            $endresult+=$result 
        } # end of if
        
    } # end of foreach
    
    
    # format for output on console
    $endresult | Select ComputerName,Printer,PortName,PortAddress | Sort-Object ComputerName | Ft -AutoSize
    
    

    I appreciate any feedback or suggestions for improvement you can provide.

    Thanks much!

  • #60453
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    Take a look at this logic and see if it works better for you as we are using a single loop to gather information. You could certainly turn this into a function as well and it does need error handling, but the basic logic is there.

    # grab list of printservers from AD
    $servers = Get-ADComputer -filter "name -like '*printserver*'" | Select -ExpandProperty Name
    
    # enumerate list of printservers
    $results = foreach ($computername in $Servers) {
       #Get server port data
       $ports = Get-WMIObject -Class Win32_TcpIpPrinterPort -ComputerName $ComputerName -ErrorAction stop | Select Name,HostAddress
    
       #Get server printer data and map port data
       $printers = Get-Printer -ComputerName $Computername | 
       Select *,
       @{Name="PortAddress";Expression={$pn = $_.PortName; $ports | Where{$_.Name -eq $pn} | Select -ExpandProperty Name}},
       @{Name="HostAddress";Expression={$pn = $_.PortName; $ports | Where{$_.Name -eq $pn} | Select -ExpandProperty HostAddress}}
    
       #Return printer data and check if the portname and hostaddress
       #meet the criteria, this will return a boolean (True\False)
       $printers | 
       Select *,
       @{Name="IsStandardPort";Expression={$_.PortName -match "^\w+\.domain\.com" -or $_.HostAddress -match "^\w+\.domain\.com"}}
        
    } # end of foreach
    
    #Show printers where it is not using a standard port
    $results | Where{$_.IsStandardPort -eq $false}
    
  • #60627
    Profile photo of Simon M
    Simon M
    Participant

    Thanks for your feedback. I've never used the

     XXXX | Select *,@{} 

    functionality before, that looks pretty interesting, seems to shorten everything quite a bit.

You must be logged in to reply to this topic.