Use "-replace" to compare and replace more variations of a string - powershell

I have to check if a string matches with one of these four strings and then replace the string. How can I do it?
I tried the following but it doesn't work
$NewOne = $One -replace("111" -or "112" -or "113" -or "114","000")
Instead of those numbers it should write 000.

Don't use parentheses with operators.
As -replace is RegEx based either use alternation or a character class
$NewOne = $One -replace '111|112|113|114','000'
or
$NewOne = $One -replace '11[1-4]','000'

Related

Split string in Powershell

I have sth written in a ".ini" file that i want to read from PS. The file gives the value "notepad.exe" and i want to give the value "notepad" into a variable. So i do the following:
$CLREXE = Get-Content -Path "T:\keeran\Test-kill\test.ini" | Select-String -Pattern 'CLREXE'
#split the value from "CLREXE ="
$CLREXE = $CLREXE -split "="
#everything fine untill here
$CLREXE = $CLREXE[1]
#i am trying to omit ".exe" here. But it doesn't work
$d = $CLREXE -split "." | Select-String -NotMatch 'exe'
How can i do this ?
#Mathias R. Jessen is already answered your question.
But instead of splitting on filename you could use the GetFileNameWithoutExtension method from .NET Path class.
$CLREXE = "notepad.exe"
$fileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($CLREXE)
Write-Host $fileNameWithoutExtension # this will print just 'notepad'
-split is a regex operator, and . is a special metacharacter in regex - so you need to escape it:
$CLREXE -split '\.'
A better way would be to use the -replace operator to remove the last . and everything after it:
$CLREXE -replace '\.[^\.]+$'
The regex pattern matches one literal dot (\.), then 1 or more non-dots ([^\.]+) followed by the end of the string $.
If you're not comfortable with regular expressions, you can also use .NET's native string methods for this:
$CLREXE.Remove($CLREXE.LastIndexOf('.'))
Here, we use String.LastIndexOf to locate the index (the position in the string) of the last occurrence of ., then removing anything from there on out

powershell filter filenames with regex

I am building a list of files that I'm putting into my $list variable.
Then I want to filter the list based on the $filter variable. The current solution works, but it doesn't work with a regex.
$filter = #("test.txt","Fake","AnotherFile\d{1..6}")
######### HTML TESTS #############
[string]$list = #"
FakeFile.txt
test120119.txt
AnotherFile120119.txt
LastFile.txt
"#
[array]$files = $list -split '\r?\n'
$files = $files | Where-Object {$_} | Where {$_ -notin $filter} # filter out empty items from the array...
$files
My idea is to put regex patterns in the $filter variable so I can catch filenames that have datestamps in them such as test120119.txt in the $list variable above.
How can I change my code to allow for regex? I tried some variations of select-string without splitting my $list, but was not fruitful. I also tried changing my -notin to -notmatch but this doesn't work at all of course.
If you want to use regex, I think it would be easier to just fully commit to regex with your $filter array.
$filter = "^test\d{0,6}\.txt","^Fake","^AnotherFile\d{0,6}\.txt" -join '|'
$list = #"
FakeFile.txt
test120119.txt
AnotherFile120119.txt
LastFile.txt
"#
$files = $list -split '\r?\n'
$files | Where {$_ -notmatch $filter}
The thing to keep in mind is remembering to escape special regex characters if you want them treated literally. You can use the [regex]::Escape() method to do this for you but not if you already purposely injected regex characters.
Once you have your regex filter list, you can join each item with a regex or using the | character.
Not all operators recognize regex language. -match and -notmatch are among the few that do. -match and -notmatch are not case-sensitive. If you want to match against case, you should use the -c variants of the operators, namely -cmatch and -cnotmatch.
The regex items can be tweaked to your liking. More requirements would need to be given in order to come up with an exact solution. Here are some examples to consider:
\d{0,6} matches 0 to 6 consecutive digits. 122619 will match successfully, but so will 1226. If you want only 0 or 6 digits to match, you can use (\d{6})?.
^ should be used if you want to start each match at the beginning of the input string. So if you want the regex or to apply from the beginning of the string, you need to include ^ in each item or group items succeeding the initial ^ with () accordingly. ^item1|^item2 will return the same capture group 0 match as ^(item1|item2).
\ escape the literal . characters.
Not using anchor characters like ^ and $ create a lot of flexibility and potentially unwanted results. 'FakeFile' -match 'Fake' returns true but so does 'MyFakeFile' -match 'Fake'. However, 'MyFakeFile' -match 'Fake$' returns false and 'MyFake' -match 'Fake$' returns true.

Contains operator not working in Powershell

I have never got the -contains operator to work in Powershell I don't know why.
Here's an example of where it isn't working. I use -like in its place but I'd love it if you could tell me why this isn't working.
PS HKLM:\Software\Microsoft\Windows NT\CurrentVersion> (gp . P*).ProductName
Windows 10 Enterprise
PS HKLM:\Software\Microsoft\Windows NT\CurrentVersion> (gp . P*).ProductName -contains "Windows"
False
PS HKLM:\Software\Microsoft\Windows NT\CurrentVersion> (gp . P*).ProductName | gm | select TypeName | Get-Unique
TypeName
--------
System.String
The -contains operator is not a string operator, but a collection containment operator:
'a','b','c' -contains 'b' # correct use of -contains against collection
From the about_Comparison_Operators help topic:
Type Operator Description
Containment -contains Returns true when reference value contained in a collection
-notcontains Returns true when reference value not contained in a collection
-in Returns true when test value contained in a collection
-notin Returns true when test value not contained in a collection
Usually you would use the -like string operator in PowerShell, which supports Windows-style wildcard matching (* for any number of any characters, ? for exactly one of any character, [abcdef] for one of a character set):
'abc' -like '*b*' # $true
'abc' -like 'a*' # $true
Another alternative is the -match operator:
'abc' -match 'b' # $true
'abc' -match '^a' # $true
For verbatim substring matching, you would want to escape any input pattern, since -match is a regex operator:
'abc.e' -match [regex]::Escape('c.e')
An alternative is to use the String.Contains() method:
'abc'.Contains('b') # $true
With the caveat that, unlike powershell string operators, it's case-sensitive.
String.IndexOf() is yet another alternative, this one allows you to override the default case-sensitivity:
'ABC'.IndexOf('b', [System.StringComparison]::InvariantCultureIgnoreCase) -ge 0
IndexOf() returns -1 if the substring is not found, so any non-negative return value can be interpreted as having found the substring.
The '-contains' operator is best used for comparison to lists or arrays, e.g.
$list = #("server1","server2","server3")
if ($list -contains "server2"){"True"}
else {"False"}
output:
True
I'd suggest using '-match' instead for string comparisons:
$str = "windows"
if ($str -match "win") {"`$str contains 'win'"}
if ($str -match "^win") {"`$str starts with 'win'"}
if ($str -match "win$") {"`$str ends with 'win'"} else {"`$str does not end with 'win'"}
if ($str -match "ows$") {"`$str ends with 'ows'"}
output:
$str contains 'win'
$str starts with 'win'
$str does not end with 'win'
$str ends with 'ows'

does not work split on powershell

I have code, which split string to array. So can you help me, why this is doesn't work?
$var="test.1->test.2"
$arr=$var.Split("->")
$arr[0]#show correct: "test.1"
$arr[1]#doesn't show...
The string Split() method takes an array of characters and splits the string on any character that is in the array. Powershell also has a -split operator that takes a delimiter. I think you probably wanted to use the -split operator here.
Here's the difference. The first splits at both the '-' and the '>', the second splits on the '->':
PS C:\> $var.Split("->")
test.1
test.2
PS C:\> $var -split "->"
test.1
test.2
Note that split takes a regular expression pattern rather than a simple string. While that is fine for this particular pattern other punctuation could provide problems requiring you to escape special characters in the pattern or use the SimpleMatch option:
PS C:\> "a[b" -split "[",0,"SimpleMatch"
a
b
It works. But it did split the string by "-" OR ">", so $arr[1] has empty string between "-" and ">", and "test.2" is in $arr[2].
So you can either:
$var="test.1->test.2"
$arr=$var.Split("->")
write-host $arr[0]
write-host $arr[2]
or:
$var="test.1->test.2"
$arr=$var.Split("->") | select -First 1 -Last 1
write-host $arr[0]
write-host $arr[1]
or something like:
$var="test.1->test.2"
$arr= $($var -replace "->","#").Split("#")
write-host $arr[0]
write-host $arr[1]

Match strings stored in variables using PowerShell

I am attempting to create a backup script that will move files that are older that 30 days, but I want to be able to exclude folders from the list
$a = "C:\\Temp\\Exclude\\test"
$b = "C:\\Temp\\Exclude"
if I run the following:
$a -match $b
Following PowerShell Basics: Conditional Operators -Match -Like -Contains & -In -NotIn:
$Guy ="Guy Thomas 1949"
$Guy -match "Th"
This returns true.
I'd say use wilcards and the like operator, it can save you a lot of head aches:
$a -like "$b*"
The match operator is using regex pattern and the path is having regex special characters in it (the escape characeter). If you still want to use -match - make sure to escape the string:
$a -match [regex]::escape($b)
This will work but keep in mind that it can match in the middle of the string, you can add the '^' anchor to tell the regex engine to match from the begining of the string:
$a -match ("^"+[regex]::escape($b))