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?
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).