> pshdo

Beware Get-ChildItem

I discovered today that the Get-ChildItem cmdlet wasn’t behaving as I expected. Passing it $null, @(), or '' will return the contents of the current directory:

> Get-ChildItem .


   Directory: C:\Temp\BewareGetChildItem

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---          5/4/2012   4:08 PM          6 Get-ChildItem.txt


> Get-ChildItem $null


   Directory: C:\Temp\BewareGetChildItem

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---          5/4/2012   4:08 PM          6 Get-ChildItem.txt


> Get-ChildItem @()


   Directory: C:\Temp\BewareGetChildItem

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---          5/4/2012   4:08 PM          6 Get-ChildItem.txt


> Get-ChildItem ''


   Directory: C:\Temp\BewareGetChildItem

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---          5/4/2012   4:08 PM          6 Get-ChildItem.txt

Yikes! I would expect it to write an error or just return nothing.

We have a function in our website deployment script that takes in a list of items and a filter, and deletes any item that doesn’t match the filter, like this:

function Remove-ExtraFiles($Items, $Exclude)
{
    Get-ChildItem $Items -Exclude $Exclude -Recurse |
        Where-Object { -not $_.PsIsContainer } |
        Remove-Item
}

I was testing this script when I saw that files under my local directory were getting deleted. By the time I killed the script, it was too late: the last two hours of work were gone. It turns out that Remove-ExtraFiles was getting called with an empty array as the $Items parameter value.

In my case, the solution was to add some validation to the $Items parameter:

function Remove-ExtraFiles
{
    param(
        [Parameter(Mandatory=$true)]
        [string[]]
        $Items,

        [string[]]
        $Exclude)
    )
    Get-ChildItem $Items -Exclude $Exclude -Recurse |
        Where-Object { -not $_.PsIsContainer } |
        Remove-Item
}

Making the parameter mandatory causes a script error if calling Remove-ExtraFiles with null, an empty array, or an empty string.