Use PowerShell to Detect and Fix Files with Leading Spaces

Use PowerShell to Detect and Fix Files with Leading Spaces

  • Comments 4
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to detect and to fix files that have leading spaces in the file name.

Hey, Scripting Guy! Question Hey, Scripting Guy! I am hoping that you can help me. We have a rather strange problem at work, and if I do not get to the end of it, I am afraid I might be looking for a new job. The reason is that for some reason we are getting files that have a leading space in the file name on one of our storage servers. This is only part of the problem because our backup program is rather old. It works—except that it fails when it finds a file with a leading space in the file name. You might say we should upgrade our backup program, and that would be fine, except that our tape array is no longer supported and new backup programs do not have the correct driver. I know, I know, I know. But, for now, I need to figure out a way to detect files that are getting this leading space in the file name. As luck would have it, the way we found out that the files were not getting backed up is that our CEO corrupted one of the files that had the leading space in it, and when we attempted to restore the file, we discovered the problem. Of course, we did not replace the guy who was in charge of backups and who must have been the last planet to know about the software and the old tape array, but no one wants to hear about that. Well anyway, now I am “on notice” and I am really hoping you can help me.

—KS

Hey, Scripting Guy! Answer Hello KS,

Microsoft Scripting Guy, Ed Wilson, is here. Wow! KS, I am sorry things have not been going so well for you recently. I am really saddened to hear about your problems at work. To be honest, I do not think I have ever created a file with a leading space in the name—don’t know why I would want to do so. As a matter of a fact, I am not certain that until I read your email to scripter@microsoft.com, I even knew that one could create a file with a leading space in it.

The first thing I decided to do was to create a file with a leading space in it. I opened Windows File Explorer, and created a new text file with 10 leading spaces. This is shown in the image that follows.

Image of menu

But when I pressed ENTER, it seems that Windows Explorer stripped out the leading spaces. This is shown in the image that follows.

Image of menu

Of course, the best way to check this is to use Windows PowerShell. To do this, I run the following Windows PowerShell code, which gets the length of the file name, and uses the Trim string method to remove excess spaces. Nothing returns, which lends credence to my suspicion.

PS C:\a> gci -Recurse | % { if($_.name.length -ne $_.name.trim().length) { "file with space"}}

KS, based on this easy test, it would seem that Windows File Explorer, at least, does not permit creating files with spaces at the beginning of the name. So someone is using some other method to create the files. If I am going to test my code, I need a quick easy way to create files with leading spaces. To do that, I need to use Windows PowerShell. I create a function called New-FilesWithLeadingSpaces. This function accepts three parameters. The first is the path to create the files, and the second is a base file name parameter. I set the default value to myfile.txt, but you could use any string you choose to do this. The final parameter is Count, which tells the function how many files to create. Inside the function, I have a for loop that counts up to the Count property. Inside the loop I create a space padding string that I prepend to each FileBaseName. Of course the ItemType is file. Here is the new New-FilesWithLeadingSpaces function:

Function New-FilesWithLeadingSpaces

{

 Param([string]$path = "c:\test",

       [string]$FileBaseName = "myfile.txt",

       [int]$count)

  For($i = 0; $i -le $count ;$i ++)

    { $pad = " " * $i

     New-item -Path $path -Name "$pad$FileBasename" -ItemType file}

} #end function new-FileWithLeadingSpaces

When I run the script, I bounce over to the Windows File Explorer, and it is obvious that Windows does, in fact, permit files with a leading space—KS, a fact unfortunately of which you are painfully aware. The Windows File Explorer results are shown here:

Image of menu

So, I created a new function called Get-FilesWithLeadingSpaces. This function accepts a single parameter, Path, which specifies from whence the search begins. Next, the Get-ChildItem cmdlet with the –recurse switch is used to return the FileInfo objects that are piped to the Foreach-Object cmdlet. Inside the loop, the length of a file name is compared with the length of the file name after using the Trim method to remove any trailing spaces. Using the Trim string method is perfect for this application. The following illustrates using Trim. First, a variable that holds five spaces and the word fiveSpaces is created. That value displays and shows that there are five spaces preceding the value. Now, the Trim method is called to remove the spaces. This is shown here:

PS C:\a> $name = "     fiveSpaces"

PS C:\a> $name

     fiveSpaces

PS C:\a> $name.Trim()

fiveSpaces

If the length of the trimmed file name is not equal to the file name, it means that it contains either leading or trailing spaces. Therefore, the file name displays to the console. The complete function is shown here:

Function Get-FilesWithLeadingSpaces

{

 Param([string]$path = "c:\a")

 Get-ChildItem -Path $path -Recurse |

 foreach-object {

   if($_.name.length -ne $_.name.trim().length)

    { "$($_.basename) contains a leading space"} }

} #end function Get-FilesWithLeadingSpaces

When the function loads and is run, the output in the Windows PowerShell ISE appears as shown here:

Image of command output

