Accessing a network file share with C#

Accessing a network file share with C#

Author: Harold GregoryDate: 2022-07-11

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. I had to do something like this: Question: I want to access drives/folders/sub-folders/files on remote machines over network for a machine in C#.

Accessing a network file share with C#

Question:

I've never done this before, and all of the research I've done indicates needing user names/passwords. Here's the situation: I am developing an app for my company, and the app needs to access a file share on the network. Let's call that file share  \\server\TPK  . My app needs to get files from this folder on this share. Is working with file shares on a company network the same as working with File I/O (  System.IO  )? Can anyone give me any guidance on how to do this? I know this probably is an elementary question, and I apologize for that.


Solution 1:

Generally speaking, yes. It's the same. Just use the UNC path as you've stated. You may have security issues depending on how your application is running but a quick test should be something like:

FileInfo myFile = new FileInfo(@"\\server\TPK\some-file-that-exists.pdf");
bool exists = myFile.Exists;

Just point it to a file that you know exists and see if it finds it. You may have to deal with Credentials or Identity depending on the configuration of your application. If this is the case you should get an Exception stating "Access Denied" or something along those lines.

Solution 2:

It's not that obviously possible.

I had to do something like this:

public class SharedLocationConnector : IDisposable
{
    char driveLetter;
    bool disposed = false;
    public char ConnectToLocation(string path, string userName, string pwd)
    {
        driveLetter = MapShare(path, userName, pwd);
        Thread.Sleep(2000); //It takes that much for connection to happen
        return driveLetter;
    }
    private char MapShare(string path, string username, string pwd)
    {
        char driveLetter = GetAvailableDriveLetter();
        string cmdString = "net use " + driveLetter + ": " + path + ((username != string.Empty) ? " /user:" + username + " " + pwd : "");
        ManagementClass processClass = new ManagementClass("Win32_Process");
        object[] methodArgs = { cmdString, null, null, 0 };
        object result = processClass.InvokeMethod("Create", methodArgs);
        return driveLetter;
    }
    public void  Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    private void Dispose(bool disposing)
    {
        if (!disposed)
        {
            //Dispose managed objects. Thre are none.
            //Dispose unmanaged objects
            if (!String.IsNullOrWhiteSpace(driveLetter.ToString()))
                FileUtils.DisconnectSambaShare(driveLetter);
            disposed = true;
        }
    }
    ~SharedLocationConnector()
    {
        Dispose(false);
    }
    public void Disconnect()
    {
        if (!String.IsNullOrWhiteSpace(driveLetter.ToString()))
            DisconnectShare(driveLetter);
    }
    private void DisconnectShare(char driveLetter)
    {
        string cmdString = "net use " + driveLetter + ": /DELETE";
        ManagementClass processClass = new ManagementClass("Win32_Process");
        object[] methodArgs = { cmdString, null, null, 0 };
        object result = processClass.InvokeMethod("Create", methodArgs);
    }
}

Remote Shared folders and drives C#

Question:

I want to access drives/folders/sub-folders/files on remote machines over network for a machine in C#.

I know of a using WMI for this. However WMI might not be executable over remote machines due to security permissions.

What are alternative way in C# to enumerate the folders/subfolders/files for remote machines over the network.

Thanks! Gagan


Solution 1:

Shared folders on a UNC path can be enumerated just like local directories, using the classes in the System.IO namespace, like  Directory.EnumerateFiles  .

foreach (var file in Directory.EnumerateFiles(@"\\machine\c$"))
{
}

However, as you say, there's a question of credentials. If you need to specify different credentials to access the shares, you'll have to authenticate against the remote machine. Luckily, there's a great solution in this answer for creating ad-hoc network connections:

using (new NetworkConnection("\\machine\c$", new NetworkCredential("username", "password")))
{
    foreach (var file in Directory.EnumerateFiles(@"\\machine\c$"))
    {
    }
}

Solution 2:

You can use  forfiles  , i am assuming all the machines are  Windows  .

Refer to this link for more information: Forfiles

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

Question:

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.


Solution 1:

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.

Solution 2:

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

 Nguồn: https://copyprogramming.com/howto/accessing-a-network-file-share-with-c#accessing-a-network-file-share-with-c

Comments

Popular posts from this blog

ASP.NET MVC + AdminLTE

Create schedule Restart SQL Server

Bỏ dấu tiếng việt