简体   繁体   中英

Copy file during remote powershell session c# runspace

I need to copy a file from a location on an Azure VM to my local computer using powershell. eg C:\\tmp on the VM to C:\\tmp on my local machine

The application is c# using System Automation. Currently I use the method.

    using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
                    {
                        runspace.Open();
                        Pipeline pipeline = runspace.CreatePipeline(//Some SQL that pulls files from database to C:\tmp);
                        var results = pipeline.Invoke();
    }

The powershell I use at the moment just return get-content for each file, returns it to c# in a loop, writing to file each time. However this is very inefficient.

This is the right idea, however it is more efficient to chunk the file when you do this. Powershell does not currently have a native way to do this, so you have to write some code. There are two parts, the remote powershell part to chunk the file on the server, and the C# part to re-assemble the chunks and execute the powershell.

The remote powershell part:

$streamChunks = New-Object System.Collections.Generic.List[byte[]]
$buffer = New-Object byte[] 1024
[IO.FileStream] $fileStream = $null
try  
{  
    $targetPath = # FILE TO GET
    $fileStream = [IO.File]::OpenRead($targetPath)
    [int] $bytesRead = 0
    while (($bytesRead = $fileStream.Read($buffer, 0, 1024)) -gt 0)  
    {  
        $chunk = New-Object byte[] $bytesRead
        [Array]::Copy($buffer, $chunk, $bytesRead)
        $streamChunks.Add($chunk)
    }  
    Write-Output $streamChunks
}  
finally  
{   
    if ($fileStream -ne $null)   
    {  
        $fileStream.Dispose()  
        $fileStream = $null 
    }
};

Note that this script will be invoked by a runspace on your local machine:

Pipeline pipeline = runspace.CreatePipeline(command); // command is powershell above
Collection<PSObject> results = pipeline.Invoke();

The C# part to re-assemble the chunks:

using (FileStream fileStream = new FileStream(localPath, FileMode.OpenOrCreate, FileAccess.Write))
{
    foreach (PSObject result in results)
    {
        if (result != null)
        {
            byte[] chunk = (byte[])result.BaseObject;
            if (chunk != null)
            {
                fileStream.Write(chunk, 0, chunk.Length);
            }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM