Powershell replace adding an empty line - powershell

I have this powershell code which should replace every occurrence of a string in every file in the directory with a new string.
This works, however an empty line is added in the end.
What causes this, and how can this be nicely avoided?
$files = Get-ChildItem $currentDir *.* -recurse
foreach ($file in $files)
{
$find = "placeholder"
$replace = "newvalue"
$content = Get-Content $($file.FullName) -Raw
$content -replace $find,$replace | Out-File $($file.FullName)
}
Simply removing the last line is not a good solution since sometimes my files will contain an empty line which I want to keep.

You could use the -NoNewline parameter to prevent Out-File from appending the extra line at the end of the file.
$content -replace $find,$replace | Out-File $($file.FullName) -NoNewline
Note: this was added in PowerShell 5.0

I am limited to PS version 4, and this is what I used
$files = Get-ChildItem $currentDir . -recurse
$find = "placeholder"
$replace = ""newvalue"
foreach ($file in $files)
{
$content = Get-Content $($file.FullName) -Raw | ForEach-Object { $_ -replace $find,$replace}
$content = $content -join "`r`n"
$content | Set-Content $($file.FullName)
}
Note that this only works if it is ok to store the complete file in memory.

Related

Consolidate the contents of the files instead of editing one by one

$file = 'G\*\configs.txt'
$find = '192.168.152.161:8011'
$replace = '{appconfigs.writes}'
(Get-Content $file).replace($find, $replace) | Set-Content $file
When I run the edit script on all the files together, the script unites them and does not edit one by one.
What can I do?
You are trying to potentially process multiple files.
Therefore, you cannot use Get-Content straight away. You need to wrap this in a loop.
Here is an example on how to do this.
$find = '192.168.152.161:8011'
$replace = '{appconfigs.writes}'
foreach ($File in Get-ChildItem -Path 'G\*\configs.txt') {
$Content = Get-Content -Path $File.FullName -Raw
#IndexOf to avoid using Set-Content on files that did not change
if ($Content.IndexOf($find) -gt -1) {
$Content.replace($find, $replace) | Set-Content $file.FullName
}
}

Why this code works in PowerShell but it doesn't change nothing in the html file (with Regex)

I have file1.html with this lines:
<bogus></bogus>
<title>Something goes here</title>
<TheEnd>END</TheEnd>
I made 3 different PowerShell scripts with regex in order to change this line: <title>Something goes here</title>:
$path = 'c:\Folder1\file1.html'
$Content = Get-Content -Path $path
foreach($Line in $Content){
$Line -replace "<title>(.*?)</title>",'$1 NEW is now there!' #This regex selects everything between tags and make a replace:
}
Set-Content -Path $Path -Value $Line
AND
$Content = Get-Content -Path c:\Folder1\file1.html
foreach($Line in $Content){
$Line -replace "<title>(.*?)</title>",'$1 NEW is now there!' #This regex selects everything between tags and make a replace:
}
Set-Content -Path $Path -Value $Line
OR
$path = 'c:\Folder1\file1.html'
$Content = Get-Content -Path $path
$GetTitle = [regex]"<title>(.*?)</title>"
foreach($Line in $Content){
$Line -replace $GetTitle,'$1 NEW is now there!' #This regex selects everything between tags and make a replace:
}
Set-Content -Path $Path -Value $Line
The output should be.
<bogus></bogus>
<title>NEW is now there!</title>
<TheEnd>END</TheEnd>
Mention that all my codes are working in PowerShell, but does not make any change in File1.html. That is the problem. can anyone correct my codes?
With regex -replace, you need to think what you want to keep and capture that in backreferences.
In your case, you want to retain <title> and </title>, and replace what is in between those tags.
Change the regex to '(<title>).*?(</title>)'.
Also, you can use the -Raw switch on Get-Content to read the file as a single multilined string, do the replacement and pipe the result straight through to Set-Content
$path = 'c:\Folder1\file1.html'
(Get-Content -Path $path -Raw) -replace '(<title>).*?(</title>)', '$1NEW is now there!$2' |
Set-Content -Path $Path
Details:
'$1' + Insert the text that was last matched by capturing group number 1
' NEW is now there!' + Insert the character string “ NEW is now there!” literally
'$2' Insert the text that was last matched by capturing group number 2
$path = 'c:\Folder1\file1.html'
$Content = Get-Content -Path $path
$newContent =#()
$RegexForTitle = '(?<=title>).*(?=</title>)'
foreach($Line in $Content)
{
$newContent += $Line -replace $RegexForTitle,'NEW IS NOW HERE!'
}
Set-Content -Path $Path -Value $newContent
#optional this line
'| Out-File -path file1.html'

replacing more text strings with certain text strings in powershell

