Talvez você possa executar seu código de trabalho, mas usando um token de usuário de sessão atualmente ativo (mas sem sessão ativa, isso não deve funcionar)
Por uma questão de brevidade, esse código não será compilado: você deve adaptar e adicionar alguns P / Invoke primeiro.
Você precisa encontrar o ID da sessão ativa. Para uma sessão aberta local, use este:
[DllImport("wtsapi32.dll", SetLastError = true)]
public static extern int WTSEnumerateSessions(
IntPtr hServer,
int Reserved,
int Version,
ref IntPtr ppSessionInfo,
ref int pCount);
Em seguida, procure um ID de sessão aberta:
var typeSessionInfo = typeof(WTSApi32.WTSSessionInfo);
var sizeSessionInfo = Marshal.SizeOf(typeSessionInfo);
var current = handleSessionInfo;
for (var i = 0; i < sessionCount; i++)
{
var sessionInfo = (WTSApi32.WTSSessionInfo)Marshal.PtrToStructure(current, typeSessionInfo);
current += sizeSessionInfo;
if (sessionInfo.State == WTSApi32.WTSConnectStateClass.WTSActive)
return sessionInfo.SessionID;
}
Se não encontrado, pesquise uma sessão de PDR com:
[DllImport("kernel32.dll")]
public static extern uint WTSGetActiveConsoleSessionId();
Com isso, pegue um token
private static IntPtr GetUserImpersonatedToken(uint activeSessionId)
{
if (!WTSApi32.WTSQueryUserToken(activeSessionId, out var handleImpersonationToken))
Win32Helper.RaiseInvalidOperation("WTSQueryUserToken");
try
{
return DuplicateToken(handleImpersonationToken, AdvApi32.TokenType.TokenPrimary);
}
finally
{
Kernel32.CloseHandle(handleImpersonationToken);
}
}
Com isso, você pode executar um exe do serviço Sistema Local, em uma sessão de usuário aberta.
public static void ExecuteAsUserFromService(string appExeFullPath, uint activeSessionId, bool isVisible = false, string cmdLine = null, string workDir = null)
{
var tokenUser = GetUserImpersonatedToken(activeSessionId);
try
{
if (!AdvApi32.SetTokenInformation(tokenUser, AdvApi32.TokenInformationClass.TokenSessionId, ref activeSessionId, sizeof(UInt32)))
Win32Helper.RaiseInvalidOperation("SetTokenInformation");
ExecuteAsUser(tokenUser, appExeFullPath, isVisible, cmdLine, workDir);
}
finally
{
Kernel32.CloseHandle(tokenUser);
}
}
Agora veja se você pode adaptar seu código a CreateProcessAsUSer(...)
private static void ExecuteAsUser(IntPtr token, string appExeFullPath, bool isVisible, string cmdLine, string workDir)
{
PrepareExecute(appExeFullPath, isVisible, ref workDir, out var creationFlags, out var startInfo, out var procInfo);
try
{
startInfo.lpDesktop = "WinSta0\\Default";
var processAttributes = new AdvApi32.SecurityAttributes
{
lpSecurityDescriptor = IntPtr.Zero
};
var threadAttributes = new AdvApi32.SecurityAttributes
{
lpSecurityDescriptor = IntPtr.Zero
};
if (!AdvApi32.CreateProcessAsUser(token,
appExeFullPath, // Application Name
cmdLine, // Command Line
ref processAttributes,
ref threadAttributes,
true,
creationFlags,
IntPtr.Zero,
workDir, // Working directory
ref startInfo,
out procInfo))
{
throw Win32Helper.RaiseInvalidOperation("CreateProcessAsUser");
}
}
finally
{
Kernel32.CloseHandle(procInfo.hThread);
Kernel32.CloseHandle(procInfo.hProcess);
}
}
Esperando que este código seja útil para você ou para outra pessoa!