<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://blog.overgard.dk/feed.xml" rel="self" type="application/atom+xml" /><link href="https://blog.overgard.dk/" rel="alternate" type="text/html" /><updated>2026-01-13T14:50:03+00:00</updated><id>https://blog.overgard.dk/feed.xml</id><title type="html">&amp;amp; blog</title><subtitle>A blog about Microsoft infrastructure, identity management and automation.</subtitle><author><name>Kåre Overgård</name><email>k@overgard.dk</email></author><entry><title type="html">It’s 10 p.m. - Do you know what your Conditional Access policies are doing?</title><link href="https://blog.overgard.dk/2026/automating-ca-policy-names/" rel="alternate" type="text/html" title="It’s 10 p.m. - Do you know what your Conditional Access policies are doing?" /><published>2026-01-13T00:00:00+00:00</published><updated>2026-01-13T00:00:00+00:00</updated><id>https://blog.overgard.dk/2026/automating-ca-policy-names</id><content type="html" xml:base="https://blog.overgard.dk/2026/automating-ca-policy-names/"><![CDATA[<p><strong>TL;DR:</strong> If policy display names don’t capture intent, it’s easy to lose track of what your Conditional Access policies do. I wrote a PowerShell script that analyzes each policy and suggests clear, consistent names based on policy content - helping teams keep names aligned with configuration over time.</p>

<h2 id="why-naming-matters">Why naming matters</h2>

<p>Conditional Access (CA) policies are essential for securing access across your tenant, but understanding what each policy does can be surprisingly difficult. I frequently see tenants where administrators don’t know what many policies actually enforce - which creates both security gaps and poor user experiences.</p>

<p>The root causes are common:</p>

<ul>
  <li>Policies accumulate over time, making an overview hard to maintain.</li>
  <li>Multiple administrators use different naming styles.</li>
  <li>Policies often carry obscure names created by former employees or external consultants.</li>
</ul>

<p>Because CA policies lack a description field, the only practical way to document intent in the portal is to use a meaningful display name.</p>

<p><a href="/assets/images/ca-policy-naming-convention.jpg" data-lightbox="ca-policy-naming-convention" data-title=""><img src="/assets/images/ca-policy-naming-convention.jpg" alt="" /></a></p>

<h2 id="common-naming-approaches">Common naming approaches</h2>

<h3 id="microsoft-managed-and-template-names">Microsoft-managed and template names</h3>

<p>Microsoft-managed policies and template-based policies often use sentence-like names (for example, “Block legacy authentication”). These are readable but can become inconsistent when targeting specific apps, locations, or personas.</p>

<h3 id="microsoft-learn-suggested-standard">Microsoft Learn suggested standard</h3>

<p>Microsoft Learn suggests a structured format:</p>

<p><code class="language-plaintext highlighter-rouge">&lt;SN&gt; - &lt;Cloud app&gt;: &lt;Response&gt; For &lt;Principal&gt; When &lt;Conditions&gt;</code></p>

<p>Examples:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">CA01 - Dynamics CRM: Require MFA for Marketing when on external networks</code></li>
  <li><code class="language-plaintext highlighter-rouge">CA02 - Office 365: Require Terms of Use for Guests when using browser</code></li>
  <li><code class="language-plaintext highlighter-rouge">CA03 - All apps: Block legacy authentication</code></li>
</ul>

<p>The serial numbers make it easier to identify specific policies during troubleshooting, and the structure helps readability.</p>

<h3 id="zero-trust--persona-based-naming">Zero Trust / Persona-based naming</h3>

<p>The Conditional Access guidance for Zero Trust uses persona-based naming with serial prefixes and compact tokens. Personas group accounts of similar type (Internals, Admins, Guests, AzureServiceAccounts, etc.) so policies can target specific user types.</p>

<p>Examples:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">CA100-Admins-BaseProtection-AllApps-AnyPlatform-CompliantandMFA</code></li>
  <li><code class="language-plaintext highlighter-rouge">CA206-Internals-DataandAppProtection-AllApps-iOSorAndroid-ClientAppORAPP</code></li>
  <li><code class="language-plaintext highlighter-rouge">CA403-Guests-IdentityProtection-AllApps-AnyPlatform-BlockLegacyAuth</code></li>
</ul>

<p>Projects like Joey Verlinden’s <a href="https://github.com/j0eyv/ConditionalAccessBaseline">Conditional Access Baseline</a> have kept this approach up to date.</p>

<h2 id="a-different-approach-generate-descriptive-names">A different approach: generate descriptive names</h2>

