Windows10/Powershell: How to use -include parameter when using Get-Childitem? - powershell

When using "-filter":
Get-ChildItem -file -filter "*.txt" | foreach-object { write-host $_.FullName }
I get a listing of the 4 .txt files that's in the current folder.
I tried using "-include"
Get-ChildItem -file -include *.txt | foreach-object { write-host $_.FullName }
Get-ChildItem -file -include *txt | foreach-object { write-host $_.FullName }
and I get nothing. I tried with and without the "-file" parameter and it makes no difference.
I've looked at various guides/examples (ss64.com/TechNet and etc) and supposedly I am doing it right.
Any ideas what I could be doing wrong? Thanks!

From the Get-Help page for Get-ChildItem:
The -Include parameter is effective only when the command includes the -Recurse parameter or the path leads to the contents of a directory, such as C:\Windows*, where the "*" wildcard character specifies the contents of the C:\Windows directory.
You'll note that you don't get a syntax error if you specify -include and don't specify -recurse in spite of the fact that whatever it does is literally undefined. You'll also note that C:\Windows* is not a normal wildcard expression for "all files in the C:\Windows directory". It's a wildcard expression for "all items that start with 'Windows' in the C:\ directory and may or may not have an extension". I have no idea what the authors of Get-ChildItem think this parameter is supposed to do. They've done a fantastically poor job of documenting it and implementing it.
Consequently, I avoid the -Include parameter as broken/badly documented. I don't know what it's supposed to do that -Filter doesn't. I've read articles about what it does exactly. It "passes the value to the underlying provider to filter at that level" in some manner. I don't know why they assume that a sysadmin will know what that really means. My understanding is that it's the difference between calling DirectoryInfo.GetFiles() on each directory item and calling DirectoryInfo.GetFiles('*.txt') on each directory item, but most sysadmins aren't going to know what that means. However, it's so oddly behaved that I don't trust it, so even though I am about 95% sure of what it does... I still never use it.
Instead, I just pipe to Where-Object:
Get-ChildItem -file | Where-Object Extension -eq '.txt' | [...]
Also note that Get-ChildItem is broken with -LiteralPath, -Recurse and -Include in some versions of PowerShell, and will instead return all items.
Compare:
Get-ChildItem -LiteralPath $PSHOME *.exe -Recurse # works
Get-ChildItem -Path $PSHOME -Include *.exe -Recurse # works
Get-ChildItem -LiteralPath $PSHOME -Include *.exe -Recurse # does NOT work
Issue reported here for v6.

These work for me without recursion:
Get-ChildItem -Path "C:\Users\Athom\Desktop\*.txt"
Get-ChildItem -Path ".\*.txt"
Or Just add the recursion parameter:
Get-ChildItem -Include *.txt -Recurse

Related

Get directories beginning with P in PowerShell

I want to get all directories starting with "P".
In cmd you would do this:
dir p*
How do you do it in Windows PowerShell?
I tried this but it returns nothing:
Get-ChildItem -Path C:\thePath\* -dir -Include p*
Removing the -Include p* would return all folders as expected.
Either include the pattern directly in the -Path argument:
Get-ChildItem -Path C:\thePath\p* -Directory
... or use the -Filter argument, which is the faster alternative, because it filters at the source:
Get-ChildItem -LiteralPath C:\thePath -Filter p* -Directory
As for what you tried:
The -Include and -Exclude parameters are notoriously counterintuitive in that they only operate on the input path or pattern itself, not on the child items of a given input path - except if -Recurse is also specified.
In your case, given that your -Path argument ends in *, the -Include filter should work, but inexplicably doesn't due to the additional presence of the -Directory switch - this should be considered a bug.
Seemingly, with Get-ChildItem - as opposed to Get-Item - -Include only ever includes files, not also directories - see this GitHub issue.
You could make your command work by (a) switching from Get-ChildItem to Get-Item and (b) filtering out non-directories after the fact, but that is less efficient than the alternatives above:
Get-Item C:\thePath\* -Include p* | Where-Object PSIsContainer

PowerShell not accepting command line parameter [duplicate]

