Wildcard matching in Get-ChildItem in PowerShell - powershell

Is there a way to determine how wildcard matching is done in Get-ChildItem?
Various articles (1, 2) suggest that it is done through the WildcardPattern class, but I don’t think this is the case. For example, suppose you have a file in C:\test\test2\testfile.txt. Then Get-ChildItem –Path “C:\*\testfile.txt” will not find the file while WildcardPattern::IsMatch will. Wildcard "*" matching in Get-ChildItem seems to be on directory level: so "\*\" will never match more than one level, like "\A\B\".
So if WildcardPattern class isn't used, then what is?

From what I know, it's using the WildcardPattern as you describe. However, the cmdlet Get-ChildItem limits it to the current directory (characters except \), so it won't conflict with the -Recurse switch that goes to unlimited levels.

With "C:\*\testfile.txt", the asterisk plays a role just for the first level directory (e.g test). The file you're looking for is not there and the output you get is expected. Add another asterisk for the second level and you'll get the desired output (e.g "C:\*\*\testfile.txt"). You can also add the Recurse switch to start searching from the current location, all the way downwards.

Either would work:
gci c:\test\*\testfile.txt
or
gci c:\*\testfile.txt -recurse
Example:
PS C:\temp\test2> dir
Directory: C:\temp\test2
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 4/4/2013 10:41 PM 0 testfile.txt
PS C:\temp\test2> cd \
PS C:\> gci c:\*\testfile.txt -recurse -ea SilentlyContinue
Directory: C:\Temp\test2
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 4/4/2013 10:41 PM 0 testfile.txt

Related

Find all files with the exact extension in Powershell

I'm trying to get all the files that end with ".asp" but I also get the files that ends in ".aspx" or ".asp..." when I do :
Get-ChildItem C:\test -Filter *.asp -Recurse | % {$_.FullName}
For the example, let's say I have a directory with test1.asp, test2.aspx and test3.asp, if I execute my script, the output will be:
C:\test\test1.asp
C:\test\test2.aspx
C:\test\test3.asp
but I only wanted it to get me "test1.asp and test3.asp".
For information, I use Powershell 2.1.
Can someone tell me how to fix that?
Try to check one more the last 3 symbols
Get-ChildItem 'C:\test' -Filter '*.asp' -Recurse |
Where {$_.Name.substring($_.Name.length -3, 3) -Match 'asp'} | % {$_.FullName}
Caveat: PowerShell behavior seems to have changed!
Windows PowerShell 5.1.19041.2364:
PS C:\Users\OA> Get-ChildItem -File -Path "C:\Test" -Filter "*.txt"
Verzeichnis: C:\Test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 05.02.2023 09:59 0 TestFile.txt
-a---- 05.02.2023 09:59 0 TestFile.txtLirumLarumLöffelstiel
PowerShell Core 7.3.2:
PS C:\Users\OA> Get-ChildItem -File -Path "C:\Test" -Filter "*.txt"
Directory: C:\Test
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 05.02.2023 09:59 0 TestFile.txt
Both commands were performed on Microsoft Windows Pro 10.0.19045.2546 (22H2).
Behavior on legacy operating systems: PS version 2.0 on Windows XP (using wildcard path instead of -File parameter) and PS version 5.14409.1018 on Windows 7: both have the former behavior.

Renaming my Item with File Name as a Variable not Working using Powershell

