SOLVED

Rename files the have wildcard in the name

Copper Contributor

I have a folder with files that have wildcards like "[]-"  in the name (ex: abc[def]-ghi.txt).  I get errors stating the the file does not exist.  To get around this I went into MS Powertoys and did a bulk rename removing those characters. Is there a way to ignore these wildcards?

2 Replies
best response confirmed by JimB920 (Copper Contributor)
Solution

@JimB920 

 

From a Windows file system perspective, those aren't wildcard characters, which is why they're allowable in a filename to begin with.

 

Understanding the real issue

Figure 1 below contains three example commandlets:

 

  • The first Get-ChildItem is purely to show the filenames we're focusing on - one of which is your example filename of "abc[def]-ghi.txt";
  • The second example shows how to trigger the error you're talking about;
  • The third example shows a working example on how to "properly" locate the files.

 

LainRobertson_0-1679311475587.png

Figure 1: PowerShell Get-ChildItem examples.

 

As an additional cross-check, we can easily check for the same files under a command prompt as shown below (Figure 2), confirming that the characters are perfectly allowable in a file name (in fact the minus sign is one of the more common filename delimiters around.)

 

LainRobertson_1-1679311714160.png

Figure 2: DOS cross-check to avoid the PowerShell fluffery.

 

Conversely, if you do try and use an actual file system-specific wildcard - I'm using the question mark in my example below (Figure 3), it simply won't feature in the resulting file name:

 

LainRobertson_2-1679311788648.png

Figure 3: The wildcard (question mark) is stripped out of the requested filename.

 

What's going on in PowerShell then?

The error from Get-ChildItem is not from the file system at all, as these are not wildcard characters. Rather, the error is coming specifically from the Get-ChildItem commandlet, as in its internal workings it appears to be leveraging something called a regular expression to perform the pattern matching, and it's actually this regular expression throwing the error, not the file system.

 

Specifically, the error is being cause by the opening square parenthesis (i.e. "[").

 

If you go back up and look at the third example from Figure 1, you'll notice that I had to do some funky escaping in the first  "-Include" value (i.e. "*[\[]*") while for the second value, I did not (i.e. "*]*").

 

This is because the "[" has a special meaning to a regular expression, and it's this specific character - not the minus sign or closing square bracket (at least not when it's on its own) - that is generating your "pattern is not valid" error.

 

I'm not going to get into the specifics on why - you can look up ".NET regular expression syntax" if you want to learn more about them.

 

Removing undesirable characters

Now that we're reviewed the real cause of the error, that still leaves your question on removing these additional characters unanswered.

 

Ironically, while a regular expression is the root cause of your error, it's also the mechanism for providing the solution,

 

Note: I would strongly suggest you leave the minus symbol alone, however, as you've included it in your question, I'll include it in the sample solution below.

 

In short, what you want to do can be reduced to two steps:

 

  1. Find the files you wish to rename using the combination of Get-ChildItem and a regular expression; and
  2. Rename the file name to exclude the characters of your choosing (noting once again that they are not wildcard characters as far as the file system is concerned.)

 

Sample script

Get-ChildItem -Path "D:\Data\Temp\Forum" -Recurse |
    Where-Object {
        [regex]::IsMatch($_.Name, "[-\[\]]", [System.Text.RegularExpressions.RegexOptions]::CultureInvariant)
    } |
        ForEach-Object {
            $NewName = [regex]::Replace($_.Name, "[-\[\]]", "", [System.Text.RegularExpressions.RegexOptions]::CultureInvariant);
            $_ | Rename-Item -NewName $NewName -Force -ErrorAction:SilentlyContinue;
        }

 

And here's the output (Figure 4) - using a couple of variations of the above script purely to demonstrate how we get to the final version.

 

LainRobertson_3-1679314145640.png

Figure 4: Journey from start to end with the undesired characters removed.

 

The first command only serves to show the original file names featuring the characters we want to remove.

 

The second command is like a preview of what's coming once we do actually rename the files, but we haven't done the renaming yet.

 

The third command is the actual execution of the script above from which there's no output.

 

The fourth command is a simple directory listing which confirms that the script from above has indeed renamed the file to exclude the undesired characters.

 

The key to this solution are the regular expressions on lines 3 and 6.

 

The regular expression on line 3 is purely to identify if the filename has characters we want to replace, while the actual character replacement and file renaming takes places on lines 6 and 7.

 

Technically, this script is a little verbose - which was deliberate so I could clearly illustrate the thinking in code. From a functional perspective, the example script can be compressed down to something like this by omitting the Where-Object statement:

 

Get-ChildItem -Path "D:\Data\Temp\Forum" -Recurse |
    ForEach-Object {
        if (($NewName = [regex]::Replace($_.Name, "[-\[\]]", "", [System.Text.RegularExpressions.RegexOptions]::CultureInvariant)).Length -ne $_.Name.Length)
        {
            $_ | Rename-Item -NewName $NewName -Force -ErrorAction:SilentlyContinue;
        }
    }

 

