Script PowerShell pour trouver et remplacer tous les fichiers avec une Extension spécifique

j'ai plusieurs fichiers de configuration sur Windows Server 2008 imbriqués comme ceci:

C:ProjectsProject_1project1.config

C:ProjectsProject_2project2.config

dans ma configuration je dois faire une chaîne de caractères remplacer comme ceci:

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

deviendra:

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

j'ai pensé à utiliser des scripts par lots, mais il n'y avait pas de bonne façon de le faire, et j'ai entendu dire qu'avec PowerShell scripting vous pouvez facilement exécuter ceci. J'ai trouvé des exemples de rechercher/remplacer, mais j'espérais pour une façon qui traverserait tous les dossiers à l'intérieur de mon C:Projects répertoire et trouver tous les fichiers qui se terminent par le '.config ' extension. Quand il en trouve un, je veux remplacer ma chaîne de valeurs.

de bonnes ressources pour savoir comment faire ceci ou n'importe quel gurus PowerShell qui peut offrir une certaine perspicacité?

96
demandé sur Brandon 2010-05-15 01:36:12

8 réponses

Voici une première tentative au-dessus de ma tête.

$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
    (Get-Content $file.PSPath) |
    Foreach-Object { $_ -replace "Dev", "Demo" } |
    Set-Content $file.PSPath
}
143
répondu Robben_Ford_Fan_boy 2015-10-02 08:56:55

PowerShell est un bon choix ;) il est très facile d'énumérer des fichiers dans un répertoire donné, de les lire et de les traiter.

le script pourrait ressembler à ceci:

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

je divise le code à plus de lignes pour être lisible pour vous. Notez que vous pouvez utiliser Set-Content au lieu de [IO.File]::WriteAllText , mais il ajoute une nouvelle ligne à la fin. Avec WriteAllText vous pouvez l'éviter.

sinon le code pourrait ressembler à ceci: $c | Set-Content $_.FullName .

25
répondu stej 2010-05-14 21:57:00

Cette approche fonctionne bien:

gci C:\Projects *.config -recurse | ForEach {
  (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ 
}
  • changer" ancien "et" nouveau " à leurs valeurs correspondantes (ou utiliser des variables).
  • N'oubliez pas la parenthèse -- sans laquelle vous recevrez une erreur d'accès.
13
répondu Tolga 2015-07-28 21:04:15

j'utiliserais xml et 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)  
}
8
répondu Shay Levy 2011-09-26 02:47:37

cet exemple powershell recherche toutes les instances de la chaîne "\foo\ "dans un dossier et ses sous-dossiers, remplace" \foo\ "par" \bar\ "et ne réécrit pas les fichiers qui ne contiennent pas la chaîne" \foo\ "de cette façon, vous ne détruisez pas le fichier date de dernière mise à jour timbres où la chaîne n'a pas été trouvée:

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 $_ }
           }
4
répondu Kaye 2015-07-08 14:53:37

j'ai trouvé le commentaire de @Artyom utile, mais malheureusement il n'a pas posté de réponse.

C'est la version courte, à mon avis la meilleure version, de la accepté de répondre;

ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}
4
répondu Masoud 2018-01-28 09:33:10

j'ai écrit une petite fonction d'aide pour remplacer le texte dans un fichier:

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

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

exemple:

Get-ChildItem . *.config -rec | ForEach-Object { 
    Replace-TextInFile -FilePath $_ -Pattern 'old' -Replacement 'new' 
}
3
répondu Martin Brandl 2016-05-26 18:29:51

lors d'un remplacement récursif, le chemin et le nom du fichier doivent être inclus:

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

ceci remplacera tout" ancien "par" nouveau " sensible à la casse dans tous les fichiers de vos dossiers de votre répertoire courant.

1
répondu Geir Ivar Jerstad 2017-07-25 11:25:37