PowerShell Basics: Detecting if a String Ends with a Certain Character
Published Jan 02 2019 12:01 AM 112K Views
Microsoft

Did you know you can detect if a string ends in a specific character or if it starts in one in PowerShell? Thomas Rayner previously shared on CANITPRO.NET how this can be easily done by using regular expressions or more simply know as Regex.  Consider the following examples:
 

'something\' -match '\\$'
#returns true

'something' -match '\\$'
#returns false

'\something' -match '^\\'
#returns true

'something' -match '^\\'
#returns false

In the first two examples, the script checks the string ends to see if it ends in a backslash. In the last two examples, the script check the string to see if it starts with one.

 

The regex pattern being matched for the first two is \\$ . What’s that mean? Well, the first part \\ means “a backslash” (because \ is the escape character, we’re basically escaping the escape character. The last part $ is the signal for the end of the line. Effectively what we have is “anything at all, where the last thing on the line is a backslash” which is exactly what we’re looking for.

 

In the second two examples, I’ve just moved the \\ to the start of the line and started with ^ instead of ending with $ because ^ is the signal for the start of the line.

 

Now you can do things like this:
 

$dir = 'c:\temp'
if ($dir -notmatch '\\$')
{
$dir += '\'
}
$dir
#returns 'c:\temp\'

Here, the script checks to see if the string ‘bears’ ends in a backslash, and if it doesn’t, I’m appending one. 

 PowerShell Basics SeriesPowerShell Basics Series

 

11 Comments
Deleted
Not applicable
There's no need for .+?. You could just use the pattern '\\$' to match a backslash at the end. Ditto for begins with '^\\'.
Microsoft

@Deleted updated as per your suggestion.  Thank you for the tip!


Copper Contributor

I don't think this situation really calls for regex.

 

PowerShell is capable of indexing a string just like a character array, and its comparison system can convert data types when needed. As a result, you can do something very straightforward like this:

$String = "When Lords and Ladies quest for fame, a Beast will touch the land with flame."

if ( $String[-1] -eq '.' ) {
    # Do something
}
else {
# Do something else
}

Also, if this is about checking if a path is a container or leaf object, you can do that much more effectively, thoroughly, and verbosely like this:

Test-Path -Path "C:\MyFolder" -PathType Container

And if the path might not exist you can add -IsValid to that call, although in that case I believe the -PathType isn't particularly useful there and then, perhaps, some more manual checking might be a bit more useful depending on your specific use case.

 

Copper Contributor

Nice.

Copper Contributor

Another method (and the one I prefer) is to use the -Like comparison operator:

if ("something\" -like "*\") {
    Write-Host "Ends in a backslash."
}
else {
    Write-Host "Does not end in a backslash."
}

 

With this method you don't need to escape the backslash, and it uses an asterisk to match any text (or none) before the backslash.

Microsoft

@Tonedef Thank you for the share.  Let me know if there are any other PowerShell tips you'd be interested in use researching and sharing.

Copper Contributor

Quick question, is this faster than the in-built $var.EndsWith("string") ?

Copper Contributor

Using Windows PowerShell 5.1, EndsWith() and -like are almost twice as fast as RegEx, across 100,000 iterations each (using the code below). @TheDammedGamer

 

RegEx method: 295 ms
EndsWith method: 189 ms
Like method: 160 ms

 

 

using namespace System.Diagnostics

$stopwatch = [Stopwatch]::StartNew();
for ($i = 0; $i -lt 100000; $i++) {
    $boolValue = 'something\' -match '\\$'
}
"RegEx method: $($stopwatch.ElapsedMilliseconds) ms "

$stopwatch = [Stopwatch]::StartNew();
for ($i = 0; $i -lt 100000; $i++) {
    $boolValue = 'something\'.EndsWith('\')
}
"EndsWith method: $($stopwatch.ElapsedMilliseconds) ms "

$stopwatch = [Stopwatch]::StartNew();
for ($i = 0; $i -lt 100000; $i++) {
    $boolValue = 'something\' -like '*\'
}
"Like method: $($stopwatch.ElapsedMilliseconds) ms "

Copper Contributor

Quick comparison of 100 iterations of testing a simple string "hello" and checking for the last letter:

 

$string.EndsWith("o") - 10.5 ms
$string -like "*o" - 11 ms
$string -match "o$" - 35 ms
$string[-1] -eq "o" - 14 ms

Using Measure-Command.

 

.EndsWith() is the quickest method in most cases, I would venture. Ran @Anthony Bartolo's code and got the following results in PS Core 6.1.0:

RegEx method: 1229 ms
EndsWith method: 459 ms
Like method: 594 ms

(With a rather lacklustre machine ;) )

Copper Contributor

@Joel Francis I just installed PS Core 6.1.1 and got similar results as you. I also tested your array index method and it's even faster than .EndsWith():

 

RegEx method: 125 ms
EndsWith method: 17 ms
Like method: 52 ms
Array index method: 9 ms

  

Code for array index method:

 

$stopwatch = [Stopwatch]::StartNew();
for ($i = 0; $i -lt 100000; $i++) {
    $boolValue = 'something\'[-1] -eq '\'
}
"Array index method: $($stopwatch.ElapsedMilliseconds) ms "

 

Also, the times in my previous comment were generated using the play button (Run Script) in Windows PowerShell ISE, which adds debugging overhead. When I run it directly in PowerShell.exe (5.1.1) I get similar results to PS Core:

 

RegEx method: 127 ms 
EndsWith method: 23 ms 
Like method: 44 ms 
Array index method: 14 ms 

 

(In the end, unless you're checking the ends of many strings or performance matters a lot, it doesn't really matter what method you use. Personally I'll probably stick with -Like because I like it. ;)

Copper Contributor

$dir.trimend('\') + '\'

Version history
Last update:
‎Nov 09 2023 11:09 AM
Updated by: