Friday Puzzle: Why doesn’t Include include?

On Friday, January 20, 2017, I posted the following puzzle on Twitter and Facebook (and here!).

It shows a Get-ChildItem command where the value of the Path parameter is $PSHome, the Windows PowerShell installation directory, and the value of the Include parameter is ‘*ps1xml.’ The command returns nothing — not a single file — even though the next command shows that there are 14 *.ps1xml files in the root of the $PSHome directory.

What happened here? Why didn’t the Get-ChildItem -Include command work?

This might enlighten you. Or, confuse you even more. In this command, we add ‘\*’ to the path, which indicates its immediate subfolders. When you add ‘\*’, Get-ChildItem gets the .ps1xml files in its root folder.

And, adding -Recurse works, too, although it gets all .ps1xml files in all subdirectories of $PSHome recursively. And, sadly the Depth parameter (new in PowerShell 5.0) seems to have no effect on Get-ChildItem when -Include or -Exclude are used (not documented).

PS C:\> Get-ChildItem -Path $PSHome -Include '*ps1xml' -Recurse

What’s going on here?

 

About the Include Parameter

To solve the mystery, look at help for the Include parameter. I worked really hard to get this parameter description right, so I remember it well.

As we’ve found, the Include parameter works only when the path includes “\*” or the command includes the Recurse parameter.

The coolest thing about the Include and Exclude parameters are that they take an array of values, and include or exclude all items in the array.

PS C:\ > Get-ChildItem -Path $PSHOME\* -Include "*.xml", "*.txt"

TIP: Exclude does not require -Recurse or ‘\*’

 

Include is critical in PowerShell 2.0, because the Recurse parameter doesn’t work on items that have no child-items.

# This fails
PS C:\> Get-ChildItem -Path $PSHome\*.ps1xml -Recurse

In Windows PowerShell 2.0, you need to do this:

# This works
PS C:\> Get-ChildItem -Path $PSHome\* -Recurse -Include '*ps1xml'

Which parameters can you use?

To get .psm1xml files in a directory, you can specify the file name extension on the Path parameter.

PS C:\> Get-ChildItem -Path $PSHome\*.ps1xml

 

Beginning in PowerShell 3.0, you can use the Recurse parameter even when the Path value is an item without child-items (a “leaf”).

PS C:\> Get-ChildItem -Path $PSHome\*.ps1xml -Recurse

 

You can also use the Filter parameter. But neither take an array.

PS C:\> Get-ChildItem -Path $PSHome -Filter "*.ps1xml"

You can also use the Exclude parameter, which works without the ‘\*’ and Recurse, although it has the opposite effect. And, like Include, when you use the Recurse parameter with Exclude, the Depth parameter has no effect.

PS C:\> Get-ChildItem -Path $PSHome -Exclude "*.ps1xml"

 

And, you can pipe the result to Where-Object or the Where method, although those options are significantly slower.

PS C:\> Get-ChildItem -Path $PSHOME | Where-Object {$_.Extension -eq '.ps1xml' -or $_.Extension -eq '.dll'}
PS C:\> (Get-ChildItem -Path $PSHOME).where({$_.Extension -eq '.ps1xml' -or $_.Extension -eq '.dll'})

 

Read the help!

So, the moral of the story is to read the help. And, when the help is missing or wrong, file an issue on UserVoice or in the PowerShell-Docs repo on GitHub. The cool folks on the PowerShell team, and their open-source helpers, respond very quickly.

Like this Friday PowerShell Puzzle? Find more puzzles here. If you have a PowerShell puzzle suggestion, post it here or ping me on Twitter at @juneb_get_help.

June Blender is a technology evangelist at SAPIEN Technologies, Inc and a Microsoft Cloud & Datacenter MVP. You can reach her at juneb@sapien.com or follow her on Twitter at @juneb_get_help.