Копировать файл удаленно с помощью PowerShell

95

Я пишу сценарий PowerShell, который хочу запустить с сервера A. Я хочу подключиться к серверу B и скопировать файл на сервер A в качестве резервной копии.

Если это невозможно сделать, я хотел бы подключиться к серверу B с сервера A и скопировать файл в другой каталог на сервере B.

Я вижу Copy-Itemкоманду, но не понимаю, как дать ей имя компьютера.

Я бы подумал, что могу сделать что-то вроде

Copy-Item -ComputerName ServerB -Path C:\Programs\temp\test.txt -Destination (not sure how it would know to use ServerB or ServerA)

Как я могу это сделать?

chobo2
источник
4
Чтобы использовать Copy-Item, вам нужно будет использовать UNC-путь, например "\\ ServerB \ C $ \ Programs \ temp \ test.txt"

Ответы:

97

Просто используйте административные общие ресурсы для копирования файлов между системами. Так намного проще.

Copy-Item -Path \\serverb\c$\programs\temp\test.txt -Destination \\servera\c$\programs\temp\test.txt;

Используя пути UNC вместо путей локальной файловой системы, вы помогаете гарантировать, что ваш сценарий будет исполняться из любой клиентской системы, имеющей доступ к этим путям UNC. Если вы используете пути локальной файловой системы, то вы заставляете себя запускать скрипт на определенном компьютере.

Это работает только тогда, когда сеанс PowerShell выполняется под пользователем, имеющим права на оба административных общих ресурса.

Я предлагаю использовать обычный сетевой ресурс на сервере B с доступом только для чтения для всех и просто позвонить (с сервера A):

Copy-Item -Path "\\\ServerB\SharedPathToSourceFile" -Destination "$Env:USERPROFILE" -Force -PassThru -Verbose
Тревор Салливан
источник
9
Одна из возможных проблем с этим подходом заключается в том, что Copy-Item не поддерживает альтернативные учетные данные (если вам нужно запустить команду с другим пользователем). В этом случае требуется подход New-PSDrive.
Иордания
1
Это решение работает только в том случае, если между хостами нет брандмауэра, блокирующего общие ресурсы UNC. В этом случае правильное решение находится ниже ( Copy-Item -FromSession).
Марк
88

Начиная с версии PowerShell 5 и выше (включенной в Windows Server 2016, загружаемой как часть WMF 5 для более ранних версий ), это возможно с помощью удаленного взаимодействия. Преимущество этого в том, что он работает, даже если по какой-либо причине вы не можете получить доступ к общим ресурсам.

Чтобы это работало, в локальном сеансе, в котором инициируется копирование, должен быть установлен PowerShell 5 или выше. Для удаленного сеанса не обязательно должна быть установлена ​​оболочка PowerShell 5 - она ​​работает с версиями PowerShell до 2 и версиями Windows Server до 2008 R2. [1]

С сервера A создайте сеанс на сервере B:

$b = New-PSSession B

А потом еще из А:

Copy-Item -FromSession $b C:\Programs\temp\test.txt -Destination C:\Programs\temp\test.txt

Копирование элементов в B выполняется с помощью -ToSession. Обратите внимание, что в обоих случаях используются локальные пути; вы должны отслеживать, на каком сервере вы находитесь.


[1]: при копировании с или на удаленный сервер, на котором есть только PowerShell 2, остерегайтесь этой ошибки в PowerShell 5.1 , которая на момент написания означает, что рекурсивное копирование файлов не работает -ToSession, очевидно, копирование не работает в все с -FromSession.

