File Output in Powershell without Extension

Pass the file name to the GetFileNameWithoutExtension method to remove the extension:

Get-ChildItem "C:\Folder" | `
    ForEach-Object { [System.IO.Path]::GetFileNameWithoutExtension($_.Name) } `
    > C:\Folder\File.txt

I wanted to comment on @MatthewMartin's answer, which splits the incoming file name on the . character and returns the first element of the resulting array. This will work for names with zero or one ., but produces incorrect results for anything else:

  • file.ext1.ext2 yields file
  • powershell.exe is good for me. Let me explain to thee..doc yields powershell

The reason is because it's returning everything before the first . when it should really be everything before the last .. To fix this, once we have the name split into segments separated by ., we take every segment except the last and join them back together separated by .. In the case where the name does not contain a . we return the entire name.

ForEach-Object {
    $segments = $_.Name.Split('.')

    if ($segments.Length -gt 1) {
        $segmentsExceptLast = $segments | Select-Object -First ($segments.Length - 1)

        return $segmentsExceptLast -join '.'
    } else {
        return $_.Name
    }
}

A more efficient approach would be to walk backwards through the name character-by-character. If the current character is a ., return the name up to but not including the current character. If no . is found, return the entire name.

ForEach-Object {
    $name = $_.Name;

    for ($i = $name.Length - 1; $i -ge 0; $i--) {
        if ($name[$i] -eq '.') {
            return $name.Substring(0, $i)
        }
    }

    return $name
}

The [String] class already provides a method to do this same thing, so the above can be reduced to...

ForEach-Object {
    $i = $_.Name.LastIndexOf([Char] '.');

    if ($i -lt 0) {
        return $_.Name
    } else {
        return $_.Name.Substring(0, $i)
    }
}

All three of these approaches will work for names with zero, one, or multiple . characters, but, of course, they're a lot more verbose than the other answers, too. In fact, LastIndexOf() is what GetFileNameWithoutExtension() uses internally, while what BaseName uses is functionally the same as calling $_.Name.Substring() except it takes advantage of the already-computed extension.


(ls).BaseName > C:\Folder\File.txt

Get-ChildItem "C:\Folder" | Select BaseName > C:\Folder\File.txt

And now for a FileInfo version, since everyone else beat me to a Path.GetFileNameWithoutExtension solution.

Get-ChildItem "C:\" | `
where { ! $_.PSIsContainer } | `
Foreach-Object {([System.IO.FileInfo]($_.Name)).Name.Split('.')[0]}