Sooner or later you need a script to list the files in a folder. In DOS we would type: 'DIR'; the nearest equivalent in PowerShell is gci. The full name behind the alias of gci is the informative, get-
ChildItem. You can take the comparison further, dir /s in DOS, translates to get-ChildItem -recurse in PowerShell.
Get-ChildItem Topics
• Trusty Twosome (get-Help and get-Member) • Example 1 - List files in the root of the C:\ drive • Example 2 - List ALL files, including hidden and system • Example 3 - Filter to list just the System files
• Example 4 - The famous -recurse parameter
• Problems with -recurse, and how to overcome them Trusty Twosome (get-Help and get-Member)
When you discover a new PowerShell command, it benefits from being probed with what I call the 'Trusty Twosome'. Experiment with get-Help and get-Member and unlock new scripting possibilities for get-childitem. To see what I mean try these two commands:
1) get-help get-childitem
(help gci) If you prefer abbreviations. (help gci -full) If you like examples.
get-help unearths useful parameters such as -recurse, -exclude, it also helps to reveals hidden files with: -force.
2) get-childitem | get-member (gci | gm) If you enjoy aliases.
(gci | gm -membertype property) If you are fond of filters.
get-member reveals properties that you don't normally see in explorer, for example, CreationTime. Example 1 - List files in the root of the C:\ drive
Here is an example which lists all the files in the C:\ root. # Powershell script to list the files in C: root
get-childitem "C:\"
Note 1: In this instance C:\ is the root and get-childitem lists any files in this directory. Note 2: get-childitem "C:\" works equally well without the speech marks.
Example 2 - List ALL files, including hidden and system $i=0
$GciFiles = get-childitem c:\ -force foreach ($file in $GciFiles) {$i++}
$GciFiles |sort |ft name, attributes -auto Write-host "Number of files: " $i
Note 1: The key addition is the parameter -force. What this does is include hidden and system files. Note 2: The additional commands are so that we can count the files, this makes easier to see prove that -force really makes a difference. Double check what I mean by running the script with, and without, the -force switch.
Example 3 - Filter to list just the System files # PowerShell cmdlet to list the System files in the root of C:\ $i=0
$GciFiles = get-ChildItem "c:\" -force |where {$_.attributes -match "System"} foreach ($file in $GciFiles) {$i++}
$GciFiles |sort |ft name, attributes -auto Write-host "Number of files: " $i
Note 1: We need to employ the comparison parameter -match, rather than -eq "System", this is because System files also have Hidden and other attributes. Consequently, their attribute does not equal ''System'', although it does contain, or match the word System.
Note 2: You probably worked it out for your self, but just to emphasise that the variable $i is a counter. Moreover, ++ increments $i each time the 'where' statements makes a match.
Incidentally, omitting $=0 at the beginning produces an unexpected, or undesirable result, should you run the script for a second time.
Challenge 1: Repeat the command with and without -force.
Challenge 2: Substitute this new 'where' clause on line 3: where {$_.attributes -ne "Directory"}. -ne is the opposite of -eq. Thus this command filters out the directory entry.
# PowerShell cmdlet to list the System files in the root of C:\ $i=0
$GciFiles = gci c:\ -force |where {$_.attributes -ne "Directory"} foreach ($file in $GciFiles) {$i++}
$GciFiles |sort |ft name, attributes -auto # $GciFiles |get-Member
Example 4 - The famous -recurse parameter
Outside of PowerShell, recurse is a little known verb meaning rerun. Inside of PowerShell, -recurse is one of the most famous parameters meaning: repeat the procedure on sub-folders.
The point of this script is to list all the executables in the System32 folder. Moreover it will display the CreationTime, which can help determine if a file is up-to-date. This technique is particularly useful for troubleshooting .dll files.
# Powershell script to list the exe files under C:\Windows\System32 $i =0
$DllFiles = gci "C:\Windows\System32" -recurse | ? {$_.extension -eq ".exe"} Foreach ($Dll in $DllFiles) {
$Dll.name + "`t " + $DLL. CreationTime + "`t " + $Dll. Length $i++
}
Write-Host The total number of files is: $i
Note 1: This example uses two aliases; my principle reason was to make line 4 shorter. Gci is an alias for our featured command get-childitem, and the question mark (?) is an alias for 'where'.
Note 2: The -recurse parameter comes directly after the name of the directory. For completeness, the location should be introduced by the -path parameter, but as this is optional, I have omitted the -path parameter in this script. However, this is how to include the -path parameter.
$DllFiles = gci -path "C:\Windows\System32" -recurse.
Note 3: If you investigate the file's properties, then you can spot other assets, for example: LastWriteTime, or even Length. Here is how to employ get-member to list the properties. # Powershell script to investigate file properties
get-ChildItem | get-Member -membertype property The Rest of the Item Family
Copy-Item get-Item (gi) Move-Item New-Item Remove-Item Set-Item
Problems with -recurse, and how to overcome them Case Study
The mission is to list all files containing the word 'Microsoft' in the Windows folder or its sub-folders. For this we use the select-string pattern matching command.
The problem is that this script does not work. All that happens is that we get an error: Cannot find path... Path does not exist.
$i=0
$Path = "C:\windows"
$Full = get-ChildItem $Path -recurse $StringText= "Microsoft"
$List = select-string -pattern $StringText $Full foreach ($file in $List) {$file.Path; $i++} $i
The solution: Add the -include parameter $i=0
$Path = "C:\windows"
$Full = get-ChildItem $Path -include *.txt -recurse $StringText= "Microsoft"
$List = select-string -pattern $StringText $Full foreach ($file in $List) {$file.Path; $i++} $i
Note 1: When we add -include *.txt the cmdlet works as initially planned. Actually, you could swap the famous *. * for *.txt, thus : -include *. *
Note 2: -include only works when you also append the -recurse parameter.
Note 3: -include applies to the filename and extension. Where I made a mistake was thinking that - include would apply to the path.
Simplification
There is no reason why you cannot simplify by removing at least two of the variables, especially on a production script. The only reason that I employed $Path and $StringText is that I like to isolate and control each step of the script.
$i=0
$Full = get-ChildItem C:\windows -include *.txt -recurse $List = select-string -pattern "Microsoft" $Full
foreach ($file in $List) {$file.Path; $i++} $i
Summary of -Recurse
-Recurse is a classic switch to instruct PowerShell commands to repeat for sub directories. Once you learn the name -recurse and the position, directly after the directory, then it will serve you well in scripts that need to search repeatedly for information.