0

output of cscript prnmngr.vbs -l

Server name abcd 
Printer name \\abcd.com\mailroom
Share name mailroom
Driver name Canon iR-ADV 4225/4235 UFR II
Port name mailroom.com
Comment
Location
Print processor winprint
Data type RAW
Parameters
Attributes 536
Priority 1
Default priority 0
Average pages per minute 0
Printer status Idle
Extended printer status Unknown
Detected error state Unknown
Extended detected error state Unknown

Server name cdef 
Printer name \\cdfet.com\mailroom3
Share name mailroom3
Driver name Canon iR-ADV 4225/4235 UFR II
Port name mailroomxxx.com
Comment
Location
Print processor winprint
Data type RAW
Parameters
Attributes 536
Priority 1
Default priority 0
Average pages per minute 0
Printer status Idle
Extended printer status Unknown
Detected error state Unknown
Extended detected error state Unknown

something like (note the modified output property names):

$CustomPrinterobjects = New-Object –TypeName PSObject
$CustomPrinterobjects | Add-Member –MemberType NoteProperty –Name ComputerName –Value "$a" 
$CustomPrinterobjects | Add-Member –MemberType NoteProperty –Name Name –Value "$b" 
$CustomPrinterobjects | Add-Member –MemberType NoteProperty –Name ShareName –Value "$c" 
$CustomPrinterobjects | Add-Member –MemberType NoteProperty –Name DriverName –Value "$d"
$CustomPrinterobjects | Add-Member –MemberType NoteProperty –Name PortName –Value "$e"

where $a, $b, $c,$d, $e represent property values looped over the output of cscript prnmngr.vbs -l

mklement0
  • 382,024
  • 64
  • 607
  • 775
munish
  • 4,505
  • 14
  • 53
  • 83
  • 7
    Why not just call Get-Printer? – Kory Gill May 08 '18 at 19:50
  • 2
    A lot of people on SO assume the **ideal** - that Windows 7 installations world-wide are insignificant. Not so - [here](http://gs.statcounter.com/os-version-market-share/windows/desktop/worldwide) and [here](https://www.computerworld.com/article/3199373/windows-pcs/windows-by-the-numbers-its-a-topsy-turvy-world-with-windows-10-down-7-up.html) for example. The `get-printer` cmdlet is only available from Window 8. If you're on Windows 7: `Get-WmiObject -Class Win32_Printer` gets you a collection of objects the _PowerShell_ way. – kuujinbo May 08 '18 at 21:38

2 Answers2

1

Kory Gill helpfully suggests using the W8+ / W2K12+ Get-Printer cmdlet instead.

Similarly, kuujinbo suggests Get-WmiObject -Class Win32_Printer for earlier OS versions.

In the spirit of PowerShell, both commands returns objects whose properties you can access directly - no need for text parsing.


In case you still have a need to parse the output from cscript prnmngr.vbs -l (if it provides extra information that the cited commands do not), use the following approach - note how much effort is needed to parse the textual output into structured objects:

Given that all information is space-separated and the property name part of each line is composed of varying numbers of tokens, the only predictable way to parse the text is to:

  • maintain a collection of well-known property names
  • consider whatever comes after the property name on the line the value.

A PSv3+ solution:

# Map the input property names of interest to output property names,
# using a hashtable.
$propNameMap = @{ 
  'Server name ' = 'ComputerName'
  'Printer name ' = 'Name'
  'Share name ' = 'ShareName'
  'Driver name ' = 'DriverName'
  'Port name ' = 'PortName'
}

# Split the output of `cscript prnmngr.vbs -l` into paragraphs and 
# parse each paragaph into a custom object with only the properties of interest.
$customPrinterObjs = (cscript prnmngr.vbs -l) -join "`n" -split "`n`n" | ForEach-Object {
  $ohtFields = [ordered] @{}
  foreach ($line in $_ -split "`n") {
    foreach ($propNamePair in $propNameMap.GetEnumerator()) {
      if ($line -like ($propNamePair.Key + '*')) {
        $ohtFields[$propNamePair.Value] = $line.Substring($propNamePair.Key.length)
      }
    }
  }
  [pscustomobject] $ohtFields
}

# Output the resulting custom objects.
$customPrinterObjs

With your sample input, the above yields a 2-element [pscustomobject] array:

ComputerName : abcd 
Name         : \\abcd.com\mailroom
ShareName    : mailroom
DriverName   : Canon iR-ADV 4225/4235 UFR II
PortName     : mailroom.com

ComputerName : cdef 
Name         : \\cdfet.com\mailroom3
ShareName    : mailroom3
DriverName   : Canon iR-ADV 4225/4235 UFR II
PortName     : mailroomxxx.com
  • (cscript prnmngr.vbs -l) -join "`n" collects the output lines from cscript prnmngr.vbs -l in an array and then joins them to form a single multiline string.

  • -split "`n`n" splits the resulting multiline string into paragraphs, each representing a single printer's properties.

  • The ForEach-Object script block then processes each printer's properties paragraph:

    • foreach($line in $_ -split "`n") splits the multiline paragraph back into an array of lines and loops over them.
    • $ohtFields = [ordered] @{} initializes an empty ordered hashtable (where entries are reflected in definition order on output) to serve as the basis for creating a custom object.
    • The inner foreach loop then checks each line for containing a property of interest, and, if so, adds an entry to the output hashtable with the output property name and the property value, which is the part that follows the well-known property name on the line.
    • Finally, the ordered hashtable is output as a custom object by casting it to [pscustomobject].
mklement0
  • 382,024
  • 64
  • 607
  • 775
1

Calling a vbscript-script from Powershell just feels like a "re-write it in Powershell sort of thing" (not to be judgy). @KoryGill asks an interesting question, "Why not just call Get-Printer"?

But, to your question, you can totally turn that into an object, but you'll have to do some text manipulation:

$printer_stuff = $(cscript prnmngr.vbs -l)

This will create a string array named $printer_stuff where each element has a separate line of output on it. You'll want to make a list of tokens for each printer property e.g., server name, printer name, etc. You'll iterate over the output (in the string array) copying the properties to a PSObject. Here is a cheap example to demonstrate the point:

## Make a list of tokens
$tokens = @('Server name', 'Printer name', 'Share name')

## This will be your printer object
$printer = New-Object -TypeName PSObject

## Parsing the string array and stuffing the good bits into your printer object
foreach ($thing in $printer_stuff[0..17]) {
    foreach ($token in $tokens) {
        if ($thing -match $token) {
            Add-Member -InputObject $printer -MemberType NoteProperty -Name $token -Value $thing.Replace($token, '')
        }
    }
}

## Here is your object...
$printer

If the prnmgr.vbs script will be returning information on a bunch of printers, you can stuff that $printer object into an an array:

$printers = @()
....
$printers += $printer

You can pull each printer's data out of the string array with something like...

$min = 0
$max = $size
while ($min -lt $printer_stuff.length) {
    $printer_stuff[$min..$max]
    $min = $max + 1
    $max += $size
}

As you can see, this is a big pain in the ass, which is why I suggest just to re-write the thing in Powershell. If you're slick enough to do this bit, you're slick enough to port the vbscript-script.

Good Luck, A-

mklement0
  • 382,024
  • 64
  • 607
  • 775
Adam
  • 3,891
  • 3
  • 19
  • 42