Star InactiveStar InactiveStar InactiveStar InactiveStar Inactive
 

I love to explain things in clear, simple terms. So, a few weeks ago, I tweeted a request for a Windows PowerShell concept that could use more explanation. Andy Fair (@ravensportal) from Oklahoma City asked for a clear explanation of the PassThru parameter. PassThru is frequently used and frequently ignored, so I’m taking him up on his idea. Thanks, Andy!

The PassThru parameter lets you request output from cmdlets that return no output by default. It’s used most often to verify that the cmdlet did what you intended.

 

Using the PassThru Parameter

In Windows PowerShell, Get-* cmdlets almost always return the object that they get. New-* cmdlets typically return the objects that they create. Add-*, Format-*, Convert-*, and Update-* cmdlets sometimes return the objects that they’ve changed. But many cmdlets return nothing – at least by default.

For example, the Copy-Item cmdlet doesn’t return anything. It just copies the object in the path to the specified destination. In this case, it copied the OutputFile.txt file to the CopyTest subdirectory.

    PS C:\> Copy-Item -Path C:\ps-test\OutputFile.txt -Destination .\CopyTest
    PS C:\> 

 

This is fine, because I typically don’t want any noise in my scripts. But, if I want to verify that the file got to its intended destination, I need to run a Get-ChildItem or Test-Path command. Or, I can use the PassThru parameter of Copy-Item. In Copy-Item, the PassThru parameter returns the copied item in its new location.

    PS C:\> Copy-Item -Path .\OutputFile.txt -Destination .\CopyTest\OutputFile.txt –PassThru

    Directory: C:\ps-test\CopyTest

    
     Mode                LastWriteTime     Length Name
     ----                -------------     ------ ----
     -a---                2/24/20148:43 PM     20 OutputFile.txt    

 

In a script, I can save the output to a variable and check it before I execute the next command.

    $file = Copy-Item -Path .\OutputFile.txt -Destination .\CopyTest\OutputFile.txt –PassThru
    if ($file) { …<keep going>… }   

-or-

    if ($file.FullName –like “*CopyTest\OutputFile.txt”) { …<keep going>…. }

 

When using the PassThru parameter of a command, be sure to check the type of the object that it returns. This information should be in the help file for the command, either in the description of the PassThru parameter or the Outputs section of the cmdlet help file.

For example, the help for Copy-Item says:

“When you use the PassThru parameter, Copy-Item returns an object that represents the copied item. Otherwise, this cmdlet does not generate any output.”

It’s important to check before writing your verification code (e.g. if ($file) ), because not all cmdlets return the object that they change. For example, when the cmdlets in the Azure module (Azure Service Management) have a PassThru parameter, they return a Boolean value — $True or $False  — that represents the success ($True) or failure ($False) of the command.

For example, the Get-AzurePublishSettingsFile cmdlet downloads an identity file, but it does not return an object that represents the file or its secure location. By default, the cmdlet returns nothing, but if you use its PassThru parameter, it returns $True or $False.

$result = Get-AzurePublishSettingsFile
    if ($result) { …<keep going>… }

 

Find the PassThru Parameter

To find cmdlets in your modules that have the PassThru parameter, use a command like this one. It runs a Get-Command command and saves the results in the $c variable. Then it uses the Where-Object cmdlet to find parameters with the name “PassThru.” If it finds a PassThru parameter, it returns the cmdlet that was saved in the $c pipeline variable. (I’m running Windows PowerShell 4.0, but this command should work on 3.0 and later.)

Get-Command -PipelineVariable c | 
    where { $_.ParameterSets.Parameters.Name -eq "PassThru" } | 
        ForEach-Object {$c}

 

On my machine, it returned 48 cmdlets with the following distribution of verbs. It’s really all over the place.

