Search code examples
windowspowershellwindows-10powershell-7.0

Access user environment variables from elevated script?


I have a script that utilizes $env:appdata which results in C:\Users\username\AppData\Roaming. This works great if I run the script manually, even in an "administrative" prompt. However, when it runs as part of a scheduled task under "SYSTEM" with "Highest Priveleges", it instead outputs c:\windows\system32\config\system.

I am able to get the logged in username using (Get-CimInstance CIM_ComputerSystem).Username. How can I get other environment variables, especially the AppData path?


Solution

  • The problem here is that running under SYSTEM is that SYSTEM is actually the built-in machine account with the highest privileges you can achieve. This is an account that supersedes even the built-in local Administrator. If you are running something as SYSTEM, its user profile is C:\Windows\System32\config\system. This is all running as expected and designed.

    If you need to run in the context of another user, the best solution is to create the task to execute as that user and delegate permissions to the principal appropriately. In fact, running something as SYSTEM is almost never the right solution, unless you need to perform one of the specific functions it alone can do by default (for these functions it's generally not recommended to delegate those permissions out).

    If it needs to run under SYSTEM, well, you know where the SYSTEM profile is, so seed its AppData appropriately or retrieve artifacts after the task is complete from there. But it sounds like you really want to run this as another user, which is what you should configure your task to run as instead.


    I don't recommend doing this from the SYSTEM user, but if you need to view another user's environment variables for some other reason, you can load their registry hive as long as another process doesn't have the hive opened (like if that user is using regedit.exe or has it loaded like I'm about to show you themselves):

    Two things first:

    1. You will need to know the location of their user profile to do this

    2. PowerShell cannot load another user's hive itself so we must use the reg.exe command to do this

      • The Registry provider can still access the data, it just cannot load it.
      reg load HKEY_Users\username "C:\Users\username\NTUSER.DAT"
      
      # If we can't load it then no point continuing
      if( $? ) {
        try {
          # Read envvars into variable
          $uservars = Get-ItemProperty HKEY_Users:\Environment
        } finally {
          reg unload HKEY_Users\username
      
          if ( !$? ) {
            Write-Warning "Unable to unload userhive, see previous error message for details"
          }
        }
      
        # Do what you need here
        # $uservars is a `PSCustomObject` containing the other user's
        # environment variables.
      } else {
        throw "Unable to load userhive, logon script could not complete"
      }