I have two network shares that both have dedicated accounts (network credentials) to access them
For example:
\RemoteComputer1\Folder - user1
\RemoteComputer2\Folder - user2
user1 don't have access to local computer and to \RemoteComputer2\Folder, same with user2, he doesn't have access to local computer and \RemoteComputer1\Folder.
I need to be able to do 3 types of operations:
- Copy local file to \RemoteComputer1\Folder
- Copy file from \RemoteComputer1\Folder to \RemoteComputer2\Folder
- Copy file from \RemoteComputer1\Folder to local folder
Right now I'm using https://github.com/mj1856/SimpleImpersonation to get source stream and target stream and then I'm copying from source to target stream using stream.CopyTo
Below is my current code:
public static void CopyWithCredentials(string @sourcePath, string destinationPath, NetworkCredential readUser = null, NetworkCredential writeUser = null)
{
//same user, do normal File.Copy
if (readUser!=null && writeUser!=null && readUser == writeUser)
{
using (Impersonation.LogonUser(readUser.Domain, readUser.UserName, readUser.Password, LogonType.NewCredentials))
{
if (!Directory.Exists(Path.GetDirectoryName(destinationPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
}
File.Copy(@sourcePath, destinationPath);
return;
}
}
FileStream sourceStream;
if (readUser != null)
{
using (Impersonation.LogonUser(readUser.Domain, readUser.UserName, readUser.Password, LogonType.NewCredentials))
{
sourceStream = new FileStream(@sourcePath, FileMode.OpenOrCreate, System.IO.FileAccess.Read);
}
}
else
{
sourceStream = new FileStream(@sourcePath, FileMode.OpenOrCreate, System.IO.FileAccess.Read);
}
FileStream destinationStream;
if (writeUser != null)
{
using (Impersonation.LogonUser(writeUser.Domain, writeUser.UserName, writeUser.Password, LogonType.NewCredentials))
{
if (!Directory.Exists(Path.GetDirectoryName(destinationPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
}
while (File.Exists(destinationPath))
{
string fileName = Path.GetFileNameWithoutExtension(destinationPath);
string newFileName = fileName + "1";
destinationPath = destinationPath.Replace(fileName, newFileName);
}
destinationStream = File.Create(destinationPath);
}
}
else
{
if (!Directory.Exists(Path.GetDirectoryName(destinationPath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
}
destinationStream = File.Create(destinationPath);
}
#warning is this enough for closing streams after copying?
using (sourceStream)
{
using (destinationStream)
{
sourceStream.CopyTo(destinationStream);
}
}
sourceStream.Dispose();
destinationStream.Dispose();
sourceStream = null;
destinationStream = null;
}
I must admit this looks ugly and over-complicated.
Problem is I have multiple files in one folder and I want to copy all of them to second folder. Using my approach I call LogonUser
twice for each file. For 1000 files I must call it 2000 times. Ideally I'd like to call LogonUser
twice (ones for first folder and second time for second folder) and copy all files in that "session".
I would like to use File.Copy because it uses native kernel32.dll function (https://stackoverflow.com/a/1247092/965722) and as I found out in same question File.Copy has much improved since Vista SP1.
Also I found question about File.Copy and Stream speed and it looks like they should be equal, because File.Copy is using streams.
My question is: Can this be done simpler without using streams?
I don't want to create super admin account that has access everywhere.
I'd like to avoid WNetUseConnection because it can leave open connections.
I don't want to add permissions per files as mentioned in comments to this question.