2010-05-14 12 views
90

Tengo varios archivos de configuración en Windows Server 2008 anidado como tales:PowerShell Script para buscar y reemplazar todos los archivos con una extensión específica

C:\Projects\Project_1\project1.config 

C:\Projects\Project_2\project2.config 

En mi configuración tengo que hacer una cadena sustituir como tales:

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

se convertirá en:

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

pensé acerca del uso de secuencias de comandos por lotes, pero hay no era una buena manera de hacer esto, y oí 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 recurso bueno para saber cómo hacer esto o cualquier gurú de PowerShell que pueda ofrecer alguna información?

+1

Háganos saber cómo se metió o si hubo algunos problemas de formato extraño con los archivos que deben abordarse. Una cosa buena sobre el problema es que es una prueba sin afectar el código de producción –

Respuesta

135

Aquí un primer intento 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 
} 
+3

. Me gustaría agregar que probar todas las soluciones proporcionadas funciona, pero esta fue la más fácil de leer. Pude entregar esto a un compañero de trabajo y él podía entender fácilmente lo que estaba pasando. Gracias por la asistencia. – Brandon

+0

Cosas geniales Brandon. No he abrazado por completo a Powershell, ¡pero cuando consideras cuánto tardaría esto en VBScript! –

+9

Para que esto funcione en archivos en subdirectorios, necesita ".PSPath". Curiosamente, cuando traté de hacer que esto funcionara sin un() alrededor de get-content, falló en el contenido de escritura porque el archivo estaba bloqueado. –

22

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

El guión podría tener este aspecto:

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")) 
    } 

yo nos dividimos el código para más líneas para ser legible para usted. 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 ser así: $c | Set-Content $_.FullName.

5

Me gustaría ir con XML y XPath:

11

Este enfoque funciona bien:

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

Este ejemplo PowerShell busca todas las instancias de la cadena "\ foo \" en una carpeta y sus subcarpetas, reemplaza "\ foo \" con "\ bar \" Y NO reescribir los archivos que no contengan la cadena "\ foo \" de esta manera no destruir el archivo de actualización sellos de fecha y hora últimos en los que no se encuentra 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 $_ } 
      } 
3

he escrito un poco de 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' 
} 
1

Encontré el comentario de @Artyom útil pero desafortunadamente no ha dado ninguna 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} 
+0

En caso de que alguien más se encuentre con esto, como lo hice, buscando ejecutar esto directamente desde un archivo por lotes, puede ser útil usar 'foreach-object' en lugar del'% 'alias cuando ejecutando un comando como este. De lo contrario, puede provocar el error: 'Las expresiones solo están permitidas como el primer elemento de una tubería –

0

Al hacer la sustitución recursiva, la ruta y el nombre deben ser incluidos:

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

Este Wil reemplazar todos "viejo" con el "nuevo" entre mayúsculas y minúsculas en todos los archivos de las carpetas de tu directorio actual

Cuestiones relacionadas