Replace block text in ini file - regex

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"

Related

looking for RexEx to replace a string within a string

I have to replace a string in a text file with Powershell. The text file has this content:
app.framework.locale=de_DE
app.gf.data.profile=somevalues,somevalues[,...]
app.gf.data.profile.path=C:\somepath\somesubpath
app.basket.currencies=currencies
I want to set the profile and the profile.path. So everything behind the "=" should be replaced, regardless of how long the string behind the "=" is.
I am reading the file, replacing the string, and writing back the file with these commands:
change the profile:
(Get-Content $TXT_FILE ).Replace('app.gf.data.profile=default,',"app.gf.data.profile=default,$Man") | Out-File $TXT_FILE -Encoding ASCII
change the profile path:
(Get-Content $TXT_FILE ).Replace('app.gf.data.profile.path=',"app.gf.data.profile.path=$Path") | Out-File $TXT_FILE -Encoding ASCII
As you can see, my replacement script is not correct, the rest behind the "=" will remain. I think I need a regex or some kind of wildcards to fit my needs.
You need to use
(Get-Content $TXT_FILE) `
-replace '^(app\.gf\.data\.profile=).*', "`$1,$Man" `
-replace '^(app\.gf\.data\.profile\.path=).*', "`${1}$Path" | `
Out-File $TXT_FILE -Encoding ASCII
Here, -replace is used to enable regex replacing, and both regular expressions follow a similar logic:
^ - matches start of a line
(app\.gf\.data\.profile=) - captures a literal string (literal dots in regex must be escaped) into Group 1 ($1 or ${1})
.* - matches the rest of the line.
${1} is used in the second case as the variable $Path follows the backreference immediately, and if it starts with a digit, the replacement will not be as expected.

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]

Powershell: append text after string in file

Problem: I am trying to append a string after a tag. I got a large text file, and I only need to append some text after the tag (including the text xxxxxx) <xxxxxx>, and I cannot seem to figure it out just yet.
Currently im trying this with regex: <[(xxxxxx)]+>, which according to regex101.com does match the exact tag <xxxxxx>, but when I use this in Powershell it returns a lot of other stuff.
How can I make sure that Powershell only matches <xxxxxx> ? And to append some string after <xxxxxx> ?
Sample snippet from the text file: PredefinedSettings=<xxxxxx><abc test123 /abc></xxxxxx>
Sample PS command: Get-Content .\samplefile.ini | Select-String -Pattern "<[(xxxxxx)]+>"
Which returns the entire line PredefinedSettings=<xxxxxx><abc test123 /abc></xxxxx> instead of just <xxxxxx>
If you want to output just the matched text, you can do the following:
Select-String -Path sample.ini -Pattern '<(/?xxxxxx)>' -AllMatches | Foreach-Object {
$_.Matches.Groups[1].Value # Outputs matched text between `<>`
$_.Matches.Value # Outputs all matched text
}
The -AllMatches switch will allow matching beyond the first match. So it would return <xxxxxx> and </xxxxxx>.
If you want to replace text in a file, you can do the following:
(Get-Content .\samplefile.ini) -replace '<(/?xxxxxx)>','<$1Text>' |
Set-Content .\sampplefile.ini
If your replacement text is in a variable, you will need to escape the $ for the capture group.
$Text = 'replacement Text'
(Get-Content .\samplefile.ini) -replace '<(/?xxxxxx)>',"<`$1$Text>" |
Set-Content .\sampplefile.ini
$1 is the capture group 1 data matched within the first (). Depending on your Text, it may be wise to name your capture group. If Text is 23OtherText, <$123OtherText> will attempt to substitute capture group 123. Using a named capture group, you can do the following:
(Get-Content .\samplefile.ini) -replace '<(?<Tag>/?xxxxxx)>','<${Tag}Text>' |
Set-Content .\sampplefile.ini
/? matches zero or more / characters.
-replace will return all text not matched and all text replaced by the operator.
I hope I got your question right.
In regex Quantifiers are greedy so it will select from the first open tag to the last closing tag, you can change that by using a ?.
So your Regex will be <[(xxxxxx)]+?>.

Using Regex to replace multiple lines of text in file

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('$', '$$')

