Script de PowerShell para buscar y reemplazar todos los archivos con una extensión específica

Tengo varios archivos de configuración en Windows Server 2008 nesteds así:

C:\Projects\Project_1\project1.config C:\Projects\Project_2\project2.config 

En mi configuración necesito hacer una cadena de reemplazo como tal:

  

se convertirá:

  

Pensé en usar scripts por lotes, pero no había una buena manera de hacerlo, y escuché que con el scripting de PowerShell puedes realizar esto fácilmente. He encontrado ejemplos de find / replace, pero esperaba una forma de atravesar todas las carpetas dentro de mi directorio C: \ Projects y encontrar cualquier archivo que termine con la extensión ‘.config’. Cuando encuentre uno, quiero que reemplace mis valores de cadena.

¿Algún buen recurso para averiguar cómo hacer esto o cualquier gurú de PowerShell que pueda ofrecer alguna información?

Aquí un primer bash en la parte superior de mi cabeza.

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

PowerShell es una buena opción;) Es muy fácil enumerar archivos en un directorio determinado, leerlos y procesarlos.

El script podría verse así:

 Get-ChildItem C:\Projects *.config -recurse | Foreach-Object { $c = ($_ | Get-Content) $c = $c -replace '','' [IO.File]::WriteAllText($_.FullName, ($c -join "`r`n")) } 

Divido el código en más líneas para que pueda leerlo. Tenga en cuenta que puede usar Set-Content en lugar de [IO.File]::WriteAllText , pero agrega una nueva línea al final. Con WriteAllText puedes evitarlo.

De lo contrario, el código podría verse así: $c | Set-Content $_.FullName $c | Set-Content $_.FullName .

Este enfoque funciona bien:

 gci C:\Projects *.config -recurse | ForEach { (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ } 
  • Cambia “viejo” y “nuevo” a sus valores correspondientes (o usa variables).
  • No olvide el paréntesis, sin el cual recibirá un error de acceso.

Me gustaría ir con xml y 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) } 

Este ejemplo de PowerShell busca todas las instancias de la cadena “\ foo \” en una carpeta y sus subcarpetas, reemplaza “\ foo \” por “\ bar \” Y NO REESCRIBE archivos que no contengan la cadena “\ foo \” “De esta forma no se destruye el archivo de la última actualización de sellos de fecha y hora donde no se encontró la cadena:

 Get-ChildItem -Path C:\YOUR_ROOT_PATH\*.* -recurse | ForEach {If (Get-Content $_.FullName | Select-String -Pattern '\\foo\\') {(Get-Content $_ | ForEach {$_ -replace '\\foo\\', '\bar\'}) | Set-Content $_ } } 

He escrito una pequeña función auxiliar para reemplazar texto en un archivo:

 function Replace-TextInFile { Param( [string]$FilePath, [string]$Pattern, [string]$Replacement ) [System.IO.File]::WriteAllText( $FilePath, ([System.IO.File]::ReadAllText($FilePath) -replace $Pattern, $Replacement) ) } 

Ejemplo:

 Get-ChildItem . *.config -rec | ForEach-Object { Replace-TextInFile -FilePath $_ -Pattern 'old' -Replacement 'new' } 

Encontré útil el comentario de @Artyom, pero lamentablemente no ha publicado una respuesta.

Esta es la versión corta, en mi opinión la mejor versión, de la respuesta aceptada;

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

Al hacer un reemplazo recursivo, la ruta y el nombre del archivo deben ser incluidos:

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

Esto reemplazará todos los “viejos” por “nuevos” mayúsculas y minúsculas en todos los archivos de sus carpetas de su directorio actual.