MicrosoftDocs / PowerShell-Docs

The official PowerShell documentation sources
https://learn.microsoft.com/powershell
Other
2.01k stars 1.58k forks source link

about_Calculated_Properties does not mention expression variables being read-only #11440

Closed caliniaru closed 1 month ago

caliniaru commented 1 month ago

Prerequisites

Links

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_calculated_properties?view=powershell-7.4

Summary

Take this example:

function TestExpression
{
    $x = 0;
    Get-Process | Select-Object @{Name = "ProcessID"; Expression = {$_.Id; $x ++;}}
    $x;
}

TestExpression;

The output is:

1112
2884
5256
0

There is no mention of variables inside expression being read-only.

Details

No response

Suggested Fix

No response

michaeltlombardi commented 1 month ago

The problem you're running into isn't that variables inside of expressions are read-only, but that you're trying to modify a variable in a child scope. The value of the expression is a scriptblock, and runs in a child scope. In about_Scopes, the documentation explains:

Items that you create or change in a child scope don't affect the parent scope, unless you explicitly specify the scope when you create the items.

It's also worth noting that if you want to perform an action for every item output by a cmdlet, the idiomatic option is to use the ForEach-Object cmdlet (or a foreach loop). Reusing your example, I might write something like:

function Test-Example {
    [CmdletBinding()]
    param()

    begin {
        $processCount = 0
    }

    process {
        Get-Process pwsh | ForEach-Object {
            # Increment the count
            $processCount++
            # Output the item to the pipeline
            [pscustomobject]@{ ProcessID = $_.Id }
        }
    }

    end {
        Write-Verbose "Process count: $processCount"
    }
}

Test-Example -Verbose
VERBOSE: Process count: 2

ProcessID
---------
    12388
    17912
caliniaru commented 1 month ago

Thank you for the prompt response.