Posted: 2021-06-29 05:56 AM . Last Modified: 2024-03-13 12:16 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Email to a Friend
- Report Inappropriate Content
Link copied. Please paste this link to share this article on your social media post.
Posted: 2021-06-29 05:56 AM . Last Modified: 2024-03-13 12:16 AM
[FYI] - How to run executable in user session from service session 0
Ladies and Gentleman,
I hereby post a solution that will make it possible to run a program in a user session. This might come in handy when you want to interact with your desktop before shutting down your computer by the UPS.
There are 2 files required, which are a .cmd file and a .ps1 file. (.ps1 = powershell script file)(In this example I will use the names calculator.cmd and calculator.ps1)
1. CMD file
The Powerchute software supports the functionality to execute a .cmd file before shutting down the computer. From this file we are going to execute the Powershell script file.
Type/Copy the following code:
@echo OFF
SET ThisScriptsDirectory=%~dp0
SET PowerShellScriptPath=%ThisScriptsDirectory%calculator.ps1
PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& {Start-Process PowerShell -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%PowerShellScriptPath%""' -Verb RunAs}";
Store and save the file at the cmdfiles location.
2. Powershell script file
The powershell script is going to execute the calculator program with the current session ID of the logged in user.
Side note: Microsoft prevented interaction from a service with programs running on the desktop of a user. This has been done from Windows Vista and higher. When shutting down your PC you want to shutdown certain programs, due to session 0 isolation this has be come impossible (well nearly :P).
What is this file going to do? It is going to check if the 'explorer.exe' is running and if so it is going to retrieve its token. Then the script is going to execute your command in the user session. (I know there is more to it but I don't want to explain every little detail because I want you to read/study *cough* copy the script).
$source = @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security;
public class ApplicationLoader
{
#region Structures
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}
enum TOKEN_TYPE : int
{
TokenPrimary = 1,
TokenImpersonation = 2
}
enum SECURITY_IMPERSONATION_LEVEL : int
{
SecurityAnonymous = 0,
SecurityIdentification = 1,
SecurityImpersonation = 2,
SecurityDelegation = 3,
}
public const int TOKEN_DUPLICATE = 0x0002;
public const uint MAXIMUM_ALLOWED = 0x2000000;
public const int CREATE_NEW_CONSOLE = 0x00000010;
public const int IDLE_PRIORITY_CLASS = 0x40;
public const int NORMAL_PRIORITY_CLASS = 0x20;
public const int HIGH_PRIORITY_CLASS = 0x80;
public const int REALTIME_PRIORITY_CLASS = 0x100;
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hSnapshot);
[DllImport("kernel32.dll")]
static extern uint WTSGetActiveConsoleSessionId();
[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")]
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")]
static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurity]
static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
///
/// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt
///
///
Save and store the file in the same directory as the .cmd file.
Hopefully, this helps you out. We contacted the tech support of APC for help and they told us they did not support the feature to shutdown programs. (This is in my opinion a HUGE FAILURE).
Good luck!!
Greetings,
Phanvi
Link copied. Please paste this link to share this article on your social media post.