Powershell regex match sequence doesn't work although it matches in Sublime Text find and replace

I am trying to create a Powershell regex statement to remove the top five lines of this output from a git diff file that has already been modified with Powershell regex.
[1mdiff --git a/uk1.adoc b/uk2.adoc</span>+++
[1mindex b5d3bf7..90299b8 100644</span>+++
[1m--- a/uk1.adoc</span>+++
[1m+++ b/uk2.adoc</span>+++
[36m## -1,9 +1,9 ##</span>+++
= Heading
Body text
Image shown because binary code doesn't show in the text
The following statement matches the text so the '= Heading' line is placed at the top of the page if I replace with nothing.
^[^=]*.[+][\n]
But in Powershell, it isn't matching the text.
Get-Content "result2.adoc" | % { $_ -Replace '^[^=]*.[+][\n]', '' } | Out-File "result3.adoc";
Any ideas about why it doesn't work in Powershell?
My overall goal is to create a diff file of two versions of an AsciiDoc file and then replace the ASCII codes with HTML/CSS code to display the resulting AsciiDoc file with green/red track changes.
The simplest - and faster - approach is to read the input file as a single, multiline string with Get-Content -Raw and let the regex passed to -replace operate across multiple lines:
(Get-Content -Raw result2.adoc) -replace '(?s)^.+?\n(?==)' |
Set-Content result3.adoc
(?s) activates in-line option s which makes . match newline (\n) characters too.
^.+?\n(?==) matches from the start of the string (^) any number of characters (including newlines) (.+), non-greedily (?)
until a newline (\n) followed by a = is found.
(?=...) is a look-ahead assertion, which matches = without consuming it, i.e., without considering it part of the substring that matched.
Since no replacement operand is passed to -replace, the entire match is replace with the implied empty string, i.e., what was matched is effectively removed.
As for what you tried:
The -replace operator passes its LHS through if no match is found, so you cannot use it to filter out non-matching lines.
Even if you match an undesired line in full and replace it with '' (the empty string), it will show up as an empty line in the output when sent to Set-Content or Out-File (>).
As for your specific regex, ^[^=]*.[+][\n] (whether or not the first ^ is followed by an ESC (0x1b) char.):
[\n] (just \n would suffice) tries to match a newline char. after a literal + ([+]), yet lines read individually with Get-Content (without -Raw) by definition are stripped of their trailing newline, so the \n will never match; instead, use $ to match the end of a line.
Instead of % (the built-in alias for the ForEach-Object cmdlet) you could have used ? (the built-in alias for the Where-Object cmdlet) to perform the desired filtering:
Get-Content result2.adoc | ? { $_ -notmatch '^\e\[' }
$_ -notmatch '^\e[' returns $True only for lines that don't start (^) with an ESC character (\e, whose code point is 0x1b) followed by a literal (\) [, thereby effectively filtering out the lines before the = Heading line.
However, the multi-line -replace command at the top is a more direct and faster expression of your intent.
Here is the code I ended up with after help from #mklement0. This Powershell script creates MS Word-style track changes for two versions of an AsciiDoc file. It creates the Diff file, uses regex to replace ASCII codes with HTML/CSS tags, removes the Diff header (thank you!), uses AsciiDoctor to create an HTML file and then PrinceXML to create a PDF file of the output that I can send to document reviewers.
git diff --color-words file1.adoc file2.adoc > result.adoc;
Get-Content "result.adoc" | % {
$_ -Replace '(=+ ?)([A-Za-z\s]+)(\[m)', '$1$2' `
-Replace '\[32m', '+++<span style="color: #00cd00;">' `
-Replace '\[31m', '+++<span style="color: #cd0000; text-decoration: line-through;">' `
-Replace '\[m', '</span>+++' } | Out-File -encoding utf8 "result2.adoc" ;
(Get-Content -Raw result2.adoc) -replace '(?s)^.+?\n(?==)', '' | Out-File -encoding utf8 "result3.adoc" ;
asciidoctor result3.adoc -o result3.html;
prince result3.html --javascript -o result3.pdf;
Read-Host -Prompt "Press Enter to exit"
Here's a screenshot of the result using some text from Wikipedia: