How to transfer files to a shared folder using IP address in C#

6.9k Views Asked by At

I am new in C#, i am having a PowerShell Script to send files to multiple PC using IP address and username, there I am using new-PSDrive. I want to create the same program in C#.

I am not sure how to do that i went through some tutorials and tried it out but stuck with Windows Impersonate Class. It was written in the post that i followed that: _If we want to share file to a shared folder we can use File.Copy(destPath, SourcePath) but its not working.

This is the Code i am trying :

WindowsIdentity idnt = new WindowsIdentity("Administrator", "Test123!");
WindowsImpersonationContext context = idnt.Impersonate();
File.Copy(@"C:\\Sent.txt", @"\\192.xxx.xxx.xxx\\SharedFolder", true);
context.Undo(); 

An error Pop's up : The name provided is not a properly formed account name. WindowsIdentity idnt = new WindowsIdentity("Administrator", "Test123!");

I don't know how to get proper name, i am trying this : WindowsIdentity idnt = new WindowsIdentity(Username,Password);

I also trien this ("\192.xxx.xxx.xxx\WIN-9SMSBCR4V7B\SharedFolder",Password);

The Machine on which i want to copy files is running on Vmware on same machine and i am able to send using Powershell Script.

Any suggestion would be appreciated.

2

There are 2 best solutions below

0
On BEST ANSWER

Found the Solution, Here's the complete code for sending files to a remote PC using its IP address, UserName and Password for machines which are not on same DOMAIN. Here the Link which explains the use of correct LOGON PROVIDER

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;
using System.IO;

namespace File_Send_Test
{
    class Program
    {
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
         int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        public extern static bool CloseHandle(IntPtr handle);

        // Test harness.
        // If you incorporate this code into a DLL, be sure to demand FullTrust.
        [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
        public static void Main(string[] args)
        {
            SafeTokenHandle safeTokenHandle;
            try
            {
                string userName, domainName;
                //domainName = Console.ReadLine();
                domainName = ".";

                Console.Write("Enter the login of a user on {0} that you wish to impersonate: ", domainName);
                //provide username of remote machine.
                userName = Console.ReadLine();
                //provide password of remote machine.
                Console.Write("Enter the password for {0}: ", userName);

                //Here's the Catch 
                //LOGON32_PROVIDER_WinNT50 = 3; and LOGON32_LOGON_NewCredentials = 9;
                const int LOGON32_PROVIDER_WinNT50 = 3;
                //This parameter causes LogonUser to create a primary token.
                const int LOGON32_LOGON_NewCredentials = 9;

                // Call LogonUser to obtain a handle to an access token.
                bool returnValue = LogonUser(userName, domainName, Console.ReadLine(),
                    LOGON32_LOGON_NewCredentials, LOGON32_PROVIDER_WinNT50,
                    out safeTokenHandle);

                Console.WriteLine("LogonUser called.");

                if (false == returnValue)
                {
                    int ret = Marshal.GetLastWin32Error();
                    Console.WriteLine("LogonUser failed with error code : {0}", ret);
                    throw new System.ComponentModel.Win32Exception(ret);
                }
                using (safeTokenHandle)
                {
                    Console.WriteLine("Did LogonUser Succeed? " + (returnValue ? "Yes" : "No"));
                    Console.WriteLine("Value of Windows NT token: " + safeTokenHandle);

                    // Check the identity.
                    Console.WriteLine("Before impersonation: "
                        + WindowsIdentity.GetCurrent().Name);
                    // Use the token handle returned by LogonUser.
                    using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
                    {
                        using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
                        {

                            // Check the identity.
                            Console.WriteLine("After impersonation: "
                                + WindowsIdentity.GetCurrent().Name);
                            //File.Copy(Source File,DestinationFile);
                            File.Copy(@"C:\\Sent.txt", @"\\192.168.xxx.xxx\\Suji\\Sent.txt", true);
                        }
                    }
                    // Releasing the context object stops the impersonation
                    // Check the identity.
                    Console.WriteLine("After closing the context: " + WindowsIdentity.GetCurrent().Name);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Exception occurred. " + ex.Message);
            }
            Console.ReadLine();
        }
    }
    public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle()
            : base(true)
        {
        }

        [DllImport("kernel32.dll")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    }
}

Hope this would help others.

1
On

You would have thought copying a file from one folder to a remote share (which needs a user name / password) would be simple ! But, it is not !

The following 2 links provide some options:

(1) How to provide user name and password when connecting to a network share

The above links is about mapping a network drive first and then doing a file copy

(2) copy files with authentication in c#

This option is about using the WindowsIdentity class (as you have attempted). The above link gives a way to construct the object in a correct way

Both of the above options, in a way, are NOT pure .Net solutions. They call Win32 APIs directly.

Another option:

If you could have a mapped network connection created (outside of your application) first, then a simple file copy would work.

In that case the steps would be:

(1) Map a drive to the shared folder using an user name and password, using the net use command

net use Z: /delete
net use Z: \\server name\share name password /user:user name

(2) Run your copy program

File.Copy(sourceFileName, @"Z:\path\to\folder\filename");

(3) Remove the drive mapping

net use Z: /delete