Using PowerShell, can I copy one file from my local system to many remote computers in parallel?

90 views Asked by At

As the title suggests, I cant seem to get either workflows or foreach-object -Parallel to work.

Here is one attempt:

$Computers = Get-Content 'C:\temp\Inputfiles\computers.txt'
$SourcePath = 'C:\Temp\Inputfiles\VMTools\Setup64.exe'

$Job = $Computers | ForEach-Object -Parallel {
  Copy-Item -Path $using:SourcePath -Destination "\\$_\C$\Temp\" -Force
  Start-Sleep -Seconds 1
} -ThrottleLimit 5 -AsJob

$Job | Wait-Job | Receive-Job

I tried variations of the above, but cant get it to work.

Here is the error I was getting on the above:

>  .\Copy-FileToRemote.ps1
ForEach-Object : Parameter set cannot be resolved using the specified named parameters.
At C:\Temp\ITScript\Workflow\Copy-FileToRemote.ps1:4 char:21
+ $Job = $Computers | ForEach-Object -Parallel {
+                     ~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [ForEach-Object], ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.ForEachObjectCommand

Wait-Job : Cannot validate argument on parameter 'Job'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Temp\ITScript\Workflow\Copy-FileToRemote.ps1:9 char:8
+ $Job | Wait-Job | Receive-Job
+        ~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Wait-Job], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.WaitJobCommand
2

There are 2 answers

1
mklement0 On BEST ANSWER

Preface:


To get the benefits of parallel processing, use the following approach:

  • Create a remoting session explicitly, targeting all target computers, using New-PSSession.

  • Use that session with Copy-Item's -ToSession parameter to copy the source file to all target computers.

$session =
  New-PSSession -ComputerName (Get-Content C:\temp\InputFiles\computers.txt)

Copy-Item -ToSession $session C:\temp\InputFiles\vmtools\Setup64.exe -Destination C:\temp\

Note that, with a -ToSession argument, the -Destination parameter is implicitly treated as target machine-local.

Also, the requirement is that the target directory on each machine, C:\temp, must already exist.

3
Matt On

Got it working:

File Deployment Script

$computers = Get-Content 'C:\temp\InputFiles\computers.txt'

foreach ($computer in $computers) {
    $scriptblock1 = {
        param($sourcepath, $destpath, $computer)
        Copy-Item -Path 'c:\temp\InputFiles\vmtools\Setup64.exe' -Destination "\\$computer\c$\temp\" -Recurse -Force 
    }

    # Run the script block on each remote computer in parallel
    Invoke-Command -ScriptBlock $scriptblock1 -ArgumentList $sourcepath, 'C:\temp', $computer
}

Thanks!