Невозможно удалить каталог с квадратными скобками в имени с помощью WinSCP и PowerShell.
-
21-12-2019 - |
Вопрос
Я пытаюсь написать сценарий PowerShell, который автоматически удаляет пустые каталоги на нашем FTP-сервере.У меня нет прямого доступа к серверу, на котором находятся каталоги, я могу получить к ним доступ только через FTP.По этой причине я написал сценарий PowerShell, который использует сборку WinSCP .NET для (попытки) удаления пустых каталогов.Однако у меня есть проблема: многие каталоги на сервере имеют в имени каталога квадратные скобки.
Например, имя каталога может называться: [a]153432
Таких каталогов очень много, отсюда и мое желание написать скрипт для их удаления.Это происходит потому, что они были созданы программой, которая использует номер для создания необходимых ей каталогов.Для работы с этой программой я создал пустой каталог
/latest/[b]test
Моя программа выглядит следующим образом:
# 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
}
Когда я запускаю его, он отображает следующее сообщение:
PS C:\Users\dbuddrige\Documents\dps> .\delete-squarebracket-dir.ps1
Removal of remote file /latest/[b]test succeeded
Однако каталог не удаляется.
Я также попытался указать имя каталога с разделителями, например:
$remoteFileWithUnixPath = "/latest/\[b\]test"
Но это тоже не получается (но, по крайней мере, так сказано):
PS C:\Users\dbuddrige\Documents\dps> .\delete-squarebracket-dir.ps1
Removal of remote file /latest/\[b\]test failed
НО, если я изменю имя каталога [и переменную $remoteFileWithUnixPath
] к чему-то вроде
/latest/foo
А потом перезапустить программу, она удалит каталог /latest/foo
просто хорошо.
Есть ли у кого-нибудь идеи, что мне нужно сделать, чтобы это заработало?
Ответ на этот вопрос указал Мартин Прикрыл [Спасибо!]
Полностью рабочий код следующий:
# 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
}
Решение
Некоторые методы сборки WinSCP .NET, в том числе метод Session.RemoveFiles
, примите маску файла, а не простой путь.
Квадратные скобки имеют особое значение в маска файла.
Вы всегда должны использовать RemotePath.EscapeFileMask
метод по путям к файлам, прежде чем передавать их методам сборки.
Другие советы
Я бы использовал escape-последовательность в командной строке:
Remove-Item 'C:\Scripts\Test`[1`].txt'
Или используйте -LiteralPath
параметр.
Remove-Item -LiteralPath C:\scripts\test[1].txt
Параметр -LiteralPath не пытается преобразовать строку.