I spent weeks trying to figure out the best way to use Get-Childitem or LS or DIR to generate the file listing of some VERY large directories (> 1M files per directory) on remote servers (servers.txt) when I came across the idea of using .NET.
The core of the script below is found in many places on this website and the web in general. It is so much faster than get-childitem.
I am not familiar with .NET commands. Is there a way I can modify this such that it will also return the file size and date/time modified?
invoke-command -computername (gc servers.txt) -scriptblock {
$directoryPath = "s:somepathstructure"
##### gets directory listing #####
Try {
$Folders = [System.IO.Directory]::EnumerateFiles($directoryPath, '*.*', 'AllDirectories')
} catch {
$_.Exception.message
}
[System.IO.File]::WriteAllLines('c:tempoutfile.txt', $folders)
}
Sure there is, the static method Directory.EnumerateFiles
only returns the file’s absolute path (.FullName
) however if you need more information about the files you can change the logic to use the instance method EnumerateFiles
from DirectoryInfo
which returns an enumerable of FileInfo
. Worth noting here that since this method outputs objects instead of simple strings, the way you export to a file should also be different, you should use a cmdlet capable of converting objects into structured data, for example Csv (Export-Csv
) or Json (ConvertTo-Json
):
Invoke-Command -ComputerName (Get-Content servers.txt) -ScriptBlock {
try {
$directoryPath = Get-Item 's:somepathstructure'
$directoryPath.EnumerateFiles('*', 'AllDirectories') |
Export-Csv 'c:tempoutfile.csv' -NoTypeInformation
}
catch {
$_.Exception.message
}
}
Another notable mention is that this method will stop the enumeration as soon as there is an inaccessible file or folder, in which case you need to change the logic of your code to handle that.
Here is how the code would look:
Invoke-Command -ComputerName (Get-Content servers.txt) -ScriptBlock {
& {
$enumerator = (Get-Item 's:somepathstructure').
EnumerateFiles('*', 'AllDirectories').
GetEnumerator()
while ($true) {
try {
if (-not $enumerator.MoveNext()) {
# done enumeration, break the loop
break
}
# else, output
$enumerator.Current
}
catch {
# you can leave this block empty to ignore any error,
# or have error handling needed if you need loging, etc
}
}
} | Export-Csv 'c:tempoutfile.csv' -NoTypeInformation
}