2010-05-14 4 views
90

ich mehrere Konfigurationsdateien auf Windows Server 2008 haben wie so verschachtelt:Powershell-Skript zum Suchen und Ersetzen für alle Dateien mit einer bestimmten Erweiterung

C:\Projects\Project_1\project1.config 

C:\Projects\Project_2\project2.config 

In meiner Konfiguration Ich muss wie eine solche Zeichenfolge ersetzen tun:

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

wird geworden:

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

ich dachte über Batch-Scripting, aber es war keine gute Möglichkeit, dies zu tun, und ich habe gehört, dass mit PowerShell-Skripts können Sie dies einfach durchführen. Ich habe Beispiele für find/replace gefunden, aber ich habe auf einen Weg gehofft, der alle Ordner in meinem C: \ Projects-Verzeichnis durchläuft und alle Dateien findet, die mit der Erweiterung ".config" enden. Wenn es eins findet, möchte ich, dass es meine String-Werte ersetzt.

Haben Sie gute Ressourcen, um herauszufinden, wie Sie diese oder andere PowerShell-Gurus einsetzen können, die Ihnen einen Einblick bieten können?

+1

Lassen Sie uns wissen, wie Sie vorankamen oder ob es einige seltsame Formatierungsprobleme mit den Dateien gibt, die angesprochen werden müssen. Eine gute Sache über das Problem ist, dass es Test ist, ohne Produktionscode zu beeinflussen –

Antwort

135

Hier ein erster Versuch an der Spitze meines Kopfes.

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

Ich möchte hinzufügen, dass das Testen der bereitgestellten Lösungen alles funktioniert, aber dieses war das Einfachste für die Lesbarkeit. Ich konnte es einem Kollegen geben und er konnte leicht verstehen, was vor sich ging. Danke für die Hilfe. – Brandon

+0

Tolles Zeug Brandon. Ich habe Powershell nicht voll akzeptiert, aber wenn man bedenkt, wie lange das in VBScript dauern würde !!!! –

+9

Damit dies in Dateien in Unterverzeichnissen funktioniert, benötigen Sie ".PSPath". Interessanterweise, als ich versuchte, dies ohne a() um get-content zu machen, scheiterte es am write-content, weil die Datei gesperrt war. –

22

PowerShell ist eine gute Wahl;) Es ist sehr einfach, Dateien im angegebenen Verzeichnis zu nummerieren, sie zu lesen und zu verarbeiten.

Das Skript könnte wie folgt aussehen:

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

ich teilen den Code, um mehr Zeilen für Sie lesbar zu sein. Beachten Sie, dass Sie Set-Content anstelle von [IO.File]::WriteAllText verwenden können, aber am Ende eine neue Zeile hinzugefügt wird. Mit WriteAllText können Sie es vermeiden.

Andernfalls könnte der Code wie folgt aussehen: $c | Set-Content $_.FullName.

5

ich mit XML und XPath gehen würde:

11

Dieser Ansatz funktioniert gut:

gci C:\Projects *.config -recurse | ForEach { 
    (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ 
} 
  • Change "alten" und "neuen", um ihre entsprechenden Werte (oder Verwenden Sie Variablen).
  • Vergessen Sie nicht die Klammern - ohne die Sie einen Zugriffsfehler erhalten.
4

Dieses Power Beispiel für alle Instanzen der Zeichenfolge sieht „\ foo \“ in einem Ordner und dessen Unterordner, ersetzt „\ foo \“ mit „\ bar \“ und Dateien NICHT REWRITE, die keine die Zeichenfolge „\ foo \“ auf diese Weise können Sie die Datei nicht Datetime-briefmarken in der die Zeichenkette letzte Änderung zerstören wurde nicht gefunden:

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

ich eine kleine Hilfsfunktion geschrieben habe Text in einer Datei zu ersetzen:

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

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

Beispiel:

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

Ich fand einen Kommentar von @Artyom nützlich, aber leider hat er keine Antwort geschrieben.

Dies ist die kurze Version, meiner Meinung nach beste Version, der angenommenen Antwort;

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

Im Falle, dass irgendjemand anderes über dies läuft, wie ich es tat - wenn ich direkt aus einer Batch-Datei ausführen möchte - kann es helfen, 'foreach-object' anstelle von'% 'zu verwenden einen Befehl wie diesen ausführen. Andernfalls kann der Fehler auftreten: 'Ausdrücke sind nur als erstes Element einer Pipeline zulässig –

0

Wenn rekursive Ersatz zu tun, müssen Sie den Pfad und Dateinamen enthalten sein:

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

Diese wil in allen Dateien Ihrer Ordner alle „alten“ mit „neuen“ case-sensitive ersetzen von Ihr aktuelles Verzeichnis.