powershell slow(?) - 将子文件夹的名称写入文本文件

时间:2014-12-23 16:56:10

标签: powershell

我的Powershell脚本似乎很慢,当我在ISE中运行以下代码时,它会一直运行,不会停止。

我正在尝试将文件夹中的子文件夹列表(文件夹路径在$ scratchpart中)写入文本文件。有> 30k子文件夹

$limit = (Get-Date).AddDays(-15)
$path = "E:\Data\PathToScratch.txt"
$scratchpath = Get-Content $path -TotalCount 1

Get-ChildItem -Path $scratchpath -Recurse -Force | Where-Object { $_.PSIsContainer -and $_.CreationTime -lt $limit } | Add-Content C:\Data\eProposal\POC\ScratchContents.txt

如果我的方法不是最优的,请告诉我。最后,我将读取文本文件,压缩子文件夹进行存档并删除它们。

提前感谢您的帮助。我是PS的新手,在MVA上观看了几个视频

2 个答案:

答案 0 :(得分:2)

在PowerShell中,

Add-ContentSet-Content甚至Out-File都非常慢。这是因为每次调用都会打开文件,写入文件并关闭句柄。它永远不会比那更聪明。

在您考虑管道如何与Get-ChildItem(以及Where-ObjectSelect-Object)配合使用之前,这听起来并不糟糕。在它开始将对象传入管道之前,它不会等到它完成。一旦提供者返回它,它就会开始传递对象。对于大的结果集,这意味着在几个完成处理之后,对象仍然在很长时间内进入管道。一般来说,这太棒了!这意味着系统将更有效地运行,这就是为什么这样的原因:

$x = Get-ChildItem;
$x | ForEach-Object { [...] };

明显慢于这样的东西:

Get-ChildItem | ForEach-Object { [...] };

这就是为什么像这样的东西似乎停滞不前:

Get-ChildItem | Sort-Object Name | ForEach-Object { [...] };

Sort-Object cmdlet需要等待,直到它在排序之前收到所有管道对象。它必须能够排序。排序本身几乎是瞬间完成的;只是cmdlet等到它有完整的结果。

Add-Content的问题在于,它经历了管道而不是“这是一个写一次的巨型字符串”,而是“,这是一个要写的字符串。这是一个要写的字符串。这是一个要写的字符串。这是一个要写的字符串。“您将逐行向Add-Content发送内容。 每一行将实例化对Add-Content的新调用,要求文件打开,写入和关闭。如果将Get-ChildItem [...] | Where-Object [...]的结果分配给变量,然后立即将整个变量写入文件,您可能会看到更好的性能:

$limit = (Get-Date).AddDays(-15);
$path = "E:\Data\PathToScratch.txt";
$scratchpath = Get-Content $path -TotalCount 1;

$Results = Get-ChildItem -Path $scratchpath -Recurse -Force -Directory | `
    Where-Object{$_.CreationTime -lt $limit } | `
    Select-Object -ExpandPropery FullName;

Add-Content C:\Data\eProposal\POC\ScratchContents.txt -Value $Results;

但是,如果结果实际上非常大,您可能会担心内存使用情况。实际上,您也可以将System.IO.StreamWriter用于此目的。通过切换到StreamWriter我的过程速度提高了近两个数量级(从12小时到20分钟),并且当我有大约250行写入时,我只调用StreamWriter(这似乎是StreamWriter开销的盈亏平衡点。但我正在为大约10,000个用户和近10 TB的数据解析用户家庭和组共享的所有ACL。你的任务可能不会那么大。

Here是一个很好的博客,解释了这个问题。

答案 1 :(得分:0)

你至少有PowerShell 3.0吗?如果你这样做,你应该能够通过过滤掉文件来减少时间,因为你也会返回这些文件。

Get-ChildItem -Path $scratchpath -Recurse -Force -Directory | ...

目前,您正在返回所有文件和文件夹,然后使用$_.PSIsContainer过滤掉较慢的文件。所以应该最终得到像这样的东西

Get-ChildItem -Path $scratchpath -Recurse -Force -Directory | 
    Where-Object{$_.CreationTime -lt $limit } |
    Select-Object -ExpandPropery FullName | 
    Add-Content C:\Data\eProposal\POC\ScratchContents.txt