繁体   English   中英

如何修复/加速powershell脚本?

[英]How to fix/speed up powershell script?

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

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

这是两个文件的链接, sdn.old.batsdn.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 秒,我不知道为什么。 这也没有任何作用。 此代码应删除%Appdata%%LocalAppdata%下的所有*.log*.log.txt文件,但不会删除任何内容。 我测试了随机放置空白*.log*.log.txt的测试文件,但它们在运行后仍然存在。

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


TL;博士

  1. 我不知道为什么我的代码不起作用,而且运行时间也太长。
  2. 有什么可以“提高”速度的吗?

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 类允许我们忽略不可访问的文件和文件夹,此任务大大简化:

# IgnoreInaccessible is set to `$true` by Defaut.

$enum = [IO.EnumerationOptions]@{
    RecurseSubdirectories = $true
    AttributesToSkip      = 2, 4, 1024, 512
}

$env:LocalAppdata, $env:Appdata | ForEach-Object {
    foreach($filter in '*.log', '*.log.txt') {
        [IO.Directory]::EnumerateFiles($_, $filter, $enum)
    }
} | Remove-Item -Force

有关AttributesToSkip的详细信息,请参阅此答案

问题是您的-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!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM