如何将 prnmngr 的输出转换为自定义对象?

How can i convert the output of prnmngr into custom object?

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

类似于(注意修改后的输出 属性 名称):

$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"

其中 $a$b$c$d$e 表示 属性 在 [=12 的输出上循环的值=]

Kory Gill helpfully suggests using the W8+ / W2K12+ Get-Printer cmdlet 代替。

同样,kuujinbo 建议 Get-WmiObject -Class Win32_Printer 早期 OS 版本。

本着 PowerShell 的精神,这两个命令 returns objects 您可以直接访问其 properties - 无需 文本解析.


如果您仍然需要解析 cscript prnmngr.vbs -l 的输出(如果它提供了引用的命令没有提供的额外信息),请使用以下方法 - 注意解析需要多少努力文本输出到结构化对象:

鉴于所有信息都是space分隔的,每行的属性 name部分由varying[=组成71=] 个标记,唯一可预测的解析文本的方法是:

  • 维护着名的 属性 名字
  • 考虑 行上的 属性 名称 value.
  • 之后的任何内容

一个 PSv3+ 解决方案:

# 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

根据您的示例输入,以上生成一个 2 元素 [pscustomobject] 数组:

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"cscript prnmngr.vbs -l 的输出行收集到一个数组中,然后将它们连接起来形成一个多行字符串。

  • -split "`n`n" 将生成的多行字符串拆分为 段落 ,每个段落代表一个打印机的属性。

  • ForEach-Object 脚本块然后处理每个打印机的属性段落:

    • foreach($line in $_ -split "`n") 将多行段落拆分回行数组并循环遍历它们。
    • $ohtFields = [ordered] @{} 初始化一个空的 ordered 哈希表(其中条目反映在输出的定义顺序中)作为创建自定义对象的基础。
    • 内部 foreach 循环然后检查每一行是否包含感兴趣的 属性,如果是,则向输出哈希表添加一个条目,输出 属性 名称和属性 值,即行中众所周知的 属性 名称之后的部分。
    • 最后,将有序哈希表转换为 [pscustomobject]
    • 将其输出为自定义对象

从 Powershell 调用 vbscript-script 感觉就像 "re-write it in Powershell sort of thing"(不要评判)。 @KoryGill 问了一个有趣的问题,"Why not just call Get-Printer"?

但是,对于你的问题,你完全可以把它变成一个对象,但是你必须做一些文本操作:

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

这将创建一个名为 $printer_stuff 的字符串数组,其中每个元素都有单独的输出行。您需要为每台打印机制作一个令牌列表 属性,例如服务器名称、打印机名称等。您将遍历输出(在字符串数组中),将属性复制到 PSObject。这是一个简单的例子来证明这一点:

## 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

如果 prnmgr.vbs 脚本将返回有关一堆打印机的信息,您可以将 $printer 对象填充到一个数组中:

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

您可以使用类似...的方式将每台打印机的数据从字符串数组中拉出...

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

如您所见,这是一件很麻烦的事,这就是为什么我建议只用 Powershell 重写这个东西。如果您足够熟练地执行此操作,那么您也足够熟练地移植 vbscript 脚本。

祝你好运, A-