Invoke-CommandAs
Invoke-CommandAs copied to clipboard
Running as a GMSA requires the GMSA to have Admin on the Server
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.
Try using a PSSession with user with admin rights on the server, and use -AsGMSA switch.
Did you find a workaround/fix?
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.
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.
-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 did you end up with some results from your testing?
Closing since inactive.
Please test with latest version (3.0)
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
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.
Nice @awickham10. I attempted to use procmon as well with not much luck!
Sorry guys. I don’t use GMSA accounts, so I’m unable to test :/
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.
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.
I hope others may be able to use this information to understand the actual problem encountered (which may be different to my experience).
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 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.
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.
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!
@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,
-
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.
-
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.
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$"