PowerShell function that sends a file to a remote session.
function Send-File
{
##############################################################################
##
## Send-File
##
## From Windows PowerShell Cookbook (O'Reilly)
## by Lee Holmes (http://www.leeholmes.com/guide)
##
##############################################################################
<#
.SYNOPSIS
Sends a file to a remote session.
.EXAMPLE
PS > $session = New-PsSession leeholmes1c23
PS > Send-File c:\temp\test.exe c:\temp\test.exe $session
#>
param(
## The path on the local computer
[Parameter(Mandatory = $true)]
$Source,
## The target path on the remote computer
[Parameter(Mandatory = $true)]
$Destination,
## The session that represents the remote computer
[Parameter(Mandatory = $true)]
[System.Management.Automation.Runspaces.PSSession] $Session
)
Set-StrictMode -Version 3
$remoteScript = {
param($destination, $bytes)
## Convert the destination path to a full filesystem path (to support relative paths)
$Destination = $executionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Destination)
## Write the content to the new file
$file = [IO.File]::Open($Destination, "OpenOrCreate")
$null = $file.Seek(0, "End")
$null = $file.Write($bytes, 0, $bytes.Length)
$file.Close()
}
## Get the source file, and then start reading its content
$sourceFile = Get-Item $source
## Delete the previously-existing file if it exists
Invoke-Command -Session $session {
if (Test-Path $args[0]) { Remove-Item $args[0] }
} -ArgumentList $Destination
## Now break it into chunks to stream
Write-Progress -Activity "Sending $Source" -Status "Preparing file"
$streamSize = 1MB
$position = 0
$rawBytes = New-Object byte[] $streamSize
$file = [IO.File]::OpenRead($sourceFile.FullName)
while(($read = $file.Read($rawBytes, 0, $streamSize)) -gt 0)
{
Write-Progress -Activity "Writing $Destination" `
-Status "Sending file" `
-PercentComplete ($position / $sourceFile.Length * 100)
## Ensure that our array is the same size as what we read from disk
if ($read -ne $rawBytes.Length)
{
[Array]::Resize( [ref] $rawBytes, $read)
}
## And send that array to the remote system
Invoke-Command -Session $session $remoteScript -ArgumentList $destination,$rawBytes
## Ensure that our array is the same size as what we read from disk
if ($rawBytes.Length -ne $streamSize)
{
[Array]::Resize([ref] $rawBytes, $streamSize)
}
[GC]::Collect()
$position += $read
}
$file.Close()
## Show the result
Invoke-Command -Session $session { Get-Item $args[0] } -ArgumentList $Destination
}