vb.net 使用凭据打开远程共享文件夹

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7559867/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 15:42:04  来源:igfitidea点击:

Open remote shared folder with credentials

vb.netsharedexplorer

提问by Mitchel

I need to open a folder on a remote server with different credentials in a window (explorer.exe).

我需要在一个窗口 (explorer.exe) 中使用不同的凭据在远程服务器上打开一个文件夹。

I managed to do it with no credentials (my credentials), but when I do it with another username and another password than mine, it opens a prompt to enter a username and a password, and it says "access denied".

我设法在没有凭据(我的凭据)的情况下执行此操作,但是当我使用另一个用户名和另一个密码执行此操作时,它会打开一个输入用户名和密码的提示,并显示“拒绝访问”。

In the access log on the remote desktop, it says that I tried to connect with my own username, and not the other username I entered. So, the process obviously did not work.

在远程桌面上的访问日志中,它说我尝试使用自己的用户名进行连接,而不是我输入的其他用户名。所以,这个过程显然是行不通的。

But, I can't figure out why. My code is as follows:

但是,我想不通为什么。我的代码如下:

Dim domain, username, passwordStr, remoteServerName As String
Dim password As New Security.SecureString
Dim command As New Process

domain = "domain.com"
username = "username"
passwordStr = "password"
remoteServerName = "serverName"

For Each c As Char In passwordStr.ToCharArray
    password.AppendChar(c)
Next


command.StartInfo.FileName = "explorer.exe"
command.StartInfo.Arguments = "\" & serverName & "\admin$\Temp"

command.StartInfo.UserName = username
command.StartInfo.Password = password
command.StartInfo.Domain = domain
command.StartInfo.Verb = "open"
command.StartInfo.UseShellExecute = False

command.Start()

回答by Chris Santiago

I ran into this same problem at work and was able to solve it with impersonation. just add a new class with the following:

我在工作中遇到了同样的问题,并且能够通过模拟解决它。只需添加一个具有以下内容的新类:

    '*****************************************************************************************
'*****************************************************************************************
' Contents: AliasAccount Class
'
' This Class is a template class that provides all the functionality to impersonate a user
' over a designated instance.
'*****************************************************************************************
'*****************************************************************************************


Public Class AliasAccount
  Private _username, _password, _domainname As String

  Private _tokenHandle As New IntPtr(0)
  Private _dupeTokenHandle As New IntPtr(0)
  Private _impersonatedUser As System.Security.Principal.WindowsImpersonationContext


  Public Sub New(ByVal username As String, ByVal password As String)
    Dim nameparts() As String = username.Split("\")
    If nameparts.Length > 1 Then
      _domainname = nameparts(0)
      _username = nameparts(1)
    Else
      _username = username
    End If
    _password = password
  End Sub

  Public Sub New(ByVal username As String, ByVal password As String, ByVal domainname As String)
    _username = username
    _password = password
    _domainname = domainname
  End Sub


  Public Sub BeginImpersonation()
    'Const LOGON32_PROVIDER_DEFAULT As Integer = 0
    'Const LOGON32_LOGON_INTERACTIVE As Integer = 2
    Const LOGON32_LOGON_NEW_CREDENTIALS As Integer = 9
    Const LOGON32_PROVIDER_WINNT50 As Integer = 3
    Const SecurityImpersonation As Integer = 2

    Dim win32ErrorNumber As Integer

    _tokenHandle = IntPtr.Zero
    _dupeTokenHandle = IntPtr.Zero

    If Not LogonUser(_username, _domainname, _password, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_WINNT50, _tokenHandle) Then
      win32ErrorNumber = System.Runtime.InteropServices.Marshal.GetLastWin32Error()
      Throw New ImpersonationException(win32ErrorNumber, GetErrorMessage(win32ErrorNumber), _username, _domainname)
    End If

    If Not DuplicateToken(_tokenHandle, SecurityImpersonation, _dupeTokenHandle) Then
      win32ErrorNumber = System.Runtime.InteropServices.Marshal.GetLastWin32Error()

      CloseHandle(_tokenHandle)
      Throw New ImpersonationException(win32ErrorNumber, "Unable to duplicate token!", _username, _domainname)
    End If

    Dim newId As New System.Security.Principal.WindowsIdentity(_dupeTokenHandle)
    _impersonatedUser = newId.Impersonate()
  End Sub


  Public Sub EndImpersonation()
    If Not _impersonatedUser Is Nothing Then
      _impersonatedUser.Undo()
      _impersonatedUser = Nothing

      If Not System.IntPtr.op_Equality(_tokenHandle, IntPtr.Zero) Then
        CloseHandle(_tokenHandle)
      End If
      If Not System.IntPtr.op_Equality(_dupeTokenHandle, IntPtr.Zero) Then
        CloseHandle(_dupeTokenHandle)
      End If
    End If
  End Sub


  Public ReadOnly Property username() As String
    Get
      Return _username
    End Get
  End Property

  Public ReadOnly Property domainname() As String
    Get
      Return _domainname
    End Get
  End Property


  Public ReadOnly Property currentWindowsUsername() As String
    Get
      Return System.Security.Principal.WindowsIdentity.GetCurrent().Name
    End Get
  End Property


#Region "Exception Class"
  Public Class ImpersonationException
    Inherits System.Exception

    Public ReadOnly win32ErrorNumber As Integer

    Public Sub New(ByVal win32ErrorNumber As Integer, ByVal msg As String, ByVal username As String, ByVal domainname As String)
      MyBase.New(String.Format("Impersonation of {1}\{0} failed! [{2}] {3}", username, domainname, win32ErrorNumber, msg))
      Me.win32ErrorNumber = win32ErrorNumber
    End Sub
  End Class
#End Region


#Region "External Declarations and Helpers"
  Private Declare Auto Function LogonUser Lib "advapi32.dll" (ByVal lpszUsername As [String], _
          ByVal lpszDomain As [String], ByVal lpszPassword As [String], _
          ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, _
          ByRef phToken As IntPtr) As Boolean


  Private Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal ExistingTokenHandle As IntPtr, _
              ByVal SECURITY_IMPERSONATION_LEVEL As Integer, _
              ByRef DuplicateTokenHandle As IntPtr) As Boolean


  Private Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean


  <System.Runtime.InteropServices.DllImport("kernel32.dll")> _
  Private Shared Function FormatMessage(ByVal dwFlags As Integer, ByRef lpSource As IntPtr, _
          ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, ByRef lpBuffer As [String], _
          ByVal nSize As Integer, ByRef Arguments As IntPtr) As Integer
  End Function


  Private Function GetErrorMessage(ByVal errorCode As Integer) As String
    Dim FORMAT_MESSAGE_ALLOCATE_BUFFER As Integer = &H100
    Dim FORMAT_MESSAGE_IGNORE_INSERTS As Integer = &H200
    Dim FORMAT_MESSAGE_FROM_SYSTEM As Integer = &H1000

    Dim messageSize As Integer = 255
    Dim lpMsgBuf As String = ""
    Dim dwFlags As Integer = FORMAT_MESSAGE_ALLOCATE_BUFFER Or FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS

    Dim ptrlpSource As IntPtr = IntPtr.Zero
    Dim prtArguments As IntPtr = IntPtr.Zero

    Dim retVal As Integer = FormatMessage(dwFlags, ptrlpSource, errorCode, 0, lpMsgBuf, messageSize, prtArguments)
    If 0 = retVal Then
      Throw New System.Exception("Failed to format message for error code " + errorCode.ToString() + ". ")
    End If

    Return lpMsgBuf
  End Function

