我可以更快地制作这个脚本吗?

时间:2017-06-05 21:34:04

标签: windows powershell powershell-v4.0

我为实习编写了一个简单的脚本,该脚本遍历提供的目录并删除任何超过指定天数的文件。我今天花了我所有的空闲时间试图收紧它。这是我到目前为止所得到的:

function delOld($dir, $numDays){
    $timespan = new-timespan -days $numDays
    $curTime = get-date
    get-childItem $dir -Recurse -file | 
    where-object {(($curTime)-($_.LastWriteTime)) -gt $timespan} | 
    remove-Item -whatif
}

以下是函数调用的示例:

delOld -dir "C:\Users\me\Desktop\psproject" -numDays 5

对于难以阅读,我发现将操作压缩到一行比在每次迭代时将它们重新分配给易读变量更有效。出于测试目的,删除项目目前尚未确定。我知道在这一点上,我可能无法加快速度,但是,我在TB文件上运行它,所以每个操作都很重要。

提前感谢您提供的任何建议!

3 个答案:

答案 0 :(得分:5)

保持PowerShell和.NET方法的领域,以及如何加快功能:

  • 预先计算一次的截止时间戳。

  • [IO.DirectoryInfo]类型的EnumerateFiles()方法(PSv3 + / .NET4 +)与foreach 语句结合使用。 提示wOxxOm

    • EnumerateFiles()一次枚举一个文件,保持内存使用不变,类似但比Get-ChildItem更快。

      • 警告

        • EnumerateFiles() 总是包含隐藏的文件,而Get-ChildItem默认排除它们,只有{{1}才包含它们}已指定。

        • 如果由于缺少权限而遇到无法访问的目录,则
        • -Force不合适,因为即使您附上整个 EnumerateFiles()语句在foreach / try块中,只有在遇到第一个无法访问的目录时迭代停止,您才会获得部分输出

        • 枚举顺序可能与catch不同。

    • PowerShell的Get-ChildItem 声明foreach cmdlet 快得多,而且比PSv4 + {更快{1}}集合方法

  • 直接在循环体内的每个ForEach-Object实例上调用.ForEach()方法。

注意:为简便起见,下面的函数中没有错误检查,例如.Delete()是否具有允许值以及[System.IO.FileInfo]是否引用现有目录(如果&# 39;基于自定义PS驱动器的路径,您必须首先使用$numDays解决它。 功能

$dir

注意:以上只需输出要删除的文件的路径;将Convert-Path替换为function delOld($dir, $numDays) { $dtCutoff = [datetime]::now - [timespan]::FromDays($numDays) # Make sure that the .NET framework's current dir. is the same as PS's: [System.IO.Directory]::SetCurrentDirectory($PWD.ProviderPath) # Enumerate all files recursively. # Replace $file.FullName with $file.Delete() to perform actual deletion. foreach ($file in ([IO.DirectoryInfo] $dir).EnumerateFiles('*', 'AllDirectories')) { if ($file.LastWriteTime -lt $dtCutOff) { $file.FullName } } } 以执行实际删除。

答案 1 :(得分:1)

许多PowerShell cmdlet比.NET等效版本慢。例如,您可以拨打[System.IO.File]::Delete($_.FullName),然后查看是否存在性能差异。同样适用于Get-ChildItem => [System.IO.Directory]::GetFiles(...)

为此,我会编写一个小脚本,创建两个临时文件夹,每个文件夹中包含100,000个空测试文件。然后调用[System.Diagnostics.StopWatch]中包含的函数的每个版本。

一些示例代码:

$stopwatch = New-Object 'System.Diagnostics.StopWatch'
$stopwatch.Start()

Remove-OldItems1 ...

$stopwatch.Stop()
Write-Host $stopwatch.ElapsedMilliseconds

$stopwatch.Reset()
$stopwatch.Start()

Remove-OldItems2 ...

$stopwatch.Stop()
Write-Host $stopwatch.ElapsedMilliseconds

PowerShell的更多布朗尼点:在Powershell窗口中运行Get-Verb,您可以看到已批准的动词列表。建议将PowerShell中的函数命名为Verb-Noun,因此Remove-OldItems之类的内容符合要求。

答案 2 :(得分:1)

这将删除并行处理中的所有内容。

workflow delOld([string]$dir, [int]$numDays){
    $timespan = new-timespan -days $numDays
    $curTime = get-date
    $Files = get-childItem $dir -Recurse -file | where-object {(($curTime)-($_.LastWriteTime)) -gt $timespan}
    foreach -parallel ($file in $files){
        Remove-Item $File
    }

}

delOld -dir "C:\Users\AndrewD\Downloads" -numDays 8

现在,如果有很多文件夹试试这个