Йерун Мостерт
источник
3
Я обнаружил, что на обоих серверах нет необходимости устанавливать PS 5. Я только что выполнил успешный тест, на котором только на исходном сервере (Windows 10) была установлена ​​PS 5. Целью был Windows Server 2012 R2 с установленным PS по умолчанию (отчеты $ PSVersionTable.PSVersion 4).
Тейлор Бьюкенен
2
Если вы используете -ToSession для источника, только для источника требуется установка PS 5. Если вы используете -FromSession для цели, только для цели требуется установка PS 5.
Тейлор Бьюкенен
1
Это также работает, когда у вас установлен только гипервизор (без сервера), нет необходимости настраивать общие ресурсы, просто используйте сеансы!
dashesy
Спасибо! Nice, элегантное решение, аналогично scpболее sshна Linux ... нет необходимости возиться с надоедливыми акциями!
Tobias J
40

Используйте net useили, New-PSDriveчтобы создать новый диск:

New-PsDrive: создать новый PsDrive, видимый только в среде PowerShell:

New-PSDrive -Name Y -PSProvider filesystem -Root \\ServerName\Share
Copy-Item BigFile Y:\BigFileCopy

Чистое использование: создать новый диск, видимый во всех частях ОС.

Net use y: \\ServerName\Share
Copy-Item BigFile Y:\BigFileCopy
JPBlanc
источник
Если я запустил это дважды, я получу New-PSDrive : A specified logon session does not exist. It may already have been terminated-> Я думаю, что предыдущий сеанс все еще продолжается -> Итак, я попытался использовать Remove-PSDrive-> все еще не работает. Тоже net use <driveLetter> /deleteне помогло. Что еще я могу сделать, чтобы запустить эту команду в конфигурации сборки программного обеспечения?
Бруно Бьери
Нет смысла бежать New-PSDriveдва раза, которые должны были бытьA drive with the name 'Y' already exists.
JPBlanc
Согласен, нет смысла запускать дважды. Но он включен в этап сборки, и сборка выполняется несколько раз в день. Итак, мой подход заключался в том, чтобы удалить диск после того, как я выполнил нужную мне работу, и я предполагал, что не составит труда воссоздать его после выполнения новой сборки. Но это кажется проблемой. Есть еще намек?
Бруно Бьери
Как насчет тестирования, если он установлен, прежде чем устанавливать? или вы можете использовать Remove-PSDrive в своем скрипте, если вы уверены, что все дескрипторы, использующие этот путь, закрыты.
JPBlanc
16

На всякий случай, если для доступа к удаленному файлу требуются ваши учетные данные, вы можете сгенерировать объект System.Net.WebClient с помощью командлета New-Object для «Удаленного копирования файла», например

$Source = "\\192.168.x.x\somefile.txt"
$Dest   = "C:\Users\user\somefile.txt"
$Username = "username"
$Password = "password"

$WebClient = New-Object System.Net.WebClient
$WebClient.Credentials = New-Object System.Net.NetworkCredential($Username, $Password)

$WebClient.DownloadFile($Source, $Dest)

Или, если вам нужно загрузить файл, вы можете использовать UploadFile:

$Dest = "\\192.168.x.x\somefile.txt"
$Source   = "C:\Users\user\somefile.txt"

$WebClient.UploadFile($Dest, $Source)
shyan1
источник
1
@klm_ Не могли бы вы объяснить, что вы имеете в виду?
FastTrack
0

Ни один из приведенных выше ответов не помог мне. Я продолжал получать эту ошибку:

Copy-Item : Access is denied
+ CategoryInfo          : PermissionDenied: (\\192.168.1.100\Shared\test.txt:String) [Copy-Item], UnauthorizedAccessException>   
+ FullyQualifiedErrorId : ItemExistsUnauthorizedAccessError,Microsoft.PowerShell.Commands.CopyItemCommand

Так что это сделало это для меня:

netsh advfirewall firewall set rule group="File and Printer Sharing" new enable=yes

Затем с моего хоста моя машина в поле Run я только что сделал это:

\\{IP address of nanoserver}\C$
RogerW
источник
1
Скорее всего, у вас возникли проблемы с разрешениями share + filesystem. Помните, что самые строгие разрешения побеждают, поэтому, даже если у вас есть доступ на уровне файловой системы NTFS, если разрешения общего доступа ограничивают вас, вы не сможете писать. :)
Тревор Салливан