При работе на серверах в режиме подключения Remote Desktop Connection (RDP) постоянно возникает необходимость копирования/перемещения файлов между локальной и удаленной машиной. Для этого в подключении настраивается "проброс" дисков и буфера обмена локальной машины. Файлы копируются обычным способом в проводнике удаленной машины или просто через буфер обмена.
Такой "обычный" метод прекрасно работает до тех пор, пока файлы не оказываются сравнительно большими или соединение недостаточно стабильным. А большинство файлов, которые необходимо скопировать, как раз и являются большими: дистрибутивы, конфигурации, выгрузки баз, архивы логов, бэкапы и т.д. Загрузка / выгрузка таких файлов не всегда проходит успешно. Малейшая нестабильность канала приводит к обрыву передачи с ошибкой. Иногда приходится возобновлять передачу вновь и вновь и вновь, что может длиться часами. Особенно, если размер файла составляет несколько Гигабайт.
И если на серверах, которыми владеете Вы или Ваша Компания, возможны другие варианты организации файлообмена, кроме как по RDP-соединению, то к серверам, находящихся в инфраструктуре Заказчика, чаще всего есть только RDP доступ (к тому же, в большинстве случаев, через VPN) и организация альтернативных способов требует согласования со службой информационной безопасности Заказчика.
Однажды, после того как выгрузка нескольких гигабайт архивированных логов ТехЖурнала с продуктивной системы в контуре Заказчика для отправки на контроль в ЦКТП, продолжалась у меня практически весь рабочий день с десятком реконнектов и возобновлений с начала, пришлось заняться поиском решения. И оно было найдено.
Сразу оговорюсь, что речь идет о работе в Windows - системах. Как локальных так и удаленных машин.
BITS-Transfer
Background Intelligent Transfer Service, или по-русски, "Фоновая интеллектуальная служба передачи (BITS)" - это, упрощенно и в двух словах - транспортная система, которую Windows использует для загрузки и распространения обновлений. Работает в фоновом режиме, использует свободную полосу пропускания сети, самостоятельно восстанавливает работу после обрывов связи, отключений и перезагрузок.
Целью заметки не является подробное описание данного протокола. В Сети достаточно материала, в том числе и на русском языке. Сосредоточимся лишь на практическом применении в отношении RDP-сессий.
Согласно описанию от Microsoft, данный сервис предназначен для скачки/закачки файлов через HTTP-соединение и по SMB в/из папки общего доступа.
Однако, как показали эксперименты, ничто не мешает копировать файлы и в рамках локальной файловой системы, скажем с одного диска на другой, или даже в соседний каталог. В ситуации с RDP-сессией, "проброшенный" в удаленную систему диск нашего компьютера и будет для BITS-transfer таким же каталогом общего доступа, как и SMB (эти диски отображаются в системе как сетевые вида \\tsclient\D). Т.е. нам не понадобится никаких дополнительных портов и разрешений.
Таким образом, главными достоинствами BITS-transfer применительно к текущей задаче, будут:
- Автоматическое возобновление докачки при обрыве связи или перезагрузке компьютера;
- Передача в фоновом режиме, без помех для работающего пользователя, с "бережным" отношением к пропускной способности канала;
Для управления службой нет каких-либо визуальных средств. Возможны два варианта управления:
- Утилита командной строки BITSadmin
- Командлеты PowerShell BitsTransfer
Реализация
При решении задачи я воспользовался реализацией скрипта на PowerShell
Для примера будем загружать с локальной машины на удаленную дистрибутив сервера 1С, т.к. доступа к Интернет с самого сервера нет.
Ниже привожу основную, рабочую часть скрипта. Достаточно указать в параметрах -Source и -Destination свои пути к файлам. Оба пути - с удаленной машины. Один указывает на локальный диск, второй - на "проброшенный" (\\tsclient)
Служба может работать в обе стороны, т.е. как скачивать на удаленную машину с локальной, так и закачивать с удаленной на локальную. Достаточно поменять местами значения параметров -Source и -Destination.
Запускать скрипт нужно на удаленной машине, т.е. в RDP-сессии.
$source = "\\tsclient\G\_temp\windows64_8_3_12_1790.rar"
$destination = "E:\temp"
$jobName = "MyBitsTransferJob"
$job = Get-BitsTransfer -Name $jobName -ErrorAction SilentlyContinue -ErrorVariable ProcessError;
if ($ProcessError) {
$job = Start-BitsTransfer -Source $source -Destination $destination -Asynchronous -DisplayName $jobName
} else {
Resume-BitsTransfer -BitsJob $job -Asynchronous
}
while( ($job.JobState.ToString() -eq 'Transferring') -or ($job.JobState.ToString() -eq 'Connecting') ) {
Write-host $Job.JobState.ToString()
$Percent = ($job.BytesTransferred / $job.BytesTotal) * 100
Write-Host $Percent.tostring("0.00") “%”
Sleep 3
}
if ($job.JobState.ToString() -eq 'Transferred') {
Complete-BitsTransfer -BitsJob $job
Write-Host "Передача завершена."
Write-Host "Нажмите любую клавишу для выхода..."
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')
}
Совет: самый простой способ добавить путь к файлу - найти его в проводнике, выделить, нажать Shift+ПКМ и выбрать "Копировать как путь". Что сделать дальше со строкой в буфере, полагаю и так все знают.
После запуска скрипт демонстрирует прогресс операции в процентах.
Можно в любой момент прервать его выполнение по Ctrl-C или закрыв окно. При следующем запуске через несколько минут можно заметить что процент выполнения будет больше того, на котором был произведен обрыв. Таким же образом будет возобновлена передача файлов после повторного соединения при обрыве связи или отключении сессии. При настройках по умолчанию, следующая попытка после неудачной предпринимается через 10 минут. Чтобы не ожидать автоматического возобновления, можно запустить скрипт повторно.
Если оставить задачу "без присмотра", т.е. без работающего скрипта, то загрузка выполнится, но загружаемые файлы не появятся в целевом каталоге. Вернее, в нём будут временные файлы вида "BIT5F71.tmp". Для того, чтобы в каталоге назначения объявились "правильные" файлы, необходимо выполнить "финализацию", при которой созданные временные файлы будут переименованы и задание службы будет удалено.
Сделать это можно, просто повторно запустив скрипт. Либо выполнить в консоли:
PS C:\> Get-BitsTransfer -Name "MyBitsTransferJob" | Complete-BitsTransfer
В случае, если на протяжении загрузки скрипт выполнялся, то финализация будет выполнена автоматически, без дополнительных действий.
Как уже было показано, при завершении скрипта по Ctrl-C или закрытием окна и даже выходом из сессии, задача BITS-transfer не удаляется.
При необходимости отменить задачу, сделать это можно следующим образом:
PS C:\> Get-BitsTransfer -Name "MyBitsTransferJob" | Remove-BitsTransfer
Возможные ошибки
При первом запуске скрипта может возникнуть ошибка вида:
.\FileTransfer_Resume.ps1 : Невозможно загрузить файл C:\...\FileTransfer_Resume.ps1, так как выполнение сценариев отключено в этой системе. Для получения дополнительных сведений см. about_Execution_Policies по адресу https:/go.microsoft.com/fwlink/?LinkID=135170.
Для устранения ошибки необходимо разрешить выполнение сценариев, сменив политику выполнения:
PS C:\> Set-ExecutionPolicy RemoteSigned
Файл для загрузки
В загружаемом файле приложена чуть более доработанная версия скрипта, с интерактивными диалоговыми окнами выбора файла-источника и каталога-назначения, а также возможностью выбора нескольких файлов.
Документация
BITS, PowerShell comandlets (Microsoft, eng)
Дисклаймер
Отмечу, что не являюсь гуру PowerShell-а. Постигаю его мощь по мере возникновения практических задач. В скрипте наверняка есть что-то, что можно было бы улучшить или сделать более эффективно. Поэтому приветствую советы и предложения.