Search code examples
powershellget-childitem

How do I use Get-ChildItem to return files that don't have an extension?


I want to get a list of files that don't have a filename extension. Consider the content of my directory to be:

folder
file1
file2.mp4

My goal would be to get file1 only.

Running Get-ChildItem -Exclude *.* -File returned nothing.

Running Get-ChildItem -Exclude *.* returned folder and file1.

Running Get-ChildItem -File returned file1 and file2.mp4.

Any idea if there is any way of using Get-ChildItem to only return file1?


Solution

  • In PowerShell v3+ (including PowerShell (Core) 7):

    Get-ChildItem -File -Filter *.
    
    • -File limits output to just files (as opposed to directories).

    • -Filter *. selects only those files that have no extension.

    -Filter is generally preferable to -Include / -Exclude for performance reasons, because it filters at the source, rather than returning all objects and letting PowerShell do the filtering.

    In PSv2, where the -File switch isn't available, you need an additional Where-Object call to limit the results to files, as TheIncorrigible1 points out:

    Get-ChildItem -Filter *. | Where-Object { -not $_.PSIsContainer }
    

    Slower PowerShell (Core) 7 solution:

    Get-ChildItem -File | Where-Object -Not Extension
    

    Optional background information:

    That a -Filter argument is processed by the underlying provider, means that its behavior may differ from PowerShell's native capabilities, which is indeed the case here: the FileSystem provider uses the Windows API's wildcard-expression matching, which has fewer features than PowerShell's wildcards as well as some historical quirks; also, it is limited to a single wildcard expression, whereas -Include / -Exclude support multiple ones (separated with ,).

    Here, however, -Filter offers something that PowerShell's wildcard matching doesn't: using *. to match files / directories without extension.

    -Include / -Exclude generally offer functional advantages at the expense of performance, but they have their own limitations and quirks:

    • *. isn't supported to match items without extension in PowerShell's wildcard expressions.

    • -Include / -Exclude operate on the last component of the specified or implied path, so if you're implicitly targeting the current directory, they apply to that directory path, not to the individual files inside the directory.

    • Specifying -Recurse changes that, but that searches the entire directory subtree.

    • While you should be able to add -Depth 0 to limit matches to the immediate child items while still being able to apply -Include / -Exclude, this is broken in Windows PowerShell: The -Depth argument is ignored in this case.
      This problem has been fixed in PowerShell (Core) 7, however.

    In short: -Include / -Exclude offer no solution here.