<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Day 3 Bits</title>
        <link>https://day3bits.com/</link>
        <description>Notes about enterprise IT with a focus on automation, design, security, user experience. Sam's primary goal is to promote the growth of operational maturity through intentional growth and continuous improvement.</description>
        <lastBuildDate>Wed, 18 Mar 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>Copyright © 2026 Sam Erde</copyright>
        <item>
            <title><![CDATA[Microsoft Graph Updates for New Sovereign Cloud Partner Environments]]></title>
            <link>https://day3bits.com/2026-03-18-new-microsoft-graph-soverign-cloud-partner-environments/</link>
            <guid>https://day3bits.com/2026-03-18-new-microsoft-graph-soverign-cloud-partner-environments/</guid>
            <pubDate>Wed, 18 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Microsoft is building new national partner cloud environments and has updated the Graph PowerShell module to support them.]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="interesting-updates-in-microsoftgraph-2360">Interesting Updates in Microsoft.Graph 2.36.0<a href="https://day3bits.com/2026-03-18-new-microsoft-graph-soverign-cloud-partner-environments/#interesting-updates-in-microsoftgraph-2360" class="hash-link" aria-label="Direct link to Interesting Updates in Microsoft.Graph 2.36.0" title="Direct link to Interesting Updates in Microsoft.Graph 2.36.0" translate="no">​</a></h2>
