powershell regex select string in variable - regex

I am trying to create a script that select the four numbers that the company computer have in the host name.
I have tested the regex '\d{4}' in a regex web site, and it works fine to select the four numbers. but when using it with powershell y only get the $true or $false.
I need that the 4 numbers are keept in a variable for later use but i havent achieved it.
any ideas??
$machinename = "mac0016w701"
$test = $machinename -match '\d{4}'
$test2= Select-String -Pattern '\d{4}' -inputobject $machinename
$test2

-match is an operator which returns true/false, so you can use it in tests. If you want the values from the regex, it sets the magic variable $Matches, e.g.
PS D:\> 'computer1234' -match '\d{4}'
True
PS D:\> $matches[0]
1234
Alternately, you could use:
[regex]::Matches('computer1234', '\d{4}').Value

Related

Get an array of captures from a regex search in PowerShell

Let's say I have this string:
"14 be h90 bfh4"
And I have this regex pattern:
"(\w+)\d"
In PowerShell, how do I get an array with the contents {"h", "bfh"}?
You want to capture one or more alphabets that are followed by a number, hence the regex for what you want to capture would be this,
[a-zA-Z]+(?=\d)
And the powershell code for same will be this,
$str = "14 be h90 bfh4"
$reg = "[a-zA-Z]+(?=\d)"
$spuntext = $str | Select-String $reg -AllMatches |
ForEach-Object { $_.Matches.Value }
echo $spuntext
Disclaimer: I barely know powershell scripting language so you may have to tweak some codes.
A bit shorten version:
#(Select-String "[a-zA-Z]+(?=\d)" -Input "14 be h90 bfh4" -AllMatches).Matches.Value
Multiple ways to skin a cat as demonstrated by the other answers. Yet another way would be by using the [regex] object provided by .Net
$regex = [regex] '([a-z]+)(?=\d+)'
$regex.Matches("14 be h90 bfh4") | Select Value

Replace or substring first set of numbers with regex

I am struggling to find a way to get only the first set of numbers in a file name in PowerShell. The file names can be similar to the ones below but I only want to get the first string of numbers and nothing else.
Example file names:
123456 (12).csv
123456abc.csv
123456(Copy 1).csv
123456 (Copy 1).csv
What I am currently attempting:
$test = "123456 (12).csv"
$POPieces = $test -match "^[0-9\s]+$"
Write-Host $POPieces
What I'd expect from above:
123456
The -match operator stores the matches in the automatic variable $matches. However, your regular expression includes not only digits, but also whitespace (\s), so you won't necessarily get just the number. Change the expression to ^\d+ to match only a number at the beginning of the string. Use Get-ChildItem to enumerate the files, as Martin Brandl suggested.
$POPieces = Get-ChildItem 'C:\root\folder' -Filter '*.csv' |
Where-Object { $_.Name -match '^\d+' } |
ForEach-Object { $matches[0] }

How to make select-string only match records that are 6 characters long?

I’m creating a script that reads a text file and compares the results to an array. It works fine, but I have some records that say they match but they don’t.
For example - TG1032 and TG match according to the select-string script.
Here is my select-string:
$Sel = select-string -pattern $strArrVal -path $txt
Is there a way to alter this to make select-string only match records that are 6 characters long?
I would still like to point out where your pattern is wrong but the solution will most likely be the same regardless. If you are looking to match lines that are exactly 6 characters then you could just use the pattern ^.{6}$.
$strArrVal = "^.{6}$"
Select-String -Pattern $strArrVal -Path $txt
If that is really all you are looking for then regex is not really required. You could do this with Get-Content with similar results
Get-Content $txt | Where-Object{$_.length -eq 6}

Regex in powershell does not work as expected

