Dynamically replacing file content - powershell

I have to read one properties file (let's say prop.txt) and update it dynamically.
Content looks like this.
server.names=xyz[500],server2[500],test[500]
I wanted to replace the content anything after server.names= with correct values, e.g.:
server1.company.com[500],server2.company.com[500],server3.company.com[500]
I tried below command but it is replacing server.names=. I want to replace the values of server.names=
(Get-Content $path).Replace("server.names=",$NewServerNames) | Set-Content $path
Any idea how to replace the value of server.names=?

You were close, but your syntax is off. This solution utilizes regex to capture the original key:
$Pattern = 'server\.names='
Get-Content -Path $Path |
ForEach-Object {
If ($_ -match $Pattern)
{
$_ -replace "($Pattern).*","$1$NewServerNames"
}
Else
{
$_
}
} |
Set-Content -Path $Path

Related

delete everything after keyword

I try to merge to files with Compare-Object and I got a file like this:
Number=5
Example=4
Track=1000
Date=07/08/2018 19:51:16
MatCaissierePDAAssoc=
NomImpPDAAssoc=
TpeForceLectPan=0
Number=1
Example=1
Track=0
Date=01/01/1999
You can see it repeats with Number=1. Except with a different value.
I would like to delete everything (everything means not only "= 1") after my keyword "Number" and my keyword itself.
This is what I did so far:
$files = Get-ChildItem "D:\all"
foreach ($file in $files) {
$name = dir $file.FullName | select -ExpandProperty Name
Compare-Object -ReferenceObject (Get-Content D:\original\test.ini) -DifferenceObject (Get-Content $file.FullName) -PassThru |
Out-File ('D:\output\' + $name)
}
And I would like to delete all lines with "Track" and "Date".
My Result should look like this:
Number=5
Example=4
MatCaissierePDAAssoc=
NomImpPDAAssoc=
TpeForceLectPan=0
In fact I need something to delete double keys in my file.
This might help:
# read existing file
$fileContent = Get-Content C:\tmp\so01.txt
# iterate over lines
foreach($line in $fileContent) {
# filter lines beginning with 'Track' or 'Number'
if((-not $line.StartsWith('Track')) -and (-not $line.StartsWith('Number'))) {
# output lines to new file
$line | Add-Content C:\tmp\so02.txt
}
}
Content of C:\tmp\so02.txt:
Example=4
Date=07/08/2018 19:51:16
MatCaissierePDAAssoc=
NomImpPDAAssoc=
TpeForceLectPan=0
Example=1
Date=01/01/1999

How to make changes to file content and save it to another file using powershell?

I want to do this
read the file
go through each line
if the line matches the pattern, do some changes with that line
save the content to another file
For now I use this script:
$file = [System.IO.File]::ReadLines("C:\path\to\some\file1.txt")
$output = "C:\path\to\some\file2.txt"
ForEach ($line in $file) {
if($line -match 'some_regex_expression') {
$line = $line.replace("some","great")
}
Out-File -append -filepath $output -inputobject $line
}
As you can see, here I write line by line. Is it possible to write the whole file at once ?
Good example is provided here :
(Get-Content c:\temp\test.txt) -replace '\[MYID\]', 'MyValue' | Set-Content c:\temp\test.txt
But my problem is that I have additional IF statement...
So, what could I do to improve my script ?
You could do it like that:
Get-Content -Path "C:\path\to\some\file1.txt" | foreach {
if($_ -match 'some_regex_expression') {
$_.replace("some","great")
}
else {
$_
}
} | Out-File -filepath "C:\path\to\some\file2.txt"
Get-Content reads a file line by line (array of strings) by default so you can just pipe it into a foreach loop, process each line within the loop and pipe the whole output into your file2.txt.
In this case Arrays or Array List(lists are better for large arrays) would be the most elegant solution. Simply add strings in array until ForEach loop ends. After that just flush array to a file.
This is Array List example
$file = [System.IO.File]::ReadLines("C:\path\to\some\file1.txt")
$output = "C:\path\to\some\file2.txt"
$outputData = New-Object System.Collections.ArrayList
ForEach ($line in $file) {
if($line -match 'some_regex_expression') {
$line = $line.replace("some","great")
}
$outputData.Add($line)
}
$outputData |Out-File $output
I think the if statement can be avoided in a lot of cases by using regular expression groups (e.g. (.*) and placeholders (e.g. $1, $2 etc.).
As in your example:
(Get-Content .\File1.txt) -Replace 'some(_regex_expression)', 'great$1' | Set-Content .\File2.txt
And for the good example" where [MYID\] might be somewhere inline:
(Get-Content c:\temp\test.txt) -Replace '^(.*)\[MYID\](.*)$', '$1MyValue$2' | Set-Content c:\temp\test.txt
(see also How to replace first and last part of each line with powershell)

Replacing text only in lines that match a criteria, using the pipeline

My goal is to replace specific texts in specific lines in a text file, and I want to do that using the pipeline.
At first, I tried to write the code for the text replacement, without the condition that set the replacement to happen only in specific lines:
$fileName = Read-Host "Enter the full path of the file, without quotes"
(Get-Content -Path $fileName -Encoding UTF8) |
ForEach-Object { $_ -replace "01", "January " } |
Set-Content -Path $fileName -Encoding UTF8
It seems that it works. But then, I inserted an IF statement to the pipeline:
$fileName = Read-Host "Enter the full path of the file, without quotes"
(Get-Content -Path $fileName -Encoding UTF8) |
ForEach-Object { if ($_ -match "Month") {$_ -replace "03", "March"} } |
Set-Content -Path $fileName -Encoding UTF8
When I ran the last script, at the end of the process I got a file that includes only the lines that matched the if Statement. If I'm understanding correctly what happened, it seems that only the lines that match the if statement are passed to the next stage in the pipeline. So I understand why the output of the process, but I still can't figure how to solve this - How to pass all the lines in the files through all the stages of the pipeline, but to still make the text replacements to happen only in specific lines that match a specific criteria.
Could you please assist me with this issue?
Please notice that I would like not to use a temporary file for this and also remember that I prefer an elegant way of doing this, using the pipeline.
You have to add else statement like:
(Get-Content -Path $fileName -Encoding UTF8) |
Foreach-Object { If ($_ - match "Month") { $_ -replace "03", "March"} else { $_ } } |
Set-Content -Path $fileName - Encoding UTF8
Without else you didn't put line in pipeline. So your if was like filter
Depending on what your input data looks like you may not need a nested conditional (or a ForEach-Object) at all. If your input looks for instance like this:
Month: 03
you can do the replacement like this:
(Get-Content -Path $fileName -Encoding UTF8) -replace '^(.*Month.*)03','$1March' |
Set-Content -Path $fileName -Encoding UTF8
That will modify just the lines matching the pattern (^(.*Month.*)03) and leave everything else unchanged.

Powershell - reading ahead and While

I have a text file in the following format:
.....
ENTRY,PartNumber1,,,
FIELD,IntCode,123456
...
FIELD,MFRPartNumber,ABC123,,,
...
FIELD,XPARTNUMBER,ABC123
...
FIELD,InternalPartNumber,3214567
...
ENTRY,PartNumber2,,,
...
...
the ... indicates there is other data between these fields. The ONLY thing I can be certain of is that the field starting with ENTRY is a new set of records. The rows starting with FIELD can be in any order, and not all of them may be present in each group of data.
I need to read in a chunk of data
Search for any field matching the
string ABC123
If ABC123 found, search for the existence of the
InternalPartNumber field & return that row of data.
I have not seen a way to use Get-Content that can read in a variable number of rows as a set & be able to search it.
Here is the code I currently have, which will read a file, searching for a string & replacing it with another. I hope this can be modified to be used in this case.
$ftype = "*.txt"
$fnames = gci -Path $filefolder1 -Filter $ftype -Recurse|% {$_.FullName}
$mfgPartlist = Import-Csv -Path "C:\test\mfrPartList.csv"
foreach ($file in $fnames) {
$contents = Get-Content -Path $file
foreach ($partnbr in $mfgPartlist) {
$oldString = $mfgPartlist.OldValue
$newString = $mfgPartlist.NewValue
if (Select-String -Path $file -SimpleMatch $oldString -Debug -Quiet) {
$stringData = $contents -imatch $oldString
$stringData = $stringData -replace "[\n\r]","|"
foreach ($dataline in $stringData) {
$file +"|"+$stringData+"|"+$oldString+"|"+$newString|Out-File "C:\test\Datachanges.txt" -Width 2000 -Append
}
$contents = $contents -replace $oldString $newString
Set-Content -Path $file -Value $contents
}
}
}
Is there a way to read & search a text file in "chunks" using Powershell? Or to do a Read-ahead & determine what to search?
Assuming your fine isn't too big to read into memory all at once:
$Text = Get-Content testfile.txt -Raw
($Text -split '(?ms)^(?=ENTRY)') |
foreach {
if ($_ -match '(?ms)^FIELD\S+ABC123')
{$_ -replace '(?ms).+(^Field\S+InternalPartNumber.+?$).+','$1'}
}
FIELD,InternalPartNumber,3214567
That reads the entire file in as a single multiline string, and then splits it at the beginning of any line that starts with 'ENTRY'. Then it tests each segment for a FIELD line that contains 'ABC123', and if it does, removes everything except the FIELD line for the InternalPartNumber.
This is not my best work as I have just got back from vacation. You could use a while loop reading the text and set an entry flag to gobble up the text in chunks. However if your files are not too big then you could just read up the text file at once and use regex to split up the chunks and then process accordingly.
$pattern = "ABC123"
$matchedRowToReturn = "InternalPartNumber"
$fileData = Get-Content "d:\temp\test.txt" | Where-Object{$_ -match '^(entry|field)'} | Out-String
$parts = $fileData | Select-String '(?smi)(^Entry).*?(?=^Entry|\Z)' -AllMatches | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value
$parts | Where-Object{$_ -match $pattern} | Select-String "$matchedRowToReturn.*$" | Select-Object -ExpandProperty Matches | Select-Object -ExpandProperty Value
What this will do is read in the text file, drop any lines that are not entry or field related, as one long string and split it up into chunks that start with lines that begin with the work "Entry".
Then we drop those "parts" that do not contain the $pattern. Of the remaining that match extract the InternalPartNumber line and present.

How do I add a simple search and replace to this loop in Powershell?

I wrote this so far, it runs through and does exactly what I want, now I'm stuck. I can't seem to get it to open the newly created $NOSPACE.shtml and replace a word with the variable $SPACE though. A little help please?
$CITYLIST=import-csv CityList.txt
$CITYLIST | FOREACH-OBJECT { $_ }
FOREACH ($Item in $CITYLIST) {
$Item.City
$NOSPACE=$Item.City.replace(" ","_")
$SPACE=$Item.City
Add-Content _citylist.shtml "`n<a class=`"cityareaslist`" href=`"`/$NOSPACE.shtml`"> $SPACE<`/a>" ; Copy-Item index.shtml "$NOSPACE.shtml"
}
(Get-Content "$NOSPACE.shtml") |
Foreach-Object {$_ -replace 'word',$SPACE} |
Set-Content "$NOSPACE.shtml"