用于查找和替换具有特定扩展名的所有文件的PowerShell脚本

用于查找和替换具有特定扩展名的所有文件的PowerShell脚本,powershell,scripting,replace,find,Powershell,Scripting,Replace,Find,我在Windows Server 2008上有几个嵌套的配置文件,如下所示: C:\Projects\Project_1\project1.config C:\Projects\Project_2\project2.config <add key="Environment" value="Dev"/> 在我的配置中,我需要执行如下字符串替换: C:\Projects\Project_1\project1.config C:\Projects\Project_2\project

我在Windows Server 2008上有几个嵌套的配置文件,如下所示:

C:\Projects\Project_1\project1.config

C:\Projects\Project_2\project2.config
<add key="Environment" value="Dev"/>
在我的配置中,我需要执行如下字符串替换:

C:\Projects\Project_1\project1.config

C:\Projects\Project_2\project2.config
<add key="Environment" value="Dev"/>

将成为:

<add key="Environment" value="Demo"/>

我曾考虑过使用批处理脚本,但没有很好的方法可以做到这一点,我听说使用PowerShell脚本可以轻松地执行这一点。我已经找到了find/replace的例子,但我希望有一种方法可以遍历我的C:\Projects目录中的所有文件夹,并找到以“.config”扩展名结尾的任何文件。当它找到一个时,我希望它替换我的字符串值


有什么好的资源可以找到如何做到这一点,或者有什么PowerShell大师可以提供一些见解?

PowerShell是一个不错的选择;)枚举给定目录中的文件、读取它们并进行处理非常容易

脚本可以如下所示:

Get-ChildItem C:\Projects *.config -recurse |
    Foreach-Object {
        $c = ($_ | Get-Content) 
        $c = $c -replace '<add key="Environment" value="Dev"/>','<add key="Environment" value="Demo"/>'
        [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n"))
    }
Get ChildItem C:\Projects*.config-recurse|
Foreach对象{
$c=($|获取内容)
$c=$c-替换“”,“”
[IO.File]::writealText($\ ux.FullName,($c-join“`r`n”))
}
为了便于阅读,我将代码拆分为更多行。 请注意,您可以使用Set Content代替
[IO.File]::writealText
,但它会在末尾添加新行。使用
writealText
可以避免它


否则代码可能会如下所示:
$c | Set Content$\ FullName

这是我头上的第一次尝试

$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
    (Get-Content $file.PSPath) |
    Foreach-Object { $_ -replace "Dev", "Demo" } |
    Set-Content $file.PSPath
}

我将使用xml和xpath:

dir C:\Projects\project_*\project*.config -recurse | foreach-object{  
   $wc = [xml](Get-Content $_.fullname)
   $wc.SelectNodes("//add[@key='Environment'][@value='Dev']") | Foreach-Object {$_.value = 'Demo'}  
   $wc.Save($_.fullname)  
}

这种方法很有效:

gci C:\Projects *.config -recurse | ForEach {
  (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ 
}
  • 将“旧”和“新”更改为相应的值(或使用变量)
  • 不要忘记括号——没有括号,您将收到一个访问错误

此powershell示例查找文件夹及其子文件夹中字符串“\foo\”的所有实例,将“\foo\”替换为“\bar\”,并且不会重写不包含字符串“\foo\”的文件。这样,您就不会破坏未找到字符串的文件上次更新日期戳:

Get ChildItem-Path C:\YOUR\u ROOT\u Path\*.-递归
|ForEach{If(获取内容$\全名|选择字符串-模式'\\foo\\\'))
{(获取内容$| ForEach{$|-替换'\\foo\'','\bar\'})}设置内容$|
}

我编写了一个小助手函数来替换文件中的文本:

function Replace-TextInFile
{
    Param(
        [string]$FilePath,
        [string]$Pattern,
        [string]$Replacement
    )

    [System.IO.File]::WriteAllText(
        $FilePath,
        ([System.IO.File]::ReadAllText($FilePath) -replace $Pattern, $Replacement)
    )
}
例如:

Get-ChildItem . *.config -rec | ForEach-Object { 
    Replace-TextInFile -FilePath $_ -Pattern 'old' -Replacement 'new' 
}
我发现他的评论很有用,但不幸的是他没有给出答案

在我看来,这是公认答案的简短版本,也是最好的版本

ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}

进行递归替换时,需要包括路径和文件名:

Get-ChildItem -Recurse | ForEach {  (Get-Content $_.PSPath | 
ForEach {$ -creplace "old", "new"}) | Set-Content $_.PSPath }

这将用“新”替换当前目录下文件夹中所有文件中的所有“旧”区分大小写。

请告诉我们您的进展情况,或者需要解决的文件是否存在一些奇怪的格式问题。这个问题的一个好处是它的测试不会影响生产代码。我想补充一点,测试提供的所有解决方案都是可行的,但这一个是最容易实现可读性的。我可以把这个交给一个同事,他可以很容易地理解发生了什么。感谢您的帮助。要在子目录中的文件中工作,您需要“.PSPath”。有趣的是,当我尝试在没有()的情况下使用get content时,它在写入内容时失败了,因为文件被锁定。短版本(使用了常见别名):
ls*.config-rec |%{$f=$};(gc$f.PSPath)|%{$}替换“Dev”,“Demo”}sc$f.PSPath}
@Artyom不要忘记
ls
之后的
。我自己也被刺痛了。如果您要删除*.config以在所有文件上运行,UnauthorizedAccessException也可能由于文件夹而导致。您可以将-File筛选器添加到Get-ChildItem。。。我花了一段时间才弄明白,如果其他人遇到这个问题,就像我所做的那样——直接从批处理文件执行这个问题——在执行这样的命令时,使用
foreach对象
而不是
%
别名可能会有所帮助。否则,它可能会导致错误:
表达式只允许作为管道的第一个元素
答案中的“.PSPath”部分确实帮助了我。但我必须将内部的“{$”更改为“$\”.我会编辑你的答案,但我没有使用你的-creplace部分--我使用的是接受的答案与.pspath一起使用,因此为了简洁表达,我选择了这个答案-但我必须将
Get Content$\ucode>替换为
Get Content$\ucode>。FullName
,以及
Set Content
的等效项,以处理不在根目录下的文件。