146 votes

PowerShell script pour rechercher et remplacer tous les fichiers avec une extension spécifique

J'ai plusieurs fichiers de configuration imbriqués de la sorte :

C:\Projects\Project_1\project1.config

C:\Projects\Project_2\project2.config

Dans ma configuration, j'ai besoin de faire un remplacement de chaîne de caractères comme ceci :

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

deviendra :

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

J'ai pensé à utiliser des scripts batch, mais il n'y avait pas de bon moyen de le faire, et j'ai entendu dire qu'avec les scripts PowerShell vous pouvez facilement le faire. J'ai trouvé des exemples de recherche/remplacement, mais j'espérais trouver une méthode permettant de parcourir tous les dossiers de ma base de données C:\Projects et trouve tous les fichiers qui se terminent par l'extension '.config'. Lorsqu'il en trouve un, je veux qu'il remplace mes valeurs de chaîne.

Y a-t-il de bonnes ressources pour trouver comment faire cela ou des gourous de PowerShell qui peuvent donner leur avis ?

1 votes

Faites-nous savoir comment vous vous en êtes sortis ou s'il y a eu des problèmes de formatage des fichiers qui ont dû être résolus. Une bonne chose à propos de ce problème est qu'il est testé sans affecter le code de production.

216voto

David Relihan Points 3719

Voici une première tentative au sommet 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
}

3 votes

Je voudrais ajouter que les solutions proposées ont toutes fonctionné, mais que celle-ci était la plus facile à lire. J'ai pu la remettre à un collègue de travail et il a pu comprendre facilement ce qui se passait. Merci pour votre aide.

0 votes

Excellent travail, Brandon. Je n'ai pas encore totalement adopté Powershell, mais quand on pense au temps que cela prendrait en VBScript !!!!.

11 votes

Pour que cela fonctionne dans les fichiers des sous-répertoires, vous avez besoin de ".PSPath". Il est intéressant de noter que lorsque j'ai essayé de faire fonctionner ce système sans () autour de get-content, il a échoué à write-content parce que le fichier était verrouillé.

36voto

stej Points 14257

PowerShell est un bon choix ;) Il est très facile d'énumérer les 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"))
    }

J'ai divisé le code en plusieurs lignes pour qu'il soit plus 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 .

19voto

Tolga Points 201

Cette approche fonctionne bien :

gci C:\Projects *.config -recurse | ForEach {
  (Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_ 
}
  • Remplacez "old" et "new" par leurs valeurs correspondantes (ou utilisez des variables).
  • N'oubliez pas les parenthèses, sans lesquelles vous recevrez une erreur d'accès.

5 votes

J'ai donc choisi celle-ci pour l'expression succincte - mais j'ai dû remplacer Get-Content $_ con Get-Content $_.FullName et l'équivalent pour Set-Content pour qu'il puisse gérer des fichiers qui n'étaient pas à la racine.

11voto

Shay Levy Points 41404

J'opterais pour 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)  
}

0voto

Avery Points 1

MERCI ! Tolga ! Presque un PowerShell one liner utilisé pour une tonne de fichiers html qui avaient besoin d'une mise à jour de la taille de l'image.

get-childItem '\\someServer\systemsDump\*.html' -recurse | ForEach { (Get-Content $_ | ForEach {$_ -replace 'width="223" height="24"', 'width="450" height="64"'}) | Set-Content $_

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X