If there was only one file, renaming it might not be too bad. But in the case of my example, if I renamed each file after removing the leading spaces, I would end up with a bunch of duplicate files. Therefore, I decided to add a counter number to the file name after renaming it. Renaming a file in Windows PowerShell is trivial because there is a Rename-Item cmdlet that takes a Path and a new Name parameter. Rather than creating a new function with much of the same capabilities of the Get-FilesWithLeadingSpaces function (such as detecting files that have a leading space in the name, I decided instead to add a Rename switch to rename the files with leading spaces in the name. Adding a switched parameter is super easy in Windows PowerShell—all you do is use the [switch] type constraint in front of the variable name as shown here:

[switch]$rename

Because I wanted an easy way to create a unique file name, I added a counter variable at the Begin portion of the Foreach-Object command. In the Begin portion, I set the value of the $count variable to 0. This appears here.

-Begin {$count = 0}

When I detect that I have a file name with spaces either before or after the file name, I check to see if the $rename switch appears. If it does, the Rename-Item cmdlet renames the file. The path is the FullName property from the FileInfo object. The FullName property contains the complete path to the file, and it should always be used when working with files that are discovered via the Get-Item cmdlet (this is one good property name to remember). Next, the new name needs to be created. First I take the BaseName property—that is the file name without the path or the file extension. I trim that BaseName, and then I use the count number from the $count variable. Lastly, I add back in the file extension. The file extension is always available from the Extension property. If at any time you are not certain of what properties you have available to you, use the Get-Member cmdlet to display the properties of your file. This technique is shown here:

PS C:\a> Get-Item .\myfile.txt | Get-Member -MemberType property

 

   TypeName: System.IO.FileInfo

 

Name              MemberType Definition

----              ---------- ----------

Attributes        Property   System.IO.FileAttributes Attributes {get;set;}

CreationTime      Property   System.DateTime CreationTime {get;set;}

CreationTimeUtc   Property   System.DateTime CreationTimeUtc {get;set;}

Directory         Property   System.IO.DirectoryInfo Directory {get;}

DirectoryName     Property   System.String DirectoryName {get;}

Exists            Property   System.Boolean Exists {get;}

Extension         Property   System.String Extension {get;}

FullName          Property   System.String FullName {get;}

IsReadOnly        Property   System.Boolean IsReadOnly {get;set;}

LastAccessTime    Property   System.DateTime LastAccessTime {get;set;}

LastAccessTimeUtc Property   System.DateTime LastAccessTimeUtc {get;set;}

LastWriteTime     Property   System.DateTime LastWriteTime {get;set;}

LastWriteTimeUtc  Property   System.DateTime LastWriteTimeUtc {get;set;}

Length            Property   System.Int64 Length {get;}

Name              Property   System.String Name {get;}

The newly added rename clause appears here.

if($rename)

      {

        Rename-Item -Path $_.fullname -NewName ("{0}{1}{2}" -f `

         $_.basename.trim(),$count,$_.extension)

        $count++

        }

The complete function is shown here:

Function Get-FilesWithLeadingSpaces

{

 Param(

       [string]$path = "c:\a",

       [switch]$rename

       )

 Get-ChildItem -Path $path -Recurse |

 foreach-object -Begin {$count = 0} -process {

   if($_.name.length -ne $_.name.trim().length)

    {

     if($rename)

      {

        Rename-Item -Path $_.fullname -NewName ("{0}{1}{2}" -f `

         $_.basename.trim(),$count,$_.extension)

        $count++

        }

     else

      {"$($_.basename) contains a leading space"}} }

} #end function Get-FilesWithLeadingSpaces

After I run the function, I go back into the Windows File Explorer to see if it worked. As shown here, it worked perfectly.

Image of menu

KS, that is all there is to using Windows PowerShell to detect files that have leading spaces. Join me tomorrow for more good Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Hi Ed,

    stange enough ... but I'm not that KS even if these are the initials of my name (Klaus Schulte:-)

    Well it is a good example of how to do mass renames but there are two things to consider:

    1. The test " if($_.name.length -ne $_.name.trim().length) "

    does not necessarily indicate the presence of a name with leading spaces.

    We could as well have trailing spaces here!

    Trim() does delete spaces on both sides of the string.

    An Rtrim() or LTrim() function would be more specialized!

    2. We should always test the existence of a file before we try to rename it!

    If you run the function each day and the same files would be there again, we

    would always try to rename a file like an existing file ( maybe from yesterday's run)

    A test-path should preceed each rename operation imho :-)

    Klaus.

  • @K_Schulte glad to see you  back, I have missed your comments :-)

    You are absolutely correct that my test does NOT test only for leading spaces -- I knew that when I was writing it, but then did not point it out -- good catch, thanks! Your second point is absolutely correct as well, one should ALWAYS test for the existence of a file prior to doing the rename, because it would be possible of a name collision. I did not even think about doing this for the scenario answer. In fact, it would be best to test, and IF the name collision exists, automatically try additional names (perhaps adding a number) until the collision no longer exists.

  • A small change from

    if($_.name.length -ne $_.name.trim().length)

    to

    if($_.name.length -ne $_.name.trimstart().length)

    would fix the leading space only problem.

    Alan.

  • There is another way to create a file with blank trailing / leading spaces within File Explorer - use alt + 255 to insert the character and File Explorer won't undo your rename.

    I actually ran across this post while looking for the answer to a different but semi-related question. If you have a folder that involves blank spaces it completely chokes the get-childitem command. If you are running it on a folder with a blank (or running it with the recurse flag and one exists in the structure) it will choke up because it appears to always strip them out. I was looking for an easy way to get the child items under one of these folders without renaming it. The -literalpath flag doesn't seem to help.

    PS.

    If you want to torment the heck out of someone that runs PS scripts against your directory structure, name a folder with just a blank and it will cause an infinite recursion loop.