my code replace one text for another text well
$pathhh = "E:\times"
$searchWords = 'NEWYORK'
$replaceWord = 'CANCELED'
Foreach ($sw in $searchWords)
{
Get-Childitem -Path $pathhh -Recurse |
Select-String -Pattern "$sw" |
Select Path,LineNumber,#{n='SearchWord';e={$sw}}
}
if (1 -eq 1) {
$files = Get-Childitem -Path $pathhh -File -Recurse
foreach ($file in $files) {
$content = get-content -raw $file.PSPath
# regex may have problems
$content = $content -replace $searchWords,
$replaceWord
set-content $file.PSPath $content
}
}
but I need more different replacements like
replace NEWYORK with CANCELLED and replace LA with INFO and replace LONDON with DELAYED so more text replacements so like
$searchWords = 'NEWYORK,LA,LONDON'
$replaceWord = 'CANCELED,INFO,DELAYED'
but have no idea how to connect it all together thank you for your help!
Instead of using two comma delimited strings as you are trying now, I would suggest creating a replacements map (Hashtable) to store the words to replace and their replacement strings in one easy to use structure.
Something like this:
$replacements = #{
'NEWYORK' = 'CANCELLED'
'LA' = 'INFO'
'LONDON' = 'DELAYED'
}
$files = Get-Childitem -Path $pathhh -File -Recurse
foreach($file in $files) {
$content = Get-Content -Path $file.FullName -Raw
foreach ($item in $replacements.Keys) {
$content = $content.Replace($item, $replacements[$item])
}
Set-Content -Path $file.FullName -Value $content
}

Power shell code to remove special characters in the column headers(.csv file)

I'm trying to loop through 40 CSV files in a path and remove any characters that are not numeric,alphabets and space values only in the headers.
Below is my code i tried working on, This is working for headers in the files but also its replacing all the data in the file and i can see only headers without special characters in it, i'm just a beginner in power shell, not sure how to proceed further any help is much appreciated.
$path = "C:\AllFiles\"
Get-ChildItem -path $path -Filter *.csv |
Foreach-Object {
$content = Get-Content $_.FullName
$content[0] = $content[0] -replace '[^0-9a-zA-Z, ]'|Set-Content $_.FullName
}
The -replace operator requires two values, the first value is what you are looking for, and the second value is what to replace the first value with.
EXAMPLE:
"John Jones" -replace "Jones","Smith"
This will replace "Jones" with the text "Smith" creating a new string "John Smith"
In your example, instead of creating a regex of what you want to keep, create a regex of what you want to replace.
EXAMPLE:
$path = "C:\AllFiles\"
Get-ChildItem -path $path -Filter *.csv |
Foreach-Object {
$content = Get-Content -Path $path
$content[0] = $content[0] -replace '[regex for special chars]',""
Set-Content $path -value $content -force
}
This will replace the whole string, with a string where you've replaced the regex values with ""
This should do the trick and should be the fastest method:
$path = 'C:\AllFiles\'
$collection = Get-ChildItem -path $path -Filter *.csv'
foreach( $file in $collection ) {
$content = [System.IO.File]::ReadAllLines( $file.FullName )
$content[0] = $content[0] -replace '[^0-9a-zA-Z, ]'
[System.IO.File]::WriteAllLines( $file.FullName, $content ) | Out-Null
}
Pretty close, try it like this instead:
$path = "C:\temp"
Get-ChildItem -path $path -Filter *.csv |
Foreach-Object {
$content = Get-Content $_
$content[0] = $content[0] -replace '[^a-zA-Z0-9, ]',''
$content | Out-File $_
}
This will only clear special characters on the first line but leaves the rest of the file untouched.
Try this:
dir "C:\AllFiles" -Filter *.csv | % {
(Get-Content $_.FullName)[0] -replace '[\W]', '' | Set-Content $_.FullName -Force
}

Replace the text for all files in a Directory

I have written the below conditional script to go through the files in the directory and replace the one text in all files only if file contains the word as 'Health'
cd -Path "\\shlhfilprd08\Direct Credits\Temp2"
ForEach ($file in (Get-ChildItem -Path "\\shlhfilprd08\Direct Credits\Temp2"))
{
$filecontent = Get-Content -path $file -First 1
if($filecontent -like '*Health*'){$filecontent = $filecontent -replace 'TEACHERF','UniHlth '}
Set-Content $file.PSpath -Value $filecontent
}
I come across with two issues such as
If the ($filecontent -like 'Health'), it is replacing the word in first raw and deleting other rows along with replace.I do not want that to happen
I'm getting set-content to path is denied error message for file content does not contain the Health text
Can you try with this
cd -Path "\\shlhfilprd08\Direct Credits\Temp2"
$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace "TEACHERF", "UniHlth " } |
Set-Content $file.PSPath
}
I would try this; it worked for me in a little file
(make a small copy of a few data into a new folder and test it there)
$path = "\\shlhfilprd08\Direct Credits\Temp2"
$replace ="TEACHERF" #word to be replaced
$by = "UniHlth " #by this word (change $replace by $by)
gci $path -file | %{
foreach($line in $(Get-content $_.Fullname)){
if($line -like $replace){
$newline = $line.Replace($($replace),$($by))
Set-Content $_.FullName $newline
}
}
}