Powershell 查找和替换循环,OutOfMemoryException

Powershell Find and Replace Loop, OutOfMemoryException

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

我是 运行 Server 2012 R2 虚拟机中的脚本,具有 4 个 vCPU 和 4GB 内存。我已将 Powershell 的 MaxMemoryPerShellMB 值设置为 3GB。如前所述,该脚本有效,但 2-4 小时后 powershell 将开始抛出 OutOfMemoryExceptions 并崩溃。该脚本是 'V2 friendly',我还没有将它采用到 V3+,但我怀疑这是否重要。

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

$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++}

欢迎大家提出意见、批评和建议。

谢谢

我能看到的最大问题是您为每个 属性 查询重复获取文件。将其替换为每次循环传递一次调用,并将其保存以在传递过程中使用。此外,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,因为您已准备好所有对象,但我只想确保我们在走得更远之前是正确的轨道。