Невозможно удалить каталог с квадратными скобками в имени с помощью WinSCP и PowerShell

Я пытаюсь написать сценарий 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
}

person David    schedule 26.02.2014    source источник


Ответы (2)


Некоторые методы сборки WinSCP .NET, включая Session.RemoveFiles, принимают маску файла, а не простой путь.

Квадратные скобки имеют особое значение в маске файла.

Вы всегда должны использовать RemotePath.EscapeFileMask метод для путей к файлам, прежде чем передавать их методам сборки.

person Martin Prikryl    schedule 26.02.2014
comment
Спасибо, сработало! Я выложу обновленный код полностью, но главное изменение таково: $ removeResult = $ session.RemoveFiles ($ session.EscapeFileMask (/ latest / [b] test)) - person David; 26.02.2014

Я бы использовал escape-последовательность в командной строке:

Remove-Item 'C:\Scripts\Test`[1`].txt'

Или используйте параметр -LiteralPath.

Remove-Item -LiteralPath C:\scripts\test[1].txt

Параметр -LiteralPath не пытается преобразовать строку.

person ravikanth    schedule 26.02.2014
comment
Спасибо за ваш ответ - однако я должен уточнить - рассматриваемые каталоги существуют на нашем ftp-сервере, и единственный доступ к ftp-серверу у меня есть через ftp - именно по этой причине я использую winscp [с его библиотекой .net ], чтобы удалить каталог. Я не могу запустить сценарий PowerShell на том же компьютере, на котором находятся удаляемые каталоги. - person David; 26.02.2014
comment
Ааа! Я пропустил эту часть. Я попробую это воспроизвести. - person ravikanth; 26.02.2014
comment
Спасибо - инструкции по установке библиотеки winscp для доступа к ней из .net и powershell находятся по адресу: winscp.net / eng / docs / - person David; 26.02.2014