VB.Net Impersonate a specified User in code
I had some trouble finding a method that worked the way I wanted, and finally found this lovely little class – can’t remember where I originally got it from but it’s definitely worth sharing…
NOTE: If you just want to start a process (run a program) as another user it may be easier to use the little snippet of code at the end of this article instead.
I prefer executable files to scripts, and require low privilege users to be able to run sections of the code/script with elevated privileges but without IT intervention – this does the job nicely. Whapped it into exes/scripts that required elevated privileges and now my most menial of users can run them with no Admin intervention 😉
Just add a new vb class to your project and save it as RunAs_Impersonator – then copy the code below over the entire RunAs_Impersonator page. In case of problems on pasting, you can click here for the .TXT RunAs_Impersonator.txt, or here for the zipped class file RunAs_Impersonator.vb. You may need to add references to the Imports…
Once in your project, any sections of code that require running with elevated privileges are preceeded by:
Dim imp As New RunAs_Impersonator ‘(somewhere in your declarations)
–
–
imp.ImpersonateStart(‘YourDomain’, ‘UserName’, ‘UserPassword’)
– – – Code to run with elevated privileges – – –
imp.ImpersonateStop()
To run as a local account rather than a Domain User use ‘.’ (full stop) for the Domain.
Recently migrated 500 users, PCs, and 60 Servers to our new owners domain at short notice (1 week) – a most entertaining and quite educational experience… Didn’t go too badly considering – managed to keep both main Call Centres and payment processing running throughout so a success in my book – I’ll be posting about a few of the VB.Net tweaks I needed to get things working properly again.
RunAs_Impersonator code is below:
Imports System
Imports System.Runtime.InteropServices
Imports System.Security.Principal
Imports System.Security.Permissions
Imports Microsoft.VisualBasic
<Assembly: SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode:=True), _
Assembly: PermissionSetAttribute(SecurityAction.RequestMinimum, Name:="FullTrust")>
Public Class RunAs_Impersonator
#Region "Private Variables and Enum Constants"
Private tokenHandle As New IntPtr(0)
Private dupeTokenHandle As New IntPtr(0)
Private impersonatedUser As WindowsImpersonationContext
#End Region
#Region "Properties"
#End Region
#Region "Public Methods"
Public Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean
Public Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal ExistingTokenHandle As IntPtr, _
ByVal SECURITY_IMPERSONATION_LEVEL As Integer, _
ByRef DuplicateTokenHandle As IntPtr) As Boolean
' Test harness.
' If you incorporate this code into a DLL, be sure to demand FullTrust.
<PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
Public Sub ImpersonateStart(ByVal Domain As String, ByVal userName As String, ByVal Password As String)
Try
tokenHandle = IntPtr.Zero
' Call LogonUser to obtain a handle to an access token.
Dim returnValue As Boolean = LogonUser(userName, Domain, Password, 2, 0, tokenHandle)
'check if logon successful
If returnValue = False Then
Dim ret As Integer = Marshal.GetLastWin32Error()
Console.WriteLine("LogonUser failed with error code : {0}", ret)
Throw New System.ComponentModel.Win32Exception(ret)
Exit Sub
End If
'Logon succeeded
' Use the token handle returned by LogonUser.
Dim newId As New WindowsIdentity(tokenHandle)
impersonatedUser = newId.Impersonate()
Catch ex As Exception
Throw ex
Exit Sub
End Try
End Sub
<PermissionSetAttribute(SecurityAction.Demand, Name:="FullTrust")> _
Public Sub ImpersonateStop()
' Stop impersonating the user.
impersonatedUser.Undo()
' Free the tokens.
If Not System.IntPtr.op_Equality(tokenHandle, IntPtr.Zero) Then
CloseHandle(tokenHandle)
End If
End Sub
#End Region
#Region "Private Methods"
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
<DllImport("kernel32.dll")> _
Public 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
#End Region
End Class
Start Process as different user
If you just want to run a program or start a process as a different user, this can be accomplished easily as follows (using IE as an example). The first 3 lines should be on one line, if you know what I mean.
You should be OK copying and pasting the below code, or click here for the .TXT version.
The password string requires converting to a System.Security.SecureString() – hence the loop on the password string that passes each character.
‘**** Start IE as Admin ***********
Dim p As New ProcessStartInfo(My.Computer.FileSystem.SpecialDirectories.ProgramFiles + "\Internet Explorer\IEXPLORE.EXE")
p.UseShellExecute = False
p.Domain = "Domain"
p.UserName = "Username"
p.Password = New System.Security.SecureString()
For Each c As Char In "Password"
p.Password.AppendChar(c)
Next
p.Arguments = ("http://www.google.com")
Process.Start(p)
‘**** End Start IE as Admin ***********
Pingback: Tales from the IT side » VB.Net easily Change/Modify NTFS File/Directory Security 2008
This works great !
For beginning users it’s great that you write what to do exactly.
(create al class, call it bla bla, etc)
thanks you very much for sharing
its really help full for me..
(^_^)
Thaks a lot!!
It?s very useful for me. You are a crack!
Yay! Thanks!
Been looking for this code for awhile.
Works great – thanks!
This works great for elevating calls where I access the C$ shares of workstations and remote registry calls. However, it is not working for any sort of remote WMI calls I am trying to make. It reverts back to using the security context of the user who launched the .exe vs. using the impersonation account. I am using VB.Net and Visual Studio 2010.
Has anyone else also experienced this? If so, did you find a solution?
Does this work on Windows 7 ? I added the class, then made myself Administrator and started Notepad with the protected ‘hosts’ file, modified it and could not save it back. Code:
Dim AdminPass As String = InputBox(“Please type the Administrator Password”, “Need Admin PW”)
Dim imp As New RunAs_Impersonator
imp.ImpersonateStart(Environment.MachineName, “Administrator”, AdminPass)
MsgBox(WindowsIdentity.GetCurrent.Name)
Dim p As Process = Process.Start(“Notepad”, “C:\Windows\System32\drivers\etc\hosts”)
MessageBox.Show(“Clear this box when finished with Notepad”)
imp.ImpersonateStop()
MsgBox(WindowsIdentity.GetCurrent.Name)
I’ll struggle to find a Win 7 PC to try it on quickly, and not used this routine for a while so will need to revisit and check.
Try using “.” as Domain Name (parameter 1) instead of environment.machinename.?