55

I'm writing a simple script to delete USMT migration folders after a certain amount of days:

## Server List ##
$servers = "Delorean","Adelaide","Brisbane","Melbourne","Newcastle","Perth"

## Number of days (-3 is over three days ago) ##
$days = -3

$timelimit = (Get-Date).AddDays($days)

foreach ($server in $servers)
{
    $deletedusers = @()
    $folders = Get-ChildItem \\$server\USMT$ | where {$_.psiscontainer}
    write-host "Checking server : " $server
    foreach ($folder in $folders) 
    {
        If ($folder.LastWriteTime -lt $timelimit -And $folder -ne $null)
        {
            $deletedusers += $folder
            Remove-Item -recurse -force $folder.fullname
        }
    }
        write-host "Users deleted : " $deletedusers
        write-host
}

However I keep hitting the dreaded Remove-Item : The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

I've been looking at workarounds and alternatives but they all revolve around me caring what is in the folder.

I was hoping for a more simple solution as I don't really care about the folder contents if it is marked for deletion.

Is there any native Powershell cmdlet other than Remove-Item -recurse that can accomplish what I'm after?

Martin Brandl
  • 56,134
  • 13
  • 133
  • 172
mhouston100
  • 1,173
  • 2
  • 19
  • 41

17 Answers17

60

I often have this issue with node projects. They nest their dependencies and once git cloned, it's difficult to delete them. A nice node utility I came across is rimraf.

npm install rimraf -g
rimraf <dir>
Andrew Chaa
  • 6,120
  • 2
  • 45
  • 33
  • 2
    Great! the robocopy solution worked partially, it removed some files but not everything. This rimraf works flawlessly. Thanks @Andy a lot! – Allan.C Jul 19 '16 at 02:25
48

Just as CADII said in another answer: Robocopy is able to create paths longer than the limit of 260 characters. Robocopy is also able to delete such paths. You can just mirror some empty folder over your path containing too long names in case you want to delete it.

For example:

robocopy C:\temp\some_empty_dir E:\temp\dir_containing_very_deep_structures /MIR

Here's the Robocopy reference to know the parameters and various options.

mguassa
  • 4,051
  • 2
  • 14
  • 19
Harald
  • 489
  • 4
  • 2
  • I can confirm that this solution works and it's the one I've used when I came across the same problem. – mguassa Jul 05 '15 at 19:31
  • Thank you so much for this! I've been trying to find a tool to delete borked folders names for years. – dotdawtdaught Feb 07 '17 at 23:21
  • This should be the answer.. its clean and lean no third party tools used – Egli Becerra Aug 16 '19 at 00:54
  • This worked for me but I had to add a removal step after robocopy mirrored it (Remove-Item). I was left with E:\temp\dirname with the empty dir contents. Thank you very much. I've been trying to figure this out for a while now!!! – Michele Oct 04 '19 at 19:19
29

I've created a PowerShell function that is able to delete a long path (>260) using the mentioned robocopy technique:

function Remove-PathToLongDirectory 
{
    Param(
        [string]$directory
    )

    # create a temporary (empty) directory
    $parent = [System.IO.Path]::GetTempPath()
    [string] $name = [System.Guid]::NewGuid()
    $tempDirectory = New-Item -ItemType Directory -Path (Join-Path $parent $name)

    robocopy /MIR $tempDirectory.FullName $directory | out-null
    Remove-Item $directory -Force | out-null
    Remove-Item $tempDirectory -Force | out-null
}

Usage example:

Remove-PathToLongDirectory c:\yourlongPath
Martin Brandl
  • 56,134
  • 13
  • 133
  • 172
  • 2
    FYI : in Windows 10 with build numbers 14393 (Anniversary update) the path limit bug in .NET has been fixed. You need to enable long path support in the local policies and you can do anything you want with long paths without having to resort to P/Invoke or robocopy – bluuf Sep 20 '16 at 16:16
  • 2
    This works like a dream. And there was me for months using subst z: myLongPath – Dean Meehan Oct 16 '18 at 10:07
  • 1
    This is the only solution on this page that worked for me. Thanks! – AndyJ Jul 29 '19 at 23:46
  • What about if the directories are in Windows Server 2016? – Senior Systems Engineer Jul 13 '20 at 05:54
22

This answer on SuperUser solved it for me: https://superuser.com/a/274224/85532

Cmd /C "rmdir /S /Q $myDir"
Community
  • 1
  • 1
Daniel Lee
  • 7,709
  • 2
  • 48
  • 57
  • This answer has worked some times in the past for me, but failed in removing my `node_modules` folder. For that case I resorted to [this other answer](http://stackoverflow.com/a/33692148/419956) as I hade node installed in that case anyways. – Jeroen Jan 06 '16 at 09:30
  • Didn't work for me either. It also risks failing with dirs with spaces deleting the wrong stuff (though that would be fixable) – arberg May 04 '18 at 16:12
21

I learnt a trick a while ago that often works to get around long file path issues. Apparently when using some Windows API's certain functions will flow through legacy code that can't handle long file names. However if you format your paths in a particular way, the legacy code is avoided. The trick that solves this problem is to reference paths using the "\\?\" prefix. It should be noted that not all API's support this but in this particular case it worked for me, see my example below:

The following example fails:

PS D:\> get-childitem -path "D:\System Volume Information\dfsr" -hidden


Directory: D:\System Volume Information\dfsr


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a-hs        10/09/2014  11:10 PM     834424 FileIDTable_2
-a-hs        10/09/2014   8:43 PM    3211264 SimilarityTable_2

PS D:\> Remove-Item -Path "D:\System Volume Information\dfsr" -recurse -force
Remove-Item : The specified path, file name, or both are too long. The fully qualified file name must be less than 260
characters, and the directory name must be less than 248 characters.
At line:1 char:1
+ Remove-Item -Path "D:\System Volume Information\dfsr" -recurse -force
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : WriteError: (D:\System Volume Information\dfsr:String) [Remove-Item], PathTooLongExcepti
on
+ FullyQualifiedErrorId : RemoveItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand

PS D:\>

However, prefixing the path with "\\?\" makes the command work successfully:

PS D:\> Remove-Item -Path "\\?\D:\System Volume Information\dfsr" -recurse -force
PS D:\> get-childitem -path "D:\System Volume Information\dfsr" -hidden
PS D:\>
AaronH
  • 349
  • 2
  • 5
  • That's a great trick. I'll have to give it a go. I'm not usually doing anything too exotic when I run up against the limit, mainly just parsing a folder structure or removing files etc. Thanks! – mhouston100 Sep 13 '14 at 09:25
  • 5
    I get no errors, but it also doesn't remove the folder. – rainabba Sep 17 '14 at 22:55
  • 3
    This worked for me prefixes, win 10 powershell 5.1. Like this Remove-Item -Recurse -Force -Path "\\?\$($_.FullName)" – arberg Mar 23 '18 at 09:33
  • Deletes folder with long paths on PS 5.1 but doesn't delete it on PS 7.1 (no error) (on Windows Server 2019) – Andy Arismendi Jan 08 '22 at 18:24
  • PS 7.1 (core) is able to delete the folder without the prefix. (on Windows Server 2019) – Andy Arismendi Jan 08 '22 at 18:40
10

If you have ruby installed, you can use Fileman:

gem install fileman

Once installed, you can simply run the following in your command prompt:

fm rm your_folder_path

This problem is a real pain in the neck when you're developing in node.js on Windows, so fileman becomes really handy to delete all the garbage once in a while

Nicolas Dao
  • 987
  • 12
  • 22
9

This is a known limitation of PowerShell. The work around is to use dir cmd (sorry, but this is true).

http://asysadmin.tumblr.com/post/17654309496/powershell-path-length-limitation

or as mentioned by AaronH answer use \?\ syntax is in this example to delete build

dir -Include build -Depth 1 | Remove-Item -Recurse -Path "\\?\$($_.FullName)"
arberg
  • 4,148
  • 4
  • 31
  • 39
Bill
  • 5,263
  • 6
  • 35
  • 50
7

If all you're doing is deleting the files, I use a function to shorten the names, then I delete.

    function ConvertTo-ShortNames{
    param ([string]$folder)
    $name = 1
    $items = Get-ChildItem -path $folder
    foreach ($item in $items){
        Rename-Item -Path $item.FullName -NewName "$name"
        if ($item.PSIsContainer){
            $parts = $item.FullName.Split("\")
            $folderPath = $parts[0]
            for ($i = 1; $i -lt $parts.Count - 1; $i++){
                $folderPath = $folderPath + "\" + $parts[$i]
            }
            $folderPath = $folderPath + "\$name"
            ConvertTo-ShortNames $folderPath
        }
        $name++
    }
}

I know this is an old question, but I thought I would put this here in case somebody needed it.

Mike Wallace
  • 71
  • 1
  • 2
3

There is one workaround that uses Experimental.IO from Base Class Libraries project. You can find it over on poshcode, or download from author's blog. 260 limitation is derived from .NET, so it's either this, or using tools that do not depend on .NET (like cmd /c dir, as @Bill suggested).

BartekB
  • 8,492
  • 32
  • 33
2

Combination of tools can work best, try doing a dir /x to get the 8.3 file name instead. You could then parse out that output to a text file then build a powershell script to delete the paths that you out-file'd. Take you all of a minute. Alternatively you could just rename the 8.3 file name to something shorter then delete.

Zenbu
  • 21
  • 1
2

For my Robocopy worked in 1, 2 and 3

  1. First create an empty directory lets say c:\emptydir
  2. ROBOCOPY c:\emptydir c:\directorytodelete /purge
  3. rmdir c:\directorytodelete
orellabac
  • 2,077
  • 2
  • 26
  • 34
1

This is getting old but I recently had to work around it again. I ended up using 'subst' as it didn't require any other modules or functions be available on the PC this was running from. A little more portable.

Basically find a spare drive letter, 'subst' the long path to that letter, then use that as the base for GCI.

Only limitation is that the $_.fullname and other properties will report the drive letter as the root path.

Seems to work ok:

$location = \\path\to\long\
$driveLetter = ls function:[d-z]: -n | ?{ !(test-path $_) } | random

subst $driveLetter $location
sleep 1
Push-Location $driveLetter -ErrorAction SilentlyContinue
Get-ChildItem -Recurse

subst $driveLetter /D

That command is obviously not to delete files but can be substituted.

mhouston100
  • 1,173
  • 2
  • 19
  • 41
1

PowerShell can easily be used with AlphaFS.dll to do actual file I/O stuff without the PATH TOO LONG hassle.

For example:

Import-Module <path-to-AlphaFS.dll>

[Alphaleonis.Win32.Filesystem.Directory]::Delete($path, $True)

Please see at Codeplex: https://alphafs.codeplex.com/ for this .NET project.

Shogun
  • 11
  • 2
1

I had the same issue while trying to delete folders on a remote machine.

Nothing helped but... I found one trick :

# 1:let's create an empty folder
md ".\Empty" -erroraction silentlycontinue

# 2: let's MIR to the folder to delete : this will empty the folder completely.
robocopy ".\Empty" $foldertodelete /MIR /LOG+:$logname 

# 3: let's delete the empty folder now:
remove-item $foldertodelete -force

# 4: we can delete now the empty folder
remove-item ".\Empty" -force

Works like a charm on local or remote folders (using UNC path)

henrycarteruk
  • 12,708
  • 2
  • 36
  • 40
Jean-Luc
  • 11
  • 1
0

Adding to Daniel Lee's solution, When the $myDir has spaces in the middle it gives FILE NOT FOUND errors considering set of files splitted from space. To overcome this use quotations around the variable and put powershell escape character to skip the quatations.

PS>cmd.exe /C "rmdir /s /q <grave-accent>"$myDir<grave-accent>""

Please substitute the proper grave-accent character instead of <grave-accent>
SO plays with me and I can't add it :). Hope some one will update it for others to understand easily

isuru chathuranga
  • 995
  • 15
  • 24
0

Just for completeness, I have come across this a few more times and have used a combination of both 'subst' and 'New-PSDrive' to work around it in various situations.

Not exactly a solution, but if anyone is looking for alternatives this might help.

Subst seems very sensitive to which type of program you are using to access the files, sometimes it works and sometimes it doesn't, seems to be the same with New-PSDrive.

mhouston100
  • 1,173
  • 2
  • 19
  • 41
0

Any thing developed using .NET out of the box will fail with paths too long. You will have to move them to 8.3 names, PInVoke (Win32) calls, or use robocopy