Monday, May 18, 2026

The secrets of GPResult "Access denied"

 Hi all. Recently stumbled over a quite old and common error.

The error 

 

gpresult /r throws "ERROR: Access Denied." I first assumed "missing admin rights" - nope, the command prompt was running elevated. Then I tried all methods of repairing/recreating the WMI repository. A corrupted WMI repository is a common reason for this error. But nothing helped. After updating group policy, gpresult fails with "Access Denied".

Surprisingly enough, trying to create a RSoP report from within Group Policy Management Console or the deprecated rsop.msc shows a different error:

 

(None) isn't an error at all... Dismissing this window revealed a second window:

 

Error Code = 80041031, which translates to WBEM_E_INVALID_PROPERTY. Why would an invalid WMI property throw "Access Denied" in gpresult? See below...

Setting gpmgmtdebuglevel to 2 also didn't collect anything in the GPMC debug log (%temp%\gpmgmt.log).

Narrowing down

Doing some try-and-error with linking and unlinking GPOs applied to the computer showed that a GPO was the culprit that had a startup script defined.

 

The Name of the script is set to C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe, and the Parameters value is native powershell code. Which works well in a lot of our GPOs. Why not here?

The analysis 

Bummer - what next? Remember Mark Russinovich - "if you don't know what to do, use process monitor".

I know that for RSoP, computer scripts from GPOs are not stored in WMI (root/RSOP/Computer), but are simply queried from their registry location at HKLM\Software\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts. So let's find out what happens there during gpresult.

What happens 

Firing up procmon, running gpupdate /r and then analyzing the results was a matter of seconds. After filtering out garbage, I finally stumbled upon 2 BUFFER OVERFLOW errors. These are usually uncritical - if you read "something", you define a buffer for the result to be stored in. If this buffer is too small, you get a BUFFER OVERFLOW which will also tell you the correct buffer size, and then you read again with this size.

 

We can see 2 BUFFER OVERFLOW errors regarding the scripts registry area. The first one it is followed by a second query which succeeds.

Operation:    RegQueryValue
Result:    BUFFER OVERFLOW
Path:    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\Startup\0\GPO-ID
Length:    144

The initial buffer of 144 bytes was too small, the value size is 180 bytes.

Operation:    RegQueryValue
Result:    SUCCESS
Path:    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\Startup\0\GPO-ID
Type:    REG_SZ
Length:    180
Data:    cn={46000E5F-138A-41DD-9A4F-409FCE83991B},cn=policies,cn=system,DC=corp,DC=contoso,DC=com

But the second BUFFER OVERFLOW lacks the following query. It shows that the buffer is set to 144 bytes initially. The follow-up query using the correct buffer size is missing.

Operation:    RegQueryValue
Result:    BUFFER OVERFLOW
Path:    HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts\Startup\0\0\Parameters
Length:    144
 

Reviewing the GPO in question, the Parameters value of the startup script has 438 bytes.

Why it happens 

I don't have source code access, but I can guess:

The code in wmiprvse.exe isn't prepared for reading the Parameters value returning a BUFFER OVERFLOW (missing try/catch). So the error, which wmiprvse.exe translates to WBEM_E_INVALID_PROPERTY, travels up the stack. Since it is unhandled, it makes its way all up to gpresult.exe or gpmc.msc/rsop.msc respectively. And there it ends up in an error handler that can't handle a WBEM_E_INVALID_PROPERTY, but takes a default route in the code.

The Solution 

The solution is an easy fix: Move the powershell code from the Parameters block to a script file and enter this script in the Parameters block.

The Learnings

Always be aware that length matters. Too long can lead to unexpected errors. And also be aware that - although I didn't fully test - the same issue might apply to the script name itself or any other non-ADM-Templates input field that allows for long content. ADM templates input fields aren't affected that heavily, because they can be configured for maximum length.

An example for another gpo setting this issue applies to is the Host-to-Realm mapping for kerberos - https://gpsearch.azurewebsites.net/#1823

Here you can enter a list of realms (aka "AD domains") and the hostnames or suffixes that can be found in these realms. Within the ADM template setting, you can enter a really long list of hosts/suffixes. But the component that processes this list (kerberos.dll) has a hard coded (!) limit of 2.048 bytes when evaluating it. Everything exceeding this limit is simply cut off.