PowerShell Problem Solver: In Case it Matters
Most of the time, Windows IT pros don’t worry too much about case. For the most part, PowerShell doesn’t care if something is upper case or lower case, and PowerShell commands are not case sensitive. Today, I want to tackle a problem where case does matter to you.
For the my demonstration, I’m going to define a variable with a case-sensitive string.
$var = "I am SOME type of STRING that needs TO BE REVISED: FOO_BAR/TEST"
And I’ll say that this string is representative of many strings that need to be processed. If you wanted to make the entire string lower case, that’s a pretty simple to do
You can also make the string upper case:
But let’s make this a bit more difficult. I’m going to say that I have the text FOO_BAR that needs to be converted to lower case, but the rest of the string should remain the same.
One approach is to use the Replace() method on the string object, which just happens to be case-sensitive.
You can also use the –Replace operator.
$var -replace "FOO_BAR","foo_bar"
Both methods will give you the same result.
This is very easy assuming you know ahead of time what string you want to search for. You could even use variables:
$text = "Foo_Bar" $var -replace $text.toUpper(),$text.ToLower()
But let’s make it more complicated because nothing is ever easy. Let’s say we have no idea what text will be in place of FOO_BAR. All we know for sure is that it will follow “: ” and precede /TEST. In other words, there’s a pattern.
If there’s a pattern, then we can use regular expressions. Don’t run away.
First, I’ll make it easy and take a step back by saying the text to be replaced will be some work followed by an underscore and then another word. I can test the pattern like this:
$var -match "\w+_\w+"
Knowing that there is a match, I can do the replacement like this:
$var -replace $Matches.values, $Matches.values.toLower()
Now that I’ve proved my concept, if I need a more complicated regular expression pattern, once I work it out, then I can easily do the replacement. In my example, one such pattern can include regular expression “look behinds” and “look aheads”.
$var -match "(?<=:\s)\w+(?=\/)"
A look behind is a way of doing a pattern match that says, “Match something where just before it you see this pattern, but don’t include that in the match.” In my regular expression pattern, this is (?<=:\s). The “?<=” is the look behind indicator. The “:\s” is the pattern, which means a colon followed by a space. The look ahead is (?=\/), which means, “look ahead of the pattern for a /. The slash needs to be escaped, which is why it looks like \/. The “real” thing I am looking for is merely a group of work characters (\w+). These are handy regular expression techniques for getting exactly the pattern you want. But as with all things regex, you have to know what you are looking for, and it has to be consistent.
The last iteration of my solution is to use a regular expression object.
[regex]$rx = "(?<=:\s)\w+(?=\/)"
I can match the string like this:
This is just another type of object.
See where I’m going with this?
$m = $rx.Match($var) $var -replace $m.Value, $m.value.ToLower()
Finally, you could condense this because the regex object can do the replacing for you.
You’ll get the same result.
It wouldn’t take much more work to put this inside a ForEach loop or using ForEach-Object to process multiple strings.
There’s a lot going on in this article and if you are still new to regular expressions your head might reel a bit. I know mine did when I was getting started with regular expressions. So go ahead. Practice and play. If you’re still stuck or confused, feel free to leave a comment or track me down on Twitter.