增强管道的内容?

Enhancing the pipeline's content?

假设您有一个使用 7-zip 压缩文件的命令,该命令接受来自管道的值:

Function New-Archive {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$True,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)][Alias('FullName')]
        [string[]]$Files,

        [string]$Archive='Archive.zip'
    )

    BEGIN {}
    PROCESS {
      Foreach ($File in $Files) {
        & 7z a -tZIP $Archive $File
      }
    }
    END {}
}

假设foo目录有这些文件:a.txt、b.txt、c.txt

正在执行命令:

PS Foo> GCI | New-Archive

产生的输出类似于:

7-Zip [64] 9.20  Copyright (c) 1999-2010 Igor Pavlov  2010-11-18

Scanning

Updating archive .\files.zip

Compressing  a.txt
Compressing  b.txt
Compressing  c.txt
Compressing  files.zip

Everything is Ok

解析输出、捕获压缩结果并将其添加到管道中非常容易:

...
$output = & 7z a $Archive $File

#
# parse stdout; capture files that were compressed; convert to PsObject[] 
#
$output = $output[7..($output.Length-4)]
$output | foreach {
  $parts = $_ -split "\s+", 2
    New-Object -Type PSObject -Property @{
      Name = $parts[1]
    }
}

问题:

  1. 管道应该包括原始内容(来自 GCI)、修改后的内容(来自 7a),还是两者都包括?
  2. 如果两者都有,这是怎么做到的?
  3. 结果文件 (Archive.zip) 的路径应该添加到管道中,还是由函数返回?

这有点主观,但我会说:

  1. 在失败的情况下重新抛出任何引发的异常(或使用 Write-Error)
  2. 除非有意义或被请求,否则不要产生输出
  3. 解析输出和 return 正确的对象,而不仅仅是来自您包装的可执行文件的输出字符串

在您的示例中,我可能会为 Archive.zip 添加一个 [Switch]$PassThru 参数和 return 一个 FileInfo 对象:Write-Output $(Get-Item $Archive)(如果存在)

Updating archive .\files.zip ... Compressing files.zip ?检查你的函数在将 Archive.zip 添加到 Archive.zip 时是否有 case,这应该会引发警告,如复制自身。

关于管道 - 我认为你应该使用 -passthru 开关,如果开关存在,return 存档作为 Get-Item 结果(System.IO.FileInfo 对象),否则 return 无效。此外,如果您使用 -AsJob 标志,return 作业作为函数结果。

附带说明一下,如果您打算在 7zip 模块中使用存档,则需要指向它们的链接,可能作为通用文件的子类型,或者只是文件,并且由于 New-Archive 正在生成一个存档而不是一组,管道对于这个功能来说似乎是多余的。

总结:

  1. 在这种情况下,修改的内容还是作废。
  2. 没有"both".
  3. 返回一个 System.IO.FileInfo 对象将解决这两个目标。
  4. 考虑添加一个 -LogFile 参数来指示将来自 7zip 的文本数据放在何处。