管理者権限のアプリケーションから、他のアプリケーションを呼び出すと、呼ばれた側のアプリケーションのプロセスも管理者権限になります。
たまに、管理者権限だとうまく動作しないOCXなどがあるので、子プロセスを通常ユーザーの権限で起動させたい場合があります。
間にバッチファイルを噛ませてやってみましたが、管理者権限で起動してしまうのでダメでした。
スポンサーリンク
以下のページのソースコードを利用して、テストアプリを作ってみました。
https://social.msdn.microsoft.com/Forums/vstudio/en-US/3c9aa0fa-c860-4a26-bde0-4ccf8a3793b3/use-processstart-to-start-an-application-without-administrator-privileges-on-windows-7?forum=vbgeneral
アプリ名は、「RunAsBasicUser」です。
Form1にボタンを2つ配置しました。

「RunAsBasicUser」を管理者として実行します。
管理者特権は「はい」となっています。

Button2をクリックして、Terapadを起動させてみました。
管理者特権は「はい」となっています。

Button1をクリックして、Terapadを起動させてみました。
管理者特権は「いいえ」となっています。

上記ページのほとんどコピペですが、以下がソースコードです。
Imports System.Runtime.InteropServices
Public Class Form1
<DllImport("advapi32.dll", SetLastError:=True)>
Private Shared Function OpenProcessToken(ByVal ProcessHandle As IntPtr, ByVal DesiredAccess As Integer, ByRef TokenHandle As IntPtr) As Boolean
End Function
' <DllImport("advapi32.dll", SetLastError:=True)>
' Public Shared Function GetTokenInformation(ByVal TokenHandle As IntPtr, ByVal TokenInformationClass As TOKEN_INFORMATION_CLASS,
' ByVal TokenInformation As IntPtr, ByVal TokenInformationLength As System.UInt32,
' ByRef ReturnLength As System.UInt32) As Boolean
' End Function
<DllImport("User32.dll", SetLastError:=True)>
Public Shared Function GetShellWindow() As IntPtr
End Function
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function GetWindowThreadProcessId(ByVal hwnd As IntPtr,
ByRef lpdwProcessId As IntPtr) As Integer
End Function
<DllImport("kernel32.dll")>
Private Shared Function OpenProcess(ByVal dwDesiredAccess As UInteger, <MarshalAs(UnmanagedType.Bool)> ByVal bInheritHandle As Boolean, ByVal dwProcessId As Integer) As IntPtr
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Private Shared Function DuplicateTokenEx(
ByVal ExistingTokenHandle As IntPtr,
ByVal dwDesiredAccess As UInt32,
ByRef lpThreadAttributes As SECURITY_ATTRIBUTES,
ByVal ImpersonationLevel As Integer,
ByVal TokenType As Integer,
ByRef DuplicateTokenHandle As System.IntPtr) As Boolean
End Function
<DllImport("advapi32.dll", SetLastError:=True)>
Private Shared Function LookupPrivilegeValue(lpSystemName As String,
lpName As String, ByRef lpLuid As LUID) As Boolean
End Function
' Use this signature if you want the previous state information returned
<DllImport("advapi32.dll", SetLastError:=True)>
Private Shared Function AdjustTokenPrivileges(
ByVal TokenHandle As IntPtr,
ByVal DisableAllPrivileges As Boolean,
ByRef NewState As TOKEN_PRIVILEGES,
ByVal BufferLengthInBytes As Integer,
ByRef PreviousState As TOKEN_PRIVILEGES,
ByRef ReturnLengthInBytes As Integer
) As Boolean
End Function
<DllImport("advapi32", SetLastError:=True, CharSet:=CharSet.Unicode)>
Public Shared Function CreateProcessWithTokenW(hToken As IntPtr, dwLogonFlags As Integer, lpApplicationName As String, lpCommandLine As String, dwCreationFlags As Integer, lpEnvironment As IntPtr, lpCurrentDirectory As IntPtr, ByRef lpStartupInfo As STARTUPINFO, ByRef lpProcessInformation As PROCESS_INFORMATION) As Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Structure SECURITY_ATTRIBUTES
Public nLength As Integer
Public lpSecurityDescriptor As IntPtr
Public bInheritHandle As Integer
End Structure
Structure TOKEN_PRIVILEGES
Public PrivilegeCount As Integer
Public TheLuid As LUID
Public Attributes As Integer
End Structure
Structure LUID
Public LowPart As UInt32
Public HighPart As UInt32
End Structure
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)>
Structure STARTUPINFO
Public cb As Integer
Public lpReserved As String
Public lpDesktop As String
Public lpTitle As String
Public dwX As Integer
Public dwY As Integer
Public dwXSize As Integer
Public dwYSize As Integer
Public dwXCountChars As Integer
Public dwYCountChars As Integer
Public dwFillAttribute As Integer
Public dwFlags As Integer
Public wShowWindow As Short
Public cbReserved2 As Short
Public lpReserved2 As Integer
Public hStdInput As Integer
Public hStdOutput As Integer
Public hStdError As Integer
End Structure
Structure PROCESS_INFORMATION
Public hProcess As IntPtr
Public hThread As IntPtr
Public dwProcessId As Integer
Public dwThreadId As Integer
End Structure
Public Const SE_PRIVILEGE_ENABLED = &H2L
Public Const PROCESS_QUERY_INFORMATION = &H400
Public Const TOKEN_ASSIGN_PRIMARY = &H1
Public Const TOKEN_DUPLICATE = &H2
Public Const TOKEN_IMPERSONATE = &H4
Public Const TOKEN_QUERY = &H8
Public Const TOKEN_QUERY_SOURCE = &H10
Public Const TOKEN_ADJUST_PRIVILEGES = &H20
Public Const TOKEN_ADJUST_GROUPS = &H40
Public Const TOKEN_ADJUST_DEFAULT = &H80
Public Const TOKEN_ADJUST_SESSIONID = &H100
Public Const SecurityImpersonation = 2
Public Const TokenPrimary = 1
Public Const SE_INCREASE_QUOTA_NAME = "SeIncreaseQuotaPrivilege"
Private Sub RusAsBasicUser(sApplicationPath As String, sCommandLIne As String)
Dim currentProcess As Process = Process.GetCurrentProcess
'Enable SeIncreaseQuotaPrivilege in this process. (This requires administrative privileges.)
Dim hProcessToken As IntPtr = Nothing
OpenProcessToken(currentProcess.Handle, TOKEN_ADJUST_PRIVILEGES, hProcessToken)
Dim tkp As TOKEN_PRIVILEGES
tkp.PrivilegeCount = 1
LookupPrivilegeValue(Nothing, SE_INCREASE_QUOTA_NAME, tkp.TheLuid)
tkp.Attributes = SE_PRIVILEGE_ENABLED
AdjustTokenPrivileges(hProcessToken, False, tkp, 0, Nothing, Nothing)
'Get window handle representing the desktop shell. This might not work if there is no shell window, or when
'using a custom shell. Also note that we're assuming that the shell is not running elevated.
Dim hShellWnd As IntPtr = GetShellWindow()
'Get the ID of the desktop shell process.
Dim dwShellPID As IntPtr
GetWindowThreadProcessId(hShellWnd, dwShellPID)
'Open the desktop shell process in order to get the process token.
Dim hShellProcess As IntPtr = OpenProcess(PROCESS_QUERY_INFORMATION, False, dwShellPID)
Dim hShellProcessToken As IntPtr = Nothing
Dim hPrimaryToken As IntPtr = Nothing
'Get the process token of the desktop shell.
OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, hShellProcessToken)
'Duplicate the shell's process token to get a primary token.
Dim dwTokenRights As Integer = TOKEN_QUERY Or TOKEN_ASSIGN_PRIMARY Or TOKEN_DUPLICATE Or TOKEN_ADJUST_DEFAULT Or TOKEN_ADJUST_SESSIONID
DuplicateTokenEx(hShellProcessToken, dwTokenRights, Nothing, SecurityImpersonation, TokenPrimary, hPrimaryToken)
Dim si As STARTUPINFO = Nothing
Dim pi As PROCESS_INFORMATION = Nothing
si.cb = Marshal.SizeOf(si)
CreateProcessWithTokenW(hPrimaryToken, 0, sApplicationPath, sCommandLIne, 0, Nothing, Nothing, si, pi)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
RusAsBasicUser("C:\Program Files (x86)\TeraPad\Terapad.exe", "")
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Process.Start("C:\Program Files (x86)\TeraPad\Terapad.exe")
End Sub
End Class
動作確認は、Windows10で行いました。