I am searching for a file in all the folders.
Copyforbuild.bat is available in many places, and I would like to search recursively.
$File = "V:\Myfolder\**\*.CopyForbuild.bat"
How can I do it in PowerShell?
Use the Get-ChildItem cmdlet with the -Recurse switch:
Get-ChildItem -Path V:\Myfolder -Filter CopyForbuild.bat -Recurse -ErrorAction SilentlyContinue -Force
I use this to find files and then have PowerShell display the entire path of the results:
dir -Path C:\FolderName -Filter FileName.fileExtension -Recurse | %{$_.FullName}
You can always use the wildcard * in the FolderName and/or FileName.fileExtension. For example:
dir -Path C:\Folder* -Filter File*.file* -Recurse | %{$_.FullName}
The above example will search any folder in the C:\ drive beginning with the word Folder. So if you have a folder named FolderFoo and FolderBar PowerShell will show results from both of those folders.
The same goes for the file name and file extension. If you want to search for a file with a certain extension, but don't know the name of the file, you can use:
dir -Path C:\FolderName -Filter *.fileExtension -Recurse | %{$_.FullName}
Or vice versa:
dir -Path C:\FolderName -Filter FileName.* -Recurse | %{$_.FullName}
When searching folders where you might get an error based on security (e.g. C:\Users), use the following command:
Get-ChildItem -Path V:\Myfolder -Filter CopyForbuild.bat -Recurse -ErrorAction SilentlyContinue -Force
Here is the method that I finally came up with after struggling:
Get-ChildItem -Recurse -Path path/with/wildc*rds/ -Include file.*
To make the output cleaner (only path), use:
(Get-ChildItem -Recurse -Path path/with/wildc*rds/ -Include file.*).fullname
To get only the first result, use:
(Get-ChildItem -Recurse -Path path/with/wildc*rds/ -Include file.*).fullname | Select -First 1
Now for the important stuff:
To search only for files/directories do not use -File or -Directory (see below why). Instead use this for files:
Get-ChildItem -Recurse -Path ./path*/ -Include name* | where {$_.PSIsContainer -eq $false}
and remove the -eq $false for directories. Do not leave a trailing wildcard like bin/*.
Why not use the built in switches? They are terrible and remove features randomly. For example, in order to use -Include with a file, you must end the path with a wildcard. However, this disables the -Recurse switch without telling you:
Get-ChildItem -File -Recurse -Path ./bin/* -Include *.lib
You'd think that would give you all *.libs in all subdirectories, but it only will search top level of bin.
In order to search for directories, you can use -Directory, but then you must remove the trailing wildcard. For whatever reason, this will not deactivate -Recurse. It is for these reasons that I recommend not using the builtin flags.
You can shorten this command considerably:
Get-ChildItem -Recurse -Path ./path*/ -Include name* | where {$_.PSIsContainer -eq $false}
becomes
gci './path*/' -s -Include 'name*' | where {$_.PSIsContainer -eq $false}
Get-ChildItem is aliased to gci
-Path is default to position 0, so you can just make first argument path
-Recurse is aliased to -s
-Include does not have a shorthand
Use single quotes for spaces in names/paths, so that you can surround the whole command with double quotes and use it in Command Prompt. Doing it the other way around (surround with single quotes) causes errors
Get-ChildItem V:\MyFolder -name -recurse *.CopyForbuild.bat
Will also work
Try this:
Get-ChildItem -Path V:\Myfolder -Filter CopyForbuild.bat -Recurse | Where-Object { $_.Attributes -ne "Directory"}
Filter using wildcards:
Get-ChildItem -Filter CopyForBuild* -Include *.bat,*.cmd -Exclude *.old.cmd,*.old.bat -Recurse
Filtering using a regular expression:
Get-ChildItem -Path "V:\Myfolder" -Recurse
| Where-Object { $_.Name -match '\ACopyForBuild\.[(bat)|(cmd)]\Z' }
To add to #user3303020 answer and output the search results into a file, you can run
Get-ChildItem V:\MyFolder -name -recurse *.CopyForbuild.bat > path_to_results_filename.txt
It may be easier to search for the correct file that way.
On a Windows system:
Search for all .py files in the 'c:\temp' dir and subdirs, type: dir -r *.py or dir *.py -r
On a *Nix (Linux / MacOs system:
at the terminal type: find /temp -name *.py
This works fine for me.
Generally, robocopy is the fastest and simplest way for searching multiple files in parallel threads. It needs a quite good Powersell code with parallelism to beat that. Here is a link to an article I have written in the past with all the different options you have: Fastest way to find a full path of a given file via Powershell? Check the accepted answer for the best code.

Powershell 5 Get-ChildItem LiteralPath doesn't work with Include anymore

Right now I updated to Windows 10 TH2 Build 10586 with PowerShell 5.0.10586.0
Now I got a problem with Get-ChildItem
$files = Get-ChildItem -LiteralPath $path -Force -Recurse -Include *.txt
This returns ALL files in $path even they are not .txt.
This was working before the update.
When I change it to
$files = Get-ChildItem -Path $path -Force -Recurse -Include *.txt
it works again. But that's not what I want.
Is this a bug or am I doing something wrong?
Personally, I never use -Include or -Exclude anymore. I always pipe through Where-Object. I don't know if the author of -Include and -Exclude was insane or if there's a problem with the underlying .Net provider, but they're flaky as hell.
I'm on 5.0.10240.16384.
gci -Path $path -Include *.txt -Force
Returns nothing.
gci -LiteralPath $path -Include *.txt -Force
Returns everything in $path.
gci -LiteralPath $path -Include *.txt -Force -Recurse
gci -Path $path -Include *.txt -Force -Recurse
Both return *.txt in $path and all subfolders.
So what's the proper behavior supposed to be? Does the -Recurse flag modify how -Include works? I don't know. I no longer care. I'm not going to deal with that kind of behavior. I just use this:
gci -Path $path -Recurse -Force | Where-Object { $_.Extension -eq '.txt' }
I rely on Get-ChildItem to enumerate files and folders and that's it. Just give me the objects and I'll filter them. Like all the old Remove-Item -Recurse bugs, there's something there that just doesn't work the way people expect it to.
Note that -Filter does not seem to have this issue. This works:
$files = Get-ChildItem -LiteralPath $path -Force -Recurse -Filter *.txt
Filter is also more efficient, because it is used by the underlying provider (as opposed to Include which is applied by PowerShell itself, much like a where clause added by your code).
However Filter only accepts one pattern parameter, whereas Include supports multiple patterns.
I think this is a regression. I submitted it as v5 regression: Get-ChildItem -LiteralPath -Recurse ignores -Include and gets all items

Different result from same command in powershell 3.0

Given that Get-ChildItem -Path *.exe will show all the executables in the current directory, why doesn't Get-ChildItem -File -Include *.exe return the same result? Both commands are executed in the same directory, first command (with -Path) returns a list of executables but the second command (with -File) doesn't. (gci -File will list everything including the exe)
Get-ChildItem -File | gm #=> FileInfo
Get-ChildItem *.* | gm #=> DirectoryInfo and FileInfo
All the commands bellow return objects of type FileInfo
Get-ChildItem -File
Get-ChildItem *.* -Include *.exe
Get-ChildItem -Path *.exe
But mixing -File and -Include/-Exclude returns nothing, even though the -include is looking for a filetype:
Get-ChildItem -File -Include *.exe #=> Returns nothing
What am I missing here?
From TechNet:
The Include parameter is effective only when the command includes the
Recurse parameter or the path leads to the contents of a directory,
such as C:\Windows*, where the wildcard character specifies the
contents of the C:\Windows directory.
In other words, when you use the Include parameter, it does not automatically consider all files and directories unless you use the Path or the Recurse parameters. Notice, that when just using the Path parameter, you must include a wildcard to force it to consider the file and directory results underneath that path. I cannot think of why this is.
To get your examples to work, you would use one of the following (I'm dropping the File parameter because it seems redundant):
Get-ChildItem -Path * -Include *.exe
Get-ChildItem -Include *.exe -Recurse
The gist of my answer to your question is an opinion tho - from what I've seen the Include parameter should be removed - or its behavior repaired to match the default behavior of the Get-ChildItem cmdlet when used without parameters. There may be a good explanation to why it works this way, but I'm unaware of this.
If you drop the Include parameter from your examples, the behavior/results make more sense (to me):
Get-ChildItem -Path *.exe
In this case, we would only need the Exclude parameter to effectively cover all filtering requirements. Something like:
Get-ChildItem -Path *.exe -Exclude *system*

How to search for a folder with PowerShell

I would like to search for a folder in a specific directory and subdirectorys.
I tried googling it, but didn't really find any usefull examples.
Get-ChildItem C:\test -recurse | Where-Object {$_.PSIsContainer -eq $true -and $_.Name -match "keyword"}
I believe there's no dedicated cmdlet for searching files.
Edit in response to #Notorious comment:
Since Powershell 3.0 this is much easier, since switches -Directory and -File were added to Get-ChildItem. So if you want it short you've got:
ls c:\test *key* -Recurse -Directory
With command alias and tab-completion for switches it's a snap. I just missed that the first time.
Here is my version, which is only slightly different:
gci -Recurse -Filter "your_folder_name" -Directory -ErrorAction SilentlyContinue -Path "C:\"
some more info:
-Filter "your_folder_name"
From documentation: Filters are more efficient than other parameters. The provider applies filter when the cmdlet gets the objects rather than having PowerShell filter the objects after they're retrieved. The filter string is passed to the .NET API to enumerate files. The API only supports * and ? wildcards.
-Directory
Only examine directories, also could be -File
-ErrorAction SilentlyContinue
Silences any warnings
-Path "C:\"
Specifies a path to start searching from
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-childitem?view=powershell-7