Referencing multiple "this" objects in nested loops

The following works, but I’m wondering if there is a way to reference the first “this” object within the PSCustomObject construct without having to first assign it to a variable? In this case $pg = $_ like I’m doing with VM = $_.VmName?

$results = Get-SrmProtectionGroup |
    ForEach-Object {
        $pg = $_
        $pg.ListProtectedVms() |
            ForEach-Object {
                [PSCustomObject] @{
                   Group = $pg.Name
                   VM    = $_.VmName
                }
            }
    }

Thank you.

Yes sir, use a foreach loop. I like to mix the foreach and foreach-object

$results = Get-SrmProtectionGroup | ForEach-Object {
    foreach($pg in $_.ListProtectedVms()){
        [PSCustomObject] @{
            Group = $_.Name
            VM    = $pg.VmName
        }
    }
}

I usually prefer foreach to foreach-object. The $_ always seems more unclear when I read code than using foreach.

$results = foreach ($pg in (Get-SrmProtectionGroup)) {
    foreach ($pvm in $pg.ListProtectedVms()) {
        [PSCustomObject] @{
            Group = $pg.Name
            VM    = $pvm.VmName
        }
    }
}

Thank you for the suggestion. I was looking to learn if multiple “this” objects ($_.) can be referenced directly in nested ForEach-Object loops without having to first assign the value to a variable. After researching, seems this is not possible.

Again, thanks!

1 Like

Correct, only the current pipeline item in the innermost loop is available in $_. You have to use a variable in one way or another. You can store it like you did originally. Use a named variable in a foreach loop like Darwin and I suggested. There is also the option of -PipelineVariable if the cmdlets support it. Here is an example using that common parameter.

Get-ChildItem C:\Temp -Directory -PipelineVariable Folder | ForEach-Object {
    # use select to limit each folder query to one file, it can also store the current object in a pipeline variable
    Get-ChildItem $Folder.FullName -File -PipelineVariable File | Select-Object -First 1 -PipelineVariable Selected | ForEach-Object {
        Write-Host "Folder variable has $($Folder.count) item with a path of $($Folder.FullName)" -ForegroundColor Cyan
        Write-Host "File variable has $($File.count) item named $($File.Name)" -ForegroundColor Green
        Write-Host "Selected variable has $($Selected.count) item with a size of $($Selected.length)" -ForegroundColor DarkCyan

        # only the current pipeline item will be available in $_ (aka dollar underbar) which means the innermost loop.
        Write-Host "`$_ has the current file named $($_.Name)" -ForegroundColor DarkGray
    }
}

As you can see in the output, only one item from each loop is available during each execution. This is an easy way to reference each level’s item while sticking with the pipeline/foreach-object.

1 Like

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