我的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上观看了几个视频
答案 0 :(得分:2)
Add-Content
,Set-Content
甚至Out-File
都非常慢。这是因为每次调用都会打开文件,写入文件并关闭句柄。它永远不会比那更聪明。
在您考虑管道如何与Get-ChildItem
(以及Where-Object
和Select-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