I store the output of a defragmentation analysis in a variable, then I try to match a pattern to retrieve a number.
In this following online regex tester, it works fine but in powershell, String -match $pattern returns false.
My code:
$result = Defrag C: /A /V | Out-String
echo $result
$pattern = "fragmenté[^.0-9]*([0-9]+)%"
$result -match $pattern
What am I doing wrong?
I actually had no issue with your code. I just needed to change the match to support my English output. It is possible that Wolfgang Kluge is onto something about the whitespace. However if your output actually matches what you have in the regex tester than i'm not sure what this issue you are having.
For fun I propose this update to your code. This uses ConvertFrom-StringData. I explain the code more in this answer.
$defrag = Defrag C: /A /V | out-string
$hash = (($defrag -split "`r`n" | Where-Object{$_ -match "="}) -join "`r`n" | ConvertFrom-StringData)
$result = New-Object -TypeName PSCustomObject -Property $hash
$result."Quantité totale d'espace fragmenté"
This is of course assuming that your PowerShell is perfectly OK with the accents in the words. On my ISE 3.0 that above code works.
Again... your code was working just fine for me in your question. I also don't think the Out-String is required. I still get positive output. With Out-String I get extra output that includes the entire matched line. Else I just get a boolean. In both (using the following code) I still get a result.
$result = Defrag C: /A /V #| Out-String
$pattern = "fragmented space[^.0-9]*([0-9]+)%"
$result -match $pattern
$Matches[1]
-match works as an array operator which changes how $result is treated. With Out-String $result is a System.String and without it you get System.Object
False Theory
The only way I can get the match to be False is if I am not running PowerShell as an administrator. That is important because if not you will get a message
The disk defragmenter cannot start because you have insufficient priveleges to perform this operation. (0x89000024)

Powershell regex to match vhd or vhdx at the end of a string

I'm brand new to powershell and I'm trying to write a script to copy files ending in vhd or vhdx
I can enumerate a directory of files like so:
$NEWEST_VHD = Get-ChildItem -Path $vhdSourceDir | Where-Object Name -match ".vhdx?"
This will match
foo.vhd
foo.vhdx
However this will also match
foo.vhdxxxx
How can I write a match that will only match files ending in exactly vhd or vhdx ?
Unsuccessful attempts
Where-Object Name -match ".vhdx?"
Where-Object Name -like ".vhdx?"
Where-Object Name -match ".[vhd]x?"
Where-Object Name -match ".[vhd]\^x?"
Resources I've investigated
http://ss64.com/ps/syntax-regex.html
https://technet.microsoft.com/en-us/library/ff730947.aspx
http://www.regexr.com/
Put a $ at the end of your pattern:
-match ".vhdx?$"
$ in a Regex pattern represents the end of the string. So, the above will only match .vhdx? if it is at the end. See a demonstration below:
PS > 'foo.vhd' -match ".vhdx?$"
True
PS > 'foo.vhdx' -match ".vhdx?$"
True
PS > 'foo.vhdxxxx' -match ".vhdx?$"
False
PS >
Also, the . character has a special meaning in a Regex pattern: it tells PowerShell to match any character except a newline. So, you could experience behavior such as:
PS > 'foo.xvhd' -match ".vhdx?$"
True
PS >
If this is undesirable, you can add a \ before the .
PS > 'foo.xvhd' -match "\.vhdx?$"
False
PS >
This tells PowerShell to match a literal period instead.
If you only want to check extension, then you can just use Extension property instead of Name:
$NEWEST_VHD = Get-ChildItem -Path $vhdSourceDir | Where-Object Extension -in '.vhd','.vhdx'
Mostly just an FYI but there is no need for a regex solution for this particular issue. You could just use a simple filter.
$NEWEST_VHD = Get-ChildItem -Path $vhdSourceDir -Filter ".vhd?"
Not perfect but if you dont have files called ".vhdz" then you would be safe. Again, this is not meant as an answer but just useful to know. Reminder that ? in this case optionally matches a single character but it not regex just a basic file system wildcard.
Depending on how many files you have here you could argue that this would be more efficient since you will get all the files you need off the get go instead of filtering after the fact.