I want to do something like this:
<statement> | <filter1> | <filter2> if <condition> | <filter3> | <filter4> | <filter5>
The results of <statement> run through <filter1>, then they run through <filter2> only if <condition> is met, then through the remaining filters regardless of whether <filter2> was applied. This is the equivalent of:
if (<condition>) {
<statement> | <filter1> | <filter2> | <filter3> | <filter4> | <filter5>
} else {
<statement> | <filter1> | <filter3> | <filter4> | <filter5>
}
This would be useful in functions where a given filter is applied to the result set only if a certain switch was invoked. If the conditional filter occurs early in a long pipeline, writing it with an outer if-block results in a lot of repetition of code, especially if there is more than one conditional filter.
Here's an example. The following function shows the permissions a given account has in a given directory subtree (e.g. Show-AccountPerms \\SERVERX\Marketing DOMAIN\jdoe
gives a report of permissions that the user DOMAIN\jdoe has in the directory tree under \SERVERX\Marketing).
function Show-AccountPerms {
param (
[parameter(mandatory = $true)]$rootdir,
[parameter(mandatory = $true)]$account,
[switch]$files,
[switch]$inherited
)
gci -r $rootdir `
|where {$_.psiscontainer} `
|foreach {
$dir = $_.fullname
(get-acl $_.pspath).access `
| where {$_.isinherited -eq 'False'} `
|foreach {
if ($_.identityreference -eq $account) {
"{0,-25}{1,-35}{2}" -f $_.identityreference, $_.filesystemrights, $dir
}
}
}
}
By default, it only shows explicit permissions (enforced by the | where {$_.isinherited -eq 'False'}
filter), and only on directories (enforced by the |where {$_.psiscontainer}
filter).
However, I want to ignore |where {$_.psiscontainer}
if the -files switch is invoked, and ignore | where {$_.isinherited -eq 'False'}
if the -inherited switch is invoked. Accomplishing this with outer if blocks would quadruple the code, and almost 75% of it would be repetition. Is there a way to keep these filters in-line but instruct powershell to only apply them of the corresponding switch is false?
Please note that this is just an example, so I'm not interested in any workarounds specific to this function. I'm looking for an answer to my general question regarding piping conditionally, not a solution for how to accomplish this particular task.
Powershell pipe works in an asynchronous way. Meaning that output of the first cmdlet is available to the second cmdlet immediately one object at the time (even if the first one has not finished executing). and then stop the execution by pressing Control+C you will see part of directory is written to the text file.
The && operator executes the right-hand pipeline, if the left-hand pipeline succeeded. Conversely, the || operator executes the right-hand pipeline if the left-hand pipeline failed.
InputObject is a generic name used for a parameter that takes pipeline input. It's part of internal PowerShell naming convention and there is nothing special about it.
The pipeline character in Windows PowerShell is the vertical bar (also called the pipe: | ). On most U.S. keyboards, it is found on the key with the backslash. You can press Shift + Backslash to get the pipe character.
You can test for both conditions in your filter allowing the object down the pipeline if either one is true. If your "condition" is on the left side of the -or
operator, make it result to $true
if you don't want your filter condition tested.
To use your example:
| where {$_.psiscontainer}
becomes:
| where {$files -or $_.psiscontainer}
and
| where {$_.isinherited -eq 'False'}
becomes
| where {$inherited -or $_.isinherited -eq 'False'}
To generalise:
<statement> | <filter1> | <filter2> if <condition> | <filter3> | <filter4> | <filter5>
becomes:
<statement> | <filter1> | <-not condition -or filter2> | <filter3> | <filter4> | <filter5>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With