<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: oussangelo</title>
    <description>The latest articles on DEV Community by oussangelo (@oussangelo).</description>
    <link>https://dev.to/oussangelo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4035750%2F57f6d76c-41ad-4deb-a78d-e05a09cfe304.png</url>
      <title>DEV Community: oussangelo</title>
      <link>https://dev.to/oussangelo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oussangelo"/>
    <language>en</language>
    <item>
      <title>Monitoring Hardened Domain Controllers Without Admin Rights: The Five Permission Layers Nobody Documents</title>
      <dc:creator>oussangelo</dc:creator>
      <pubDate>Sat, 18 Jul 2026 19:35:42 +0000</pubDate>
      <link>https://dev.to/oussangelo/monitoring-hardened-domain-controllers-without-admin-rights-the-five-permission-layers-nobody-o3f</link>
      <guid>https://dev.to/oussangelo/monitoring-hardened-domain-controllers-without-admin-rights-the-five-permission-layers-nobody-o3f</guid>
      <description>&lt;p&gt;&lt;em&gt;Everything works when the service account is a Domain Admin. Nothing works when you remove it. Here is the complete map of what sits in between — learned the hard way.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;If you have ever tried to run a monitoring tool against Active Directory domain controllers with a least-privilege service account, you have probably lived this exact sequence: you create a dedicated account, you grant it what every blog post says to grant (a couple of Builtin groups, some WMI namespace rights), and you get &lt;code&gt;Access denied&lt;/code&gt;. You add the account to Domain Admins "just to test" — everything works instantly. You remove it — everything breaks again.&lt;/p&gt;

&lt;p&gt;At that point, most people leave the account in an admin group and move on. That is how monitoring service accounts become the most attractive lateral-movement targets in the forest: credentials that sit in a scheduled task, touch every DC daily, and hold domain-wide admin rights.&lt;/p&gt;

&lt;p&gt;I refused to leave it there while building &lt;a href="https://github.com/oussangelo/ADEHM" rel="noopener noreferrer"&gt;ADEHM&lt;/a&gt;, an agentless AD health monitor (PowerShell + CIM/WinRM). My domain controllers run a security baseline, and getting read-only monitoring to work on them took me through &lt;strong&gt;five distinct permission layers&lt;/strong&gt; — most of which are undocumented, and two of which produce actively misleading symptoms. This article is the map I wish I had.&lt;/p&gt;

&lt;p&gt;A note before we start: on a default, non-hardened installation, layers 1, 2 and 4 are usually already open. Hardening baselines (Microsoft Security Baseline, CIS, ANSSI and friends) close them. If your DCs are hardened, expect to need all five.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model: five doors in a corridor
&lt;/h2&gt;

&lt;p&gt;A remote CIM query from your monitoring host to a DC passes through five successive access checks. Each one produces its own flavor of "access denied", and — this is the trap — the error message rarely tells you which door refused you. The doors, in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Network logon right&lt;/strong&gt; — may the account authenticate to this machine over the network at all?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WinRM root SDDL&lt;/strong&gt; — may it talk to the WinRM service?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WMI namespace DACL&lt;/strong&gt; — may it use the &lt;code&gt;root\cimv2&lt;/code&gt; namespace remotely?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Control Manager SDDL&lt;/strong&gt; — may it enumerate Windows services?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-service security descriptors&lt;/strong&gt; — may it read &lt;em&gt;this particular&lt;/em&gt; service?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Adding the account to Administrators opens all five at once, which is exactly why it "fixes" everything and teaches you nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 1 — Access this computer from the network
&lt;/h2&gt;

&lt;p&gt;Before WinRM even looks at your request, Windows checks &lt;code&gt;SeNetworkLogonRight&lt;/code&gt;. By default it includes Authenticated Users; hardening baselines restrict it on DCs to a short list (Administrators, ENTERPRISE DOMAIN CONTROLLERS...). Your service account gets turned away at the front door, before any of the layers you actually configured.&lt;/p&gt;

