web-dev-qa-db-fra.com

Supprimer le répertoire indépendamment de la limite de 260 caractères

J'écris un script simple pour supprimer les dossiers de migration USMT après un certain nombre de jours:

## 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
}

Cependant, je continue de frapper le redouté 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.

J'ai étudié des solutions de contournement et des alternatives, mais elles tournent toutes autour de moi en se souciant de ce qui se trouve dans le dossier.

J'espérais une solution plus simple car je ne me soucie pas vraiment du contenu du dossier s'il est marqué pour suppression.

Existe-t-il une applet de commande Powershell native autre que Remove-Item -recurse qui peut accomplir ce que je recherche?

43
mhouston100

Il s'agit d'une limitation connue de PowerShell. La solution consiste à utiliser dir cmd (désolé, mais c'est vrai).

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

ou comme mentionné par la réponse AaronH, utilisez la syntaxe \?\dans cet exemple pour supprimer la construction

dir -Include build -Depth 1 | Remove-Item -Recurse -Path "\\?\$($_.FullName)"
9
Bill

J'ai souvent ce problème avec les projets de nœuds. Ils imbriquent leurs dépendances et une fois git cloné, il est difficile de les supprimer. Un utilitaire de nœud agréable que j'ai rencontré est rimraf .

npm install rimraf -g
rimraf <dir>
54
Andy

Tout comme CADII l'a dit dans une autre réponse: Robocopy est capable de créer des chemins plus longs que la limite de 260 caractères. Robocopy est également capable de supprimer ces chemins. Vous pouvez simplement mettre en miroir un dossier vide sur votre chemin contenant des noms trop longs au cas où vous voudriez le supprimer.

Par exemple:

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

Voici le référence Robocopy pour connaître les paramètres et les différentes options.

37
Harald

Cette réponse sur SuperUser l'a résolu pour moi: https://superuser.com/a/274224/85532

Cmd /C "rmdir /S /Q $myDir"
22
Daniel Lee

J'ai créé une fonction PowerShell qui est capable de supprimer un long chemin (> 260) en utilisant la technique de robocopy mentionnée :

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
}

Exemple d'utilisation:

Remove-PathToLongDirectory c:\yourlongPath
15
Martin Brandl

Il y a quelque temps, j'ai appris une astuce qui fonctionne souvent pour contourner les problèmes de chemin d'accès aux fichiers longs. Apparemment, lors de l'utilisation de certaines API Windows, certaines fonctions transitent par du code hérité qui ne peut pas gérer les noms de fichiers longs. Cependant, si vous formatez vos chemins d'une manière particulière, le code hérité est évité. L'astuce qui résout ce problème consiste à référencer les chemins à l'aide du préfixe "\\? \". Il convient de noter que toutes les API ne prennent pas en charge cela, mais dans ce cas particulier, cela a fonctionné pour moi, voir mon exemple ci-dessous:

L'exemple suivant échoue:

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:\>

Cependant, le préfixe du chemin avec "\\? \" Permet à la commande de fonctionner correctement:

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:\>
11
AaronH

Si vous avez Ruby installé, vous pouvez utiliser Fileman:

gem install fileman

Une fois installé, vous pouvez simplement exécuter ce qui suit dans votre invite de commande:

fm rm your_folder_path

Ce problème est une vraie douleur dans le cou lorsque vous développez dans node.js sur Windows, donc fileman devient vraiment pratique pour supprimer toutes les ordures de temps en temps

10
Nicolas Dao

Si tout ce que vous faites est de supprimer les fichiers, j'utilise une fonction pour raccourcir les noms, puis je supprime.

    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++
    }
}

Je sais que c'est une vieille question, mais j'ai pensé que je mettrais cela ici au cas où quelqu'un en aurait besoin.

5
Mike Wallace

Il existe une solution de contournement qui utilise Experimental.IO à partir du projet Base Class Libraries . Vous pouvez le trouver sur poshcode , ou le télécharger sur blog de l'auteur . La limitation 260 est dérivée de . NET , c'est donc ça, ou utiliser des outils qui ne dépendent pas de .NET (comme cmd /c dir, comme @Bill l'a suggéré).

3
BartekB

Cela vieillit mais j'ai récemment dû le contourner. J'ai fini par utiliser "subst" car il ne nécessitait aucun autre module ou fonction sur le PC sur lequel il fonctionnait. Un peu plus portable.

Fondamentalement, trouvez une lettre de lecteur de rechange, "subst" le long chemin vers cette lettre, puis utilisez-la comme base pour GCI.

La seule limitation réside dans le fait que $ _. Fullname et les autres propriétés signalent la lettre de lecteur comme chemin racine.

Semble fonctionner correctement:

$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

Cette commande n'est évidemment pas de supprimer des fichiers mais peut être substituée.

1
mhouston100

PowerShell peut facilement être utilisé avec AlphaFS.dll pour effectuer des tâches d'E/S de fichier réelles sans les tracas PATH TOO LONG.

Par exemple:

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

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

Veuillez consulter Codeplex: https://alphafs.codeplex.com/ pour ce projet .NET.

1
Shogun

La combinaison d'outils peut mieux fonctionner, essayez de faire un dir/x pour obtenir le nom de fichier 8.3 à la place. Vous pouvez ensuite analyser cette sortie dans un fichier texte, puis créer un script PowerShell pour supprimer les chemins que vous avez sortis. Prenez-vous tous une minute. Alternativement, vous pouvez simplement renommer le nom de fichier 8.3 en quelque chose de plus court, puis le supprimer.

1
Zenbu

Pour ma Robocopy travaillé en 1, 2 et 3

  1. Créez d'abord un répertoire vide, disons c:\emptydir
  2. ROBOCOPIE c:\emptydir c:\directorytodelete/purge
  3. rmdir c:\directorytodelete
1
orellabac

Juste pour être complet, je l'ai rencontré quelques fois de plus et j'ai utilisé une combinaison de "subst" et de "New-PSDrive" pour contourner ce problème dans diverses situations.

Pas exactement une solution, mais si quelqu'un cherche des alternatives, cela pourrait aider.

Subst semble très sensible au type de programme que vous utilisez pour accéder aux fichiers, parfois cela fonctionne et parfois non, semble être le même avec New-PSDrive.

0
mhouston100

J'ai eu le même problème en essayant de supprimer des dossiers sur une machine distante.

Rien n'a aidé mais ... j'ai trouvé une astuce:

# 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

Fonctionne comme un charme sur les dossiers locaux ou distants (en utilisant le chemin UNC)

0
Jean-Luc

Toute chose développée à l'aide de .NET prête à l'emploi échouera avec des chemins trop longs. Vous devrez les déplacer vers 8.3 noms , appels PInVoke (Win32) , ou utiliser robocopy

0
DzSoundNirvana

Ajout à la solution de Daniel Lee, lorsque $ myDir a des espaces au milieu, il donne des erreurs FILE NOT FOUND en considérant un ensemble de fichiers séparés de l'espace. Pour surmonter cela, utilisez des citations autour de la variable et mettez le caractère d'échappement PowerShell pour ignorer les quatations.

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

Veuillez remplacer le caractère d'accent grave approprié au lieu de <Grave-accent>
SO joue avec moi et je ne peux pas l'ajouter :). J'espère que quelqu'un le mettra à jour pour que d'autres le comprennent facilement

0
isuru chathuranga