Powershell查找和替换循环,OutOfMemoryException

时间:2015-12-22 22:07:55

标签: powershell recursion replace out-of-memory

我有一个有效的PowerShell脚本,可以在数千个文件中查找和替换一些带有新字符串的不同字符串,而无需更改文件的修改日期。在任何给定的文件中,可能有数百个要替换的字符串实例。文件本身并不是很大,可能只有1-50MB(我正在测试的目录快速浏览显示最大的~33MB)。

我在具有4个vCPU和4GB RAM的Server 2012 R2 VM中运行脚本。我已将Powershell的MaxMemoryPerShellMB值设置为3GB。如前所述,该脚本可以工作,但2-4小时后,powershell将开始抛出OutOfMemoryExceptions并崩溃。该脚本是V2友好的'而我还没有将它用于V3 +,但我怀疑这太重要了。

我的问题是是否可以改进脚本以防止/消除我目前遇到的内存异常。如果它运行得慢,我不介意,只要它能完成工作而不必每隔几小时检查一次并重新启动它。

$i=0
$all = Get-ChildItem -Recurse -Include *.txt
$scriptfiles    = Select-String  -Pattern string1,string2,string3 $all
$output = "C:\Temp\scriptoutput.txt"

foreach ($file in $scriptFiles)

{

$filecreate=(Get-ChildItem $file.Path).creationtime
$fileaccess=(Get-ChildItem $file.Path).lastaccesstime
$filewrite=(Get-ChildItem $file.Path).lastwritetime

"$file.Path,Created: $filecreate,Accessed: $fileaccess,Modified: $filewrite" | out-file -FilePath $output -Append

    (Get-Content $file.Path) | ForEach-Object {$_ -replace "string1", "newstring" `
                                                  -replace "string2", "newstring" `
                                                  -replace "string3", "newstring"
                           } | Set-Content $file.Path   

(Get-ChildItem $file.Path).creationtime=$filecreate
(Get-ChildItem $file.Path).lastaccesstime=$fileaccess
(Get-ChildItem $file.Path).lastwritetime=$filewrite 

$filecreate=(Get-ChildItem $file.Path).creationtime
$fileaccess=(Get-ChildItem $file.Path).lastaccesstime
$filewrite=(Get-ChildItem $file.Path).lastwritetime

"$file.Path,UPDATED Created: $filecreate,UPDATED Accessed: $fileaccess,UPDATED Modified: $filewrite" | out-file -FilePath $output -Append

$i++}

欢迎任何评论,批评和建议。

由于

1 个答案:

答案 0 :(得分:0)

我可以看到的最大问题是您反复获取要查询的每个属性的文件。用每个循环传递一次调用替换它并保存它以在传递期间使用。 Out-File也是将数据输出到文件的较慢方法之一。

$output = "C:\Temp\scriptoutput.txt"
$scriptfiles  = Get-ChildItem -Recurse -Include *.txt | 
    Select-String  -Pattern string1,string2,string3 | 
    Select-Object -ExpandProperty Path

$scriptfiles | ForEach-Object{
    $file = Get-Item $_

    # Save currrent file times
    $filecreate=$file.creationtime
    $fileaccess=$file.lastaccesstime
    $filewrite=$file.lastwritetime

    "$file,Created: $filecreate,Accessed: $fileaccess,Modified: $filewrite" 

    # Update content. 
    (Get-Content $file) -replace "string1", "newstring" `
        -replace "string2", "newstring" `
        -replace "string3", "newstring" | Set-Content $file   

    # Write all the original times back. 
    $file.creationtime=$filecreate
    $file.lastaccesstime=$fileaccess
    $file.lastwritetime=$filewrite 

    # Verify the changes... Should not be required but it is what you were doing. 
    $filecreate=$file.creationtime
    $fileaccess=$file.lastaccesstime
    $filewrite=$file.lastwritetime

    "$file,UPDATED Created: $filecreate,UPDATED Accessed: $fileaccess,UPDATED Modified: $filewrite" 
} | Set-Content $output 

未经测试但应该没问题。

根据你的替换实际上你可能会节省一些时间。在生产运行之前先进行测试。

我删除了你所拥有的计数器,因为它在代码中没有出现。

您的日志记录可以很容易地基于csv,因为您已准备好所有对象,但我只是想确保在我们前往远程之前我们是正确的轨道。