Cheers,

Lain

Sorry, I should've replied earlier. I was able to using the -replace option in the script to replace those characters ([ ] -) with a "?" and everything worked the way I hoped. I do like your other options, I will try to experiment with those. I feel I'm still new to Powershell

Still learning
Jim
1 best response

Accepted Solutions
best response confirmed by JimB920 (Copper Contributor)
Solution

@JimB920 

 

From a Windows file system perspective, those aren't wildcard characters, which is why they're allowable in a filename to begin with.

 

Understanding the real issue

Figure 1 below contains three example commandlets:

 

  • The first Get-ChildItem is purely to show the filenames we're focusing on - one of which is your example filename of "abc[def]-ghi.txt";
  • The second example shows how to trigger the error you're talking about;
  • The third example shows a working example on how to "properly" locate the files.

 

LainRobertson_0-1679311475587.png

Figure 1: PowerShell Get-ChildItem examples.

 

As an additional cross-check, we can easily check for the same files under a command prompt as shown below (Figure 2), confirming that the characters are perfectly allowable in a file name (in fact the minus sign is one of the more common filename delimiters around.)

 

LainRobertson_1-1679311714160.png

Figure 2: DOS cross-check to avoid the PowerShell fluffery.

 

Conversely, if you do try and use an actual file system-specific wildcard - I'm using the question mark in my example below (Figure 3), it simply won't feature in the resulting file name:

 

LainRobertson_2-1679311788648.png

Figure 3: The wildcard (question mark) is stripped out of the requested filename.

 

What's going on in PowerShell then?

The error from Get-ChildItem is not from the file system at all, as these are not wildcard characters. Rather, the error is coming specifically from the Get-ChildItem commandlet, as in its internal workings it appears to be leveraging something called a regular expression to perform the pattern matching, and it's actually this regular expression throwing the error, not the file system.

 

Specifically, the error is being cause by the opening square parenthesis (i.e. "[").

 

If you go back up and look at the third example from Figure 1, you'll notice that I had to do some funky escaping in the first  "-Include" value (i.e. "*[\[]*") while for the second value, I did not (i.e. "*]*").

 

This is because the "[" has a special meaning to a regular expression, and it's this specific character - not the minus sign or closing square bracket (at least not when it's on its own) - that is generating your "pattern is not valid" error.

 

I'm not going to get into the specifics on why - you can look up ".NET regular expression syntax" if you want to learn more about them.

 

Removing undesirable characters

Now that we're reviewed the real cause of the error, that still leaves your question on removing these additional characters unanswered.

 

Ironically, while a regular expression is the root cause of your error, it's also the mechanism for providing the solution,

 

Note: I would strongly suggest you leave the minus symbol alone, however, as you've included it in your question, I'll include it in the sample solution below.

 

In short, what you want to do can be reduced to two steps:

 

  1. Find the files you wish to rename using the combination of Get-ChildItem and a regular expression; and
  2. Rename the file name to exclude the characters of your choosing (noting once again that they are not wildcard characters as far as the file system is concerned.)

 

Sample script

Get-ChildItem -Path "D:\Data\Temp\Forum" -Recurse |
    Where-Object {
        [regex]::IsMatch($_.Name, "[-\[\]]", [System.Text.RegularExpressions.RegexOptions]::CultureInvariant)
    } |
        ForEach-Object {
            $NewName = [regex]::Replace($_.Name, "[-\[\]]", "", [System.Text.RegularExpressions.RegexOptions]::CultureInvariant);
            $_ | Rename-Item -NewName $NewName -Force -ErrorAction:SilentlyContinue;
        }

 

And here's the output (Figure 4) - using a couple of variations of the above script purely to demonstrate how we get to the final version.

 

LainRobertson_3-1679314145640.png

Figure 4: Journey from start to end with the undesired characters removed.

 

The first command only serves to show the original file names featuring the characters we want to remove.

 

The second command is like a preview of what's coming once we do actually rename the files, but we haven't done the renaming yet.

 

The third command is the actual execution of the script above from which there's no output.

 

The fourth command is a simple directory listing which confirms that the script from above has indeed renamed the file to exclude the undesired characters.

 

The key to this solution are the regular expressions on lines 3 and 6.

 

The regular expression on line 3 is purely to identify if the filename has characters we want to replace, while the actual character replacement and file renaming takes places on lines 6 and 7.

 

Technically, this script is a little verbose - which was deliberate so I could clearly illustrate the thinking in code. From a functional perspective, the example script can be compressed down to something like this by omitting the Where-Object statement:

 

Get-ChildItem -Path "D:\Data\Temp\Forum" -Recurse |
    ForEach-Object {
        if (($NewName = [regex]::Replace($_.Name, "[-\[\]]", "", [System.Text.RegularExpressions.RegexOptions]::CultureInvariant)).Length -ne $_.Name.Length)
        {
            $_ | Rename-Item -NewName $NewName -Force -ErrorAction:SilentlyContinue;
        }
    }

 

Cheers,

Lain

View solution in original post