Using Regex to replace multiple lines of text in file - regex

Basically, I have a .bas file that I am looking to update. Basically the script requires some manual configuration and I don't want my team to need to reconfigure the script every time they run it. What I would like to do is have a tag like this
<BEGINREPLACEMENT>
'MsgBox ("Loaded")
ReDim Preserve STIGArray(i - 1)
ReDim Preserve SVID(i - 1)
STIGArray = RemoveDupes(STIGArray)
SVID = RemoveDupes(SVID)
<ENDREPLACEMENT>
I am kind of familiar with powershell so what I was trying to do is to do is create an update file and to replace what is in between the tags with the update. What I was trying to do is:
$temp = Get-Content C:\Temp\file.bas
$update = Get-Content C:\Temp\update
$regex = "<BEGINREPLACEMENT>(.*?)<ENDREPLACEMENT>"
$temp -replace $regex, $update
$temp | Out-File C:\Temp\file.bas
The issue is that it isn't replacing the block of text. I can get it to replace either or but I can't get it to pull in everything in between.
Does anyone have any thoughts as to how I can do this?

You need to make sure you read the whole files in with newlines, which is possible with the -Raw option passed to Get-Content.
Then, . does not match a newline char by default, hence you need to use a (?s) inline DOTALL (or "singleline") option.
Also, if your dynamic content contains something like $2 you may get an exception since this is a backreference to Group 2 that is missing from your pattern. You need to process the replacement string by doubling each $ in it.
$temp = Get-Content C:\Temp\file.bas -Raw
$update = Get-Content C:\Temp\update -Raw
$regex = "(?s)<BEGINREPLACEMENT>.*?<ENDREPLACEMENT>"
$temp -replace $regex, $update.Replace('$', '$$')

Related

Reg ex involving new line for Powershell script

I have a long text file that looks like this:
("B3501870","U00357"),
INSERT INTO [dbo].[Bnumbers] VALUES
("B3501871","U11019"),
("B3501899","U28503"),
I want every line before INSERT to end not with , but with ; instead.
So the end result should look like this:
("B3613522","U00357");
INSERT INTO [dbo].[Bnumbers] VALUES
("B3615871","U11019"),
("B3621899","U28503"),
I tried multiple ways to achieve this but it does not appear to work with multiple lines.
One way I tried was like this:
(Get-Content -path C:\temp\bnr\list.sql -Raw) -replace ",\nINSERT", ";\nINSERT" | Add-Content -Path C:\temp\bnr\test.sql
Tried with
[io.file]::ReadAllText("C:\temp\bnr\list.sql")
hoping it treat the file as one giant string but to no avail.
Any way to tell PS to find comma+newline+INSERT and do changes to it?
,\nINSERT
works on Sublime text with reg ex but not in PS.
You can use
(Get-Content -path C:\temp\bnr\list.sql -Raw) -replace ',(\r?\nINSERT)', ';$1'
Or,
(Get-Content -path C:\temp\bnr\list.sql -Raw) -replace ',(?=\r?\nINSERT)', ';'
See the regex demo.
The ,(?=\r?\nINSERT) regex matches a comma that is immediately followed with an optional CR char, then LF char, then INSERT text. The ,(\r?\nINSERT) variation captures the CRLF/LF ending + INSERT string into Group 1, hence the $1 backreference in the replacement pattern that puts this text back into the result.

Get the next string after validating patterns using powershell

I have a text file and the contents can be:
debug --configuration "Release" \p corebuild
Or:
-c "Dev" debug
And now I have to validate the file to see if it has any pattern that matches --configuration or -c and print the string next to it
Pattern 1 - It should be Release
Pattern 2 - It should be Dev
How to achieve this in single command?
I tried below , but not sure how to extract only the release in the text , I only tried to see 1 pattern at a time
PS Z:\> $text = Get-Content 'your_file_path' -raw
PS Z:\> $Regex = [Regex]::new("(?<=\-\-configuration)(.*)")
PS Z:\> $Match = $Regex.Match($text)
PS Z:\> $Match.Value
**Release /p net**
Any help would be appreciated
If I understand correctly and you only care about extracting the argument to the parameters and not which parameter was used, this might do the trick:
$content = Get-Content 'your_file_path' -Raw
$re = [regex] '(?i)(?<=(?:--configuration|-c)\s")[^"]+'
$re.Matches($content).Value
See https://regex101.com/r/d2th35/3 for details.
From feedback in comments --configuration and -c can appear together, hence Regex.Matches is needed to find all occurrences.
To complement Santiago's helpful answer with a PowerShell-only alternative:
Assuming that a matching line only ever contains --configuration OR -c, you can avoid the need for .NET API calls with the help of the -match operator, which outputs a Boolean ($true or $false) to indicate whether the input string matches, and also reports the match it captures in the automatic $Matches variable:
# Note: Omitting -Raw makes Get-Content read the file *line by line*.
Get-Content 'your_file_path' |
ForEach-Object { # Look for a match on each line
# Look for the pattern of interest and capture the
# substring of interest in a capture group - (...) -
# which is later reflected in $Matches by its positional index, 1.
if ($_ -match '(?:--configuration|-c) "(.*?)"') { $Matches[1] }
}
Note:
-match only every looks for one match per input string, and only populates $Matches if the input is a single string (if it is an array of strings, -match acts as a filter and returns the subarray of matching elements).
GitHub issue #7867 proposes introducing -matchall operator that looks for all matches in the input string.
See this regex101.com page for an explanation of the regex.

