Combine file IO for -replace and Set-Content in PowerShell - powershell

I have the following script:
$allFiles = Get-ChildItem "./" -Recurse | Where { ($_.Extension -eq ".ts")}
foreach($file in $allFiles)
{
# Find and replace the dash cased the contents of the files
(Get-Content $file.PSPath) |
Foreach-Object {$_ -replace "my-project-name", '$appNameDashCased$'} |
Set-Content $file.PSPath
# Find and replace the dash cased the contents of the files
(Get-Content $file.PSPath) |
Foreach-Object {$_ -replace "MyProjectName", '$appNameCamelCased$'} |
Set-Content $file.PSPath
# Find and replace the dash cased the contents of the files
(Get-Content $file.PSPath) |
Foreach-Object {$_ -replace "myProjectName", '$appNamePascalCased$'} |
Set-Content $file.PSPath
}
It takes a file and does some replacing, then saves the file. Then it takes the same file and does some more replacing then saves the file again. Then it does it one more time.
This works, but seems inefficient.
Is there a way to do all the replacing and then save the file once?
(If possible, I would prefer to keep the readable style of PowerShell.)

Sure, just chain your replaces inside the ForEach-Object block:
$allFiles = Get-ChildItem "./" -Recurse | Where { ($_.Extension -eq ".ts")}
foreach($file in $allFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object {
# Find and replace the dash cased the contents of the files
$_ -replace "my-project-name", '$appNameDashCased$' `
-replace "MyProjectName", '$appNameCamelCased$' `
-replace "myProjectName", '$appNamePascalCased$'
} |
Set-Content $file.PSPath
}

This can be done, and is actually far simpler than what you're doing. You can chain the -Replace command as such:
$allFiles = Get-ChildItem "./" -Recurse | Where { ($_.Extension -eq ".ts")}
foreach($file in $allFiles)
{
# Find and replace the dash cased the contents of the files
(Get-Content $file.PSPath) -replace "my-project-name", '$appNameDashCased$' -replace "StringB", '$SecondReplacement$' -replace "StringC", '$ThirdReplacement$' | Set-Content $file.PSPath
}

Related

How to replace text in multiple file in many folder using powershell

I have many folder
ex: folder1,folder2,folder3... about folder100
In those folder have many files
ex: 1.html,2.html,3.html,4.html...about 20.html
I want to replace some text in those all html file in all folder
but not all text i want to replace is same.
ex:(for 1.html, i want to replace ./1_files/style.css to style.css) and (for 2.html, i want to replace ./2_files/style.css to style.css)....
So i try something like this and it work well
Get-ChildItem "*\1.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './1_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\2.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './2_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\3.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './3_files/style.css', 'style.css' | Set-Content $_
}
Get-ChildItem "*\4.html" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './4_files/style.css', 'style.css' | Set-Content $_
}
but i have to write many of those code "\4.html" "\5.html" "*\6.html" ...
i try this but it do not work
Do {
$val++
Write-Host $val
$Fn = "$val.html"
Get-ChildItem "*\$Fn" -Recurse | ForEach-Object -Process {
(Get-Content $_) -Replace './$val_files/style.css', 'style.css' |
Set-Content $_
}
} while($val -ne 100)
Please show me correct way to do..loop replace
thanks you
Assuming all your subfolders can be found inside one source folder path, you can do below to do the replacement in all those files:
# the path where all subfolders and html files can be found
$sourcePath = 'X:\Wherever\Your\Subfolders\Are\That\Contain\The\Html\Files'
Get-ChildItem -Path $sourcePath -Filter '*.html' -Recurse -File |
# filter on html files that have a numeric basename
Where-Object {$_.BaseName -match '(\d+)'} | ForEach-Object {
# construct the string to repace and escape the regex special characters
$replace = [regex]::Escape(('./{0}_files/style.css' -f $matches[1]))
# get the content as one single multiline string so -replace works faster
(Get-Content -Path $_.FullName -Raw) -replace $replace, 'style.css' |
Set-Content -Path $_.FullName
}

Replacing text with a defined text

