J'ai plusieurs fichiers de configuration sur Windows Server 2008 imbriqués comme ceux-ci:
C:\Projects\Project_1\project1.config
C:\Projects\Project_2\project2.config
Dans ma configuration, je dois remplacer une chaîne par une telle chaîne:
<add key="Environment" value="Dev"/>
va devenir:
<add key="Environment" value="Demo"/>
J'ai envisagé d'utiliser un script de traitement par lots, mais il n'y avait pas de bonne façon 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 un moyen de parcourir tous les dossiers de mon répertoire C:\Projects et de rechercher tous les fichiers se terminant par l'extension '.config'. Quand il en trouve un, je veux qu'il remplace mes valeurs de chaîne.
Des ressources utiles pour savoir comment procéder ou des gourous de PowerShell pouvant vous aider?
Voici un premier essai 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
}
PowerShell est un bon choix;) Il est très facile d’énumérer, de lire et de traiter les fichiers d’un répertoire donné.
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 en plusieurs lignes pour qu'il soit lisible. Notez que vous pouvez utiliser Set-Content au lieu de [IO.File]::WriteAllText
, mais ajoute une nouvelle ligne à la fin. Avec WriteAllText
, vous pouvez l'éviter.
Sinon, le code pourrait ressembler à ceci: $c | Set-Content $_.FullName
.
Cette approche fonctionne bien:
gci C:\Projects *.config -recurse | ForEach {
(Get-Content $_ | ForEach {$_ -replace "old", "new"}) | Set-Content $_
}
J'irais avec 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)
}
Cet exemple de PowerShell recherche toutes les occurrences de la chaîne "\ foo \" dans un dossier et ses sous-dossiers, remplace "\ foo \" par "\ bar \" ET NE RÉENROULE PAS les fichiers qui ne contiennent pas la chaîne "\ foo\"De cette façon, vous ne détruisez pas le fichier de la dernière mise à jour des horodatages 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 $_ }
}
J'ai trouvé le commentaire de @ Artyom utile mais malheureusement il n'a pas posté de réponse.
Ceci est la version courte, à mon avis la meilleure version, de la réponse acceptée;
ls *.config -rec | %{$f=$_; (gc $f.PSPath) | %{$_ -replace "Dev", "Demo"} | sc $f.PSPath}
J'ai écrit une petite fonction d'assistance pour remplacer du 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'
}
Lors du 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 tous les "anciens" par les "nouveaux" en respectant la casse dans tous les fichiers de vos dossiers de votre répertoire actuel.