&lt;?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Articles from August 2026 on PowerShell.org - Welcome Automaters!</title><link>https://powershell.org/articles/2026/08/</link><description>Recent content in Articles from August 2026 on PowerShell.org - Welcome Automaters!</description><generator>Hugo</generator><language>en-us</language><atom:link href="https://powershell.org/articles/2026/08/index.xml" rel="self" type="application/rss+xml"/><item><title>Analyze Dependencies with PSQuickGraph and PSGraphView</title><link>https://powershell.org/articles/2026-08-22-analyze-dependencies-with-psquickgraph-and-psgraphview/</link><guid>https://powershell.org/articles/2026-08-22-analyze-dependencies-with-psquickgraph-and-psgraphview/</guid><pubDate>Sat, 22 Aug 2026 00:00:00 +0000</pubDate><description>&lt;p&gt;PowerShell is excellent at collecting objects. The harder question often comes
one step later: how are those objects related?&lt;/p&gt;
&lt;p&gt;A table can tell us that an Orders API uses a database, a message broker, and a
vault. It is much less useful when we need to answer questions such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What will be affected if Azure Service Bus is unavailable?&lt;/li&gt;
&lt;li&gt;Why does the customer-facing application depend on Key Vault?&lt;/li&gt;
&lt;li&gt;In what order should the platform be deployed or migrated?&lt;/li&gt;
&lt;li&gt;Where are the cycles and tightly coupled groups when the model grows?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those are graph questions. &lt;a href="https://github.com/eosfor/PSGraph"&gt;PSGraph&lt;/a&gt; provides
the graph model and algorithms through the &lt;code&gt;PSQuickGraph&lt;/code&gt; PowerShell module. The
sibling &lt;a href="https://github.com/eosfor/PSGraphView"&gt;PSGraphView&lt;/a&gt; module renders those
models as Graphviz, Vega, MSAGL, and design structure matrix views.&lt;/p&gt;</description><content:encoded>&lt;![CDATA[<p>PowerShell is excellent at collecting objects. The harder question often comes
one step later: how are those objects related?</p><p>A table can tell us that an Orders API uses a database, a message broker, and a
vault. It is much less useful when we need to answer questions such as:</p><ul><li>What will be affected if Azure Service Bus is unavailable?</li><li>Why does the customer-facing application depend on Key Vault?</li><li>In what order should the platform be deployed or migrated?</li><li>Where are the cycles and tightly coupled groups when the model grows?</li></ul><p>Those are graph questions.<a href="https://github.com/eosfor/PSGraph">PSGraph</a> provides
the graph model and algorithms through the<code>PSQuickGraph</code> PowerShell module. The
sibling<a href="https://github.com/eosfor/PSGraphView">PSGraphView</a> module renders those
models as Graphviz, Vega, MSAGL, and design structure matrix views.</p><p>This article builds one small platform model and uses it for several jobs. The
point is not the fictional architecture. The point is that the same native
PowerShell objects can support automation, analysis, and documentation without
maintaining three separate models.</p><h2 id="two-modules-with-different-jobs" class="ps-heading">Two modules with different jobs<a class="ps-heading-anchor" href="#two-modules-with-different-jobs" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>The naming is worth explaining before installing anything:</p><table><thead><tr><th>Name</th><th>Responsibility</th></tr></thead><tbody><tr><td><code>PSGraph</code></td><td>The project and GitHub repository.</td></tr><tr><td><code>PSQuickGraph</code></td><td>The installable module for graph objects, algorithms, GraphML, Graphviz/DOT export, and DSM analysis.</td></tr><tr><td><code>PSGraphView</code></td><td>The installable visualization module for Graphviz, Vega, MSAGL, and DSM output.</td></tr></tbody></table><p><code>PSQuickGraph</code> is not the Microsoft Graph API, and it is not the older Graphviz
DSL module named<code>PSGraph</code>. Its focus is an object graph that can be queried and
passed through PowerShell pipelines.</p><p>The examples below use the current prerelease pair because the renderer split is
new. Pinning the versions makes the article reproducible:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 9</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">10</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">11</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">12</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">13</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">14</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span>Install-PSResource `</span></span><span style="display:flex;"><span> -Name PSQuickGraph `</span></span><span style="display:flex;"><span> -Version<span style="color:#a5d6ff">2.6</span>.<span style="color:#a5d6ff">0</span>-beta1 `</span></span><span style="display:flex;"><span> -Prerelease `</span></span><span style="display:flex;"><span> -Scope CurrentUser</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>Install-PSResource `</span></span><span style="display:flex;"><span> -Name PSGraphView `</span></span><span style="display:flex;"><span> -Version<span style="color:#a5d6ff">0.2</span>.<span style="color:#a5d6ff">0</span>-beta1 `</span></span><span style="display:flex;"><span> -Prerelease `</span></span><span style="display:flex;"><span> -Scope CurrentUser</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>Import-Module PSQuickGraph -RequiredVersion<span style="color:#a5d6ff">2.6</span>.<span style="color:#79c0ff">0</span></span></span><span style="display:flex;"><span>Import-Module PSGraphView -RequiredVersion<span style="color:#a5d6ff">0.2</span>.<span style="color:#79c0ff">0</span></span></span></code></pre></td></tr></table></div></div><p>If you only need graph construction and algorithms,<code>PSGraphView</code> is optional.</p><h2 id="model-a-platform-with-ordinary-objects" class="ps-heading">Model a platform with ordinary objects<a class="ps-heading-anchor" href="#model-a-platform-with-ordinary-objects" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>The sample inventory contains applications, services, workers, shared platform
services, databases, and observability. There is no required vertex class in the
calling code; each item is a normal<code>PSCustomObject</code>:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 9</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">10</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">11</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">12</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">13</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">14</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$services</span> =<span style="color:#79c0ff">@</span>(</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Customer Portal'</span>; Kind =<span style="color:#a5d6ff">'Application'</span>; Team =<span style="color:#a5d6ff">'Experience'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Admin Portal'</span>; Kind =<span style="color:#a5d6ff">'Application'</span>; Team =<span style="color:#a5d6ff">'Operations'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Orders API'</span>; Kind =<span style="color:#a5d6ff">'Service'</span>; Team =<span style="color:#a5d6ff">'Orders'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Inventory API'</span>; Kind =<span style="color:#a5d6ff">'Service'</span>; Team =<span style="color:#a5d6ff">'Inventory'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Billing Worker'</span>; Kind =<span style="color:#a5d6ff">'Worker'</span>; Team =<span style="color:#a5d6ff">'Billing'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Notification Worker'</span>; Kind =<span style="color:#a5d6ff">'Worker'</span>; Team =<span style="color:#a5d6ff">'Experience'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Azure Service Bus'</span>; Kind =<span style="color:#a5d6ff">'Platform'</span>; Team =<span style="color:#a5d6ff">'Platform'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Orders DB'</span>; Kind =<span style="color:#a5d6ff">'Data'</span>; Team =<span style="color:#a5d6ff">'Orders'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Inventory DB'</span>; Kind =<span style="color:#a5d6ff">'Data'</span>; Team =<span style="color:#a5d6ff">'Inventory'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Billing DB'</span>; Kind =<span style="color:#a5d6ff">'Data'</span>; Team =<span style="color:#a5d6ff">'Billing'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Key Vault'</span>; Kind =<span style="color:#a5d6ff">'Platform'</span>; Team =<span style="color:#a5d6ff">'Platform'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ Name =<span style="color:#a5d6ff">'Application Insights'</span>; Kind =<span style="color:#a5d6ff">'Observability'</span>; Team =<span style="color:#a5d6ff">'Platform'</span> }</span></span><span style="display:flex;"><span>)</span></span></code></pre></td></tr></table></div></div><p>Dependencies are data too. In this model an edge points from a consumer to its
dependency:<code>Orders API -&gt; Orders DB</code> means that the API depends on the database.</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 9</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">10</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">11</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">12</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">13</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">14</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">15</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">16</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">17</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">18</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">19</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">20</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">21</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">22</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">23</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$dependencies</span> =<span style="color:#79c0ff">@</span>(</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Customer Portal'</span>; To =<span style="color:#a5d6ff">'Orders API'</span>; Reason =<span style="color:#a5d6ff">'HTTPS'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Customer Portal'</span>; To =<span style="color:#a5d6ff">'Inventory API'</span>; Reason =<span style="color:#a5d6ff">'HTTPS'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Admin Portal'</span>; To =<span style="color:#a5d6ff">'Orders API'</span>; Reason =<span style="color:#a5d6ff">'HTTPS'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Admin Portal'</span>; To =<span style="color:#a5d6ff">'Inventory API'</span>; Reason =<span style="color:#a5d6ff">'HTTPS'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Orders API'</span>; To =<span style="color:#a5d6ff">'Orders DB'</span>; Reason =<span style="color:#a5d6ff">'SQL'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Orders API'</span>; To =<span style="color:#a5d6ff">'Inventory API'</span>; Reason =<span style="color:#a5d6ff">'HTTPS'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Orders API'</span>; To =<span style="color:#a5d6ff">'Azure Service Bus'</span>; Reason =<span style="color:#a5d6ff">'AMQP'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Orders API'</span>; To =<span style="color:#a5d6ff">'Key Vault'</span>; Reason =<span style="color:#a5d6ff">'Secrets'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Inventory API'</span>; To =<span style="color:#a5d6ff">'Inventory DB'</span>; Reason =<span style="color:#a5d6ff">'SQL'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Inventory API'</span>; To =<span style="color:#a5d6ff">'Key Vault'</span>; Reason =<span style="color:#a5d6ff">'Secrets'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Billing Worker'</span>; To =<span style="color:#a5d6ff">'Azure Service Bus'</span>; Reason =<span style="color:#a5d6ff">'AMQP'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Billing Worker'</span>; To =<span style="color:#a5d6ff">'Billing DB'</span>; Reason =<span style="color:#a5d6ff">'SQL'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Billing Worker'</span>; To =<span style="color:#a5d6ff">'Key Vault'</span>; Reason =<span style="color:#a5d6ff">'Secrets'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Notification Worker'</span>; To =<span style="color:#a5d6ff">'Azure Service Bus'</span>; Reason =<span style="color:#a5d6ff">'AMQP'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Notification Worker'</span>; To =<span style="color:#a5d6ff">'Key Vault'</span>; Reason =<span style="color:#a5d6ff">'Secrets'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Customer Portal'</span>; To =<span style="color:#a5d6ff">'Application Insights'</span>; Reason =<span style="color:#a5d6ff">'Telemetry'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Admin Portal'</span>; To =<span style="color:#a5d6ff">'Application Insights'</span>; Reason =<span style="color:#a5d6ff">'Telemetry'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Orders API'</span>; To =<span style="color:#a5d6ff">'Application Insights'</span>; Reason =<span style="color:#a5d6ff">'Telemetry'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Inventory API'</span>; To =<span style="color:#a5d6ff">'Application Insights'</span>; Reason =<span style="color:#a5d6ff">'Telemetry'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Billing Worker'</span>; To =<span style="color:#a5d6ff">'Application Insights'</span>; Reason =<span style="color:#a5d6ff">'Telemetry'</span> }</span></span><span style="display:flex;"><span> [<span style="color:#79c0ff;font-weight:bold">pscustomobject</span>]<span style="color:#79c0ff">@</span>{ From =<span style="color:#a5d6ff">'Notification Worker'</span>; To =<span style="color:#a5d6ff">'Application Insights'</span>; Reason =<span style="color:#a5d6ff">'Telemetry'</span> }</span></span><span style="display:flex;"><span>)</span></span></code></pre></td></tr></table></div></div><p>Build the graph in two passes. Explicitly adding vertices preserves isolated
services; adding only edges would omit objects that currently have no
relationships.</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 9</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">10</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">11</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">12</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">13</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">14</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">15</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">16</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">17</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">18</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$serviceByName</span> =<span style="color:#79c0ff">@</span>{}</span></span><span style="display:flex;"><span><span style="color:#79c0ff">$graph</span> = New-Graph</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#ff7b72">foreach</span> (<span style="color:#79c0ff">$service</span><span style="color:#ff7b72">in</span><span style="color:#79c0ff">$services</span>) {</span></span><span style="display:flex;"><span><span style="color:#79c0ff">$serviceByName</span>[<span style="color:#79c0ff">$service</span>.Name] =<span style="color:#79c0ff">$service</span></span></span><span style="display:flex;"><span><span style="color:#79c0ff">$vertex</span> = Add-Vertex -Graph<span style="color:#79c0ff">$graph</span> -Vertex<span style="color:#79c0ff">$service</span> -PassThru</span></span><span style="display:flex;"><span><span style="color:#79c0ff">$vertex</span>.<span style="color:#79c0ff">Metadata</span> |</span></span><span style="display:flex;"><span> Add-Member -NotePropertyName Team -NotePropertyValue<span style="color:#79c0ff">$service</span>.<span style="color:#79c0ff">Team</span></span></span><span style="display:flex;"><span>}</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#ff7b72">foreach</span> (<span style="color:#79c0ff">$dependency</span><span style="color:#ff7b72">in</span><span style="color:#79c0ff">$dependencies</span>) {</span></span><span style="display:flex;"><span> Add-Edge `</span></span><span style="display:flex;"><span> -Graph<span style="color:#79c0ff">$graph</span> `</span></span><span style="display:flex;"><span> -From<span style="color:#79c0ff">$serviceByName</span>[<span style="color:#79c0ff">$dependency</span>.From] `</span></span><span style="display:flex;"><span> -To<span style="color:#79c0ff">$serviceByName</span>[<span style="color:#79c0ff">$dependency</span>.To] `</span></span><span style="display:flex;"><span> -Tag<span style="color:#79c0ff">$dependency</span>.<span style="color:#79c0ff">Reason</span> |</span></span><span style="display:flex;"><span> Out-Null</span></span><span style="display:flex;"><span>}</span></span></code></pre></td></tr></table></div></div><p>The sample graph contains 12 vertices and 21 directed edges. The wrapper vertex
retains the original object in<code>OriginalObject</code>, so analysis results can return
to normal PowerShell processing at any time.</p><h2 id="first-view-the-dependency-map" class="ps-heading">First view: the dependency map<a class="ps-heading-anchor" href="#first-view-the-dependency-map" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p><code>PSQuickGraph</code> exports the model as DOT;<code>PSGraphView</code> asks Graphviz to lay it out
and return SVG. Keeping these steps separate is useful: algorithms can run on a
server that never renders an image, while a documentation build can apply its
own visual style.</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 9</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">10</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">11</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">12</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">13</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">14</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">15</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">16</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">17</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$dot</span> = Export-Graph `</span></span><span style="display:flex;"><span> -Graph<span style="color:#79c0ff">$graph</span> `</span></span><span style="display:flex;"><span> -Format Graphviz `</span></span><span style="display:flex;"><span> -GraphScript {<span style="color:#79c0ff">@</span>{ rankdir =<span style="color:#a5d6ff">'LR'</span>; bgcolor =<span style="color:#a5d6ff">'white'</span> } } `</span></span><span style="display:flex;"><span> -VertexScript {</span></span><span style="display:flex;"><span><span style="color:#79c0ff">@</span>{</span></span><span style="display:flex;"><span> shape =<span style="color:#a5d6ff">'Record'</span></span></span><span style="display:flex;"><span> style =<span style="color:#a5d6ff">'filled'</span></span></span><span style="display:flex;"><span> label =<span style="color:#a5d6ff">"{{ {0} | {1} }}"</span><span style="color:#ff7b72;font-weight:bold">-f</span><span style="color:#79c0ff">$_</span>.Name,<span style="color:#79c0ff">$_</span>.<span style="color:#79c0ff">Kind</span></span></span><span style="display:flex;"><span> }</span></span><span style="display:flex;"><span> }</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>Export-GraphvizView `</span></span><span style="display:flex;"><span> -InputObject<span style="color:#79c0ff">$dot</span> `</span></span><span style="display:flex;"><span> -Renderer Dot `</span></span><span style="display:flex;"><span><span style="color:#ff7b72;font-weight:bold">-As</span> Svg `</span></span><span style="display:flex;"><span> -OutputPath ./platform-dependencies.<span style="color:#79c0ff">svg</span></span></span></code></pre></td></tr></table></div></div><p><img src="/images/articles/psgraphview-platform-dependencies.svg" alt="A consumer-to-dependency graph of the sample platform. Each record shows the component name and kind."/><p>A drawing is already useful for a design review, but the graph becomes more
valuable when it answers operational questions.</p><h2 id="immediate-dependencies-and-dependents" class="ps-heading">Immediate dependencies and dependents<a class="ps-heading-anchor" href="#immediate-dependencies-and-dependents" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>Because the edge direction is explicit, outgoing and incoming edges answer two
different questions:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">9</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$orders</span> =<span style="color:#79c0ff">$graph</span>.<span style="color:#79c0ff">Vertices</span> | Where-Object Label<span style="color:#ff7b72;font-weight:bold">-EQ</span><span style="color:#a5d6ff">'Orders API'</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># What does Orders API require?</span></span></span><span style="display:flex;"><span>Get-OutEdge -Graph<span style="color:#79c0ff">$graph</span> -Vertex<span style="color:#79c0ff">$orders</span> |</span></span><span style="display:flex;"><span> ForEach-Object {<span style="color:#79c0ff">$_</span>.<span style="color:#79c0ff">Target</span>.<span style="color:#79c0ff">OriginalObject</span> }</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic"># What calls Orders API directly?</span></span></span><span style="display:flex;"><span>Get-InEdge -Graph<span style="color:#79c0ff">$graph</span> -Vertex<span style="color:#79c0ff">$orders</span> |</span></span><span style="display:flex;"><span> ForEach-Object {<span style="color:#79c0ff">$_</span>.<span style="color:#79c0ff">Source</span>.<span style="color:#79c0ff">OriginalObject</span> }</span></span></code></pre></td></tr></table></div></div><p>The result is still the inventory object, not display text. It can be grouped by
team, joined with ownership data, exported to CSV, or used to open incidents.</p><h2 id="explain-a-dependency-with-a-path" class="ps-heading">Explain a dependency with a path<a class="ps-heading-anchor" href="#explain-a-dependency-with-a-path" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>Knowing that two components are connected is not always enough.<code>Get-GraphPath</code>
returns the edge sequence that explains the relationship:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">6</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$from</span> =<span style="color:#79c0ff">$graph</span>.<span style="color:#79c0ff">Vertices</span> | Where-Object Label<span style="color:#ff7b72;font-weight:bold">-EQ</span><span style="color:#a5d6ff">'Customer Portal'</span></span></span><span style="display:flex;"><span><span style="color:#79c0ff">$to</span> =<span style="color:#79c0ff">$graph</span>.<span style="color:#79c0ff">Vertices</span> | Where-Object Label<span style="color:#ff7b72;font-weight:bold">-EQ</span><span style="color:#a5d6ff">'Key Vault'</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#79c0ff">$path</span> = Get-GraphPath -Graph<span style="color:#79c0ff">$graph</span> -From<span style="color:#79c0ff">$from</span> -To<span style="color:#79c0ff">$to</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#79c0ff">@</span>(<span style="color:#79c0ff">$path</span>.<span style="color:#79c0ff">Source</span>.Label) +<span style="color:#79c0ff">$path</span>[<span style="color:#a5d6ff">-1</span>].<span style="color:#79c0ff">Target</span>.<span style="color:#79c0ff">Label</span></span></span></code></pre></td></tr></table></div></div><p>For this model the result is:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">1</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Customer Portal -&gt; Orders API -&gt; Key Vault</span></span></code></pre></td></tr></table></div></div><p>This is useful in change reviews and incident response because it provides an
explanation, not just a Boolean answer.</p><h2 id="calculate-blast-radius" class="ps-heading">Calculate blast radius<a class="ps-heading-anchor" href="#calculate-blast-radius" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>Suppose Azure Service Bus is unavailable. Every vertex that can reach it through
consumer-to-dependency edges is transitively affected:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 9</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">10</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">11</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$serviceBus</span> =<span style="color:#79c0ff">$graph</span>.<span style="color:#79c0ff">Vertices</span> |</span></span><span style="display:flex;"><span> Where-Object Label<span style="color:#ff7b72;font-weight:bold">-EQ</span><span style="color:#a5d6ff">'Azure Service Bus'</span></span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#79c0ff">$affected</span> =<span style="color:#79c0ff">$graph</span>.<span style="color:#79c0ff">Vertices</span> |</span></span><span style="display:flex;"><span> Where-Object Label<span style="color:#ff7b72;font-weight:bold">-NE</span><span style="color:#79c0ff">$serviceBus</span>.<span style="color:#79c0ff">Label</span> |</span></span><span style="display:flex;"><span> Where-Object {</span></span><span style="display:flex;"><span> Test-GraphPath -Graph<span style="color:#79c0ff">$graph</span> -From<span style="color:#79c0ff">$_</span> -To<span style="color:#79c0ff">$serviceBus</span></span></span><span style="display:flex;"><span> } |</span></span><span style="display:flex;"><span> Sort-Object Label</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#79c0ff">$affected</span>.<span style="color:#79c0ff">OriginalObject</span></span></span></code></pre></td></tr></table></div></div><p><img src="/images/articles/psgraphview-service-bus-impact.svg" alt="Azure Service Bus and every direct or transitive consumer are marked with a bold border and a warning marker."/><p>The result includes both direct consumers and applications affected indirectly:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">5</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Admin Portal</span></span><span style="display:flex;"><span>Billing Worker</span></span><span style="display:flex;"><span>Customer Portal</span></span><span style="display:flex;"><span>Notification Worker</span></span><span style="display:flex;"><span>Orders API</span></span></code></pre></td></tr></table></div></div><p><code>Get-InEdge</code> finds immediate consumers.<code>Test-GraphPath</code> also finds portals that
depend on Service Bus indirectly through Orders API.</p><h2 id="derive-a-deployment-order" class="ps-heading">Derive a deployment order<a class="ps-heading-anchor" href="#derive-a-deployment-order" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>The same graph can become an execution plan. With consumer-to-dependency edges,
reversing the topological order puts dependencies before their consumers:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">7</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$deploymentOrder</span> = Get-GraphTopologicalSort `</span></span><span style="display:flex;"><span> -Graph<span style="color:#79c0ff">$graph</span> `</span></span><span style="display:flex;"><span> -Reverse</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span><span style="color:#79c0ff">$deploymentOrder</span> |</span></span><span style="display:flex;"><span> Select-Object -ExpandProperty OriginalObject |</span></span><span style="display:flex;"><span> Select-Object Name, Kind, Team</span></span></code></pre></td></tr></table></div></div><p>The result starts with shared dependencies and ends with applications:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 9</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">10</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">11</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">12</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Azure Service Bus</span></span><span style="display:flex;"><span>Orders DB</span></span><span style="display:flex;"><span>Key Vault</span></span><span style="display:flex;"><span>Inventory DB</span></span><span style="display:flex;"><span>Billing DB</span></span><span style="display:flex;"><span>Application Insights</span></span><span style="display:flex;"><span>Inventory API</span></span><span style="display:flex;"><span>Billing Worker</span></span><span style="display:flex;"><span>Orders API</span></span><span style="display:flex;"><span>Notification Worker</span></span><span style="display:flex;"><span>Customer Portal</span></span><span style="display:flex;"><span>Admin Portal</span></span></code></pre></td></tr></table></div></div><p>Topological sorting is appropriate only for a directed acyclic graph. If two
services depend on each other, the sort fails rather than inventing a safe
order. That failure is useful evidence: the cycle needs an explicit migration
strategy or an architectural change.</p><h2 id="when-a-node-link-diagram-becomes-too-dense" class="ps-heading">When a node-link diagram becomes too dense<a class="ps-heading-anchor" href="#when-a-node-link-diagram-becomes-too-dense" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>Arrows work well for a dozen components. They become a hairball for a hundred. A
design structure matrix (DSM) represents the same edges as cells: the row is the
consumer and the column is its dependency.</p><p><code>PSQuickGraph</code> creates and sequences the matrix;<code>PSGraphView</code> renders it:</p><div class="highlight"><div style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><table style="border-spacing:0;padding:0;margin:0;border:0;"><tr><td style="vertical-align:top;padding:0;margin:0;border:0;"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 1</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 2</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 3</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 4</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 5</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 6</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 7</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 8</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679"> 9</span><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#737679">10</span></code></pre></td><td style="vertical-align:top;padding:0;margin:0;border:0;;width:100%"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-powershell" data-lang="powershell"><span style="display:flex;"><span><span style="color:#79c0ff">$dsm</span> = New-DSM -Graph<span style="color:#79c0ff">$graph</span></span></span><span style="display:flex;"><span><span style="color:#79c0ff">$sequencedDsm</span> = Start-DSMSequencing `</span></span><span style="display:flex;"><span> -Dsm<span style="color:#79c0ff">$dsm</span> `</span></span><span style="display:flex;"><span> -LoopDetectionMethod Condensation</span></span><span style="display:flex;"><span/></span><span style="display:flex;"><span>Export-DSMView `</span></span><span style="display:flex;"><span> -SequencedDsm<span style="color:#79c0ff">$sequencedDsm</span> `</span></span><span style="display:flex;"><span> -Renderer DsmVegaMatrix `</span></span><span style="display:flex;"><span><span style="color:#ff7b72;font-weight:bold">-As</span> Json `</span></span><span style="display:flex;"><span> -Path ./dependency-matrix.<span style="color:#79c0ff">json</span></span></span></code></pre></td></tr></table></div></div><p><img src="/images/articles/psgraphview-dependency-matrix.svg" alt="A sequenced design structure matrix of the same platform. Filled cells map consumers to dependencies without crossing edges."/><p>The Vega renderer produces an interactive matrix whose row and column labels can
be highlighted on hover. The static image above uses the same Vega specification
for the article page. For larger models,<code>Start-DSMClustering</code> can group strongly
related components before rendering. That makes the matrix useful for finding
candidate service boundaries, not merely documenting the current state.</p><h2 id="other-scenarios-for-the-same-pattern" class="ps-heading">Other scenarios for the same pattern<a class="ps-heading-anchor" href="#other-scenarios-for-the-same-pattern" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p>Only the data collection step changes between domains. The graph workflow
remains: collect objects, create stable vertices, add directed relationships,
ask questions, then choose a view.</p><ul><li><strong>Security events:</strong> connect processes, users, hosts, files, and network
destinations to reconstruct a suspicious chain.</li><li><strong>Network policy:</strong> turn accepted and rejected firewall flows into host and
port relationships.</li><li><strong>Infrastructure as code:</strong> model semantic Bicep dependencies and validate
cross-resource relationships, as shown in<a href="/articles/2026-07-24-validate-azure-resource-relationships-with-psrule-and-powershell-graphs/">Validate Azure Resource Relationships with PSRule and PowerShell Graphs</a>.</li><li><strong>Web diagnostics:</strong> connect pages to scripts, APIs, and third-party origins
discovered through Chrome DevTools Protocol.</li><li><strong>Execution graphs:</strong> use topological order to evaluate a computation graph,
as shown in<a href="/articles/2026-07-24-explore-micrograd-with-verso-and-powershell/">Explore Micrograd with Verso and PowerShell</a>.</li></ul><p>These examples look different on screen, but the useful questions are the same:
what depends on this, how did we get there, what order is valid, and where is the
system too tightly coupled?</p><h2 id="takeaways" class="ps-heading">Takeaways<a class="ps-heading-anchor" href="#takeaways" aria-label="Link to this section" title="Link to this section"><i class="fas fa-link" aria-hidden="true"/></a></h2><p><code>PSQuickGraph</code> is most useful when a diagram is not the final product. The graph
can drive impact reports, validation, deployment ordering, and incident
analysis.<code>PSGraphView</code> then turns that same tested model into the representation
that fits the audience: a familiar node-link diagram, an interactive view, or a
dense DSM.</p><p>The practical pattern is small:</p><ol><li>Keep vertices as domain objects with stable names or IDs.</li><li>Decide and document the edge direction.</li><li>Use algorithms before reaching for visualization.</li><li>Render from the same model instead of maintaining diagrams by hand.</li></ol><p>Once relationships become first-class data, PowerShell can do much more than
draw boxes and arrows.</p>
]]></content:encoded></item></channel></rss>