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

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
}

Related

Extracting url from a string with regex and Powershell

I'm using powershell and regex. I'm scraping a web page result to a variable, but I can't seem to extract a generated url from that variable.
this is the content (the actual url varies):
"https://api16-something-c-text.sitename.com/aweme/v2/going/?video_id=v12044gd0666c8ohtdbc77u5ov2cqqd0&
$reg = "([^&]*)&;$" always returns false.
I've been trying -match and Select-String with regex but I'm in need of guidance.
I suggest using a -replace operation:
$str = '"https://api16-something-c-text.sitename.com/aweme/v2/going/?video_id=v12044gd0666c8ohtdbc77u5ov2cqqd0&'
$str -replace '^"(.+)&$', '$1'
It really depends on what format the content is in.
(?<=\") looks behind "&quot" for (.*?) which any numbers of non-newline characters and then looks ahead for (?=\&) which is "&".
Here's a fair start:
$pattern = "(?<=\")(.*?)(?=\&)"
$someText = ""https://api16-something-c-text.sitename.com/aweme/v2/going/?video_id=v12044gd0666c8ohtdbc77u5ov2cqqd0&"
$newText = [regex]::match($someText, $pattern)
$newText.Value
Returns:
https://api16-something-c-text.sitename.com/aweme/v2/going/?video_id=v12044gd0666c8ohtdbc77u5ov2cqqd0

unable to parse regex pattern form file to the variable in powershell

I am looking for whether the folder name is as per the below regex pattern in powershell.
Check first 4 letters are HOST.
Check next 3 or 4 letters as per the shortnames in the c:\shortnameslist.csv.
Check the last three letters are END.
#$shortname = (Import-Csv "c:\shortnameslist.csv")
$foldername = "FOLDERABSNAME"
$regex = '\b^(HOST)($shortname)(END)\b'
$foldername -match $regex
Problem:
How to parse the middle part "short name" from the csv list in the regex pattern.
Thanks.
Combine the shortname values from the CSV with the regex 'OR' symbol '|'
Escape any possible regex special characters
$shortname = (Import-Csv -Path 'c:\shortnameslist.csv' | ForEach-Object { [regex]::Escape($_.shortname) }) -join '|'
$regex = "^HOST($shortname).*END$"
$foldername = 'HOSTIFS-blahblahEND' # "FOLDERABSNAME"
$foldername -match $regex # --> True
If this returns $true, then the matching shortname can be found in $matches[1]
If the comparison needs to be Case-Sensitive, change -match into cmatch

Select-String Regex to find string between simple quotes

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].

Regex is working on Regex101 but not inside Powershell

I have this Text file:
[Tabs]
MAILBOXSEND=1
MAILBOX=8
USERS=6
DOCUMENTS_Q=9
MED_WEBSERVCALLS_LOA=3
FCLMNA=1
INCZOOMFORM=1
USERSB=1
USERSB_ONE=1
DATAPRIV=1
MED_WEBSERVCALLS=2
TINVOICES=1
PORDERS=9
PORDERSTOTAL=1
LOGPART=1
LOGCOUNTERS=1
PARTMSG=1
[External Mail]
Send=Y
Hostname=Server
Domain=Domain
Myemail=My#email.com
MyName=My Test
Port=25
SSL=0
[Search]
SUPPLIERS=5,1
StartButton=1
Ignore Case=0
PART=6,1
I'm Trying to capture all the text between [External Mail] to the Next [] Brackets Group,
I have this Regex which do the job and tested in Regex101, after all the testing's I found it's not working inside powershell:
$Text = Get-Content c:\text.txt
$Text -match '(?s)(?<=\[External Mail\]).*?(?=\[.*?\])'
or:
$Text | Select-String '(?s)(?<=\[External Mail\]).*?(?=\[.*?\])'
Nothing Return
Do you have any idea what I'm missing?
Thanks
Looks like you are parsing an .INI file. Don't try to invent the wheel again, take leverage from existing code. This solution reads the .Ini file as nested hash tables that are easy to work with.
In case of link rot, here's the function from Scripting Guys archive:
function Get-IniContent ($filePath)
{
$ini = #{}
switch -regex -file $FilePath
{
"^\[(.+)\]" # Section
{
$section = $matches[1]
$ini[$section] = #{}
$CommentCount = 0
}
"^(;.*)$" # Comment
{
$value = $matches[1]
$CommentCount = $CommentCount + 1
$name = "Comment" + $CommentCount
$ini[$section][$name] = $value
}
"(.+?)\s*=(.*)" # Key
{
$name,$value = $matches[1..2]
$ini[$section][$name] = $value
}
}
return $ini
}
# Sample usage:
$i = Get-IniContent c:\temp\test.ini
$i["external mail"]
Name Value
---- -----
Domain Domain
SSL 0
Hostname Server
Send Y
MyName My Test
Port 25
Myemail My#email.com
$i["external mail"].hostname
Server
Since you are trying to get a multiline regex match you need to be working against a single multiline string. That is the difference between your two cases of regex101 and PowerShell. Get-Content will be returning a string array. Your regex was not matching anything as it was only doing the test on single lines within the file.
PowerShell 2.0
$Text = Get-Content c:\text.txt | Out-String
PowerShell 3.0 of higher
$Text = Get-Content c:\text.txt -Raw
As I said in my comments you don't really need regex, in this way, for this type of string extraction. There are scripts that already exist to parse INI content. If you intend to be replacing content you would have to find the partner cmdlet Out-INIContent assuming it exists but I am sure someone made it. vonPryz's answer contains more information on the cmdlet

