Willy
Willy

Reputation: 10638

Passing Powershell Get-ChildItem filter parameter through a string variable is not working

In my script I have below function that returns a string as "*.csproj", "*.vbproj", "*.sln". Assuming I always pass a string such as "csproj, vbproj, sln" to $filter parameter:

Function Create-Filter($filter)
{    
    $str = $filter.Split(',') | ForEach-Object {"""*.$($_.Trim())"""}

    $str = $str -join ', '
    [string]$str
    return
}

Later in my script I perform:

$filter = Create-Filter($filter)
$myFiles = Get-ChildItem $source -Include $filter -Recurse  

But $myFiles is empty, Get-ChildItem is not returning anything. I know that the problem is in $filter parameter when passing to Get-ChildItem but I do not know how to solve this.

Anyway, from powershell console, If i do below It works:

PS > $filter = "*.csproj", "*.vbproj", "*.sln"
PS > Get-ChildItem "D:\Path\To\My\Root\Folder" -Include $filter -Recurse

So what am I doing wrong?

My powershell version is as below image shows:

enter image description here

UPDATE (SOLUTION): Solution proposed by AdminOfThings works. In my case applying AdminOfThings was not working because I did a mistake in my code. I was assigning the value returned by Create-Filter function into the same variable as that I was passing as argument, like below:

$filter = Create-Filter ($filter)
Get-ChildItem "D:\Path\To\My\Root\Folder" -Include $filter -Recurse

In order to make it work I have done below:

$formattedfilter = Create-Filter ($filter)
Get-ChildItem "D:\Path\To\My\Root\Folder" -Include $formattedfilter -Recurse

...that is, using a different variable to assign returned value by function instead of using the same as that I was passing as argument.

Upvotes: 1

Views: 2444

Answers (2)

AdminOfThings
AdminOfThings

Reputation: 25001

In short, you need to remove the literal quotes (replace triple double quotes with single double quotes), the -Join, and the string casting ([string]) from your function. Basically, anything that stringifies your output, needs to be removed.

Function Create-Filter($filter)
{    
    $filter.Split(',') | ForEach-Object {"*.$($_.Trim())"}
    return
}

The -Include parameter accepts a single string or an array of strings. When you pass -Include "string1","string2", you are passing an array of strings into the command. In your filter, you are creating one string that includes literal quotes and commas. The subtlety here is including the commas within the quotes creates a string that contains quotes whereas quotes BETWEEN commas creates a comma separated list of strings. So effectively, the command is reading -Include '"string1","string2"', which will find nothing. Even though your function outputs text that looks identical to what you would type directly into the command, PowerShell will interpret those values differently.

You can see the behavior below where the output of your function is interpreted by PowerShell as a single string.

create-filter ("txt","csv")
"*.txt", "*.csv"
(create-filter ("txt","csv")).gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

The array syntax (comma separated list of string types) below outputs a different result.

"*.txt","*.csv"
*.txt
*.csv
("*.txt","*.csv").gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

Executing the Code:

$str = "txt,csv"
create-filter $str
*.txt
*.csv
$filter = create-filter $str
Get-ChildItem . -Include $filter -Recurse
    Directory: C:\temp\test1


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----         6/8/2019  10:47 AM             68 -44.csv
-a----         6/8/2019  10:47 AM            101 -54.csv
-a----        6/11/2019   8:50 AM            229 count.txt
-a----        6/11/2019   8:58 AM            170 destination.txt
-a----        6/11/2019   8:53 AM            302 f.txt
-a----        6/12/2019   6:36 AM            294 hashash.txt
-a----         6/6/2019   1:14 PM              4 jaf.csv
-a----         6/6/2019   1:31 PM              0 job1.txt

Upvotes: 2

js2010
js2010

Reputation: 27428

Hmm, I would use -filter which is faster.

ls -r D:\Path\To\My\Root\Folder -filter *.csproj,*.vbproj,*.sln

EDIT: Aww, that doesn't work. But this does. I'm not sure what you need the function for.

ls -r D:\Path\To\My\Root\Folder -include *.csproj,*.vbproj,*.sln

or

$source = 'D:\Path\To\My\Root\Folder'
$filter = '*.csproj','*.vbproj.*','*.sln' # or
$filter = echo *.csproj,*.vbproj,*.sln 

ls -r $source -include $filter

Upvotes: 0

Related Questions