3

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:

  1. Copy local file to \RemoteComputer1\Folder
  2. Copy file from \RemoteComputer1\Folder to \RemoteComputer2\Folder
  3. 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.

Community
  • 1
  • 1
Misiu
  • 4,738
  • 21
  • 94
  • 198
  • As long as the shares are not on the same computer you can do this as long you map the drives with the right users, it should then use the right access to the right drive - but being windows, it may not, especially if both users have access. – BugFinder Aug 19 '16 at 09:00
  • @BugFinder sorry I didn't wrote that in my question. Shares can sometimes be on same computer. My streams solution works in my test cases, but as I mentioned I'd like to use File.Copy instead of streams if it is possible and avoid mapping everything as drive. I need to move multiple files across network between different places. Ideally I like to impersonate whole folders and copy multiple files between them without need to call impersonate for each file. This would speed thing a lot. – Misiu Aug 19 '16 at 09:14
  • then that would be harder .. you cant map two shares with different IDs on the same machine.. you would almost certainly need to read to memory and then pass to an impersonated thread to write out the new – BugFinder Aug 19 '16 at 09:33
  • @BugFinder that's what I'm doing right now. I create one impersonated stream with read access and second impersonated stream with write access. Then I simply do `source.CopyTo(destination)` – Misiu Aug 19 '16 at 09:40
  • I dont think you can avoid streams if you have potential of same server – BugFinder Aug 19 '16 at 09:45
  • @BugFinder I don't know either, that's why I've created this question :) I would like to have better, more optimized solution (if it is possible). – Misiu Aug 19 '16 at 09:52
  • I have the same challenge. What I did was create stealth mapped drives for each share and handled the copy with File.Copy. BUT, mapped drives on windows is a pain. Can't seem to remove them consistently. So I'm relooking at this. – TheLegendaryCopyCoder May 14 '18 at 14:28
  • @TheLegendaryCopyCoder I'm using this solution for more than a Year in couple of applications. I didn't found better solution, so if You find something interesting please let me know :) – Misiu May 14 '18 at 14:30
  • @Misui will do, i might post the mapped drive solution as an alternative if I can figure out a way to solve removing the mapped drive consistently afterwards. – TheLegendaryCopyCoder May 14 '18 at 14:33

0 Answers0