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, False0, 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