PS C:\>  $pass | Group-Object -Property Verb
Count Name        Group
—– —-        —–
6 Add             {Add-Computer, Add-Content, Add-History, Add-Member…}
2 Clear           {Clear-ItemProperty, Clear-Variable}
1 Compare         {Compare-Object}
2 Copy            {Copy-Item, Copy-ItemProperty}
1 Disable         {Disable-PSBreakpoint}
1 Enable          {Enable-PSBreakpoint}
1 Export          {Export-Alias}
2 Import          {Import-Alias, Import-Module}
2 Invoke          {Invoke-RestMethod, Invoke-WebRequest}
2 Move            {Move-Item, Move-ItemProperty}
3 New             {New-Alias, New-ModuleManifest, New-Variable}
1 Out             {Out-GridView}
1 Pop             {Pop-Location}
1 Push            {Push-Location}
2 Remove          {Remove-Computer, Remove-PSSnapin}
3 Rename          {Rename-Computer, Rename-Item, Rename-ItemProperty}
1 Restart         {Restart-Service}
1 Resume          {Resume-Service}
8 Set             {Set-Alias, Set-Content, Set-Item, Set-ItemProperty…}
1 Show            {Show-Command}
2 Start           {Start-Process, Start-Service} 

 

Implement the PassThru Parameter

You can also add the PassThru parameter to the scripts and functions that you write. Because PassThru doesn’t take a value, its parameter type is always Switch or SwitchParameter, regardless of the type of the object that it returns. And, PassThru parameters should always be optional (not mandatory). For example, I have a little script that adds a timestamp to the file name. By default, it doesn’t return any output, so I always run a Get-Item or Test-Path when it completes. Instead, I’ll add a PassThru parameter. Here’s the “before” version:

    Param
            (
                [parameter(Mandatory=$True)]
                [String]
                $FilePath
            )

    if (!(Test-Path $FilePath)) {throw "Can't find file\folder at $filepath"}

    $item = Get-Item $FilePath
    $timestamp = (Get-Date $item.Lastwritetime -Format o) -replace ":", "-" 

    $newname = $item.BaseName + "-" + $timestamp + $item.Extension
    Rename-Item -Path $FilePath -NewName $newname

 

Now, I’ll add a PassThru parameter. It’s optional and the parameter type is Switch. I also add a line of code at the end that checks the value of that PassThru parameter. Switch parameters have a Boolean ($True/$False) value. The value is $True if the parameter is used (IsPresent) in the command and $False if it is not used.

In my code, if the PassThru parameter is $True ( if ($PassThru) ), I call the Get-Item cmdlet to return the file with the new name.

    Param
    (
        [parameter(Mandatory = $True)]
        [String]
        $FilePath,
        
        [parameter(Mandatory = $False)]
        [Switch]
        $PassThru
    )

    if (!(Test-Path $FilePath)) { throw "Can't find file\folder at $filepath" }

    $item = Get-Item $FilePath
    $timestamp = (Get-Date $item.Lastwritetime -Format o) -replace ":", "-"

    $newname = $item.BaseName + "-" + $timestamp + $item.Extension
    Rename-Item -Path $FilePath -NewName $newname

    if ($PassThru) { Get-Item $newname }

 

But, wait! The Rename-Item cmdlet that I call to change the file name has a PassThru parameter that returns the item that it renamed. All I need to do is to pass the value of my PassThru parameter to the PassThru parameter of Rename-Item.

Switch parameters can take a $True or $False value. Just type a colon (:) after the parameter name and then type the Boolean value. Here’s the syntax:

    -PassThru:$True
    -PassThru:$False

 

Because my PassThru parameter also has a Boolean value, I can type the colon and then type the $PassThru parameter.

So I can replace:

    if ($PassThru) { Get-Item $newname }

… with a Rename-Item command that uses the PassThru parameter:

    Rename-Item -Path $FilePath -NewName $newname -PassThru:$PassThru

This instance of reusing the PassThru parameter of Rename-Item isn’t just a corner case. In almost all of my scripts and functions that have a PassThru parameter, I just reuse the PassThru parameter of the final command.

 

Thanks again for the question, Andy. If you’d like me to explain a Windows PowerShell concept, or something that you’ve seen in a forum or blog post, just let me know.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at This email address is being protected from spambots. You need JavaScript enabled to view it. or follow her on Twitter at @juneb_get_help.

If you have questions about our products, please post in our support forum.
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.
Copyright © 2024 SAPIEN Technologies, Inc.