Use a function in Powershell replace - regex

I'm trying to replace part of a string in Powershell. However, the replacement string is not hardcoded, it's calculated from a function:
$text = "the image is -12345-"
$text = $text -replace "-(\d*)-", 'This is the image: $1'
Write-Host $text
This gives me the correct result:
"This is the image: 12345"
Now, I want to include the base64 encoded image. I can read the image from the id. I was hoping the following would work, but it doesn't:
function Get-Base64($path)
{
[convert]::ToBase64String((get-content $path -encoding byte))
}
$text -replace "-(\d*)-", "This is the image: $(Get-Base64 '$1')"
The reason that it doesn't work, is because it first passes $1 (the string, not the value of $1) to the function, executes it and only then does it do the replace. What I want to do is
Find the occurrence of the pattern
Replace each occurence with the pattern
For each replace:
Pass the capture group to the function
Use the value of the capture group to get the base64 image
inject the base64 image into the replacement

You can use the static Replace method from the [regex] class:
[regex]::Replace($text,'-(\d*)-',{param($match) "This is the image: $(Get-Base64 $match.Groups[1].Value)"})
Alternatively you can define a regex object and use the Replace method of that object:
$re = [regex]'-(\d*)-'
$re.Replace($text, {param($match) "This is the image: $(Get-Base64 $match.Groups[1].Value)"})
For better readability you could define the callback function (the scriptblock) in a separate variable and use that in the replacement:
$callback = {
param($match)
'This is the image: ' + (Get-Base64 $match.Groups[1].Value)
}
$re = [regex]'-(\d*)-'
$re.Replace($text, $callback)

PetSerAl's helpful answer is your only option in Windows PowerShell, as of v5.1.
PowerShell Core v6.1+ now offers a native PowerShell solution via an enhancement to the
-replace operator, which obviates the need to call [regex]::Replace():
Just as with [regex]::Replace(), you can now:
pass a script block as the -replace replacement operand, which must return the replacement string,
except that the match at hand (an instance of type [System.Text.RegularExpressions.Match]) is represented as automatic variable $_, as is customary in PowerShell.
Applied to your case:
$text -replace "-(\d*)-", { "This is the image: $(Get-Base64 $_.Groups[1].Value)" }
A simpler example:
# Increment the number embedded in a string:
PS> '42 years old' -replace '\d+', { [int] $_.Value + 1 }
43 years old

Here's another way. Use the -match operator, and then reference $matches. Note that $matches doesn't get set with arrays on the left side of the -match operator. $matches.1 is the first grouping formed by the ( ).
$text = "the image is -12345-"
function Get-Base64($path) {
[convert]::ToBase64String( (get-content $path -asbytestream) ) } # ps 6 ver
if (! (test-path 12345)) { echo hi > 12345 }
$text -match '-(\d*)-'
$text -replace '-(\d*)-', "$(Get-Base64 $matches.1)"
the image is aGkNCg==
Or to break it up even more:
$text -match '-(\d*)-'
$result = Get-Base64 $matches.1
$text -replace '-(\d*)-', $result

Related

How to extract a string between square brackets

I have to extract a string from square brackets using Powershell or Groovy script.
PowerShell :
$string = "[test][OB-110] this is some text"
$found = $string -match '(?<=\[)[^]]+(?=\])'
echo $matches
When I run the above code it returns :
test
I want it to return this :
test
OB-110
I need to extract all text within brackets.
-match will internally call Regex.Match() in the background, which in turn will only capture the first match.
Either use Select-String with the -AllMatches switch:
($string |Select-String '(?<=\[)[^]]+(?=\])' -AllMatches).Matches.Value
Or invoke Regex.Matches() directly:
[regex]::Matches($string, '(?<=\[)[^]]+(?=\])').Value
For Groovy:
def str = "[test][OB-110] this is some text"
str.findAll(/(?<=\[)[^]]+(?=\])/).each {
println it
}
Which prints
test
OB-110

Powershell replace multiple occurrences of regex in text file [duplicate]

