Pour lancer une commande depuis un service dans une session utilisateur... Attention, dans l'exemple ci-dessous ça l'exécute dans toutes les sessions trouvées s'il y en a plusieurs.
A peaufiner (si besoin de séparer la commande en exécutable/arguments notamment), c'est plutôt brut et un peu "goret". Je ne sais plus où j'avais trouvé ça...
Fonctionne sous W8.1 ; non testé sous W10 mais ça devrait être pareil.
[DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public extern static bool CreateProcessAsUser(IntPtr hToken,
String lpApplicationName,
String lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandle,
int dwCreationFlags,
IntPtr lpEnvironment,
String lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
public static extern bool ProcessIdToSessionId(uint dwProcessId,
ref uint pSessionId);
[DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
int TokenType,
int ImpersonationLevel,
ref IntPtr DuplicateTokenHandle);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(uint dwDesiredAccess,
bool bInheritHandle,
uint dwProcessId);
[DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute]
public static extern bool OpenProcessToken(IntPtr ProcessHandle,
int DesiredAccess,
ref IntPtr TokenHandle);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hSnapshot);
private static string ExecuteCommandInUserContext(string Command)
{
StringBuilder stbResponse = new StringBuilder();
string strSep = string.Empty;
try
{
// retrieve winlogon process list
Process[] processes = Process.GetProcessesByName("logonUI");
if (processes.Count() == 0)
{
// retrieve winlogon process list
processes = Process.GetProcessesByName("winlogon");
// loop on each process
foreach (Process p in processes)
{
strSep = (stbResponse.Length == 0 ? string.Empty : ", ");
// declare objects
PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
STARTUPINFO startupInfo = new STARTUPINFO();
startupInfo.cb = Marshal.SizeOf(startupInfo);
startupInfo.lpDesktop = @"winsta0\default";
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = (short)WINDOW_SHOW_STYLE.Hide;
SECURITY_ATTRIBUTES securityAttributes = new SECURITY_ATTRIBUTES();
securityAttributes.Length = Marshal.SizeOf(securityAttributes);
// declare variables
IntPtr hUserTokenDup = IntPtr.Zero;
IntPtr hProcessToken = IntPtr.Zero;
IntPtr hProcess = IntPtr.Zero;
// retrieve handle of the process from its pid
hProcess = OpenProcess(MAXIMUM_ALLOWED, false, (uint)p.Id);
// retrieve token of the process from its handle
if (OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hProcessToken))
{
// token duplication ok?
if (DuplicateTokenEx(hProcessToken, MAXIMUM_ALLOWED, ref securityAttributes, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
{
// yes...
// try to execute process
bool boolResult = CreateProcessAsUser(hUserTokenDup,
null,
Command,
ref securityAttributes,
ref securityAttributes,
false,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
IntPtr.Zero,
null,
ref startupInfo,
out processInfo);
// execution ok?
if (boolResult == false)
{
// no... then retrieve error code
int intError = Marshal.GetLastWin32Error();
string strError = new System.ComponentModel.Win32Exception(intError).Message;
stbResponse.AppendFormat("{0}KO (error encountered: {1})", strSep, strError);
}
else
{
// yes...
stbResponse.AppendFormat("{0}OK", strSep);
}
// close handles
CloseHandle(hProcess);
CloseHandle(hProcessToken);
CloseHandle(hUserTokenDup);
}
else
{
// close handles
CloseHandle(hProcess);
CloseHandle(hProcessToken);
stbResponse.AppendFormat("{0}KO (error encountered in token duplication)", strSep);
}
}
else
{
// close handle
CloseHandle(hProcess);
stbResponse.AppendFormat("{0}KO (error encountered in token open)", strSep);
}
}
}
else
{
stbResponse.Append("KO (logon screen displayed)");
}
}
catch (Exception ex)
{
stbResponse.AppendFormat("{0}KO (error encountered: {1})", strSep, ex.Message.Replace('\r', ' '));
}
return stbResponse.ToString();
}
@+