PowerShell Script Works Locally but Can't Find Filepath in a Worklet

Automox runs Worklet scripts in 32-bit PowerShell as the SYSTEM account. Both of those change what a script can see, which is why a script that works when you run it yourself can fail inside a Worklet with no obvious error in the logic.

Symptoms

  • Cannot find path errors
  • ItemNotFoundException
  • A Test-Path check returning False for something you can see on the device
  • A registry value reading as missing when it is present
  • A file written by the Worklet appearing in a different folder than expected

What is actually being redirected

On 64-bit Windows, a 32-bit process is silently redirected for certain paths. Nothing errors, so the script simply operates on the wrong location:

Your script references A 32-bit process actually reaches
C:\Windows\System32 C:\Windows\SysWOW64
C:\Program Files C:\Program Files (x86)
HKLM:\SOFTWARE\... HKLM:\SOFTWARE\WOW6432Node\...

Separately, because the script runs as SYSTEM rather than as a signed-in user:

  • HKCU: resolves to the SYSTEM account's profile, not the logged-in user's.
  • Paths under a user profile, and environment variables such as $env:USERPROFILE and $env:APPDATA, resolve to the SYSTEM profile.

So "the file is not there" is usually accurate from the script's point of view. It is looking somewhere else.

Confirm the cause first

Reproduce the failure under the same conditions before changing anything:

  1. Run the script in Windows PowerShell (x86). If it now fails the same way it did in the Worklet, path redirection is your cause.
  2. If it still succeeds, run it as SYSTEM as well, since the second half of the problem is the account rather than the architecture.

See How to Test a PowerShell Script Locally for Worklets for reproducing the Automox execution context locally.

Resolution 1: reference sysnative directly

For a script that only needs to reach a 64-bit path, this is the simplest fix and avoids relaunching PowerShell entirely. sysnative is a virtual directory that exists only for 32-bit processes and maps to the real System32:

$realSystem32 = "$env:SystemRoot\sysnative"
& "$realSystem32\some64bitTool.exe" /arguments

Note that sysnative is not visible to a 64-bit process, so a script written this way will not work if you later run it in a 64-bit session. For the 64-bit view of the registry, see Requested Registry Access is Not Allowed.

Resolution 2: run the whole script in 64-bit PowerShell

When the script does enough 64-bit work that patching individual paths is impractical, wrap it in a script block and invoke the 64-bit PowerShell:

$scriptBlock = {
    # Your code here. This runs 64-bit.
    Write-Output "Running 64-bit."
    exit 2
}

& "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" `
    -ExecutionPolicy Bypass -NoProfile -NonInteractive -Command $scriptBlock

exit $LASTEXITCODE

Two things to get right in that pattern

  • Propagate the exit code with exit $LASTEXITCODE. Do not assign the invocation to a variable and exit on that. The call operator returns the command's output, not its status, so a variable named $exitCode will contain your text. Exiting on it either fails to convert to an integer or exits 0, which makes the Worklet report success no matter what the inner script did.
  • Let the output print. Assigning the invocation to a variable, or adding -WindowStyle Hidden, causes the inner script's output to be swallowed so nothing reaches the Activity Log. If you need to capture it, write it out explicitly and store the exit code first:
$result = & "$env:SystemRoot\sysnative\WindowsPowerShell\v1.0\powershell.exe" `
    -ExecutionPolicy Bypass -NoProfile -NonInteractive -Command $scriptBlock
$code = $LASTEXITCODE

Write-Output $result
exit $code

$LASTEXITCODE is overwritten by the next command that runs, so capture it immediately.

If the problem is the user context rather than the architecture

Running 64-bit does not change the account. If your script needs a signed-in user's profile or HKCU, resolve the user's SID and address their hive under HKEY_USERS explicitly, or have the Worklet create a scheduled task that runs in the user's own context. Running 64-bit as SYSTEM will still not see the user's HKCU.

Related articles

Was this article helpful?
0 out of 0 found this helpful