Impossible de supprimer un répertoire avec des crochets dans le nom à l'aide de WinSCP et PowerShell
-
21-12-2019 - |
Question
J'essaie d'écrire un script PowerShell qui supprime automatiquement les répertoires vides sur notre serveur FTP.Je n'ai pas d'accès direct au serveur sur lequel résident les répertoires - je ne peux y accéder que via FTP.Pour cette raison, j'ai écrit un script PowerShell qui utilise l'assembly WinSCP .NET pour (essayer de) supprimer les répertoires vides.Cependant, j'ai un problème dans la mesure où de nombreux répertoires sur le serveur ont des crochets dans le nom du répertoire.
Par exemple, le nom du répertoire peut s'appeler : [a]153432
Il existe beaucoup de ces répertoires, d'où mon envie d'écrire un script pour les supprimer.Cela se produit parce qu'ils ont été créés par un programme qui utilise un numéro pour créer les répertoires dont il a besoin.Afin de travailler sur ce programme, j'ai créé un répertoire vide
/latest/[b]test
Mon programme ressemble à ceci :
# program to test deletion of directories with square-brackets in the name.
$HOSTNAME="myftpservername"
$USERNAME="myftpusername"
$PASSWORD="myftppassword"
$DLL_LOCATION="C:\Program Files (x86)\WinSCP\WinSCPnet.dll"
$LOCAL_DIRECTORY="C:\testdir\extended\baseroot"
# Load WinSCP .NET assembly
[Reflection.Assembly]::LoadFrom($DLL_LOCATION) | Out-Null
# Session.FileTransferred event handler
try
{
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.Protocol = [WinSCP.Protocol]::ftp
$sessionOptions.HostName = $HOSTNAME
$sessionOptions.UserName = $USERNAME
$sessionOptions.Password = $PASSWORD
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
$remoteFileWithUnixPath = "/latest/[b]test"
$removalResult = $session.RemoveFiles($remoteFileWithUnixPath)
if ($removalResult.IsSuccess)
{
Write-Host ("Removal of remote file {0} succeeded" -f $remoteFileWithUnixPath)
}
else
{
Write-Host ("Removal of remote file {0} failed" -f $remoteFileWithUnixPath)
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
exit 0
}
catch [Exception]
{
Write-Host $_.Exception.Message
exit 1
}
Lorsque je le lance, il affiche le message suivant :
PS C:\Users\dbuddrige\Documents\dps> .\delete-squarebracket-dir.ps1
Removal of remote file /latest/[b]test succeeded
Toutefois, le répertoire n'est pas supprimé.
J'ai également essayé de spécifier le nom du répertoire avec des délimiteurs tels que :
$remoteFileWithUnixPath = "/latest/\[b\]test"
Mais cela échoue également (mais au moins c'est ce qui est dit) :
PS C:\Users\dbuddrige\Documents\dps> .\delete-squarebracket-dir.ps1
Removal of remote file /latest/\[b\]test failed
MAIS, si je change le nom du répertoire [et la variable $remoteFileWithUnixPath
] à quelque chose comme
/latest/foo
Et puis relancez le programme, il supprime le répertoire /latest/foo
ça va.
Quelqu'un a-t-il une idée de ce que je dois faire pour que cela fonctionne ?
La réponse à cette question a été soulignée par Martin Prikryl [Merci !]
Le code entièrement fonctionnel suit :
# program to test deletion of directories with square-brackets in the name.
$HOSTNAME="myftpservername"
$USERNAME="myftpusername"
$PASSWORD="myftppassword"
$DLL_LOCATION="C:\Program Files (x86)\WinSCP\WinSCPnet.dll"
$LOCAL_DIRECTORY="C:\testdir\extended\baseroot"
# Load WinSCP .NET assembly
[Reflection.Assembly]::LoadFrom($DLL_LOCATION) | Out-Null
# Session.FileTransferred event handler
try
{
$sessionOptions = New-Object WinSCP.SessionOptions
$sessionOptions.Protocol = [WinSCP.Protocol]::ftp
$sessionOptions.HostName = $HOSTNAME
$sessionOptions.UserName = $USERNAME
$sessionOptions.Password = $PASSWORD
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
$remoteFileWithUnixPath = "/latest/[b]test"
$removalResult =
$session.RemoveFiles($session.EscapeFileMask($remoteFileWithUnixPath))
if ($removalResult.IsSuccess)
{
Write-Host ("Removal of remote file {0} succeeded" -f $remoteFileWithUnixPath)
}
else
{
Write-Host ("Removal of remote file {0} failed" -f $remoteFileWithUnixPath)
}
}
finally
{
# Disconnect, clean up
$session.Dispose()
}
exit 0
}
catch [Exception]
{
Write-Host $_.Exception.Message
exit 1
}
La solution
Certaines méthodes de l'assembly WinSCP .NET, notamment la Session.RemoveFiles
, acceptez un masque de fichier, pas un simple chemin.
Les crochets ont une signification particulière dans le masque de fichier.
Vous devriez toujours utiliser le RemotePath.EscapeFileMask
méthode sur les chemins de fichiers, avant de les transmettre aux méthodes d'assemblage.
Autres conseils
J'utiliserais la séquence d'échappement dans la ligne de commande :
Remove-Item 'C:\Scripts\Test`[1`].txt'
Ou utilisez le -LiteralPath
paramètre.
Remove-Item -LiteralPath C:\scripts\test[1].txt
Le paramètre -LiteralPath n'essaie pas de convertir la chaîne.