2011-09-26 190 views
3

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

我设法做到了没有凭据(我的凭据),但是当我用另一个用户名和另一个密码来做它时,它会打开一个提示输入用户名和密码,它说“访问被拒绝” 。

在远程桌面的访问日志中,它表示我试图连接自己的用户名,而不是我输入的其他用户名。所以,这个过程显然不起作用。

但是,我不明白为什么。我的代码如下:

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() 

回答

6

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

'***************************************************************************************** 
'***************************************************************************************** 
' 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 

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

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() 
+0

我相信它的原因是,即使你给这个过程正确的凭证,它只会使用凭证的过程。问题在于你的会话将使用你的凭证,模拟会冒充同一个用户的开始和结束模拟之间的代码块。 –

+0

完全正确。 –

+0

谢谢,它工作 – Mitchel