Powershell script to replace link:lalala.html[lalala] with xref:lalala.adoc[lalala] capture pattern and replace recursively

I have a folder full of text documents in .adoc format that have some text in them. The text is following: link:lalala.html[lalala]. I want to replace this text with xref:lalala.adoc[lalala]. So, basically, just replace link: with xref:, .html with .adoc, leave all the rest unchanged.
But the problem is that lalala can be anything from a word to ../topics/halva.html.
I definitely know that I need to use regex patterns, I previously used similar script. A replace directive wrapped in an object:
Get-ChildItem -Path *.adoc -file -recurse | ForEach-Object {
$lines = Get-Content -Path $PSItem.FullName -Encoding UTF8 -Raw
$patterns = #{
'(\[\.dfn \.term])#(.*?)#' = '$1_$2_' ;
}
$option = [System.Text.RegularExpressions.RegexOptions]::Singleline
foreach($k in $patterns.Keys){
$pat = [regex]::new($k, $option)
$lines = $pat.Replace($lines, $patterns.$k)
}
$lines | Set-Content -Path $PSItem.FullName -Encoding UTF8 -Force
}
Looks like I need a different script since the new task cannot be added as just another object. I could've just replaced each part separately, using two objects: replace link: with xref:, then replace .html with .adoc.
But this can interfere with other links that end with .html and don't start with link:. In the text, absolute links usually don't have link: in the beginning. They always start with http:// or https://. And they still may or may not end with .html. So the best idea is to take the whole string link:lalala.html[lalala] and try to replace it with xref:lalala.adoc[lalala].
I need the help of someone who knows regex and PowerShell, please this would save me.
As a pattern, you might use
\blink:(.+?)\.html(?=\[[^][]*])
\blink: Match link:
(.+?) Capture 1+ chars as least as possbile in group 1
\.html match .html
(?=\[[^][]*]) Assert from an opening till closing square bracket at the right
Regex demo
In the replacement use group 1 using $1
xref:$1.adoc
Example
$Strings = #("link:lalala.html[lalala]", "link:../topics/halva.html[../topics/halva.html]")
$Strings -replace "\blink:(.+?)\.html(?=\[[^][]*])",'xref:$1.adoc'
Output
xref:lalala.adoc[lalala]
xref:../topics/halva.adoc[../topics/halva.html]

Replace block text in ini file

I need replace a block text inside a .ini file.
My script is:
$oFile = "$Env:ProgramFiles (x86)\Advanced Monitoring Agent\Settings.ini
$oSettings = Get-Content -Path $oFile
$oPattern = '[PATCHMANAGEMENT](.*?)[SITECONCENTRATOR]'
$oTextToReplace = [regex]::match($oSettings , $oPattern).Groups[1].Value
$oNewFile = $oSettings -replace $oTextToReplace.ToString, "][" | out-file -FilePath $Env:ProgramFiles
(x86)\Advanced Monitoring Agent\newSettings.ini
But it is not working. Can you help me with this?
Sorry for my weak English.
Greetings!
First of all, you should read the file in as a single variable:
$oSettings = Get-Content -Path $oFile -Raw
Next, use a DOTALL, or (?s) inline modifier at the pattern start, to make . match across lines. Also, escape [ that is outside a character class to make it match a literal [, else, it denotes a character class start. Then, enclose the tags you want to keep, not the text in between the tags:
$oPattern = '(?s)(\[PATCHMANAGEMENT]).*?(\[SITECONCENTRATOR])'
See the regex demo (just how it works).
The rest is a mere -replace:
$oNewFile = $oSettings -replace $oPattern, '$1$2' |
out-file -FilePath "${Env:ProgramFiles(x86)}\Advanced Monitoring Agent\newSettings.ini"

Replace text between two string powershell

I have a question which im pretty much stuck on..
I have a file called xml_data.txt and another file called entry.txt
I want to replace everything between <core:topics> and </core:topics>
I have written the below script
$test = Get-Content -Path ./xml_data.txt
$newtest = Get-Content -Path ./entry.txt
$pattern = "<core:topics>(.*?)</core:topics>"
$result0 = [regex]::match($test, $pattern).Groups[1].Value
$result1 = [regex]::match($newtest, $pattern).Groups[1].Value
$test -replace $result0, $result1
When I run the script it outputs onto the console it doesnt look like it made any change.
Can someone please help me out
Note: Typo error fixed
There are three main issues here:
You read the file line by line, but the blocks of texts are multiline strings
Your regex does not match newlines as . does not match a newline by default
Also, the literal regex pattern must when replacing with a dynamic replacement pattern, you must always dollar-escape the $ symbol. Or use simple string .Replace.
So, you need to
Read the whole file in to a single variable, $test = Get-Content -Path ./xml_data.txt -Raw
Use the $pattern = "(?s)<core:topics>(.*?)</core:topics>" regex (it can be enhanced in case it works too slow by unrolling it to <core:topics>([^<]*(?:<(?!</?core:topics>).*)*)</core:topics>)
Use $test -replace [regex]::Escape($result0), $result1.Replace('$', '$$') to "protect" $ chars in the replacement, or $test.Replace($result0, $result1).