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'
Related
I'm trying to replace ALL accented letters and some strings in multiple files located in one folder. The strings replacement is working but not the accented letters
I've multiple files located in "C:\\FilePath"
I've created a Batch file with the following code:
#echo off
Powershell.exe -executionpolicy remotesigned -File C:\Users\User\Desktop\IFCParser.ps1
pause
And IFCParser.ps1 contains all the following lines, one after the other:
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName | Select-String -Pattern 'IFCBuilding') {(Get-Content $_ | ForEach {$_ -replace 'IFCBuilding', 'IFCBuildingElementProxy'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName | Select-String -Pattern 'IFCAnotherWord') {(Get-Content $_ | ForEach {$_ -replace 'IFCAnotherWord', 'IFCBuildingElementProxy'}) | Set-Content $_ }}
The above code DOES the job when I run the bat file, but I can't get the following part to work:
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'á' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'á', 'a'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'é' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'é', 'e'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'í' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'í', 'i'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'ó' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'ó', 'o'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'ú' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'ú', 'u'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'Á' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'Á', 'A'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'É' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'É', 'E'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'Í' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'Í', 'I'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'Ó' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'Ó', 'O'}) | Set-Content $_ }}
Get-ChildItem -Path C:\FilePath\*.* -recurse | ForEach {If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'Ú' -AllMatches) {(Get-Content $_ -Encoding UTF8 | ForEach {$_ -creplace 'Ú', 'U'}) | Set-Content $_ }}
I'm testing this on a file like this:
áéíóúÁÉÍÓÚÑñáéíóúÁ
ÉÍÓÚÑñáéíóúÁÉÍÓÚÑñá
éíóúÁÉÍÓÚÑñáéíóúÁÉÍÓÚÑñáéíó
úÁÉÍÓÚÑñáéíóúÁÉÍÓÚÑñ
And it stays the same, no accents removed.
I think that I've something wrong with the encoding, I've run this with the parameter just in the first GetContent, only on the second one, and with no -Encoding at all.
By the way, I'm sure that there are more effective ways of doing this, but I'm just starting with this here and not finding one that works.
As for replacing the contents of the files in your folder, you should be able to do that using just one Get-ChildItem call.
Put this helper function on top of your script; it is used for replacing all the accented letters in the files:
function Replace-Diacritics {
Param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string] $Text
)
($Text.Normalize( [Text.NormalizationForm]::FormD ).ToCharArray() |
Where-Object {[Globalization.CharUnicodeInfo]::GetUnicodeCategory($_) -ne
[Globalization.UnicodeCategory]::NonSpacingMark }) -join ''
}
Now the rest of the code simplified:
Get-ChildItem -Path 'C:\FilePath\*.*' -File -Recurse | ForEach-Object {
$content = Get-Content -Path $_.FullName -Raw -Encoding UTF8 | Replace-Diacritics
$content -replace '\b(IFCBuilding|IFCAnotherWord)\b', 'IFCBuildingElementProxy' | Set-Content -Path $_.FullName -Encoding UTF8
}
Using your example file, the new content after calling `Replace-Diacritics``will be:
aeiouAEIOUNnaeiouA
EIOUNnaeiouAEIOUNna
eiouAEIOUNnaeiouAEIOUNnaeio
uAEIOUNnaeiouAEIOUNn
Operator -replace uses regex. The pattern '\b(IFCBuilding|IFCAnotherWord)\b' means to find he words 'IFCBuilding' OR 'IFCAnotherWord' as whole words (\b is a Word Boundary) and replace these with 'IFCBuildingElementProxy'.
If you also need this to be case-sensitive, use -creplace instead of -replace
For very large files, Get-Content may not be the cmdlet you'll want to use as it reads the file in memory as a whole.
To handle those large files using a combination of a StreamReader and a StreamWriter would be much more memory efficient (at the cost of more disk read/write actions).
Note that you cannot read a file and write to the same file simultaniously, so the code below will create a new name for the updated file by appending _New to the BaseName.
Again start with this helper function on top
function Replace-Diacritics {
Param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string] $Text
)
($Text.Normalize( [Text.NormalizationForm]::FormD ).ToCharArray() |
Where-Object {[Globalization.CharUnicodeInfo]::GetUnicodeCategory($_) -ne
[Globalization.UnicodeCategory]::NonSpacingMark }) -join ''
}
Get-ChildItem -Path 'C:\FilePath\*.*' -File -Recurse | ForEach-Object {
# create a StreamReader to read the file line-by-line
$reader = [System.IO.StreamReader]::new($_.FullName, [System.Text.Encoding]::UTF8)
# older PowerShell versions use:
# $reader = New-Object System.IO.StreamReader($_.FullName, [System.Text.Encoding]::UTF8)
# create a full path and filename for the updated output file
$outFile = Join-Path -Path $_.DirectoryName -ChildPath ('{0}_New{1}' -f $_.BaseName, $_.Extension)
# create a StreamWriter object to write the lines to the new output file
# The StreamWriter class by default writes files with UTF-8 encoding without a Byte-Order Mark (BOM)
$writer = [System.IO.StreamWriter]::new($outFile)
# loop through the lines of the file
while ($null -ne ($line = $reader.ReadLine())) {
if (![string]::IsNullOrWhiteSpace($line)) {
$line = ($line | Replace-Diacritics) -replace '\b(IFCBuilding|IFCAnotherWord)\b', 'IFCBuildingElementProxy'
}
$writer.WriteLine($line)
}
# clean up for next file
$writer.Flush()
$writer.Dispose()
$reader.Dispose()
}
Running a single line of code on a single file like this works as expected:
Get-ChildItem -Path C:\temp\testdata.txt | ForEach-Object {
If (Get-Content $_.FullName -Encoding UTF8 | Select-String 'á' -AllMatches) {
(Get-Content $_ -Encoding UTF8 | ForEach-Object { $_ -creplace 'á', 'a' }) | Set-Content $_ }
}
Given this, your code must be failing in the file recursion or in the execution process.
Run the script in an editor before trying to run as a batch and try adding error trapping. You can also add some logging to track down what's happening when running as batch:
Start-Transcript -Path 'c:\temp\outputlog.txt'
Try {
Get-ChildItem -Path C:\temp\testdata.txt -recurse -ErrorAction Stop | ForEach-Object {
Write-Host "Processing $_"
If (Get-Content $_.FullName -Encoding UTF8 -ErrorAction Stop | Select-String 'á' -AllMatches) {
Write-Host "Found match for á, replacing...."
(Get-Content $_ -Encoding UTF8 -ErrorAction Stop | ForEach-Object { $_ -creplace 'á', 'a' }) | Set-Content $_ -ErrorAction Stop }
}
}
Catch {
$_
Stop-Transcript
}
Stop-Transcript
I have code in PowerShell and I need to replace letter $ for ;$ or insert ;
CSV file:
"11/23/2018 17:10:08"$"https://www.google.com"
"11/23/2018 17:10:20"$"https://www.yahoo.com"
And I need file:
11/23/2018 17:10:08;$https://www.google.com
11/23/2018 17:10:20;$https://www.yahoo.com
PS: Is it possible to find the titles to URLs?
(Get-Content C:\Users\user\Desktop\test\import.txt) |
Foreach-Object {$_ -replace '"'} |
Foreach-Object {$_ -replace "$", ';$'} |
Set-Content C:\Users\user\Desktop\test\export.txt
The wrong result is:
11/23/2018 17:03:46$https://www.seznam.cz;$
You need to escape $ since it has a special meaning in a regular expression (end of text).
(Get-Content C:\Users\user\Desktop\test\import.txt) |
Foreach-Object {$_ -replace '"'}|
Foreach-Object {$_ -replace "\$", ';$'} |
Set-Content C:\Users\user\Desktop\test\export.txt
It's an one-liner:
$inputFile = 'C:\test.txt'
$outputFile = 'C:\test1.txt'
[System.IO.File]::ReadAllLines($inputFile) | % { $_.Replace( '"$"', ';$' ).Trim('"') } | Out-File $outputFile
You can use multiple -replace in one command as follows:
(Get-Content C:\Users\user\Desktop\test\import.txt) |
Foreach-Object {$_ -replace '"' -replace '$', ';$'}|
Set-Content C:\Users\user\Desktop\test\export.txt
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
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
}
I am trying to remove all the lines from a text file that contains a partial string using the below PowerShell code:
Get-Content C:\new\temp_*.txt | Select-String -pattern "H|159" -notmatch | Out-File C:\new\newfile.txt
The actual string is H|159|28-05-2005|508|xxx, it repeats in the file multiple times, and I am trying to match only the first part as specified above. Is that correct? Currently I am getting empty as output.
Am I missing something?
Suppose you want to write that in the same file, you can do as follows:
Set-Content -Path "C:\temp\Newtext.txt" -Value (get-content -Path "c:\Temp\Newtext.txt" | Select-String -Pattern 'H\|159' -NotMatch)
Escape the | character using a backtick
get-content c:\new\temp_*.txt | select-string -pattern 'H`|159' -notmatch | Out-File c:\new\newfile.txt
Another option for writing to the same file, building on the existing answers. Just add brackets to complete the action before the content is sent to the file.
(get-content c:\new\sameFile.txt | select-string -pattern 'H`|159' -notmatch) | Set-Content c:\new\sameFile.txt
You don't need Select-String in this case, just filter the lines out with Where-Object
Get-Content C:\new\temp_*.txt |
Where-Object { -not $_.Contains('H|159') } |
Set-Content C:\new\newfile.txt
String.Contains does a string comparison instead of a regex so you don't need to escape the pipe character, and it's also faster
The pipe character | has a special meaning in regular expressions. a|b means "match either a or b". If you want to match a literal | character, you need to escape it:
... | Select-String -Pattern 'H\|159' -NotMatch | ...
This is probably a long way around a simple problem, it does allow me to remove lines containing a number of matches. I did not have a partial match that could be used, and needed it to be done on over 1000 files.
This post did help me get to where I needed to, thank you.
$ParentPath = "C:\temp\test"
$Files = Get-ChildItem -Path $ParentPath -Recurse -Include *.txt
$Match2 = "matchtext1"
$Match2 = "matchtext2"
$Match3 = "matchtext3"
$Match4 = "matchtext4"
$Match5 = "matchtext5"
$Match6 = "matchtext6"
$Match7 = "matchtext7"
$Match8 = "matchtext8"
$Match9 = "matchtext9"
$Match10 = "matchtext10"
foreach ($File in $Files) {
$FullPath = $File | % { $_.FullName }
$OldContent = Get-Content $FullPath
$NewContent = $OldContent `
| Where-Object {$_ -notmatch $Match1} `
| Where-Object {$_ -notmatch $Match2} `
| Where-Object {$_ -notmatch $Match3} `
| Where-Object {$_ -notmatch $Match4} `
| Where-Object {$_ -notmatch $Match5} `
| Where-Object {$_ -notmatch $Match6} `
| Where-Object {$_ -notmatch $Match7} `
| Where-Object {$_ -notmatch $Match8} `
| Where-Object {$_ -notmatch $Match9} `
| Where-Object {$_ -notmatch $Match10}
Set-Content -Path $FullPath -Value $NewContent
Write-Output $File
}
If you anyone having this issue while doing what suggested by Robert Brooker-
*These files have different encodings. Left file: Unicode (UTF-8) with signature. Right file: Unicode (UTF-8) without signature. You can resolve the difference by saving the right file with the encoding Unicode (UTF-8) with signature.* with Set-Content
use -Encoding UTF8
so like this
(get-content c:\new\sameFile.txt | select-string -pattern 'H`|159' -notmatch) | Set-Content c:\new\sameFile.txt -Encoding UTF8