<p>A naming standard helps, but names can drift as policies change - or administrators might not follow the standard. To address this, I created <code class="language-plaintext highlighter-rouge">Get-ConditionalAccessPolicyNameSuggestion.ps1</code> which can be found in my repository at <a href="https://github.com/kovergard/ConditionalAccess/tree/main/Naming">https://github.com/kovergard/ConditionalAccess/tree/main/Naming</a></p>

<h3 id="what-the-script-does">What the script does</h3>

<ul>
  <li>Parses each Conditional Access policy.</li>
  <li>Breaks policy configuration into components (persona, target, network, conditions, response).</li>
  <li>Combines components using a configurable pattern to produce suggested display names.</li>
</ul>

<h3 id="pattern-components">Pattern components</h3>

<table>
  <thead>
    <tr>
      <th>Component</th>
      <th>Description</th>
      <th>Default</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>{SerialNumber}</td>
      <td>Unique ID <code class="language-plaintext highlighter-rouge">CA{PersonaSerialNumber}{Counter}</code></td>
      <td> </td>
    </tr>
    <tr>
      <td>{Persona}</td>
      <td>Persona the policy applies to</td>
      <td>Global</td>
    </tr>
    <tr>
      <td>{TargetResource}</td>
      <td>Application or user action</td>
      <td>All apps</td>
    </tr>
    <tr>
      <td>{Network}</td>
      <td>Network conditions</td>
      <td>Any network</td>
    </tr>
    <tr>
      <td>{Condition}</td>
      <td>Any additional conditions</td>
      <td>Always</td>
    </tr>
    <tr>
      <td>{Response}</td>
      <td>Either <code class="language-plaintext highlighter-rouge">Block</code> or a list of requirements (MFA, etc.)</td>
      <td>(none)</td>
    </tr>
  </tbody>
</table>

<p>More details in the repo <a href="https://github.com/kovergard/ConditionalAccess/tree/main/Naming#name-pattern-components">README</a></p>

<h2 id="examples">Examples</h2>

<p>First, connect to Graph (read-only to inspect):</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Connect-MgGraph</span><span class="w"> </span><span class="nt">-Scopes</span><span class="w"> </span><span class="nx">Policy.Read.All</span><span class="p">,</span><span class="nx">Application.Read.All</span><span class="p">,</span><span class="nx">Group.Read.All</span><span class="w">
</span></code></pre></div></div>

<p>For the following examples, a set of sample policies are used.</p>

<p><a href="/assets/images/ca-policy-sample-set.png" data-lightbox="ca-policy-sample-set" data-title=""><img src="/assets/images/ca-policy-sample-set.png" alt="" style="border:1px solid #999" /></a></p>

<h3 id="default-suggestions">Default suggestions</h3>

<p>Run without parameters (uses default pattern):</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">.</span><span class="n">\Get-ConditionalAccessPolicyNameSuggestion.ps1</span><span class="w">
</span></code></pre></div></div>

<p><a href="/assets/images/ca-policy-suggestion-default.png" data-lightbox="ca-policy-suggestion-default" data-title=""><img src="/assets/images/ca-policy-suggestion-default.png" alt="" /></a></p>

<ul>
  <li>Names consistently show key configuration details.</li>
  <li>A serial prefix enables sorting by persona.</li>
  <li>Existing serial numbers are preserved where appropriate.</li>
</ul>

<h3 id="emulate-microsoft-learn-style">Emulate Microsoft Learn style</h3>

<p>Set a pattern similar to Learn guidance:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$Pattern</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'{SerialNumber} - {TargetResource}: {Response} For {Persona} On {Network} When {Condition}'</span><span class="w">
</span><span class="o">.</span><span class="n">\Get-ConditionalAccessPolicyNameSuggestion.ps1</span><span class="w"> </span><span class="nt">-NamePattern</span><span class="w"> </span><span class="nv">$Pattern</span><span class="w">
</span></code></pre></div></div>

<p><a href="/assets/images/ca-policy-suggestion-microsoftlearn.png" data-lightbox="ca-policy-suggestion-microsoftlearn" data-title=""><img src="/assets/images/ca-policy-suggestion-microsoftlearn.png" alt="" /></a></p>

<h3 id="make-it-yours">Make it yours</h3>

<p>Want compact names or different delimiters?</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$Pattern</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'{SerialNumber}.{TargetResource}.{Network}.{Condition}.{Response}'</span><span class="w">
</span><span class="o">.</span><span class="n">\Get-ConditionalAccessPolicyNameSuggestion.ps1</span><span class="w"> </span><span class="nt">-NamePattern</span><span class="w"> </span><span class="nv">$Pattern</span><span class="w"> </span><span class="nt">-Condense</span><span class="w"> </span><span class="nt">-KeepSerialNumbers</span><span class="w">
</span></code></pre></div></div>

