Enhancing the pipeline's content?

97 Views Asked by At

Let's assume that you have a command that compresses files using 7-zip that accepts values from the pipeline:

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 {}
}

Assuming the foo directory has these files: a.txt, b.txt, c.txt

Executing the command:

PS Foo> GCI | New-Archive

produces output is something like:

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

It's easy enough to parse the output, capture the results of the compression, and add it to the pipeline:

...
$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]
    }
}

Questions:

  1. Should the pipeline include the original content (from GCI), the modified content (from 7a), or both?
  2. If both, how is this done?
  3. Should the path of resulting file (Archive.zip) be added to the pipeline, or returned by the function?
2

There are 2 best solutions below

2
Vesper On BEST ANSWER

Updating archive .\files.zip ... Compressing files.zip ? Check if your function has a case when adding Archive.zip to Archive.zip, this should throw a warning like copying over itself.

About pipeline - I think you should employ -passthru switch, if the switch is present, return the archive as a Get-Item result (System.IO.FileInfo object), otherwise return void. Also, if you'd use -AsJob flag, return the job as the function result.

On a side note, if you plan to work with archives in your 7zip module, you need links to them, probably as a subtype of generic file, or just files, and since New-Archive is producing one archive and not a set of them, piping seems redundant for this function.

Summary:

  1. In this case, modified content or void.
  2. No "both".
  3. Returning a System.IO.FileInfo object will solve both goals.
  4. Consider adding a -LogFile parameter that would indicate where to put text data from 7zip.
2
Mathias R. Jessen On

This is a bit subjective, but I would say that:

  1. Re-throw any exceptions raised (or use Write-Error) in case of failure
  2. Don't produce output unless it makes sense or is requested
  3. Parse the output and return proper objects, not just output strings from the executable you wrap

In your example I would probably add a [Switch]$PassThru parameter and return a FileInfo object for Archive.zip: Write-Output $(Get-Item $Archive) if present