Some history on this -
Given PS > $a = 1..9 | ? {$_ -eq 10}
Powershell 2.0 behavior
PS > $a | % { "hello" }
hello
PS > $null | % { "hello" }
hello
Powershell 3.0 behavior - "fixed" the issue when variable is null, but built-in $null still iterates
PS > $a | % { "hello" }
PS > $null | % { "hello" }
hello
In the ForEach-Object documentation in 3.0 they added this -
Because Windows PowerShell treats null as an explicit placeholder, the
ForEach-Object cmdlet generates a value for $null, just as it does for
other objects that you pipe to it.
PS C:\> 1, 2, $null, 4 | ForEach-Object {"Hello"}
Hello
Hello
Hello
Hello
The about_automatic_variables documentation for $null was also updated for 3.0.
Powershell 2.0 $null documentation
$NULL
Contains a NULL or empty value. You can use this variable to
represent NULL in commands and scripts instead of using the string
"NULL". The string can be interpreted as TRUE if it is converted to a
non-empty string or a non-zero integer.
Powershell 3.0 $null documentation
$NULL
$null is an automatic variable that contains a NULL or empty value. You
can use this variable to represent an absent or undefined value in commands
and scripts.
Windows PowerShell treats $null as an object with a value, that is, as an
explicit placeholder, so you can use $null to represent an empty value in a
series of values.
For example, when $null is included in a collection, it is counted as one of
the objects.
C:\PS> $a = ".dir", $null, ".pdf"
C:\PS> $a.count
3
If you pipe the $null variable to the ForEach-Object cmdlet, it generates a
value for $null, just as it does for the other objects.
PS C:\ps-test> ".dir", "$null, ".pdf" | Foreach {"Hello"}
Hello
Hello
Hello
As a result, you cannot use $null to mean "no parameter value." A parameter
value of $null overrides the default parameter value.
However, because Windows PowerShell treats the $null variable as a placeholder,
you can use it scripts like the following one, which would not work if $null
were ignored.
$calendar = @($null, $null, “Meeting”, $null, $null, “Team Lunch”, $null)
$days = Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"
$currentDay = 0
foreach($day in $calendar)
{
if($day –ne $null)
{
"Appointment on $($days[$currentDay]): $day"
}
$currentDay++
}
Appointment on Tuesday: Meeting
Appointment on Friday: Team lunch
Note - they also made foreach
keyword behave the same as ForEach-Object in 3.0 (skipping $null valued variables but converts the $null built-in to a iterable value) but they didn't mention the new behavior in the documentation like they did with ForEach-Obect.