如何修复/加速powershell脚本?

问题描述 投票:0回答:2

我知道存在“加速”的代码审查,但我还需要“修复”我的脚本问题。

我从命令提示符(

.bat
)迁移到Powershell(
.ps1
),因为我认为命令提示符很难为复杂的事情制作脚本。我听说 Powershell 可能比命令提示符有一些开销,但如果它足够快,我不在乎。

这是两个文件的链接,

sdn.old.bat
sdn.new.ps1
。我把它们放在粘贴网站中,因为它们足够长。

粘贴.gg

这是我的问题。

这部分需要很长时间才能运行。

$logs_loc = @(
    "$Env:LocalAppdata"
    "$Env:Appdata"
)
ForEach ($item in $logs_loc) {
    Get-ChildItem -Path "$item\*" -Recurse -Force -Include *.log *.log.txt | Remove-Item -Force
}

需要大约 5 秒,我不知道为什么。这也没有任何作用。此代码应删除

*.log
*.log.txt
下的所有
%Appdata%
%LocalAppdata%
文件,但不会删除任何内容。我使用随机放置空白
*.log
*.log.txt
的测试文件进行测试,但它们在运行后仍然存在。

我还没有测试脚本的其他部分,所以可能存在另一个问题......


TL;博士

  1. 我不知道为什么我的代码不起作用,而且运行时间也太长。
  2. 有什么可以‘提高’速度吗?
powershell
2个回答
5
投票

Otter的有用答案已经解释了您当前代码的问题,

-Include
参数采用
string[]
字符串数组)作为参数,如果您想将多个过滤器传递给参数,您需要将它们分开用逗号
,
。有关详细信息,请参阅about_Arrays

为了提高代码效率,您需要对

IO.Directory
进行 .NET API 调用,如 zett42 在评论中指出的那样或
IO.DirectoryInfo
,这两个选项都是有效的,但后者输出
IO.FileInfo
而不是字符串。为了处理文件夹递归,您可以使用
Queue<T>
实例
:

$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

.NET Core / PowerShell Core 7+ 中,由于 EnumerationOptions Class 允许我们忽略不可访问的文件和文件夹,此任务大大简化:

# 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

2
投票

问题是您的

-include
参数将
*.log *.log.txt
解释为单个模式,但我们希望它匹配任一模式,因此只需用
,
将它们分开,因此
*.log, *.log.txt

$logs_loc = @(
    "$Env:LocalAppdata"
    "$Env:Appdata"
)
ForEach ($item in $logs_loc) {
    Get-ChildItem -Path "$item\*" -Recurse -Force -Include *.log, *.log.txt | Remove-Item -Force
}

至于速度,这似乎是一个你不会经常执行的操作,所以我不确定是否值得投入大量时间来使其更快,我的需要 10 秒。我建议向 Code Review 询问这一点!

© www.soinside.com 2019 - 2024. All rights reserved.