<p><a href="/assets/images/ca-policy-suggestion-compact.png" data-lightbox="ca-policy-suggestion-compact" data-title=""><img src="/assets/images/ca-policy-suggestion-compact.png" alt="" /></a></p>

<h2 id="moving-beyond-suggestions---careful-updates">Moving beyond suggestions - careful updates</h2>

<p>The script suggests names; it does not change them by default. If you want to apply suggestions, you must connect with write permissions:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Connect-MgGraph</span><span class="w"> </span><span class="nt">-Scopes</span><span class="w"> </span><span class="nx">Policy.ReadWrite.ConditionalAccess</span><span class="p">,</span><span class="nx">Application.Read.All</span><span class="p">,</span><span class="nx">Group.Read.All</span><span class="w">
</span></code></pre></div></div>

<p>Compare current names with suggestions:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$CaNamesToUpdate</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">.</span><span class="n">\Get-ConditionalAccessPolicyNameSuggestion.ps1</span><span class="w"> </span><span class="o">|</span><span class="w">
    </span><span class="n">Where-Object</span><span class="w"> </span><span class="p">{</span><span class="bp">$_</span><span class="o">.</span><span class="nf">Name</span><span class="w"> </span><span class="o">-ne</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">SuggestedName</span><span class="p">}</span><span class="w">
</span><span class="nv">$CaNamesToUpdate</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">Format-List</span><span class="w">
</span></code></pre></div></div>

<p>To apply suggested names:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$CaNamesToUpdate</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ForEach-Object</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="nv">$DisplayName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="bp">$_</span><span class="o">.</span><span class="nf">SuggestedName</span><span class="w">
    </span><span class="n">Invoke-MgGraphRequest</span><span class="w"> </span><span class="nt">-Method</span><span class="w"> </span><span class="nx">PATCH</span><span class="w"> </span><span class="se">`
</span><span class="w">        </span><span class="nt">-Uri</span><span class="w"> </span><span class="s2">"https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies/</span><span class="si">$(</span><span class="bp">$_</span><span class="o">.</span><span class="nf">id</span><span class="si">)</span><span class="s2">"</span><span class="w"> </span><span class="se">`
</span><span class="w">        </span><span class="nt">-Body</span><span class="w"> </span><span class="p">(@{</span><span class="w"> </span><span class="nx">displayName</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nv">$DisplayName</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">ConvertTo-Json</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<blockquote>
  <p>⚠️ Important: This is not a security control - it’s a naming and documentation aid. Always review suggested names and update any inclusion/exclusion groups or references that rely on policy names.</p>
</blockquote>

<h2 id="automation-and-next-steps">Automation and next steps</h2>

<p>You can automate the script to run periodically and generate a report of name drift. I recommend keeping it supervised until you’re comfortable with the pattern and script behavior.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Clear, consistent policy names make troubleshooting and governance far easier. This script helps you try naming standards across your actual policies so you can pick the format that best fits your organization.</p>

<p>Feedback and suggestions are welcome - open an issue in the repo or contact me via GitHub/LinkedIn/email.</p>]]></content><author><name>Kåre Overgård</name><email>k@overgard.dk</email></author><category term="conditional-access" /><category term="automation" /><category term="powershell" /><summary type="html"><![CDATA[TL;DR: If policy display names don’t capture intent, it’s easy to lose track of what your Conditional Access policies do. I wrote a PowerShell script that analyzes each policy and suggests clear, consistent names based on policy content - helping teams keep names aligned with configuration over time.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blog.overgard.dk/assets/images/pexels-mikhail-nilov-6963062.jpg" /><media:content medium="image" url="https://blog.overgard.dk/assets/images/pexels-mikhail-nilov-6963062.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Welcome</title><link href="https://blog.overgard.dk/2026/welcome/" rel="alternate" type="text/html" title="Welcome" /><published>2026-01-08T00:00:00+00:00</published><updated>2026-01-08T00:00:00+00:00</updated><id>https://blog.overgard.dk/2026/welcome</id><content type="html" xml:base="https://blog.overgard.dk/2026/welcome/"><![CDATA[<p>Welcome to the blog!</p>

<p>I needed a place for sharing tips, scripts and experiences from my work with Microsoft infrastructure, identity management and automation, so I decided to spin up this blog.</p>

<p>My aim is to help other people working with Microsoft technologies.</p>]]></content><author><name>Kåre Overgård</name><email>k@overgard.dk</email></author><category term="general" /><summary type="html"><![CDATA[Welcome to the blog!]]></summary></entry></feed>