#End Region

End Class

This will allow you to impersonate a designated user for a session. so you would than change your code to:

这将允许您模拟会话的指定用户。所以你会比改变你的代码:

Dim domain, username, passwordStr, remoteServerName As String    
Dim password As New Security.SecureString    
Dim command As New Process  

domain = "domain.com"    
username = "username"    
passwordStr = "password"    
remoteServerName = "serverName"
Dim impersonator As New AliasAccount(username, password)

For Each c As Char In passwordStr.ToCharArray        
  password.AppendChar(c)    
Next


command.StartInfo.FileName = "explorer.exe"    
command.StartInfo.Arguments = "\" & serverName & "\admin$\Temp"        

command.StartInfo.UserName = username    
command.StartInfo.Password = password    
command.StartInfo.Domain = domain    
command.StartInfo.Verb = "open"    
command.StartInfo.UseShellExecute = False 

  impersonator.BeginImpersonation()
command.Start() 
  impersonator.EndImpersonation()

回答by LilDipper

The answer given is a very long-winded solution that is unnecessary. I know the answer is from 2011, but all you need to do is the following:

给出的答案是一个非常冗长的解决方案,是不必要的。我知道答案是从 2011 年开始的,但您需要做的就是以下几点:

Public Sub Open_Remote_Connection(ByVal strComputer As String, ByVal strUsername As String, ByVal strPassword As String)
    Try
        Dim procInfo As New ProcessStartInfo
        procInfo.FileName = "net"
        procInfo.Arguments = "use \" & strComputer & "\c$ /USER:" & strUsername & " " & strPassword
        procInfo.WindowStyle = ProcessWindowStyle.Hidden
        procInfo.CreateNoWindow = True

        Dim proc As New Process
        proc.StartInfo = procInfo
        proc.Start()
        proc.WaitForExit(15000)
    Catch ex As Exception
        MsgBox("Open_Remote_Connection" & vbCrLf & vbCrLf & ex.Message, 4096, "Error")
    End Try
End Sub

and then this function to actually open the C$ share:

然后这个函数来实际打开 C$ 共享:

Private Sub OpenCDriveofPC(ByVal compName As String)
    Try
        If isPingable(compName) Then
            Open_Remote_Connection(compName, strUserName, strPassword)
            Process.Start("explorer.exe", "\" & compName & "\c$")
        End If
    Catch ex As Exception
        MsgBox("OpenCDriveofPC" & vbCrLf & vbCrLf & ex.message, 4096, "Error")
    Finally
        Close_Remote_Connection("net use \" & compName & "\c$ /delete /yes")
    End Try

And here is the 'Close_Remote_Connection' sub, which needs to be called so that you don't make your net use list get crazy huge. Even if you call this sub, you will still have full admin rights to the c$ you open:

这里是“Close_Remote_Connection”子,它需要被调用,这样你就不会让你的网络使用列表变得非常庞大。即使你调用这个 sub,你仍然对你打开的 c$ 拥有完全的管理员权限:

Public Sub Close_Remote_Connection(ByVal device As String)
    Shell("cmd.exe /c " & device, vbHidden)
End Sub

I looked all over the Internet for how to do this and no one came even close to this simplicity. It does exactly what you want and is crazy simple and not long-winded with all sorts of crazy functions/classes that just are not needed to do this simple thing.

我在互联网上四处寻找如何做到这一点,但没有人能做到这一点。它完全符合您的要求,而且非常简单,并且没有冗长的各种疯狂的函数/类,而这些函数/类并不是做这个简单的事情所必需的。

Hope it helps others like it helped me! :)

希望它可以帮助其他人,就像它对我的帮助一样!:)

LilD

律所