December 27th, 2015

Weekend Scripter: Remove a Long Path File

Doctor Scripto
Scripter

Summary: Boe Prox shows how to remove a file with a long path.

Honorary Scripting Guy and Cloud and Datacenter Management MVP, Boe Prox, here today filling in for my good friend, the Scripting Guy.

This is a continuation of this weekend series on working with PowerShell and PInvoke to do things that you normally couldn’t do natively. Also see Manage Window Placement by Using PInvoke.

Today I am continuing my approach of working with PInvoke by using Add-Type to compile C# code that contains the PInvoke signatures to show that it can be pretty easy to pull together and use a Windows API when we need it.

Yesterday I showed an approach to locate and move a window on the screen, which is pretty neat, but ultimately, probably a novelty. Today I will show something that may be of more use for removing a file or folder that can’t be deleted normally because the length of the path exceeds a MAX_PATH limitation of 260 characters. Although this is a limit in the API, it doesn’t mean that we cannot get around it with a little help from a PInvoke signature and knowing how to provide the proper path to the file.

To show my dilemma, I have a file called PleaseDeleteMe.txt which was created by someone who mapped a drive to a location deep in the file system. When I attempt to delete this file, I am greeted with an error message that states the path is too long to reach in and delete the file.

Image of error message

Actually in this case, because it cannot get beyond that character length limit, it doesn’t even know that this file exists, let alone be able to remove it. Regardless, we have an issue on hand if we want to remove this file. We could remove it by mapping a drive letter to a folder deeper down in the file system, then navigate to that new drive letter and remove the file. Or we could use Robocopy (it allows us to bypass the API limit and remove the file). Or we can use the DeleteFile PInvoke signature to accomplish this. Of course, we are going to go the PInvoke route and remove that file via PowerShell.

First we need to see that signature on PINVOKE.NET and copy it into a here-string so we can compile that into a usable type.

Image of menu

The only signature that I am worried about here is the first one (DeleteFile), and I will work to compile that into our new type:

Add-Type @"

    using System;

    using System.Runtime.InteropServices;

    public class LongFilePath {

        [DllImport("kernel32.dll", SetLastError = true)]

        [return: MarshalAs(UnmanagedType.Bool)]

        public static extern bool DeleteFile(string lpFileName);      

    }

"@

[LongFilePath]::DeleteFile

Image of command output

Don’t let the parameter fool you by thinking it will take a string path like what we are used to. If you supply the full file path as-is, you will be greeted with disappointment:

Image of command output

The return value of $False tells us that we were not successful in removing the file from the folder. Why didn’t this work?

We are using the Windows API to call DeleteFile, so that should “just work,” right? Well, that is mostly true—except for the part where we have to adjust the format of the file path into something else that will tell the API to bypass that limit on the path. The trick is to make the file path acceptable by prepending a ‘\\?\’ to the path so that the DeleteFile function treats it differently and allows us to remove the file.

$File = '\\?\C:\thisisaveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryveryverylongdirectory\NestedFolder\AnotherNestedFolder\PleaseDeleteMe.txt'

[LongFilePath]::DeleteFile($File)

Image of command output

The return value of $True tells us that this file has been successfully removed from the long folder path. A quick look at the folder that this file resided in proves that this is accurate.

Image of menu

Using a windows API function and formatting the full path properly by prepending a UNC path allowed us to easily remove a problem file that was buried deeply in the folder structure without no issue at all.

I wrote a simple function to make this process a little easier. All you have to do is copy the file path and use Remove-LongPathFile with the –Path parameter to remove the file. It also accepts input via the pipeline to remove more files. Here is a quick example:

Image of command output

So you now have a way via the PowerShell console to remove files that are buried deeply in the file system, which would normally prevent you from easily handling their deletion!

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

Boe Prox, Microsoft Cloud and Datacenter Management MVP and Honorary Scripting Guy 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • Alina Valker

    I have been using long path tool. It is very easy and can delete, copy, move and bulk rename long path files or locked file.