Explanating of code, $($_.FullName) from Get-ChildItem and ForEach-Object

Get-ChildItem -Path "C:\" -Filter *.log -Recurse |
    ForEach-Object {
        "$($_.FullName) is $($_.Length) bytes"
    }

Question regarding “$($_.FullName)” - what does it do in detail? If I only use $_.FullName it only list the filename of the log file.

In a string, the syntax $( $obj.property ) returns the content of the property “property” of the variable obj.

if you just put $_.property, $_ is replaced by a string representing the object (in case of item, it is the property name) and is concatenate with the string “.property”

Example : suppose that $_ represente the item c:\windows\win.ini

“$_.fullname” returns “win.ini.fullname”

“$($_.fullname)” returns “c:\windows\win.ini”

1 Like

Ok. Is there any explanation why $_ represente the item?

To answer your last question first, $_ represents the item that was taken from the pipeline (which is being filled by the Get-ChildItem cmdlet) by the Foreach-Object and passed into your code block. Why is it named $_? It’s a common representation taken from PowerShells’ predecessors, e.g. Perl, that represents “the current item”.

The reason "$_.FullName" returns only the file name followed by the string “.FullName” because only the $_ in resolved. The “.FullName” is treated as a literal string value.

The reason "($_.Fullname)" returns only the file name (without the “.FullName”) is because you’ve now supplied an expression, and the value of the expression is the “FullName” property of the current item ($_).

String interpolation can be a real PITA, and it’s also slower that using the format operator -f. To get the result you want, try using this instead:

"{0} is {1} bytes" -f $_.FullName, $_.Length

1 Like

This is by design.

As dot character is not allowed in variable name :

  • in the syntax “$_.fullname”, powershell considers that $_ is the object to display and .fullname a literal string.
  • in the syntax “$($_.fullname) xxx”, you say to powershell that the string between ( and ) is a powershell command to execute before putting the result in the string.
1 Like

You may read more about the Pipline Variable ($PSItem or $_) here:

… and about the Subexpression Operator ($(...)) here:

2 Likes

Another way to do the same thing with syntax that is easier to understand IMO

$Items = Get-ChildItem -Path "C:\" -Filter *.log -Recurse 
foreach ($Item in $Items) {
    "$($Item.FullName) is $($Item.Length) bytes"
}
1 Like

IMHO the plural “s” is very easy to miss. That’s why I usually use for names for arrays something with the ending “$...List” … in this case it would be $ItemList … and it fits to the PowerShell rule only to use singular names. :wink:

1 Like

Agreed - $ItemList is a better choice :slight_smile:

So, it’s also possible to use $PSItem but $_ works as well ?

A example from the documentation that was easy to understand Subexpression:

"Today is $(Get-Date)"

$PSItem does work, but $_ is a far more widely used practice

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.