Piping Files and Folders

by Feb 7, 2018

Let’s assume you want to create a function that accepts a file path. There are numerous tasks that can be done with files. You may want to copy files, archive them, turn them to hidden files, or whatever else comes to mind. We are not focused on what you do with files here. We want to look at how your PowerShell function can accept files from a user.

So you’d come up with a function like this:

function Process-File
{
    param
    (
        $Path
    )
 
    # do something with the file
    $file = Get-Item -Path $Path
    'File {0} is of size {1} bytes.' -f $file.FullName, $file.Length
}
 
Process-File -Path C:\windows\explorer.exe

The result would look similar to this:

 
PS> Process-File -Path C:\windows\explorer.exe
 
File C:\windows\explorer.exe is of size 3903784 bytes.
 
PS>  
 

This function can always process only one path at a time. If you’d like it to accept more than one path, this is what you’d do:

function Process-File
{
    param
    (
        [string[]]
        $Path
    )
 
    foreach($SinglePath in $Path)
    {
        # do something with the file
        $file = Get-Item -Path $SinglePath
        'File {0} is of size {1} bytes.' -f $file.FullName, $file.Length
    }
}
 
Process-File -Path C:\windows\explorer.exe, C:\windows\notepad.exe

Now, your function would accept any number of comma-separated paths. What if you’d also like it to accept the paths via pipeline? Then this is what you’d add:

function Process-File
{
    param
    (
        [Parameter(ValueFromPipeline)]
        [string[]]
        $Path
    )
 
    process
    {
        foreach($SinglePath in $Path)
        {
            # do something with the file
            $file = Get-Item -Path $SinglePath
            'File {0} is of size {1} bytes.' -f $file.FullName, $file.Length
        }
    }
}
 
Process-File -Path C:\windows\explorer.exe, C:\windows\notepad.exe
'C:\windows\explorer.exe', 'C:\windows\notepad.exe' | Process-File

Basically, you now have two nested loops: process {} is the loop used by pipeline objects, and the foreach loop inside of it takes care of string arrays submitted by the user.

Now what if you wanted Get-ChildItem to provide paths to the function? It does not return strings. It returns filesystem objects, and inside of these, there is a property called “FullName” that has the path. This is what you’d do:

function Process-File
{
    param
    (
        [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [string[]]
        [Alias("FullName")]
        $Path
    )
 
    process
    {
        foreach($SinglePath in $Path)
        {
            # do something with the file
            $file = Get-Item -Path $SinglePath
            'File {0} is of size {1} bytes.' -f $file.FullName, $file.Length
        }
    }
}
 
Process-File -Path C:\windows\explorer.exe, C:\windows\notepad.exe
'C:\windows\explorer.exe', 'C:\windows\notepad.exe' | Process-File
Get-ChildItem -Path c:\windows -Filter *.exe | Process-File

Now, the function would not only accept strings via pipeline (ValueFromPipeline), but also objects (ValueFromPipelineByPropertyName) that have a property named like the parameter (Path) or one of its aliases (FullName). Mission accomplished. Your function would now provide maximum flexibility for the user, and this is basically what cmdlets do too.

Are you an experienced professional PowerShell user? Then learning from default course work isn’t your thing. Consider learning the tricks of the trade from one another! Meet the most creative and sophisticated fellow PowerShellers, along with Microsoft PowerShell team members and PowerShell inventor Jeffrey Snover. Attend this years’ PowerShell Conference EU, taking place April 17-20 in Hanover, Germany, for the leading edge. 35 international top speakers, 80 sessions, and security workshops are waiting for you, including two exciting evening events. The conference is limited to 300 delegates. More details at www.psconf.eu.

Twitter This Tip! ReTweet this Tip!