Trying to use ForEach() method and confused what I'm doing wrong

Hello,

I have List of Objects returned from AzureRM cmdlet and I’m trying just to output them to output stream and it’s not working for some reason.

https://gist.github.com/artisticcheese/7467954280c1de6f3ceb2d2f0b1647c6

It appears that you cannot do that on a generic list…

$a = [System.Collections.Generic.List[int]]::new()
$a.AddRange([int[]](1,4,7,10))

$a.ForEach

OverloadDefinitions                      
-------------------                      
void ForEach(System.Action[int] action)

This is the native .NET method, and it returns nothing. It gets called like this:

$a.ForEach({ Write-Host ("Value: {0}" -f $args[0]) })

Value: 1
Value: 4
Value: 7
Value: 10

A couple of ways to make it behave…

$a.GetEnumerator().ForEach({ $_ })

foreach($x in $a) {
    $x
}

This should work as well:

$nicInfo.IpConfigurations | ForEach{$_}

I’m fairly certain the .foreach{} method doesn’t support $_, only $PSItem. Can’t explain why but that’s my experience.

Nope, it supports $_ and $PSItem. In the PowerShell code that handles those things, there is a difference, but they’re handled the same when parsing script blocks, so there aren’t any situations where you can use one and not the other.

However, there are situations where they aren’t used by themselves. Some of the methods on the List class (including its ForEach() method, which differs from the usual PowerShell ETS method that can be used on almost anything that doesn’t have it’s own ForEach()-named method) can’t, for example, and you have to either use $args or define a param() block for them. For example:

using namespace System.Collections.Generic
$List = [List[int]]::new()
$List.AddRange( @(1, 2, 3, 4, 5) )

$List.FindAll(
    {
        param($Item)
        $Item -gt 3
    }
)


# output
4
5

PSItem gets resolved to _ internally, so with other words: it’s an alias.

Well, sort of. The code itself does distinguish clearly between them as different tokens, but in terms of how the function they’re treated identically from what I’ve seen.

They have this in the source code for Core:

internal static string GetUnaliasedVariableName(string varName)
{
	return varName.Equals(SpecialVariables.PSItem, StringComparison.OrdinalIgnoreCase)
			   ? SpecialVariables.Underbar
			   : varName;
}

internal static class SpecialVariables
{
	internal static bool IsUnderbar(string name) { return name.Length == 1 && name[0] == '_'; }
	internal const string PSItem = "PSItem";  // simple alias for $_
	internal const string Underbar = "_";
}

So if varName == “PSItem” then return “_”

So is there any difference between $_ and $psitem?

There is a difference in the amount of characters you have to write. In functionality, no.

Would you know why ‘-and’ and ‘-or’ have the same precedence?