&lt;p&gt;The telltale sign lives in the DC security log — reproduce the failure, then look for event &lt;strong&gt;4625&lt;/strong&gt; and read its Status field:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-WinEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-FilterHashtable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@{&lt;/span&gt;&lt;span class="nx"&gt;LogName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Security'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4625&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;StartTime&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Date&lt;/span&gt;&lt;span class="err"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;AddMinutes&lt;/span&gt;&lt;span class="err"&gt;(-&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Where-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'svc-monitoring'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-First&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ExpandProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;0xC000015B&lt;/code&gt; means &lt;em&gt;"the user has not been granted the requested logon type"&lt;/em&gt; — this layer, confirmed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix belongs in the hardening GPO, not on the machines.&lt;/strong&gt; Add your monitoring group to &lt;em&gt;Computer Configuration → Policies → Windows Settings → Security Settings → Local Policies → User Rights Assignment → Access this computer from the network&lt;/em&gt; in the GPO applied to the Domain Controllers OU. A local change would be silently reverted at the next policy refresh — a pattern you will meet again in this article. While you are there, check that the account does not match anything in &lt;em&gt;Deny access to this computer from the network&lt;/em&gt;: a Deny wins over everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 2 — The WinRM RootSDDL
&lt;/h2&gt;

&lt;p&gt;WinRM gates all remote management through a root security descriptor. On modern Windows Server the default contains &lt;code&gt;(A;;GA;;;RM)&lt;/code&gt; — an allow entry for BUILTIN\Remote Management Users, so putting your group in that Builtin group is enough. (Handy fact: DCs have no local groups; their "local" groups are the domain Builtin groups, so one membership covers every DC.)&lt;/p&gt;

&lt;p&gt;Hardened or upgraded-in-place systems, however, sometimes carry a stripped RootSDDL. Check yours:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Invoke-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ComputerName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dcs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ScriptBlock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WSMan:\localhost\Service\RootSDDL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you see something like &lt;code&gt;O:NSG:BAD:P(A;;GA;;;BA)(A;;GR;;;IU)S:...&lt;/code&gt; — Administrators and Interactive only, no &lt;code&gt;RM&lt;/code&gt; — that is your blocker. Insert an ACE for your group's SID at the end of the DACL, just before the &lt;code&gt;S:&lt;/code&gt; (SACL) marker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-ADGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'GRP-AD-Monitoring'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;Invoke-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ComputerName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dcs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ScriptBlock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WSMan:\localhost\Service\RootSDDL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;";;;&lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Already present'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Set-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\Windows\Temp\RootSDDL_backup_&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="n"&gt;Get-Date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;yyyyMMdd_HHmmss&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.txt"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$ace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(A;;GA;;;&lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'S:'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-ge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Set-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;WSMan:\localhost\Service\RootSDDL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s1"&gt;'Updated'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ArgumentList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Why &lt;code&gt;String.Insert&lt;/code&gt; instead of a regex replace: it behaves identically whether or not a SACL exists, and cannot silently do nothing. SDDL strings punish creativity.)&lt;/p&gt;

&lt;p&gt;Same GPO caveat as layer 1: if a baseline manages this value, codify the change in the baseline or watch it evaporate every 90–120 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 3 — The WMI namespace DACL
&lt;/h2&gt;

&lt;p&gt;The layer everyone knows about, with two classic mistakes. Remote CIM access to &lt;code&gt;root\cimv2&lt;/code&gt; requires &lt;strong&gt;two&lt;/strong&gt; rights on the namespace: &lt;em&gt;Enable Account&lt;/em&gt; (&lt;code&gt;0x1&lt;/code&gt;) &lt;strong&gt;and&lt;/strong&gt; &lt;em&gt;Remote Enable&lt;/em&gt; (&lt;code&gt;0x20&lt;/code&gt;). The &lt;code&gt;wmimgmt.msc&lt;/code&gt; UI makes it very easy to tick only Remote Enable — which yields the signature symptom "WinRM accepts the connection, then WMI returns access denied". The second mistake is setting the rights on &lt;code&gt;root&lt;/code&gt; instead of &lt;code&gt;root\cimv2&lt;/code&gt; with "this namespace only" scope, which does not propagate.&lt;/p&gt;

