powershell non greedy replace upto the pattern - powershell

I have a file with multiple lines as shown in the example below, but I need the chars mentioned in the pattern to be present in the output, in other words non-greedy match.
I need a way to remove the first part of the line and get the line which contains with starting with '07' or '08' and everything in the line till end of line.
Example:
Input: 'SELECT TZ_OFFSET (SESSIONTIMEZONE) FROM DUAL07.16.0162 (B0375, U0847)'
output: 07.16.0162 (B0375, U0207)
Input: 'SELECT TZ_OFFSET (SESSIONTIMEZONE) FROM DUAL08.15.0162 (B03075, U07)'
output: 08.15.0162 (B08075, U07)

This should work:
$str = 'SELECT TZ_OFFSET (SESSIONTIMEZONE) FROM DUAL07.16.0162 (B0375, U0847)'
$str -replace '^.*?DUAL(.*)$','$1'

New-Variable -Name file -Value "c:\abc.txt" #This file contains the line that needs to be edited
(Get-Content -Path $file) -replace '^.*?DUAL(.*)$','$1'|set-content $file

Related

From output, include line only contain a key word and extract first field from the included lines with powershell

With PowerShell, I am trying to extract the first field from an output that contains multiple lines as below. Along with this, I wanted to exclude if the line doesn't have a key 'web:'
Getting apps in org SomeOrg / space Somespace as x-user...
name requested state processes routes
maskedappname1 started web:1/1 maskedappname1.com
maskedappname2 started web:0/1 maskedappname2.com
maskedappname3 started web:1/1 maskedappname3.com
maskedappname4 started web:1/1 maskedappname4.com
maskedappname5 started web:1/1 maskedappname5.com
maskedappname6 stopped web:0/1 maskedappname6.com
after execution, my final output should be
maskedappname1
maskedappname2
maskedappname3
maskedappname4
maskedappname5
maskedappname6
tried multiple ways didn't help me.
Much appreciate it if I get some help on this.
Thanks.
You can use a switch with the -Regex parameter to match any line having web: and capture the everything from the beginning of the line until the first whitespace.
switch -File path\to\file.ext -Regex {
'(^\S+).+web:' { $Matches[1] }
}
See https://regex101.com/r/fxQtcN/1 for details.
iterate through each line
$array = $textWithMultipleLines.Split(“`n”)
foreach ($line in $array){
# ...
}
take fixed length (if possible) or split on space ant take the first item of the split array
($extract -split " ")[0]
# or the regex way:
$extract -replace '^([^ ]+ ).+$','$1'
all together
$array = $textWithMultipleLines.Split(“`n”)
foreach ($line in $array){
$maskedAppName = ($line -split " ")[0]
Write-Host "maskedAppName: $maskedAppName"
}

Powershell replace last two occurrences of a '/' in file path with '.'

I have a filepath, and I'm trying to remove the last two occurrences of the / character into . and also completely remove the '{}' via Powershell to then turn that into a variable.
So, turn this:
xxx-xxx-xx\xxxxxxx\x\{xxxx-xxxxx-xxxx}\xxxxx\xxxxx
Into this:
xxx-xxx-xx\xxxxxxx\x\xxxx-xxxxx-xxxx.xxxxx.xxxxx
I've tried to get this working with the replace cmdlet, but this seems to focus more on replacing all occurrences or the first/last occurrence, which isn't my issue. Any guidance would be appreciated!
Edit:
So, I have an excel file and i'm creating a powershell script that uses a for each loop over every row, which amounts to thousands of entries. For each of those entries, I want to create a secondary variable that will take the full path, and save that path minus the last two slashes. Here's the portion of the script that i'm working on:
Foreach($script in $roboSource)
{
$logFileName = "$($script.a).txt".Replace('(?<=^[^\]+-[^\]+)-','.')
}
$script.a will output thousands of entries in this format:
xxx-xxx-xx\xxxxxxx\x{xxxx-xxxxx-xxxx}\xxxxx\xxxxx
Which is expected.
I want $logFileName to output this:
xxx-xxx-xx\xxxxxxx\x\xxxx-xxxxx-xxxx.xxxxx.xxxxx
I'm just starting to understand regex, and I believe the capture group between the parenthesis should be catching at least one of the '\', but testing attempts show no changes after adding the replace+regex.
Please let me know if I can provide more info.
Thanks!
You can do this in two fairly simply -replace operations:
Remove { and }
Replace the last two \:
$str = 'xxx-xxx-xx\xxxxxxx\x\{xxxx-xxxxx-xxxx}\xxxxx\xxxxx'
$str -replace '[{}]' -replace '\\([^\\]*)\\([^\\]*)$','.$1.$2'
The second pattern matches:
\\ # 1 literal '\'
( # open first capture group
[^\\]* # 0 or more non-'\' characters
) # close first capture group
\\ # 1 literal '\'
( # open second capture group
[^\\]* # 0 or more non-'\' characters
) # close second capture group
$ # end of string
Which we replace with the first and second capture group values, but with . before, instead of \: .$1.$2
If you're using PowerShell Core version 6.1 or newer, you can also take advantage of right-to-left -split:
($str -replace '[{}]' -split '\\',-3) -join '.'
-split '\\',-3 has the same effect as -split '\\',3, but splitting from the right rather than the left.
A 2-step approach is simplest in this case:
# Input string.
$str = 'xxx-xxx-xx\xxxxxxx\x\{xxxx-xxxxx-xxxx}\xxxxx\xxxxx'
# Get everything before the "{"
$prefix = $str -replace '\{.+'
# Get everything starting with the "{", remove "{ and "}",
# and replace "\" with "."
$suffix = $str.Substring($prefix.Length) -replace '[{}]' -replace '\\', '.'
# Output the combined result (or assign to $logFileName)
$prefix + $suffix
If you wanted to do it with a single -replace operation (with nesting), things get more complicated:
Note: This solution requires PowerShell Core (v6.1+)
$str -replace '(.+)\{(.+)\}(.+)',
{ $_.Groups[1].Value + $_.Groups[2].Value + ($_.Groups[3].Value -replace '\\', '.') }
Also see the elegant PS-Core-only -split based solution with a negative index (to split only a fixed number of tokens off the end) in Mathias R. Jessen's helpful answer.
try this
$str='xxx-xxx-xx\xxxxxxx\x\{xxxx-xxxxx-xxxx}\xxxxx\xxxxx'
#remove bracket and split for get array
$Array=$str -replace '[{}]' -split '\\'
#take all element except 2 last elements, and concat after last elems
"{0}.{1}.{2}" -f ($Array[0..($Array.Length -3)] -join '\'), $Array[-2], $Array[-1]

How to match 3 lines in txt file and extract string in the middle line

Using Powershell I would like to extract a value from text file that is in between two lines that match a pattern.
I'm trying to match 3 lines, 1st & 3rd will always be the same:
1st: ' 1'
2nd: trying to read... always 2-4 characters
3rd: ' 40'
There are multiple occasions where line 1&3 should match this.
I tried with bellow code.
$aa=Get-Content $filename1 -Raw
$aaa=$aa |Where-Object { ( $_ -match '(.\s1)(?:\r\n|[\r\n])*(?:\r\n|[\r\n])(\s40)') }
$aaa
I get too much output...maybe it's matching just 1st and 3rd line and many lines in between.
You can do it using Regex:
$regex = [regex] '\s+1\r?\n(?<secondline>.*)\r?\n\s+40'
$match = $regex.Match($text)
$result = while ($match.Success) {
$match.Groups['secondline'].Value
$match = $match.NextMatch()
}
$result
Where $text is the file you read with $text = Get-Content 'FILENAME' -Raw like this:
1
trying to read... always 2-4 characters
40
1
another second line
40
1
the line you are interested in
40
The result is
trying to read... always 2-4 characters
another second line
the line you are interested in
Regex is usually a poor substitute for a context-sensitive multi-line parser.
Given the document format, I'd simply write one:
$grabLine = $false
switch -File($filename1){
' 1' {
$grabLine = $true
}
' 40' {
$grabLine = $false
}
default{
if($grabLine){
$_
# break here if you only need one line
}
}
}

Remove all carriage return and line feed from file

Last week I have asked you guys to replace a string with newline character with .bat script. I have realized that my file has some carriage return and newline characters already, which I need to remove first and then do the replace.
to replace '#####' with linefeed I am using the line below.
(gc $Source) -replace "#####", "`r`n"|set-content $Destination
So I tried to implement the same logic to replace \r and \n as well, however it did not work.
(gc $Source) -replace "`n", ""|set-content $Destination
my file looks like :
abc|d ef|123#####xyz|tuv|567#####
and I need to make it look like
abc|def|123 xyz|tuv|567
like I said, replacing the row delimiter character with new line works, but I need to remove all cr and lf characters first before I do that.
For small files the script below works, but my file is >1.5GB and it throws OutofMemoryException error
param
(
[string]$Source,
[string]$Destination
)
echo $Source
echo $Destination
$Writer = New-Object IO.StreamWriter $Destination
$Writer.Write( [String]::Join("", $(Get-Content $Source)) )
$Writer.Close()
Use the below function to remove the special characters. Put all of them in $SpecChars what ever you want to remove and call the function with the Text-data as a parameter.
Function Convert-ToFriendlyName
{param ($Text)
# Unwanted characters (includes spaces and '-') converted to a regex:
#Whatever characters you want to remove, put it here with comma separation.
$SpecChars = '\', ' ','\\','-'
$remspecchars = [string]::join('|', ($SpecChars | % {[regex]::escape($_)}))
# Convert the text given to correct naming format (Uppercase)
$name = (Get-Culture).textinfo.totitlecase(“$Text”.tolower())
# Remove unwanted characters
$name = $name -replace $remspecchars, ""
$name
}
Hope it helps...!!!
This is vbscript. Windows isn't consistent. Mostly it breaks on CR and removes LF (all inbuilt programming languages). But Edit controls (ie Notepad) break on LF and ignore CR (unless preceding a LF).
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Do Until Inp.AtEndOfStream
Text = Inp.readall
Text = Replace(Text, vbcr, "")
Text = Replace(Text, vblf, "")
Text = Replace(Text, "#####", vblf)
outp.write Text
Loop
This uses redirection of StdIn and StdOut.
Filtering the output of a command
YourProgram | Cscript //nologo script.vbs > OutputFile.txt
Filtering a file
Cscript //nologo script.vbs < InputFile.txt > OutputFile.txt
See my CMD Cheat Sheet about the Windows' command line Command to run a .bat file
So this removes line ending in win.ini and prints to screen the now one line win.ini.
cscript //nologo "C:\Users\David Candy\Desktop\Replace.vbs" < C:\windows\win.ini

Edit text between two lines using powershell

I want to change this text
PortNumber=10001
;UserName=xxxxxxxxx
;Password=xxxxxxxxx
CiPdfPath=xxxxx
into this
PortNumber=10001
UserName=xxxxxxxxx
Password=xxxxxxxxx
CiPdfPath=xxxxx
I cannot simply search for ;Username=xxxx and ;Password=xxxx because they exist multiple times in the file and need to be commented on some places.
I found the next command
$file = Get-Content "Test.ini" -raw
$file -replace "(?m)^PortNumber=10001[\n\r]+;UserName=xxxx[\r\n]+;Password=xxxx","PortNumber=10001 `r`nUserName=xxxxx`r`nPassword=xxxxx"
And it worked!
But maybe it can be simplyfied
If you use the (?ms) (multiline-singleline) option and here-strings, you can do most of the work with copy/paste:
$string =
#'
PortNumber=10001
;UserName=xxxxxxxxx
;Password=xxxxxxxxx
CiPdfPath=xxxxx
'#
$regex =
#'
(?ms)PortNumber=10001
;UserName=xxxxxxxxx
;Password=xxxxxxxxx
CiPdfPath=xxxxx
'#
$replace =
#'
PortNumber=10001
UserName=xxxxxxxxx
Password=xxxxxxxxx
CiPdfPath=xxxxx
'#
$string -replace $regex,$replace
PortNumber=10001
UserName=xxxxxxxxx
Password=xxxxxxxxx
CiPdfPath=xxxxx
Why don't you search full text which you'd like to replace?
So find:
PortNumber=10001
;UserName=xxxxxxxxx
;Password=xxxxxxxxx
CiPdfPath=xxxxx
and replace with:
PortNumber=10001
UserName=xxxxxxxxx
Password=xxxxxxxxx
CiPdfPath=xxxxx
You can use regular expression to express irrelevant characters
http://www.regular-expressions.info/powershell.html
http://www.powershelladmin.com/wiki/Powershell_regular_expressions
You could use Regex.
Or even simpler, depending on your requirement;
If you know the linenumber of the lines you want to replace, you could easily do this do replace the certain lines:
Given that the file format is the text you've pasted (e.g. username on line 2 and password on line 3), read the file into a line buffer. Replace line 2 and 3 and set the content back to the file.
$lines=(Get-Content .\Test.txt)
$lines[1]= $lines[1].Replace(";","")
$lines[2]= $lines[2].Replace(";","")
$lines|Set-Content .\Test.txt
I might be misunderstading the nature of the question but are you not simply trying to remove the leading semicolons? Is it important to seach for those strings exclusivley?
$file = Get-Content "Test.ini" -raw
$file -replace "(?sm)^;"
$file -replace "(?smi)^;(?=(username|password))"
Both examples should produce the same output. The first will match all leading semicolons. The second will match leading semicolons if the are followed, using a lookahead, by either username or password.