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

后端 未结 11 1620
不知归路
不知归路 2020-11-22 00:34

When connecting to a network share for which the current user (in my case, a network enabled service user) has no rights, name and password have to be provided.

I kn

相关标签:
11条回答
  • 2020-11-22 01:24

    I searched lots of methods and i did it my own way. You have to open a connection between two machine via command prompt NET USE command and after finishing your work clear the connection with command prompt NET USE "myconnection" /delete.

    You must use Command Prompt process from code behind like this:

    var savePath = @"\\servername\foldername\myfilename.jpg";
    var filePath = @"C:\\temp\myfileTosave.jpg";
    

    Usage is simple:

    SaveACopyfileToServer(filePath, savePath);
    

    Here is functions:

    using System.IO
    using System.Diagnostics;
    
    
    public static void SaveACopyfileToServer(string filePath, string savePath)
        {
            var directory = Path.GetDirectoryName(savePath).Trim();
            var username = "loginusername";
            var password = "loginpassword";
            var filenameToSave = Path.GetFileName(savePath);
    
            if (!directory.EndsWith("\\"))
                filenameToSave = "\\" + filenameToSave;
    
            var command = "NET USE " + directory + " /delete";
            ExecuteCommand(command, 5000);
    
            command = "NET USE " + directory + " /user:" + username + " " + password;
            ExecuteCommand(command, 5000);
    
            command = " copy \"" + filePath + "\"  \"" + directory + filenameToSave + "\"";
    
            ExecuteCommand(command, 5000);
    
    
            command = "NET USE " + directory + " /delete";
            ExecuteCommand(command, 5000);
        }
    

    And also ExecuteCommand function is:

    public static int ExecuteCommand(string command, int timeout)
        {
            var processInfo = new ProcessStartInfo("cmd.exe", "/C " + command)
                                  {
                                      CreateNoWindow = true, 
                                      UseShellExecute = false, 
                                      WorkingDirectory = "C:\\",
                                  };
    
            var process = Process.Start(processInfo);
            process.WaitForExit(timeout);
            var exitCode = process.ExitCode;
            process.Close();
            return exitCode;
        } 
    

    This functions worked very fast and stable for me.

    0 讨论(0)
  • 2020-11-22 01:24

    Also ported to F# to use with FAKE

    module NetworkShare
    
    open System
    open System.ComponentModel
    open System.IO
    open System.Net
    open System.Runtime.InteropServices
    
    type ResourceScope =
    | Connected = 1
    | GlobalNetwork = 2
    | Remembered = 3
    | Recent = 4
    type ResourceType =
    | Any = 0
    | Disk = 1
    | Print = 2
    | Reserved = 8
    type ResourceDisplayType =
    | Generic = 0x0
    | Domain = 0x01
    | Server = 0x02
    | Share = 0x03
    | File = 0x04
    | Group = 0x05
    | Network = 0x06
    | Root = 0x07
    | Shareadmin = 0x08
    | Directory = 0x09
    | Tree = 0x0a
    | Ndscontainer = 0x0b
    
    //Uses of this construct may result in the generation of unverifiable .NET IL code.
    #nowarn "9"
    [<StructLayout(LayoutKind.Sequential)>]
    type NetResource =
      struct
        val mutable Scope : ResourceScope
        val mutable ResourceType : ResourceType
        val mutable DisplayType : ResourceDisplayType
        val mutable Usage : int
        val mutable LocalName : string
        val mutable RemoteName : string
        val mutable Comment : string
        val mutable Provider : string
        new(name) = {
          // lets preset needed fields
          NetResource.Scope = ResourceScope.GlobalNetwork
          ResourceType = ResourceType.Disk
          DisplayType = ResourceDisplayType.Share
          Usage = 0
          LocalName = null
          RemoteName = name
          Comment = null
          Provider = null
        }
      end
    
    type WNetConnection(networkName : string, credential : NetworkCredential) =
      [<Literal>]
      static let Mpr = "mpr.dll"
      [<DllImport(Mpr, EntryPoint = "WNetAddConnection2")>]
      static extern int connect(NetResource netResource, string password, string username, int flags)
      [<DllImport(Mpr, EntryPoint = "WNetCancelConnection2")>]
      static extern int disconnect(string name, int flags, bool force)
    
      let mutable disposed = false;
    
      do
        let userName = if String.IsNullOrWhiteSpace credential.Domain
                       then credential.UserName
                       else credential.Domain + "\\" + credential.UserName
        let resource = new NetResource(networkName)
    
        let result = connect(resource, credential.Password, userName, 0)
    
        if result <> 0 then
          let msg = "Error connecting to remote share " + networkName
          new Win32Exception(result, msg)
          |> raise
    
      let cleanup(disposing:bool) =
        if not disposed then
          disposed <- true
          if disposing then () // TODO dispose managed resources here
          disconnect(networkName, 0, true) |> ignore
    
      interface IDisposable with
        member __.Dispose() =
          disconnect(networkName, 0, true) |> ignore
          GC.SuppressFinalize(__)
    
      override __.Finalize() = cleanup(false)
    
    type CopyPath =
      | RemotePath of string * NetworkCredential
      | LocalPath of string
    
    let createDisposable() =
      {
        new IDisposable with
          member __.Dispose() = ()
      }
    
    let copyFile overwrite destPath srcPath : unit =
      use _srcConn =
        match srcPath with
        | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
        | LocalPath(_) -> createDisposable()
      use _destConn =
        match destPath with
        | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
        | LocalPath(_) -> createDisposable()
      match srcPath, destPath with
      | RemotePath(src, _), RemotePath(dest, _)
      | LocalPath(src), RemotePath(dest, _)
      | RemotePath(src, _), LocalPath(dest)
      | LocalPath(src), LocalPath(dest) ->
        if FileInfo(src).Exists |> not then
          failwith ("Source file not found: " + src)
        let destFilePath =
          if DirectoryInfo(dest).Exists then Path.Combine(dest, Path.GetFileName src)
          else dest
        File.Copy(src, destFilePath, overwrite)
    
    let rec copyDir copySubDirs filePattern destPath srcPath =
      use _srcConn =
        match srcPath with
        | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
        | LocalPath(_) -> createDisposable()
      use _destConn =
        match destPath with
        | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
        | LocalPath(_) -> createDisposable()
      match srcPath, destPath with
      | RemotePath(src, _), RemotePath(dest, _)
      | LocalPath(src), RemotePath(dest, _)
      | RemotePath(src, _), LocalPath(dest)
      | LocalPath(src), LocalPath(dest) ->
        let dir = DirectoryInfo(src)
        if dir.Exists |> not then
          failwith ("Source directory not found: " + src)
    
        let dirs = dir.GetDirectories()
        if Directory.Exists(dest) |> not then
          Directory.CreateDirectory(dest) |> ignore
    
        let files = dir.GetFiles(filePattern)
        for file in files do
          let tempPath = Path.Combine(dest, file.Name)
          file.CopyTo(tempPath, false) |> ignore
    
        if copySubDirs then
          for subdir in dirs do
            let subdirSrc =
              match srcPath with
              | RemotePath(_, credential) -> RemotePath(Path.Combine(dest, subdir.Name), credential)
              | LocalPath(_) -> LocalPath(Path.Combine(dest, subdir.Name))
            let subdirDest =
              match destPath with
              | RemotePath(_, credential) -> RemotePath(subdir.FullName, credential)
              | LocalPath(_) -> LocalPath(subdir.FullName)
            copyDir copySubDirs filePattern subdirDest subdirSrc
    
    0 讨论(0)
  • 2020-11-22 01:26

    One option that might work is using WindowsIdentity.Impersonate (and change the thread principal) to become the desired user, like so. Back to p/invoke, though, I'm afraid...

    Another cheeky (and equally far from ideal) option might be to spawn a process to do the work... ProcessStartInfo accepts a .UserName, .Password and .Domain.

    Finally - perhaps run the service in a dedicated account that has access? (removed as you have clarified that this isn't an option).

    0 讨论(0)
  • 2020-11-22 01:28

    OK... I can resond..

    Disclaimer: I just had an 18+ hour day (again).. I'm old and forgetfull.. I can't spell.. I have a short attention span so I better respond fast.. :-)

    Question:

    Is it possible to change the thread principal to an user with no account on the local machine?

    Answer:

    Yes, you can change a thread principal even if the credentials you are using are not defined locally or are outside the "forest".

    I just ran into this problem when trying to connect to an SQL server with NTLM authentication from a service. This call uses the credentials associated with the process meaning that you need either a local account or a domain account to authenticate before you can impersonate. Blah, blah...

    But...

    Calling LogonUser(..) with the attribute of ????_NEW_CREDENTIALS will return a security token without trying to authenticate the credentials. Kewl.. Don't have to define the account within the "forest". Once you have the token you might have to call DuplicateToken() with the option to enable impersonation resulting in a new token. Now call SetThreadToken( NULL, token ); (It might be &token?).. A call to ImpersonateLoggedonUser( token ); might be required, but I don't think so. Look it up..

    Do what you need to do..

    Call RevertToSelf() if you called ImpersonateLoggedonUser() then SetThreadToken( NULL, NULL ); (I think... look it up), and then CloseHandle() on the created handles..

    No promises but this worked for me... This is off the top of my head (like my hair) and I can't spell!!!

    0 讨论(0)
  • 2020-11-22 01:28

    If you can't create an locally valid security token, it seems like you've ruled all out every option bar Win32 API and WNetAddConnection*.

    Tons of information on MSDN about WNet - PInvoke information and sample code that connects to a UNC path here:

    http://www.pinvoke.net/default.aspx/mpr/WNetAddConnection2.html#

    MSDN Reference here:

    http://msdn.microsoft.com/en-us/library/aa385391(VS.85).aspx

    0 讨论(0)
提交回复
热议问题