<p>You can often learn interesting things by looking at release notes. While reading the "what's changed" list for the <strong>msgraph-sdk-powershell</strong> project (Microsoft Graph PowerShell module), three things stood out:</p>
<blockquote>
<p><strong>Re-establish Separate Auth Paths for WAM Enabled/Disabled by @ramsessanchez in <a href="https://github.com/microsoftgraph/msgraph-sdk-powershell/pull/3542" target="_blank" rel="noopener noreferrer" class="">#3542</a></strong>
Can we hope for continued improvements with WAM support in PowerShell?</p>
<p><strong>fix: update msal dependencies by @gavinbarron in <a href="https://github.com/microsoftgraph/msgraph-sdk-powershell/pull/3542" target="_blank" rel="noopener noreferrer" class="">#3548</a></strong>
Of interest to me due to my work on mitigating MSAL version conflicts for <a href="https://maester.dev/" target="_blank" rel="noopener noreferrer" class="">Maester</a> and the <a href="https://github.com/samerde/dllpickle" target="_blank" rel="noopener noreferrer" class="">DLL Pickle</a> module.</p>
<p><strong>Add BleuCloud, DelosCloud, and GovSGCloud sovereign cloud environments, remove deprecated Germany cloud by @Copilot in <a href="https://github.com/microsoftgraph/msgraph-sdk-powershell/pull/3523" target="_blank" rel="noopener noreferrer" class="">#3523</a></strong>
What are these new names???</p>
</blockquote>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="looking-deeper">Looking Deeper<a href="https://day3bits.com/2026-03-18-new-microsoft-graph-soverign-cloud-partner-environments/#looking-deeper" class="hash-link" aria-label="Direct link to Looking Deeper" title="Direct link to Looking Deeper" translate="no">​</a></h3>
<h4 class="anchor anchorTargetStickyNavbar_Vzrq" id="sovereign-cloud-changes">Sovereign Cloud Changes<a href="https://day3bits.com/2026-03-18-new-microsoft-graph-soverign-cloud-partner-environments/#sovereign-cloud-changes" class="hash-link" aria-label="Direct link to Sovereign Cloud Changes" title="Direct link to Sovereign Cloud Changes" translate="no">​</a></h4>
<p>The EU has been keeping Microsoft busy, and in PR #3523, we see their latest developments spinning up, thanks to this GitHub Copilot prompt:</p>
<blockquote>
<p>Microsoft is building two new fully instanced national partner clouds in France an Germany. To support customers and ISV of these clouds to easily connect to these clouds the built-in environments should be updated to include the correct endpoints. In addition the current built-in environment for Germany (Blackforest) is not longer available and should be removed to avoid confusion for customers of the new national partner cloud in Germany which is owned and operated by Delos Cloud.</p>
</blockquote>
<p>Subtasks in this plan include cleanup of deprecated Microsoft-managed environments and name clarifications:</p>
<ul>
<li class="">Remove the old Germany (Blackforest) environment from GraphEnvironmentConstants.cs</li>
<li class="">Update GraphSettingsTests.cs to reflect new built-in environment count (6 instead of 5)</li>
<li class="">Update NationalCloudHandlerTests.cs to test DelosCloud instead of removed Germany</li>
<li class="">Add GovSGCloud sovereign cloud environment</li>
<li class="">Update tests to reflect 7 built-in environments</li>
<li class="">Fix PowerShell test to use DelosCloud instead of Germany</li>
<li class="">Update GovSGCloud comment to "Sovereign Government Cloud"</li>
</ul>
<p>Customers of national cloud partners will be able to add user-defined environments for these new partner clouds using the following commands:</p>
<p><strong>France</strong></p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Add-MgEnvironment</span><span class="token plain">  </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name BleuCloud</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">-</span><span class="token plain">AzureAdEndpoint &lt;https:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">login</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sovcloud-identity</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">fr/&gt; `</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">-</span><span class="token plain">GraphEndpoint &lt;https:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">graph</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">svc</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sovcloud</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">fr/&gt;</span><br></div></code></pre></div></div>
<p><strong>Germany</strong></p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Add-MgEnvironment</span><span class="token plain">  </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name DelosCloud</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">-</span><span class="token plain">AzureAdEndpoint &lt;https:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">login</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sovcloud-identity</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">de/&gt; `</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">-</span><span class="token plain">GraphEndpoint &lt;https:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">graph</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">svc</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sovcloud</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">de/&gt;</span><br></div></code></pre></div></div>
<p><strong>GovSGCloud</strong></p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Add-MgEnvironment</span><span class="token plain">  </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name GovSGCloud</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">-</span><span class="token plain">AzureAdEndpoint &lt;https:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">login</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sovcloud-identity</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sg/&gt; `</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token operator" style="color:#393A34">-</span><span class="token plain">GraphEndpoint &lt;https:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">graph</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">svc</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sovcloud</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">sg/&gt;</span><br></div></code></pre></div></div>
<p><strong>Output</strong></p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Name        AzureADEndpoint                    GraphEndpoint                           Type</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">----            ---------------                    -------------                           ----</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">USGovDoD        https://login.microsoftonline.us   https://dod-graph.microsoft.us          Built-in</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">USGov           https://login.microsoftonline.us   https://graph.microsoft.us              Built-in</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">China           https://login.chinacloudapi.cn     https://microsoftgraph.chinacloudapi.cn Built-in</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Global          https://login.microsoftonline.com  https://graph.microsoft.com             Built-in</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">BleuCloud       https://login.sovcloud-identity.fr https://graph.svc.sovcloud.fr           Built-in</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">DelosCloud      https://login.sovcloud-identity.de https://graph.svc.sovcloud.de           Built-in</span><br></div></code></pre></div></div>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="questions">Questions<a href="https://day3bits.com/2026-03-18-new-microsoft-graph-soverign-cloud-partner-environments/#questions" class="hash-link" aria-label="Direct link to Questions" title="Direct link to Questions" translate="no">​</a></h2>
<p>What I don't see in the PR is any work on the <code>Singapore</code> environment that Copilot references (is this a hallucination or discovered fact?) or an explanation of what <code>GovSGCloud</code> is reserved for. Let me know if you have any insights into these developments or if you are waiting to migrate workloads to them!</p>
<p>Keep learning and discovering! Have a great day, friends!</p>
<p>Sam</p>]]></content:encoded>
            <category>PowerShell</category>
            <category>Azure</category>
            <category>Microsoft Graph</category>
        </item>
        <item>
            <title><![CDATA[Issues with Windows Update KB5066835 Cause Problems with Authentication Flows]]></title>
            <link>https://day3bits.com/2025-10-16-windows-update-kb5066835-authentication-problems/</link>
            <guid>https://day3bits.com/2025-10-16-windows-update-kb5066835-authentication-problems/</guid>
            <pubDate>Thu, 16 Oct 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[Security update breaks localhost listeners that are used to connect to Microsoft 365 services with PowerShell and affect other 3rd party applications such as Cisco Duo.]]></description>
            <content:encoded><![CDATA[<p>This Wednesday, October 15th, I encountered an unpleasant surprise when I began connecting to Microsoft 365 services to test the latest prerelease version of Maester: I could not connect to Microsoft Teams using PowerShell!</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Import-Module</span><span class="token plain"> Maester</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Connect-Maester</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Service All </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">TenantId </span><span class="token variable" style="color:#36acaa">$MyTenantId</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Connect-MicrosoftTeams</span><span class="token plain">: ~\Documents\PowerShell\Modules\Maester\1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">3</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">90\public\</span><span class="token function" style="color:#d73a49">Connect-Maester</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ps1:284</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Line </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 284 </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain">                    </span><span class="token function" style="color:#d73a49">Connect-MicrosoftTeams</span><span class="token plain"> &gt; </span><span class="token variable" style="color:#36acaa">$null</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain">                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> One or more errors occurred</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">An HttpListenerException occurred </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> listening on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> http:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">localhost:52723/ </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> the system browser to complete the login</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> Possible cause and</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> mitigation: the app is unable to listen on the specified URL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> run </span><span class="token string" style="color:#e3116c">'netsh http add</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">     | iplisten 127.0.0.1'</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> the Admin command prompt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Connect-MicrosoftTeams</span><span class="token plain">: ~\Documents\PowerShell\Modules\Maester\1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">3</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">90\public\</span><span class="token function" style="color:#d73a49">Connect-Maester</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ps1:284</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Line </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 284 </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain">                    </span><span class="token function" style="color:#d73a49">Connect-MicrosoftTeams</span><span class="token plain"> &gt; </span><span class="token variable" style="color:#36acaa">$null</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain">                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> An HttpListenerException occurred </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> listening on http:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">localhost:52723/ </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> the</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> system browser to complete the login</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> Possible cause and mitigation: the app is unable to</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> listen on the specified URL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> run </span><span class="token string" style="color:#e3116c">'netsh http add iplisten 127.0.0.1'</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> the Admin</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> command prompt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Connect-MicrosoftTeams</span><span class="token plain">: ~\Documents\PowerShell\Modules\Maester\1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">3</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">90\public\</span><span class="token function" style="color:#d73a49">Connect-Maester</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ps1:284</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Line </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 284 </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain">                    </span><span class="token function" style="color:#d73a49">Connect-MicrosoftTeams</span><span class="token plain"> &gt; </span><span class="token variable" style="color:#36acaa">$null</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain">                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> The request is not supported</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Connect-MicrosoftTeams</span><span class="token plain">: ~\Documents\PowerShell\Modules\Maester\1</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">3</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">90\public\</span><span class="token function" style="color:#d73a49">Connect-Maester</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ps1:284</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Line </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"> 284 </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain">                    </span><span class="token function" style="color:#d73a49">Connect-MicrosoftTeams</span><span class="token plain"> &gt; </span><span class="token variable" style="color:#36acaa">$null</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain">                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> One or more errors occurred</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">An HttpListenerException occurred </span><span class="token keyword" style="color:#00009f">while</span><span class="token plain"> listening on</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> http:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">localhost:52723/ </span><span class="token keyword" style="color:#00009f">for</span><span class="token plain"> the system browser to complete the login</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain"> Possible cause and</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">     </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> mitigation: the app is unable to listen on the specified URL</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> run </span><span class="token string" style="color:#e3116c">'netsh http add</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">     | iplisten 127.0.0.1'</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">from</span><span class="token plain"> the Admin command prompt</span><span class="token punctuation" style="color:#393A34">.</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>The process still opened a browser, which proceeded to show a "localhost refused to connect" error.</p>
<p>The timing of this felt like it may have been patch related, but I do frequently test prerelease software and it honestly could have been anything. Then I was fortunate to see a Twitter/X post from <a href="https://x.com/bdam555" target="_blank" rel="noopener noreferrer" class="">Bryan Dam</a> and a reply from <a href="https://x.com/SBSDiva" target="_blank" rel="noopener noreferrer" class="">Susan Bradley</a> that validated the theory.</p>
<p><a href="https://x.com/bdam555/status/1978935615807783322" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/twitter-KB5066835.png" alt="@bdam555 on X: &quot;PSA: have heard multiple reports that this month's CS (ex. KB5066835) break/alter the hocalhost loopback in ways that has broken a fairly wide swath of software" class="img_ev3q"></a></p>
<p>That post and the Cisco Duo article 9527 that Susan Brady shared (<a href="https://help.duo.com/s/article/9527" target="_blank" rel="noopener noreferrer" class="">Why is Duo Desktop not detected on my Windows device after installing updates to Windows 11?</a>) was the confirmation that I needed. (Additional information: <a href="https://www.askwoody.com/forums/topic/october-2025-updates-released/#post-2815434" target="_blank" rel="noopener noreferrer" class="">#2815434 on askwoody.com</a>.)</p>
<p>The <a href="https://support.microsoft.com/en-us/topic/october-14-2025-kb5066835-os-builds-26200-6899-and-26100-6899-1db237d8-9f3b-4218-9515-3e0a32729685" target="_blank" rel="noopener noreferrer" class="">October 14, 2025 KB5066835 update</a> is definitely breaking apps and authentication processes that utilize the localhost loopback listener. I removed the two updates that the Cisco Duo article mentioned, rebooted, and the issue immediately went away.</p>
<p>I haven't found a publicly visible statement from Microsoft yet, but this explanation is included in the Windows release health message center:</p>
<blockquote>
<p>Following installation of updates releases on or after October 14 (the Originating KBs listed above), server-side applications that rely on HTTP.sys may experience issues with incoming connections. As a result, IIS websites might fail to load, displaying a message such as "Connection reset – error (ERR_CONNECTION_RESET)", or similar error. This includes websites hosted on <a href="http://localhost/" target="_blank" rel="noopener noreferrer" class="">http://localhost/</a>, and other IIS connections.</p>
</blockquote>
<p>Here's one way to resolve the issue until a new security patch or hotfix is released:</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-wusa-to-remove-the-patches">Use WUSA to Remove the Patches<a href="https://day3bits.com/2025-10-16-windows-update-kb5066835-authentication-problems/#use-wusa-to-remove-the-patches" class="hash-link" aria-label="Direct link to Use WUSA to Remove the Patches" title="Direct link to Use WUSA to Remove the Patches" translate="no">​</a></h3>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Remove specific Windows Updates</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$KBs</span><span class="token plain"> = </span><span class="token string" style="color:#e3116c">'KB5066835'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'KB5065789'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">foreach</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">$KB</span><span class="token plain"> in </span><span class="token variable" style="color:#36acaa">$KBs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Write-Host</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Attempting to uninstall </span><span class="token string variable" style="color:#36acaa">$KB</span><span class="token string" style="color:#e3116c">..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Start-Process</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">FilePath </span><span class="token string" style="color:#e3116c">"wusa.exe"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ArgumentList </span><span class="token string" style="color:#e3116c">"/uninstall /kb:</span><span class="token string function" style="color:#d73a49">$</span><span class="token string function punctuation" style="color:#393A34">(</span><span class="token string function variable" style="color:#36acaa">$KB</span><span class="token string function" style="color:#d73a49"> </span><span class="token string function operator" style="color:#393A34">-replace</span><span class="token string function" style="color:#d73a49"> </span><span class="token string function string" style="color:#e3116c">'KB'</span><span class="token string function punctuation" style="color:#393A34">,</span><span class="token string function string" style="color:#e3116c">''</span><span class="token string function punctuation" style="color:#393A34">)</span><span class="token string" style="color:#e3116c"> /quiet /norestart"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Wait</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Or simply:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">wusa /uninstall kb:5066835</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">wusa /uninstall kb:5065789</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-dism-to-remove-the-patches">Use DISM to Remove the Patches<a href="https://day3bits.com/2025-10-16-windows-update-kb5066835-authentication-problems/#use-dism-to-remove-the-patches" class="hash-link" aria-label="Direct link to Use DISM to Remove the Patches" title="Direct link to Use DISM to Remove the Patches" translate="no">​</a></h3>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Remove updates using DISM</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$KBs</span><span class="token plain"> = </span><span class="token string" style="color:#e3116c">'KB5066835'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'KB5065789'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">foreach</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">$KB</span><span class="token plain"> in </span><span class="token variable" style="color:#36acaa">$KBs</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Write-Host</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Attempting to remove </span><span class="token string variable" style="color:#36acaa">$KB</span><span class="token string" style="color:#e3116c"> using DISM..."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Start-Process</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">FilePath </span><span class="token string" style="color:#e3116c">"dism.exe"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ArgumentList </span><span class="token string" style="color:#e3116c">"/Online /Remove-Package /PackageName:</span><span class="token string variable" style="color:#36acaa">$KB</span><span class="token string" style="color:#e3116c"> /Quiet /NoRestart"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Wait</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="use-the-pswindowsupdate-powershell-module">Use the PSWindowsUpdate PowerShell Module<a href="https://day3bits.com/2025-10-16-windows-update-kb5066835-authentication-problems/#use-the-pswindowsupdate-powershell-module" class="hash-link" aria-label="Direct link to Use the PSWindowsUpdate PowerShell Module" title="Direct link to Use the PSWindowsUpdate PowerShell Module" translate="no">​</a></h3>
<p>I used the PSWindowsUpdate PowerShell module to remove the patches:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Install-PSResource</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name PSWindowsUpdate</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Remove-WindowsUpdate</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">KBArticleID 5066835</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Remove-WindowsUpdate</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">KBArticleID 5065789</span><br></div></code></pre></div></div>
<p>After uninstalling, you will need to reboot your computer.</p>
<p>I'm sure there are many more details to spell out and more affected applications to list, but I wanted to get this post out quickly to help others that were struggling with this issue. Please add others that you know of in the comments!</p>
<p>Thank you!</p>
<p>Sam</p>]]></content:encoded>
            <category>Issue</category>
            <category>PowerShell</category>
            <category>Windows</category>
            <category>Microsoft-Teams</category>
        </item>
        <item>
            <title><![CDATA[Installing PowerShell with the .NET Tool]]></title>
            <link>https://day3bits.com/2025-07-09-installing-powershell-with-the-dotnet-tool/</link>
            <guid>https://day3bits.com/2025-07-09-installing-powershell-with-the-dotnet-tool/</guid>
            <pubDate>Wed, 09 Jul 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[The .NET Tool (dotnet) can be used to easily install the LTS or STS version of PowerShell without local admin rights, but it does have some limitations.]]></description>
            <content:encoded><![CDATA[<p>There are a surprising number of ways that you can install PowerShell on a system. Today we'll look at how to install it as a ".NET tool." <em><strong>This approach is not necessary or ideal for everyday use</strong></em>, but it does have some valid use cases and conveniently does not require local admin rights.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>A .NET tool is a special NuGet package that contains a console application. You can read more about them on <a href="https://learn.microsoft.com/en-us/dotnet/core/tools/global-tools" target="_blank" rel="noopener noreferrer" class="">Microsoft Learn</a>.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="installation">Installation<a href="https://day3bits.com/2025-07-09-installing-powershell-with-the-dotnet-tool/#installation" class="hash-link" aria-label="Direct link to Installation" title="Direct link to Installation" translate="no">​</a></h2>
<p>The first thing you will need to do is download and install the .NET (dotnet) tool from Microsoft:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Download Microsoft's dotnet tool install script to the TEMP directory.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"> = </span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$env</span><span class="token plain">:TEMP </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">'dotnet-install.ps1'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Invoke-WebRequest</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'https://dot.net/v1/dotnet-install.ps1'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">OutFile </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Remove the MOTW (mark of the web).</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Unblock-File</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Install current stable release (STS) of the dotnet tool in your profile directory.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">InstallDir </span><span class="token string" style="color:#e3116c">'~/.dotnet'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Channel </span><span class="token string" style="color:#e3116c">'STS'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Clean up the download.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Remove-Item</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Confirm:</span><span class="token boolean" style="color:#36acaa">$false</span><br></div></code></pre></div></div>
<div class="theme-admonition theme-admonition-warning admonition_xJq3 alert alert--warning"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z"></path></svg></span>warning</div><div class="admonitionContent_BuS1"><p>The .NET tool includes the latest LTS (long term support) release of .NET by default. PowerShell provides both LTS and STS (current stable) releases that are aligned with .NET's LTS and STS releases. If you want to run the latest version of PowerShell as a .NET tool, you have to ensure that the .NET tool is installed using the <code>Channel 'STS'</code> parameter.</p></div></div>
<p>Install PowerShell using the <code>dotnet</code> tool:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">dotnet tool install </span><span class="token operator" style="color:#393A34">--</span><span class="token plain">global PowerShell</span><br></div></code></pre></div></div>
<p>If you have Windows Terminal installed, you should now see a new profile for this:</p>
<p><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/Windows-Terminal-PowerShell-dotnet-global-tool-profile.png" alt="Windows Terminal with a profile added for the PowerShell .NET tool" class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="using-a-script">Using a Script<a href="https://day3bits.com/2025-07-09-installing-powershell-with-the-dotnet-tool/#using-a-script" class="hash-link" aria-label="Direct link to Using a Script" title="Direct link to Using a Script" translate="no">​</a></h2>
<p>Copy and paste if you'd like, but here's the whole thing wrapped in a script that also checks if the dotnet tool is already installed:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">Get-Command</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name </span><span class="token string" style="color:#e3116c">'dotnet'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ErrorAction SilentlyContinue</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Write-Verbose</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'dotnet is already installed.'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">else</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"> = </span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$env</span><span class="token plain">:TEMP </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">'dotnet-install.ps1'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">Invoke-WebRequest</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'https://dot.net/v1/dotnet-install.ps1'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">OutFile </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">Unblock-File</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token function" style="color:#d73a49">Write-Error</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"Failed to download dotnet-install.ps1 to '</span><span class="token string variable" style="color:#36acaa">$DownloadPath</span><span class="token string" style="color:#e3116c">'."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token variable" style="color:#36acaa">$_</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">.</span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">InstallDir </span><span class="token string" style="color:#e3116c">'~/.dotnet'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Channel </span><span class="token string" style="color:#e3116c">'STS'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token keyword" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token variable" style="color:#36acaa">$_</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">try</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    dotnet tool install </span><span class="token operator" style="color:#393A34">--</span><span class="token plain">global PowerShell</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">$env</span><span class="token plain">:PATH </span><span class="token operator" style="color:#393A34">+=</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">';'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">+</span><span class="token plain"> </span><span class="token namespace" style="opacity:0.7">[System.IO.Path]</span><span class="token plain">::Combine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">$HOME</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'.dotnet'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'tools'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">catch</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">throw</span><span class="token plain"> </span><span class="token variable" style="color:#36acaa">$_</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">if</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">Test-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Remove-Item</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Confirm:</span><span class="token boolean" style="color:#36acaa">$false</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>This script is also available on GitHub at <a href="https://github.com/SamErde/PowerShell/blob/main/General/Install-PowerShellAsDotNetTool.ps1" target="_blank" rel="noopener noreferrer" class="">SamErde/PowerShell/General/Install-PowerShellAsDotNetTool.ps1</a></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="installing-lts">Installing LTS<a href="https://day3bits.com/2025-07-09-installing-powershell-with-the-dotnet-tool/#installing-lts" class="hash-link" aria-label="Direct link to Installing LTS" title="Direct link to Installing LTS" translate="no">​</a></h2>
<p>What if your organization has a requirement that only LTS versions of software may be installed? I should (and will) update the above script with a parameter to specify LTS or STS, but for the sake of time, here are the steps.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Download Microsoft's dotnet tool install script to the TEMP directory.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"> = </span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$env</span><span class="token plain">:TEMP </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">'dotnet-install.ps1'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Invoke-WebRequest</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'https://dot.net/v1/dotnet-install.ps1'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">OutFile </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Remove the MOTW (mark of the web).</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Unblock-File</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Install the .NET Tool with support for the LTS version of .NET ('STS' is the default).</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">.</span><span class="token variable" style="color:#36acaa">$DownloadPath</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">InstallDir </span><span class="token string" style="color:#e3116c">'~/.dotnet'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Channel </span><span class="token string" style="color:#e3116c">'LTS'</span><br></div></code></pre></div></div>
<p>When installing PowerShell with the .NET (dotnet) Tool, you can specify the <code>--version 7.4.11</code> parameter, but there is no option to simply install the LTS version. Let's find a way to get the latest LTS release of PowerShell:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$LTSVersion</span><span class="token plain"> = </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">Invoke-RestMethod</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Uri https:</span><span class="token operator" style="color:#393A34">/</span><span class="token operator" style="color:#393A34">/</span><span class="token plain">aka</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ms/pwsh-buildinfo-lts</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">ReleaseTag</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Replace</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'v'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">''</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">dotnet tool install </span><span class="token operator" style="color:#393A34">--</span><span class="token plain">global PowerShell </span><span class="token operator" style="color:#393A34">--</span><span class="token plain">version </span><span class="token variable" style="color:#36acaa">$LTSVersion</span><br></div></code></pre></div></div>
<p>As a alternative, we can also get the LTS version number from the <code>metadata.json</code> file in the PowerShell repository: <code>(Invoke-RestMethod -Uri 'https://raw.githubusercontent.com/PowerShell/PowerShell/master/tools/metadata.json').LTSReleaseTag.Replace('v','')</code>.</p>
<p>Both of these two URIs that I queried provide some details about PowerShell releases, as you can see in this screenshot:
<img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/PowerShell-LTS-Version-Release-Commands.png" alt="PowerShell in Windows Terminal showing the output of Invoke-RestMethod getting two PowerShell release info URIs. " class="img_ev3q"></p>
<p>You should now have a fresh installation of PowerShell as a .NET tool on either the LTS or STS release.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>This setup is completely independent of any versions of .NET and PowerShell that you already have installed on your system from an MSI, WinGet, or the Microsoft Store.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="limitations">Limitations<a href="https://day3bits.com/2025-07-09-installing-powershell-with-the-dotnet-tool/#limitations" class="hash-link" aria-label="Direct link to Limitations" title="Direct link to Limitations" translate="no">​</a></h2>
<p>PowerShell as a .NET tool is easy to setup, but it does have some limitations.</p>
<ul>
<li class="">Updates must be managed via <code>dotnet tool update</code> instead of WinGet, Windows Updates, or the Microsoft Store.</li>
<li class="">PowerShell remoting and WinRM might be unreliable or unsupported.</li>
<li class="">Base PowerShell modules may not be available or may have reduced functionality due to missing dependencies.</li>
<li class="">Modules such as <strong>Microsoft.Graph</strong> may fail due to dependencies on the full PowerShell host.</li>
<li class="">GUI-based modules that rely on Windows Forms or WPF won't work.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="closing-thoughts">Closing Thoughts<a href="https://day3bits.com/2025-07-09-installing-powershell-with-the-dotnet-tool/#closing-thoughts" class="hash-link" aria-label="Direct link to Closing Thoughts" title="Direct link to Closing Thoughts" translate="no">​</a></h2>
<p>Despite these limitations, this can be a useful tool for development and testing, or when you need a lightweight installation option that doesn't require local admin rights.</p>]]></content:encoded>
            <category>PowerShell</category>
            <category>.NET</category>
        </item>
        <item>
            <title><![CDATA[Using the Microsoft Artifact Registry (MAR) with PowerShell]]></title>
            <link>https://day3bits.com/2025-06-20-using-mar-as-a-secure-repository/</link>
            <guid>https://day3bits.com/2025-06-20-using-mar-as-a-secure-repository/</guid>
            <pubDate>Fri, 20 Jun 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[A trusted and secure source for PowerShell modules, packages, and other application components.]]></description>
            <content:encoded><![CDATA[<p>The PowerShell Gallery has long been the "official" public source for PowerShell modules. It is convenient, but some organizations require more strictly vetted and approved software repositories for their environments. This can be achieved by <a href="https://learn.microsoft.com/powershell/gallery/how-to/working-with-local-psrepositories?view=powershellget-3.x&amp;WT.mc_id=MVP_449935" target="_blank" rel="noopener noreferrer" class="">maintaining a private repository</a> in Azure DevOps, a NuGet-based web server, or even a file share with approved modules hosted in it. With thanks likely given to the <a href="https://www.microsoft.com/en-us/trust-center/security/secure-future-initiative?msockid=0fb2870f6432600e325592a465d6612b&amp;WT.mc_id=MVP_449935" target="_blank" rel="noopener noreferrer" class="">Secure Future Initiative</a>, those organizations now have an option called the <a href="https://mcr.microsoft.com/en-us/?WT.mc_id=MVP_449935" target="_blank" rel="noopener noreferrer" class="">Microsoft Artifact Registry (MAR)</a>.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-is-the-microsoft-artifact-registry-mar">What is the Microsoft Artifact Registry (MAR)?<a href="https://day3bits.com/2025-06-20-using-mar-as-a-secure-repository/#what-is-the-microsoft-artifact-registry-mar" class="hash-link" aria-label="Direct link to What is the Microsoft Artifact Registry (MAR)?" title="Direct link to What is the Microsoft Artifact Registry (MAR)?" translate="no">​</a></h2>
<blockquote>
<p>MAR is a public registry for housing Microsoft's official artifacts, such as container images. MAR enhances security by ensuring only Microsoft can publish official packages, eliminating risks like name squatting. It also improves software supply chain integrity by offering greater transparency and control over artifact provenance.</p>
</blockquote>
<p>Far from being just a PowerShell module repository, MAR is a container registry that provides application frameworks, CI/CD runners, container images, SDKs, and more. At this time, the only PowerShell modules that I have found in it so far are the Az module and its myriad of sub-modules.</p>
<p><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/Microsoft-Artifact-Registry.png" alt="A screen shot of the Microsoft Artifact Registry, with a view filtered to show the DevOps and Programming Languages categories." class="img_ev3q"></p>
<p>Microsoft do have plans to publish more PowerShell modules to the MAR. We do not know how soon the different product teams will publish their modules to it, but they will first have to update their release pipeline to do so. For now, here's what you need to know:</p>
<p>Support for MAR was added to the <strong>Microsoft.PowerShell.PSResourceGet v1.1.1</strong> release on 2025/03/07. You may need to update if you have not already.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>PowerShell 7.6-preview.4 includes <strong>Microsoft.PowerShell.PSResourceGet v1.1.1</strong>, so we can expect that version to be included when 7.6 becomes generally available.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="getting-started-with-the-microsoft-artifact-registry">Getting Started with the Microsoft Artifact Registry<a href="https://day3bits.com/2025-06-20-using-mar-as-a-secure-repository/#getting-started-with-the-microsoft-artifact-registry" class="hash-link" aria-label="Direct link to Getting Started with the Microsoft Artifact Registry" title="Direct link to Getting Started with the Microsoft Artifact Registry" translate="no">​</a></h2>
<p>Here's how you can start using it:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$MARUrl</span><span class="token plain"> = </span><span class="token string" style="color:#e3116c">'https://mcr.microsoft.com'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Register-PSResourceRepository</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name MAR </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Uri </span><span class="token variable" style="color:#36acaa">$MARUrl</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ApiVersion ContainerRegistry </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Trusted:</span><span class="token boolean" style="color:#36acaa">$true</span><br></div></code></pre></div></div>
<p>Now you can even set the MAR to have a higher priority than the PSGallery by running <code>Set-PSResourceRepository -Name MAR -Priority 10</code> (or any number lower than the current priority of the PSGallery).</p>
<p>You can confirm that this worked by running <code>Get-PSResourceRepository</code>.</p>
<p><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/MAR-Repository-Setup.png" alt="A screen shot of the Windows Terminal running the above commands." class="img_ev3q"></p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="limitations">Limitations<a href="https://day3bits.com/2025-06-20-using-mar-as-a-secure-repository/#limitations" class="hash-link" aria-label="Direct link to Limitations" title="Direct link to Limitations" translate="no">​</a></h2>
<p>The <strong>Microsoft.PowerShell.PSResourceGet</strong> module does have some limitations when working with the MAR and other Microsoft container registries. It does <em>not</em> support the following search functionality that you <em>can</em> use with the PowerShell Gallery:</p>
<ul>
<li class="">
<p>Find by tag value
<code>Find-PSResource -Tag TagValue -Repository ACRDemoRepo</code></p>
</li>
<li class="">
<p>Find by command
<code>Find-PSResource -Command CommandName -Repository ACRDemoRepo</code></p>
</li>
<li class="">
<p>Find by DSC resource name
<code>Find-PSResource -DscResourceName ResourceName -Repository ACRDemoRepo</code></p>
</li>
<li class="">
<p>I did not expect wildcard searches to work, but surprisingly, this approach does work sometimes:
<code>Find-PSResource -Repository MAR -Type Module -Name "Az*"</code></p>
</li>
</ul>
<p>Let's install a couple of modules as a test. If you have followed along and changed the priority of the MAR, the <code>Install-PSResource</code> command will try the MAR first.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Install-PSResource</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name Az</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">CognitiveServices </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Scope CurrentUser</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Install-PSResource</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name Az</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Automation </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Scope CurrentUser </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Repository PSGallery</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/MAR-Modules-Installed.png" alt="The output of running Get-InstalledPSResource -Name Az.*." class="img_ev3q"></p>
<p>You can see here that it installed the <strong>Az.CognitiveServices</strong> module <em>and its dependency</em> (<strong>Az.Accounts</strong>) from the MAR automatically. The <strong>Az.Automation</strong> module was installed from the PSGallery because that source was specified in my command.</p>
<p>That's it for now! For more information, check the official documentation on <a href="https://learn.microsoft.com/powershell/gallery/powershellget/supported-repositories?view=powershellget-3.x&amp;WT.mc_id=MVP_449935#azure-container-registry" target="_blank" rel="noopener noreferrer" class="">Microsoft Learn</a>.</p>
<p>Thanks to Sean Wheeler for the tip and the great documentation, as always!</p>
<p>Have a great day! ☀️🙏</p>]]></content:encoded>
            <category>PowerShell</category>
            <category>Scripting</category>
        </item>
        <item>
            <title><![CDATA[Using Obsolete Parameters in PowerShell]]></title>
            <link>https://day3bits.com/2025-02-17-using-obsolete-parameters-in-powershell/</link>
            <guid>https://day3bits.com/2025-02-17-using-obsolete-parameters-in-powershell/</guid>
            <pubDate>Mon, 17 Feb 2025 00:00:00 GMT</pubDate>
            <description><![CDATA[How to deprecate a parameter in your PowerShell functions without breaking existing scripts.]]></description>
            <content:encoded><![CDATA[<p>When you maintain PowerShell code for long enough, you may eventually want to stop using one of your original parameters in a function. It may have been used to provide a switch that is no longer needed or an input that is no longer supported. However, you do not want to completely remove that parameter and risk breaking scripts that rely on it. Instead, you can begin deprecating that parameter and mark it as obsolete. The <strong>System.Obsolete</strong> attribute is used to do this.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">param</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">System</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Obsolete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"'Mode' is being replaced by a more flexible set of parameters. It will be removed in a future release. Please use 'Get-Help Test-Obsolete' or visit &lt;https://day3bits.com/2025-02-17-using-obsolete-parameters-in-powershell/&gt; for more information."</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token namespace" style="opacity:0.7">[int16]</span><span class="token variable" style="color:#36acaa">$Mode</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>When this parameter is used in a function, the user is warned that it is obsolete, but it will still continue to work.</p>
<p>Here is a full example of the <strong>Obsolete</strong> attribute in use:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Test-Obsolete</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">param</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token comment" style="color:#999988;font-style:italic"># Test mode parameter.</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token namespace" style="opacity:0.7">[Parameter(Mandatory)]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">Obsolete</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"'Mode' is being replaced by a more flexible set of parameters. It will be removed in a future release.`n`nPlease use 'Get-Help Test-Obsolete' or visit &lt;https://day3bits.com/2025-02-17-using-obsolete-parameters-in-powershell/&gt; for more information."</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token namespace" style="opacity:0.7">[ValidateNotNullOrEmpty()]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token namespace" style="opacity:0.7">[ValidateRange(0, 5)]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token namespace" style="opacity:0.7">[int16]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        </span><span class="token variable" style="color:#36acaa">$Mode</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token function" style="color:#d73a49">Write-Output</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">"You chose mode ${Mode}."</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic"># end function Test-Obsolete</span><br></div></code></pre></div></div>
<p>The output of this function will look like this:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">PS C:\Code&gt; Test-Obsolete -Mode 3</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">WARNING: Parameter 'Mode' is obsolete. 'Mode' is being replaced by a more flexible set of parameters. It will be removed in a future release.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Please use 'Get-Help Test-Obsolete -Full' or visit &lt;https://day3bits.com/2025-02-17-using-obsolete-parameters-in-powershell/&gt; for more information.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">You chose mode 3.</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">PS C:\Code&gt;</span><br></div></code></pre></div></div>
<p>You can download this sample function (<a href="https://github.com/SamErde/PowerShell/blob/main/Snippets/Test-Obsolete.ps1" target="_blank" rel="noopener noreferrer" class="">Test-Obsolete.ps1</a>) and a few hundred others from my <a href="https://github.com/SamErde/PowerShell" target="_blank" rel="noopener noreferrer" class="">PowerShell repository</a>.</p>
<p>This is just one of those little things you can do to improve the experience for people who use your code. Take advantage of it to make your PowerShell code 1% better every day!</p>
<p>Have a great day! ☀️🙏</p>]]></content:encoded>
            <category>PowerShell</category>
            <category>Scripting</category>
        </item>
        <item>
            <title><![CDATA[Creating an IT Systems Management User Group for Charlotte]]></title>
            <link>https://day3bits.com/2024-12-30-creating-an-it-systems-management-user-group-for-charlotte/</link>
            <guid>https://day3bits.com/2024-12-30-creating-an-it-systems-management-user-group-for-charlotte/</guid>
            <pubDate>Mon, 30 Dec 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[I am looking for colleagues who share this vision for a new tech community in CLT that focuses on cybersecurity, Microsoft 365, on-premises and cloud infrastructure, PowerShell, and personal growth!]]></description>
            <content:encoded><![CDATA[<p>As IT professionals, we thrive on learning new things, tackling challenges, and growing our skills. While this is work inherently satisfying, we can only find real meaning in our work when we understand why we do it, when we are able to contribute value to the community, and when we take care of ourselves. These ideas drive my passion to keep growing and to connect with others who feel the same. Plus, as you may have guessed, I love geeking out about PowerShell, Microsoft 365, Windows Server, and securing all the things!</p>
<p>Since moving to the Charlotte area, I've been searching for an active user group focused on these interests. I haven't found one yet, so why not start one? Building a community takes a community, which is why I'm sharing this request:</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p><strong>Will you help me organize and get a Charlotte Systems Management User Group running?</strong> 🙏</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="vision">Vision<a href="https://day3bits.com/2024-12-30-creating-an-it-systems-management-user-group-for-charlotte/#vision" class="hash-link" aria-label="Direct link to Vision" title="Direct link to Vision" translate="no">​</a></h2>
<p>To get things started, here is the initial vision that I would love your feedback on:</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p><strong>The core purpose of the Charlotte Systems Management User Group is to foster growth and connection as an IT community.</strong> The primary technical focus areas are automation, cybersecurity, hybrid cloud, infrastructure, PowerShell, and the Microsoft 365 ecosystem (but is not exclusively limited to these). Other core topics that are fundamental to the identity of this community are career development, soft skills, mental health and wellness, and family.</p></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="who-is-this-group-for">Who is this group for?<a href="https://day3bits.com/2024-12-30-creating-an-it-systems-management-user-group-for-charlotte/#who-is-this-group-for" class="hash-link" aria-label="Direct link to Who is this group for?" title="Direct link to Who is this group for?" translate="no">​</a></h2>
<ul>
<li class="">Support Specialists / Technicians</li>
<li class="">Systems / Network Administrators</li>
<li class="">Systems / Network / Infrastructure Engineers</li>
<li class="">Solutions Analysts</li>
<li class="">Solutions Architects</li>
<li class="">Leaders of any of the above</li>
<li class="">People aspiring to be any of the above</li>
</ul>
<p>There are no superstars here. We're all at different points on our journey, all experiencing a different phase of life. Everyone has something to contribute and things to learn!</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-topics-could-we-discuss">What topics could we discuss?<a href="https://day3bits.com/2024-12-30-creating-an-it-systems-management-user-group-for-charlotte/#what-topics-could-we-discuss" class="hash-link" aria-label="Direct link to What topics could we discuss?" title="Direct link to What topics could we discuss?" translate="no">​</a></h2>
<p>I have my favorites, but any of the following could be great topics to discuss!</p>















































<table><thead><tr><th>hybrid infrastructure</th><th>identity &amp; security</th><th>operations &amp; productivity</th><th>personal development</th></tr></thead><tbody><tr><td>Azure</td><td>Active Directory</td><td>Microsoft 365</td><td>career growth</td></tr><tr><td>virtualization</td><td>Microsoft Entra</td><td>PowerShell</td><td>leading</td></tr><tr><td>datacenter management</td><td>Microsoft Defender XDR</td><td>Ansible</td><td>speaking</td></tr><tr><td>storage</td><td>PKI</td><td>automation</td><td>writing</td></tr><tr><td>networking</td><td>configuration management</td><td>GitOps / DevOps</td><td>personal interests</td></tr><tr><td>Terraform</td><td>Intune / GPO / SCCM</td><td>GitHub / Azure DevOps</td><td>networking</td></tr></tbody></table>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="sounds-good">Sounds Good!<a href="https://day3bits.com/2024-12-30-creating-an-it-systems-management-user-group-for-charlotte/#sounds-good" class="hash-link" aria-label="Direct link to Sounds Good!" title="Direct link to Sounds Good!" translate="no">​</a></h2>
<p>Are you interested in joining or helping? I would love to continue the conversation! Please take two minutes to let me know <a href="https://forms.office.com/r/zYrH0QFAbv" target="_blank" rel="noopener noreferrer" class="">here</a>.</p>
<p><a href="https://forms.office.com/r/zYrH0QFAbv" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/QRCode-for-Charlotte-Systems-Management-User-Group-Interest-Form.png" alt="QRCode for Charlotte Systems Management User Group Interest Form" class="img_ev3q"></a></p>
<p>Cheers!</p>
<p>Sam</p>
<hr>
<p>Photo by <a href="https://unsplash.com/@anniespratt?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer" class="">Annie Spratt</a> on <a href="https://unsplash.com/photos/group-of-people-using-laptop-computer-QckxruozjRg?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer" class="">Unsplash</a></p>]]></content:encoded>
            <category>User Group</category>
            <category>Community</category>
        </item>
        <item>
            <title><![CDATA[Revisiting Join-Path in PowerShell]]></title>
            <link>https://day3bits.com/2024-12-09-Revisiting-Join-Path-in-PowerShell/</link>
            <guid>https://day3bits.com/2024-12-09-Revisiting-Join-Path-in-PowerShell/</guid>
            <pubDate>Mon, 09 Dec 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Tips for using Join-Path in backwards-compatible and cross-platform PowerShell scripts.]]></description>
            <content:encoded><![CDATA[<p>Many people have already written about the benefits of using PowerShell's <code>Join-Path</code> cmdlet. Instead of repeating the details, let's review some of the less common tricks, and then look at the differences between Windows PowerShell 5.1 and newer versions of PowerShell.</p>
<p>The syntax in Windows PowerShell is pretty basic. You can provide a parent path and a child path.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> &lt;String</span><span class="token punctuation" style="color:#393A34">[</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain">&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"> &lt;String&gt;</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Resolve</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Credential &lt;PSCredential&gt;</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token operator" style="color:#393A34">-</span><span class="token plain">UseTransaction</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">&lt;CommonParameters&gt;</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<p>You may not have realized that it supports wildcards in the parent and child paths, and can return an array of strings that represent paths.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token string" style="color:#e3116c">"</span><span class="token string variable" style="color:#36acaa">$Home</span><span class="token string" style="color:#e3116c">\AppData\Local*"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">"Microsoft*"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Resolve</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/Join-Path-Wildcards.png" alt="A screen shot of PowerShell in Windows Terminal running the command 'Join-Path -Path &quot;$Home\AppData\Local*&quot; -ChildPath &quot;Microsoft*&quot; -Resolve'." class="img_ev3q"></p>
<p>It can also accept multiple parent paths and return multiple resolved paths:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path C:\</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> C:\Windows</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token variable" style="color:#36acaa">$env</span><span class="token plain">:LOCALAPPDATA </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">"Temp"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Resolve</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/Join-Path-Multiple-Parents.png" alt="A screen shot of PowerShell in Windows Terminal running an example of Join-Path with multiple parent paths." class="img_ev3q"></p>
<p>The difference between Windows PowerShell and PowerShell becomes apparent when you want to join more than one child path. PowerShell added the <strong>AdditionalPath</strong> parameter, which allows you to add virtually unlimited child paths like this:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Join multiple child paths in PowerShell</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$HOME</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">"Documents"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">AdditionalChildPath </span><span class="token string" style="color:#e3116c">'PowerShell'</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Join multiple child paths with an array of additional child paths</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token namespace" style="opacity:0.7">[string[]]</span><span class="token variable" style="color:#36acaa">$AdditionalChildPaths</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Personal'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'PSPreworkout'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'src'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'PSPreworkout'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Public'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path C:\ </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">'Code'</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">AdditionalChildPath </span><span class="token variable" style="color:#36acaa">$AdditionalChildPaths</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Or even the very ugly but still functional:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> \ a b c d e f g h 1 2 3 4 5 6</span><br></div></code></pre></div></div>
<p>Since Windows PowerShell doesn't have the <strong>AdditionalPath</strong> parameter, how can we do this on older systems? There are a few ways to expand its functionality:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Join multiple child paths in Windows PowerShell (or PowerShell) by piping to the next Join-Path:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$HOME</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">"Documents"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">"PowerShell"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">"Modules"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Or, even worse: join multiple child paths in Windows PowerShell (or PowerShell) by nesting commands:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token variable" style="color:#36acaa">$HOME</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">"Documents"</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token punctuation" style="color:#393A34">(</span><span class="token function" style="color:#d73a49">Join-Path</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Path </span><span class="token string" style="color:#e3116c">"PowerShell"</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ChildPath </span><span class="token string" style="color:#e3116c">"Modules"</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p>I like to dig into things like this when writing scripts that should be able to work cross-platform and on both editions of PowerShell. The last two examples shown above do work on Windows PowerShell 5.1, but can get hard to follow once you go more than two paths deep.</p>
<p>You might notice an emerging theme when we look into one more option that works on PowerShell, Windows PowerShell, and across platforms: .NET again! The <strong>System.IO.Path</strong> type's <code>Combine</code> method takes a list of path segments and joins them easily.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Join multiple child paths in any version of PowerShell on Linux, macOS, or Windows</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token namespace" style="opacity:0.7">[System.IO.Path]</span><span class="token plain">::Combine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">$HOME</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Documents"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"PowerShell"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Modules"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># The same as above, but with a variable</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token namespace" style="opacity:0.7">[string[]]</span><span class="token variable" style="color:#36acaa">$Segments</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">$HOME</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Documents"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"PowerShell"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Modules"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token namespace" style="opacity:0.7">[System.IO.Path]</span><span class="token plain">::Combine</span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">$Segments</span><span class="token punctuation" style="color:#393A34">)</span><br></div></code></pre></div></div>
<p><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/content/Path-Combine.png" alt="A screen shot of Windows Terminal running the following command in Ubuntu (WSL): '[System.IO.Path]::Combine($HOME,&quot;Documents&quot;,&quot;PowerShell&quot;,&quot;Modules&quot;)'." class="img_ev3q"></p>
<p>That looks like a nice, clean option that runs almost anywhere and is easy to read!</p>
<p>Photo by <a href="https://unsplash.com/@madebyjens?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer" class="">Jens Lelie</a> on <a href="https://unsplash.com/photos/two-roads-between-trees-u0vgcIOQG08?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer" class="">Unsplash</a></p>]]></content:encoded>
            <category>PowerShell</category>
            <category>Scripting</category>
            <category>.NET</category>
        </item>
        <item>
            <title><![CDATA[How to Get Active Directory Trust Details in PowerShell]]></title>
            <link>https://day3bits.com/2024-11-20-how-to-get-active-directory-trust-details-in-powershell/</link>
            <guid>https://day3bits.com/2024-11-20-how-to-get-active-directory-trust-details-in-powershell/</guid>
            <pubDate>Wed, 20 Nov 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[In which .NET inspires an answer to a question I had for years.]]></description>
            <content:encoded><![CDATA[<p>Through most of the past 20 years of working with Active Directory, I have supported and worked in multi-forest environments. This work has involved one forest being split into 3 forests, a cross-forest migration of Exchange Server (I was spared the first one), and multiple forest consolidation projects. At various points throughout that timeline, I have needed to write PowerShell scripts that rely on either the DNS name, NetBIOS name, or SID of domains in the trust relationship. This information is easy to get using the ActiveDirectory module's <code>Get-ADTrust</code> cmdlet.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Get-ADTrust</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">Filter</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">&lt;# Example Output:</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    Direction               : BiDirectional</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    DisallowTransivity      : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    DistinguishedName       : CN=example.com,CN=System,DC=domain,DC=com</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    ForestTransitive        : True</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    IntraForest             : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    IsTreeParent            : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    IsTreeRoot              : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    Name                    : example.com</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    ObjectClass             : trustedDomain</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    ObjectGUID              : 00000000-0000-0000-0000-000000000000</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    SelectiveAuthentication : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    SIDFilteringForestAware : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    SIDFilteringQuarantined : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    Source                  : DC=domain,DC=com</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    Target                  : example.com</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    TGTDelegation           : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    TrustAttributes         : 8</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    TrustedPolicy           :</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    TrustingPolicy          :</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    TrustType               : Uplevel</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    UplevelOnly             : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    UsesAESKeys             : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    UsesRC4Encryption       : False</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">#&gt;</span><br></div></code></pre></div></div>
<p>Now for the embarrassing part of this post: for a painfully long time, I thought the target domain's NetBIOS name and domain SID were not returned by the <code>Get-ADTrust</code> cmdlet. 🤦‍♂️</p>
<p>Guess what, Past Sam Erde? It is there. You just need to look closer. 🕵️‍♂️</p>
<p>This cmdlet can return the <strong>flatName</strong> property, which <em>is</em> the target domain's NetBIOS name, and <strong>securityIdentifier</strong>, which is the target domain's SID. All you needs is <code>Get-ADTrust -Filter * -Properties flatName,securityIdentifier</code>. To remind myself, let's display the results in a pretty table with labels that make sense:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Get-ADTrust</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token keyword" style="color:#00009f">Filter</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Properties Source</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Target</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">flatName</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">securityIdentifier </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Format-Table</span><span class="token plain"> Source</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Target</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> @</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">Name = </span><span class="token string" style="color:#e3116c">"NetBIOSName"</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> Expression = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token variable" style="color:#36acaa">$_</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">flatName</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> @</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain">Name = </span><span class="token string" style="color:#e3116c">'DomainSID'</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> Expression = </span><span class="token punctuation" style="color:#393A34">{</span><span class="token variable" style="color:#36acaa">$_</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">securityIdentifier</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">AutoSize</span><br></div></code></pre></div></div>
<p>Cool! Now then--what I <em>was</em> going to write about was 'a really cool solution to get this "missing" information using a .NET type.' The original premise of my post was wrong, but let's still talk about that option. Using a .NET type instead of the <strong>Get-ADTrust</strong> cmdlet is going to be very useful when the ActiveDirectory PowerShell module is not available and you cannot install it. It can also be more efficient to use, especially when pulling invalid trusts. For example, <code>Get-ADTrust</code> is a bit slower and waits for a timeout or error when it cannot validate the target domain. You probably won't notice the difference in most cases, though. Let's just look at the code!</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$Forest</span><span class="token plain"> = </span><span class="token namespace" style="opacity:0.7">[System.DirectoryServices.ActiveDirectory.Forest]</span><span class="token plain">::GetCurrentForest</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$TrustRelationships</span><span class="token plain"> = </span><span class="token variable" style="color:#36acaa">$Forest</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">GetAllTrustRelationships</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$TrustRelationships</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">TrustedDomainInformation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">&lt;# Example Output:</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"></span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    DnsName         NetBiosName     DomainSid                                Status</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    -------         -----------     ---------                                ------</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">    example.com     EXAMPLE         S-1-5-21-000000000-1234567890-1234567890 Enabled</span><br></div><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">#&gt;</span><br></div></code></pre></div></div>
<p>I honestly like this approach better!</p>
<p>If one-liners are your thing, we can do that as well: <code>[System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().GetAllTrustRelationships().TrustedDomainInformation</code>.</p>
<p>By using the <code>System.DirectoryServices.ActiveDirectory.Forest</code> type from .NET, we can directly interact with Active Directory objects and retrieve trust details without relying on the ActiveDirectory PowerShell module.</p>
<p>What do you think? Have you already moved your Active Directory scripts away from depending on the ActiveDirectory module? Let me know!</p>]]></content:encoded>
            <category>Active Directory</category>
            <category>PowerShell</category>
            <category>.NET</category>
        </item>
        <item>
            <title><![CDATA[The Benefits of Removing the Az and Microsoft.Graph PowerShell Modules]]></title>
            <link>https://day3bits.com/2024-09-05-benefits-of-removing-the-az-and-microsoft-graph-powershell-modules/</link>
            <guid>https://day3bits.com/2024-09-05-benefits-of-removing-the-az-and-microsoft-graph-powershell-modules/</guid>
            <pubDate>Thu, 05 Sep 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[Save time and simplify your workspace by removing all unused PowerShell modules.]]></description>
            <content:encoded><![CDATA[<p>The Microsoft Graph SDK v2.23.0 was released today, and with it, the updated Microsoft Graph PowerShell module. You can use <code>Update-Module</code> or <code>Update-PSResource</code> to update this module, or you can try out my new <a href="https://day3bits.com/PSPreworkout" target="_blank" rel="noopener noreferrer" class="">PSPReworkout</a> module's <code>Update-AllTheThings</code> function.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><blockquote>
<p><code>Update-AllTheThings</code> was built to update all installed PowerShell modules and scripts, PowerShell help, WinGet packages, and Chocolatey packages in one shot. (It also has the beginnings of very basic support for Linux and macOS packages.) Please try it out and share your feedback to help it improve!</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Install-Module</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name PSPreworkout</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Import-Module</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name PSPreworkout</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Update-AllTheThings</span><br></div></code></pre></div></div>
</blockquote></div></div>
<p>Regardless of how you update, you may find that it takes a terribly long time to update these modules. Minutes, even!!! 😱 Many people have probably followed the same steps that I did to get here, and many of us have wasted hours while waiting for the <code>Update-Module</code> and <code>Update-Help</code> commands to finish.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># We installed ALL OF THE THINGS 🧹🤪</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Install-Module</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name Az</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token function" style="color:#d73a49">Install-Module</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name Microsoft</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Graph</span><br></div></code></pre></div></div>
<p>When we use these commands, we don't just install one module or two modules. As of this writing:</p>
<ul>
<li class="">The <a href="https://github.com/Azure/azure-powershell/blob/main/documentation/azure-powershell-modules.md" target="_blank" rel="noopener noreferrer" class="">Az module</a> includes 171 service submodules.</li>
<li class="">The <a href="https://github.com/microsoftgraph/msgraph-sdk-powershell/wiki/MS-Graph-PowerShell-Modules" target="_blank" rel="noopener noreferrer" class="">Microsoft.Graph PowerShell module</a> includes 38 service submodules.</li>
</ul>
<p>We just installed 211 modules on our system, and many of us will only ever use 10-20 of them! This is where my click-baity title comes in. 😜</p>
<p>My advice to you now is to review the modules installed on your system and uninstall any that you do not use. Start with <code>Get-InstalledModule</code> to view a list of all modules that you have installed.</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><blockquote>
<p>Using <code>Get-InstalledModule</code> instead of <code>Get-Module -ShowAvailable</code> will help filter out the modules that come pre-installed with your OS. Don't waste more time by trying to manually filter through that list.</p>
</blockquote></div></div>
<p>If you need to remove modules that were installed for the AllUsers scope, then you will need to begin this process with an elevated PowerShell session.</p>
<p>If your list is very long, and possibly includes multiple versions of each, manually removing the unused ones could be a very tedious process. Here's a quick way to clean the slate before only installing the ones that you will actually use:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$AzGraphModules</span><span class="token plain"> = </span><span class="token function" style="color:#d73a49">Get-InstalledModule</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name Az</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Az</span><span class="token punctuation" style="color:#393A34">.</span><span class="token operator" style="color:#393A34">*</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Microsoft</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Graph</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain">Microsoft</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Graph</span><span class="token punctuation" style="color:#393A34">.</span><span class="token operator" style="color:#393A34">*</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ErrorAction SilentlyContinue</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">foreach</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">$module</span><span class="token plain"> in </span><span class="token variable" style="color:#36acaa">$AzGraphModules</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Uninstall-Module</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name </span><span class="token variable" style="color:#36acaa">$module</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">Name </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">AllVersions </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Force </span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>This may take a few minutes to run. After completing, you should see a much shorter list when running <code>Get-InstalledModule</code>. At this point, you can re-install only the modules that you will likely need, and expand the list as your needs grow. I would suggest starting with the following ones:</p>
<ul>
<li class="">Az.Accounts</li>
<li class="">Az.Resources</li>
<li class="">Az.Tools.Predictor</li>
<li class="">Microsoft.Graph.Applications</li>
<li class="">Microsoft.Graph.Authentication</li>
<li class="">Microsoft.Graph.Groups</li>
<li class="">Microsoft.Graph.Users</li>
<li class="">Microsoft.Graph.Identity.DirectoryManagement</li>
<li class="">Microsoft.Graph.Identity.SignIns</li>
</ul>
<p>Whether you install this list, or others, installing them in batch is fairly straightforward with an array:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$ModulesToInstall</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">'Az.Accounts'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Az.Resources'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Az.Tools,Predictor'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Microsoft.Graph.Applications'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Microsoft.Graph.Authentication'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Microsoft.Graph.Groups'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Microsoft.Graph.Users'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Microsoft.Graph.Identity.DirectoryManagement'</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">'Microsoft.Graph.Identity.SignIns'</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">foreach</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">(</span><span class="token variable" style="color:#36acaa">$module</span><span class="token plain"> in </span><span class="token variable" style="color:#36acaa">$ModulesToInstall</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Install-Module</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Name </span><span class="token variable" style="color:#36acaa">$module</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Scope CurrentUser </span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Check your results with <code>Get-InstalledModule</code>. (What other modules do you have installed? Let me know!) You can now reap the benefits of having fewer PowerShell modules installed:</p>
<ul>
<li class=""><strong>Faster Auto-Import and Tab-Completion:</strong> With fewer modules, PowerShell has fewer cmdlets and functions to load and index, which can speed up the auto-import process and make tab-completion more responsive.</li>
<li class=""><strong>Reduced Memory Usage:</strong> Each module loaded into a PowerShell session consumes memory. By removing unused modules, you can reduce the overall memory footprint of your PowerShell environment.</li>
<li class=""><strong>Avoiding Conflicts:</strong> Having many modules installed can sometimes lead to cmdlet name conflicts, where multiple modules define cmdlets with the same name. Reducing the number of installed modules can help avoid these conflicts.</li>
<li class=""><strong>Improved Security:</strong> Unused modules might not be regularly updated, potentially leaving security vulnerabilities unpatched. Removing them reduces the attack surface and helps maintain a more secure environment.</li>
<li class=""><strong>Simplified Management:</strong> Fewer modules mean less complexity in managing updates and dependencies, making it easier to keep your environment up to date and stable.</li>
</ul>
<p>Try it out and let me know if you notice the difference!</p>]]></content:encoded>
            <category>PowerShell</category>
            <category>Scripting</category>
            <category>Azure</category>
            <category>Microsoft Graph</category>
        </item>
        <item>
            <title><![CDATA[Services Included with Microsoft 365 E5 Developer Subscriptions]]></title>
            <link>https://day3bits.com/2024-03-21-services-included-in-microsoft-365-e5-developer-plan/</link>
            <guid>https://day3bits.com/2024-03-21-services-included-in-microsoft-365-e5-developer-plan/</guid>
            <pubDate>Thu, 21 Mar 2024 00:00:00 GMT</pubDate>
            <description><![CDATA[What is currently included when you sign up for a Microsoft 365 E5 developer subscription?]]></description>
            <content:encoded><![CDATA[<p>Welcome back! Here's a quick hit that falls into the "make notes and share them" category.</p>
<p>During the first quarter of 2024, Microsoft <a href="https://devblogs.microsoft.com/microsoft365dev/stay-ahead-of-the-game-with-the-latest-updates-to-the-microsoft-365-developer-program/" target="_blank" rel="noopener noreferrer" class="">announced some unfortunate changes to the developer program</a>. There have been many posts about how far fewer people will have access to this amazing learning and developing resource. I won't dive into that again in this post. For now, I wanted to create an easy reference for one other question that often comes up: "if it's E5, but not all services are actually included, which ones <em>are</em>?" (Spoiler: Microsoft Defender for Endpoint is still excluded.) The announcement states:</p>
<blockquote>
<p><strong>Updated service plans</strong>. The Microsoft 365 developer subscription now includes service plans that were previously missing. For a complete list of the service plans that are included, see <a href="https://learn.microsoft.com/en-us/entra/identity/users/licensing-service-plan-reference?source=devblogs" target="_blank" rel="noopener noreferrer" class="">Product names and service plan identifiers for licensing</a>.</p>
</blockquote>
<p>If you've ever visited that page, you know how hard it is to read! This seems like a great opportunity for a GitHub action to scrape and remodel the table. For now, here's a quick copy/paste of the friendly names for all service plans included with the DEVELOPERPACK_E5 SKU.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Avatars for Teams</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Avatars for Teams (additional)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Azure Information Protection Premium P1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Azure Information Protection Premium P2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Azure Rights Management</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Commercial data protection for Microsoft Copilot</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Common Data Service</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Common Data Service for Teams</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Customer Lockbox</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Customer Lockbox (A)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Data Classification in Microsoft 365</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Exchange Online (Plan 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Graph Connectors Search with Index</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Information Protection and Governance Analytics - Premium</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Information Protection for Office 365 - Premium</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Information Protection for Office 365 - Standard</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft 365 Advanced Auditing</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft 365 Apps for enterprise</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft 365 Audit Platform</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft 365 Communication Compliance</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft 365 Defender</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft 365 Lighthouse (Plan 1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft 365 Phone System</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Azure Multi-Factor Authentication</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Bookings</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Clipchamp</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Communications DLP</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Customer Key</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Data Investigations</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Defender for Cloud Apps</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Defender for Identity</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Defender for Office 365 (Plan 1)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Defender for Office 365 (Plan 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Entra ID P1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Entra ID P2</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Excel Advanced Analytics</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Forms [Plan E5]</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Information Governance</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Insider Risk Management</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Intune Plan 1</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Loop</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft ML-Based Classification</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft MyAnalytics (Full)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Planner</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Records Management</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Search</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft StaffHub</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Stream for Office 365 E5</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Microsoft Teams</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Mobile Device Management for Office 365</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Nucleus</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Office 365 Advanced eDiscovery</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Office 365 Cloud App Security</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Office 365 Privileged Access Management</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Office 365 SafeDocs</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Office for the Web</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Power Apps for Office 365 (Plan 3)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Power Automate for Office 365</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Power BI Pro</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Power Virtual Agents for Office 365</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Project for Office (Plan E5)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Purview Discovery</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RETIRED - Microsoft Communications Compliance</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">RETIRED - Microsoft Insider Risk Management</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">SharePoint (Plan 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Skype for Business Online (Plan 2)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Sway</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">To-Do (Plan 3)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Viva Learning Seeded</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Whiteboard (Plan 3)</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Yammer Enterprise</span><br></div></code></pre></div></div>
<p>If you're reading this, I hope you've been fortunate enough to have your developer tenant renewed for now!</p>
<p>Happy learning!
Sam</p>
<p>Photo by <a href="https://unsplash.com/@kensuarez?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer" class="">Ken Suarez</a> on <a href="https://unsplash.com/photos/black-and-white-computer-keyboard-4IxPVkFGJGI?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer" class="">Unsplash</a></p>]]></content:encoded>
            <category>Microsoft 365</category>
            <category>M365</category>
        </item>
        <item>
            <title><![CDATA[Return Multiple Objects from a PowerShell Function]]></title>
            <link>https://day3bits.com/2023-12-08-return-multiple-objects-from-a-powershell-function/</link>
            <guid>https://day3bits.com/2023-12-08-return-multiple-objects-from-a-powershell-function/</guid>
            <pubDate>Fri, 08 Dec 2023 00:00:00 GMT</pubDate>
            <description><![CDATA[Hash tables are back with another slick use case!]]></description>
            <content:encoded><![CDATA[<p>One of the things that makes PowerShell so fun is the endless opportunities to learn new and better ways to do things. We all began learning it by trying out useful cmdlets and following tutorials to write basic functions. However, nothing sinks in as well as when we work on a project with specific goals that stretch our PowerShell knowledge.</p>
<p>For me, one such project has been <a href="https://github.com/trimarcjake/locksmith" target="_blank" rel="noopener noreferrer" class="">Locksmith</a>, which I had the pleasure of joining earlier this year. While working on an enhancement for the Locksmith PowerShell module, I had to ask myself for the first time, <strong>can I return multiple objects from a PowerShell function?</strong></p>
<p>The answer is yes, you can return multiple objects from a PowerShell function, and there are multiple ways to do it.</p>
<p>Here is one simple example:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Get-Food</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">$TreeFruit</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Apple"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Orange"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Peach"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">$Squash</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Pumpkin"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Acorn Squash"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Winter Squash"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">$RootVegetable</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Potato"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Sweet Potato"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Turnip"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Radish"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token keyword" style="color:#00009f">Return</span><span class="token plain"> </span><span class="token variable" style="color:#36acaa">$TreeFruit</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token variable" style="color:#36acaa">$Squash</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token variable" style="color:#36acaa">$RootVegetable</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$Food</span><span class="token plain"> = </span><span class="token function" style="color:#d73a49">Get-Food</span><br></div></code></pre></div></div>
<p>This function doesn't do anything other than return three arrays, but you get the idea. You can return any kind of object, or a mix of different object types. Cool!</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p><em>At this point, it's helpful to remember that everything in PowerShell is an object. (Yes, even strings are objects!) PowerShell lets us move those objects along the pipeline, doing whatever we need to with them in the process. It’s like a powerful little shell game!</em> 😉</p></div></div>
<p>…but there's a problem! If you run this code, you’ll notice something that could be an issue: the objects that are returned in <code>$Food</code> look like an ambiguous list.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Apple</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Orange</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Peach</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Pumpkin</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Acorn Squash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Winter Squash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Potato</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Sweet Potato</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Turnip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Radish</span><br></div></code></pre></div></div>
<p>The array names are gone, so if you want to reference a specific type of food from the results, you have to find a creative way to get it. What if you need to enumerate the TreeFruit array, and then enumerate the RootVegetable array later in a different function?</p>
<p>We can try using <code>imatch</code> to find arrays that might contain words we know:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$TreeFruit</span><span class="token plain"> = </span><span class="token variable" style="color:#36acaa">$Food</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">imatch </span><span class="token string" style="color:#e3116c">"Apple"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$Squash</span><span class="token plain"> = </span><span class="token variable" style="color:#36acaa">$Food</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">imatch </span><span class="token string" style="color:#e3116c">"Squash"</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$RootVegetable</span><span class="token plain"> = </span><span class="token variable" style="color:#36acaa">$Food</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">imatch </span><span class="token string" style="color:#e3116c">"Turnip"</span><br></div></code></pre></div></div>
<p>This isn't very friendly code and also depends on you knowing one of the values, which defeats the whole point to begin with.</p>
<p>We could try rebuilding the arrays by referencing the index of each object returned:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$TreeFruit</span><span class="token plain"> = </span><span class="token variable" style="color:#36acaa">$Food</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">0</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$Squash</span><span class="token plain"> = </span><span class="token variable" style="color:#36acaa">$Food</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">1</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$RootVegetable</span><span class="token plain"> = </span><span class="token variable" style="color:#36acaa">$Food</span><span class="token punctuation" style="color:#393A34">[</span><span class="token plain">2</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<p>While this does work, it is still unfriendly, error-prone, and requires you to already know the order of objects being returned. And what if the objects returned aren't arrays? They could be integers or booleans. It is a very unreliable way to manage code for any project, especially one being developed by a team.</p>
<p>After an embarrassingly long time, a light finally came on in my head.</p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p>💡 <em>The value side of a hash table entry can be any kind of object!</em> 💡</p></div></div>
<p>I then put the <em>name</em> of the object (the array, in this case) in the key and stored the actual object (arrays) in the value.</p>
<p>Our function can be thus written to return a hash table like this:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">function</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">Get-Food</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">$TreeFruit</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Apple"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Orange"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Peach"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">$Squash</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Pumpkin"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Acorn Squash"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Winter Squash"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token variable" style="color:#36acaa">$RootVegetable</span><span class="token plain"> = @</span><span class="token punctuation" style="color:#393A34">(</span><span class="token string" style="color:#e3116c">"Potato"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Sweet Potato"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Turnip"</span><span class="token punctuation" style="color:#393A34">,</span><span class="token string" style="color:#e3116c">"Radish"</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    @</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        TreeFruit     = </span><span class="token variable" style="color:#36acaa">$TreeFruit</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        Squash        = </span><span class="token variable" style="color:#36acaa">$Squash</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">        RootVegetable = </span><span class="token variable" style="color:#36acaa">$RootVegetable</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$Results</span><span class="token plain"> = </span><span class="token function" style="color:#d73a49">Get-Food</span><br></div></code></pre></div></div>
<p>This is especially useful because of the easy way you can reference the values of hash tables by their key names:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">&gt; </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'TreeFruit'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Apple</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Orange</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Peach</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">&gt; </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'Squash'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Pumpkin</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Acorn Squash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Winter Squash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">&gt; </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'RootVegetable'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Potato</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Sweet Potato</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Turnip</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Radish</span><br></div></code></pre></div></div>
<p>Now you can get fancy and do whatever you want with those results:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token function" style="color:#d73a49">Write-Output</span><span class="token plain"> @</span><span class="token string" style="color:#e3116c">"</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">  Tree Fruit:</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">  </span><span class="token string function" style="color:#d73a49">$</span><span class="token string function punctuation" style="color:#393A34">(</span><span class="token string function variable" style="color:#36acaa">$Results</span><span class="token string function punctuation" style="color:#393A34">[</span><span class="token string function string" style="color:#e3116c">'TreeFruit'</span><span class="token string function punctuation" style="color:#393A34">]</span><span class="token string function" style="color:#d73a49"> </span><span class="token string function operator" style="color:#393A34">-join</span><span class="token string function" style="color:#d73a49"> </span><span class="token string function string" style="color:#e3116c">', '</span><span class="token string function punctuation" style="color:#393A34">)</span><span class="token string" style="color:#e3116c"></span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c"></span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">  Squash:</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">  </span><span class="token string function" style="color:#d73a49">$</span><span class="token string function punctuation" style="color:#393A34">(</span><span class="token string function variable" style="color:#36acaa">$Results</span><span class="token string function punctuation" style="color:#393A34">[</span><span class="token string function string" style="color:#e3116c">'Squash'</span><span class="token string function punctuation" style="color:#393A34">]</span><span class="token string function" style="color:#d73a49"> </span><span class="token string function operator" style="color:#393A34">-join</span><span class="token string function" style="color:#d73a49"> </span><span class="token string function string" style="color:#e3116c">', '</span><span class="token string function punctuation" style="color:#393A34">)</span><span class="token string" style="color:#e3116c"></span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c"></span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">  Root Vegetables:</span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">  </span><span class="token string function" style="color:#d73a49">$</span><span class="token string function punctuation" style="color:#393A34">(</span><span class="token string function variable" style="color:#36acaa">$Results</span><span class="token string function punctuation" style="color:#393A34">[</span><span class="token string function string" style="color:#e3116c">'RootVegetable'</span><span class="token string function punctuation" style="color:#393A34">]</span><span class="token string function" style="color:#d73a49"> </span><span class="token string function operator" style="color:#393A34">-join</span><span class="token string function" style="color:#d73a49"> </span><span class="token string function string" style="color:#e3116c">', '</span><span class="token string function punctuation" style="color:#393A34">)</span><span class="token string" style="color:#e3116c"></span><br></div><div class="token-line" style="color:#393A34"><span class="token string" style="color:#e3116c">"</span><span class="token plain">@</span><br></div></code></pre></div></div>
<p>Which gives you this:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">Tree Fruit:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Apple</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Orange</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Peach</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Squash:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Pumpkin</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Acorn Squash</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Winter Squash</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Root Vegetables:</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">Potato</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Sweet Potato</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Turnip</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Radish</span><br></div></code></pre></div></div>
<p>I like it! Let's get back to <a href="https://github.com/trimarcjake/locksmith" target="_blank" rel="noopener noreferrer" class="">Locksmith</a> so you can see it put to practical use. My goal was to call a number of scans from a private function and then return the results of each scan back to the <a href="https://github.com/TrimarcJake/Locksmith/blob/2d54c5b1171f4a8c392e0b21a3a00eb7dd258149/Public/Invoke-Locksmith.ps1#L191" target="_blank" rel="noopener noreferrer" class="">main function</a>. We needed to be able to reliably reference each result as a named array for the next steps.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$Results</span><span class="token plain"> = </span><span class="token function" style="color:#d73a49">Invoke-Scans</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">Scans </span><span class="token variable" style="color:#36acaa">$Scans</span><br></div></code></pre></div></div>
<p>The <a href="https://github.com/TrimarcJake/Locksmith/blob/main/Private/Invoke-Scans.ps1" target="_blank" rel="noopener noreferrer" class="">Invoke-Scans</a> function does its work and then returns the results with the following:</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"># Start Condensed Example</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token namespace" style="opacity:0.7">[array]</span><span class="token variable" style="color:#36acaa">$AuditingIssues</span><span class="token plain"> = </span><span class="token function" style="color:#d73a49">Find-AuditingIssue</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ADCSObjects </span><span class="token variable" style="color:#36acaa">$ADCSObjects</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token namespace" style="opacity:0.7">[array]</span><span class="token variable" style="color:#36acaa">$ESC1</span><span class="token plain"> = Find-ESC1 </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ADCSObjects </span><span class="token variable" style="color:#36acaa">$ADCSObjects</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">SafeUsers </span><span class="token variable" style="color:#36acaa">$SafeUsers</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token namespace" style="opacity:0.7">[array]</span><span class="token variable" style="color:#36acaa">$ESC2</span><span class="token plain"> = Find-ESC2 </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">ADCSObjects </span><span class="token variable" style="color:#36acaa">$ADCSObjects</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">-</span><span class="token plain">SafeUsers </span><span class="token variable" style="color:#36acaa">$SafeUsers</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># End Condensed Example</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Later, at the end of the function:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Return a hash table of array names (keys) and arrays (values)</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">@</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    AllIssues = </span><span class="token variable" style="color:#36acaa">$AllIssues</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    AuditingIssues = </span><span class="token variable" style="color:#36acaa">$AuditingIssues</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ESC1 = </span><span class="token variable" style="color:#36acaa">$ESC1</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ESC2 = </span><span class="token variable" style="color:#36acaa">$ESC2</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ESC3 = </span><span class="token variable" style="color:#36acaa">$ESC3</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ESC4 = </span><span class="token variable" style="color:#36acaa">$ESC4</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ESC5 = </span><span class="token variable" style="color:#36acaa">$ESC5</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ESC6 = </span><span class="token variable" style="color:#36acaa">$ESC6</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    ESC8 = </span><span class="token variable" style="color:#36acaa">$ESC8</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p>Back in the main <a href="https://github.com/TrimarcJake/Locksmith/blob/2d54c5b1171f4a8c392e0b21a3a00eb7dd258149/Public/Invoke-Locksmith.ps1#L192" target="_blank" rel="noopener noreferrer" class="">Invoke-Locksmith function</a>, we can now work with these results much more easily. As noted above, hash table values can be pulled by referencing their key name, like <code>$Results['ESC1']</code>, which will return all findings in the <code>$ESC1</code> array.</p>
<p>Alternatively, we can save them as new variables in the main function, making things even easier for repeated use.</p>
<div class="language-powershell codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-powershell codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token variable" style="color:#36acaa">$AllIssues</span><span class="token plain">      = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'AllIssues'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$AuditingIssues</span><span class="token plain"> = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'AuditingIssues'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$ESC1</span><span class="token plain">           = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'ESC1'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$ESC2</span><span class="token plain">           = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'ESC2'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$ESC3</span><span class="token plain">           = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'ESC3'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$ESC4</span><span class="token plain">           = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'ESC4'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$ESC5</span><span class="token plain">           = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'ESC5'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$ESC6</span><span class="token plain">           = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'ESC6'</span><span class="token punctuation" style="color:#393A34">]</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token variable" style="color:#36acaa">$ESC8</span><span class="token plain">           = </span><span class="token variable" style="color:#36acaa">$Results</span><span class="token punctuation" style="color:#393A34">[</span><span class="token string" style="color:#e3116c">'ESC8'</span><span class="token punctuation" style="color:#393A34">]</span><br></div></code></pre></div></div>
<p>That's it! That's the tip. Return multiple named objects from a function but using a hash table to name and store them. Let me know if this helps with any of your projects, or if you have an even better way to do it!</p>
<p>Be sure to check out the Locksmith project if you're interested in Active Directory, Active Directory Certificate Services, or PKI in general.</p>
<p><a href="https://github.com/trimarcjake/locksmith" target="_blank" rel="noopener noreferrer" class=""><img decoding="async" loading="lazy" src="https://day3bits.com/assets/img/locksmith.png" alt="An image of the first Locksmith sticker: a coral-colored padlock with the basic PowerShell prompt characters on the front. The top caption says, 'Got AD CS?' and the bottom caption says, 'Invoke-Locksmith' on a purple background." height="250" width="250" class="img_ev3q"></a></p>
<p>Peace.
Sam</p>
<p>Photo by <a href="https://unsplash.com/@aeschwarz?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer" class="">Adrian Schwarz</a> on <a href="https://unsplash.com/photos/time-lapse-photography-of-city-night-lights-XS7q-baZrmE?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash" target="_blank" rel="noopener noreferrer" class="">Unsplash</a></p>]]></content:encoded>
            <category>PowerShell</category>
            <category>PKI</category>
        </item>
    </channel>
</rss>