Is using Select-Object suitable when you don't have access to -Extension?

181 Views Asked by At

In Powershell v6, the split-path has the -Extension parameter to access the extension of a file name, for example:

$pathToResume = "R:\Work\cover.letter_resume_base.odt"
$extension = Split-Path -Extension $pathtoResume
Write-Output $extension # Will print .odt

However, Powershell 3 doesn't provide the -Extension parameter, but I came up with this solution:

# Notice the period between cover and letter
$pathToResume = "R:\Work\cover.letter_resume_base.odt"
$pathToResumeLeaf = Split-Path -Leaf $pathToResume
$pathToResumeLeafArray = $pathToResumeLeaf.Split(".")

$fileExtension = $pathToResumeLeafArray | Select-Object -Last 1
Write-Output $fileExtension # Will print odt

I still get the file extension, but without the period. No matter how many periods are in the filename or the length of the array, I will get the same output.

I can't think of any situation where the period is required. If I wanted to print the period with the extension, I can easily add it when I use Write-Output or [string]::format()

Is Select-Object as I've shown above a viable solution when -Extension is unavailable?

1

There are 1 best solutions below

1
On BEST ANSWER

With a path string as the input, a concise and performant - though a bit obscure - PowerShell-native solution is to use the
-replace operator to extract the extension using a regex:

PS> "R:\Work\cover.letter_resume_base.odt" -replace '^.+(\.[^.]+)$', '$1'
.odt

Note: This solution only works reliably if the file path has an extension.

Alternatively, use the .NET framework directly, as Theo suggests:

PS> [IO.Path]::GetExtension("R:\Work\cover.letter_resume_base.odt")
.odt

You can also cast to [System.IO.FileInfo] and access the .Extension property:

PS> ([IO.FileInfo] "R:\Work\cover.letter_resume_base.odt").Extension
.odt

The above is a faster and more flexible alternative to LotPings' Get-Item suggestion, which, as Theo points, requires that the file exist:

# Works, but file must exist.
PS> (Get-Item "R:\Work\cover.letter_resume_base.odt").Extension
.odt

Is Select-Object, as shown above, a viable solution when -Extension is unavailable?

Yes, it is, but it is verbose and slow (though performance may not matter in this case), because using the pipeline and cmdlets invariably introduces overhead compared to using expressions involving operators.

LotPings points out that simply indexing with [-1] into the results of the .Split() call to extract the last token is both more concise and faster.

Also, consider routinely using PowerShell's -split operator instead of the [string] type's .Split() method:

PS> '.' + ("R:\Work\cover.letter_resume_base.odt" -split '\.')[-1]
.odt

As for whether or not to retain the initial . as part of the extension:

Either way, works, as long as you make sure the . is there when you synthesize a filename, but retaining the . has two advantages:

  • looking at the value makes it obvious that you're dealing with an extension

  • you can directly append the value to a file's base name (e,g, $baseName + $ext), which also works in the case when there's no extension (if $ext happens to contain the empty string).