Select-String Regex to find string between simple quotes - regex

I get the followings lines from an invoke-webrequest :
numVersion = 'v1.1805.24',
if(numVersion!="##numVersion##" && numVersion!="v1.1805.24") {
From this extract, I only need to keep the numVersion Number between the simple quotes ==> v1.1805.24.
But I get as a result the all line:
numVersion = 'v1.1805.24',
if(numVersion!="##numVersion##" && numVersion!="v1.1805.24") {
Here is the code:
$r = Invoke-WebRequest -Uri $url -Method Get
$split_string = $r.content -split "`n"
$raw_version = $split_string | select-string -Pattern 'numVersion'
$raw_version -match '(.*?[^*])'

You may use
$r.content -match "(?<=numVersion\s*=\s*')v[0-9.]+"
See the regex demo.
Then, the value you need will be in $matches[0]. Or, you may also capture the text you need:
$r.content -match "numVersion\s*=\s*'(v[0-9.]+)"
Then, the value will be in $matches[1].
Pattern details
(?<=numVersion\s*=\s*') - a positive lookbehind that matches, but does not consume, numVersion and a = enclosed with 0+ whitespaces and then a ' char
v[0-9.]+ - v and then 1 or more digits or . chars. You may replace this pattern with a mere [^']+ here, but it is less specific to the current task.

The simplest solution would be:
$r.content -match "'([\S]+)'"
The value with the quotes will be in $matches[0] and the value without the quotes will be in $matches[1].

Related

Negative Lookbehind Works in Editor But Not in Powershell Script

Using the following. I am attempting to replace spaces with comma-space for all instances in a string. While avoiding repeating commas already present in the string.
Test string:
'186 ATKINS, Cindy Maria 25 Every Street Smalltown, Student'
Using the following code:
Get-Content -Path $filePath |
ForEach-Object {
$match = ($_ | Select-String $regexPlus).Matches.Value
$c = ($_ | Get-Content)
$c = $c -replace $match,', '
$c
}
The output is:
'186, ATKINS,, Cindy, Maria, 25, Every, Street, Smalltown,, Student'
My $regexPlus value is:
$regexPlus = '(?s)(?<!,)\s'
I have tested the negative lookbehind assertion in my editor and it works. Why does it not work in this Powershell script? The regex 101 online editor produces this curious mention of case sensitivity:
Negative Lookbehind (?<!,)
Assert that the Regex below does not match
, matches the character , with index 4410 (2C16 or 548) literally (case sensitive)
I have tried editing to:
$match = ($_ | Select-String $regexPlus -CaseSensitive).Matches.Value
But still not working. Any ideas are welcome.
Part of the problem here is that you are trying to force through the regex to do the replacement, when, like #WiktorStribiżew mentions, simply use -replace like it's supposed to be used. i.e. -replace does all the hard work for you.
When you do this:
$match = ($_ | Select-String $regexPlus).Matches.Value
You are right, you are trying to find Regex matches. Congratulations! It found a space character, but when you do this:
$c = $c -replace $match,', '
It interprets $match as a space character like this:
$c = $c -replace ' ',', '
And not as a regular expression that you might have been expecting. That's why it's not seeing the negative lookbehind for the commas, because all it is searching for are spaces, and it is dutifully replacing all the spaces with comma spaces.
The solution is simple in that, all you have to do is simply use the Regex text in the -replace string:
$regexPlus = '(?s)(?<!,)\s'
$c = $c -replace $regexPlus,', '
e.g. The negative lookbehind working as advertised:
PS C:> $str = '186 ATKINS, Cindy Maria 25 Every Street Smalltown, Student'
PS C:> $regexPlus = '(?s)(?<!,)\s'
PS C:> $str -replace $regexPlus,', '
186, ATKINS, Cindy, Maria, 25, Every, Street, Smalltown, Student
You can use
(Get-Content -Path $filePath) -replace ',*\s+', ', '
This code replaces zero or more commas and all one or more whitespaces after them with a single comma + space.
See the regex demo.
More details:
,* - zero or more commas
\s+ - one or more whitespace chars.

Replace text after special character

I have string which should to be change from numbers to text in my case variable is:
$string = '18.3.0-31290741.41742-1'
I want to replace everything after '-' to be "-SNAPSHOT" and when perform echo $string to show information below. I tried with LastIndexOf(), Trim() and other things but seems not able to manage how to do it.
Expected result:
PS> echo $string
18.3.0-SNAPSHOT
Maybe that can be the light of the correct way, but when have two '-' is going to replace the last one not the first which can see:
$string = "18.3.0-31290741.41742-1" -replace '(.*)-(.*)', '$1-SNAPSHOT'
.* is a greedy match, meaning it will produce the longest matching (sub)string. In your case that would be everything up to the last hyphen. You need either a non-greedy match (.*?) or a pattern that won't match hyphens (^[^-]*).
Demonstration:
PS C:\> '18.3.0-31290741.41742-1' -replace '(^.*?)-.*', '$1-SNAPSHOT'
18.3.0-SNAPSHOT
PS C:\> '18.3.0-31290741.41742-1' -replace '(^[^-]*)-.*', '$1-SNAPSHOT'
18.3.0-SNAPSHOT
By using a positive lookbehind assertion ((?<=...)) you could eliminate the need for a capturing group and backreference:
PS C:\> "18.3.0-31290741.41742-1" -replace '(?<=^.*?-).*', 'SNAPSHOT'
18.3.0-SNAPSHOT
You could use Select-String and an regular expression to match the pattern, then pass the match to ForEach-Object (commonly shorthanded with alias %) to construct the final string:
$string = "18.3.0-31290741.41742-1" | Select-String -pattern ".*-.*-" | %{ "$($_.Matches.value)SNAPSHOT" }
$string

Regex for multiple app versions

Im trying to get list of versions from my custom attribute in powershell script. Atrribute looks like this:
[assembly: CompatibleVersions("1.7.1.0","1.7.1.1","1.2.2.3")]
And I end up with regex like this but it does'nt work at all:
'\(\"([^\",?]*)\"+\)'
You should do this as a two-step process: First you parse out the CompatibleVersions attribute, and then you split out those version numbers. Otherwise you will have difficulties finding the version numbers individually without likely finding otheer version-like numbers.
$s = '[assembly: CompatibleVersions("1.7.1.0","1.7.1.1","1.2.2.3")]'
$versions = ($s | Select-String -Pattern 'CompatibleVersions\(([^)]+)\)' | % { $_.Matches }).Groups[1].Value
$versions.Split(',') | % { $_.Trim('"') } | Write-Host
# 1.7.1.0
# 1.7.1.1
# 1.2.2.3
Start by grabbing the parentheses pair and everything inside:
$string = '[assembly: CompatibleVersions("1.7.1.0","1.7.1.1","1.2.2.3")]'
if($string -match '\(([^)]+)\)'){
# Remove the parentheses themselves, split by comma and then trim the "
$versionList = $Matches[0].Trim("()") -split ',' |ForEach-Object Trim '"'
}
You may use
$s | select-string -pattern "\d+(?:\.\d+)+" -AllMatches | Foreach {$_.Matches} | ForEach-Object {$_.Value}
The \d+(?:\.\d+)+ pattern will match:
\d+ - 1 or more digits
(?:\.\d+)+ - 1 or more sequences of a . and 1+ digits.
See the regex demo on RegexStorm.
'"([.\d]+)"' will match any substring composed of dots and digits (\d) and comprised into double quotes (")
Try it here
A number between .. can be 0, but cannot be 00, 01 or similar.
Pay attention to the starting [
This is a regex for the check:
^\[assembly: CompatibleVersions\("(?:[1-9]\d*|0)(?:\.(?:[1-9]\d*|0)){3}"(?:,"(?:[1-9]\d*|0)(?:\.(?:[1-9]\d*|0)){3}")*\)]$
Here is the regex with tests.
But if you are reading a list, you should use instead:
^\[assembly: CompatibleVersions\("((?:[1-9]\d*|0)(?:\.(?:[1-9]\d*|0)){3}"(?:,"(?:[1-9]\d*|0)(?:\.(?:[1-9]\d*|0)){3}")*)\)]$
By it you will extract the "...","..."... consequence from the inner parenthesis.
After that split the result string by '","' into a list and remove last " from the last element and the first " from the first element. Now you have list of correct versions Strings.
Alas, regex cannot create a list without split() function.

Powershell to get a DLL name out of it's full path

I have a string "....\xyz\abc\0.0\abc.def.ghi.jkl.dll" am trying to get the value of a "abc.def.ghi.jkl.dll" into a variable using powershell.
I am totally new to regex and PS and kinda confused on how to get this done. I read various posts about regex and I am unable to get anything to work
Here is my code,
$str = "..\..\xyz\abc\0.0\abc.def.ghi.jkl.dll"
$regex = [regex] '(?is)(?<=\b\\b).*?(?=\b.dll\b)'
$result = $regex.Matches($str)
Write-Host $result
I would like to get "abc.def.ghi.jkl.dll" into $result. Could someone please help me out
You can use the following regex:
(?is)(?<=\\)[^\\]+\.dll\b
See regex demo
And no need to use Matches, just use a -match (or Match).
Explanation:
(?<=\\) - make sure there is a \ right before the current position in string
[^\\]+ - match 1 or more characters other than \
\.dll\b - match a . symbol followed by 3 letters dll that are followed by a trailing word boundary.
Powershell:
$str = "..\..\xyz\abc\0.0\abc.def.ghi.jkl.dll"
[regex]$regex = "(?is)(?<=\\)[^\\]+\.dll\b"
$match = $regex.match($str)
$result = ""
if ($match.Success)
{
$result = $match.Value
Write-Host $result
}

Program-Name Detection

this is how the lines look like:
//| Vegas.c |
and I would like to get the name, here Vegas.c
This works in PS' regex:
$found = $body -match '.+?\s+(\w.+?\.c[\+]+)[\s\|]+'
But what if the name does not start with a-zA-Z0-9 (=\w) but e.g. ~ or other none-word-chars?
The first char of the name must be different from a blank so I tried:
$found = $body -match '.+?\s+(\S+.+?\.c[\+]+)[\s\|]+'
$found = $body -match '.+?\s+([^\ ]+.+?\.c[\+]+)[\s\|]+'
$found = $body -match '.+?\s+([^\s]+.+?\.c[\+]+)[\s\|]+'
None of them work even some more work. In most of the cases this detects only the whole line!
Any ideas?
How about this?
\/\/\| *([^ ]*)
\/ matches the character /
\/ matches the character /
\| matches the character |
 * matches 0 to many of the character
round brackets ( ) are the first capture group
[^ ] captures all the characters that are ^(not) a space (so long as all your file names do not contain spaces this should work)
I think you made your question more basic then you needed from what I see in your comments but I have this which worked with your test string.
$string = #"
//| Vegas.c |
"#
Just look for data inbetween the pipes and whitespace the pipes border. Not sure how it will perform with you real data but should work if spaces are in the program names.
[void]($string -match "\|\s+(.+)\s+\|")
$Matches[1]
Vegas.c
You could also used named matches in PowerShell
[void]($string -match "\|\s+(?<Program>.+)\s+\|")
$Matches.Program
Vegas.c