<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Expert Opinion (Posts about Microsoft)</title><link>http://findlay.space/</link><description></description><atom:link href="http://findlay.space/categories/microsoft.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2020 &lt;a href="mailto:justin@findlay.space"&gt;jmoney&lt;/a&gt; 
&lt;a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/"&gt;
&lt;img alt="Creative Commons License BY-NC-SA"
style="border-width:0; margin-bottom:12px;"
src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png"&gt;&lt;/a&gt;</copyright><lastBuildDate>Fri, 11 Sep 2020 20:35:47 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>PowerShell Discard Empty Lines</title><link>http://findlay.space/posts/powershell-discard-empty-lines/</link><dc:creator>jmoney</dc:creator><description>&lt;div&gt;&lt;p&gt;Lately I have found myself needing to normalize the whitespace in a
line-delimited list of strings and have found the following construct very
useful for this need:&lt;/p&gt;
&lt;pre class="code PowerShell"&gt;&lt;a name="rest_code_182f270725004ccc869d707a4353a61c-1"&gt;&lt;/a&gt;&lt;span class="nb"&gt;PS &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;Users&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;Dude&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;\&lt;/span&gt;&lt;span class="n"&gt;MyRepo&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="n"&gt;-n&lt;/span&gt; &lt;span class="n"&gt;19&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;-format&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'%B'&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;  &lt;span class="c"&gt;# Let's trim the empty lines from this git output&lt;/span&gt;
&lt;a name="rest_code_182f270725004ccc869d707a4353a61c-2"&gt;&lt;/a&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;%&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;`&lt;/span&gt;                                       &lt;span class="c"&gt;# Trim any pre/post-whitespace&lt;/span&gt;
&lt;a name="rest_code_182f270725004ccc869d707a4353a61c-3"&gt;&lt;/a&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;$_&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;                                                &lt;span class="c"&gt;# Discard empty lines&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</description><category>Microsoft</category><category>PowerShell</category><guid>http://findlay.space/posts/powershell-discard-empty-lines/</guid><pubDate>Tue, 19 Nov 2019 22:40:49 GMT</pubDate></item><item><title>Visual Studio Power Environment: Jenkins Pipeline Edition</title><link>http://findlay.space/posts/visual-studio-power-environment-jenkins-pipeline-edition/</link><dc:creator>jmoney</dc:creator><description>&lt;div&gt;&lt;p&gt;Rather than bother with custom groovy to hack the &lt;a class="reference external" href="https://jenkins.io/doc/book/pipeline/syntax/"&gt;Jenkins declarative pipeline&lt;/a&gt; environment, let's use a
structural paradigm that has been successful for me because of its simplicity
(the only cost being a reusable custom groovy function) and readability (the
function wrapper demonstrates what it does in salutary clarity).&lt;/p&gt;
&lt;pre class="code groovy"&gt;&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-1"&gt;&lt;/a&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;withVSEnvironment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Boolean&lt;/span&gt; &lt;span class="n"&gt;returnStatus&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-2"&gt;&lt;/a&gt;    &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;powershell&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-3"&gt;&lt;/a&gt;        &lt;span class="nl"&gt;label:&lt;/span&gt; &lt;span class="n"&gt;label&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-4"&gt;&lt;/a&gt;        &lt;span class="nl"&gt;returnStatus:&lt;/span&gt; &lt;span class="n"&gt;returnStatus&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-5"&gt;&lt;/a&gt;        &lt;span class="nl"&gt;script:&lt;/span&gt; &lt;span class="s2"&gt;"""&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-6"&gt;&lt;/a&gt;&lt;span class="s2"&gt;            foreach (\$_ in cmd /c "`"%VS140COMNTOOLS%`"..\\..\\vc\\bin\\vcvars32.bat &amp;gt; nul 2&amp;gt;&amp;amp;1 &amp;amp; SET") {&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-7"&gt;&lt;/a&gt;&lt;span class="s2"&gt;                if (\$_ -match '^([^=]+)=(.*)') {&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-8"&gt;&lt;/a&gt;&lt;span class="s2"&gt;                    [System.Environment]::SetEnvironmentVariable(\$matches[1], \$matches[2])&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-9"&gt;&lt;/a&gt;&lt;span class="s2"&gt;                }&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-10"&gt;&lt;/a&gt;&lt;span class="s2"&gt;            }&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-11"&gt;&lt;/a&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-12"&gt;&lt;/a&gt;&lt;span class="s2"&gt;            $script&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-13"&gt;&lt;/a&gt;&lt;span class="s2"&gt;        """&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-14"&gt;&lt;/a&gt;    &lt;span class="o"&gt;)&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-15"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;returnStatus&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-16"&gt;&lt;/a&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-17"&gt;&lt;/a&gt;    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-18"&gt;&lt;/a&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-19"&gt;&lt;/a&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-20"&gt;&lt;/a&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-21"&gt;&lt;/a&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-22"&gt;&lt;/a&gt;    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-23"&gt;&lt;/a&gt;    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-24"&gt;&lt;/a&gt;        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Stage Left'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-25"&gt;&lt;/a&gt;            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-26"&gt;&lt;/a&gt;                &lt;span class="n"&gt;withVSEnvironment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-27"&gt;&lt;/a&gt;                    &lt;span class="s1"&gt;'Building with PowerShell!!!'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-28"&gt;&lt;/a&gt;                    &lt;span class="n"&gt;False&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;// returnStatus&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-29"&gt;&lt;/a&gt;                    &lt;span class="s1"&gt;'''&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-30"&gt;&lt;/a&gt;&lt;span class="s1"&gt;                    # No weak cmd script here&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-31"&gt;&lt;/a&gt;&lt;span class="s1"&gt;                    MSBuild.exe Source/Answer/The_Solution.sln /m /t:Clean,Rebuild&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-32"&gt;&lt;/a&gt;&lt;span class="s1"&gt;                    '''&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-33"&gt;&lt;/a&gt;                &lt;span class="o"&gt;)&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-34"&gt;&lt;/a&gt;            &lt;span class="o"&gt;}&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-35"&gt;&lt;/a&gt;        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-36"&gt;&lt;/a&gt;    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;a name="rest_code_f4ff8a9bee594e0daa66aeff0e696bdd-37"&gt;&lt;/a&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</description><category>Batch</category><category>Groovy</category><category>Jenkins</category><category>Microsoft</category><category>PowerShell</category><category>Visual Studio</category><guid>http://findlay.space/posts/visual-studio-power-environment-jenkins-pipeline-edition/</guid><pubDate>Tue, 12 Nov 2019 22:19:59 GMT</pubDate></item><item><title>Visual Studio Power Environment</title><link>http://findlay.space/posts/visual-studio-power-environment/</link><dc:creator>jmoney</dc:creator><description>&lt;div&gt;&lt;p&gt;It is sometimes interesting to speculate about how unusual feature patterns in
Microsoft projects may reflect the traditions or prejudices of the teams
involved with creating and evolving those projects.  Today's example is
&lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;"%VS140COMNTOOLS%"..\..\vc\bin\vcvars32.bat&lt;/span&gt;&lt;/code&gt;, that wily little batch script
that mucks your command environment enough to enable most Visual Studio
declarative-like thingies to happen (easily) on the command prompt.&lt;/p&gt;
&lt;p&gt;So PowerShell has been around for like 17 years now (if you include the Monad
proto period).  That's enough time for an effective rewrite or two of the
Visual Studio codebase and yet we're still stuck with this inconvenient script
written in possibly the worst shell still in popular use today.  How can we get
it to work with possibly the best shell in popular use today?  Unfortunately
there is no single command that will dump the environment of a &lt;code class="docutils literal"&gt;cmd&lt;/code&gt;
subprocess into the parent &lt;code class="docutils literal"&gt;powershell&lt;/code&gt; environment.  I found several hacks
online proposing to do this, the most correct and elegant being
&lt;a class="reference external" href="https://github.com/nightroman/PowerShelf/blob/master/Invoke-Environment.ps1"&gt;Invoke-Environment&lt;/a&gt;.&lt;/p&gt;
&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;[Digression] reStructureText's link formatting is &lt;a class="reference external" href="https://stackoverflow.com/questions/4743845/format-text-in-a-link-in-restructuredtext#comment65215146_4836544"&gt;egregiously inferior&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;What I really wanted was some Groovy code that will dynamically modify the
environment of a declarative pipeline with the results of &lt;code class="docutils literal"&gt;vcvars32.bat&lt;/code&gt;.
Jenkins pipeline allows for &lt;a class="reference external" href="https://jenkins.io/doc/book/pipeline/jenkinsfile/#setting-environment-variables-dynamically"&gt;setting environment variables dynamically&lt;/a&gt;,
but the dynamism packaged into this feature only allows for arbitrary values
for a set of &lt;em&gt;a priori&lt;/em&gt; variable names.  The &lt;code class="docutils literal"&gt;vcvars32.bat&lt;/code&gt; script sets an
indeterminate set of variable names.  There may still be a way to do this, but
my Groovy-fu does not show me how to edit the &lt;code class="docutils literal"&gt;env&lt;/code&gt; object at sufficient
introspection.&lt;/p&gt;
&lt;p&gt;Here is the essential functionality of &lt;code class="docutils literal"&gt;&lt;span class="pre"&gt;Invoke-Environment&lt;/span&gt;&lt;/code&gt; applied to
&lt;code class="docutils literal"&gt;vcvars32.bat&lt;/code&gt;.  This is what I used to prime the PowerShell environment for
Visual Studio work by pasting the code block directly into the &lt;a class="reference external" href="https://jenkins.io/doc/pipeline/steps/workflow-durable-task-step/#powershell-powershell-script"&gt;powershell()&lt;/a&gt;
step before executing Visual Studio commands.  This is not the most elegant,
but it is only a few more lines than directly sourcing the batch script and
seems to be the plainest way to absorb its environment.&lt;/p&gt;
&lt;pre class="code powershell"&gt;&lt;a name="rest_code_28bff3c7ea374c6c940e6f6b54354245-1"&gt;&lt;/a&gt;&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;`"&lt;/span&gt;&lt;span class="s2"&gt;%VS140COMNTOOLS%&lt;/span&gt;&lt;span class="se"&gt;`"&lt;/span&gt;&lt;span class="s2"&gt;..\\..\\vc\\bin\\vcvars32.bat &amp;gt; nul 2&amp;gt;&amp;amp;1 &amp;amp; SET"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;a name="rest_code_28bff3c7ea374c6c940e6f6b54354245-2"&gt;&lt;/a&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_&lt;/span&gt; &lt;span class="o"&gt;-match&lt;/span&gt; &lt;span class="s1"&gt;'^([^=]+)=(.*)'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;a name="rest_code_28bff3c7ea374c6c940e6f6b54354245-3"&gt;&lt;/a&gt;        &lt;span class="no"&gt;[System.Environment]&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nv"&gt;$matches&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;a name="rest_code_28bff3c7ea374c6c940e6f6b54354245-4"&gt;&lt;/a&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;a name="rest_code_28bff3c7ea374c6c940e6f6b54354245-5"&gt;&lt;/a&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;div class="admonition note"&gt;
&lt;p class="admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;If you are using this in a Jenkins pipeline, all &lt;code class="docutils literal"&gt;$&lt;/code&gt;'s will need to be
escaped, &lt;code class="docutils literal"&gt;\$&lt;/code&gt;, to signify that they signal PowerShell variables and not
Groovy variables.  Also &lt;code class="docutils literal"&gt;`&lt;/code&gt; is PowerShell's escape character, so &lt;code class="docutils literal"&gt;`"&lt;/code&gt;
is an escaped quote.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;</description><category>Batch</category><category>Groovy</category><category>Jenkins</category><category>Microsoft</category><category>PowerShell</category><category>Visual Studio</category><guid>http://findlay.space/posts/visual-studio-power-environment/</guid><pubDate>Fri, 26 Jul 2019 21:41:13 GMT</pubDate></item></channel></rss>