I have a text file which contains the following
php_configuration=up21
sql_configuration=up22
apache_configuration=up23
java_script=down
html=down
I want to replace the up21, up22 and up23 with cat, dog and elephant and keep the remaining content of the file as it is.
But when I execute the below powershell script, it will replace the strings, but wont preserve the remaining content of the text file:
$a=Get-Content -Path C:\Users\Administrator\Desktop\Pow\loc.txt |Select-String -Pattern
"php_configuration"|ForEach-Object {$_ -Replace 'up21', 'cat'}
$b=Get-Content -Path C:\Users\Administrator\Desktop\Pow\loc.txt |Select-String -Pattern
"sql_configuration"|ForEach-Object {$_ -Replace 'up22', 'dog'}
$c=Get-Content -Path C:\Users\Administrator\Desktop\Pow\loc.txt |Select-String -Pattern
"apache_configuration"|ForEach-Object {$_ -Replace 'up23', 'elephant'}
$a, $b, $c| Set-Content -Path C:\Users\Administrator\Desktop\Pow\loc.txt
You can basically do like:
(Get-Content 'C:\Users\Administrator\Desktop\Pow\loc.txt') | Foreach-Object {
$_ -replace 'up21', 'cat' `
-replace 'up22', 'dog' `
-replace 'up23', 'elephant'
} | Set-Content 'C:\Users\Administrator\Desktop\Pow\loc.txt'
Is there a need to specify "php_configuration" etc.?
EDIT: Ok, after reading #T-Me's comment below, I have changed the answer. Not the prettiest but here you go.
(Get-Content 'C:\Users\Administrator\Desktop\Pow\loc.txt') | Foreach-Object {
if($_ | Select-string -Pattern "php_configuration"){$_ -replace 'up21', 'cat'}
elseif($_ | Select-String -Pattern "sql_configuration"){$_ -replace 'up22', 'dog'}
elseif($_ | Select-String -Pattern "apache_configuration"){$_ -replace 'up23', 'elephant'}
else {$_}
} | Set-Content 'C:\Users\Administrator\Desktop\Pow\loc.txt'

Redundant code, how can I have multiple arguments per line

This script works, I want to condense it so if I add more lines to find and replace in the file I'm not being redundant.
Get-ChildItem C:\Users\JonSa\Desktop -Filter callcounts.xml | Foreach- Object{
(Get-Content $_.FullName) |
Foreach-Object {$_ -replace "#aXXXXX.ac1.vbspbx.com", ""} |
Set-Content $_.FullName
}
Get-ChildItem C:\Users\JonSa\Desktop -Filter callcounts.xml | Foreach- Object{
(Get-Content $_.FullName) |
Foreach-Object {$_ -replace "sip:", ""} |
Set-Content $_.FullName
}
I would like to accomplish this with fewer lines that leaves room for more arguments.
With only one file, don't use Get-ChildItem and a ForEach-Object
when using the -raw -parameter, you can apply the replace on the whole file
you can also append several -replace one after the other.
for the same replacement (here none) you can use an alternation | (OR)
an empty replacement can be omitted with the -replace operator (not so with the .replace() method)
$File = 'C:\Users\JonSa\Desktop\callcounts.xml'
(Get-Content $File -raw) -replace '#aXXXXX.ac1.vbspbx.com|sip:' |
Set-Content $File

Modify a line in a file located in the AppData folder of all users on a computer

I would like to modify a line in a file located in the AppData folder of all users on a computer.
The line to be changed in the prefs.js file begins with:
user_pref("mail.server.server1.directory", "C:\\Users\
I would replace the entire line:
user_pref("mail.server.server1.directory", "C:\\ Thunderbird Mail\\Local Folders")
I am doing this in each user profile.
I started a script, but it does not work:
$configFiles = Get-ChildItem C:\users\*\appdata prefs.js -rec
$ligne1 = 'user_pref("mail.server.server1.directory", "C:\\Users\'
$ligne2 = 'user_pref("mail.server.server1.directory", "C:\\Thunderbird\\Mail\\Local Folders");'
foreach ($file in $configFiles) {
(Get-Content $file.PSPath) |
ForEach-Object { $_ -replace $ligne1.+, $ligne2 } |
Set-Content $file.PSPath
}
The -replace operator does regular expression replacements, so you need to escape special characters in your match string ($ligne1), particularly the backslashes and parentheses.
Replace this:
(Get-Content $file.PSPath) |
ForEach-Object { $_ -replace $ligne1.+, $ligne2 } |
Set-Content $file.PSPath
with this:
(Get-Content $file.FullName) -replace ([regex]::Escape($ligne1) + '.+'), $ligne2 |
Set-Content $file.FullName
and the problem will disappear.

Read all files, change content, save again

I'm trying to do a replace in content of all files in a certain directory structure.
get-childItem temp\*.* -recurse |
get-content |
foreach-object {$_.replace($stringToFind1, $stringToPlace1)} |
set-content [original filename]
Can I get the filename from the original get-childItem to use it in the set-content?
Add processing for each file:
get-childItem *.* -recurse | % `
{
$filepath = $_.FullName;
(get-content $filepath) |
% { $_ -replace $stringToFind1, $stringToPlace1 } |
set-content $filepath -Force
}
Key points:
$filepath = $_.FullName; — get path to file
(get-content $filepath) — get content and close file
set-content $filepath -Force — save modified content
You can simply use $_, but you need a foreach-object around each file, too. While #akim's answer will work, the use of $filepath is unnecessary:
gci temp\*.* -recurse | foreach-object { (Get-Content $_) | ForEach-Object { $_ -replace $stringToFind1, $stringToPlace1 } | Set-Content $_ }