Launching an App as a user account (context) from a Service
https://blog.cjwdev.co.uk/2011/06/10/vb-net-start-process-in-console-session-from-windows-service-on-windows-7/
' Usage of it, followed by the WindowsApi class
Dim UserTokenHandle As IntPtr = IntPtr.Zero
WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)
Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION
Dim StartInfo As New WindowsApi.STARTUPINFOW
StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
WindowsApi.CreateProcessAsUser(UserTokenHandle, "C:\Windows\System32\cmd.exe", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
If Not UserTokenHandle = IntPtr.Zero Then
WindowsApi.CloseHandle(UserTokenHandle)
End If
Imports System.Runtime.InteropServices
Public Class WindowsApi
<DllImport("kernel32.dll", EntryPoint:="WTSGetActiveConsoleSessionId", SetLastError:=True)> _
Public Shared Function WTSGetActiveConsoleSessionId() As UInteger
End Function
<DllImport("Wtsapi32.dll", EntryPoint:="WTSQueryUserToken", SetLastError:=True)> _
Public Shared Function WTSQueryUserToken(ByVal SessionId As UInteger, ByRef phToken As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("kernel32.dll", EntryPoint:="CloseHandle", SetLastError:=True)> _
Public Shared Function CloseHandle(<InAttribute()> ByVal hObject As IntPtr) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<DllImport("advapi32.dll", EntryPoint:="CreateProcessAsUserW", SetLastError:=True)> _
Public Shared Function CreateProcessAsUser(<InAttribute()> ByVal hToken As IntPtr, _
<InAttribute(), MarshalAs(UnmanagedType.LPWStr)> ByVal lpApplicationName As String, _
ByVal lpCommandLine As System.IntPtr, _
<InAttribute()> ByVal lpProcessAttributes As IntPtr, _
<InAttribute()> ByVal lpThreadAttributes As IntPtr, _
<MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandles As Boolean, _
ByVal dwCreationFlags As UInteger, _
<InAttribute()> ByVal lpEnvironment As IntPtr, _
<InAttribute(), MarshalAsAttribute(UnmanagedType.LPWStr)> ByVal lpCurrentDirectory As String, _
<InAttribute()> ByRef lpStartupInfo As STARTUPINFOW, _
<OutAttribute()> ByRef lpProcessInformation As PROCESS_INFORMATION) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
<StructLayout(LayoutKind.Sequential)> _
Public Structure SECURITY_ATTRIBUTES
Public nLength As UInteger
Public lpSecurityDescriptor As IntPtr
<MarshalAs(UnmanagedType.Bool)> _
Public bInheritHandle As Boolean
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure STARTUPINFOW
Public cb As UInteger
<MarshalAs(UnmanagedType.LPWStr)> _
Public lpReserved As String
<MarshalAs(UnmanagedType.LPWStr)> _
Public lpDesktop As String
<MarshalAs(UnmanagedType.LPWStr)> _
Public lpTitle As String
Public dwX As UInteger
Public dwY As UInteger
Public dwXSize As UInteger
Public dwYSize As UInteger
Public dwXCountChars As UInteger
Public dwYCountChars As UInteger
Public dwFillAttribute As UInteger
Public dwFlags As UInteger
Public wShowWindow As UShort
Public cbReserved2 As UShort
Public lpReserved2 As IntPtr
Public hStdInput As IntPtr
Public hStdOutput As IntPtr
Public hStdError As IntPtr
End Structure
<StructLayout(LayoutKind.Sequential)> _
Public Structure PROCESS_INFORMATION
Public hProcess As IntPtr
Public hThread As IntPtr
Public dwProcessId As UInteger
Public dwThreadId As UInteger
End Structure
End Class
<DllImport("Userenv.dll", EntryPoint:="CreateEnvironmentBlock", SetLastError:=True)> _
Public Shared Function CreateEnvironmentBlock( ByRef lpEnvironment As IntPtr, ByVal hToken As IntPtr, ByVal bInherit As Boolean) As Boolean
End Function
Public Shared Function CreateEnvironmentBlock( ByRef lpEnvironment As IntPtr, ByVal hToken As IntPtr, ByVal bInherit As Boolean) As Boolean
End Function
' This is if you want to pass command line params
Adding in Command Line Args
Have to update the library reference
<DllImport("advapi32.dll", EntryPoint:="CreateProcessAsUserW", SetLastError:=True)>
Public Shared Function CreateProcessAsUser(<InAttribute()> ByVal hToken As IntPtr,
<InAttribute(), MarshalAs(UnmanagedType.LPWStr)> ByVal lpApplicationName As String,
<InAttribute(), MarshalAs(UnmanagedType.LPWStr)> ByVal lpCommandLine As String,
<InAttribute()> ByVal lpProcessAttributes As IntPtr,
<InAttribute()> ByVal lpThreadAttributes As IntPtr,
<MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandles As Boolean,
ByVal dwCreationFlags As UInteger,
<InAttribute()> ByVal lpEnvironment As IntPtr,
<InAttribute(), MarshalAsAttribute(UnmanagedType.LPWStr)> ByVal lpCurrentDirectory As String,
<InAttribute()> ByRef lpStartupInfo As STARTUPINFOW,
<OutAttribute()> ByRef lpProcessInformation As PROCESS_INFORMATION) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function ' 'ByVal lpCommandLine As System.IntPtr,
CreateEnvironmentBlock
' If you need this
Then to use it you just call it:
CreateEnvironmentBlock(EnvironmentBlock, UserTokenHandle, False)
Then pass that pointer in to CreateProcessAsUser (the 4th to last argument) :
CreateProcessAsUser(UserTokenHandle, Nothing, CommandLine, IntPtr.Zero, IntPtr.Zero, False, ApiDefinitions.CREATE_UNICODE_ENVIRONMENT Or ApiDefinitions.CREATE_NEW_CONSOLE, EnvironmentBlock, Nothing, StartInfo, ProcInfo)
Check to see if a Process is running
Function CheckIfRunning() As Boolean
p = Process.GetProcessesByName("MDRecords")
If p.Count > 0 Then
' Process is running
Return True
Else
' Process is not running
Return False
End If
End Function
Example
Private Sub Timer_Tick(sender As Object, e As EventArgs)
Dim instance As myNewTimer = DirectCast(sender, myNewTimer)
instance.Stop()
Dim UserTokenHandle As IntPtr = IntPtr.Zero
Dim EnvironmentBlock As IntPtr = IntPtr.Zero
Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION
Dim StartInfo As New WindowsApi.STARTUPINFOW
WindowsApi.WTSQueryUserToken(WindowsApi.WTSGetActiveConsoleSessionId, UserTokenHandle)
'Dim UserTokenHandle As IntPtr = IntPtr.Zero
'Dim EnvironmentBlock As IntPtr = IntPtr.Zero
'Dim ProcInfo As New WindowsApi.PROCESS_INFORMATION
'Dim StartInfo As New WindowsApi.STARTUPINFOW
StartInfo.cb = CUInt(Runtime.InteropServices.Marshal.SizeOf(StartInfo))
WindowsApi.CreateEnvironmentBlock(EnvironmentBlock, UserTokenHandle, False)
'Dim evaluator As New Threading.Thread(Sub() StartTimer("-None-"))
Debug.Print(Now & " Tick for: " & instance.IDNumber.ToString)
If Not CheckIfRunning() Then
WindowsApi.CreateProcessAsUser(UserTokenHandle, "c:\PROGRA~2\IMPRIV~1\ONESIG~1\ISXRunAs.exe", " /profile c:\CrouseScripts\MDRecords.exe", IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
'WindowsApi.CreateProcessAsUser(UserTokenHandle, "c:\crousescripts\MDRecords.exe", IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, False, 0, IntPtr.Zero, Nothing, StartInfo, ProcInfo)
If Not UserTokenHandle = IntPtr.Zero Then
WindowsApi.CloseHandle(UserTokenHandle)
End If
End If
instance.Start()
End Sub
Dim p() As Process
List Processes For a Session ID
Dim AllP() As Process = Process.GetProcesses()
Dim CurP As Process = Process.GetCurrentProcess()
Dim lst = (From x As Process In AllP Where x.SessionId = CurP.SessionId Select x).ToArray()
For Each p As Process In lst
ComboBox1.Items.Add(p.ProcessName)
Next
Kill Remote Process
Function funTaskKill(sRemoteName As String, sEXE As String, Optional txtDomain As String = "", Optional txtUser As String = "", Optional txtPassword As String = "") As String
Dim sRet As String = ""
Dim pProcess As New Process
pProcess.StartInfo.CreateNoWindow = True
If Len(txtUser) > 0 Then pProcess.StartInfo.UserName = txtUser
If Len(txtPassword) > 0 Then pProcess.StartInfo.PasswordInClearText = (txtPassword)
pProcess.StartInfo.UseShellExecute = False
pProcess.StartInfo.WorkingDirectory = "c:\windows\system32"
If Len(txtDomain) > 0 Then pProcess.StartInfo.Domain = txtDomain
pProcess.StartInfo.FileName = "C:\Windows\System32\taskkill.exe"
pProcess.StartInfo.Arguments = " /F " & IIf(Len(sRemoteName) > 0, " /S " & sRemoteName & " ", "") & " /IM " & sEXE
pProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
pProcess.StartInfo.RedirectStandardOutput = True
pProcess.StartInfo.RedirectStandardError = True
' Try
'TextBox1.AppendText("Query " & servername & " " & Now & vbCrLf)
pProcess.Start()
If Not pProcess.WaitForExit(1000 * 10) Then
'TextBox1.AppendText("60 second timeout on " & servername & " " & Now & " Aborting." & vbCrLf)
pProcess.Kill()
oLog.WriteEntry(Now, "RestartServicesMPF", sUser, "KillProcess", "Timeout: " & pProcess.StartInfo.FileName & " " & pProcess.StartInfo.Arguments)
'Return
sRet = "error: Timeout trying to kill: " & sEXE & " on " & sRemoteName
Else
Dim errortext As String = pProcess.StandardError.ReadToEnd.ToString
If errortext.Length = 0 Then
Dim sOutputText As String = pProcess.StandardOutput.ReadToEnd.ToString & vbCrLf
sRet = "success: kill of " & sEXE & " on " & sRemoteName
oLog.WriteEntry(Now, "RestartServicesMPF", sUser, "KillProcess", "OutputText: " & sOutputText)
Else 'error text > 0
oLog.WriteEntry(Now, "RestartServicesMPF", sUser, "KillProcess", "ErrorText: " & errortext)
sRet = "error: " & errortext
End If
End If
Return sRet
End Function