powershellsplitpowershell-3.0powershell-v6.0

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


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?


Solution

  • 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: