【问题标题】:How can i convert the output of prnmngr into custom object?如何将 prnmngr 的输出转换为自定义对象?
【发布时间】:2018-05-08 19:45:03
【问题描述】:

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 表示在cscript prnmngr.vbs -l 的输出上循环的属性值

【问题讨论】:

  • 为什么不直接调用 Get-Printer?
  • SO 上的很多人都认为理想 - 全球范围内的 Windows 7 安装微不足道。不是这样 - 例如herehereget-printer cmdlet 仅适用于 Window 8。如果您使用的是 Windows 7:Get-WmiObject -Class Win32_PrinterPowerShell 方式为您获取对象集合。

标签: powershell text-parsing pscustomobject


【解决方案1】:

Kory Gill 建议改用 W8+ / W2K12+ Get-Printer cmdlet

同样,kuujinbo 建议 Get-WmiObject -Class Win32_Printer 用于早期操作系统版本。

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


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

鉴于所有信息都是用空格分隔的,并且每一行的属性 name 部分由 不同 数量的标记组成,解析文本的唯一可预测方法是到:

  • 维护一组知名属性名称
  • 考虑行上的属性名称​​之后

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],将其作为自定义对象输出。

【讨论】:

    【解决方案2】:

    从 Powershell 调用 vbscript-script 感觉就像是“在 Powershell 中重写它之类的东西”(不要判断)。 @KoryGill 提出了一个有趣的问题,“为什么不直接调用 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-script。

    祝你好运, A-

    【讨论】:

      猜你喜欢
      • 2014-02-15
      • 1970-01-01
      • 2011-01-15
      • 2014-04-17
      • 2018-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-24
      相关资源
      最近更新 更多