Remove everything from string before given variable - powershell

I have a string some\string/with/**/special\chars\haha. In variable I hold chars string and I try to remove everything before and including chars so expected output would be \haha
I tried sth like:
$temp = "some\string/with/**/special\chars\haha"
$tmp="chars"
$temp -replace '(?s)^.*$tmp', ''
and
$temp -replace '(?s)^.*$([regex]::Escape($tmp))', ''
but the only thing that works is when I put the string directly into regex condition. Only this example gives expected output:
$temp -replace '(?s)^.*chars', ''
What am I doing wrong?
Edit.:
I need to use variable in regex, because I iterate through multiple strings like this one and not always the part I want to remove has the same string (example: some\string/with/**/special\chars\haha -> \haha; C:\st/h/*/1234\asdf\x -> \x). So in conclusion I have a problem using variable in regex, not with the regex itself as that works as intended when I replace variable with string (as shown above)

Try
$temp = "some\string/with/**/special\chars\haha"
$tmp="chars"
$regex = '(?s)^.*' + $tmp
$temp -replace $regex, ''

Looks like it's because you are using single quotes in your regex instead of double quotes. This means that the variable $tpm isn't being used.
Here is what your code should look like:
$temp = "some\string/with/**/special\chars\haha"
$tmp="chars"
$temp -replace "(?s)^.*$tmp", ''
Your code was using $tmp instead of the actual value inside the $tmp variable.

Related

powershell How to capture 'left side' of the -replace regex?

First time posting.
i have the following code to replace the suffix of an email and its working fine
replace all characters after # sign with #testdomain.com
$a = 'john.doe#domain.com'
$b = $a -replace "[?=#].*", '#testdomain.com'
$b
john.doe#testdomain.com
what i would like to do, is to capture the actual left side 'source' regex expression to a variable, which would be #domain.com so that i know what i;m replacing and i don;t know how to do it.
Sorry if this had been posted before.
Thank you
So, I'm not sure if this is possible using only the -replace operator and without the use of -match which would store the capture group on the $Matches automatic variable.
This is how you could do it using the regex class directly:
$a = 'john.doe#domain.com'
$Capture = #{}
$b = [regex]::Replace($a, "[?=#].*", {
param($s)
'#testdomain.com'
$Capture.Value = $s.Value
})
$b # => john.doe#testdomain.com
$Capture.Value # => #domain.com
This what I could think using only -replace, adding a delimiter (// in this case) to the replaced string followed by the capture group $0 and then splitting the replacement. Though, this is obviously not a robust solution.
$a = 'john.doe#domain.com'
$b, $capture = $a -replace "[?=#].*", '#testdomain.com//$0' -split '//'
$b # => john.doe#testdomain.com
$capture # => #domain.com
To change the user part you can replace ^.*(?=#):
PS ~> $a = 'john.doe#domain.com'
PS ~> $a -replace '^.*(?=#)', 'jane.doe'
jane.doe#domain.com
The (?=#) construct is known as a lookahead, and describes a zero-length string at the position immediately before the #.

Extract unspecified length of characters to the right of a pattern - Powershell

I have a function that returns a string value:
"D:\Put_Your_Temporary_Files_HERE\Auto_Receive\user_out-automation.ini:9:IpAccessListEx=1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|"
Everything after the equals sign can change depending on what's return in my function. What I want to do is return all text after the equals (=) sign.
Any help will be greatly appreciated.
Thanks
Rob
You can use Select-String Cmdlet with -Pattern parameter to specify the text to find on input
$r = "IPAddressEx=|2.33.31.45|108.38.48.17|" | Select-String -Pattern "IPAddressEx=(.*)"
It return Microsoft.PowerShell.Commands.MatchInfo object on successful pattern match. So to get the sub group from match you have to the access Matches property.
$r.Matches.Groups[1].Value
You can do a simple -split like
$str = "D:\Put_Your_Temporary_Files_HERE\Auto_Receive\user_out-automation.ini:9:IpAccessListEx=1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|"
($str -split '=', 2)[-1]
Result: 1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|
OR use -replace:
$str = "D:\Put_Your_Temporary_Files_HERE\Auto_Receive\user_out-automation.ini:9:IpAccessListEx=1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|"
$str -replace '.*=(.+)$', '$1'
Result: 1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|
OR use the regex .Match() method
$str = "D:\Put_Your_Temporary_Files_HERE\Auto_Receive\user_out-automation.ini:9:IpAccessListEx=1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|"
([regex]'.*=(.+)$').Match($str).Groups[1].Value
Result: 1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|
OR even the String methods IndexOf() combined with SubString():
$str = "D:\Put_Your_Temporary_Files_HERE\Auto_Receive\user_out-automation.ini:9:IpAccessListEx=1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|"
$str.Substring($str.IndexOf("=") + 1)
Although this last alternative is not advisable because IndexOf() may return -1 if the search string is not found
An alternative to Abdul's answer is to use regular expressions. For your case, this should work:
$ret = [regex]::match($string,'(?<=.*=).*')
if ($ret.Success) {
$tag = $ret.Value
}
The regex uses a positive lookbehind, which finds all characters which precede an '='. It then finds all characters which follow it. It stores the object in $ret. You can get your value with $ret.Value.
This returns 1|131.203.181.66|1|10.21.5.34|1|109.146.13.135|1|10.21.3.3|

How can I split a string into an array on every newline?

In my situation, I will have a string that looks like this.
$emailList = "example#mail.com
example2#mail.com
example3#mail.com"
How can I port this into an array with no white-space so it would look like
$emailList = #("example#mail.com","example2#mail.com","example3#mail.com"
Per the comments, if you do this:
($emailList -split '\r?\n').Trim()
It uses -split to separate the list in to an array based on the new line/return charaters and then .Trim() to remove any whitespace either side of each string.
Following this the result is now already an array. However if you explicitly want the output to be as a list of comma separated strings surrounded by double quotes you could then do this:
(($emailList -split '\r?\n').Trim() | ForEach-Object { '"'+$_+'"' }) -Join ','
Which uses ForEach-Object to add quote marks around each entry and then uses -Join to connect them with a ,.
$emailList = "example#mail.com
example2#mail.com
example3#mail.com"
$emailList.Split([Environment]::NewLine,[Stringsplitoptions]::RemoveEmptyEntries).trim()
-split on the left side splits on variable whitespace:
$emailList = -split 'example#mail.com
example2#mail.com
example3#mail.com'
$emailList
example#mail.com
example2#mail.com
example3#mail.com
You can also form an array list this. #() is almost never needed.
$emailList = 'example#mail.com','example2#mail.com','example3#mail.com'
Or as a shortcut (echo is an alias for write-output):
$emailList = echo example#mail.com example2#mail.com example3#mail.com

Powershell TRIM() is removing extra character

I'm attempting to remove the "\MOSS2013" instance name from my SQL Server instance "WSFCSQLN1\MOSS2013"
This works:
$primaryReplicaGEN = $wsfcsqln2.AvailabilityGroups.PrimaryReplicaServerName
$primaryReplica = $PrimaryReplicaGEN.TRIM("\GEN")
$primaryReplica shows WSFCSQLN1
$primaryReplicaGEN shows WSFCSQLN1\GEN
This does not work:
$primaryReplicaMOSS2013 = $wsfcsqln1MOSS2013.AvailabilityGroups.PrimaryReplicaServerName
$primaryReplica = $PrimaryReplicaMOSS2013.TRIM("\MOSS2013")
$primaryReplica shows WSFCSQLN
$primaryReplicaMOSS2013 shows WSFCSQLN1\MOSS2013
Notice the replica name is missing the 1 at the end even though I did not choose to trim it. Why is it trimming the 1 for this particular string object? How can I force it to trim the correct characters.
Trim() turns the string argument into a [char[]] and removes any of those characters from both ends of the string.
If you just want to grab the server name, use the -split operator and then discard the instance name:
$ServerName = 'WSFCSQLN1\MOSS2013' -split '\\' |Select-Object -First 1
or
$ServerName,$null = 'WSFCSQLN1\MOSS2013' -split '\\'
well, thats how trim works, it will remove all the occurrences of all the characters you are going to trim which it can get to.
"agababga".Trim("ag")
would return bab not ababga, notice it didn't trim a inside bab as it cannot trim b, if you do:
"agababga".Trim("agb")
you would get nothing (empty string) in response
you can use convertfrom-string too like this
$SplitedVar='WSFCSQLN1\MOSS2013' | ConvertFrom-String -Delimiter "\\" -PropertyNames "Domain", "ServerName"
$SplitedVar.Domain
$SplitedVar.ServerName
I'd use a split call:
$primaryReplica = $PrimaryReplicaGEN.split('\')[0];

Change specific part of a string

I've got a .txt-File with some text in it:
Property;Value
PKG_GUID;"939de9ec-c9ac-4e03-8bef-7b7ab99bff74"
PKG_NAME;"WinBasics"
PKG_RELATED_TICKET;""
PKG_CUSTOMER_DNS_SERVERS;"12314.1231
PKG_CUSTOMER_SEARCH_DOMAINS;"ms.com"
PKG_JOIN_EXISTING_DOMAIN;"True"
PKG_DOMAINJOIN_DOMAIN;"ms.com"
PKG_DOMAINJOIN_USER;"mdoe"
PKG_DOMAINJOIN_PASSWD;"*******"
So now, is there a way to replace those *'s with e.g. numbers or sth. ?
If so, may you tell me how to do it?
Much like Rahul I would use RegEx as well. Considering the application I'd run Get-Content through a ForEach loop, and replace text as needed on a line-by-line basis.
Get-Content C:\Path\To\File.txt | ForEach{$_ -replace "(PKG_DOMAINJOIN_PASSWD;`")([^`"]+?)(`")", "`${1}12345678`$3"}
That would output:
Property;Value
PKG_GUID;"939de9ec-c9ac-4e03-8bef-7b7ab99bff74"
PKG_NAME;"WinBasics"
PKG_RELATED_TICKET;""
PKG_CUSTOMER_DNS_SERVERS;"12314.1231
PKG_CUSTOMER_SEARCH_DOMAINS;"ms.com"
PKG_JOIN_EXISTING_DOMAIN;"True"
PKG_DOMAINJOIN_DOMAIN;"ms.com"
PKG_DOMAINJOIN_USER;"mdoe"
PKG_DOMAINJOIN_PASSWD;"12345678"
On second thought, I don't know if I'd do that. I might import it as a CSV, update the property, and export the CSV again.
Import-CSV C:\Path\To\File.txt -Delimiter ";" |%{if($_.Property -eq "PKG_DOMAINJOIN_PASSWD"){$_.value = "12345678";$_}else{$_}|export-csv c:\path\to\newfile.txt -delimiter ";" -notype
If You are using Powershell V2.0 (Hopefully) you can try something like below. gc is short hand for get-content commandlet.
(gc D:\SO_Test\test.txt) -replace '\*+','12345678'
With this the resultant data would be as below (notice the last line)
Property;Value
PKG_GUID;"939de9ec-c9ac-4e03-8bef-7b7ab99bff74"
<Rest of the lines here>
PKG_DOMAINJOIN_USER;"mdoe"
PKG_DOMAINJOIN_PASSWD;"12345678" <-- Notice here; *'s changed to numbers
Rahul's answer was good, I just wanted to mention that *+ will replace all instances of a single * character or more, so it would match any other place there is at least one star. If what you posted is all you would ever expect for you sample data though this would be fine.
You could alter the regex match to make it more specific if it was needed by changing it to something like
\*{3,0}
which would match 3 or more stars, or very specific would be
(?<=")\*{3,}(?=")
which would replace 3 or more stars which are surrounded by double quotes.
Here's a function that uses regex lookahead and lookbehind zero-length assertions to replace named parameters in a string similar to your example:
function replace-x( $string, $name, $value ) {
$regex = "(?<=$([regex]::Escape($name));`").*(?=`")"
$string -replace $regex, $value
}
Its reusable for different settings in your file, e.g:
$settings = get-content $filename
$settings = replace-x $settings PKG_DOMAINJOIN_USER foo
$settings = replace-x $settings PKG_DOMAINJOIN_PASSWD bar