Remove empty elements from an array in PowerShell

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

Given various definitions of "empty", I will demonstrate how to remove / filter out empty elements from an array in PowerShell.

You will typically define empty as $null, an empty string, a string consisting only of whitespace, or a combination of two or more of these.

I'm using Where-Object to demonstrate here, but these are just examples. Remember that you can put the code I show you inside foreach loops or ForEach-Object if that's more suitable and/or efficient in your case, inside an if () {} statement. This is more efficient in many cases as someone pointed out. Where-Object seems obvious for demonstrative purposes.

Remove and consider only $null as empty

In PowerShell version 4 and up, you can use the LINQ-based, optimized (faster, but likely more memory-consuming) "Where" method on the array to remove the $null elements. You can of course also use the regular pipeline-based cmdlet Where-Object as you can in PowerShell v2.

I'll show you the PSv4 and up way now, but will from then on stick to PSv2 syntax, to be friendlier to people stuck in non-optimal environments with older software (trust me, it happens).

I'll be using a four-element array that represents all the cases. Here's the PSv4 syntax for the optimized .Where({}).

Since we're only filtering out $null, the expected count of elements remaining in the list/array should be 3, and as we can see, it is.

Putting $null on the left side of the comparison is necessary if you have a potentially nested array, so I will use the best-practice form in this example.

PS C:\> $Array = @("", " ", $null, "a")

PS C:\> $Array.Count

PS C:\> $NewArray = $Array.Where({ $null -ne $_ })

PS C:\> $NewArray.Count

Here's the same example using the PSv2-compatible syntax I'll stick to from now on.

PS C:\> ($Array | Where { $null -ne $_ }).Count

Remove and consider only empty strings as empty, keeping $null

To remove only empty strings and keep $null, whitespace-only strings, and anything else, you can simply use the comparison operator in the same way as for $null only, but instead compare to an empty string. "" or ' ' (the latter are single quotes).

This will keep the space, $null and the letter, and should give a count of 3. It does.

PS C:\> (@("", " ", $null, "a") | Where { $_ -ne "" }).Count 

Remove and consider $null and empty strings as empty elements

Both $null and empty strings are considered false, so you can actually just throw the pipeline object into the Where-Object script block.

Here we should get a count of two elements, the space and the letter, and we do.

PS C:\> @(@("", " ", $null, "a") | Where { $_ }).Count

I will demonstrate an explicit way as well. If you have integers with the numeric value "0" in the array, they will also be considered false, so if this is relevant, and you want to keep those, use this:

PS C:\> @(@("", " ", $null, "a") | Where { $null -ne $_ -and $_ -ne ""}).Count

Another explicit way that's v2-/.NET 3.5-compatible is to use the [string]::IsNullOrEmpty("string here") method:

PS C:\temp> @(@("", " ", $null, "a") | Where { -not [string]::IsNullOrEmpty($_) }).Count

Remove and consider $null, empty strings and whitespace-only strings as empty

Since $null and empty are considered false, we can use that to filter, and you might think that running the System.String.Trim() method on the string is a good idea - and it's not bad, except it produces an error for the $null element (can't call method on a null-valued expression).

To work around this, you can simply check for truth first, and then Trim(), removing all whitespace. If there is nothing else in the string, this leaves you with an empty string that will be considered false, and thus the element will be filtered out by Where-Object when the last condition returns false.

PS C:\> (@("", " ", $null, "a") | Where { $_ -and $_.Trim() }).Count

PS C:\> @("", " ", $null, "a") | Where { $_ -and $_.Trim() }

In PowerShell version 3 and up (.NET framework 4 and up), you can also access the System.String class' method IsNullOrWhiteSpace(), to do exactly the same (it returns true for empty strings too):

PS C:\> @("", " ", $null, "a") | Where { -not [string]::IsNullOrWhiteSpace($_) }
PS C:\>

A regex alternative

To make sure a string contains something that isn't whitespace, you can also use the regular expression "\S". This is the complement of all characters included in the "whitespace" regex class, meaning one instance of any non-whitespace character.

You could for instance use it like this, and it is logically equivalent to considering $null, empty strings, and whitespace-only strings empty.

PS C:\> (@("", " ", $null, "a") | Where { $_ -match '\S' }).Count 

PS C:\> @("", " ", $null, "a") | Where { $_ -match '\S' }