Techromancer
Techromancer

Reputation: 473

Cannot filter Directories with Powershell using an environment variable

I have come across an unexpected behaviour when trying to filter a list of directories set in an environment variable array.

When I run this code using a local variable I get the expected result:

$myPath = "C:\temp\"
$myList = 'Folder1', 'Folder2', 'Folder3'
Write-Host "myList: $myList" 
Get-ChildItem -Recurse $myPath | Where-Object { $_.PSIsContainer } | Where-Object { $_.Name -in $myList } | Select-Object FullName

i.e.

myList: Folder1 Folder2 Folder3

FullName
--------
C:\temp\Folder1
C:\temp\Folder2
C:\temp\Folder3

However when I replace $myList with an environment variable $env:yourList

$myPath = "C:\temp\"
$env:yourList = 'Folder1', 'Folder2', 'Folder3'
Write-Host "yourList: $env:yourList"
Get-ChildItem -Recurse $myPath | Where-Object { $_.PSIsContainer } | Where-Object { $_.Name -in $env:yourList } | Select-Object FullName

the result of Get-ChildItem is empty

yourList: Folder1 Folder2 Folder3
.

As you can see from the output above the value set in $env:yourList is printed identical to the one set in $myList, so what's so special about environment variables that causes them to be processed differently in Where-Object criteria?

BTW, the same behaviour occurs when using -Include instead of Where-Object, i.e.:

Get-ChildItem -Path $myPath -Recurse -Include $env:yourList -Directory

Upvotes: 1

Views: 104

Answers (1)

mklement0
mklement0

Reputation: 437197

An environment variable is always a single string, so you cannot store arrays in them (or any other data types other than [string]).

  • Note: This is outside of PowerShell's control: environment variables are a system-level feature.

PowerShell stringifies the input array on assignment[1], which means joining the array elements with a space as the separator (or, if defined, the separator stored in preference variable $OFS), which is why array 'Folder1', 'Folder2', 'Folder3' turned into single string
'Folder1 Folder2 Folder3'.


If you really do need an environment variable to store your array - which is normally only needed for communicating values to child processes - you'll have to choose a single-string representation for it on assignment, which you can re-convert to an array on reading the variable; e.g.:

# Assuming the array elements contain no newlines, use newlines
# to separate them.
$env:yourList = ('Folder1', 'Folder2', 'Folder3') -join "`n"

# Later, re-convert the single-string representation to an array.
$env:yourList -split "`n"

[1] As Doug Maurer points out, this automatic to-string conversion happens with any RHS that isn't already of type [string], such as with $env:yourList = 42 (assigns string '42'). In other words: Anything you assign to an environment variable is automatically converted to a (single) string.

Upvotes: 2

Related Questions