PowerShell not accepting command line parameter [duplicate] - powershell

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.

Related

Recursive Wildcards in PowerShell

I'm trying to delete files in a specific set of folders with PowerShell. My code currently looks like this:
$tempfolders = #(
"C:\Windows\Temp\*"
"C:\Documents and Settings\*\Local Settings\temp\*"
"C:\Users\*\Appdata\Local\Temp\*"
)
Remove-Item $tempfolders -Recurse -Force -ErrorAction SilentlyContinue
I want to add a new folder to that list, with the following formula:
"C:\users\*\AppData\Local\Program\**\Subfolder"
where ** could be multiple subfolders of unknown length. For example, it could be settings\subsettings or it could be folder\settings\subsettings. Is there a way to do this?
You can feed the full path of each file to a regex; this will return only the files that match your format, which you can then pipe to Remove-Item:
ls "C:\Users" -Recurse -Hidden | Where-Object { $_.FullName -imatch '^C:\\users\\([^\\]+)\\AppData\\Local\\Program\\(.*)\\Subfolder' }
Because regexes are considered write-only, a bit of explanation:
backslashes count as escape characters inside a regex and need to be doubled.
([^\\]+) means one or more of any character except a backslash
.* means zero or more of any character
You can use Get-ChildItem -Directory -Recurse,
This will do exactly what you are asking for. Pipe it from the array to a Remove-Item
#("C:\Windows\Temp\*", "C:\Documents and Settings\*\Local Settings\temp\*", "C:\Users\*\Appdata\Local\Temp\*") |
Get-ChildItem -Directory -Recurse -Force -ErrorAction SilentlyContinue |
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
Just for a heads up in Powershell Piping | is key. PowerShell we love to chain commands.

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

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

Using Remove-Item cmdlet but excluding sub-directory

I want to remove the following files from the source, however in the source there is a sub-directory that contains files with similar names. When I run the following command it is deleting files in the sub-directory with similar file name. Is there a way to just delete the files from the source and not the sub-directory?
Example: test_1_file, test_2_file, test_3_file exists in each directory, TestFolder and TestFolder/sub
$source = testfolder
remove-item -Path $source -filter test_*_file -recurse -force
It's usually easiest to pipe the output of Get-ChildItem cmdlet into Remove-Item. You then can use the better filtering of Get-ChildItem as I think -Recurse in Remove-Item has some issues. You can even use Where-Object to further filter before passing to Remove-Item
$source = testfolder
Get-ChildItem -Path $source -Filter test_*_file -Recurse |
Where-Object {$_.Fullname -notlike "$source\sub\*"} |
Remove-Item -Force
If the files to delete:
are all located directly in $source
and no other files / directories must be deleted:
Remove-Item -Path $source/test_*_file -Force
No need for -Recurse (as #Bill_Stewart notes).
Note: For conceptual clarity I've appended the wildcard pattern (test_*_file) directly to the $source path.
Using a wildcard expression separately with -Filter is generally faster (probably won't matter here), but it has its quirks and pitfalls.

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

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