I'm trying to replace part of a string in Powershell. However, the replacement string is not hardcoded, it's calculated from a function:
$text = "the image is -12345-"
$text = $text -replace "-(\d*)-", 'This is the image: $1'
Write-Host $text
This gives me the correct result:
"This is the image: 12345"
Now, I want to include the base64 encoded image. I can read the image from the id. I was hoping the following would work, but it doesn't:
function Get-Base64($path)
{
[convert]::ToBase64String((get-content $path -encoding byte))
}
$text -replace "-(\d*)-", "This is the image: $(Get-Base64 '$1')"
The reason that it doesn't work, is because it first passes $1 (the string, not the value of $1) to the function, executes it and only then does it do the replace. What I want to do is
Find the occurrence of the pattern
Replace each occurence with the pattern
For each replace:
Pass the capture group to the function
Use the value of the capture group to get the base64 image
inject the base64 image into the replacement
You can use the static Replace method from the [regex] class:
[regex]::Replace($text,'-(\d*)-',{param($match) "This is the image: $(Get-Base64 $match.Groups[1].Value)"})
Alternatively you can define a regex object and use the Replace method of that object:
$re = [regex]'-(\d*)-'
$re.Replace($text, {param($match) "This is the image: $(Get-Base64 $match.Groups[1].Value)"})
For better readability you could define the callback function (the scriptblock) in a separate variable and use that in the replacement:
$callback = {
param($match)
'This is the image: ' + (Get-Base64 $match.Groups[1].Value)
}
$re = [regex]'-(\d*)-'
$re.Replace($text, $callback)
PetSerAl's helpful answer is your only option in Windows PowerShell, as of v5.1.
PowerShell Core v6.1+ now offers a native PowerShell solution via an enhancement to the
-replace operator, which obviates the need to call [regex]::Replace():
Just as with [regex]::Replace(), you can now:
pass a script block as the -replace replacement operand, which must return the replacement string,
except that the match at hand (an instance of type [System.Text.RegularExpressions.Match]) is represented as automatic variable $_, as is customary in PowerShell.
Applied to your case:
$text -replace "-(\d*)-", { "This is the image: $(Get-Base64 $_.Groups[1].Value)" }
A simpler example:
# Increment the number embedded in a string:
PS> '42 years old' -replace '\d+', { [int] $_.Value + 1 }
43 years old
Here's another way. Use the -match operator, and then reference $matches. Note that $matches doesn't get set with arrays on the left side of the -match operator. $matches.1 is the first grouping formed by the ( ).
$text = "the image is -12345-"
function Get-Base64($path) {
[convert]::ToBase64String( (get-content $path -asbytestream) ) } # ps 6 ver
if (! (test-path 12345)) { echo hi > 12345 }
$text -match '-(\d*)-'
$text -replace '-(\d*)-', "$(Get-Base64 $matches.1)"
the image is aGkNCg==
Or to break it up even more:
$text -match '-(\d*)-'
$result = Get-Base64 $matches.1
$text -replace '-(\d*)-', $result

Replace until a pattern is found in PowerShell

I have been trying to transform the following string:
CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM
to:
FR.CONTOSO.COM
As a first step, I tried to remove everything until ",DC" pattern.
I thought I could use the un-greedy ".+?" to match everything until the first ",DC" pattern:
$str = 'CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM'
$str -replace '.+?,DC', ''
This returns:
=COM
Any idea why it's getting only the last one even with the un-greedy version?
How could I do this?
Just split the string:
$parts = ('CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM' -split ',')
$newString = '{0}.{1}.{2}' -f $parts[-3].split('=')[1], $parts[-2].split('=')[1], $parts[-1].split('=')[1]
OK, so I took #EBGreen's advice and decided to make a function that does all the work:
#Requires -Version 4
Function ConvertFrom-DistinguishedName
{
[CmdletBinding()]
[OutputType('System.Management.Automation.PSCustomObject')]
Param(
[Parameter(Position = 0, Mandatory)]
[Alias('DistinguishedName', 'Name')]
[ValidatePattern('^CN=.+?,(OU=.+?,)+DC=.+$')]
[string]
$Path
)
$local:ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
$WS = $Path -split ',' # working set
$User = $WS[0] -replace 'CN='
$Domain = $WS.Where({$PSItem.StartsWith('DC=')}).ToLower() -replace 'dc=' -join '.'
$OU = $WS.Where({$PSItem.StartsWith('OU=')}) -replace 'OU='
[array]::Reverse($OU)
[pscustomobject]#{
'User' = $User
'Domain' = $Domain
'OU' = $OU -join '\'
}
}
PS C:\> ConvertFrom-DistinguishedName 'CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM'
User Domain OU
---- ------ --
John Doe fr.contoso.com HQ\Department\Support\IT
The end result? This converts your distinguished AD name to a PSCustomObject you can easily work with.
To get the domain out of the Distinguishedname, you will want to use -Split. Finally we can use -join to insert '.' between the DCs
This will store your domain string to $domain:
$dn = "CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM"
$domain = $dn -Split "," | ? {$_ -like "DC=*"}
$domain = $domain -join "." -replace ("DC=", "")
Write-Host "Current Domain: " $domain
You should use the ^ to start from the beginning.
$str = 'CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC=FR,DC=CONTOSO,DC=COM'
$str = $str -replace '^.+?,DC',''
$str = $str -replace 'DC=',''
$str -replace ',','.'
Since nobody bothered explaining the behavior yet:
The replacement operation replaces every occurrence of the pattern .+?,DC in the string, so it first removes CN=John Doe,OU=IT,OU=Support,OU=Department,OU=HQ,DC, then continues where that replacement left off and removes =FR,DC, and then =CONTOSO,DC, leaving you with just =COM.
To avoid this behavior you need to anchor the expression at the beginning of the string (^), as others have already suggested. The second replacement for substituting the remaining ,DC= with dots can be daisy-chained to the first one, so you need just one statement:
$str -replace '^.*?,dc=' -replace ',dc=', '.'

