I know there is code review for 'speed up' exists, but I also need to 'fix' problem of my script.
I migrated from Command Prompt(.bat
) to Powershell(.ps1
) because I think Command Prompt is hard to make script for complex things. I've heard that Powershell may have some overhead than Command Prompt, but if it is fast enough, I don't care.
Here is link for two files, sdn.old.bat
and sdn.new.ps1
. I put them in paste site because those are long enough.
Here is my problem.
This part takes a very long time to run.
$logs_loc = @(
"$Env:LocalAppdata"
"$Env:Appdata"
)
ForEach ($item in $logs_loc) {
Get-ChildItem -Path "$item\*" -Recurse -Force -Include *.log *.log.txt | Remove-Item -Force
}
It takes ~5 seconds and I don't know why. This also doesn't do anything. This code should remove all *.log
or *.log.txt
files under %Appdata%
and %LocalAppdata%
, but it don't delete anything. I tested with test file randomly placed blank *.log
and *.log.txt
but they remain after run.
I haven't tested other part of my script, so there may another problem exists...
TL;DR
Otter's helpful answer already explains the issue with your current code, the -Include
parameter takes string[]
(string array) as argument, if you want to pass multiple filters to the parameter you need to separate them by a comma ,
. See about_Arrays for details.
As for improving the efficiency of your code, you would need to make .NET API calls to IO.Directory
as zett42 points out in a comment or IO.DirectoryInfo
, both options are valid however the latter outputs IO.FileInfo
instead of strings. For handling the folder recursion you can use a Queue<T>
instance:
$env:LocalAppdata, $env:Appdata | & {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline)]
[string] $Path
)
begin { $queue = [Collections.Generic.Queue[IO.DirectoryInfo]]::new() }
process { $queue.Enqueue($Path) }
end {
while($queue.Count) {
$dir = $queue.Dequeue()
foreach($filter in '*.log', '*.log.txt') {
$dir.EnumerateFiles($filter)
}
foreach($i in $dir.EnumerateDirectories()) {
$queue.Enqueue($i)
}
}
}
} -ErrorAction SilentlyContinue | Remove-Item -Force
In .NET Core / PowerShell Core 7+, this task simplifies a lot thanks to the EnumerationOptions Class which allows us to Ignore Inaccessible files and folders:
# IgnoreInaccessible is set to `$true` by Defaut.
$enum = [IO.EnumerationOptions]@{
RecurseSubdirectories = $true
AttributesToSkip = 'Hidden, System, SparseFile, ReparsePoint'
}
$env:LocalAppdata, $env:Appdata | ForEach-Object {
foreach($filter in '*.log', '*.log.txt') {
[IO.Directory]::EnumerateFiles($_, $filter, $enum)
}
} | Remove-Item -Force