<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>History · Loosely Decoupled</title>
    <link>https://looselydecoupled.com/topics/history/</link>
    <description>Where a current practice came from, and what it inherited.</description>
    <language>en-us</language>
    
    <copyright>© 2026 Emmanuel Tsouris</copyright>
    <lastBuildDate>Mon, 21 Sep 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://looselydecoupled.com/topics/history/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>How VBScript&#39;s Friction Produced PowerShell&#39;s Object Pipeline</title>
      <link>https://looselydecoupled.com/vbscript-primitive-glue-retrospective/</link>
      <guid isPermaLink="true">https://looselydecoupled.com/vbscript-primitive-glue-retrospective/</guid>
      <pubDate>Fri, 26 Dec 2025 00:00:00 +0000</pubDate>
      <dc:creator>Emmanuel Tsouris</dc:creator>
      <category>VBScript</category>
      <category>PowerShell</category>
      <category>History</category>
      <category>Windows Server</category>
      <category>DevOps</category>
      
      <description>The friction that moved Windows automation from VBScript&#39;s text to PowerShell&#39;s objects also moved cloud tooling from scripts to declarative templates.</description>
      <content:encoded><![CDATA[<p>If you started in the cloud era, infrastructure as code is JSON, HCL and YAML:
declare a state, and the provider makes it so. In the Windows environments I
managed in the early 2000s, state wasn&rsquo;t declared. It was coerced, one
script at a time, and the language was VBScript.</p>
<p>My claim: VBScript&rsquo;s friction is what produced PowerShell&rsquo;s object pipeline,
and the same friction is what moved cloud tooling from imperative scripts to
declarative templates. The history is worth a few minutes because it predicts
what the next tool will fix.</p>
<h2 id="on-error-resume-next"><code>On Error Resume Next</code><a class="heading-anchor" href="https://looselydecoupled.com/vbscript-primitive-glue-retrospective/#on-error-resume-next"
     aria-label="Link to section: On Error Resume Next" data-pagefind-ignore></a>
</h2>
<p>In 2003, mapping a printer by security group or reading the BIOS version of
500 servers had no command. It had Notepad, and a <code>.vbs</code> file run by Windows
Script Host.</p>
<p>VBScript had no safety rails. The line that opened most production scripts
was:</p>
<div class="code-block code-block--wrap" data-copyable data-copy-label="VBScript">
  <div class="code-block__head"><span class="code-block__lang">VBScript</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vb" data-lang="vb"><span class="line"><span class="cl"><span class="k">On</span> <span class="k">Error</span> <span class="k">Resume</span> <span class="k">Next</span></span></span></code></pre></div></div>
  </div>
</div><p>It tells the interpreter to ignore any failing line and carry on. Distributed
systems talk about failing fast; a VBScript failed silently and left the
system in whatever state the last successful line produced. Nobody wrote it
out of carelessness. Without it, one missing printer stopped that user&rsquo;s logon
script at that line, and every mapping after it was skipped. Structured error
handling in VBScript was awkward enough that swallowing errors was the
pragmatic choice.</p>
<h2 id="wmi-as-the-engine-vbscript-as-the-crank">WMI as the engine, VBScript as the crank<a class="heading-anchor" href="https://looselydecoupled.com/vbscript-primitive-glue-retrospective/#wmi-as-the-engine-vbscript-as-the-crank"
     aria-label="Link to section: WMI as the engine, VBScript as the crank" data-pagefind-ignore></a>
</h2>
<p>The lasting legacy of that era isn&rsquo;t VBScript&rsquo;s syntax. It&rsquo;s that VBScript
was how a generation of administrators met WMI, Windows Management
Instrumentation, Microsoft&rsquo;s implementation of the DMTF&rsquo;s WBEM standard. WMI
exposed the operating system as a queryable database: disks, services and
processes as rows, with a SQL-like language to select them.</p>
<p>The database was good. The interface to it was this:</p>
<div class="code-block" data-copyable data-copy-label="VBScript">
  <div class="code-block__head"><span class="code-block__lang">VBScript</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-vb" data-lang="vb"><span class="line"><span class="cl"><span class="c">&#39; Free space per logical disk
</span></span></span><span class="line"><span class="cl"><span class="n">strComputer</span> <span class="o">=</span> <span class="s">&#34;.&#34;</span>
</span></span><span class="line"><span class="cl"><span class="k">Set</span> <span class="n">objWMIService</span> <span class="o">=</span> <span class="n">GetObject</span><span class="p">(</span><span class="s">&#34;winmgmts:\\&#34;</span> <span class="o">&amp;</span> <span class="n">strComputer</span> <span class="o">&amp;</span> <span class="s">&#34;\root\cimv2&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">Set</span> <span class="n">colItems</span> <span class="o">=</span> <span class="n">objWMIService</span><span class="p">.</span><span class="n">ExecQuery</span><span class="p">(</span><span class="s">&#34;Select * from Win32_LogicalDisk&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">For</span> <span class="k">Each</span> <span class="n">objItem</span> <span class="ow">in</span> <span class="n">colItems</span>
</span></span><span class="line"><span class="cl">    <span class="n">Wscript</span><span class="p">.</span><span class="n">Echo</span> <span class="s">&#34;Disk: &#34;</span> <span class="o">&amp;</span> <span class="n">objItem</span><span class="p">.</span><span class="n">Name</span> <span class="o">&amp;</span> <span class="s">&#34; Free Space: &#34;</span> <span class="o">&amp;</span> <span class="n">objItem</span><span class="p">.</span><span class="n">FreeSpace</span>
</span></span><span class="line"><span class="cl"><span class="k">Next</span></span></span></code></pre></div></div>
  </div>
</div><p>Seven lines to read one property, and every line is ceremony: a COM moniker,
a query string, a loop and string concatenation to print. The verbosity forced
administrators to learn loops, variable types and COM objects, which is the
one thing VBScript did for the profession. It was a high barrier, and it
separated the people who clicked from the people who scripted.</p>
<h2 id="from-parsing-text-to-passing-objects">From parsing text to passing objects<a class="heading-anchor" href="https://looselydecoupled.com/vbscript-primitive-glue-retrospective/#from-parsing-text-to-passing-objects"
     aria-label="Link to section: From parsing text to passing objects" data-pagefind-ignore></a>
</h2>
<p>Every VBScript that read another program&rsquo;s output parsed text. Jeffrey
Snover&rsquo;s Monad Manifesto (2002), the design document behind PowerShell 1.0
(2006), names that practice as the problem. Text output is a contract nobody
declared, so a script is coupled to the exact formatting of whatever it
reads. When &ldquo;Free Space&rdquo; became &ldquo;FreeSpace&rdquo;, the script broke.</p>
<p>PowerShell separated the data from its presentation. The same query, in the
modern cmdlet:</p>
<div class="code-block code-block--wrap" data-copyable data-copy-label="PowerShell">
  <div class="code-block__head"><span class="code-block__lang">PowerShell</span>
  </div>
  <div class="code-block__scroll">
    <div data-copy-source><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-powershell" data-lang="powershell"><span class="line"><span class="cl"><span class="c"># Objects, not text</span>
</span></span><span class="line"><span class="cl"><span class="nb">Get-CimInstance</span> <span class="n">Win32_LogicalDisk</span> <span class="p">|</span> <span class="nb">Select-Object</span> <span class="n">DeviceID</span><span class="p">,</span> <span class="n">FreeSpace</span></span></span></code></pre></div></div>
  </div>
</div><p>Side by side, the two snippets show a change of model, not of syntax.
VBScript was imperative: you told the computer how to connect, how to iterate
and how to print. PowerShell is declarative at the call site: you ask for the
object and the pipeline handles the rest. Formatting happens once, at the end,
by a formatter that knows the object&rsquo;s type.</p>
<h2 id="why-this-matters-for-cloud-work">Why this matters for cloud work<a class="heading-anchor" href="https://looselydecoupled.com/vbscript-primitive-glue-retrospective/#why-this-matters-for-cloud-work"
     aria-label="Link to section: Why this matters for cloud work" data-pagefind-ignore></a>
</h2>
<p>Cloud tooling made the same move, a decade later. The first generation of AWS
automation was imperative scripts around the CLI: create an instance, wait,
attach a volume, tag it. CloudFormation (2011) and Terraform (2014) replaced
that with a declared end state and an engine that computes the steps.</p>
<p>VBScript was the imperative-scripts phase of Windows administration. It was
hard to debug and didn&rsquo;t scale past the person who wrote it. It was also
necessary: it&rsquo;s how administration got from the GUI to anything automated at
all, and the pain of it is what made the next model&rsquo;s advantages legible.</p>
<h2 id="what-would-change-my-mind">What would change my mind<a class="heading-anchor" href="https://looselydecoupled.com/vbscript-primitive-glue-retrospective/#what-would-change-my-mind"
     aria-label="Link to section: What would change my mind" data-pagefind-ignore></a>
</h2>
<p>The argument rests on one causal claim: that text-parsing friction, not some
other pressure, is what produced the object pipeline. The Monad Manifesto
supports it in Snover&rsquo;s own words, which is the best evidence available short
of the design meetings. The account could be a retrospective tidying of
decisions made for other reasons, such as .NET adoption inside Microsoft. If
it is, the lineage still holds but the lesson doesn&rsquo;t.</p>
<p>I still keep a folder of old <code>.vbs</code> scripts. I do not run them. They are a
record of what the tooling cost before someone decided the cost was the
problem. The next time a CloudFormation template takes an afternoon to debug,
the alternative was <code>On Error Resume Next</code>.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
