I'm probably misunderstanding how PowerShell functions work, but I have the following to extract the year from a string such as "abcdef20201123xyz":
function getYear($str) {
$str -match ".*(?<year>[\d]{4})[\d]{4}.*"
return $matches['year']
}
I expected getYear("abcdef20201123xyz") just to return "2020", but I get
True
2020
Why is this, and how do I just get what I put in the "return"?
In PowerShell, every not handled function call is sent to the output. So you either assign the return value to a variable, or you pipe it to Out-Null:
function getYear($str) {
$str -match ".*(?<year>[\d]{4})[\d]{4}.*" | out-null
return $matches['year']
}
Related
Can someone assist on how to fill a combobox with the result of a powershell command?
Im trying to fill a combobox with the result of a "Get" cmdlet but I only get some powershell parameters as result.
$ButtonCollectionSearch.Add_Click({
$name = $textboxlogonname.text
$ComboBox = New-Object System.Windows.Forms.ComboBox
$ComboBox.Width = 400
$Collections = Get-RDSessionCollection | fl -Property CollectionName
Foreach ($Collection in $Collection) {
$ComboBox.Items.Add($Collection);
}
$ComboBox.Location = New-Object System.Drawing.Point(120, 10)
$main_form.Controls.Add($ComboBox)
})
The reason you're getting formatting metadata is that you asked for formatting metadata - by piping all your data through fl (which is a alias for Format-List).
Since we just want the value of the CollectionName, use ForEach-Object -MemberName in place of fl -Property:
$Collections = Get-RDSessionCollection | ForEach-Object -MemberName CollectionName
You'll also want to address the typo in the foreach loop declaration - change:
Foreach ($Collection in $Collection) {
to:
Foreach ($Collection in $Collections) {
I had created this function to attempt to break strings into groups of tokens that can be made into PowerShell object. This is what I have so far. If I use the code outside of the function I get the desired result but if I attempt to use it within the function I get nothing. I believe the output is disappearing. I know I am not using the right terminology to describe what is happening. Any assistance would be appreciated.
Function Convert-MatchToPSCustomObject
{
<#
.SYNOPSIS
Converts $matches to PSCustomObject
.DESCRIPTION
Takes an input string and converts it to PSCustomObject
.PARAMETER Pattern
Mandatory. Pattern which to match within the string
.PARAMETER String
Mandatory. Input String
.EXAMPLE
Convert-MatchToPSCustomObject -Pattern '(?<descriptor>^\b[A-Z]{2})(?>[=])(?<value>[\w \.\-]+\b$)' -String 'CN=Only Da Best'
.LINK
https://regex101.com/r/1hYb2J/1/
.LINK
https://vexx32.github.io/2018/11/08/Named-Regex-Matches-PSCustomObject/
.NOTES
Version: 1.0
Author: Kino Mondesir
#>
[cmdletbinding()]
param
(
[Parameter(HelpMessage="Pattern to match", Position=0, Mandatory=$false, ValueFromPipelineByPropertyName=$true)]
[ValidateNotNullorEmpty()]
[string]$pattern = '(?<descriptor>^\b[A-Z]{2})(?>[=])(?<value>[\w \.\-]+\b$)',
[Parameter(HelpMessage="Input string", Position=1, Mandatory=$true, ValueFromPipeline=$true)]
[ValidateNotNullorEmpty()]
[string]$string
)
Try
{
return $string -split ',' | ForEach-Object {
if ($PSItem -match $pattern)
{
$Matches.Remove(0)
[PSCustomObject]$Matches
}
else
{
Throw "No matching items found!"
}
}
}
Catch
{
$exception = $_.Exception
Write-Error $exception.Message
return -1
}
}
This code is supposed to find a line with a regular expression and replace the line with "test". It is finding that line and replace it with "test" but also deleting the line under it, no matter what is in the next line down. I feel like I am just missing something about how a switch works in PowerShell.
Note: This is super boiled down code. There is a larger program this is part of.
$reg = '^HI\*BH'
$appendText = ''
$file = Get-ChildItem (join-path $PSScriptRoot "a.txt.BAK")
foreach ($f in $file){
switch -regex -file $f {
$reg
{
$appendText = "test"
}
default {
If ($appendText -eq '') {$appendText = $_}
$appendText
$appendText = ''
}
}
}
a.txt.BAK
HI*BH>00>D8>0*BH>00>D8>0*BH>A1>D8>0*BH>B1>D8>0000000~
HI*BE>02>>>0.00*BE>00>>>0.00~
NM1*71*1*TTT*NAME****XX*0000000~
PRV*AT*PXC*000V00000X~
Output:
test
NM1*71*1*TTT*NAME****XX*0000000~
PRV*AT*PXC*000V00000X~
The switch is not "deleting" anything - but you explicit ask it to overwrite $appendText on match, and you only ever output (and reset the value of) $appendText when it doesn't.
This code is supposed to find a line with a regular expression and replace the line with "test".
In that case I suggest you simplify your switch:
switch -regex -file $f {
$reg {
"test"
}
default {
$_
}
}
That's it - no fiddling around with variables - just output "test" on match, otherwise output the line as-is.
If you insist on using the intermediate variable, you'll need to output + reset the value in both cases:
switch -regex -file $f {
$reg {
$appendText = "test"
$appendText
$appendText = ''
}
default {
$appendText = $_
$appendText
$appendText = ''
}
}
Hi can anybody help me I am stuck and can't get regex to work with powershell and a switch statement.
Could not find anything on the web that was helpful either.
How can I filter an IP for example or a string of 7 to 8 numbers?
switch -regex ($buffer)
{
($buffer -match '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}')
{}
($buffer -match {'\d{7,8}'})
{}
}
When used in -regex mode, PowerShell expects the case condition to be a regex pattern, nothing else:
switch -regex ($buffer)
{
'[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
{
# looks kinda like an IP
}
'\d{7,8}'
{
# just numbers
}
}
Use braces instead of parenthesis, and omit the variable for switch altogether:
switch (1)
{
{ $buffer -match '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' }
{ Write-Output "IP Address" }
{ $buffer -match '\d{7,8}' }
{ Write-Output "7-8 digits" }
}
I'm new to threads. I written a script to check the threads module in which i have some modules which do some pattern matching job and returns to two values 1st the input and second match found instance along with its line number. But using the threads it returns nothing.
here is the code
use threads;
sub pattern_finder($){
my $filebuf = shift;
my #threads;
my $pattern_found;
my $thr1 = threads->create(\&sub_pattern1,$filebuf);
push(#threads, $thr1);
my $thr2 = threads->create(\&sub_pattern2,$filebuf);
push(#threads, $thr2);
my $thr3 = threads->create(\&sub_pattern3,$filebuf);
push(#threads, $thr3);
for my $t(#threads){
($filebuf, $tmp)= $t->join();
$pattern_found .= $tmp;
}
return $filebuf, $pattern_found;
}
sub sub_pattern1($)
{
my ($filebuf) = shift;
my $found;
while($filebuf =~ /<LINE(\d+)>Pattern1/gsi)
{
$found .= "Pattern1 found at line $1\n";
}
return $filebuf, $found;
}
sub sub_pattern2($)
{
my ($filebuf) = shift;
my $found;
while($filebuf =~ /<LINE(\d+)>Pattern2/gsi)
{
$found .= "Pattern2 found at line $1\n";
}
return $filebuf, $found;
}
sub sub_pattern3($)
{
my ($filebuf) = shift;
my $found;
while($filebuf =~ /<LINE(\d+)>Pattern3/gsi)
{
$found .= "Pattern3 found at line $1\n";
}
$found = "$pre_checks"."$found";
return $filebuf, $found;
}
Can anyone suggest me what is wrong in the code?
Ah yes, a common problem: The code reference you pass to threads->create is called in the context that the create method was called. Here, this is scalar context. Thus return $filebuf, $found is equivalent to return $found.
As you use that single element in list context when joining the thread, you do something equivalent to $filebuf = $t->join, $tmp = undef which is not what you're expecting.
This can be fixed in two ways:
create the thread in list context:
my ($thr1) = threads->create(...)
explicitly specify the context:
my $thr1 = threads->create({context => 'list'}, \&sub_pattern1, $filebuf);
See also the section on context in the threads documentation.
Note also that there is no reason to return $filebuf at all as you don't really use that value – you just return the $filebuf of the last thread which was joined.
Tip: If you're using multithreading for performance, you should benchmark your code both with and without threads – in your case the non-threaded (sequential) solution is likely to perform better.