Assign variable value dynamically to Regex captured string [duplicate]

I'm trying to replace part of a string in Powershell. However, the replacement string is not hardcoded, it's calculated from a function:
$text = "the image is -12345-"
$text = $text -replace "-(\d*)-", 'This is the image: $1'
Write-Host $text
This gives me the correct result:
"This is the image: 12345"
Now, I want to include the base64 encoded image. I can read the image from the id. I was hoping the following would work, but it doesn't:
function Get-Base64($path)
{
[convert]::ToBase64String((get-content $path -encoding byte))
}
$text -replace "-(\d*)-", "This is the image: $(Get-Base64 '$1')"
The reason that it doesn't work, is because it first passes $1 (the string, not the value of $1) to the function, executes it and only then does it do the replace. What I want to do is
Find the occurrence of the pattern
Replace each occurence with the pattern
For each replace:
Pass the capture group to the function
Use the value of the capture group to get the base64 image
inject the base64 image into the replacement
You can use the static Replace method from the [regex] class:
[regex]::Replace($text,'-(\d*)-',{param($match) "This is the image: $(Get-Base64 $match.Groups[1].Value)"})
Alternatively you can define a regex object and use the Replace method of that object:
$re = [regex]'-(\d*)-'
$re.Replace($text, {param($match) "This is the image: $(Get-Base64 $match.Groups[1].Value)"})
For better readability you could define the callback function (the scriptblock) in a separate variable and use that in the replacement:
$callback = {
param($match)
'This is the image: ' + (Get-Base64 $match.Groups[1].Value)
}
$re = [regex]'-(\d*)-'
$re.Replace($text, $callback)
PetSerAl's helpful answer is your only option in Windows PowerShell, as of v5.1.
PowerShell Core v6.1+ now offers a native PowerShell solution via an enhancement to the
-replace operator, which obviates the need to call [regex]::Replace():
Just as with [regex]::Replace(), you can now:
pass a script block as the -replace replacement operand, which must return the replacement string,
except that the match at hand (an instance of type [System.Text.RegularExpressions.Match]) is represented as automatic variable $_, as is customary in PowerShell.
Applied to your case:
$text -replace "-(\d*)-", { "This is the image: $(Get-Base64 $_.Groups[1].Value)" }
A simpler example:
# Increment the number embedded in a string:
PS> '42 years old' -replace '\d+', { [int] $_.Value + 1 }
43 years old
Here's another way. Use the -match operator, and then reference $matches. Note that $matches doesn't get set with arrays on the left side of the -match operator. $matches.1 is the first grouping formed by the ( ).
$text = "the image is -12345-"
function Get-Base64($path) {
[convert]::ToBase64String( (get-content $path -asbytestream) ) } # ps 6 ver
if (! (test-path 12345)) { echo hi > 12345 }
$text -match '-(\d*)-'
$text -replace '-(\d*)-', "$(Get-Base64 $matches.1)"
the image is aGkNCg==
Or to break it up even more:
$text -match '-(\d*)-'
$result = Get-Base64 $matches.1
$text -replace '-(\d*)-', $result

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
}