powershellforeach-object

what is the scope of $_ in a foreach-object loop in Powershell


Here's a simplified version of the script I'm trying to write:

$i = 0
Get-ChildItem -Filter *.bat|
ForEach-Object {
    Write-Host $_.Name
    switch ($i) {
        0 { Write-Host $_.Name}
        1 { Write-Host $_.Name }
        2 { Write-Host $_.Name }
        Default {Write-Host "nothing here"}
    }
}

So the first Write-Host command works as expected, but once I get inside the switch statement Write-Host prints out nothing, which is mystifying to me. I assume the problem has something to do with the scope of $_ but I don't know. I'm a total Powershell amateur. Isn't the switch statement inside the foreach loop so the scope shouldn't be an issue?

If I do this then everything works like I expected, the filenames get printed from inside and outside the switch statement:

$i = 0
Get-ChildItem -Filter *.bat |
ForEach-Object {
    Write-Host $_.Name
    $temp = $_.Name
    switch ($i) {
        0 { Write-Host $temp }
        1 { Write-Host $temp }
        2 { Write-Host $temp }
        Default {Write-Host "nothing here"}
    }
}

Can someone explain what is going on here?


Solution

  • $_ is getting a different value inside your switch statement - it's actually getting the value of $i and it therefore is an Int32 and doesn't have a Name property. When you assign to $temp and use that inside the switch it works because you assign the (string) value you want to a new variable.

    If you were to use $_ again after the switch you would be able to access all the properties as before.

    By using the code below, you're able to see what type $_ is taking as it is used in the different scopes/pipelines

    Get-ChildItem -Filter *.bat |
    ForEach-Object {
        Write-Host $_.gettype()
        switch ($i) {
            Default {
              Write-Host $_.gettype()
            }
        }
    }