Skip to content

Instantly share code, notes, and snippets.

@leftp
Forked from anuriq/WinRM_File_Copy.cs
Created April 21, 2023 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save leftp/881215d56ae97f109039c094e21cea66 to your computer and use it in GitHub Desktop.
Save leftp/881215d56ae97f109039c094e21cea66 to your computer and use it in GitHub Desktop.
code example to copy files through winrm
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Security;
namespace WinRM_File_Copy
{
class Program
{
static void Main(string[] args)
{
var winrm = new WinRMController("remote.host", 5985, "Administrator", "pass");
winrm.CopyLargeFile(@"c:\file1", @"c:\file_copy");
}
}
public class WinRMController
{
private string hostAddress;
private string username;
private string password;
private int winrmPort;
private const string ShellSchema = "http://schemas.microsoft.com/powershell/Microsoft.PowerShell";
public WinRMController(string HostAddress, int WinRMPort, string UserName, string Password)
{
hostAddress = HostAddress;
username = UserName;
password = Password;
winrmPort = WinRMPort;
}
public void CopyLargeFile(string sourceFilePath, string destinationFilePath)
{
var fs = File.Open(sourceFilePath, FileMode.Open, FileAccess.Read);
uploadChunks(fs, destinationFilePath);
}
private void uploadChunks(FileStream reader, string filePath)
{
// Upload the file in chunks to get around the Windows command line size limit.
// Base64 encodes each set of three bytes into four bytes. In addition the output
// is padded to always be a multiple of four.
//
// ceil(n / 3) * 4 = m1 - m2
//
// where:
// n = bytes
// m1 = max (8192 character command limit.)
// m2 = len(filePath)
int chunkSize = ((8000 - filePath.Length) / 4) * 3;
byte[] chunk = new byte[chunkSize];
var runspace = OpenRunspace(false);
runspace.ThreadOptions = PSThreadOptions.ReuseThread;
runspace.ApartmentState = ApartmentState.STA;
runspace.Open();
try
{
int bytesRead = reader.Read(chunk, 0, chunkSize);
while (bytesRead != 0)
{
string content = Convert.ToBase64String(chunk.Take(bytesRead).ToArray());
appendContent(runspace, filePath, content);
bytesRead = reader.Read(chunk, 0, chunkSize);
}
}
finally
{
runspace.Close();
}
}
private void appendContent(Runspace runspace, string filePath, string content)
{
string remoteScript = string.Concat(
string.Format("$b='{0}';$d='{1}';\r\n", content, filePath),
"$bytes=[Convert]::FromBase64String($b);",
"$fs=[IO.File]::Open($d,[IO.FileMode]::Append,[IO.FileAccess]::Write);",
"$fs.Write($bytes,0,$bytes.Length);",
"$fs.Flush();$fs.Dispose();"
);
var powershell = PowerShell.Create();
powershell.Runspace = runspace;
powershell.AddScript(remoteScript);
var results = powershell.Invoke();
if (powershell.HadErrors)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (var errorRecord in powershell.Streams.Error)
{
stringBuilder.AppendLine(errorRecord.ToString());
}
Console.Write(stringBuilder.ToString());
throw new Exception("Error occured during file copy.");
}
powershell.Dispose();
}
private Runspace OpenRunspace(bool opened = true)
{
Runspace remoteRunspace = null;
getRunspace(
string.Format("https://{0}/wsman", hostAddress),
winrmPort,
ShellSchema,
username,
password,
ref remoteRunspace
);
if (opened)
remoteRunspace.Open();
return remoteRunspace;
}
private static void getRunspace(string uri, int port, string schema, string username, string livePass, ref Runspace remoteRunspace)
{
SecureString password = new SecureString();
livePass.ToCharArray().ToList().ForEach(p => password.AppendChar(p));
PSCredential psc = new PSCredential(username, password);
WSManConnectionInfo rri = new WSManConnectionInfo(new Uri(uri), schema, psc);
rri.AuthenticationMechanism = AuthenticationMechanism.Basic;
rri.Port = port;
rri.ProxyAuthentication = AuthenticationMechanism.Negotiate;
rri.SkipCACheck = true;
rri.SkipCNCheck = true;
rri.SkipRevocationCheck = true;
remoteRunspace = RunspaceFactory.CreateRunspace(rri);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment