seirved
seirved

Reputation: 25

Powershell - Export Output From Multiple Cmdlets

I have, on a number of occasions had issues exporting data when it is sourced from multiple cmdlets.

Fore example: I am trying to export a list of printers and other relevant information using WMI but there are two cmdlets necessary to extract all the information:

Get-WmiObject -Class Win32_Printer `
        -ComputerName $Computer -Credential $cred

and...

Get-WmiObject -Class Win32_PrinterConfiguration `
        -ComputerName $Computer -Credential $cred

I have created an object to pipe the data into so it can be exported:

$CSVData = New-Object PSObject
$CSVData | Add-Member -MemberType NoteProperty -Name "Name" -Value ""
$CSVData | Add-Member -MemberType NoteProperty -Name "DriverName" -Value ""
$CSVData | Add-Member -MemberType NoteProperty -Name "Location" -Value ""
$CSVData | Add-Member -MemberType NoteProperty -Name "PrintProcessor" -Value ""
$CSVData | Add-Member -MemberType NoteProperty -Name "PortName" -Value ""
$CSVData | Add-Member -MemberType NoteProperty -Name "Duplex" -Value ""
$CSVData | Add-Member -MemberType NoteProperty -Name "Color" -Value ""
$CSVData | Add-Member -MemberType NoteProperty -Name "PrintQuality" -Value ""

$CSVData.Name = @()
$CSVData.DriverName = @()
$CSVData.Location = @()
$CSVData.PrintProcessor = @()
$CSVData.PortName = @()
$CSVData.Duplex = @()
$CSVData.Color = @()
$CSVData.PrintQuality = @()

I have tried to lay it out like this:

    $PrinterConfig = Get-WmiObject -Class Win32_PrinterConfiguration `
        -ComputerName $Computer -Credential $cred |
            Select-Object Duplex,
                          Color,
                          PrintQuality

    $CSVData.Duplex += $PrinterConfig.Duplex
    $CSVData.Color += $PrinterConfig.Color
    $CSVData.PrintQuality += $PrinterConfig.PrintQuality

And, like this:

        $PrinterInfo = Get-WmiObject -Class Win32_Printer `
        -ComputerName $Computer -Credential $cred | 
            Select-Object Name,
                          DriverName,
                          Location,
                          PrintProcessor,
                          PortName |
                ForEach-Object {
                    $CSVData.Name += $_.Name
                    $CSVData.DriverName += $_.DriverName
                    $CSVData.Location += $_.Location
                    $CSVData.PrintProcessor += $_.PrintProcessor
                    $CSVData.PortName += $_.PortName
                }

I then export like this:

$CSVData | Export-Csv -Path c:\temp\printers.csv $OutDir

The issue is that no useful data is actually exported and I'm not sure how to properly combine the output from these two cmdlets.

There is most likely a more elegant way to do this...

Please help!

Upvotes: 1

Views: 1307

Answers (1)

brendan62269
brendan62269

Reputation: 1106

