<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Posts about PowerShell</title><link>https://chriswarrick.com/</link><atom:link href="https://chriswarrick.com/blog/tags/powershell.xml" rel="self" type="application/rss+xml" /><description>A rarely updated blog, mostly about programming.</description><lastBuildDate>Mon, 29 Apr 2024 16:45:00 GMT</lastBuildDate><generator>https://github.com/Kwpolska/YetAnotherBlogGenerator</generator><item><title>PowerShell: the object-oriented shell you didn’t know you needed</title><dc:creator>Chris Warrick</dc:creator><link>https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/</link><pubDate>Mon, 29 Apr 2024 16:45:00 GMT</pubDate><guid>https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/</guid><description>PowerShell is an interactive shell and scripting language from Microsoft. It’s object-oriented — and that’s not just a buzzword, that’s a big difference to how the standard Unix shells work. And it is actually usable as an interactive shell.
</description><content:encoded><![CDATA[<p>PowerShell is an interactive shell and scripting language from Microsoft. It’s object-oriented — and that’s not just a buzzword, that’s a big difference to how the standard Unix shells work. And it is actually usable as an interactive shell.</p>



<h2 id="getting-started">Getting Started</h2>
<p>PowerShell is so nice, Microsoft made it twice.</p>
<p>Specifically, there concurrently exist two products named PowerShell:</p>
<ul>
<li>Windows PowerShell (5.1) is a built-in component of Windows. It is proprietary, Windows-only, and is based on the equally proprietary and equally Windows-only .NET Framework 4.x. It has a blue icon.</li>
<li>PowerShell (7.x), formerly known as PowerShell Core, is a stand-alone application. It is MIT-licensed <a href="https://github.com/PowerShell/PowerShell">(developed on GitHub)</a>, available for Windows, Linux, and macOS, and is based on the equally MIT-licensed and equally multi-platform .NET (formerly .NET Core). It has a black icon.</li>
</ul>
<p>Windows PowerShell development stopped when PowerShell (Core) came out. There are some niceties and commands missing in it, but it is still a fine option for trying it out or for when one can’t install PowerShell on a Windows system but need to solve something with code.</p>
<p>All examples in this post should work in either version of PowerShell on any OS (unless explicitly noted otherwise).</p>
<p>Install the modern PowerShell: <a href="https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.4">Windows</a>, <a href="https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-linux?view=powershell-7.4">Linux</a>, <a href="https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-linux?view=powershell-7.4">macOS</a>.</p>
<h2 id="objects-in-my-shell">Objects? In my shell?</h2>
<p>Let’s try getting a directory listing. This is Microsoft land, so let’s try the DOS command for a directory listing — that would be <code>dir</code>:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-1" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-1"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="nb">dir</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-2" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-3" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-3"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Directory</span><span class="p">:</span> <span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-4" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-4"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-5" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-5"></a><span class="n">Mode</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">LastWriteTime</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Length</span> <span class="n">Name</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-6" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-6"></a><span class="p">----</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">-------------</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">------</span> <span class="p">----</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-7" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-7"></a><span class="n">d</span><span class="p">----</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2024</span><span class="p">-</span><span class="n">04</span><span class="p">-</span><span class="n">29</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">18</span><span class="p">:</span><span class="n">00</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">world</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-8" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-8"></a><span class="n">-a</span><span class="p">---</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2024</span><span class="p">-</span><span class="n">04</span><span class="p">-</span><span class="n">29</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">18</span><span class="p">:</span><span class="n">00</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">23</span> <span class="n">example</span><span class="p">.</span><span class="n">py</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-9" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-9"></a><span class="n">-a</span><span class="p">---</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2024</span><span class="p">-</span><span class="n">04</span><span class="p">-</span><span class="n">29</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">18</span><span class="p">:</span><span class="n">00</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">7</span> <span class="n">foobar</span><span class="p">.</span><span class="n">txt</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-10" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-10"></a><span class="n">-a</span><span class="p">---</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2024</span><span class="p">-</span><span class="n">04</span><span class="p">-</span><span class="n">29</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">18</span><span class="p">:</span><span class="n">00</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">14</span> <span class="n">helloworld</span><span class="p">.</span><span class="n">txt</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-11" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-11"></a><span class="n">-a</span><span class="p">---</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2024</span><span class="p">-</span><span class="n">04</span><span class="p">-</span><span class="n">29</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">18</span><span class="p">:</span><span class="n">00</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">0</span> <span class="n">newfile</span><span class="p">.</span><span class="n">txt</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_5487e1609201ce902c883e7cd5ea641dfe46849f-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="code_5487e1609201ce902c883e7cd5ea641dfe46849f-12" name="code_5487e1609201ce902c883e7cd5ea641dfe46849f-12"></a><span class="n">-a</span><span class="p">---</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2024</span><span class="p">-</span><span class="n">04</span><span class="p">-</span><span class="n">29</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">18</span><span class="p">:</span><span class="n">00</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">5</span> <span class="n">test</span><span class="p">.</span><span class="n">txt</span>
</code></td></tr></table></div>
<p>This looks like a typical (if slightly verbose) file listing.</p>
<p>Now, let’s try to do something useful with this. Let’s get the total size of all <code>.txt</code> files.</p>
<p>In a Unix shell, one option is <code>du -bc *.txt</code>. The arguments: <code>-b</code> (<code>--bytes</code>) gives the real byte size, and <code>-c</code> (<code>--summarize</code>) produces a total. The result is this:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2026e78c6a1fda66be195947828c8cd5292e1e12-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="code_2026e78c6a1fda66be195947828c8cd5292e1e12-1" name="code_2026e78c6a1fda66be195947828c8cd5292e1e12-1"></a>7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foobar.txt
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2026e78c6a1fda66be195947828c8cd5292e1e12-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="code_2026e78c6a1fda66be195947828c8cd5292e1e12-2" name="code_2026e78c6a1fda66be195947828c8cd5292e1e12-2"></a>14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;helloworld.txt
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2026e78c6a1fda66be195947828c8cd5292e1e12-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="code_2026e78c6a1fda66be195947828c8cd5292e1e12-3" name="code_2026e78c6a1fda66be195947828c8cd5292e1e12-3"></a>0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;newfile.txt
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2026e78c6a1fda66be195947828c8cd5292e1e12-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="code_2026e78c6a1fda66be195947828c8cd5292e1e12-4" name="code_2026e78c6a1fda66be195947828c8cd5292e1e12-4"></a>5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.txt
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2026e78c6a1fda66be195947828c8cd5292e1e12-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="code_2026e78c6a1fda66be195947828c8cd5292e1e12-5" name="code_2026e78c6a1fda66be195947828c8cd5292e1e12-5"></a>26&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;total
</code></td></tr></table></div>
<p>But how to get just the number? This requires text manipulation (getting the first word of the last line). Something like <code>du -bc *.txt | tail -n 1 | cut -f 1</code> will do. There’s also <code>wc --total=only --bytes *.txt</code> — but this is specific to GNU wc, so it won’t cut it on *BSD or macOS. Another option would be to parse the output of <code>ls -l</code> — but that might not always be easy, and the output may contain something unexpected added by the specific <code>ls</code> version or the user’s specific shell configuration.</p>
<p>Let’s try something in PowerShell. If we do <code>$x = dir</code>, we’ll have the output of the <code>dir</code> command in <code>$x</code>. Let’s try to analyse it further, is the first character a newline?</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_732adae82ccca20456365dc143dee4ccde7d735d-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="code_732adae82ccca20456365dc143dee4ccde7d735d-1" name="code_732adae82ccca20456365dc143dee4ccde7d735d-1"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="nv">$x</span> <span class="p">=</span> <span class="nb">dir</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_732adae82ccca20456365dc143dee4ccde7d735d-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="code_732adae82ccca20456365dc143dee4ccde7d735d-2" name="code_732adae82ccca20456365dc143dee4ccde7d735d-2"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="nv">$x</span><span class="p">[</span><span class="n">0</span><span class="p">]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_732adae82ccca20456365dc143dee4ccde7d735d-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="code_732adae82ccca20456365dc143dee4ccde7d735d-3" name="code_732adae82ccca20456365dc143dee4ccde7d735d-3"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_732adae82ccca20456365dc143dee4ccde7d735d-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="code_732adae82ccca20456365dc143dee4ccde7d735d-4" name="code_732adae82ccca20456365dc143dee4ccde7d735d-4"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Directory</span><span class="p">:</span> <span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_732adae82ccca20456365dc143dee4ccde7d735d-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="code_732adae82ccca20456365dc143dee4ccde7d735d-5" name="code_732adae82ccca20456365dc143dee4ccde7d735d-5"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_732adae82ccca20456365dc143dee4ccde7d735d-6"><code data-line-number="6"></code></a></td><td class="code"><code><a id="code_732adae82ccca20456365dc143dee4ccde7d735d-6" name="code_732adae82ccca20456365dc143dee4ccde7d735d-6"></a><span class="n">Mode</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">LastWriteTime</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Length</span> <span class="n">Name</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_732adae82ccca20456365dc143dee4ccde7d735d-7"><code data-line-number="7"></code></a></td><td class="code"><code><a id="code_732adae82ccca20456365dc143dee4ccde7d735d-7" name="code_732adae82ccca20456365dc143dee4ccde7d735d-7"></a><span class="p">----</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">-------------</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">------</span> <span class="p">----</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_732adae82ccca20456365dc143dee4ccde7d735d-8"><code data-line-number="8"></code></a></td><td class="code"><code><a id="code_732adae82ccca20456365dc143dee4ccde7d735d-8" name="code_732adae82ccca20456365dc143dee4ccde7d735d-8"></a><span class="n">d</span><span class="p">----</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2024</span><span class="p">-</span><span class="n">04</span><span class="p">-</span><span class="n">29</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">18</span><span class="p">:</span><span class="n">00</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">world</span>
</code></td></tr></table></div>
<p>That’s interesting, we didn’t get the first character or the first line, we got the first <em>file</em>. And if we try <code>$x[1]</code>?</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a0872bfab1d587bc08f128eb0a76b8101473a096-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="code_a0872bfab1d587bc08f128eb0a76b8101473a096-1" name="code_a0872bfab1d587bc08f128eb0a76b8101473a096-1"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="nv">$x</span><span class="p">[</span><span class="n">1</span><span class="p">]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a0872bfab1d587bc08f128eb0a76b8101473a096-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="code_a0872bfab1d587bc08f128eb0a76b8101473a096-2" name="code_a0872bfab1d587bc08f128eb0a76b8101473a096-2"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a0872bfab1d587bc08f128eb0a76b8101473a096-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="code_a0872bfab1d587bc08f128eb0a76b8101473a096-3" name="code_a0872bfab1d587bc08f128eb0a76b8101473a096-3"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Directory</span><span class="p">:</span> <span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a0872bfab1d587bc08f128eb0a76b8101473a096-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="code_a0872bfab1d587bc08f128eb0a76b8101473a096-4" name="code_a0872bfab1d587bc08f128eb0a76b8101473a096-4"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a0872bfab1d587bc08f128eb0a76b8101473a096-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="code_a0872bfab1d587bc08f128eb0a76b8101473a096-5" name="code_a0872bfab1d587bc08f128eb0a76b8101473a096-5"></a><span class="n">Mode</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">LastWriteTime</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Length</span> <span class="n">Name</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a0872bfab1d587bc08f128eb0a76b8101473a096-6"><code data-line-number="6"></code></a></td><td class="code"><code><a id="code_a0872bfab1d587bc08f128eb0a76b8101473a096-6" name="code_a0872bfab1d587bc08f128eb0a76b8101473a096-6"></a><span class="p">----</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">-------------</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">------</span> <span class="p">----</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a0872bfab1d587bc08f128eb0a76b8101473a096-7"><code data-line-number="7"></code></a></td><td class="code"><code><a id="code_a0872bfab1d587bc08f128eb0a76b8101473a096-7" name="code_a0872bfab1d587bc08f128eb0a76b8101473a096-7"></a><span class="n">-a</span><span class="p">---</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2024</span><span class="p">-</span><span class="n">04</span><span class="p">-</span><span class="n">29</span>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">18</span><span class="p">:</span><span class="n">00</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">23</span> <span class="n">example</span><span class="p">.</span><span class="n">py</span>
</code></td></tr></table></div>
<p>What if we try getting the <code>Length</code> property out of that?</p>
<div class="highlight"><pre><span></span><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="nv">$x</span><span class="p">[</span><span class="n">1</span><span class="p">].</span><span class="n">Length</span>
<span class="n">23</span>
</pre></div>

<p>It turns out that <code>dir</code> returns an array of objects, and PowerShell knows how to format this array (and a single item from the array) into a nice table. What can we do with it? This:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-1" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-1"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="nb">Get-ChildItem</span> <span class="n">-Filter</span> <span class="s1">&#39;*.txt&#39;</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-2" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-2"></a>&nbsp;&nbsp;<span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Length</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-3" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-3"></a>&nbsp;&nbsp;<span class="nb">Measure-Object</span> <span class="n">-Sum</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-4" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-4"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-5" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-5"></a><span class="n">Count</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">:</span> <span class="n">4</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-6" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-6"></a><span class="n">Average</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-7" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-7"></a><span class="n">Sum</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">:</span> <span class="n">26</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-8" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-8"></a><span class="n">Maximum</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-9" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-9"></a><span class="n">Minimum</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-10" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-10"></a><span class="n">StandardDeviation</span> <span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-11" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-11"></a><span class="n">Property</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-12" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-12"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-13" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-13"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="p">(</span><span class="nb">Get-ChildItem</span> <span class="n">-Filter</span> <span class="s1">&#39;*.txt&#39;</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-14" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-14"></a>&nbsp;&nbsp;<span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Length</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-15" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-15"></a>&nbsp;&nbsp;<span class="nb">Measure-Object</span> <span class="n">-Sum</span><span class="p">).</span><span class="n">Sum</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-16"><code data-line-number="16"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-16" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-16"></a><span class="n">26</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-17"><code data-line-number="17"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-17" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-17"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="p">(</span><span class="nb">Get-ChildItem</span> <span class="n">-Filter</span> <span class="s1">&#39;*.txt&#39;</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-18"><code data-line-number="18"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-18" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-18"></a>&nbsp;&nbsp;<span class="nb">Measure-Object</span> <span class="n">-Sum</span> <span class="n">-Property</span> <span class="n">Length</span><span class="p">).</span><span class="n">Sum</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-19"><code data-line-number="19"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-19" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-19"></a><span class="n">26</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-20"><code data-line-number="20"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-20" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-20"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="p">(</span><span class="nb">Get-ChildItem</span> <span class="n">-Recurse</span> <span class="n">-Filter</span> <span class="s1">&#39;*.txt&#39;</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-21"><code data-line-number="21"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-21" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-21"></a>&nbsp;&nbsp;<span class="nb">Measure-Object</span> <span class="n">-Sum</span> <span class="n">-Property</span> <span class="n">Length</span><span class="p">).</span><span class="n">Sum</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-22"><code data-line-number="22"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-22" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-22"></a><span class="n">30</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-23"><code data-line-number="23"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-23" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-23"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="nv">$measured</span> <span class="p">=</span> <span class="p">(</span><span class="nb">Get-ChildItem</span> <span class="n">-Recurse</span> <span class="n">-Filter</span> <span class="s1">&#39;*.txt&#39;</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-24"><code data-line-number="24"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-24" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-24"></a>&nbsp;&nbsp;<span class="nb">Measure-Object</span> <span class="n">-Sum</span> <span class="n">-Property</span> <span class="n">Length</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-25"><code data-line-number="25"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-25" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-25"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">hello</span><span class="p">&gt;</span> <span class="nv">$measured</span><span class="p">.</span><span class="n">Sum</span> <span class="p">/</span> <span class="nv">$measured</span><span class="p">.</span><span class="n">Count</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-26"><code data-line-number="26"></code></a></td><td class="code"><code><a id="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-26" name="code_b6bfcaf6e4ff4bdba3718ce7e5233412217eab04-26"></a><span class="n">6</span>
</code></td></tr></table></div>
<p>We can iterate over all file objects, get their length (using <code>ForEach-Object</code> and a lambda), and then use <code>Measure-Object</code> to compute the sum (<code>Measure-Object</code> returns an object, we need to get its <code>Sum</code> property). We can replace the <code>ForEach-Object</code> call with the <code>-Property</code> argument in <code>Measure-Object</code>. And if we want to look into subdirectories, we can easily add <code>-Recurse</code> to <code>Get-ChildItem</code>. We get actual integers we can do math on.</p>
<p>You might have noticed I used <code>Get-ChildItem</code> instead of <code>dir</code> in the previous example. <code>Get-ChildItem</code> is the full name of the command (<em>cmdlet</em>). <code>dir</code> is one of its aliases, alongside <code>gci</code> and <code>ls</code> (Windows-only to avoid shadowing <code>/bin/ls</code>). Many common commands have aliases defined for easier typing and ease of use — <code>Copy-Item</code> can be written as <code>cp</code> (for compatibility with Unix), <code>copy</code> (for compatibility with MS-DOS), and <code>ci</code>. In our examples, we could also use <code>measure</code> for <code>Measure-Object</code> and <code>foreach</code> or <code>%</code> for <code>ForEach-Object</code>. Those aliases are a nice thing to have for interactive use, but for scripts, it’s best to use the full names for readability, and to avoid depending on the environment for those aliases.</p>
<h2 id="more-filesystem-operations">More filesystem operations</h2>
<h3 id="files-per-folder">Files per folder</h3>
<p>There’s a photo collection in a <code>Photos</code> folder, grouped into folders. The objective is to see how many <code>.jpg</code> files are in each folder. Here’s the PowerShell solution:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_57265ffb293a3ee263d5186a87f7fc665c0e654a-1"><code data-line-number="1"></code></a></td><td class="code"><code><a id="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-1" name="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-1"></a><span class="nb">PS </span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">&gt;</span> <span class="nb">Get-ChildItem</span> <span class="n">Photos</span><span class="p">/*/*.</span><span class="n">jpg</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_57265ffb293a3ee263d5186a87f7fc665c0e654a-2"><code data-line-number="2"></code></a></td><td class="code"><code><a id="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-2" name="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-2"></a>&nbsp;&nbsp;<span class="nb">Group-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Directory</span><span class="p">.</span><span class="n">Name</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_57265ffb293a3ee263d5186a87f7fc665c0e654a-3"><code data-line-number="3"></code></a></td><td class="code"><code><a id="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-3" name="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-3"></a>&nbsp;&nbsp;<span class="nb">Sort-Object</span> <span class="n">-Property</span> <span class="n">Count</span> <span class="n">-Descending</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_57265ffb293a3ee263d5186a87f7fc665c0e654a-4"><code data-line-number="4"></code></a></td><td class="code"><code><a id="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-4" name="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-4"></a><span class="n">Count</span> <span class="n">Name</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">Group</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_57265ffb293a3ee263d5186a87f7fc665c0e654a-5"><code data-line-number="5"></code></a></td><td class="code"><code><a id="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-5" name="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-5"></a><span class="p">-----</span> <span class="p">----</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">-----</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_57265ffb293a3ee263d5186a87f7fc665c0e654a-6"><code data-line-number="6"></code></a></td><td class="code"><code><a id="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-6" name="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-6"></a>&nbsp;&nbsp;&nbsp;<span class="n">10</span> <span class="n">foo</span> <span class="n">bar</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">{</span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">Photos</span><span class="p">\</span><span class="n">foo</span> <span class="n">bar</span><span class="p">\</span><span class="n">img001</span><span class="p">.</span><span class="n">jpg</span><span class="p">,</span> <span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">Photos</span><span class="p">\</span><span class="n">foo</span> <span class="n">bar</span><span class="p">\</span><span class="n">img002</span><span class="p">.</span><span class="n">jpg</span><span class="p">,</span> <span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">Photos</span><span class="p">\</span><span class="n">foo</span> <span class="n">bar</span><span class="p">\</span><span class="n">img003</span><span class="p">.</span><span class="n">jpg</span><span class="err">…</span><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_57265ffb293a3ee263d5186a87f7fc665c0e654a-7"><code data-line-number="7"></code></a></td><td class="code"><code><a id="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-7" name="code_57265ffb293a3ee263d5186a87f7fc665c0e654a-7"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">2</span> <span class="n">example</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">{</span><span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">Photos</span><span class="p">\</span><span class="n">example</span><span class="p">\</span><span class="n">img101</span><span class="p">.</span><span class="n">jpg</span><span class="p">,</span> <span class="n">C</span><span class="p">:\</span><span class="n">tmp</span><span class="p">\</span><span class="n">Photos</span><span class="p">\</span><span class="n">example</span><span class="p">\</span><span class="n">img201</span><span class="p">.</span><span class="n">jpg</span><span class="p">}</span>
</code></td></tr></table></div>
<p>In Unix land, <a href="https://stackoverflow.com/questions/15216370/how-to-count-number-of-files-in-each-directory">StackOverflow has a lot of solutions</a>. The top solution is <code>du -a | cut -d/ -f2 | sort | uniq -c | sort -nr</code> — a lot of tools mashed together, starting with a tool to check disk usage, and a lot of string manipulation. The second solution uses find, read, and shell globbing. The PowerShell solution is quite simple and obvious to anyone who has ever touched SQL.</p>
<p>The above example works for one level of nesting. For more levels, given <code>Photos\one\two\three.jpg</code>, use <code>Get-ChildItem -Filter '*.jpg' -Recurse Photos</code>, and:</p>
<ul>
<li>Group by <code>$_.Directory.Name</code> (same as before) to get <code>two</code></li>
<li>Group by <code>Split-Path -Parent ([System.IO.Path]::GetRelativePath(&quot;$PWD/Photos&quot;, $_.FullName))</code> to get <code>one/two</code></li>
<li>Group by <code>([System.IO.Path]::GetRelativePath(&quot;$PWD/Photos&quot;, $_.FullName)).Split([System.IO.Path]::DirectorySeparatorChar)[0]</code> to get <code>one</code></li>
</ul>
<p>(All of the above examples work for a single folder as well. The latter two examples don’t work on Windows PowerShell.)</p>
<h3 id="duplicate-finder">Duplicate finder</h3>
<p>Let’s build a simple tool to detect byte-for-byte duplicated files. <code>Get-FileHash</code> is a shell built-in. We can use <code>Group-Object</code> again, and <code>Where-Object</code> to filter only matching objects. Computing the hash of every file is quite inefficient, so we’ll group by the file length first, and then ensure the hashes match. This gives us a nice pipeline of 6 commands:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-1" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-1"></a><span class="c"># Fully spelled out</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-2" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-2"></a><span class="nb">Get-ChildItem</span> <span class="n">-Recurse</span> <span class="o">-File</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-3" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-3"></a>&nbsp;&nbsp;<span class="nb">Group-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Length</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-4" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-4"></a>&nbsp;&nbsp;<span class="nb">Where-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Count</span> <span class="o">-gt</span> <span class="n">1</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-5" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-5"></a>&nbsp;&nbsp;<span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="nb">Group </span><span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-6" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-6"></a>&nbsp;&nbsp;<span class="nb">Group-Object</span> <span class="p">{</span> <span class="p">(</span><span class="nb">Get-FileHash</span> <span class="n">-Algorithm</span> <span class="n">MD5</span> <span class="nv">$_</span><span class="p">).</span><span class="n">Hash</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-7" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-7"></a>&nbsp;&nbsp;<span class="nb">Where-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Count</span> <span class="o">-gt</span> <span class="n">1</span> <span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-8" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-8"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-9" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-9"></a><span class="c"># Using aliases</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-10" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-10"></a><span class="nb">gci </span><span class="n">-Recurse</span> <span class="o">-File</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-11" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-11"></a>&nbsp;&nbsp;<span class="nb">group </span><span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Length</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-12" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-12"></a>&nbsp;&nbsp;<span class="nb">where </span><span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Count</span> <span class="o">-gt</span> <span class="n">1</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-13" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-13"></a>&nbsp;&nbsp;<span class="k">foreach</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="nb">Group </span><span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-14" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-14"></a>&nbsp;&nbsp;<span class="nb">group </span><span class="p">{</span> <span class="p">(</span><span class="nb">Get-FileHash</span> <span class="n">-Algorithm</span> <span class="n">MD5</span> <span class="nv">$_</span><span class="p">).</span><span class="n">Hash</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-15" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-15"></a>&nbsp;&nbsp;<span class="nb">where </span><span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Count</span> <span class="o">-gt</span> <span class="n">1</span> <span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-16"><code data-line-number="16"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-16" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-16"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-17"><code data-line-number="17"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-17" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-17"></a><span class="c"># Using less readable aliases</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-18"><code data-line-number="18"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-18" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-18"></a><span class="nb">gci </span><span class="n">-Recurse</span> <span class="o">-File</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-19"><code data-line-number="19"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-19" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-19"></a>&nbsp;&nbsp;<span class="nb">group </span><span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Length</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-20"><code data-line-number="20"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-20" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-20"></a>&nbsp;&nbsp;<span class="p">?</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Count</span> <span class="o">-gt</span> <span class="n">1</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-21"><code data-line-number="21"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-21" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-21"></a>&nbsp;&nbsp;<span class="p">%</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="nb">Group </span><span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-22"><code data-line-number="22"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-22" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-22"></a>&nbsp;&nbsp;<span class="nb">group </span><span class="p">{</span> <span class="p">(</span><span class="nb">Get-FileHash</span> <span class="n">-Algorithm</span> <span class="n">MD5</span> <span class="nv">$_</span><span class="p">).</span><span class="n">Hash</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_23a175a4070286ab72d28ef04e77af82705e2c7c-23"><code data-line-number="23"></code></a></td><td class="code"><code><a id="code_23a175a4070286ab72d28ef04e77af82705e2c7c-23" name="code_23a175a4070286ab72d28ef04e77af82705e2c7c-23"></a>&nbsp;&nbsp;<span class="p">?</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Count</span> <span class="o">-gt</span> <span class="n">1</span> <span class="p">}</span>
</code></td></tr></table></div>
<h2 id="serious-scripting-software-bill-of-materials">Serious Scripting: Software Bill of Materials</h2>
<p>Software Bills of Materials (SBOMs) and supply chain security are all the rage these days. The boss wants to have something like that, i.e. a CSV file with a list of packages and versions, and only the direct production dependencies. Sure, there exist standards like SPDX, but the boss does not like those pesky “standards”. The backend is written in C#, and the frontend is written in Node.js. Since we care only about the production dependencies, we can look at the <code>.csproj</code> and <code>package.json</code> files. For Node packages, we’ll also try to fetch the license name from the npm API (the API is a bit more complicated for NuGet, so we’ll keep it as a <code>TODO</code> in this example).</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-1" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-1"></a><span class="nv">$ErrorActionPreference</span> <span class="p">=</span> <span class="s2">&quot;Stop&quot;</span> <span class="c"># stop execution on any error</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-2" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-2"></a><span class="nb">Set-StrictMode</span> <span class="n">-Version</span> <span class="n">3</span><span class="p">.</span><span class="n">0</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-3" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-3"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-4" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-4"></a><span class="k">function</span> <span class="nb">Get-CsprojPackages</span><span class="p">(</span><span class="no">[string]</span><span class="nv">$Path</span><span class="p">)</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-5" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-5"></a>&nbsp;&nbsp;<span class="k">return</span> <span class="nb">Select-Xml</span> <span class="n">-Path</span> <span class="nv">$Path</span> <span class="n">-XPath</span> <span class="s1">&#39;//PackageReference&#39;</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-6" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-6"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-7" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-7"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="no">[PSCustomObject]</span><span class="p">@{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-8" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-8"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Name</span> <span class="p">=</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Node</span><span class="p">.</span><span class="n">GetAttribute</span><span class="p">(</span><span class="s2">&quot;Include&quot;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-9" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-9"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Version</span> <span class="p">=</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Node</span><span class="p">.</span><span class="n">GetAttribute</span><span class="p">(</span><span class="s2">&quot;Version&quot;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-10" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-10"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Source</span> <span class="p">=</span> <span class="s1">&#39;nuget&#39;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-11" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-11"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">License</span> <span class="p">=</span> <span class="s1">&#39;TODO&#39;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-12" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-12"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-13" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-13"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-14" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-14"></a><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-15" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-15"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-16"><code data-line-number="16"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-16" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-16"></a><span class="k">function</span> <span class="nb">Get-NodePackages</span><span class="p">(</span><span class="no">[string]</span><span class="nv">$Path</span><span class="p">)</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-17"><code data-line-number="17"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-17" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-17"></a>&nbsp;&nbsp;<span class="nv">$nameToVersion</span> <span class="p">=</span> <span class="p">(</span><span class="nb">Get-Content</span> <span class="n">-Raw</span> <span class="nv">$Path</span> <span class="p">|</span> <span class="nb">ConvertFrom-Json</span><span class="p">).</span><span class="n">dependencies</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-18"><code data-line-number="18"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-18" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-18"></a>&nbsp;&nbsp;<span class="k">return</span> <span class="nv">$nameToVersion</span><span class="p">.</span><span class="n">psobject</span><span class="p">.</span><span class="n">Properties</span> <span class="p">|</span> <span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-19"><code data-line-number="19"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-19" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-19"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="no">[PSCustomObject]</span><span class="p">@{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-20"><code data-line-number="20"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-20" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-20"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Name</span> <span class="p">=</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Name</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-21"><code data-line-number="21"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-21" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-21"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Version</span> <span class="p">=</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Value</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-22"><code data-line-number="22"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-22" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-22"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">Source</span> <span class="p">=</span> <span class="s1">&#39;node&#39;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-23"><code data-line-number="23"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-23" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-23"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">License</span> <span class="p">=</span> <span class="p">(</span><span class="nb">Get-NodeLicense</span> <span class="n">-Name</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Name</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-24"><code data-line-number="24"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-24" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-24"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-25"><code data-line-number="25"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-25" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-25"></a>&nbsp;&nbsp;<span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-26"><code data-line-number="26"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-26" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-26"></a><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-27"><code data-line-number="27"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-27" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-27"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-28"><code data-line-number="28"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-28" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-28"></a><span class="k">function</span> <span class="nb">Get-NodeLicense</span><span class="p">(</span><span class="no">[string]</span><span class="nv">$Name</span><span class="p">)</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-29"><code data-line-number="29"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-29" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-29"></a>&nbsp;&nbsp;<span class="k">try</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-30"><code data-line-number="30"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-30" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-30"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="p">(</span><span class="nb">Invoke-RestMethod</span> <span class="n">-TimeoutSec</span> <span class="n">3</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-31"><code data-line-number="31"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-31" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-31"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="s2">&quot;https://registry.npmjs.org/$Name&quot;</span><span class="p">).</span><span class="n">license</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-32"><code data-line-number="32"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-32" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-32"></a>&nbsp;&nbsp;<span class="p">}</span> <span class="k">catch</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-33"><code data-line-number="33"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-33" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-33"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">return</span> <span class="s2">&quot;???&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-34"><code data-line-number="34"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-34" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-34"></a>&nbsp;&nbsp;<span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-35"><code data-line-number="35"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-35" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-35"></a><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-36"><code data-line-number="36"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-36" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-36"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-37"><code data-line-number="37"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-37" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-37"></a><span class="nv">$csprojData</span> <span class="p">=</span> <span class="p">@(</span><span class="nb">Get-ChildItem</span> <span class="n">-Recurse</span> <span class="n">-Filter</span> <span class="s1">&#39;*.csproj&#39;</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-38"><code data-line-number="38"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-38" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-38"></a>&nbsp;&nbsp;<span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span> <span class="nb">Get-CsprojPackages</span> <span class="nv">$_</span><span class="p">.</span><span class="n">FullName</span> <span class="p">})</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-39"><code data-line-number="39"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-39" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-39"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-40"><code data-line-number="40"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-40" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-40"></a><span class="nv">$nodeData</span> <span class="p">=</span> <span class="p">@(</span><span class="nb">Get-ChildItem</span> <span class="n">-Recurse</span> <span class="n">-Filter</span> <span class="s1">&#39;package.json&#39;</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-41"><code data-line-number="41"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-41" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-41"></a>&nbsp;&nbsp;<span class="nb">Where-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">FullName</span> <span class="o">-notlike</span> <span class="s1">&#39;*node_modules*&#39;</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-42"><code data-line-number="42"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-42" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-42"></a>&nbsp;&nbsp;<span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span> <span class="nb">Get-NodePackages</span> <span class="nv">$_</span><span class="p">.</span><span class="n">FullName</span> <span class="p">})</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-43"><code data-line-number="43"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-43" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-43"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-44"><code data-line-number="44"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-44" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-44"></a><span class="nv">$allData</span> <span class="p">=</span> <span class="nv">$csProjData</span> <span class="p">+</span> <span class="nv">$nodeData</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-45"><code data-line-number="45"></code></a></td><td class="code"><code><a id="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-45" name="code_4fe48e7fd8d202d89c2e576d8d8b41ace059bc6a-45"></a><span class="nv">$allData</span> <span class="p">|</span> <span class="nb">ConvertTo-Csv</span> <span class="n">-NoTypeInformation</span> <span class="p">|</span> <span class="nb">Tee-Object</span> <span class="n">sbom</span><span class="p">.</span><span class="n">csv</span>
</code></td></tr></table></div>
<p>Just like every well-written shell script starts with <code>set -euo pipefail</code>, every PowerShell script should start with <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode?view=powershell-7.4"><code>$ErrorActionPreference = &quot;Stop&quot;</code></a> so that execution is stopped as soon as something goes wrong. Note that this does <em>not</em> affect native commands, you still need to check <code>$LASTEXITCODE</code>. Another useful early command is <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/set-strictmode?view=powershell-7.4"><code>Set-StrictMode -Version 3.0</code></a> to catch undefined variables.</p>
<p>For <code>.csproj</code> files, which are XML, we look for <code>PackageReference</code> elements using XPath, and then build a PSCustomObject out of a hashmap — extracting the appropriate attributes from the <code>PackageReference</code> nodes.</p>
<p>For <code>package.json</code>, we read the file, parse the JSON, and extract the properties of the <code>dependencies</code> object (it’s a map of package names to versions). To get the license, we use <code>Invoke-RestMethod</code>, which takes care of parsing JSON for us.</p>
<p>In the main body of the script, we look for the appropriate files (skipping things under <code>node_modules</code>) and call our parser functions. After retrieving all data, we concatenate the two arrays, convert to CSV, and use <code>Tee-Object</code> to output to a file and to standard output. We get this:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-1" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-1"></a><span class="s">&quot;Name&quot;</span><span class="p">,</span><span class="s">&quot;Version&quot;</span><span class="p">,</span><span class="s">&quot;Source&quot;</span><span class="p">,</span><span class="s">&quot;License&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-2" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-2"></a><span class="s">&quot;AWSSDK.S3&quot;</span><span class="p">,</span><span class="s">&quot;3.7.307.24&quot;</span><span class="p">,</span><span class="s">&quot;nuget&quot;</span><span class="p">,</span><span class="s">&quot;TODO&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-3" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-3"></a><span class="s">&quot;Microsoft.AspNetCore.SpaProxy&quot;</span><span class="p">,</span><span class="s">&quot;7.0.17&quot;</span><span class="p">,</span><span class="s">&quot;nuget&quot;</span><span class="p">,</span><span class="s">&quot;TODO&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-4" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-4"></a><span class="s">&quot;@testing-library/jest-dom&quot;</span><span class="p">,</span><span class="s">&quot;^5.17.0&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-5" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-5"></a><span class="s">&quot;@testing-library/react&quot;</span><span class="p">,</span><span class="s">&quot;^13.4.0&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-6" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-6"></a><span class="s">&quot;@testing-library/user-event&quot;</span><span class="p">,</span><span class="s">&quot;^13.5.0&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-7" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-7"></a><span class="s">&quot;@types/jest&quot;</span><span class="p">,</span><span class="s">&quot;^27.5.2&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-8" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-8"></a><span class="s">&quot;@types/node&quot;</span><span class="p">,</span><span class="s">&quot;^16.18.96&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-9" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-9"></a><span class="s">&quot;@types/react&quot;</span><span class="p">,</span><span class="s">&quot;^18.3.1&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-10" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-10"></a><span class="s">&quot;@types/react-dom&quot;</span><span class="p">,</span><span class="s">&quot;^18.3.0&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-11" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-11"></a><span class="s">&quot;react&quot;</span><span class="p">,</span><span class="s">&quot;^18.3.1&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-12" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-12"></a><span class="s">&quot;react-dom&quot;</span><span class="p">,</span><span class="s">&quot;^18.3.1&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-13" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-13"></a><span class="s">&quot;react-scripts&quot;</span><span class="p">,</span><span class="s">&quot;5.0.1&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;MIT&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-14" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-14"></a><span class="s">&quot;typescript&quot;</span><span class="p">,</span><span class="s">&quot;^4.9.5&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;Apache-2.0&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_7e45a17d671643979b2466b48fce4eb30fc60fa8-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-15" name="code_7e45a17d671643979b2466b48fce4eb30fc60fa8-15"></a><span class="s">&quot;web-vitals&quot;</span><span class="p">,</span><span class="s">&quot;^2.1.4&quot;</span><span class="p">,</span><span class="s">&quot;node&quot;</span><span class="p">,</span><span class="s">&quot;Apache-2.0&quot;</span>
</code></td></tr></table></div>
<p>Could it be done in a different language? Certainly, but PowerShell is really easy to integrate with CI, e.g. <a href="https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#example-running-a-command-using-powershell-core">GitHub Actions</a> or <a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/tasks/reference/powershell-v2?view=azure-pipelines">Azure Pipelines</a>. On Linux, you might be tempted to use Python — and you could get something done equally simply, as long as you don’t mind using the ugly <code>urllib.request</code> library, or alternatively ensuring <code>requests</code> is installed (and then you get into the hell that is Python package management).</p>
<h2 id="using.net-classes">Using .NET classes</h2>
<p>PowerShell is built on top of .NET. This isn’t just the implementation technology — PowerShell gives access to everything the .NET standard library offers. For example, the alternate ways to group photos in multiple subdirectories we’ve explored above involve a call to a static method of the .NET <code>System.IO.Path</code> class.</p>
<p>Other .NET types are also available. Need a HashSet? Here goes:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-1" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-1"></a><span class="n">PS</span><span class="p">&gt;</span> <span class="nv">$set</span> <span class="p">=</span> <span class="nb">New-Object</span> <span class="n">System</span><span class="p">.</span><span class="n">Collections</span><span class="p">.</span><span class="n">Generic</span><span class="p">.</span><span class="n">HashSet</span><span class="no">[string]</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-2" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-2"></a><span class="n">PS</span><span class="p">&gt;</span> <span class="nv">$set</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="s2">&quot;hello&quot;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-3" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-3"></a><span class="n">True</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-4" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-4"></a><span class="n">PS</span><span class="p">&gt;</span> <span class="nv">$set</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="s2">&quot;hello&quot;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-5" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-5"></a><span class="n">False</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-6" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-6"></a><span class="n">PS</span><span class="p">&gt;</span> <span class="nv">$set</span><span class="p">.</span><span class="n">Add</span><span class="p">(</span><span class="s2">&quot;world&quot;</span><span class="p">)</span> <span class="p">|</span> <span class="nb">Out-Null</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-7" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-7"></a><span class="n">PS</span><span class="p">&gt;</span> <span class="nv">$set</span><span class="p">.</span><span class="n">Count</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-8" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-8"></a><span class="n">2</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-9" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-9"></a><span class="n">PS</span><span class="p">&gt;</span> <span class="nv">$set</span> <span class="o">-contains</span> <span class="s2">&quot;hello&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-10" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-10"></a><span class="n">True</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-11" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-11"></a><span class="n">PS</span><span class="p">&gt;</span> <span class="nv">$set</span> <span class="o">-contains</span> <span class="s2">&quot;world&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-12" name="code_a55619a6cf811c2b6ab2c2bf17dbd8f62082087f-12"></a><span class="n">False</span>
</code></td></tr></table></div>
<p>It is also possible to load any .NET DLL into PowerShell (as long as it’s compatible with the .NET version PowerShell is built against) and use it as usual from C# (although possibly with slightly ugly syntax).</p>
<h2 id="sick-windows-tricks">Sick Windows Tricks</h2>
<p>Microsoft supposedly killed off Internet Explorer last year. Attempting to launch <code>iexplore.exe</code> will bring up Microsoft Edge. But you see, Internet Explorer is a crucial part of Windows, and has been so for over two decades. Software vendors have built software that depends on IE being there and being able to show web content. Some of them are using web views, but some of them prefer something else: COM.</p>
<p>COM, or Component Object Model, is Microsoft’s thing for interoperability between different applications and/or components. COM is basically a way for classes offered by different vendors and potentially written in different languages to talk to one another. Under the hood, COM is C++ <code>vtable</code>s plus standard reference counting and class loading/discovery mechanisms. The .NET Framework, and its successor .NET, have always included COM interoperability. The modern WinRT platform is COM on steroids.</p>
<p>Coming back to Internet Explorer, it exposes some COM classes. They were <em>not</em> removed with <code>iexplore.exe</code>. This means you can bring up a regular Internet Explorer window in just two lines of PowerShell:</p>
<div class="highlight"><pre><span></span><span class="nv">$ie</span> <span class="p">=</span> <span class="nb">New-Object</span> <span class="n">-ComObject</span> <span class="n">InternetExplorer</span><span class="p">.</span><span class="n">Application</span>
<span class="nv">$ie</span><span class="p">.</span><span class="n">Visible</span> <span class="p">=</span> <span class="nv">$true</span>
</pre></div>

<p>Why would you do that? The <code>InternetExplorer.Application</code> object lets you control the browser, e.g. you can use <code>$ie.Navigate(&quot;https://example.com/&quot;)</code> to go to a page. Why would you want to launch IE in 2024? I don’t know, I guess you can use it to laugh in the faces of the Microsoft developers who removed the user-accessible shortcuts? But there definitely exist some legacy applications that expect a COM-controllable IE.</p>
<p>We have already explored the possibility of using classes from .NET. .NET comes with a GUI framework named Windows Forms, <a href="https://learn.microsoft.com/en-us/powershell/scripting/samples/creating-a-custom-input-box?view=powershell-7.4">which can be loaded from PowerShell and used to build a GUI.</a> There is no form designer, so it requires manually defining and positioning controls, but it actually works.</p>
<p>PowerShell can also do various Windows management tasks. It can manage boot settings, BitLocker, Hyper-V, networking, storage… For example, to get the percentage of disk space remaining:</p>
<div class="highlight"><pre><span></span><span class="nv">$c</span> <span class="p">=</span> <span class="nb">Get-Volume</span> <span class="n">C</span>
<span class="s2">&quot;</span><span class="p">$((</span><span class="nv">$c</span><span class="p">.</span><span class="n">SizeRemaining</span> <span class="p">/</span> <span class="nv">$c</span><span class="p">.</span><span class="n">Size</span><span class="p">)</span> <span class="p">*</span> <span class="n">100</span><span class="p">)</span><span class="s2">%&quot;</span>
</pre></div>

<h2 id="getting-out-of-powershell-land">Getting out of PowerShell land</h2>
<p>As a shell, PowerShell can obviously launch subprocesses. Unlike something like Python, running a subprocess is as simple as running anything else. If you need to <code>git pull</code>, you just type that. Or you can make PowerShell interact with non-PowerShell commands, reading output and passing arguments:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-1" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-1"></a><span class="nv">$changes</span> <span class="p">=</span> <span class="p">(</span><span class="n">git</span> <span class="n">status</span> <span class="p">-</span><span class="n">-porcelain</span> <span class="p">-</span><span class="n">-null</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-2" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-2"></a><span class="k">if</span> <span class="p">(</span><span class="nv">$LASTEXITCODE</span> <span class="o">-eq</span> <span class="n">128</span><span class="p">)</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-3" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-3"></a>&nbsp;&nbsp;<span class="k">throw</span> <span class="s2">&quot;Not a git repository&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-4" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-4"></a><span class="p">}</span> <span class="k">elseif</span> <span class="p">(</span><span class="nv">$LASTEXITCODE</span> <span class="o">-ne</span> <span class="n">0</span><span class="p">)</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-5" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-5"></a>&nbsp;&nbsp;<span class="k">throw</span> <span class="s2">&quot;Getting changes from git failed&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-6" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-6"></a><span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-7" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-7"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-8" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-8"></a><span class="k">if</span> <span class="p">(</span><span class="nv">$null</span> <span class="o">-eq</span> <span class="nv">$changes</span><span class="p">)</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-9" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-9"></a>&nbsp;&nbsp;<span class="nb">Write-Host</span> <span class="s2">&quot;No changes found&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-10" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-10"></a><span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-11"><code data-line-number="11"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-11" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-11"></a>&nbsp;&nbsp;<span class="nv">$untrackedFiles</span> <span class="p">=</span> <span class="p">@(</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-12"><code data-line-number="12"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-12" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-12"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nv">$changes</span><span class="p">.</span><span class="n">Split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">`0</span><span class="s2">&quot;</span><span class="p">)</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-13"><code data-line-number="13"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-13" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-13"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">Where-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">StartsWith</span><span class="p">(</span><span class="s1">&#39;?? &#39;</span><span class="p">)</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-14"><code data-line-number="14"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-14" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-14"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span> <span class="nv">$_</span><span class="p">.</span><span class="n">Remove</span><span class="p">(</span><span class="n">0</span><span class="p">,</span> <span class="n">3</span><span class="p">)</span> <span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-15"><code data-line-number="15"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-15" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-15"></a>&nbsp;&nbsp;<span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-16"><code data-line-number="16"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-16" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-16"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-17"><code data-line-number="17"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-17" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-17"></a>&nbsp;&nbsp;<span class="c"># Alternate spelling for regex fans:</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-18"><code data-line-number="18"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-18" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-18"></a>&nbsp;&nbsp;<span class="nv">$untrackedFilesForRegexFans</span> <span class="p">=</span> <span class="p">@(</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-19"><code data-line-number="19"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-19" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-19"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nv">$changes</span><span class="p">.</span><span class="n">Split</span><span class="p">(</span><span class="s2">&quot;</span><span class="se">`0</span><span class="s2">&quot;</span><span class="p">)</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-20"><code data-line-number="20"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-20" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-20"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">Where-Object</span> <span class="p">{</span> <span class="nv">$_</span> <span class="o">-match</span> <span class="s1">&#39;^\?\? &#39;</span> <span class="p">}</span> <span class="p">|</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-21"><code data-line-number="21"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-21" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-21"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="k">ForEach</span><span class="n">-Object</span> <span class="p">{</span> <span class="nv">$_</span> <span class="o">-replace</span> <span class="s1">&#39;^\?\? &#39;</span><span class="p">,</span><span class="s1">&#39;&#39;</span> <span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-22"><code data-line-number="22"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-22" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-22"></a>&nbsp;&nbsp;<span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-23"><code data-line-number="23"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-23" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-23"></a>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-24"><code data-line-number="24"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-24" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-24"></a>&nbsp;&nbsp;<span class="k">if</span> <span class="p">(</span><span class="nv">$untrackedFiles</span><span class="p">)</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-25"><code data-line-number="25"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-25" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-25"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">Write-Host</span> <span class="s2">&quot;Opening </span><span class="p">$(</span><span class="nv">$untrackedFiles</span><span class="p">.</span><span class="n">Length</span><span class="p">)</span><span class="s2"> untracked files in VS Code&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-26"><code data-line-number="26"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-26" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-26"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="n">code</span> <span class="nv">$untrackedFiles</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-27"><code data-line-number="27"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-27" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-27"></a>&nbsp;&nbsp;<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-28"><code data-line-number="28"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-28" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-28"></a>&nbsp;&nbsp;&nbsp;&nbsp;<span class="nb">Write-Host</span> <span class="s2">&quot;No untracked files&quot;</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-29"><code data-line-number="29"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-29" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-29"></a>&nbsp;&nbsp;<span class="p">}</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-30"><code data-line-number="30"></code></a></td><td class="code"><code><a id="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-30" name="code_2fac3f71ae9cdda9430242393e19be0d1318b0bf-30"></a><span class="p">}</span>
</code></td></tr></table></div>
<p>I chose to compute untracked files with the help of standard .NET string manipulation methods, but there’s also a regex option. On a related note, there are three content check operators: <code>-match</code> uses regex, <code>-like</code> uses <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_wildcards?view=powershell-7.4">wildcards</a>, and <code>-contains</code> checks collection membership.</p>
<h2 id="profile-script">Profile script</h2>
<p>I use a fairly small profile script that adds some behaviours I’m used to from Unix, and to make Tab completion show a menu. Here are the most basic bits:</p>
<div class="code"><table class="codetable"><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-1"><code data-line-number=" 1"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-1" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-1"></a><span class="nb">Set-PSReadLineOption</span> <span class="n">-HistorySearchCursorMovesToEnd</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-2"><code data-line-number=" 2"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-2" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-2"></a><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="n">UpArrow</span> <span class="n">-Function</span> <span class="n">HistorySearchBackward</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-3"><code data-line-number=" 3"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-3" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-3"></a><span class="nb">Set-PSReadLineKeyHandler</span> <span class="n">-Key</span> <span class="n">DownArrow</span> <span class="n">-Function</span> <span class="n">HistorySearchForward</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-4"><code data-line-number=" 4"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-4" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-4"></a><span class="nb">Set-PSReadlineKeyHandler</span> <span class="n">-Key</span> <span class="n">ctrl</span><span class="p">+</span><span class="n">d</span> <span class="n">-Function</span> <span class="n">DeleteCharOrExit</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-5"><code data-line-number=" 5"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-5" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-5"></a><span class="nb">Set-PSReadlineKeyHandler</span> <span class="n">-Key</span> <span class="n">Tab</span> <span class="n">-Function</span> <span class="n">MenuComplete</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-6"><code data-line-number=" 6"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-6" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-6"></a><span class="nb">Set-PSReadLineOption</span> <span class="n">-AddToHistoryHandler</span> <span class="p">{</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-7"><code data-line-number=" 7"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-7" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-7"></a>&nbsp;&nbsp;<span class="k">param</span><span class="p">(</span><span class="nv">$command</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-8"><code data-line-number=" 8"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-8" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-8"></a>&nbsp;&nbsp;<span class="c"># Commands starting with space are not remembered.</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-9"><code data-line-number=" 9"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-9" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-9"></a>&nbsp;&nbsp;<span class="k">return</span> <span class="o">-not</span> <span class="p">(</span><span class="nv">$command</span> <span class="o">-like</span> <span class="s1">&#39; *&#39;</span><span class="p">)</span>
</code></td></tr><tr><td class="linenos linenodiv"><a href="https://chriswarrick.com/blog/2024/04/29/powershell-the-object-oriented-shell-you-didnt-know-you-needed/#code_774bd000262a6b91d868ee5c7d4e2939b4716853-10"><code data-line-number="10"></code></a></td><td class="code"><code><a id="code_774bd000262a6b91d868ee5c7d4e2939b4716853-10" name="code_774bd000262a6b91d868ee5c7d4e2939b4716853-10"></a><span class="p">}</span>
</code></td></tr></table></div>
<p>Apart from that, I use a few aliases and a pretty prompt with the help of <a href="https://ohmyposh.dev/">oh-my-posh</a>.</p>
<h2 id="the-unusual-and-sometimes-confusing-parts">The unusual and sometimes confusing parts</h2>
<p>PowerShell can be verbose. Some of its syntax is a little quirky, compared to other languages, e.g. the equality and logic operators (for example, <code>-eq</code>, <code>-le</code>, <code>-and</code>). The aliases usually help with remembering commands, but they can’t always be depended on — <code>ls</code> is defined as an alias only on Windows, and Windows PowerShell aliases <code>wget</code> and <code>curl</code> to <code>Invoke-WebRequest</code>, even though all three have completely different command line arguments and outputs (this was removed in PowerShell).</p>
<p>Moreover, the Unix/DOS aliases do not change the argument handling. <code>rm -rf foo</code> is invalid. <code>rm -r foo</code> is, since argument names can be abbreviated as long as the abbreviation is unambiguous. <code>rm -r -f foo</code> is not valid, because <code>-f</code> can be an abbreviation of <code>-Filter</code> or <code>-Force</code> (so <code>rm -r -fo foo</code>) will do. <code>rm foo bar</code> does not work, an array is needed: <code>rm foo,bar</code>.</p>
<p><code>C:\Windows\regedit.exe</code> launches the Registry editor. <code>&quot;C:\Program Files\Mozilla Firefox\firefox.exe&quot;</code> is a string. Launching something with spaces in its name requires the call operator: <code>&amp; &quot;C:\Program Files\Mozilla Firefox\firefox.exe&quot;</code>. PowerShell’s tab completion will add the <code>&amp;</code> if necessary.</p>
<p>There are two function call syntaxes. Calling a function/cmdlet uses the shell-style syntax with argument names: <code>Some-Function -Arg1 value1 -Arg2 value2</code>, and argument names can be abbreviated, and can sometimes be omitted. Calling a method requires a more traditional syntax: <code>$obj.SomeMethod(value1, value2)</code>. Names are case-insensitive in either case.</p>
<p>The escape character is the backtick. The backslash is the path separator in Windows, so making it an escape character would make everything painful on Windows. At least it makes it easy to write regex.</p>
<h2 id="the-ugliest-part">The ugliest part</h2>
<p>The ugliest and the least intuitive part of PowerShell is the handling of single-element arrays. PowerShell <em>really</em> wants to unpack them to a scalar. The command <code>(Get-ChildItem).Length</code> will produce the number of files in the current directory — <em>unless</em> there is exactly one file, in which case it will produce the single file’s size in bytes. And if there are zero items, instead of an empty array, PowerShell produces <code>$null</code>. Sometimes, things will work out in the end (since many cmdlets are happy to get either as inputs), but sometimes, PowerShell must be asked to stop this madness and return an array: <code>@(Get-ChildItem).Length</code>.</p>
<p>The previous example with <code>git status</code> leverages its <code>--null</code> argument to get zero-delimited data, so we expect either <code>$null</code> or a single string according to the rules. If we didn’t want to use <code>--null</code>, we would need to use <code>@(git status --porcelain)</code> to always get an array (but we would also need to remove quotes that <code>git</code> adds to paths that contain spaces).</p>
<h2 id="conclusion">Conclusion</h2>
<p>PowerShell is a fine interactive shell and scripting language. While it does have some warts, it is more powerful than your usual Unix shell, and its strongly-typed, object-oriented code beats <em>stringly-typed</em> <code>sh</code> spaghetti any day.</p>
]]></content:encoded><category>C#/.NET</category><category>.NET</category><category>C#</category><category>PowerShell</category><category>programming</category><category>Windows</category><category>zsh</category></item></channel></rss>