There seems to be questions that are similar floating around on the web although the answers vary and i just cannot get the outcome i am looking for.
Below simply appends the content within the txt file at the end of the file
Add-Content -Path "HeartBeat.txt" -Value (Get-Content "insertme.txt")
although i want to using powershell to find a string in a text file and then copy the contents from another text file after this found string.
Factitious example of a text file searching for string "HeartBeat"
<xml>
<Server>
<HeartBeat>1</HeartBeat>
</Server>
There is another text file called "insertme.txt" that will insert its contents on a new line after "HeartBeat"
<dummydata>
<port></port>
<ipaddress></ipaddress>
Once appended will be
<xml>
<Server>
<HeartBeat>1</HeartBeat>
<dummydata>
<port></port>
<ipaddress></ipaddress>
</Server>
Any help would be appreciated.
Thank you
If you want a truly robust solution, use XML processing, which PowerShell supports via the [xml]
(System.Xml.XmlDocument
) .NET type.
If you still want a purely text-based solution, try the following (PSv3+; reads both files into memory in full; I'm using a LF-only newline ("`n"
) in the code; replace it with "`r`n"
if you want CRLF newlines):
(Get-Content -Raw Heartbeat.txt) -replace
'(?m)^.*<HeartBeat>.*$',
('$&' + "`n" + (Get-Content -Raw InsertMe.txt).TrimEnd() -replace '(?m)^', ' '))|
Set-Content HeartBeat.txt # PSv5+: Add -NoNewline to avoid extra newline
Note: The only reason that it is possible to both read from Heartbeat.txt
and write back to it in a single pipeline is that its content is read into memory up-front, in full, due to the (...)
around the Get-Content
command.
While this approach is convenient, it also bears a slight risk of data loss, which can occur if the pipeline is interrupted before all content has been written back to the file.
Get-Content -Raw
reads a file into memory in full, as a single string.
Regex '(?m)^.*<HeartBeat>.*$'
matches a single line that contains substring <HeartBeat>
(note that the -replace
operator generally looks for multiple matches)
Replacement expression '$&' + "`n" + (Get-Content -Raw InsertMe.txt).TrimEnd()
replaces the matched line with itself ($&
), followed by a newline and the content of file InsertMe.txt
.
.TrimEnd()
is used to remove trailing newlines (and whitespace in general) so that insertion does not vary based on whether the file happens to end in a newline or not.If you want to avoid an extra newline at the end of the updated file,
use Set-Content -NoNewline
, but note that this requires PSv5+.
In earlier versions you could apply .TrimEnd()
to the entire expression before sending it to Set-Content
.
If you want to modify the insertion to apply a fixed indentation to each line of the inserted content:
(Get-Content -Raw Heartbeat.txt) -replace
'(?m)^.*<HeartBeat>.*$',
('$&' + "`n" + (Get-Content -Raw InsertMe.txt).TrimEnd() -replace '(?m)^', ' '))|
Set-Content HeartBeat.txt # PSv5+: Add -NoNewline to avoid extra newline