First you may want to query in a slightly different way. This way will only return the data you actually care about (it's a bit faster, too):

$printers = Get-WmiObject -Query "Select Name,DriverName,Location,PrintProcessor,PortName from Win32_Printer" -ComputerName $ComputerName -Credential $cred
$printerCfgs = Get-WmiObject -Query "select Name,Duplex,Color,PrintQuality from Win32_PrinterConfiguration" -ComputerName $ComputerName -Credential $cred

Now you have two arrays and you have to find some way to join the data from the classes (there are many ways, mostly more complicated than this example). You'll need to loop through each printer object and find the related printer configuration object. Both arrays have the "Name" property:

    foreach ( $printer in $printers ) {
        $printerCfg = $printerCfgs | where { $_.Name -eq $printer.Name }

this way you can create a single object regarding each printer and printer configuration object.

        $printerInfo = New-Object PSObject -Property @{
            ComputerName = $ComputerName
            Name = $printer.Name
            DriverName = $printer.DriverName
            Location = $printer.Location
            PrintProcessor = $printer.PrintProcessor
            PortName = $printer.PortName
            Duplex = $printerCfg.Duplex
            Color = $printerCfg.Color
            PrintQuality = $printerCfg.PrintQuality
        }

Next you want to return the data in the right order so your csv is readable (the } after the select closes the foreach loop above, you'll need that ;) ):

    $printerInfo | Select ComputerName,Name,DriverName,Location,PrintProcessor,PortName,Duplex,Color,PrintQuality
}

Lastly, you're probably going to want this info off of more than one computer and you'll want it all in one csv file. There are a few ways, you can take the code above and put it into a ps1 file or you can make a function that takes a computer name as a param and a single cred object so you don't have to re-auth for every WMI query. I prefer functions myself, I put or dot note them in my ps profile (much easier to keep track of IMO):

function get-printerinfo {
param ( $ComputerName, $cred = (Get-Credential) )
    $printers = Get-WmiObject -Query "Select Name,DriverName,Location,PrintProcessor,PortName from Win32_Printer" -ComputerName $ComputerName -Credential $cred
    $printerCfgs = Get-WmiObject -Query "select Name,Duplex,Color,PrintQuality from Win32_PrinterConfiguration" -ComputerName $ComputerName -Credential $cred
    foreach ( $printer in $printers ) {
        $printerCfg = $printerCfgs | where { $_.Name -eq $printer.Name }
        $printerInfo = New-Object PSObject -Property @{
            ComputerName = $ComputerName
            Name = $printer.Name
            DriverName = $printer.DriverName
            Location = $printer.Location
            PrintProcessor = $printer.PrintProcessor
            PortName = $printer.PortName
            Duplex = $printerCfg.Duplex
            Color = $printerCfg.Color
            PrintQuality = $printerCfg.PrintQuality
        }
        $printerInfo | Select ComputerName,Name,DriverName,Location,PrintProcessor,PortName,Duplex,Color,PrintQuality
    }
}

To use this function against a single computer

get-printerinfo myComputer

Prompts me for a user/pass then returns something like this:

ComputerName   : myComputer
Name           : Microsoft XPS Document Writer
DriverName     : Microsoft XPS Document Writer
Location       :
PrintProcessor : winprint
PortName       : XPSPort:
Duplex         : False
Color          : 2
PrintQuality   : 600

To use it against a list of computers in a file called list.txt in the current working dir:

$cred = Get-Credential
cat .\list.txt | %{ get-printerinfo -ComputerName $_ -cred $cred }  

To use the list.txt and put the output in a csv:

$cred = Get-Credential
cat .\list.txt | %{ get-printerinfo -ComputerName $_ -cred $cred } | Export-Csv .\myPrinterData.csv -NoTypeInformation

UPDATE (New script):

Function Get-Printers {

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$true,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)][String[]]$ComputerName,
    [Parameter()][string]$OutputDir = 'C:\Temp'
)

Begin { 
    $Cred = Get-Credential 
    $OutputFile = Join-Path $OutputDir "BCMPrinterAudit - $(Get-Date -Format yyyy-MM-dd--HH-mm-ss).csv"
}

Process {
    Foreach ($Computer in $ComputerName) {

        $Printers = Get-WmiObject -Query "Select Name,DriverName,Location,PrintProcessor,PortName from Win32_Printer" `
            -ComputerName $Computer -Credential $Cred
        $PrinterCfgs = Get-WmiObject -Query "select Name,Duplex,Color,PrintQuality from Win32_PrinterConfiguration" `
            -ComputerName $Computer -Credential $Cred

        Foreach ( $Printer in $Printers ) {
            $PrinterCfg = $PrinterCfgs | Where { $_.Name -eq $Printer.Name }
            $PrinterInfo = New-Object PSObject -Property @{
                ComputerName = $Computer
                Name = $Printer.Name
                DriverName = $Printer.DriverName
                Location = $Printer.Location
                PrintProcessor = $Printer.PrintProcessor
                PortName = $Printer.PortName
                Duplex = $PrinterCfg.Duplex
                Color = $PrinterCfg.Color
                PrintQuality = $PrinterCfg.PrintQuality
            }
        }
    }
}

End {

    Write-Output $PrinterInfo     

    }
}

Upvotes: 1

Related Questions