Perl how do you assign a varanble to a regex match result

How do you create a $scalar from the result of a regex match?
Is there any way that once the script has matched the regex that it can be assigned to a variable so it can be used later on, outside of the block.
IE. If $regex_result = blah blah then do something.
I understand that I should make the regex as non-greedy as possible.
#!/usr/bin/perl
use strict;
use warnings;
# use diagnostics;
use Win32::OLE;
use Win32::OLE::Const 'Microsoft Outlook';
my #Qmail;
my $regex = "^\\s\*owner \#";
my $sentence = $regex =~ "/^\\s\*owner \#/";
my $outlook = Win32::OLE->new('Outlook.Application')
or warn "Failed Opening Outlook.";
my $namespace = $outlook->GetNamespace("MAPI");
my $folder = $namespace->Folders("test")->Folders("Inbox");
my $items = $folder->Items;
foreach my $msg ( $items->in ) {
if ( $msg->{Subject} =~ m/^(.*test alert) / ) {
my $name = $1;
print " processing Email for $name \n";
push #Qmail, $msg->{Body};
}
}
for(#Qmail) {
next unless /$regex|^\s*description/i;
print; # prints what i want ie lines that start with owner and description
}
print $sentence; # prints ^\\s\*offense \ # not lines that start with owner.
One way is to verify a match occurred.
use strict;
use warnings;
my $str = "hello what world";
my $match = 'no match found';
my $what = 'no what found';
if ( $str =~ /hello (what) world/ )
{
$match = $&;
$what = $1;
}
print '$match = ', $match, "\n";
print '$what = ', $what, "\n";
Use Below Perl variables to meet your requirements -
$` = The string preceding whatever was matched by the last pattern match, not counting patterns matched in nested blocks that have been exited already.
$& = Contains the string matched by the last pattern match
$' = The string following whatever was matched by the last pattern match, not counting patterns matched in nested blockes that have been exited already. For example:
$_ = 'abcdefghi';
/def/;
print "$`:$&:$'\n"; # prints abc:def:ghi
The match of a regex is stored in special variables (as well as some more readable variables if you specify the regex to do so and use the /p flag).
For the whole last match you're looking at the $MATCH (or $& for short) variable. This is covered in the manual page perlvar.
So say you wanted to store your last for loop's matches in an array called #matches, you could write the loop (and for some reason I think you meant it to be a foreach loop) as:
my #matches = ();
foreach (#Qmail) {
next unless /$regex|^\s*description/i;
push #matches_in_qmail $MATCH
print;
}
I think you have a problem in your code. I'm not sure of the original intention but looking at these lines:
my $regex = "^\\s\*owner \#";
my $sentence = $regex =~ "/^\s*owner #/";
I'll step through that as:
Assign $regexto the string ^\s*owner #.
Assign $sentence to value of running a match within $regex with the regular expression /^s*owner $/ (which won't match, if it did $sentence will be 1 but since it didn't it's false).
I think. I'm actually not exactly certain what that line will do or was meant to do.
I'm not quite sure what part of the match you want: the captures, or something else. I've written Regexp::Result which you can use to grab all the captures etc. on a successful match, and Regexp::Flow to grab multiple results (including success statuses). If you just want numbered captures, you can also use Data::Munge
You can do the following:
my $str ="hello world";
my ($hello, $world) = $str =~ /(hello)|(what)/;
say "[$_]" for($hello,$world);
As you see $hello contains "hello".
If you have older perl on your system like me, perl 5.18 or earlier, and you use $ $& $' like codequestor's answer above, it will slow down your program.
Instead, you can use your regex pattern with the modifier /p, and then check these 3 variables: ${^PREMATCH}, ${^MATCH}, and ${^POSTMATCH} for your matching results.