2

In this answer the author proposed the following snippet:

dir -Path C:\FolderName -Filter *.fileExtension -Recurse | %{$_.FullName}

I can understand the majority of it, but I'm unable to search documentation for the last part. The output of the search is piped | and used in %{} and as $_.

I have experimented around it, %{} is a for-each statement I believe, bing search was not effective. $_ is also somewhat magic: it is a variable, with no name and thus immediately consumed? I don't care much for the .FullName, that part I sorted out. Again, bing search was not effective, nor searching for those char sequences in PowerShell docs.

Can anybody explain it to me?

mklement0
  • 382,024
  • 64
  • 607
  • 775
Daemon Painter
  • 3,208
  • 3
  • 29
  • 44
  • 1
    It represents the object(s) passed down the pipeline. That's why you were able to reference the property of `.Fullname`. – Abraham Zinala Mar 10 '21 at 14:46
  • Just like you would store an object in a variable, such as : `$Var = Get-Process -Name wuasrv` in this case, I can reference the objects properties using dot notation: `$Var.Name`, `$_` is the same concept. It's a place holder for the actual object passed down. – Abraham Zinala Mar 10 '21 at 14:53

2 Answers2

6

%{} is not "a thing" - it's two things: % and {}

% is an alias for the ForEach-Object cmdlet:

PS ~> Get-Alias '%'
CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           % -> ForEach-Object

... so it resolves to:

... |ForEach-Object { $_.FullName }

ForEach-Object is basically PowerShell's map function - it takes input via the pipeline and applies the operation described in the {} block to each one of them.

$_ is an automatic reference to the current pipeline input item being processed

You can think of it a bit like a foreach($thing in $collection){} loop:

1..10 |ForEach-Object { $_ * 10 }
# produces the same output as
foreach($n in 1..10){
    $n * 10
}

Except we can now stick our loop in the middle of a pipeline and have it produce output for immediate consumption:

1..10 |ForEach-Object { $_ * 10 } |Do-SomethingElse

ForEach-Object is not the only thing that makes use of the $_ automatic variable in PowerShell - it's also used for pipeline-binding expressions:

mkdir NewDirectory |cd -Path { $_.FullName }

... as well as property expressions, a type of dynamic property definition supported by a number of cmdlets like Sort-Object:

1..10 |Sort-Object { -$_ } # sort in descending order without specifying -Descending

... Group-Object:

1..10 |Group-Object { $_ % 3 } # group terms by modulo congruence

... and Select-Object:

1..10 |Select-Object @{Name='TimesTen';Expression={$_ * 10}} # Create synthetic properties based on dynamic value calculation over input 
Doug Maurer
  • 8,090
  • 3
  • 12
  • 13
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • 4
    One nice thing about Visual Studio Code is if you install the powershell addin it will warn you about using alias and tell you what the alias refers to. – Bee_Riii Mar 10 '21 at 14:45
3

To complement Mathias' answer, which explains the specific constructs well, with how you could / couldn't have discovered this information yourself, using PowerShell's own help system:

Relevant help topics and use of the help system:

Note: To get an overview of all aspects of PowerShell's help system, simply run help.

  • % is a built-in alias for the ForEach-Object cmdlet:

    • Use Get-Help ForEach-Object to view the help topic in the terminal.
      • If no local topics are found, you must download them via the Update-Help cmdlet.
    • Tips:
      • Add the -Online switch to open the (potentially more current) online version of the topic in your browser.

      • You can bootstrap your use of Get-Help with Get-Help Get-Help (or even help help):

        • Cmdlet-specific help comes in detail levels: terse (default, shows the syntax and overview description only), -Detailed (includes parameter descriptions and example commands) and -Full (additionally includes technical parameter information and extended notes).
        • -Examples can be used to show example commands only.
        • With keyword-based search (see below), you can limit results to topics of a certain category with the -Category parameter.
      • For convenience, you can also use the built-in help function, which wraps Get-Help calls with display paging (simply put: by piping the output to the more utility) and defaults to detail level -Full.

  • {...} is a script block literal, a block of arbitrary PowerShell code that can be invoked on demand:

    • help about_Script_Blocks shows the topic locally; the about_ prefix indicates that the topic is a conceptual help topic (rather than one covering a specific command); when you use Get-Help to search for a keyword (see below), you can (somewhat obscurely) limit the results to conceptual topics with -Category HelpFile.
    • Note: As of this writing, about_ topics can not yet be directly viewed online by adding -Online - see GitHub issue #13550 - but it's easy to google them by name.
  • $_ is a variable, as the $ sigil followed by an identifier implies, and is more specifically an automatic (built-in) variable:

    • help about_Variables covers variables in general.
    • help about_Automatic_Variables covers the automatic ones.

How the above can / cannot be discovered based on symbols and aliases alone:

Doing a web search for symbols is notoriously unhelpful.

  • As an aside: Running distinct syntax constructs such as % and { ... } together without whitespace between them (e.g. %{$_.FullName}) constitutes an additional barrier, and should therefore be avoided.

Narrowing your search by using only PowerShell's help system helps, but only to a limited degree:

  • %

    • Because Get-Help is aware of aliases, help % actually works fine and directly shows ForEach-Object's help topic.
    • help % -Examples shows example commands that include the use of script blocks and the automatic $_ variable.
  • Even though Get-Help supports keyword-based search, searching for symbol-based terms {} and $_ directly isn't helpful, because even when limiting the search to conceptual (about_-prefixed topics) with -Category HelpFile, there are either too many hits (help '$_' -Category HelpFile) or the relevant topic doesn't show at all (help '{}' -Category HelpFile)

  • $_ can be discovered indirectly, IF you already know that it is an instance of a variable:

    • help variables -Category HelpFile happens to take you directly to the relevant (local) about_Automatic_Variables topic,
    • whereas help variable -Category HelpFile lists the following matching topics about_Variable_Provider, ``, about_Automatic_Variables, about_Preference_Variables, about_Remote_Variables, about_Variables, and about_Environment_Variables
    • Note: Thanks to PowerShell's pervasive support for wildcard expressions, you could have performed the search also as follows: help about*variable* - be sure to enclose both sides of the search term in *.
  • {...} can be discovered indirectly, IF you already know that it is an instance of a script (code) block:


Potential future improvements:

  • It would be a great improvement if PowerShell's help system supported focused symbol-based searches.

  • Similarly, the ability to directly look up operators, such as -match, the regular-expression matching operator, would be helpful:

    • GitHub issue #11339 proposes just that.

    • On a related note, GitHub issue #11338 proposes adding the ability to look up documentation for .NET types (online).

    • This answer contains custom functions Show-OperatorHelp and Show-TypeHelp, which fill that gap for now (also available as Gists).

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • I'd give +2 on this one. Websearch (especially on MS systems...) could help a little more. I didn't know about the help function, PowerShell is still pretty new to me. – Daemon Painter Mar 11 '21 at 14:25
  • Glad to hear it, @DaemonPainter. PowerShell is pretty "self-aware" in general - other helpful commands are [`Get-Command`](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/get-command) and [`Get-Member`](https://learn.microsoft.com/powershell/module/microsoft.powershell.utility/get-member) - but the help system certainly has room for improvement. Note that PowerShell (Core) 7+ now provides a bootstrapping hint when you enter an interactive shell: `Type 'help' to get help.` Running `help` shows a high-level overview of PowerShell's help system. – mklement0 Mar 11 '21 at 14:37
  • Nice extra documentation. Some concepts are clearer for me now ! – Pierre-Gilles Levallois Feb 24 '23 at 08:50