Error using non-Admin Run As account

Product: PowerShell Universal
Version: 3.4.5

I am running into an issue when using a Run As account that is not an admin on the PSU server. The job fails with a message of “Error executing job: Did not receive port from client process.” and in the logs I have the following:

2022-11-03 11:47:20.282 -05:00 [ERR] Connection id "0HMLTNC7QKAA8", Request id "0HMLTNC7QKAA8:00000003": An unhandled exception was thrown by the application.
System.InvalidOperationException: No authentication handler is registered for the scheme 'Negotiate'. The registered schemes are: Identity.External, Cookies, Bearer, Negotiate. Did you forget to call AddAuthentication().Add[SomeAuthHandler]("Negotiate",...)?
   at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
   at Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator.AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at PowerShellUniversal.DisallowedModeMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in C:\actions-runner\_work\universal\universal\src\Universal.Server\Middleware\ModeMiddleware.cs:line 46
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Universal.Server.Middleware.RoutingMiddleware.Invoke(HttpContext httpContext, IPolicyEvaluator policyEvaluator) in C:\actions-runner\_work\universal\universal\src\Universal.Server\Middleware\RoutingMiddleware.cs:line 155
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Universal.Server.Middleware.SwaggerAuthenticationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next) in C:\actions-runner\_work\universal\universal\src\Universal.Server\Middleware\SwaggerAuthMiddleware.cs:line 40
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at AspNetCoreRateLimit.RateLimitMiddleware`1.Invoke(HttpContext context) in C:\actions-runner\_work\universal\universal\src\AspNetCoreRateLimit\Middleware\RateLimitMiddleware.cs:line 109
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.StatusCodePagesMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.ResponseCompression.ResponseCompressionMiddleware.InvokeCore(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)

This is running as a Windows Service, and it is running logged in as a Service Account following the documentation. If the Run As account is added to the local machines Administrators group, then it runs fine, and fails again when removed.

Thanks

Trying to track down this issue for another user right now!

Can you try setting the -LoadProfile parameter for your script? You’ll add that to New-PSUScript in scripts.ps1. It isn’t available in the UI but will load the target user’s profile prior to launching the process. This will eventually be the default option but we are trying to figure out exactly what’s going on in some environments.

I’m also in the process of putting together a little tester app to try and verify this functionality faster because it’s not reproducible in my domain .

That changed the message received. The error in the output is “Error executing job: Failed to load user profile (1314). System.ComponentModel.Win32Exception (1314): A required privilege is not held by the client.” and I do not see an error in the text logs.

Ok. This is exactly what the other user is seeing an I’m not 100% sure why this is the case or why it doesn’t happen in my environment.

For a little bit of context, we are using CreateProcessAsUser and that’s what is throwing this error.

So looking at the required privileges for CreateProcessAsUser I don’t see anything that should not be assigned. We do have Group Policy in play, but the only privileges that are set other than Set System Time is the ones you have documented.
I did just notice something though, I did say originally that adding the RunAs account to the administrators group allowed it to work, however that is not true with the -LoadProfile option. Just wanted to point that out.

I’ve created a Run As tester application that will allow us to test things out a bit faster in your environment. You can launch this from your PowerShell Universal scripts with various options.

The application has the following options:

--username (The username of the account to run the application as)
--password (The password of the account to run the application as)
--domain (The domain of the account to run the application as) 
--workingdirectory (The working directory to set for the application)
--interactive (Performs an interactive login rather than a batch job login) 

For example.

.RunAsTester.exe –username adamin –password myPassword –domain localdomain –workingdirectory C:\ProgramData –interactive

Once run, the application will attempt to start the powershell.exe process using CreateProcessAsUser and also Process.Start with the various options defined. It will output any errors it encounters.

What I’ve noticed in my testing is that my service is actually working but when I try to run this locally I’m getting problems with the user’s profile loading. I also noticed that we weren’t specifically setting the working directory in PowerShell Universal so the child processes were inheriting it from the parent which could certainly cause some sort of permission issue.

You should run this from a script without using Run As credentials within PSU since it will be attempting to do that itself.

So first thing that is noticeable is that the EXE doesn’t seem to actually end until you hit a key at the end? The job in PSU just keeps running, and on the console it goes back to the prompt after you hit (enter).

Ran the following commands to get the relative output.


. RunAsTester\RunAsTester.exe --username |runasUser| --password |runasPass| --domain |runasDomain|
Write-Host “DONE”

Testing CreateProcessAsUser with |runasUser|
Failed to load user profile (1314). System.ComponentModel.Win32Exception (0x80004005): A required privilege is not held by the client
Testing Process.Start with |runasUser|
Process.Start Exit Code -1073741502


. RunAsTester\RunAsTester.exe --username |runasUser| --password |runasPass| --domain |runasDomain| --workingdirectory c:\Windows\Temp
Write-Host “DONE”

Testing CreateProcessAsUser with |runasUser|
Failed to load user profile (1314). System.ComponentModel.Win32Exception (0x80004005): A required privilege is not held by the client
Testing Process.Start with |runasUser|
Process.Start Exit Code -1073741502


. RunAsTester\RunAsTester.exe --username |runasUser| --password |runasPass| --domain |runasDomain| --workingdirectory c:\Windows\Temp --interactive
Write-Host “DONE”

Testing CreateProcessAsUser with |runasUser|
Failed to load user profile (1314). System.ComponentModel.Win32Exception (0x80004005): A required privilege is not held by the client
Testing Process.Start with |runasUser|
Process.Start Exit Code -1073741502


. RunAsTester\RunAsTester.exe --username |runasUser| --password |runasPass| --domain |runasDomain| --interactive
Write-Host “DONE”

Testing CreateProcessAsUser with |runasUser|
Failed to load user profile (1314). System.ComponentModel.Win32Exception (0x80004005): A required privilege is not held by the client
Testing Process.Start with |runasUser|
Process.Start Exit Code -1073741502

Any chance that the new version could/would address this. I see you did the changes to the LoadProfile defaults, so maybe just hoping for some magic fix. Thanks,

So I just updated to the 3.5.4 version, and it would appear that now local admins on the server can’t be used to do a run as either. Same failed to load profile error.
I see the default changed and that “Added -DontLoadProfile to New-PSUSetting to disable loading of profiles for run as credentials” should now be an option, however I don’t see a New-PSUSetting and New-PSUScript doesn’t recognize the -DontLoadProfile option either. In the docs I don’t see this option on Set-PSU Setting, so wondering how to set this to test to see if the Admin user still works if it doesn’t try to load the profile.

Just decided to try something and had some success. I added the account the PSU service us running as to the Admins group, and it worked to run a script under a non-admin user.

So based on some googling ending up at LoadUserProfileA function (userenv.h) - Win32 apps | Microsoft Learn (assuming you are using this before the CreateProcessAsUser when loading the profile) I added the Backup and Restore privileges to the ServiceAccount user and was able to at least get the error message to change. Instead of the 1314 privilege error, it now is reporting “Error executing job: Failed to load user profile (5). System.ComponentModel.Win32Exception (5): Access is denied.” My next attempt will be to give that service account access to the runas user profile directory. and see how that works.

And reading the sentence after the privileges required "
The calling process must have the SE_RESTORE_NAME and SE_BACKUP_NAME privileges. For more information, see Running with Special Privileges.

Starting with Windows XP Service Pack 2 (SP2) and Windows Server 2003, the caller must be an administrator or the LocalSystem account. It is not sufficient for the caller to merely impersonate the administrator or LocalSystem account.
"
I guess maybe it’s saying that you do need local admin?

I did try adding them to the backup operator group, which should be the same as the privileges already assigned with the restore and backup_name ones, but thought I would try and it was the same thing. Tried adding permissions to the user profile, but a number of sub folders didn’t allow the permissions to be set and were not visible to me to add to manually.

I’m seeing the work around being adding the service account to the admins group on the local machine, but of course trying to keep least privilege makes this less than desirable.

Hey Greg,

Thanks for spending some trying to get this to work. It gave me some things to go on an I think I have good news. I realized that my Service Account was part of the local administrators group. My Run As account was not.

Once I removed my service account from the local admins account, I could no longer use my Run As account in PSU with the same errors you were seeing. We were, in fact, calling LoadUserProfile before CreateProgressAsUser. Once my account wasn’t any longer part of the admin group, this would fail with Privilege not held exception until I added them to the two privileges you mentioned.

Once this was done, I was receiving an access denied error. I fixed this by turning off the LoadProfile setting in settings.ps1.

$Parameters = @{
	LoggingFilePath = "C:\ProgramData/PowerShellUniversal/log.txt"
	LogLevel = "Debug"
	MicrosoftLogLevel = "Debug"
	JobHandshakeTimeout = 30
	DontLoadProfile = $true
}
Set-PSUSetting @Parameters

That got the process to start but it wasn’t responding properly so I found that the child process was incorrectly inheriting the environment from the parent process. This was probably causing some sort permission issue (I could see some stuff getting ACCESS DENIED in procmon).

I corrected this and now it’s working in my environment.

image

My Current configuration:

PSU Running as Service Account: ops\psuadmin

  • Logon as Service
  • Replace process level token
  • Adjust memory quotas

Run as Account: ops\nonadmin

  • Logon as batch job

Neither are part of local admins.

I’m running a nightly build (3473245224). This should be available in the next hour or so.

Can you try giving this build a shot?

All right, looks like success. At least with my write-host test that failed before. I’ll reply if I run into more issues, but seems like the new build and the DontLoadProfile option covers it so far. Thanks for looking into this and getting a fix ready. I’ll be anticipating the final release for production to move to.

Great news. Let me know if anything crops up. We should likely have a prod build out later this week after I have some other customers verify it works for them a well.

So I’m wondering if there is any chance that this issue could have been re-introduced. I just updated to 3.8.11 and now I’m getting this type of behavior again. Adding to the local admin group fixes it again.