powershellfile-extensionrename-item-cmdlet

Powershell - Add extension to files containing dots


I have a script that addes the extension .xml to files without an extension.

Get-ChildItem "C:\TEST" -file "*." | rename-item -NewName {"{0}.xml" -f $_.fullname}

This works perfectly for a file such as: BC Logistics SPA con Socio Duo - 2022-03-31 - FT 123456VESE

However, it does not work for a file such as: A.B.C. Mini MAGAZZINI - 2022-02-25 - FT MM9 000000123

This is because of the dots. The directory also contains files that already have .xml as extension, as well as .pdf-files.

How can I add the extenion .xml to files without an extension but with dots in them?

Excluding .pdf and .xml files is not an option as the directory also contains other files that are deleted in the process.


Solution

  • The challenge is that nowadays filename extensions are a convention, and that most APIs, including .NET's, consider anything after the last ., if any, to be the extension, even if it isn't meant to be one. E.g., in A.B.C. Mini, . Mini (sic) is considered the extension, whereas
    -Filter *. in effect only matches names that contain no . at all.

    If you're willing to assume that any file that doesn't end in . followed by 3 characters (e.g., .pdf) is an extension-less file, you can use the following:

    # Note: Works with 3-character extensions only, doesn't limit what those chars.
    #       may be.
    Get-ChildItem -File C:\TEST |
      Where-Object Extension -NotLike '.???' |
      Rename-Item -NewName { '{0}.xml' -f $_.FullName } -WhatIf
    

    Note: The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.

    If you need to match what characters are considered part of an extension more specifically and want to consider a range of character counts after the . - say 1 through 4 - so that, say, .1 and .html would be considered extensions too:

    # Works with 1-4 character extensions that are letters, digits, or "_"
    Get-ChildItem -File C:\TEST |
      Where-Object Extension -NotMatch '^\.\w{1,4}$' |
      Rename-Item -NewName { '{0}.xml' -f $_.FullName } -WhatIf
    

    Note the use of a regex with the -notmatch operator.

    Regex ^\.\w{1,4}$ in essence means: match any extension that has between 1 and 4 word characters (\w), where a word characters is defined as either a letter, a digit, or an underscore (_).

    See this regex101.com page for a detailed explanation and the ability to experiment.