title: From a service started as Local System Account, run a program as a logged in user
body: <p><strong>tl/dr:</strong> I'm looking for a way to run a program as the user who is currently logged in from a service that is started as <code>Local System Account</code>.</p>
  
  <hr>
  
  <p><strong>Long Version:</strong> </p>
  
  <p>Follow up from: <a href="https://stackoverflow.com/questions/5550008/get-current-username-from-a-program-started-as-local-system-account">Get current username from a program started as Local System Account</a></p>
  
  <p>My program is started from a service that runs as <code>Local System Account</code>.</p>
  
  <p>This service is started at windows start-up time and basically provides functionality to some hardware buttons e.g. displaying an on screen keyboard. My program is also assigned to one of the buttons, but it is only available when an actual user is logged in.</p>
  
  <p>What it does is to take a picture using a hardware camera and to store it somewhere on the file system, which is working fine, but I can't store pictures on a network path, which is understandable, because doing so requires authentication.</p>
  
  <p>If the program is started directly as the logged in user, this authentication is available and storing files on a network path works fine.</p>
  
  <p>Is there any way how I can solve this problem?</p>
  
  <p>My preferred solution would be to start the program as the user who currently logged in without storing the password and username somewhere.</p>
  
  <p><strong>Working solution found on a different site:</strong>
  <a href="http://chabster.blogspot.com/2008/01/run-as-interactive-user-from-service.html" rel="nofollow noreferrer">http://chabster.blogspot.com/2008/01/run-as-interactive-user-from-service.html</a></p>
  
  <p>stdafx.h: </p>
  
  <pre><code>#include &lt;WtsApi32.h&gt;
  #pragma comment(lib, "WtsApi32.lib")
  
  #include &lt;Userenv.h&gt;
  #pragma comment(lib, "Userenv.lib")
  </code></pre>
  
  <p>RunAsInteractiveUser function: </p>
  
  <pre><code>BOOL bRet;
  HRESULT hr;
  
  HANDLE processToken = NULL;
  TOKEN_PRIVILEGES oldTokenPrivileges = { 0 };
  
  HANDLE impersonationToken = NULL;
  HANDLE userToken = NULL;
  
  LPVOID pEnvironment = NULL;
  PROCESS_INFORMATION processInformation = { 0 };
  
  __try {
      bRet = OpenProcessToken(GetCurrentProcess(), 
         TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &amp;processToken);
      if (!bRet) {
          hr = GetLastError();
          return hr;
      }
  
      // This step might not be necessary because 
      // SeTcbPrivilege is enabled by default for Local System
      LUID luid;
      bRet = LookupPrivilegeValue(NULL, _T("SeTcbPrivilege"), &amp;luid);
      if (!bRet) {
          hr = GetLastError();
          return hr;
      }
  
      TOKEN_PRIVILEGES adjTokenPrivileges = { 0 };
      adjTokenPrivileges.PrivilegeCount = 1;
      adjTokenPrivileges.Privileges[0].Luid = luid;
      adjTokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  
      DWORD dwOldTPLen;
      bRet = AdjustTokenPrivileges(processToken, FALSE, 
         &amp;adjTokenPrivileges, sizeof(TOKEN_PRIVILEGES), 
         &amp;oldTokenPrivileges, &amp;dwOldTPLen);
  
      if (bRet) {
          hr = GetLastError();
          if (hr == ERROR_SUCCESS);
          else if (hr == ERROR_NOT_ALL_ASSIGNED) {
              // Enabled by default
          }
      }
      else {
          hr = GetLastError();
          return hr;
      }
  
      DWORD conSessId = WTSGetActiveConsoleSessionId();
      if (conSessId == 0xFFFFFFFF) {
          // There is no session attached to the console
          return ERROR_SUCCESS;
      }
  
      bRet = WTSQueryUserToken(conSessId, &amp;impersonationToken);
      if (!bRet) {
          hr = GetLastError();
          return hr;
      }
  
      bRet = DuplicateTokenEx(impersonationToken, MAXIMUM_ALLOWED, NULL,
         SecurityIdentification, TokenPrimary, &amp;userToken);
      if (!bRet) {
          hr = GetLastError();
          return hr;
      }
  
      STARTUPINFO si = { 0 };
      si.cb = sizeof(STARTUPINFO);
      si.lpDesktop = _T("winsta0\\default");
  
      bRet = CreateEnvironmentBlock(&amp;pEnvironment, userToken, TRUE);
      if (!bRet) {
          hr = GetLastError();
          return hr;
      }
  
      bRet = CreateProcessAsUser(userToken, _T("C:\\Windows\\notepad.exe"), 
         NULL, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, 
         pEnvironment, NULL, &amp;si, &amp;processInformation);
  
      if (!bRet) {
          hr = GetLastError();
          return hr;
      }
  }
  __finally {
      if (processInformation.hThread) {
          CloseHandle(processInformation.hThread);
      }
      if (processInformation.hProcess) {
          CloseHandle(processInformation.hProcess);
      }
      if (pEnvironment) {
          bRet = DestroyEnvironmentBlock(pEnvironment);
      }
      if (userToken) {
          CloseHandle(userToken);
      }
      if (impersonationToken) {
          CloseHandle(impersonationToken);
      }
      if (processToken) {
          bRet = AdjustTokenPrivileges(processToken, 
             FALSE, &amp;oldTokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL);
          CloseHandle(processToken);
      }
  }
  </code></pre>