I am using Powershell. My goal is to copy one item to a different directory (which I already know how to do), get the userID (which I already know how to do), and rename the file with a file name that exists in a variable (which I am not sure what I am doing wrong).
When I run my code, it gives me an error: Rename-Item : Cannot bind argument to parameter 'NewName' because it is null. I don't know what I am doing wrong.
I got this from https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/rename-item?view=powershell-7
My code is listed below:
$name = [Environment]::UserName
$mainFile = "\\example\example.xlsx"
$copiedFile = "\\example\example\copiedFolder\example.xlsx"
#Once I have copied the file to the new directory, I do the following code which does not work:
$copiedFile = Rename-Item -Path $copiedFile -NewName $name.xlsx
You've way over complicated this. It's a simple copy command.
Get-ChildItem -Path 'D:\temp\reconcile.*'
<#
# Results
Directory: D:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 03-Feb-20 12:54 644 reconcile.txt
#>
$mainFile = 'D:\temp\reconcile.txt'
$FileTarget = 'D:\temp\'
Copy-Item -Path $mainFile -Destination "$FileTarget\reconcile.xlsx" -Force
Get-ChildItem -Path 'D:\temp\reconcile.*'
<#
# Results
Directory: D:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 03-Feb-20 12:54 644 reconcile.txt
-a---- 03-Feb-20 12:54 644 reconcile.xlsx
#>
I am not sure why this...
[Environment]::UserName
...is in your code, and in it twice, since you are not showing how it is being used. However, you can just use the built-in variable for that.
$env:USERNAME
About_EnvironmentVariables
I found the solution, and I feel incredibly dumb for not doing it first. I thank everyone for their input and apologize for all the edits in my previous code. My problem was that I wasn't putting double quotes around $name.xlsx.
This gives me \example\example\copiedFolder\JohnDoe.xlsx Tried single quotes and gave me \example\example\copiedFolder\$name.xlsx instead. Not really sure why. See code below:
$copiedFile = Rename-Item -Path $copiedFile -NewName "$name.xlsx"

How to group Get-ChildItem -Recurse results in one output table?

I'm using the following Powershell command:
Get-ChildItem -Recurse *.txt
But if there's multiple results the output will be like this:
Directory: C:\TestFolder\myfolder\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- d/m/yyyy hh:MM PM 1234 dragons.txt
Directory: C:\TestFolder\anotherfolder\
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- d/m/yyyy hh:MM PM 66550 jabberwocky.txt
But I want to get grouped results in some form.
Maybe like this:
Mode LastWriteTime Length Directory Name
---- ------------- ------ --------- ----
-a--- d/m/yyyy hh:MM PM 1234 C:\TestFolder\myfolder\ dragons.txt
-a--- d/m/yyyy hh:MM PM 66550 C:\TestFolder\anotherfolder\ jabberwocky.txt
Or this:
Length FullPath
------ --------
1234 C:\TestFolder\myfolder\dragons.txt
66550 C:\TestFolder\anotherfolder\jabberwocky.txt
You probably get the idea. How can I accomplish this, preferably in a simple and elegant manner?
I tried Get-ChildItem -Recurse *.txt | Format-Table but that doesn't do much. I've also checked the most relevant similar questions suggested by Stack Overflow (i.e. "Recurse with PowerShell's Get-ChildItem", and others), but haven't been able to distill a solution so far.
Addendum:
I used help group and found that group is actually the exact alias for the Cmdlet I thought I was looking for: Group-Object. If I do this:
Get-ChildItem -Recurse *.txt | Group-Object "FullName"
I get:
Count Name Group
----- -------- -----
1 C:\TestFold... {C:\TestFolder\myfolder\dragons.txt}
1 C:\TestFold... {C:\TestFolder\anotherfolder\jabberwocky.txt}
But this requires me to simplify with an additional step to:
Get-ChildItem -Recurse *.txt | Group-Object "FullName" | Select-Object "Name"
Which gets:
Name
----
C:\TestFolder\myfolder\dragons.txt
C:\TestFolder\anotherfolder\jabberwocky.txt
If I really want extra properties, then I guess I want to "group on multiple properties", making the question effectively a duplicate of this other SO question.
However, all this "grouping" seems like overkill. Is there not a direct way of using Get-ChildItem to get the output I want?
PowerShell has its own way of displaying System.IO.DirectoryInfo and System.IO.FileInfo objects. If you don't want to see that then you just need to use Select-Object.
Get-ChildItem -Recurse c:\temp | select Mode,LastWriteTime,Length,Directory,Name
Group-Object is completely unnecessary. Given your need I suppose Group-Object seemed appealing but its power is not needed here like it is used for in the linked question. What you really wanted to do is change how PowerShell deals with those objects. Format-Table does not work for the same reason. It was taking the PowerShell by design output and making a table. If you called the properties with Format-Table you would have the same solution as we did with Select-Object.
Get-ChildItem -Recurse c:\temp | Format-Table Mode,LastWriteTime,Length,Directory,Name
Please... Please... don't use that line if you intend to use the output in other functions. Format-cmdlets break objects and are used for the purpose of displaying data only.
If you are just trying to get a list of files recursively with their fullpath names, don't use Group or Select. All of these Commands pretends to be a spreadsheet of objects displayed in a text console.
Instead use the foreach-object operator "%{ }" to dump the raw string date to the console. Example:
Get-ChildItem -Recurse *.txt | %{ $_.fullname }
(Incidentally the above is equivalent to linux command: "find .")
If you want to see which fields are accessible from the foreach-object script block. you can issue this command:
Get-ChildItem my_filepath | get-member
Alternatively, you could pipe the output of Get-ChildItem to Export-Csv command and open it in notepad.
Get-ChildItem -Recurse -file *.txt |
Select FullName |
Export-Csv "files.csv"
notepad files.csv
Alternatively, use cmd:
cmd /c dir /b /s *.txt

