Invoke-CommandAs icon indicating copy to clipboard operation
Invoke-CommandAs copied to clipboard

Running as a GMSA requires the GMSA to have Admin on the Server

Open jeremymcgee73 opened this issue 7 years ago • 20 comments

When running as a GMSA, either locally or remotely, the GMSA must have admin on the server. If the GMSA doesn't have admin, the command will get stuck in a loop, waiting for Get-Job to return the job. I can see the Scheduled Task was started on the machine, but PowerShell returns a non 0 return code. Task Scheduler successfully completed task "\0ea45f2b-f78e-43fb-bc2e-83ae8448f2e4" , instance "{f056b0d6-764b-4128-8c0d-34071966797b}" , action "powershell.exe" with return code 2147942401.

jeremymcgee73 avatar Jul 20 '18 17:07 jeremymcgee73

Try using a PSSession with user with admin rights on the server, and use -AsGMSA switch.

mkellerman avatar Jul 31 '18 20:07 mkellerman

Did you find a workaround/fix?

mkellerman avatar Oct 12 '18 19:10 mkellerman

I haven't looked at this in awhile. The only workaround was adding the account as admin, doing the task, and removing admin. I should be able to take a look this week. I tried looking at it with procmon and didn't see anything strange.

jeremymcgee73 avatar Oct 15 '18 18:10 jeremymcgee73

FYI - Just in case:

Invoke-Command -Credential <Credential> -As <Credential>

-Credential needs to be Administrator, to create the schedule task on the remote PC. -As <shouldn't> require it.. but let me know if it does, I'm curious.

mkellerman avatar Oct 17 '18 23:10 mkellerman

-As GMSA does require the GMSA account to be administrator. I'm not 100% sure why. I looked into it for hours a few months ago and didnt get very far. The scheduled task had a non zero exit code from powershell. The script would just wait for the results to be returned, for forever.

jeremymcgee73 avatar Oct 24 '18 21:10 jeremymcgee73

@jeremymcgee73 did you end up with some results from your testing?

mkellerman avatar Jan 24 '19 07:01 mkellerman

Closing since inactive.

Please test with latest version (3.0)

mkellerman avatar Feb 05 '19 07:02 mkellerman

I ran into this today as well. It appears that the MSA is trying to access the scheduled job definition from the caller's AppData folder. I manually granted the MSA access to the folder, but I still get an access denied message. I've tried using procmon to see what it's being denied access to but I can't find anything.

$jobDef = [Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition]::LoadFromStore('612c8393-6212-4c2e-85b0-b4a68c90eb84', 'C:\Users\accountCallingInvokeCommandAs\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs')

When that is called and the MSA doesn't have admin access it gets this error:

Exception calling "LoadFromStore" with "2" argument(s): "Access is denied. (Exception from HRESULT: 0x80070005
(E_ACCESSDENIED))"
At line:1 char:1
+ $jobDef = [Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition]: ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : UnauthorizedAccessException

awickham10 avatar Apr 21 '20 18:04 awickham10

Update on what I'm finding so far. The MSA, since it isn't an admin, doesn't have access to the PowerShell Scheduled Jobs task scheduler jobs. I'm looking to see if there's a way to manually grant that - pre-Win2k16 it was done on the filesystem. Now it's through the registry.

awickham10 avatar Apr 21 '20 18:04 awickham10

Nice @awickham10. I attempted to use procmon as well with not much luck!

jeremymcgee73 avatar Apr 21 '20 23:04 jeremymcgee73

Sorry guys. I don’t use GMSA accounts, so I’m unable to test :/

mkellerman avatar Apr 22 '20 01:04 mkellerman

Hi,

Does anyone have an update on this? We are on Win2k12.

I'm not using InvokeCommandAs but am facing the same issue having registered some jobs through PowerShell. The jobs registered as running daily work fine, but the jobs registered to run on an interval indefinitely (e.g. every 5minutes) fail with the issue as described by @awickham10

Exception calling "LoadFromStore" with "2" argument(s): "Access is denied. (Exception from HRESULT: 0x80070005
(E_ACCESSDENIED))"
At line:1 char:1
+ $jobDef = [Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition]: ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : UnauthorizedAccessException

Having looked at this for hours I'm at a loss. It is permissions but seemingly not the folder permissions.

I even changed one of the daily scheduled tasks manually (through task scheduler) to be an indefinitely repeating task, this has then caused the same error on that task.

Any updates from others facing this kind of issue would be appreciated.

AdamWillden avatar Oct 28 '20 12:10 AdamWillden

Cracked it, in my case at least.

try { $jobDef =[Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition]::LoadFromStore('MY-TASK', 'C:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJobs'); } catch { Write-Host $PSItem.Exception }

This gave me not only the underlying exception but also a stack trace!

