Sometimes you might struggle to find a file or program when you have no idea where it could be saved or installed. And the Windows user interface may not always give you the results you want. If that's the case for you, you're in the right place.
Get-ChildItem (also known as gci, ls, dir ) is a very powerful command. And one of its most iconic uses is to find/search for a file. It's more precise and more reliable than Windows Explorer. It even has better filtering options that show the results that are more relevant to you.
In this tutorial, you'll learn how to use gci and how to combine it with other commands so that it becomes an even more powerful tool. Remember to enable copy-pasting in Windows PowerShell, so it's easier for you to follow along. You can see how to enable it here.
What we'll cover:
Advanced Searching – Combining Get-ChildItem with the Where-Object Command
How can you know all the properties that you can use as a filter?
I don't know the file’s name, but I know what's inside it. How do I find the file by its content?
Hard to read? Open the results in the text editor of your choice
Summary - the ultimate commands for searching and finding whatever you need
1. Basic Explanation of the Get-ChildItem Command
Let's take a look at the example searching script to understand how it works:
Get-ChildItem -Recurse -Path "C:\path to\your directory\" -Filter "*whatImLookingFor*"
Get-ChildItem (aliases: dir, ls, gci) lists the content of a folder or directory just like the Linux ls command does.
This command works by searching every single file and directory in the path specified. It shows you everything it found that matches the filter. It doesn't mean that this command doesn't look everywhere else – because it does.
So you specify the path that is the parent (folder), which means that every folder and file under it is its child. If you know some CSS and JavaScript, treat it the same way that these languages do.
If you don't use -Recurse or -Depth, then the command works only in your current directory (parent Depth level 0) and searches for its children inside that directory (children Depth level 0).
If you use -Recurse, then the gci will search for what you want on ALL LEVELS. But by using-Depth, you can specify how deep you want it to look for a file/folder.
To recurse means "to repeat an operation". So, -Recurse means that gci will repeat the search for your file or folder in every child element of the "Documents" directory, and every directory inside it, all levels deep.
All of these files and folders are children of your "Documents" folder. If you delete the folder, you delete everything inside it too.
-Filter filters the output of the command to only show what matches the filter (examples of how to use filter are further in the article).
-Path tells where the command should be looking for files (by using "C:\", for example, you're telling it to look at the very basis of your computer). If you want to search in certain directory it would look like this:
Get-ChildItem -Path "C:\path to\your directory\"
OR
Get-ChildItem -Path "~\Documents\path to\your directory\"
~\ here is a shorthand for "inside current user's folder" or "C:\Users\YourUsername".
Next, we can specify whether we'd like to look for a file or a folder, so we have fewer results to look at:
Get-ChildItem -Path C:\ -Recurse -Filter "*whatImLookingFor*" -File
Get-ChildItem -Path C:\ -Recurse -Filter "*whatImLookingFor*" -Directory
You might be wondering how you can stop the search if it takes too long. When you're using -Recurse, the output that you'll get might become quite overwhelming, especially if you didn't specify your command enough (more about that in step 3 and step 4). Luckily, you can stop any command in PowerShell after starting it with Ctrl + C OR Ctrl + Z OR Ctrl + X. All of them should work.
Most Used Examples of Searching by gci Command
Here are some handy examples of searching scripts that you can use:
Example #1: search for all executive files on your PC (remember that you can stop this command with one of shortcuts, like Ctrl + C):
Get-ChildItem -Path C:\ -Recurse -Filter "*.exe" -File
REMEMBER:
In order to paste commands into the PowerShell, you have to first enable it. Here's how.
This command will show you a very long list of executable files and their folders (as shown in the image below).
These lists might be so long that it's impossible to find anything in them. That's why you'll learn how to use more advanced techniques of filtering in step 4 to see fewer unnecessary results that don't fit your criteria.
Example #2: search for an executable file that has "notepad" in its name (or search for any program you need, basically):
Get-ChildItem -Path C:\ -Recurse -Filter "notepad*.exe" -File
One of the results will show you the location of the file you want:
In our case it's the C:\Windows\System32 folder.
You can mix it however you want! Thanks to that command, you don't have to remember much about your file and it will still work.
Get-ChildItem -Path C:\ -Recurse -Filter "n*pad*.*xe"
So what if you see some errors while scanning the whole system. Should you worry?
It's ok! Sometimes you might get lots of errors. They will most likely occur when a script scours the system folders/files. If you want to get rid of them, add -ErrorAction SilentlyContinue, like you see here:
Get-ChildItem -Path C:\ -Recurse -Filter "notepad*.exe" -File -ErrorAction SilentlyContinue
You can try it now ;)
2. Setup for Other More Complex Examples
Now, let's look at even more use cases for this command. But first, we'll create a space where I can show you examples.
First, create new folder inside your "Documents" folder. Let's call it "Items".
Inside it, create two text documents. Name one of them "Item 1- Green Bracelet" and the other "Item 2- Blue Bracelet" (Yes, make sure you write the first letter of each word in UPPER CASE).
Copy these files now.
Go one folder back (you can use the Ctrl + UpArrow shortcut ) and create another folder next to "Items" called "More items":
Paste the copied files inside the "More items" folder and change their names, so they have only lower case letters ("item 1- green bracelet" and "item 2- blue bracelet" ).
PRO TIP:
You can click once on a file with your mouse and then type the F2 key on your keyboard in order to change their names.
3. When is the -Path option not needed?
You don't have to specify the path every time. You can always just move to the desired directory with the cd (change directory) command.
This command will move you to your Documents folder:
cd ~\Documents\
Now, you should be able to see PowerShell pointing to your Documents folder on the left of the screen:
If you don't see this, then you can use double quotes " ", like in this command:
cd "~\Documents\"
Make sure that PowerShell is pointing to our desired folder. Now, the searching command looks like this without the -Path option:
Get-ChildItem -Recurse -Filter "*item*" -File
Pretty simple, right?
As you can see in the image above, we first moved to our desired directory, so later we could perform the search inside it without specifying the -Path option/parameter.
But the -Path option is very useful, either when you're creating a script or you want to search for something without moving away from the current directory:
Get-ChildItem -Path ~\Documents\ -Recurse -Filter "*item*" -File
Get-ChildItem -Path ~\Documents\ -Recurse -Filter "*item*" -Directory
Here's an example. I'm inside the System32 folder and I want to know whether the thing I'm looking for is inside the Documents folder without moving in there:
And it really is there!
From now on, because you already know what the -Path option is being used for, I won't be using it unless it's necessary.
4. Advanced Searching – Combining Get-ChildItem with the Where-Object Command
Sometimes you might have several folders named exactly the same, but they're in different places. You might want to exclude them based on their content, which folder they are in, or based on their-Depth level (see the graphic with the explanation about -Depth level in step 1). That's what we're going to cover in the next few points.
For this part of the tutorial, make sure you've gone through step 2 (but you can skip step 3 if you want).
4.1. Searching through only a particular directory
Let's say that we're now looking for the bracelets that we created in step 2. But, we want to see the results from only one folder. For that, we'll use case-sensitive search (-clike) to get only our preferred results. But -clike doesn't work with gci alone. We need to apply another filter with the Where-Object { } command:
Get-ChildItem -Path ~\Documents\ -Recurse -Filter "*item*" |
Where-Object { $_.Name -clike "*Item*" }
OR (clearer version, without the -Path option):
Get-ChildItem -Recurse -Filter "*item*" |
Where-Object { $_.Name -clike "*Item*" }
Let's review what's going on here:
Get-ChildItem -Recurse -Filter "*item*"searches for all files and folders with "item" in their name|– the "pipe" symbol is used to get the output of the previous command (the list of all files and folders filtered bygci) and send it to the next command (Where-Objectis applying another filter to what is already filtered bygci).Where-Object { }is the command used for filtering the lists of objects. The filter is being specified inside the{ }curly brackets.\(_refers to all the separate objects. Treat it as "ForEachObjectFromList". And treat the whole sequence after the|as "FindObjectsFromList that have a name with 'Item' ".\)_is very often used withWhere-Object, but also with some other commands..Name– we choose a Name property to get from every object.-clikefinds a match that is 100% correct. All letters must be the exact same case as the phrase we specified.cstands for "case sensitive" and it checks every letter to see if it's upper case or lower case.
So, Where-Object { $_.Name -clike "*Item*" } is a filter that takes the Name parameter of every object from the list (created by gci) and checks with -clike if any Name has the word "Item" in it.
As you can see in the image below, now we'll get only the files with upper case names in our result:
IMPORTANT:-like alone means that we're looking for a certain pattern, no matter what case the letters are. The c in -clike means that we look for the thing with exactly the same capitalization of the letters (both upper and lower case, hence the "c").
If you want to see the files without the upper case first letter, you can do that by changing "*Item*" from our current command to "*item*":
Get-ChildItem -Recurse -Filter "*item*" |
Where-Object { $_.Name -clike "*item*" }
Let's try it out!
4.2. How to search while excluding a particular directory
In step 4.1 we learned how to search only for files/folders with specific case-sensitive names in them. After applying only two changes to our previous code, we can exclude certain directories from our search.
Here's our starting command once again:
Get-ChildItem -Recurse -Filter "*item*" |
Where-Object { $_.Name -clike "*Item*" }
Change #1
In the example above, -clike shows only files/folders including specific phrase in their names. If we change it to -cnotlike, we'll exclude from the search all files/folders with that specific phrase in their name.
Now our code looks like this:
Get-ChildItem -Recurse -Filter "*item*" |
Where-Object { $_.Name -cnotlike "*Item*" }
Change #2
After the first change, Where-Object { \(_.Name -cnotlike "*Item*" } only excludes the names, not full paths. In order to avoid that, we need to exclude an actual path to these files. We can do that by changing \)_.Name to $_.FullName, which checks for a certain phrase in the whole path to the file and in the file's name.
Now, your command should look like this:
Get-ChildItem -Recurse -Filter "*item*" |
Where-Object { $_.FullName -cnotlike "*Item*" }
We excluded the "Items" folder from our search. You should now be able to see the files only from the "More items" directory. Try it out yourself!
What if you want to exclude the "More items" directory instead? Just change the phrase inside the filter to something like this:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.FullName -cnotlike "*More*" }
We also changed the name of the file from "*item*" to "*green*" in our gci search (first line of code). That's why now we'll see only one bracelet in our result list:
The gci command has two filters applied. First, it searches for files with phrase "green" in their names. The second filter is the "Where-Object" command, which excludes anything that has the word "More" in its path. In our case, the "More items" folder got excluded.
We don't even need the case-sensitive filter in our case. The command will work the same when we exclude just a lowercase word "more". So let's change -cnotlike "*More*" to -notlike "*more*" and see if it's true:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.FullName -notlike "*more*" }
As you can see, the result is the same! Despite different cases of the letters, we still got the right keyword. So, case-sensitive search isn't always needed – only when you want to be very specific.
Sometimes, being too specific might be bad and make your code not work as intended. To see what I mean, let's look at the example below. Let's apply case-sensitive search once again, but to our unchanged, lowercase keyword "more" and see if it still works:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.FullName -cnotlike "*more*" }
Case-sensitive search doesn't filter out anything now, because it's too specific. Both the "Items" and "More items" folders omit the filter now.
FAQ:
If the Where-Object command is what actually filters the output for us, shouldn't we drop (delete) the -Filter option from gci?
No, we should still use the -Filter option, because it already separates around 99% of the possible files, so the Where-Object command has to work roughly only on 1% of the objects. It makes this part of the command AT LEAST 100 times faster (more often 100,000 times or even faster).
You can try using this command in -Path C:/ with and without the -Filter option. In my case, using the -Filter shortened the time needed for the whole sequence of commands to finish from 16 seconds to 8 seconds (first 7.99 seconds is used by gci, so that's why the time got shortened only by a half). That's what we call ✨optimization✨ :D
4.3 Searching only 1 directory from many with exactly the same name
We've learned how to search for a phrase anywhere inside the path of a file. But what if we want to search inside exactly the "More items" folder? For that, we'll use the -match filter (which works similarly to the -like filter).
Our phrase will also use "\", instead of "\". This is because "\" is the symbol for a folder, but alone in programming it also has some other features, which we don't want.
This command will look for a match for the "More items" folder in the path of every file from the list. Then, it will show you this file if it matches.
What if we want to check for two folders, one next to the other, simultaneously? Very easy! Just connect them with the sign for a folder "\". Here, the command will search inside the "More items" folder only if it's inside the "Documents" folder:
As you can see, we didn't use "More items", only "More". You can shorten that filter how you want. It will still be applied to the whole path. See the example below:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.FullName -match "s\\Mo*" }
Earlier, we used the not statement in -like filter to exclude certain files and directories. The same can be done with -notmatch:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.FullName -notmatch "ents\\Ite*" }
Be aware that we're now excluding the "Items" folder from the search, not "More items".
And, with -cmatch we can apply the same case-sensitive filter as with -clike:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.FullName -cmatch "green*" }
I hope you get the gist of it now.
4.4 Filter how deep (how many folders in) you want to search for the file
Sometimes you might have a very long path to some of your files. If you don't want to waste time searching every folder on your computer recursively, you can use -Depth option. It specifies how many folders to search inside your folder tree. I already showed you the picture of a folder tree in the beginning of this article, but you should take a look at it here once again.
So, how does the -Depth parameter work?
-Depth 0 means that our command will search only the current folder. It will show results of all children of Depth level 0. Those results are:
1 "child file" and 2 "child folders".
-Depth 1 searches the current folder and its child-folders. It will show the results of all children of Depth level 1. Those results are:
1 "child file", 2 "child folders", 2 "grandchild files" and 1 "grandchild folder".
-Depth 2 searches the current folder and its child and grandchild folders. It will show results of all children of Depth level 2. Those results are:
1 "child file", 2 "child folders", 2 "grandchild files", 1 "grandchild folder" and 1 "great grandchild file".
Let's see the difference between these two commands:
Get-ChildItem -Recurse -Filter "*item*" -Depth 0
Get-ChildItem -Recurse -Filter "*item*" -Depth 1
The first command will show you only the files and folders inside our current directory.
The second command will also search for them inside every folder found inside the current folder.
For the sake of practice, let's combine it with Where-Object to find the green bracelet:
Get-ChildItem -Recurse -Filter "*item*" -Depth 1 | Where-Object { $_.name -clike"*green*" }
I hope that this example showed you how easy it is to use multiple options ( -Depth, -Recurse) and filters (-Filter, Where-Object).
5. How to Search Through Hidden Files
Some files are not that easily accessible to the user. You can see some of the hidden files and folders in Windows Explorer (here's how). But sometimes it's easier to find what you need if you see only those hidden files. That's possible with PowerShell.
The options we're going to use for that are:
-Force: show files otherwise not accessible by the user, such as hidden files.-Hidden: show only those hidden files and directories.
This example will search for hidden files in our user's folder:
gci -Path ~\ -Force -Hidden
Everything here is usually invisible to the typical user. But not for you now :D
The interesting thing is that there are more files not available to the user than the available ones. If you're brave enough, you can see them yourself (Remember! Ctrl + C stops the command!):
gci -Path ~\ -Force -Hidden -Recurse
6. How can you know all the properties that you can use as a filter?
Up until now, we'vce used some common properties, like Name and Fullname. But there are many others that you might want to access, like CreationTime (date of creating the file) or LastWriteTime (date of last edit of the file).
In this section, I'll first show you how to see all the possible properties. After that, you'll learn how to retrieve only the property you want for scripting purposes.
Go through step 2 above if you haven't already, because we're going to use the same files that we created before.
Move to the Documents folder in PowerShell.
I hope that this script looks familiar to you now. It searches for files with "item" in their names and checks if these names contain the word "green" (all lowercase letters):
Get-ChildItem -Recurse -Filter "*item*" |
Where-Object { $_.Name -clike "*green*" }
We know that only one file should appear (if you don't trust me, just see for yourself). So, we're going to see every possible property we can use by appending (adding at the end) this fragment of code:| Select-Object -Property *
Select-Object (alias: select) is used for selecting different types of properties. By using an option -Property we tell it to show both values and names of all the properties.
For example:
Name of property: FullName
Value of property: ~\Documents\More items\item 1- green bracelet.txt
The asterisk * at the end tells this command to show these names and values for every property possible.
The final version of this command looks like this:
Get-ChildItem -Recurse -Filter "*item*" |
Where-Object { $_.Name -clike "*green*" } |
Select-Object -Property *
Try finding the FullName property in there :D
This command showed us all possible properties that we can use for that 1 file that it found. If there were more files fitting the filter, then every single one of them would have a similar list of properties. But for different types of files you will get different results.
How to retrieve only 1 desired property
You've already learned how to check for all possible properties. So, how do we use any of them? Just put one of them instead an asterisk * at the end of the command, like we put CreationTime in here:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.Name -clike "*green*" } |
Select-Object -Property CreationTime
You can use any other property for the sake of this exercise, like LastWriteTime:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.Name -clike "*green*" } |
Select-Object -Property LastWriteTime
What if you want to retrieve only the value of the property without its name (because you already know its name and it also messes up your script)? You can retrieve just the value, by changing the -Property to -ExpandProperty:
Get-ChildItem -Recurse -Filter "*green*" -File |
Where-Object { $_.Name -clike "*green*" } |
Select-Object -ExpandProperty LastWriteTime
See the result:
7. I don't know the file’s name, but I know what's inside it. How do I find the file by its content?
Sometimes it's easier to find a file by searching it by its content. Or perhaps you have lots of similar files and you'd like to check them quickly without opening and closing them. I'll show you some techniques that will let you achieve that in no time.
This command will search every file on your system for the specified word or phrase (in our case, the phrase is "match"):
Get-ChildItem -Path C:\ -Recurse -File |
Select-String -Pattern 'match' -List
Here's what's happening:
Get-ChildItem -Path C:\ -Recurse -File: as you already know, this part searches for every file on your computer.|– passes the list of files to the next command. So, the next command will search for a certain phrase only in the files listed bygci.Select-String– "String" is a common word in programming used to describe a word/phrase/some text. So, we select the phrase that we want to search for. That phrase is specified by the-Patternparameter (in our case it's "match").-Listtells the command to show only the first found match in every file (great if you want to just see the list of all found files).
Here's an example output of our command:
Of course, you have quite a lot of files, and some images may also appear in your search (like .svg files that are basically text files that tell the system how to draw an icon). So, it's always best to specify what type of file you're searching for. Let's look for the phrase "red" inside .svg files:
Get-ChildItem -Filter "*.svg" -Recurse |
Select-String -Pattern 'red' -List
On the other hand, some text documents will never appear in your search (for example .doc and .docx documents are encoded in such a way that they're impossible to decode without Word).
But in regular text files, you can search for phrases with an emphasis on big and small letters with the -CaseSensitive option. Here, we're going to search for the phrase "github" with only lowercase letters:
Get-ChildItem -Filter "*.txt" -Recurse |
Select-String -Pattern 'github' -List -CaseSensitive
Other options that you'll often use with the Select-String command are:
Select-String -AllMatchwill show you all matches found in every searched file (instead of only 1 match found per file, like with-List).Select-String -Context 3shows the three lines of text before and after the line in which the match is found.Select-String -Rawwon't show you the paths, just the content of the files. This is great for automation and scripts. It's often combined with the-Contextoption.
Let's see some of these options in action:
Get-ChildItem -Filter "*.txt" -Recurse |
Select-String -Pattern 'github' -AllMatch -Context 3
Thanks to the -Context parameter, you can see a total of seven lines (three lines before and three lines after the match) in this file, one after another. This makes it easier to differentiate it from all the other matches found by -AllMatch that might be put in a very similar context.
If you ever feel like there's too much clutter on your screen, you can combine Select-String with Select-Object to get only the paths of the files with matched phrases.
The command below will search every .txt file on your computer for the phrase specified:
Get-ChildItem -Filter "*.txt" -Recurse |
Select-String -Pattern 'github' -List
Let's add the Select-Object -Property Path filter at the end. Now, the command will only show the paths, so there's less clutter on your screen:
Get-ChildItem -Filter "*.txt" -Recurse |
Select-String -Pattern 'github' -List |
Select-Object -Property Path
Some of the paths are not fully visible. We'll fix that in the next step.
8. I can't see the full path - how do I fix this?
Let's format the results with the Format-Table -Wrap -AutoSize command. -Autosize allows the result to take the whole available space. -Wrap allows wrapping (continuing the text in the next line when it doesn't fit in the space available), which creates more space if it's needed.
Here's an example:
Get-ChildItem -Path C:\ -Filter "*.txt" -Recurse |
Select-String -Pattern 'github' -List |
Select -Property Path |
Format-Table -Wrap -AutoSize
Now, you can see the whole paths (or any other results you need) even in PowerShell!
9. Hard to read? Open the results in the text editor of your choice
You can send the results of any script/command in two ways:
> ~\Documents\command_output.txt
AND| Out-File ~\Documents\command_output.txt
Both of these will create a file inside your Documents folder, which you can later open in any program of your choice and edit.
Just add whichever solution you prefer to the end of your command, like here:
Get-ChildItem -Filter "*.txt" -Recurse |
Select-String -Pattern 'match' -List |
Select -Property Path |
Out-File ~\Documents\command_output.txt
In the image below, first you'll see the same command, but without exporting the results to another file. The second command, at the bottom of the image, will export the results to the other file without showing them in PowerShell:
You'll see the results from second command after opening the file in any text editor:
But, what if you can't see the full path even in your text editor?
To address this, you can add | Format-Table -Wrap -AutoSize right before sending the results to the file:
Get-ChildItem -Path C:\ -Filter "*.txt" -Recurse |
Select-String -Pattern 'match' -List |
Select -Property Path |
Format-Table -Wrap -AutoSize |
Out-File ~\Documents\command_output.txt
And open the file to see the whole path!
Just remember that you have to copy each line one by one. Where you see the arrows in the screenshot above is a "newline" character, which you have to delete. Only after doing that can you copy the whole path and paste it into Windows Explorer or into some script.
10. Summary: the Ultimate Commands for Searching and Finding Whatever You Need
Here you can download a free cheat sheet with explanations of the commands and examples in one place.
Most used commands:
- Case-sensitive search:
Get-ChildItem -Path C:\ -Recurse -Filter "*whatYouNeed*" |
Where-Object { $_.Name -clike "*whatYouNeed*" } |
Select-Object { $_.FullName } |
Format-Table -Wrap -AutoSize
- Alternatively, send the result to a file:
Get-ChildItem -Path C:\ -Recurse -Filter "*whatYouNeed*" |
Where-Object { $_.Name -clike "*whatYouNeed*" } |
Select-Object { $_.FullName } |
Format-Table -Wrap -AutoSize |
Out-File ~\Documents\command_output.txt
- Search by file's content:
Get-ChildItem -Path C:\ -Recurse |
Select-String -Pattern 'what you remember' -AllMatch -Context 2 |
Format-Table -Wrap -AutoSize
- Alternatively, send the result to the file:
Get-ChildItem -Path C:\ -Recurse |
Select-String -Pattern 'what you remember' -CaseSensitive -AllMatch -Context 2 |
Format-Table -Wrap -AutoSize |
Out-File ~\Documents\command_output.txt
These commands should work for anything you want to find. I hope you understand now how they function after reading through this tutorial ;)
Wrapping Up
If you want to learn more about these commands, I show you how to work with them in depth in my tutorial “Learn PowerShell commands like a Linux user”.
If what you found here helped you in any way, consider following me on my social media in order to help me reach further audience: Mastodon, LinkedIn.
You can also rate me on Github and support me on Ko-fi!
Thank you for any support you're able to give. Have a great day!