Difference between -include and -filter in get-childitem

Can someone please explain the difference between -Include and -Filter options in the Get-ChildItem command .
Below are the two pieces of code that I am trying to execute . They both serve to find out the text files in a particular directory:
PS C:\Users\352997> get-childitem -path Desktop\Extras -filter *.txt
Directory: C:\Users\352997\Desktop\Extras
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 12/22/2014 4:05 PM 140 Expense_report.txt
-a--- 1/14/2015 4:41 PM 211 Extras.txt
-a--- 2/10/2015 2:46 PM 259 Learn Dutch.txt
PS C:\Users\352997> get-childitem -path Desktop\Extras -include *.txt
--The above command produces no result ----
Filter parameter is implemented by provider. It is efficient because applies when retrieving the objects.
Get-PSprovider commandlet shows providers that implement 'filter' parameter. For example, there are only two providers on my
system:ActiveDirectory and FileSystem
Include parameter is implemented by Powershell. It only works in conjunction with Recurse parameter (as MSDN describes here).
It's interesting that:
get-childitem -path Desktop\Extras\ -include *.txt
returns nothing
get-childitem -path Desktop\Extras\* -include *.txt
returns list of *.txt files
Maybe these are just nuances of the implementation.
Also see this excellent blog post: http://tfl09.blogspot.com/2012/02/get-childitem-and-theinclude-and-filter.html
-filter should be faster than -include. -filter can match the short version of filenames in powershell 5.1.

Why does grouping the output of a Powershell pipe sometimes not work?

I have read that when the output of Format-Table (with -GroupBy) is not
grouped, you need to 1. sort and 2. pass -AutoSize. Sometimes this does not
seem to work. This is te test case I came up with:
PS C:\> ls -Path C:\Windows\help -Include "*.chm" -Recurse|sort Directory|ft -GroupBy Directory -Auto
Directory: C:\Windows\help
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23.05.2011 10:54 21544 NVWCPFI.chm
Directory: C:\Windows\help
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 23.05.2011 10:54 21879 NVWCPESM.chm
...
Why is the output not grouped by directory? Why are there two separate entries
for the same directory? How can I group the output? (Please ignore the fact,
that output of the first command is already grouped, I just use this command as
a test case.)
Edit
As pointed out I initially forgot the the Directory argument to sort. (The output still has the same problem.)
I am using Powershell 2.0
In order to group output in Format-Table it first needs to be sorted. A technet blog, which has a discussion on this, is here. While you do have a Sort-Object cmdlet you dont choose a value to sort on. Note I do not get the same output at you with your cmdlet on powershell 3.0
Get-ChildItem -Path C:\Windows\help -Include "*.chm" -Recurse| Sort-Object Directory | Format-Table -GroupBy Directory
The output will indeed be sorted but i gather this is not what you are looking for. Another approach that might be more desired would be to use Select-Object to only output the desired information.
Get-ChildItem -Path C:\Windows\help -Include "*.chm" -Recurse| Sort-Object Directory | Select Name,Directory | Format-Table -AutoSize
You would need to experiment with the values of Select-Object to get your desired output. The next example would give you count information of chm's in folders. Not Format-Table related at all but interesting none the less.
Get-ChildItem -Path C:\Windows\help -Include "*.chm" -Recurse | Group-Object Directory
Try this if work:
...|sort directory |ft -GroupBy...