&lt;p&gt;Do not trust the UI; read what the DC actually enforces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Invoke-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ComputerName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dcs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ScriptBlock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Invoke-WmiMethod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'root/cimv2'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'__SystemSecurity=@'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GetSecurityDescriptor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Descriptor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DACL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;ForEach-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;PSCustomObject&lt;/span&gt;&lt;span class="p"&gt;]@{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nx"&gt;Trustee&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'{0}\{1}'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Trustee&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Trustee&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nx"&gt;EnableAccount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AccessMask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;band&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;x1&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nx"&gt;RemoteEnable&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AccessMask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;band&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="nx"&gt;x20&lt;/span&gt;&lt;span class="err"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two implementation notes that cost me hours. First, invoke &lt;code&gt;GetSecurityDescriptor&lt;/code&gt;/&lt;code&gt;SetSecurityDescriptor&lt;/code&gt; through &lt;code&gt;Invoke-WmiMethod&lt;/code&gt; on the &lt;code&gt;__SystemSecurity=@&lt;/code&gt; singleton path — calling the method directly on the object returned by &lt;code&gt;Get-WmiObject&lt;/code&gt; fails on some systems with &lt;em&gt;"does not contain a method named GetSecurityDescriptor"&lt;/em&gt;. Second, an ACE with mask &lt;code&gt;0x21&lt;/code&gt;, AceType 0, no inheritance is all you need; the account stays strictly read-only.&lt;/p&gt;

&lt;p&gt;An idempotent grant script (with &lt;code&gt;-WhatIf&lt;/code&gt; and rollback) ships in the &lt;a href="https://github.com/oussangelo/ADEHM" rel="noopener noreferrer"&gt;ADEHM repo&lt;/a&gt; under &lt;code&gt;Tools/Grant-ADEHMWmiPermission.ps1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer 4 — The Service Control Manager SDDL
&lt;/h2&gt;

&lt;p&gt;Here is where hardened systems diverge sharply from lab machines. Your OS query now works (&lt;code&gt;Win32_OperatingSystem&lt;/code&gt; returns data), but &lt;code&gt;SELECT * FROM Win32_Service&lt;/code&gt; fails with access denied. The WMI service provider impersonates the caller and asks the &lt;strong&gt;Service Control Manager&lt;/strong&gt; to enumerate services — and the SCM's own security descriptor, on hardened (and even many default) systems, does not grant enumeration to remote non-admin callers.&lt;/p&gt;

&lt;p&gt;Check and fix, granting the same read set Windows gives interactive users (&lt;code&gt;CCLCRPRC&lt;/code&gt;: connect, enumerate, query status, read control — no start, stop or modify):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-ADGroup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'GRP-AD-Monitoring'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SID&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Value&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;Invoke-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ComputerName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$dcs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ScriptBlock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sdshow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scmanager&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Where-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'\S'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-join&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;";;;&lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Already present'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Set-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"C:\Windows\Temp\scmanager_sddl_backup_&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="n"&gt;Get-Date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;yyyyMMdd_HHmmss&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;.txt"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$ace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(A;;CCLCRPRC;;;&lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="s2"&gt;)"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IndexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'S:'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-ge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$idx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$current&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sdset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scmanager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ArgumentList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$sid&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Layer 5 — Per-service security descriptors
&lt;/h2&gt;

&lt;p&gt;The subtlest one, because it fails &lt;em&gt;silently&lt;/em&gt;. With the SCM open, enumeration succeeds — but each service then filters the caller through its &lt;strong&gt;own&lt;/strong&gt; security descriptor. A service whose SD does not grant read to your account is not reported as denied; it is simply &lt;strong&gt;absent from the results&lt;/strong&gt;. Your query for NTDS returns nothing, your monitoring tool concludes the service does not exist, and no error is raised anywhere.&lt;/p&gt;

&lt;p&gt;I only caught this because my diagnostic script printed &lt;code&gt;OK (NTDS = )&lt;/code&gt; — an empty state — on two DCs while a third returned &lt;code&gt;Running&lt;/code&gt;. Same domain, same baseline on paper; per-service SDs had drifted.&lt;/p&gt;

&lt;p&gt;The fix mirrors layer 4, per service, with the interactive-users read set (&lt;code&gt;CCLCSWLOCRRC&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sc.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sdshow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NTDS&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c"&gt;# inspect&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# insert (A;;CCLCSWLOCRRC;;;&amp;lt;SID&amp;gt;) before S: and apply with: sc.exe sdset NTDS &amp;lt;new-sddl&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a whole list of monitored services across all DCs, idempotent and with backups, see &lt;code&gt;Tools/Grant-ADEHMServiceReadPermission.ps1&lt;/code&gt; in the repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three operational rules that will save you a day each
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Restart WinRM after any ACL change.&lt;/strong&gt; WinRM keeps per-user host processes (&lt;code&gt;WsmProvHost.exe&lt;/code&gt;) alive between sessions. A stale host process serves your requests with pre-change access state — meaning a &lt;em&gt;correct&lt;/em&gt; fix keeps failing for hours, until the process idles out. I watched identical client PIDs in the WMI log across a 40-minute debugging window and chased ghosts the whole time. &lt;code&gt;Restart-Service WinRM&lt;/code&gt; on the DCs after ACL work; the impact is a brief drop of active remote-management sessions, nothing more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;root\interop&lt;/code&gt; denials are a red herring.&lt;/strong&gt; Once you enable the WMI-Activity log analysis (below), you will see &lt;code&gt;0x80041003&lt;/code&gt; denials for &lt;code&gt;connect to namespace : root\interop&lt;/code&gt; on every CIM session — including fully working ones. The WinRM WMI plugin probes that namespace and shrugs off the refusal. I initially granted rights on it; field testing proved it unnecessary. Least privilege says: do not grant what is not needed. Ignore these entries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test with explicit credentials, never with &lt;code&gt;runas&lt;/code&gt;.&lt;/strong&gt; Hardening baselines deny service accounts interactive logon — &lt;code&gt;runas&lt;/code&gt; fails with error 1385, and that is &lt;em&gt;correct behavior&lt;/em&gt;, not a bug to fix. Test the way your tool will actually run: &lt;code&gt;New-CimSession -Credential&lt;/code&gt;, and &lt;code&gt;Test-WSMan -Credential -Authentication Default&lt;/code&gt; (without &lt;code&gt;-Authentication Default&lt;/code&gt;, Test-WSMan sends an unauthenticated probe that succeeds for any account and proves nothing). For scheduled tasks, the &lt;em&gt;batch&lt;/em&gt; logon type applies: grant &lt;em&gt;Log on as a batch job&lt;/em&gt; on the execution host only — never on the DCs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The diagnostic that ends the guessing
&lt;/h2&gt;

&lt;p&gt;The single most valuable tool in this whole journey is the DC-side &lt;strong&gt;WMI-Activity operational log&lt;/strong&gt;, because it names the refusal instead of letting you infer it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-WinEvent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LogName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Microsoft-Windows-WMI-Activity/Operational'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-MaxEvents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;50&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Where-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'0x80041003'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TimeCreated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Message&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each denial entry carries &lt;strong&gt;User, Namespace and Operation&lt;/strong&gt; — the exact identity refused, on the exact object, doing the exact thing. One look at &lt;code&gt;Operation = connect to namespace : root\cimv2&lt;/code&gt; versus &lt;code&gt;Start IWbemServices::ExecQuery ... Win32_Service&lt;/code&gt; tells you whether you are fighting layer 3 or layer 4. Combine it with the layered functional test (WinRM auth → CIM session → OS read → service read) and the 4625 status codes from layer 1, and no failure mode in this stack can hide from you. The full one-shot diagnostic script — functional chain, namespace DACLs, WMI denials and SCM SDDL captured at the same instant — is in the repo as &lt;code&gt;Tools/Test-ADEHMPermission.ps1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing thought
&lt;/h2&gt;

&lt;p&gt;None of these five layers is exotic. Each is a legitimate, documented-somewhere Windows security boundary doing its job. What is missing from the ecosystem is the &lt;em&gt;map&lt;/em&gt; — the knowledge that they stack, the order they trip in, and the misleading symptoms each produces. That gap is why so many monitoring service accounts end up in Domain Admins.&lt;/p&gt;

&lt;p&gt;The complete tooling (grant scripts, rollback, one-shot diagnostic) lives in the ADEHM repository, MIT licensed: &lt;strong&gt;&lt;a href="https://github.com/oussangelo/ADEHM" rel="noopener noreferrer"&gt;https://github.com/oussangelo/ADEHM&lt;/a&gt;&lt;/strong&gt; — where the tool itself gives you agentless, read-only health monitoring of your DCs as a daily HTML report. If your environment trips a sixth door I have not met, open an issue; the map only gets better with more territory.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>activedirectory</category>
      <category>security</category>
      <category>sysadmin</category>
    </item>
  </channel>
</rss>