PS C:\Users\USER> try { $jobDef =[Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition]::LoadFromStore('MY-TASK', 'C:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\Windows\PowerShell\ScheduledJo
bs'); } catch { Write-Host $PSItem.Exception }
System.Management.Automation.MethodInvocationException: Exception calling "LoadFromStore" with "2" argument(s): "Access
is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))" ---> System.UnauthorizedAccessException: Access is den
ied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
   at TaskScheduler.ITaskFolder.DeleteTask(String Name, Int32 flags)
   at Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition.RemoveFromWTS(Boolean force)
   at Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition.Remove(Boolean force)
   at Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition.SyncWithWTS()
   at Microsoft.PowerShell.ScheduledJob.ScheduledJobDefinition.LoadFromStore(String definitionName, String definitionPat
h)
   at CallSite.Target(Closure , CallSite , RuntimeType , String , String )
   --- End of inner exception stack trace ---
   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exc
eption)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

This reminded me I can inspect the source using the stack trace.

https://github.com/PowerShell/PowerShell/blob/432dd56ea8e2301b8cefc6622bb80dd04506cd48/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobDefinition.cs#L694

This showed me that if it is reaching SyncWithWTS() then it has managed to load the scheduled job. and it is syncing with WTS (Windows Task Scheduler). It detects there's a difference which then tries to remove the scheduled task but the user doesn't have permission to manage scheduled tasks! The question was then 'why is there a difference' between the job and scheduled task definitions.

This line was the culprit for me: https://github.com/PowerShell/PowerShell/blob/432dd56ea8e2301b8cefc6622bb80dd04506cd48/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobDefinition.cs#L394

I created the scheduled job using Get-Date which includes fractional seconds. The scheduled job definition file contains the fractional seconds, the scheduled task definition did not. So when loading both for comparison the time was seen as different.

I changed the scheduled job to use (Get-Date).Date to remove the time element. And it worked.

AdamWillden avatar Oct 28 '20 13:10 AdamWillden

I hope others may be able to use this information to understand the actual problem encountered (which may be different to my experience).

AdamWillden avatar Oct 28 '20 13:10 AdamWillden

Wow, nice work! So is the fix something we can implement in the script? Or in PS source code itself? (I vaguely was able to follow the explanation, I haven't had my first cup of coffee yet, lol)

mkellerman avatar Oct 28 '20 15:10 mkellerman

@mkellerman I'm really sorry but I have no idea how this relates to this issue specifically. As I said I'm not using Invoke-CommandAs myself (although funnily I found and considered using this command to investigate my issue!)

I just wanted to share how I found my root cause so that maybe it can help someone figure out what the cause is here.

I don't see any linked code to reference what you mean by the script - in my case yes I changed the script which registered the scheduled job.

AdamWillden avatar Oct 28 '20 19:10 AdamWillden

I have looked and I see you do a lot of modification of the task in the script. So you need to probably make sure the task and scheduled job are 'equivalent' according to the checks done here: https://github.com/PowerShell/PowerShell/blob/432dd56ea8e2301b8cefc6622bb80dd04506cd48/src/Microsoft.PowerShell.ScheduledJob/ScheduledJobDefinition.cs#L394

Not certain though, so I'd start from getting a stack trace and work from there.

AdamWillden avatar Oct 28 '20 20:10 AdamWillden

Great job! Unfortunately I no longer work with Active Directory / Windows Server so I won't be much help. Maybe @awickham10 can give it another go!

jeremymcgee73 avatar Nov 06 '20 18:11 jeremymcgee73

@AdamWillden is correct, its also the reason there is a lot of issues with trying to get it running when the target identity is not an admin (the HighestAvailable hardcoded runlevel on most of the identity types can help with this, but only in certain environments that allow for this kind of admin token injection). There are only really two paths forward,

  1. Take the source and either override the members called by [ScheduledJobDefinition]::LoadFromStore such that no task scheduler calls get used. The other option is to create new method names (probably preferable) that skip the WTS components and use those at the execution argument set on the task. This also requires some quick DACL allows on the definition folder so the target identity can pick it up from the callers profile.

  2. As much as the scheduledjob system is really nice to use, it has this scheduled task mirroring embedded too much and seeing as how this module seems more for the one run and done, the need for the execution history and all that jazz seems simpler solutions can be had.

    • To this end I plan to test some very simple scriptblock to ps1 with export-clixml drop and pickup mechanisms that should be much more friendly for targeting unelevated users ( hopefully hiding powershell window from poping up too ). Depending on how far I get I may skip using scheduled tasks in its entirety as the windows privileges should allow direct calls into SYSTEM, GMSA or any user logged into the box same as task scheduler essentially.

SeSeKenny avatar Mar 26 '21 17:03 SeSeKenny

That's my current WorkAround:

Add-LocalGroupMember -Group Administrators -Member "gMSA$"
Invoke-CommandAs -ScriptBlock { Get-Process } -AsGMSA "AD\gMSA$"
Remove-LocalGroupMember -Group Administrators -Member "gMSA$"

rvigliotti-sf avatar Dec 14 '21 15:12 rvigliotti-sf