<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alex Sarafian</title>
    <description>The latest articles on DEV Community by Alex Sarafian (@sarafian).</description>
    <link>https://dev.to/sarafian</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186518%2F919b1a4b-68fe-47fe-b32f-da4eb69a3575.jpeg</url>
      <title>DEV Community: Alex Sarafian</title>
      <link>https://dev.to/sarafian</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sarafian"/>
    <language>en</language>
    <item>
      <title>Upgrade from Pester v4 to v5</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Sat, 26 Jun 2021 12:54:58 +0000</pubDate>
      <link>https://dev.to/sarafian/upgrade-from-pester-v4-to-v5-43g3</link>
      <guid>https://dev.to/sarafian/upgrade-from-pester-v4-to-v5-43g3</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Recently somebody submitted a pull request in my &lt;a href="https://www.powershellgallery.com/packages/SemVerPS/"&gt;SemVerPS&lt;/a&gt; which failed with the &lt;a href="https://www.appveyor.com/"&gt;Appveyor&lt;/a&gt;'s CI pipeline. I've not been hands on for a while and it took me some time to figure out that the tests were failing and why. It turns out that there has been a new version (v5) of Pester which &lt;a href="https://pester-docs.netlify.app/docs/migrations/breaking-changes-in-v5"&gt;broke compatibility&lt;/a&gt; compared with the previous version (v4). Soon, it became clear to me that that I would have to make significant changes which meant that I had to work on my &lt;a href="https://github.com/Sarafian/PowerShellTemplate"&gt;PowerShellTemplate&lt;/a&gt; repository, where advanced Pester test cases are also covered. &lt;/p&gt;

&lt;p&gt;All the changes are available in this &lt;a href="https://github.com/Sarafian/PowerShellTemplate/pull/6"&gt;pull request&lt;/a&gt; and in the following sections I'll focus on the major adaptations required. To help showcase the requires changes, I'll provide the relevant extracts from the V4 and V5. Keep in mind that the extracts are relevant to the [PowerShelltTemplate] repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invoke-Pester adaptations
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://pester-docs.netlify.app/docs/commands/Invoke-Pester"&gt;Invoke-Pester&lt;/a&gt; cmdlet has many changes when used in an "advanced" mode. Basic execution still works but when the cmdlet is integrated in a CI pipeline like I do in the [PowerShelltTemplate] repository with the &lt;code&gt;CI\Invoke-Pester.ps1&lt;/code&gt;, then you probably need to use some of the advanced functionality. The main difference is that with version 5, the cmdlet is driven by a configuration variable that is initialized by the &lt;a href="https://pester-docs.netlify.app/docs/commands/New-PesterConfiguration"&gt;New-PesterConfiguration&lt;/a&gt; cmdlet. The cmdlet's documentation page provides an explanation for all options but for some it is not clear what they really do. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V4 extracts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$splat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Script&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$srcPath&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;PassThru&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;OutputFormat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"NUnitXml"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;OutputFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$outputFile&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;ExcludeTag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ExcludeTag&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Tag&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Activate code coverage&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$CodeCoverage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$codeCoveragePath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$outputFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;".codecoverage.xml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$splat&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="p"&gt;@{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;CodeCoverage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$srcPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Exclude&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"*.Tests.ps1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"*.NotReady.ps1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Src\Tests\**"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Filter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*.ps1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Recurse&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="nx"&gt;Select&lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ExpandProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FullName&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nx"&gt;CodeCoverageOutputFile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$codeCoveragePath&lt;/span&gt;&lt;span class="w"&gt;        
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$pesterResult&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Invoke-Pester&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;splat&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;V5 extracts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# https://pester-docs.netlify.app/docs/commands/New-PesterConfiguration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;New-PesterConfiguration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$srcPath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PassThru&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$srcPath&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$Tag&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Filter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExcludeTag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$ExcludeTag&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TestResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TestResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OutputFormat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"NUnitXml"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TestResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OutputPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$outputFile&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Output&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Verbosity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Detailed"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# If you want full log uncomment&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#$pesterConfiguration.Output.Verbosity="Diagnostic"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Activate code coverage&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$CodeCoverage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CodeCoverage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Enabled&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#    $pesterConfiguration.CodeCoverage.OutputFormat="JaCoCo"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CodeCoverage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;OutputPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$outputFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".xml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;".codecoverage.xml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$pesterResult&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Invoke-Pester&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Configuration&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$pesterConfiguration&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that most features were moved into the configuration variable but there are also some new welcoming options especially with regards to diagnostics. I chose &lt;code&gt;Detailed&lt;/code&gt; for &lt;code&gt;$pesterConfiguration.Output.Verbosity&lt;/code&gt; because I found it to be the right balance between knowing what Pester is doing and logging. In the same &lt;a href="https://github.com/Sarafian/PowerShellTemplate/pull/6"&gt;pull request&lt;/a&gt; you will also notice that I moved the following block from a global script check to specifically within the AppVeyors block. This is because the new version reacts differently when there are test errors. There are configuration variables for better control and maybe I missed something but I found this to be the easiest adaptation. You need to first upload the test results to AppVeyor and therefore you can't instruct Pester to exit the script from within Pester. This is also documented in AppVeyor's [running test] page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pesterResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FailedCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-gt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
     &lt;/span&gt;&lt;span class="kr"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nv"&gt;$pesterResult&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FailedCount&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; tests failed."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test file adaptations
&lt;/h2&gt;

&lt;p&gt;Big differences in the test files &lt;code&gt;*Tests.ps1&lt;/code&gt; are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Everything has to run in a block defined in a Pester function like &lt;code&gt;BeforeAll&lt;/code&gt; or &lt;code&gt;BeforeEach&lt;/code&gt;. They also adjusted the &lt;code&gt;New-Fixture&lt;/code&gt; cmdlet.&lt;/li&gt;
&lt;li&gt;All &lt;code&gt;Should&lt;/code&gt; expressions need to use &lt;code&gt;-&lt;/code&gt; with the &lt;code&gt;Be&lt;/code&gt;, &lt;code&gt;Throw&lt;/code&gt; etc assertions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Throw&lt;/code&gt; statements used to match text without wildcards. Now they are matched by comparison unless wildcards &lt;code&gt;*&lt;/code&gt; are provided similar to &lt;code&gt;-Like&lt;/code&gt; statements.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;V4 extracts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$here&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Split-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Parent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$MyInvocation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MyCommand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Path&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$sut&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Split-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Leaf&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$MyInvocation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MyCommand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-replace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'\.Tests\.'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$here&lt;/span&gt;&lt;span class="s2"&gt;\&lt;/span&gt;&lt;span class="nv"&gt;$sut&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Just invoke"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Get-M1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Error"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;V5 extracts&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;BeforeAll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$PSCommandPath&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.Tests.ps1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.ps1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Just invoke"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Get-M1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Error"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kr"&gt;throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Throw&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*error*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Mocking and InModuleScope adaptations
&lt;/h2&gt;

&lt;p&gt;The hardest part was with mocking modules, leveraging common functionality (like a random generator) and doing all this within an &lt;code&gt;InModuleScope&lt;/code&gt; block. In V4 there were a lot of gaps but the implementations were less verbose. The new strictness is welcome but there is now more code required especially. This is because the &lt;code&gt;InModuleScope&lt;/code&gt; is really a new scope (hence the name) and won't recognize local variables from other blocks, like e.g. a random string.&lt;/p&gt;

&lt;p&gt;To better understand the following differences, I need to first explain that in my code, I use a common function to generate random strings and numbers. I do this, to make sure that all unit tests work with clean values and nothing is overlooked. This is important, because the scripting nature of PowerShell allows for left over variables from within the same block or a previous execution which sometimes don't raise errors. My random generator is implemented in the &lt;code&gt;Get-RandomValue&lt;/code&gt; cmdlet and is found in &lt;code&gt;Src/Tests/Cmdlets-Helpers/Get-RandomValue.ps1&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Get-RandomValue.ps1&lt;/code&gt; got also adjusted because now it is not necessary to define it as global function. In the past the function would be declared as &lt;code&gt;function global:Get-RandomValue&lt;/code&gt; but now it can be a normal one and be declared as &lt;code&gt;function Get-RandomValue&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The goal is to test and mock the private cmdlet &lt;code&gt;Get-M1Private&lt;/code&gt; which is called by the public &lt;code&gt;Get-M1&lt;/code&gt; cmdlet. Notice that when mocking the &lt;code&gt;Get-M1Private&lt;/code&gt;, I always use a fresh random string using &lt;code&gt;Get-RandomValue&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V4 file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$PSScriptRoot&lt;/span&gt;&lt;span class="n"&gt;\..\..\..\Modules\Import-M1.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# Dot sourcing&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$PSScriptRoot&lt;/span&gt;&lt;span class="n"&gt;\..\..\Cmdlets-Helpers\Get-RandomValue.ps1&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"InModuleScope"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InModuleScope M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;InModuleScope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;M1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get-M1Private"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;Get-M1Private&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1 Private"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get-M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;Get-M1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"InModuleScope"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"MockPrivate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InModuleScope M1 Mock private"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;InModuleScope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;M1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Get-RandomValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-String&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get-M1Private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get-M1Private Mocked"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;Get-M1Private&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get-M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;Get-M1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Module"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Module"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Get-M1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Remove-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;M1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A couple of things that require special attention with the V5 adaptations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;InModuleScope&lt;/code&gt; block needs to move inside each &lt;code&gt;It&lt;/code&gt; block. This is until version &lt;code&gt;5.3.0&lt;/code&gt; as mentioned in this &lt;a href="https://github.com/pester/Pester/issues/2009"&gt;issue&lt;/a&gt; raised on Pester's gitub repository. &lt;/li&gt;
&lt;li&gt;The variable &lt;code&gt;mockedValue&lt;/code&gt; which is assigned in the &lt;code&gt;BeforeEach&lt;/code&gt; block must now be provided to the &lt;code&gt;InModuleScope&lt;/code&gt; block as a function parameter because without the parameter the &lt;code&gt;Get-M1Private| Should -BeExactly $mockedValue&lt;/code&gt; will fail because the expected value is actually &lt;code&gt;$null&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;As the module &lt;code&gt;M1&lt;/code&gt; is imported inside a &lt;code&gt;BeforeAll&lt;/code&gt; block, it must also be removed inside an &lt;code&gt;AfterAll&lt;/code&gt; block.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;V5 file&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;BeforeAll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$PSScriptRoot&lt;/span&gt;&lt;span class="n"&gt;\..\..\..\Modules\Import-M1.ps1&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$PSScriptRoot&lt;/span&gt;&lt;span class="nx"&gt;\..\..\Cmdlets-Helpers\Get-RandomValue.ps1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"InModuleScope"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InModuleScope M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get-M1Private"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;InModuleScope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;M1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;Get-M1Private&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1 Private"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get-M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Get-M1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"InModuleScope"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"MockPrivate"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InModuleScope M1 Mock private"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;BeforeEach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Get-RandomValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-String&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ModuleName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;M1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get-M1Private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nv"&gt;$inModuleScopeParameters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nx"&gt;mockedValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get-M1Private Mocked"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;InModuleScope&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;M1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Parameters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$inModuleScopeParameters&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="kr"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="n"&gt;Get-M1Private&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;It&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get-M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Get-M1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$mockedValue&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;Describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Module"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Tag&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Module"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Get-M1&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-BeExactly&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"M1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;AfterAll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Remove-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;M1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;What I didn't do is adapt all &lt;code&gt;Describe&lt;/code&gt; and &lt;code&gt;It&lt;/code&gt; blocks and declare the name properly using the &lt;code&gt;-Name&lt;/code&gt; parameter. I expect that in the next version I'll get a similar error with the &lt;code&gt;This whole Legacy-parameter set is deprecated&lt;/code&gt; that `Invoke-Pester throws when not using the configuration variable with legacy options.&lt;/p&gt;

&lt;p&gt;Overall, I feel that Pester has improved and that this was a step to the right direction but it needs getting used to it. From my experience, the &lt;code&gt;InModuleScope&lt;/code&gt; adaptations were the hardest ones to figure out. Some extra quirks had to be addressed in my other repositories &lt;a href="https://www.powershellgallery.com/packages/MarkdownPS/"&gt;MarkdownPS&lt;/a&gt; and &lt;a href="https://www.powershellgallery.com/packages/SemVerPS/"&gt;SemVerPS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you are an owner of a PowerShell module with full unit tests and code coverage, then I hope I hope you found this post useful.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>pester</category>
    </item>
    <item>
      <title>PlantUML tips and tricks</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Fri, 12 Mar 2021 16:54:17 +0000</pubDate>
      <link>https://dev.to/sarafian/tips-and-tricks-for-plantuml-1030</link>
      <guid>https://dev.to/sarafian/tips-and-tricks-for-plantuml-1030</guid>
      <description>&lt;p&gt;I love &lt;a href="https://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt;. It has it's limitations but if the size and the complexity of the diagrams can be contained, then it offers great benefits. The fact that the format is in text is so powerful in software engineering because it can be attached to any process with change management over source control. Also, it is great for &lt;a href="https://www.atlassian.com/software/confluence" rel="noopener noreferrer"&gt;Confluence&lt;/a&gt; when the &lt;a href="https://marketplace.atlassian.com/apps/1215115/plantuml-diagrams-for-confluence?hosting=cloud&amp;amp;tab=overview" rel="noopener noreferrer"&gt;PlantUML Diagrams for Confluence&lt;/a&gt; add-on is enabled.&lt;/p&gt;

&lt;p&gt;With this post I want to share some tips and tricks from my experience using it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Layout orientation in component diagram
&lt;/h1&gt;

&lt;p&gt;When using the component diagram, often the layout seems to have a mind of it's own. You can try to provide some guidelines to the rendering component by adding directions in the arrows (e.g. &lt;code&gt;-l-&amp;gt;&lt;/code&gt;) but when that doesn't work, I try to achieve an optimal layout by reorganizing the appearance of the components, especially when they are nested with e.g. &lt;code&gt;package&lt;/code&gt;. It is a bit strange, but order in rendering seems to follow a reverse order of appearance in the script.&lt;/p&gt;

&lt;h1&gt;
  
  
  Multiple and options flows in a component diagram
&lt;/h1&gt;

&lt;p&gt;Sometimes, I want to have multiple flows within a component diagram. In this case and depending on the case, I use color coding with each arrow (e.g. &lt;code&gt;A -&amp;gt; B #Green : text&lt;/code&gt;) and possibly add a legend at the end&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml

package "Some Group" {
  HTTP - [First Component]
  [Another Component]
}

node "Other Groups" {
  FTP - [Second Component]
  [First Component] --&amp;gt; FTP
}

cloud {
  [Example 1]
}


database "MySql" {
  folder "This is my folder" {
    [Folder 3]
  }
  frame "Foo" {
    [Frame 4]
  }
}

[Another Component] --&amp;gt; [Example 1] #Blue
[Example 1] --&amp;gt; [Folder 3] #Blue
[Folder 3] --&amp;gt; [Frame 4] #Blue


legend
    | Color | Flow |
    |&amp;lt;#Red&amp;gt;|  Flow 1 |
    |&amp;lt;#Blue&amp;gt;|  Flow 2 |
endlegend

@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Flegend.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Flegend.svg" title="Color coded legend" alt="Color coded legend"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When sequence is important then I use a numbering scheme like this&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flow 1

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;1.1 action&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;1.2 action&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Flow 2

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;2.1 action&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2.2 action&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Autonumber events in sequence diagram
&lt;/h1&gt;

&lt;p&gt;One of the best features of sequence diagrams is the &lt;code&gt;autonumber&lt;/code&gt; feature which will add a number before the text of each event as explained in the documentation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml

autonumber
Bob -&amp;gt; Alice : Authentication Request
Bob &amp;lt;- Alice : Authentication Response

@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Autonumbers can be formatted. In the following example the number is 2-digit padded and highlighted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml

autonumber "&amp;lt;B&amp;gt;[00]"
Bob -&amp;gt; Alice : Authentication Request
Bob &amp;lt;- Alice : Authentication Response

@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Diagram&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;simple&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Fautonumber.svg" title="Simple autonumber" alt="Simple autonumber"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;formatted&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Fautonumber-formatted.svg" title="Formatted autonumber" alt="Formatted autonumber"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I prefer the &lt;code&gt;autonumber "&amp;lt;B&amp;gt;[00]"&lt;/code&gt; the most because I've never had to exceed 99 events in a diagram. Besides, when my diagrams become big, they are usuall split by a deviders and seperators (&lt;code&gt;==&lt;/code&gt;) and for each I restart the the numbering in the sequence.&lt;/p&gt;

&lt;h1&gt;
  
  
  Text alignment in sequence diagram
&lt;/h1&gt;

&lt;p&gt;In the above example, the lines can be brought closer together to make the diagram more dense with this skin parameter &lt;code&gt;skinparam responseMessageBelowArrow true&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml

skinparam responseMessageBelowArrow true

autonumber "&amp;lt;B&amp;gt;[00]"
Bob -&amp;gt; Alice : Authentication Request
Bob &amp;lt;- Alice : Authentication Response

@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Diagram&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;default&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Fautonumber-formatted.svg" title="Default" alt="Default"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;responseMessageBelowArrow&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Fresponse-below-arrow.svg" title="Response below arrow" alt="Response below arrow"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Semi transparent group backgrounds in sequence diagrams
&lt;/h1&gt;

&lt;p&gt;I like to group my participants in boxes and color code them because when the sequence is long, you can quickly identify the scope of the vertical you are looking at even when the participants are out of view. Problem is that every one of the &lt;code&gt;Grouping message&lt;/code&gt; features (&lt;code&gt;group&lt;/code&gt;,&lt;code&gt;alt/else&lt;/code&gt;,&lt;code&gt;opt&lt;/code&gt;,&lt;code&gt;loop&lt;/code&gt;,&lt;code&gt;par&lt;/code&gt;,&lt;code&gt;break&lt;/code&gt;,&lt;code&gt;critical&lt;/code&gt; and &lt;code&gt;group&lt;/code&gt;) are rendered by default with a white solid background which hides the color of the box. This is annoying when the group overlaps many verticals and becomes one massive big white background. A solution for this is not easy. You could use the &lt;code&gt;#Transparent&lt;/code&gt; but then the entire group's background becomes transparent and when big the context is lost.&lt;/p&gt;

&lt;p&gt;This was not easy to find, but &lt;a href="https://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt; skinning supports alpha channel and the background can be set through the skin. &lt;a href="https://plantuml.com/skinparam" rel="noopener noreferrer"&gt;Skin Parameters&lt;/a&gt; are not  documented extensively and I was able to find the proper one &lt;code&gt;SequenceGroupBodyBackgroundColor&lt;/code&gt; through this &lt;a href="https://plantuml-documentation.readthedocs.io/en/latest/formatting/all-skin-params.html" rel="noopener noreferrer"&gt;page&lt;/a&gt;. After some experimentation, I've decided to use white with some tranparency using this value &lt;code&gt;#FFFFFF90&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml

skinparam SequenceGroupBodyBackgroundColor #FFFFFF90

box "Internal Service" #LightBlue
    participant Bob
    participant Alice
end box

box "Other" #LightGreen
    participant Other
end box

group group
    Bob -&amp;gt; Alice : hello
    Alice -&amp;gt; Other : hello
end

@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mode&lt;/th&gt;
&lt;th&gt;Diagram&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;default&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Fsolid-group.svg" title="Default group background" alt="Default group background"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;transparent&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Ftransparent-group.svg" title="Transparent group background" alt="Transparent group background"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;semi-transparent&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Fsemi-transparent-group.svg" title="Semi-transparent group background" alt="Semi-transparent group background"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Solve cut off issue
&lt;/h1&gt;

&lt;p&gt;When using the default &lt;a href="https://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt; server to render the diagrams in &lt;code&gt;png&lt;/code&gt;, often the diagrams are cut off because &lt;a href="https://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt; limits image width and height to 4096. This issue is discussed on github &lt;a href="https://github.com/qjebbs/vscode-plantuml/issues/136" rel="noopener noreferrer"&gt;issue&lt;/a&gt; and the solution is to either use command line parameters or use the &lt;code&gt;skinparam dpi X&lt;/code&gt; parameter. When using the &lt;a href="https://marketplace.visualstudio.com/items?itemName=jebbs.plantuml" rel="noopener noreferrer"&gt;VSCode PlantUML&lt;/a&gt; add-on with the default server, this is the only solution as current the add-on doesn't support command line parameters. Unfortunately, the &lt;code&gt;X&lt;/code&gt; for the dpi needs to be found by experimentation to make sure the diagram fits. As the diagram grows horizontally, the parameter needs to be adjusted accordingly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Help with skinning
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://plantuml.com/" rel="noopener noreferrer"&gt;PlantUML&lt;/a&gt; supports many different colors by name but it is kind of a maze. Use the &lt;code&gt;colors&lt;/code&gt; command to render a picture with all colors&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@startuml

colors

@enduml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Fcolors.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2Fplantuml%2F2021-02-24-plantuml-tips-tricks-1%2Fcolors.svg" title="PlantUML Colors" alt="PlantUML Colors"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately the &lt;a href="https://plantuml.com/skinparam" rel="noopener noreferrer"&gt;Skin Parameters&lt;/a&gt; are not very well documented and the best comprehensive list is in the &lt;a href="https://plantuml-documentation.readthedocs.io/en/latest/formatting/all-skin-params.html" rel="noopener noreferrer"&gt;All Skin Parameters&lt;/a&gt; page.&lt;/p&gt;

</description>
      <category>plantuml</category>
      <category>tips</category>
    </item>
    <item>
      <title>Enhance PowerShell tracing and logging for the console and transcriptions</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Sun, 12 Apr 2020 11:01:19 +0000</pubDate>
      <link>https://dev.to/sarafian/enhance-powershell-tracing-and-logging-for-the-console-and-transcriptions-574g</link>
      <guid>https://dev.to/sarafian/enhance-powershell-tracing-and-logging-for-the-console-and-transcriptions-574g</guid>
      <description>&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.powershellgallery.com/packages/XWrite/" rel="noopener noreferrer"&gt;XWrite&lt;/a&gt; was originally created for PowerShell &lt;code&gt;4&lt;/code&gt; but it works flawlessly with the latest and greatest of PowerShell (&lt;code&gt;7.0.0&lt;/code&gt;). It is a 100% script-powered module and explicit effort was made to keep it as less intrusive as possible to PowerShell given the sensitive nature of the affected cmdlets.&lt;/p&gt;

&lt;p&gt;The module was created because back then I was building a very complicated CI/CD pipeline for deploying &lt;a href="http://sdl.github.io/#dita" rel="noopener noreferrer"&gt;SDL Knowledge Center&lt;/a&gt; on &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;Amazon Web Services&lt;/a&gt;. As part of this effort and as I matured into the technology I realized some of the shortcomings of PowerShell and thought of some enhancements I would like for myself.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PowerShell's default tracing to the console or transcription files is lacking. To give an example, I would love to see, which cmdlet or script wrote something as debug, verbose, information, warning or even an error. The script developer needs to always add this information in the body of the output-ed entry which makes tracing annoying for the developer and the code-base dirty.
&lt;/li&gt;
&lt;li&gt;PowerShell is missing a seamless redirection of the progress into the console and transcription. Because of this, the developer of the script needs to code both lines for nice interactive user experience but also a solid trace when the script executes in non-interactive mode. I also don't like the rendering of the &lt;code&gt;Write-Progress&lt;/code&gt;'s output which often interferes with the console and is different per host (e.g. PowerShell, PowerShell ISE, PWSH, VSCode etc). I like the concept though and I would like to have the option to redirect it to the console.&lt;/li&gt;
&lt;li&gt;PowerShell is missing a simple and fast way to enable full tracing to the console. I don't want to modify multiple preference variables e.g. &lt;code&gt;$DebugPreference&lt;/code&gt; without autocomplete. There has to be something simpler and faster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For these reasons and to improve my experience with PowerShell as a developer and the transcription analysis, I had developed back then (2007) the &lt;a href="https://www.powershellgallery.com/packages/XWrite/" rel="noopener noreferrer"&gt;XWrite&lt;/a&gt; module. It turns out that it works so well, that I started using it with every PowerShell session by loading the module through my profile.&lt;/p&gt;

&lt;p&gt;Here is a glimpse of the normal and enhanced outputs&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PowerShell normal output&lt;/th&gt;
&lt;th&gt;PowerShell output with XWrite enabled&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSarafian%2FXWrite%2Fmaster%2FImages%2FPS-Normal.png" alt="PowerShell normal"&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSarafian%2FXWrite%2Fmaster%2FImages%2FXWrite-Enabled.png" alt="XWriteEnabled"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  XWrite features
&lt;/h2&gt;

&lt;p&gt;The module can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable full tracing for all preference variables and rollback to the original settings.&lt;/li&gt;
&lt;li&gt;Enhance the output of the following core (&lt;code&gt;Microsoft.PowerShell.Utility&lt;/code&gt;) cmdlets:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Write-Host&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Write-Debug&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Write-Verbose&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Write-Information&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Write-Warning&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Add inline additional output for the native &lt;code&gt;Write-Progress&lt;/code&gt; cmdlet using: 

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Write-Host&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Write-Debug&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Write-Verbose&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Write-Information&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Seamless support with PowerShell transcriptions. &lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The output of each of the &lt;code&gt;Write-*&lt;/code&gt; cmdlets can be enhanced with the following extra information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Source&lt;/strong&gt; that is the source script or module name that executed the &lt;code&gt;Write-&lt;/code&gt; cmdlet.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Caller&lt;/strong&gt; that is the name of the script or module that executed the &lt;code&gt;Write-&lt;/code&gt; cmdlet.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Date&lt;/strong&gt; that is the date part of the current date.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;Time&lt;/strong&gt; that is the time part of the current date.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above functionality is enabled or disabled by use of the following groups of cmdlets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To enable/disable different levels of preference variables:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Set-XGlobalTrace&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Undo-XGlobalTrace&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;To enable/disable the enhanced output

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Enable-XWrite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Disable-XWrite&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;To enable/disable progress output redirection

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Enable-XWriteProgress&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Disable-XWriteProgress&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting up for the demo
&lt;/h2&gt;

&lt;p&gt;To demonstrate let's first create a sample function &lt;code&gt;Test-MyXWrite&lt;/code&gt; that just writes the preference value per &lt;code&gt;Debug&lt;/code&gt;,&lt;code&gt;Verbose&lt;/code&gt;,&lt;code&gt;Information&lt;/code&gt; and &lt;code&gt;Warning&lt;/code&gt; using the respected cmdlets &lt;code&gt;Write-Debug&lt;/code&gt;, &lt;code&gt;Write-Verbose&lt;/code&gt;,&lt;code&gt;Write-Information&lt;/code&gt; and &lt;code&gt;Write-Warning&lt;/code&gt;. The same is written to the host using the &lt;code&gt;Write-Host&lt;/code&gt; cmdlet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Sample function that uses Write-* commands without any changes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Test-MyXWrite&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"DebugPreference=&lt;/span&gt;&lt;span class="nv"&gt;$DebugPreference&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"VerbosePreference=&lt;/span&gt;&lt;span class="nv"&gt;$VerbosePreference&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"InformationPreference=&lt;/span&gt;&lt;span class="nv"&gt;$InformationPreference&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"WarningPreference=&lt;/span&gt;&lt;span class="nv"&gt;$WarningPreference&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nv"&gt;$message&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;ForEach-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="n"&gt;Write-Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="n"&gt;Write-Debug&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DebugPreference=&lt;/span&gt;&lt;span class="nv"&gt;$DebugPreference&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Verbose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VerbosePreference=&lt;/span&gt;&lt;span class="nv"&gt;$VerbosePreference&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Information&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"InformationPreference=&lt;/span&gt;&lt;span class="nv"&gt;$InformationPreference&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Write-Warning&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WarningPreference=&lt;/span&gt;&lt;span class="nv"&gt;$WarningPreference&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we first enable all preference variables using &lt;code&gt;Set-XGlobalTrace&lt;/code&gt;, invoke the &lt;code&gt;Test-MyXWrite&lt;/code&gt; and undo the changes of &lt;code&gt;Set-XGlobalTrace&lt;/code&gt; using the &lt;code&gt;Undo-XGlobalTrace&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Enable full trace &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-XGlobalTrace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForAll&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Invoke test function to execute the Write-* commands&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Test-MyXWrite&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Disable full trace. Rollback to original settings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Undo-XGlobalTrace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how it looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSarafian%2FXWrite%2Fmaster%2FImages%2FPS-Normal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSarafian%2FXWrite%2Fmaster%2FImages%2FPS-Normal.png" alt="PowerShell normal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo of XWrite enhanced output
&lt;/h2&gt;

&lt;p&gt;To showcase the enhanced output, we just need to enable it using &lt;code&gt;Enable-XWrite&lt;/code&gt; and the rest of the demo is the same as before.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Enable XWrite default output enhancement&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Enable-XWrite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForAll&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Enable full trace &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-XGlobalTrace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForAll&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Invoke test function to execute the Write-* commands&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Test-MyXWrite&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Disable full trace. Rollback to original settings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Undo-XGlobalTrace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how it looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSarafian%2FXWrite%2Fmaster%2FImages%2FXWrite-Enabled.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSarafian%2FXWrite%2Fmaster%2FImages%2FXWrite-Enabled.png" alt="XWriteEnabled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that the name of the invoker, that is &lt;code&gt;Test-MyXWrite&lt;/code&gt; shows up as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo of XWrite advanced enhanced output
&lt;/h2&gt;

&lt;p&gt;The enhanced output could be configured to output more information with additional tokens such as the invoker's type and the timestamp using additional parameters of &lt;code&gt;Enable-XWrite&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Enable XWrite advanced output enhancement&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Enable-XWrite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForAll&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Time&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Enable full trace &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-XGlobalTrace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ForAll&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Invoke test function to execute the Write-* commands&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Test-MyXWrite&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Disable full trace. Rollback to original settings&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Undo-XGlobalTrace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how it looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSarafian%2FXWrite%2Fmaster%2FImages%2FXWrite-Enabled-Full.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSarafian%2FXWrite%2Fmaster%2FImages%2FXWrite-Enabled-Full.png" alt="XWriteEnabled"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice that the source &lt;code&gt;Function&lt;/code&gt; and a timestamp are added extra to the name `Test-MyXWrite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Formatting of advanced output
&lt;/h2&gt;

&lt;p&gt;The module will add a prefix to the output with the following logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The invoker's name &lt;code&gt;Test-MyXWrite&lt;/code&gt; is always present.&lt;/li&gt;
&lt;li&gt;When the &lt;code&gt;-Source&lt;/code&gt; parameter is used then the source of the invoker is added. For example

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Function&lt;/code&gt; when the invocation originates from a function declared in-script as above.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ModuleName&lt;/code&gt; when the invocation originates from a function that is part of a module.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FileName&lt;/code&gt; when the invocation originates from a script file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;SCRIPT&amp;gt;&lt;/code&gt; when the invocation originates from a script block.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;When &lt;code&gt;-Date&lt;/code&gt; or &lt;code&gt;-Time&lt;/code&gt; is used, then their respected values are added.&lt;/li&gt;

&lt;li&gt;When the &lt;code&gt;-Separator&lt;/code&gt; parameter is used, then the default &lt;code&gt;:&lt;/code&gt; separator is adapted.&lt;/li&gt;

&lt;li&gt;When the &lt;code&gt;-Format&lt;/code&gt; parameter is specified then the provided custom format is used. The valid tokens are:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%source%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%caller%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%date%&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%time%&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This is a consolidated matrix"&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Token in &lt;code&gt;-Format&lt;/code&gt; parameter&lt;/th&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Example value&lt;/th&gt;
&lt;th&gt;Remarks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%source%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-Source&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Function&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The invoker's type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%caller%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No parameter. Always active&lt;/td&gt;
&lt;td&gt;Test-MyXWrite&lt;/td&gt;
&lt;td&gt;The invoker's name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%date%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-Date&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;20170804&lt;/td&gt;
&lt;td&gt;the date stamp formatted as &lt;code&gt;yyyyMMdd&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;%time%&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;-Time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10:57:27.858&lt;/td&gt;
&lt;td&gt;the time stamp formatted as &lt;code&gt;hh:mm:ss.fff&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Considerations
&lt;/h2&gt;

&lt;p&gt;The module works by placing a global implementation overwrite of the respected cmdlet over the core one from the &lt;code&gt;Microsoft.PowerShell.Utility&lt;/code&gt; namespace. This effectively overwrites the default behavior of each &lt;code&gt;Write-*&lt;/code&gt; cmdlet. With this understanding, the following need to be always considered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the invocation is like &lt;code&gt;Microsoft.PowerShell.Utility/Write-Host&lt;/code&gt; then the global overwrite is bypassed. &lt;/li&gt;
&lt;li&gt;Binary modules, target through compiling the namespaced &lt;code&gt;Write-*&lt;/code&gt; functions and because of that &lt;a href="https://www.powershellgallery.com/packages/XWrite/" rel="noopener noreferrer"&gt;XWrite&lt;/a&gt; will not enhance their output.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Impact on PowerShell's core functionality
&lt;/h2&gt;

&lt;p&gt;The impact is minimum because &lt;a href="https://www.powershellgallery.com/packages/XWrite/" rel="noopener noreferrer"&gt;XWrite&lt;/a&gt; utilizes the above considerations and lets PowerShell's default &lt;code&gt;Write-*&lt;/code&gt; functionality do the heavy lifting. This means that the module doesn't interfere with PowerShell and just modifies the payload of the used parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Best practices
&lt;/h2&gt;

&lt;p&gt;Here are some best practices I've picked up over the years:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;Enable-XWrite&lt;/code&gt; and &lt;code&gt;Enable-XWriteProgress&lt;/code&gt; before &lt;code&gt;Set-XGlobalTrace&lt;/code&gt; because they write to &lt;code&gt;DEBUG&lt;/code&gt; the body of the overwrites and that can clutter the output.&lt;/li&gt;
&lt;li&gt;If you want to sneak pick in the implementation of each of the overwriting functions then use &lt;code&gt;Set-XGlobalTrace&lt;/code&gt; first and then invoke &lt;code&gt;Enable-XWrite&lt;/code&gt; and &lt;code&gt;Enable-XWriteProgress&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You don't have to do anything about the transcription output. This is managed by PowerShell by redirecting the output to a file. Since &lt;code&gt;XWrite&lt;/code&gt; used the PowerShell's own &lt;code&gt;Write-*&lt;/code&gt; functionality it just works.&lt;/li&gt;
&lt;li&gt;Try to invoke the &lt;code&gt;Enable-XWrite&lt;/code&gt; and &lt;code&gt;Enable-XWriteProgress&lt;/code&gt; as early as possible in your session, so any transcriptions are enhanced from the beginning.

&lt;ul&gt;
&lt;li&gt;For your interactive sessions, just add in your profile script.&lt;/li&gt;
&lt;li&gt;For non-interactive flows, this could be part of the pipeline.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Originally posted &lt;a href="https://sarafian.github.io/2020/04/11/xwrite-powershell-improved-logging-tracing.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>xwrite</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Add semantic versioning capabilities to PowerShell</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Tue, 07 Apr 2020 16:08:28 +0000</pubDate>
      <link>https://dev.to/sarafian/add-semantic-versioning-capabilities-to-powershell-4m9f</link>
      <guid>https://dev.to/sarafian/add-semantic-versioning-capabilities-to-powershell-4m9f</guid>
      <description>&lt;p&gt;The &lt;a href="https://www.powershellgallery.com/packages/SemVerPS/"&gt;SemVerPS&lt;/a&gt; PowerShell module offers the ability to work with &lt;a href="http://semver.org/"&gt;Semantic Version&lt;/a&gt; utilizing the .net implementation from &lt;a href="https://dev.tomaxhauser/semver"&gt;Max Hauser's SemVer&lt;/a&gt; repository. With this module, it is possible to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work with &lt;a href="http://semver.org/"&gt;Semantic Version&lt;/a&gt; as typed object leveraging or comparison operators&lt;/li&gt;
&lt;li&gt;Enhance object with a &lt;code&gt;NoteProperty&lt;/code&gt; that contains a &lt;a href="http://semver.org/"&gt;Semantic Version&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Filter and/or test above enhanced list of objects. 

&lt;ul&gt;
&lt;li&gt;This could be very useful if for example a list of items is retrieved where part of the name is a semantic version and we want to filter the list.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Basic usage with ConvertTo-SemVer
&lt;/h2&gt;

&lt;p&gt;Use the &lt;code&gt;ConvertTo-SemVer&lt;/code&gt; to convert strings to semantic version objects. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;ConvertTo-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Major      : 1
Minor      : 0
Patch      : 0
Prerelease : 
Build      : 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;ConvertTo-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.1-alpha+1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Strict&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Major      : 1
Minor      : 0
Patch      : 1
Prerelease : alpha
Build      : 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Use the &lt;code&gt;Test-SemVer&lt;/code&gt; to test if a string or a semantic version is stable or prerelease. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;Test-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-InputObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#True&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nf"&gt;Test-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-InputObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Stable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#True&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nf"&gt;Test-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-InputObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0-alpha+1"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PreRelease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;alpha&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;#True&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Add semantic versioning member to existing objects
&lt;/h2&gt;

&lt;p&gt;Often there is a need to attach a semantic version notation to an object or a list of objects. Use the &lt;code&gt;Add-SemVerMember&lt;/code&gt; to add a member where the semantic version value is derived either from an expression or a script block. By default the semantic version is add to a property named &lt;code&gt;SemVer&lt;/code&gt; but this can be changed by defining the &lt;code&gt;Property&lt;/code&gt; parameter. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;pscustomobject&lt;/span&gt;&lt;span class="p"&gt;]@{&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"example-1.0.0"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;Add-SemVerMember&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Expression&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Name.Replace("example-","")'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PassThru&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;pscustomobject&lt;/span&gt;&lt;span class="p"&gt;]@{&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"example-1.0.0"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;Add-SemVerMember&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ScriptBlock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"example-"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PassThru&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AnotherProperty"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name          SemVer
----          ------
example-1.0.0 1.0.0


Name          AnotherProperty
----          ---------------
example-1.0.0 1.0.0


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As an extension of the &lt;code&gt;Test-SemVer&lt;/code&gt;, use the &lt;code&gt;Limit-SemVer&lt;/code&gt; to filter objects based on semantic version conditions. Each object can be in the form of a string, or a semantic version instance or an object that has been enhanced with &lt;code&gt;Add-SemVerMember&lt;/code&gt;. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$versions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0-alpha+1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$versions&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;Limit-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Stable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$versions&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;Limit-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Prerelease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;alpha&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1.0.0

1.0.0-alpha+1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$objectsWithVersions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"example-1.0.0"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"example-1.0.0-alpha+1"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;Foreach-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;pscustomobject&lt;/span&gt;&lt;span class="p"&gt;]@{&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Add-SemVerMember&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Expression&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Name.Replace("example-","")'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-PassThru&lt;/span&gt;&lt;span class="w"&gt;  
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$objectsWithVersions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$objectsWithVersions&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;Limit-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Stable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$objectsWithVersions&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;Limit-SemVer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Prerelease&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;alpha&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Name          SemVer
----          ------
example-1.0.0 1.0.0

Name                  SemVer
----                  ------
example-1.0.0-alpha+1 1.0.0-alpha+1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Copied from my personal &lt;a href="https://sarafian.github.io/2020/04/06/semver-powershell.html"&gt;blog post&lt;/a&gt;&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>semverps</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Render a computer badge with name and state in markdown with PowerShell using MarkdownPS</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Mon, 06 Apr 2020 20:03:17 +0000</pubDate>
      <link>https://dev.to/sarafian/render-a-computer-badge-with-name-and-state-in-markdown-with-powershell-using-markdownps-4l1b</link>
      <guid>https://dev.to/sarafian/render-a-computer-badge-with-name-and-state-in-markdown-with-powershell-using-markdownps-4l1b</guid>
      <description>&lt;p&gt;Originally posted &lt;a href="https://sarafian.github.io/tips/2016/05/06/markdownps-badge.html"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://www.powershellgallery.com/packages/MarkdownPS/"&gt;MarkdownPS&lt;/a&gt; PowerShell module this is a simple cmdlet that &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tests the state of the computer using PowerShell's &lt;code&gt;Test-Connection&lt;/code&gt; cmdlet&lt;/li&gt;
&lt;li&gt;Depending on the outcome it generates a badge in markdown with red or green state.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;New-ComputerBadge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;param&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Mandatory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nv"&gt;$Computer&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;try&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="kr"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Test-Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$Computer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Quiet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nv"&gt;$color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"green"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Live"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="kr"&gt;else&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nv"&gt;$color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"red"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Not Live"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nf"&gt;New-MDImage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Subject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$Computer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$color&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="kr"&gt;catch&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nf"&gt;Write-Error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nf"&gt;New-MDImage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Subject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Badge"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Error"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-ComputerBadge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Computer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EXAMPLE"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders the following markdown&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;![](https://img.shields.io/badge/EXAMPLE-Live-green.svg)
![](https://img.shields.io/badge/EXAMPLE-Not%20Live-red.svg)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rcO5OdyP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/EXAMPLE-Live-green.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rcO5OdyP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/EXAMPLE-Live-green.svg" alt=""&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ5mOg4t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/EXAMPLE-Not%2520Live-red.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ5mOg4t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/EXAMPLE-Not%2520Live-red.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>powershell</category>
      <category>markdownps</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Render badges with PowerShell MarkdownPS and shields.io</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Mon, 06 Apr 2020 20:03:02 +0000</pubDate>
      <link>https://dev.to/sarafian/render-badges-with-powershell-markdownps-and-shields-io-2bm</link>
      <guid>https://dev.to/sarafian/render-badges-with-powershell-markdownps-and-shields-io-2bm</guid>
      <description>&lt;p&gt;Originally poste &lt;a href="https://sarafian.github.io/tempblog/tips/2016/05/06/markdownps-badge.html"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my previous post &lt;a href="https://dev.to/sarafian/generate-markdown-from-powershell-with-markdownps-36i2"&gt;Generate markdown from PowerShell with MarkdownPS&lt;/a&gt; I explained the basic cmdlets of the PowerShell module &lt;a href="https://www.powershellgallery.com/packages/MarkdownPS/"&gt;MarkdownPS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://shields.io/"&gt;Shields.io&lt;/a&gt; provides many interesting badges out of the box, but there is also an API that can be used to render any badge.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://img.shields.io/badge/&amp;lt;SUBJECT&amp;gt;-&amp;lt;STATUS&amp;gt;-&amp;lt;COLOR&amp;gt;.svg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above just renders  &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--63G7ICK9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/%253CSUBJECT%253E-%253CSTATUS%253E-%253CCOLOR%253E.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--63G7ICK9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/%253CSUBJECT%253E-%253CSTATUS%253E-%253CCOLOR%253E.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On version 1.4 of the &lt;a href="https://www.powershellgallery.com/packages/MarkdownPS/"&gt;MarkdownPS&lt;/a&gt; a new parameter set was added to the &lt;code&gt;New-MDImage&lt;/code&gt; cmdlet to drive this api.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-MDImage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Subject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;SUBJECT&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;STATUS&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;red&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;![](https://img.shields.io/badge/%3CSUBJECT%3E-%3CSTATUS%3E-red.svg)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The produced url in the image is url encoded. The parameter &lt;code&gt;-Color&lt;/code&gt; accepts only values that the shields.io API allows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Color&lt;/th&gt;
&lt;th&gt;Badge&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;brightgreen&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dm7l9Kln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-brightgreen-brightgreen.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;green&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FA1Rt17A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-green-green.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yellowgreen&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iXpi7YsS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-yellowgreen-yellowgreen.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;brightgreen&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dm7l9Kln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-brightgreen-brightgreen.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;yellow&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bTez5LEb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-yellow-yellow.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;orange&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4Wlxx_qE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-orange-orange.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;red&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ugGuQDiC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-red-red.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lightgrey&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aDgUgeg4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-lightgrey-lightgrey.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;blue&lt;/td&gt;
&lt;td&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sLw6W56O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Color-blue-blue.svg" alt=""&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To make a badge clickable then use the &lt;code&gt;-Link&lt;/code&gt; parameter like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-MDImage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Subject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"example.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"OK"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Color&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;green&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://example.com"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://example.com"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G99EdT62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/example.com-OK-green.svg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>powershell</category>
      <category>markdownps</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Generate markdown from PowerShell with MarkdownPS
</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Mon, 06 Apr 2020 19:44:44 +0000</pubDate>
      <link>https://dev.to/sarafian/generate-markdown-from-powershell-with-markdownps-36i2</link>
      <guid>https://dev.to/sarafian/generate-markdown-from-powershell-with-markdownps-36i2</guid>
      <description>&lt;p&gt;Originally posted &lt;a href="https://sarafian.github.io/tempblog/2016/05/06/markdownps.html"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.powershellgallery.com/packages/MarkdownPS/"&gt;MarkdownPS&lt;/a&gt; is a PowerShell module that wraps the &lt;strong&gt;markdown&lt;/strong&gt; syntax into PowerShell cmdlets.&lt;/p&gt;

&lt;p&gt;Initially I ran into the &lt;a href="https://www.powershellgallery.com/packages/PSMarkdown"&gt;PSMarkdown&lt;/a&gt; for which &lt;a href="https://github.com/ishu3101"&gt;ishu3101&lt;/a&gt; had developed a cmdlet that renders a table in markdown syntax. This was very useful and I decided that I needed more functionality provided by cmdlets to render other aspects of markdown. After discussing with &lt;a href="https://github.com/ishu3101"&gt;ishu3101&lt;/a&gt; I pushed a head and created a module of my own. The &lt;code&gt;New-MDTable&lt;/code&gt; cmdlet's code is inspired by the &lt;code&gt;ConvertTo-Markdown&lt;/code&gt; by &lt;a href="https://github.com/ishu3101"&gt;ishu3101&lt;/a&gt; but I enhanced it with column alignment. &lt;/p&gt;

&lt;p&gt;This is my first open source projects in GitHub, so I took the opportunity to educate myself a bit about it. The &lt;a href="https://github.com/Sarafian/MarkdownPS"&gt;MarkdownPS&lt;/a&gt; repository is integrated with visual studio services and I also use &lt;a href="https://github.com/pester/Pester"&gt;Pester&lt;/a&gt; to unit test each cmdlet. Overall, it was a good experience while picking up PowerShell knowledge along. Integrating Pester from Visual Studio Services is a bit tricky because VSS runs on PowerShell 4 and the Pester is available with PowerShell v5. The solution is available in &lt;a href="https://github.com/Sarafian/MarkdownPS/tree/master/Pester"&gt;code&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering headers
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-MDHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Headings"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The second largest heading"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"The smallest heading"&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;New-MDHeader&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;-Level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;6&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Headings

## The second largest heading

###### The smallest heading
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  Headings
&lt;/h1&gt;
&lt;h2&gt;
  
  
  The second largest heading
&lt;/h2&gt;
&lt;h6&gt;
  
  
  The smallest heading
&lt;/h6&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Paragraphs
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Paragraphs are separated by empty lines. Within a paragraph it's possible to have a line break,"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"simply press &amp;lt;return&amp;gt; for a new line."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"For example,"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"like this."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Paragraphs are separated by empty lines. Within a paragraph it's possible to have a line break,
simply press &amp;lt;return&amp;gt; for a new line.

For example,
like this.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Paragraphs are separated by empty lines. Within a paragraph it's possible to have a line break,&lt;br&gt;
simply press  for a new line.&lt;/p&gt;

&lt;p&gt;For example,&lt;br&gt;
like this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Bold, Italic and StrikeThrough
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-MDCharacterStyle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Italic characters"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Italic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDCharacterStyle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bold characters"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Bold&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDCharacterStyle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"strikethrough text"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;StrikeThrough&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s2"&gt;"All Styles"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;New-MDCharacterStyle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Bold&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;New-MDCharacterStyle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Italic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;New-MDCharacterStyle&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;StrikeThrough&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;*Italic characters*

**bold characters**

~~strikethrough text~~

~~***All Styles***~~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Italic characters&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;bold characters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;del&gt;strikethrough text&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;&lt;del&gt;&lt;strong&gt;&lt;em&gt;All Styles&lt;/em&gt;&lt;/strong&gt;&lt;/del&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Lists
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"George Washington"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"John Adams"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Thomas Jefferson"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Unordered&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"James Madison"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"James Monroe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"John Quincy Adams"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Ordered&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Make my changes"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Ordered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoNewLine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"Fix bug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Improve formatting"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Ordered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoNewLine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Make the headings bigger"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Unordered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoNewLine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Push my commits to GitHub"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Ordered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoNewLine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Open a pull request"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Ordered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoNewLine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="s2"&gt;"Describe my changes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"Mention all the members of my team"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Ordered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoNewLine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDList&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ask for feedback"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Level&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Unordered&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- George Washington
- John Adams
- Thomas Jefferson


1. James Madison
2. James Monroe
3. John Quincy Adams


1. Make my changes

   1. Fix bug
   2. Improve formatting

    - Make the headings bigger

1. Push my commits to GitHub

1. Open a pull request

   1. Describe my changes
   2. Mention all the members of my team

    - Ask for feedback
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;George Washington&lt;/li&gt;
&lt;li&gt;John Adams&lt;/li&gt;
&lt;li&gt;Thomas Jefferson&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;James Madison&lt;/li&gt;
&lt;li&gt;James Monroe&lt;/li&gt;
&lt;li&gt;&lt;p&gt;John Quincy Adams&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Make my changes&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fix bug&lt;/li&gt;
&lt;li&gt;Improve formatting&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Make the headings bigger
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Push my commits to GitHub&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open a pull request&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Describe my changes&lt;/li&gt;
&lt;li&gt;Mention all the members of my team&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Ask for feedback
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"This is "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;New-MDLink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"an example"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://www.example.com/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s2"&gt;" inline link."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;New-MDLink&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"This link"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://www.example.com/"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Title"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s2"&gt;" has a title attribute."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This is [an example](http://www.example.com/) inline link.

[This link](http://www.example.com/ "Title") has a title attribute.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;This is &lt;a href="http://www.example.com/"&gt;an example&lt;/a&gt; inline link.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.example.com/"&gt;This link&lt;/a&gt; has a title attribute.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Images
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-MDImage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.powershellgallery.com/Content/Images/Branding/psgallerylogo.svg"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AltText&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alt text"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;New-MDImage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://www.powershellgallery.com/Content/Images/Branding/psgallerylogo.svg"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AltText&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Alt text"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Optional title attribute"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;![Alt text](https://www.powershellgallery.com/Content/Images/Branding/psgallerylogo.svg)

![Alt text](https://www.powershellgallery.com/Content/Images/Branding/psgallerylogo.svg "Optional title attribute")
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CUdfV1o_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.powershellgallery.com/Content/Images/Branding/psgallerylogo.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CUdfV1o_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.powershellgallery.com/Content/Images/Branding/psgallerylogo.svg" alt="Alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CUdfV1o_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.powershellgallery.com/Content/Images/Branding/psgallerylogo.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CUdfV1o_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.powershellgallery.com/Content/Images/Branding/psgallerylogo.svg" alt="Alt text" title="Optional title attribute"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Quote
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"In the words of Abraham Lincoln:"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Pardon my French"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nf"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Multi line quote"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Line 1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Line 2"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDQuote&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Multi line quote

&amp;gt; Line 1
&amp;gt;
&amp;gt; Line 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Multi line quote&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Line 1&lt;/p&gt;

&lt;p&gt;Line 2&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Code fences
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"Use "&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;New-MDInlineCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"git status"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"to list all new or modified files that haven't yet been committed."&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nf"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Some basic Git commands are:"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Style&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"git status"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"git add"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"git commit"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDCode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$lines&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use \`git status\`to list all new or modified files that haven't yet been committed.
Some basic Git commands are:



```text
    git status
    git add
    git commit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;gt; Use `git status`to list all new or modified files that haven't yet been committed.
&amp;gt; Some basic Git commands are:
&amp;gt;



```text
    git status
    git add
    git commit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Tables
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nf"&gt;New-MDHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Tables"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Without aligned columns"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MarkdownPS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;CommandType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;New-MDTable&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;New-MDParagraph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Lines&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"With aligned columns"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nf"&gt;Get-Command&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MarkdownPS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;New-MDTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Columns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;ordered&lt;/span&gt;&lt;span class="p"&gt;]@{&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"left"&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;CommandType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"center"&lt;/span&gt;&lt;span class="err"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"right"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;renders&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Without aligned columns


| Name                 | CommandType          | Version              |
| -------------------- | -------------------- | -------------------- |
| New-MDCharacterStyle | Function             |                      |
| New-MDCode           | Function             |                      |
| New-MDHeader         | Function             |                      |
| New-MDImage          | Function             |                      |
| New-MDInlineCode     | Function             |                      |
| New-MDLink           | Function             |                      |
| New-MDList           | Function             |                      |
| New-MDParagraph      | Function             |                      |
| New-MDQuote          | Function             |                      |
| New-MDTable          | Function             |                      |

With aligned columns


| Name                 | CommandType          | Version              |
| -------------------- |:--------------------:| --------------------:|
| New-MDCharacterStyle | Function             |                      |
| New-MDCode           | Function             |                      |
| New-MDHeader         | Function             |                      |
| New-MDImage          | Function             |                      |
| New-MDInlineCode     | Function             |                      |
| New-MDLink           | Function             |                      |
| New-MDList           | Function             |                      |
| New-MDParagraph      | Function             |                      |
| New-MDQuote          | Function             |                      |
| New-MDTable          | Function             |                      |
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Without aligned columns&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;CommandType&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New-MDCharacterStyle&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDCode&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDHeader&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDImage&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDInlineCode&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDLink&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDList&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDParagraph&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDQuote&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDTable&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With aligned columns&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;CommandType&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New-MDCharacterStyle&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDCode&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDHeader&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDImage&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDInlineCode&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDLink&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDList&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDParagraph&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDQuote&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New-MDTable&lt;/td&gt;
&lt;td&gt;Function&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;
&lt;/blockquote&gt;

</description>
      <category>powershell</category>
      <category>markdownps</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Creating a private Facebook Messenger chatbot
</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Sat, 28 Mar 2020 18:13:41 +0000</pubDate>
      <link>https://dev.to/sarafian/creating-a-private-facebook-messenger-chatbot-1ef7</link>
      <guid>https://dev.to/sarafian/creating-a-private-facebook-messenger-chatbot-1ef7</guid>
      <description>&lt;p&gt;If you need a bot for your personal home automation, then this post describes how to achieve what is perceived as a private bot on &lt;a href="https://www.facebook.com/"&gt;Facebook&lt;/a&gt;'s &lt;a href="https://www.messenger.com/"&gt;Messenger&lt;/a&gt; platform. &lt;/p&gt;

&lt;h2&gt;
  
  
  Not exactly a private bot
&lt;/h2&gt;

&lt;p&gt;With &lt;em&gt;private&lt;/em&gt;, I'm referring to bots that are not possible to be found by others or won't interact with others. These sort of bots are meant usually for some personal automation, where the bot act as the delivery entity to you or your family.&lt;/p&gt;

&lt;p&gt;On my previous post &lt;a href="https://dev.to/sarafian/creating-a-private-telegram-chatbot-2n9"&gt;Creating a private Telegram chatbot&lt;/a&gt;, a comment was raised about the "private" nature of &lt;a href="https://desktop.telegram.org/"&gt;Telegram&lt;/a&gt;'s bots. With private, I'm referring to a bot that though not private can help establish your very own private communication channel. You control who can interact with the bot and who not. If the bot is discoverable, then there is no functionality supported to others and most importantly, your communication is only visible to yourself or others you have invited.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Facebook page
&lt;/h2&gt;

&lt;p&gt;On Facebook, everything is driven by a page. Organizations will create an organization page but as many do, we can also create own small pages. A page is &lt;strong&gt;always required&lt;/strong&gt; for a &lt;a href="https://www.messenger.com/"&gt;Messenger&lt;/a&gt; bot to work. The page serves its purpose to establish an entry point of interaction with other parties of interest but it is also the entry point for any chat related communication and this is where the bot needs to plug-in. So for the purpose of this post, the page needs to be something very simple.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;a href="https://www.facebook.com/pages/?category=your_pages"&gt;Facebook Pages&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on &lt;code&gt;Create a page&lt;/code&gt; and &lt;code&gt;Community or Public Figure&lt;/code&gt; and &lt;code&gt;Get Started&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Name the page &lt;code&gt;Example Private Messenger Bot&lt;/code&gt; and as category choose something appropriate e.g. &lt;code&gt;Personal Blog&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;You can upload pictures for the page if you want to but it is not necessary.&lt;/li&gt;
&lt;li&gt;The page should be ready like this &lt;a href="(https://www.facebook.com/Example-Private-Messenger-Bot-100180854977501/)"&gt;Example Private Messenger Bot&lt;/a&gt;. Notice that the page can be discovered by others. Confirm this by navigating to your page with an incognito tab.&lt;/li&gt;
&lt;li&gt;Go to &lt;code&gt;Setting-&amp;gt;General-&amp;gt;Page Visibility&lt;/code&gt; and select &lt;code&gt;Page unpublished&lt;/code&gt; and chose &lt;code&gt;Other&lt;/code&gt; for reason with e.g. &lt;code&gt;Personal Bot&lt;/code&gt;. Notice that the page is not available any longer on the incognito tab.&lt;/li&gt;
&lt;li&gt;From &lt;code&gt;Setting-&amp;gt;Messaging&lt;/code&gt; use the &lt;code&gt;Your Messenger URL&lt;/code&gt; to initiate a chat session with your page. This is the &lt;em&gt;private&lt;/em&gt; session we need with our chatbot.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating the bot
&lt;/h2&gt;

&lt;p&gt;Developing an actual bot on &lt;a href="https://www.messenger.com/"&gt;Messenger&lt;/a&gt; is quite complicated. You would need to create an application, submit policies to be able to get keys and tokens that would allow you to integrate with the page's application. For this reason, we'll keep this simple and use a service that makes things very simple. There are three options in order of complexity:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://manychat.com/"&gt;ManyChat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dialogflow.com/"&gt;Dialogflow&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Given that the purpose here is to create a simple &lt;em&gt;private&lt;/em&gt; &lt;a href="https://www.messenger.com/"&gt;Messenger&lt;/a&gt; bot, I'll choose &lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt; for the purpose of this post. Just select &lt;code&gt;Add blank bot&lt;/code&gt; on &lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt; and let's name it &lt;code&gt;Example Private Messenger Bot&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;The bot is now available and you can try a test chat with it by activating the &lt;code&gt;Test Your Bot&lt;/code&gt; from the &lt;code&gt;Automate&lt;/code&gt; panel within the bot's configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting the bot to your page
&lt;/h2&gt;

&lt;p&gt;This is not necessary, but it helps that you can discover your bot from &lt;a href="https://www.messenger.com/"&gt;Messenger&lt;/a&gt; or &lt;a href="https://www.facebook.com/"&gt;Facebook&lt;/a&gt; through the page we just created. If this is your first time in &lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt; then this is straight forward when connecting first time &lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt; with &lt;a href="https://www.facebook.com/"&gt;Facebook&lt;/a&gt;. The trickier flow that I will explain is when you've already made this connection and you need to find the new page. I've chosen this flow because I ran into this problem when writing this post. I've already have another bot connected with another &lt;a href="https://www.facebook.com/"&gt;Facebook&lt;/a&gt; page and I couldn't find how to connect the &lt;code&gt;Example Private Messenger Bot&lt;/code&gt; to its respected page.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to &lt;a href="https://www.facebook.com/settings?tab=business_tools"&gt;Facebook's Business Integration&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;code&gt;View and edit&lt;/code&gt; of the &lt;code&gt;Chatfuel&lt;/code&gt; application.&lt;/li&gt;
&lt;li&gt;Scroll down and select the &lt;code&gt;Example Private Messenger Bot&lt;/code&gt; on each of the following sections:

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Manage your Pages&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Manage and access Page conversations in Messenger&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Send messages from Pages you manage at any time after the first user interaction&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Show a list of the Pages you manage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Log events on your Page's behalf and send those events to Facebook&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Save.&lt;/li&gt;
&lt;li&gt;Wait for a short time and then refresh &lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt;. If this doesn't work try to logout and login again.&lt;/li&gt;
&lt;li&gt;Enter the &lt;code&gt;Example Private Messenger Bot&lt;/code&gt; and select the &lt;code&gt;Configuration&lt;/code&gt; panel from the left.&lt;/li&gt;
&lt;li&gt;Notice that the &lt;code&gt;Example Private Messenger Bot&lt;/code&gt; is listed with a &lt;code&gt;Connect to Page&lt;/code&gt; button to the right which you activate.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrating with Zapier
&lt;/h2&gt;

&lt;p&gt;On my previous post &lt;a href="https://dev.to/sarafian/creating-a-private-telegram-chatbot-2n9"&gt;Creating a private Telegram chatbot&lt;/a&gt; I've explained how to send messages to the bot. This allows for any integration with e.g. &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt; or &lt;a href="https://www.integromat.com/"&gt;Integromat&lt;/a&gt;. To demonstrate the ability to send messages to the &lt;code&gt;Example Private Messenger Bot&lt;/code&gt; I'll show how to hook it up with &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt; which offers an integration. To keep it simple and focused on &lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt; and this post, I'll use a two-step zap.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;Schedule by Zapier&lt;/code&gt; configured to activate every hour.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chatfuel&lt;/code&gt; configured to target a session with the &lt;code&gt;Example Private Messenger Bot&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;Schedule by Zapier&lt;/code&gt; configuration is very easy and straightforward. &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt; is good at helping configuration with UI navigation. The &lt;code&gt;chatfuel&lt;/code&gt; configuration is the trickier one and it compromises by two activities in the overall zap flow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find a Subscriber in Chatfuel&lt;/li&gt;
&lt;li&gt;Send Text Message in Chatfuel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q60JVYin--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sarafian.github.io/assets/images/posts/low-code/2020-03-27-create-private-facebook-messenger-chatbot-zap.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q60JVYin--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sarafian.github.io/assets/images/posts/low-code/2020-03-27-create-private-facebook-messenger-chatbot-zap.png" alt="2020-03-27-create-private-facebook-messenger-chatbot-zap" title="2020-03-27-create-private-facebook-messenger-chatbot-zap"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To configure the &lt;code&gt;Find a Subscriber in Chatfuel&lt;/code&gt; follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Type or select &lt;code&gt;chatfuel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Choose Action Event&lt;/code&gt;, scroll down and select &lt;code&gt;Find a Subscriber&lt;/code&gt;. This step is important and retrieves a value that helps target the session to send the message later on. In more advanced flow, this value is driven as a reaction to an incoming trigger.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Chatfuel account&lt;/code&gt; select &lt;code&gt;Add a New Account&lt;/code&gt; which will open a page and there select the &lt;code&gt;Example Private Messenger Bot&lt;/code&gt; to connect with.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Search Type&lt;/code&gt; there are multiple options. Let's choose the &lt;code&gt;Search by {{messenger user id}}&lt;/code&gt; which is the &lt;a href="https://developers.facebook.com/docs/pages/access-tokens/psid-api/"&gt;user page-scoped ID (PSID)&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;User ID&lt;/code&gt; follow these steps to retrieve it:

&lt;ol&gt;
&lt;li&gt;Make sure you have exchanged one or two messages with the bot.&lt;/li&gt;
&lt;li&gt;Navigate to &lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt;'s &lt;code&gt;Example Private Messenger Bot&lt;/code&gt;'s page.&lt;/li&gt;
&lt;li&gt;Open the &lt;code&gt;People&lt;/code&gt; panel and you should see your name on the list.&lt;/li&gt;
&lt;li&gt;Open your entry and scroll down to get the value from &lt;code&gt;messenger user id&lt;/code&gt; which is the value to fill in the &lt;code&gt;User ID&lt;/code&gt; on &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Activate the &lt;code&gt;TEST &amp;amp; REVIEW&lt;/code&gt; to confirm.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--081oTuNx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sarafian.github.io/assets/images/posts/low-code/2020-03-27-create-private-facebook-messenger-chatbot-zap-find-subscriber.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--081oTuNx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sarafian.github.io/assets/images/posts/low-code/2020-03-27-create-private-facebook-messenger-chatbot-zap-find-subscriber.png" alt="create-private-facebook-messenger-chatbot-zap-find-subscriber" title="create-private-facebook-messenger-chatbot-zap-find-subscriber"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To configure the &lt;code&gt;Send Text Message in Chatfuel&lt;/code&gt; follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Type or select &lt;code&gt;chatfuel&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Choose Action Event&lt;/code&gt; field, select &lt;code&gt;Send Text Message&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Chatfuel account&lt;/code&gt; field select the account that was created &lt;code&gt;Chatfuel Example Private Messenger Bot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Subscriber&lt;/code&gt; field select from the previous activity the &lt;code&gt;Chatfuel User ID&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the &lt;code&gt;Message Tag&lt;/code&gt; field, just choose &lt;code&gt;Update&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For the "Message Text&lt;code&gt;field, just enter&lt;/code&gt;Test from Zapier`.&lt;/li&gt;
&lt;li&gt;Activate the &lt;code&gt;TEST &amp;amp; REVIEW&lt;/code&gt; to confirm.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---X4zcH5u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sarafian.github.io/assets/images/posts/low-code/2020-03-27-create-private-facebook-messenger-chatbot-zap-send-message.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---X4zcH5u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sarafian.github.io/assets/images/posts/low-code/2020-03-27-create-private-facebook-messenger-chatbot-zap-send-message.png" alt="2020-03-27-create-private-facebook-messenger-chatbot-zap-send-message" title="2020-03-27-create-private-facebook-messenger-chatbot-zap-send-message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And on &lt;a href="https://www.messenger.com/"&gt;Messenger&lt;/a&gt; it will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EjgJE-GZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sarafian.github.io/assets/images/posts/low-code/2020-03-27-create-private-facebook-messenger-chatbot-chat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EjgJE-GZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://sarafian.github.io/assets/images/posts/low-code/2020-03-27-create-private-facebook-messenger-chatbot-chat.png" alt="create-private-facebook-messenger-chatbot-chat" title="create-private-facebook-messenger-chatbot-chat"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>chatbot</category>
      <category>lowcode</category>
      <category>messenger</category>
      <category>zapier</category>
    </item>
    <item>
      <title>Creating a private Telegram chatbot</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Wed, 25 Mar 2020 16:15:00 +0000</pubDate>
      <link>https://dev.to/sarafian/creating-a-private-telegram-chatbot-2n9</link>
      <guid>https://dev.to/sarafian/creating-a-private-telegram-chatbot-2n9</guid>
      <description>&lt;p&gt;If you need a bot for your personal home automation, then this post describes how to achieve what is perceived as a private bot on Telegram.&lt;/p&gt;

&lt;p&gt;In this post, I want to explain how to create a private bot in &lt;a href="https://desktop.telegram.org/"&gt;Telegram&lt;/a&gt;. With &lt;em&gt;private&lt;/em&gt;, I'm referring to bots that are not possible to be found by others or won't interact with others. These sort of bots are meant usually for some personal automation, where the bot act as the delivery entity to you or your family.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not exactly a private bot
&lt;/h2&gt;

&lt;p&gt;With &lt;a href="https://desktop.telegram.org/"&gt;Telegram&lt;/a&gt; bots are not private. Everybody can find them. The difference is that a certain communication channel with the bot can be made private. This is a group with the bot that you and the bot are members of. This sort of private channels is usually useful for home automation, where the bot is to speak with one person only.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the bot
&lt;/h2&gt;

&lt;p&gt;Creating the bot is generally easy by following instructions on &lt;a href="https://core.telegram.org/bots#6-botfather"&gt;Bots: An introduction for developers&lt;/a&gt; using the &lt;a href="https://telegram.me/BotFather"&gt;BotFather&lt;/a&gt;. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a session with &lt;a href="https://telegram.me/BotFather"&gt;BotFather&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;/newbot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter the name of the bot. &lt;code&gt;Example Bot for Blog&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enter a username for the bot. &lt;strong&gt;it must end with &lt;code&gt;bot&lt;/code&gt;&lt;/strong&gt;. &lt;code&gt;example_blog_bot&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Me, [25.03.20 16:02]&lt;br&gt;
/newbot&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:02]&lt;br&gt;
Alright, a new bot. How are we going to call it? Please choose a name for &amp;gt; your bot.&lt;/p&gt;

&lt;p&gt;Me, [25.03.20 16:03]&lt;br&gt;
Example Bot for Blog&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:03]&lt;br&gt;
Good. Now let's choose a username for your bot. It must end in &lt;code&gt;bot&lt;/code&gt;. Like &amp;gt; this, for example: TetrisBot or tetris_bot.&lt;/p&gt;

&lt;p&gt;Me, [25.03.20 16:03]&lt;br&gt;
example_blog_bot&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:03]&lt;br&gt;
Done! Congratulations on your new bot. You will find it at t.me/&amp;gt; example_blog_bot. You can now add a description, about section and profile &amp;gt; picture for your bot, see /help for a list of commands. By the way, when &amp;gt; you've finished creating your cool bot, ping our Bot Support if you want a &amp;gt; better username for it. Just make sure the bot is fully operational before &amp;gt; you do this.&lt;/p&gt;

&lt;p&gt;Use this token to access the HTTP API:&lt;br&gt;
1101361374:AAHS_DYrAUohT-HQXVKKz-M1howAxvXdRLA&lt;br&gt;
Keep your token secure and store it safely, it can be used by anyone to &amp;gt; control your bot.&lt;/p&gt;

&lt;p&gt;For a description of the Bot API, see this page: &lt;a href="https://core.telegram.org/%3E"&gt;https://core.telegram.org/&amp;gt;&lt;/a&gt; bots/api&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. The new bot is available and anyone can find it as &lt;a href="https://telegram.me/example_blog_bot"&gt;Example Bot for Blog&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;The bot has been deleted and therefore all sensitive information is irrelevant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a group with your bot
&lt;/h2&gt;

&lt;p&gt;This is a simple step. We need to do this now because afterward, we will disable the ability of the bot to be added into conversations.&lt;/p&gt;

&lt;p&gt;This group we have created is going to be also our private chat with the bot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable joining groups
&lt;/h2&gt;

&lt;p&gt;By default, the bot can be added to a group conversation by anybody who can find it. To make sure this doesn't happen, we need to disable this.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a session with &lt;a href="https://telegram.me/BotFather"&gt;BotFather&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;/setjoingroups&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter the name of the bot. &lt;code&gt;@example_blog_bot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;Disable&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Me, [25.03.20 16:13]&lt;br&gt;
/setjoingroups&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:13]&lt;br&gt;
Choose a bot to change group membership settings.&lt;/p&gt;

&lt;p&gt;Me, [25.03.20 16:13]&lt;br&gt;
@example_blog_bot&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:13]&lt;br&gt;
'Enable' - bot can be added to groups.&lt;br&gt;
'Disable' - block group invitations, the bot can't be added to groups.&lt;br&gt;
Current status is: ENABLED&lt;/p&gt;

&lt;p&gt;Me, [25.03.20 16:13]&lt;br&gt;
Disable&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:13]&lt;br&gt;
Success! The new status is: DISABLED. /help&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you try to add your bot into a group, you can't. So it is best that you already start a group with it before doing this step. You can always enable the group joining feature, create a group with it and yourself and then disable it again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interacting with the bot
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://core.telegram.org/bots/api"&gt;Telegram Bot API&lt;/a&gt; the API of &lt;a href="https://desktop.telegram.org/"&gt;Telegram&lt;/a&gt; is described. To interact with this bot we need the API token &lt;code&gt;1101361374:AAHS_DYrAUohT-HQXVKKz-M1howAxvXdRLA&lt;/code&gt; which the &lt;a href="https://telegram.me/BotFather"&gt;BotFather&lt;/a&gt; provided to us. The general uri pattern is &lt;code&gt;https://api.telegram.org/bot&amp;lt;token&amp;gt;/METHOD_NAME&lt;/code&gt;. &lt;strong&gt;Notice&lt;/strong&gt; that the token follows the word &lt;code&gt;bot&lt;/code&gt; in the URL.&lt;/p&gt;

&lt;p&gt;For example the &lt;code&gt;getMe&lt;/code&gt; method will provide information about the bot. Just do a &lt;code&gt;GET&lt;/code&gt; with this URL &lt;code&gt;https://api.telegram.org/bot1101361374:AAHS_DYrAUohT-HQXVKKz-M1howAxvXdRLA/getMe&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1101361374&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"is_bot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Example Bot for Blog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"example_blog_bot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"can_join_groups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"can_read_all_group_messages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"supports_inline_queries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To send messages to this &lt;em&gt;private&lt;/em&gt; group we've created with the bot, we will need to target it by providing the &lt;code&gt;chat_id&lt;/code&gt; parameter that represents this group. The &lt;code&gt;chat_id&lt;/code&gt; is also necessary for all integrations with other tools like &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt; or &lt;a href="https://www.integromat.com/"&gt;Integromat&lt;/a&gt; and this is why it is important.&lt;/p&gt;

&lt;p&gt;To extract it use the &lt;code&gt;getUpdates&lt;/code&gt; method. Do a &lt;code&gt;GET&lt;/code&gt; with this URL &lt;code&gt;https://api.telegram.org/bot1101361374:AAHS_DYrAUohT-HQXVKKz-M1howAxvXdRLA/getUpdates&lt;/code&gt;. If the result is empty then just type something to the bot in this group.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note that this method returns results only when the bot is not enabled for privacy&lt;/strong&gt;. If you want to enable privacy, make sure you do it after extracting the &lt;code&gt;chat_id&lt;/code&gt; as explained below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"update_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;726362299&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"message_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;877419474&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"is_bot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Alex"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"last_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Sarafian"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"chat"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;-475387861&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Example Blog Bot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
               &lt;/span&gt;&lt;span class="nl"&gt;"all_members_are_administrators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1585150611&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Hello&lt;/code&gt; is the message I had sent to the bot to make sure I could get results with &lt;code&gt;getUpdates&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From the JSON, the &lt;code&gt;chat_id&lt;/code&gt; is &lt;code&gt;-475387861&lt;/code&gt;. We can use this send a message using the &lt;code&gt;sendMessage&lt;/code&gt; method. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;sendMethod&lt;/code&gt; is much more complicated but for the purposes of this demonstration, a simple &lt;code&gt;GET&lt;/code&gt; with a simple message will suffice like this URL &lt;code&gt;https://api.telegram.org/bot1101361374:AAHS_DYrAUohT-HQXVKKz-M1howAxvXdRLA/sendMessage?chat_id=-475387861&amp;amp;text=Hello&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"ok"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1101361374&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"is_bot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"first_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Example Bot for Blog"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"example_blog_bot"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"chat"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;-475387861&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Example Blog Bot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
         &lt;/span&gt;&lt;span class="nl"&gt;"all_members_are_administrators"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1585151160&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And this has happened in the group with the bot&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Me, [25.03.20 16:36]&lt;br&gt;
Hello&lt;/p&gt;

&lt;p&gt;Example Bot for Blog, [25.03.20 16:46]&lt;br&gt;
Hello&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Configuring for privacy
&lt;/h2&gt;

&lt;p&gt;To enable encryption of the communication with the bot, you must enable the privacy feature. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a session with &lt;a href="https://telegram.me/BotFather"&gt;BotFather&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;/setprivacy&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Enter the name of the bot. &lt;code&gt;@example_blog_bot&lt;/code&gt;. &lt;strong&gt;Note&lt;/strong&gt; that the &lt;code&gt;@&lt;/code&gt; is required.&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;Enable&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Me, [25.03.20 16:09]&lt;br&gt;
/setprivacy&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:09]&lt;br&gt;
Choose a bot to change group messages settings.&lt;/p&gt;

&lt;p&gt;Me, [25.03.20 16:09]&lt;br&gt;
@example_blog_bot&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:09]&lt;br&gt;
'Enable' - your bot will only receive messages that either start with the '/' &amp;gt; symbol or mention the bot by username.&lt;br&gt;
'Disable' - your bot will receive all messages that people send to groups.&lt;br&gt;
Current status is: ENABLED&lt;/p&gt;

&lt;p&gt;Me, [25.03.20 16:09]&lt;br&gt;
Enable&lt;/p&gt;

&lt;p&gt;BotFather, [25.03.20 16:09]&lt;br&gt;
Success! The new status is: ENABLED. /help&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Remember&lt;/strong&gt; that after doing this the &lt;code&gt;getUpdates&lt;/code&gt; method from the API will return empty results or the last encrypted message.&lt;/p&gt;

</description>
      <category>chatbot</category>
      <category>lowcode</category>
      <category>telegram</category>
    </item>
    <item>
      <title>Low (No) Code tools from a software engineer's perspective</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Wed, 25 Mar 2020 16:12:28 +0000</pubDate>
      <link>https://dev.to/sarafian/low-no-code-tools-from-a-software-engineer-s-perspective-nm5</link>
      <guid>https://dev.to/sarafian/low-no-code-tools-from-a-software-engineer-s-perspective-nm5</guid>
      <description>&lt;p&gt;I've always had reservations for such tools and decided to take a look into this world of low (no) code tools. If you are looking for a light weight look into Buble, AirTable, Adalo, dashdash, Zapier, Integromat, chatfuel, ManyChat and others from a software engineer's perspective, then this is your post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overcoming initial reservations
&lt;/h2&gt;

&lt;p&gt;Full disclaimer here, my background in software engineering made me always suspicious about such type of tools or accelerators. Historically, we had plenty of them and they all performed the necessary function but with a huge price to pay in the long term. Who doesn't remember applications built in Access or even fancy Excel sheets driving big organization businesses? Anyone who has worked in a big organization has noticed a big amount of work being done in Excel sheets that are moved around by emails. But the temptation is big because it looks so easy at the beginning but it is also very easy to move from a convenience to a disaster. Applications in Excel sheets don't scale. We had to wait for Google Docs to show to the world on how to collaborate on the same resource online and that is still tricky. Microsoft's Office 365 collaboration is possible but still not very functional and the reality is that many people haven't picked up on the idea. Just mentioning the concept is for most like rocket science and this is not a technical topic but merely one of efficiency and productivity. Then we had the rise of the workflows with all the promises of &lt;em&gt;business&lt;/em&gt; people configuring and running their processes without the necessity of the &lt;em&gt;developers&lt;/em&gt; but we all know how that went as well. At the moment, some basic logic needed to be implemented, the &lt;em&gt;developer&lt;/em&gt; was necessary which kind of beats the purpose. Yes it takes longer to setup an actual application but the longer term benefits are well worth the effort.&lt;/p&gt;

&lt;p&gt;So, if I'm so negative about such tools why this blog post? Some time ago I started following the podcasts of &lt;a href="https://softwareengineeringdaily.com/2020/02/27/makerpad-low-code-tools-with-ben-tossell/"&gt;Software Engineering Daily&lt;/a&gt; and one of the most interesting ones I listened to was &lt;a href="https://softwareengineeringdaily.com/2020/02/27/makerpad-low-code-tools-with-ben-tossell/"&gt;Makerpad: Low Code Tools with Ben Tossell&lt;/a&gt;. I was impressed to be honest because the host &lt;a href="https://twitter.com/the_prion?lang=en."&gt;Jeff Meyerson&lt;/a&gt; who expressed similar reservations to mine seemed to be at least intrigued and towards changing his mind. So I decided to look deeper into this.&lt;/p&gt;

&lt;p&gt;Please keep in mind that this blog post is written by a person of strong technical background and it oriented towards an audience with similar understanding. Non technical people, might get confused and I'm sure that other articles would be more appropriate. Still, if you want to read the side of the story of those who build software applications, then by all means please read this post as well because it will provide some interesting remarks about the limitations of these tools from a long term and technical standpoint. I'm not going to go heavy on the technical so it won't be difficult to follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick and dirty investigation
&lt;/h2&gt;

&lt;p&gt;Initially, I found two very nice links that provide a list and a summary of each service&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://makermag.com/30-no-code-tools/"&gt;30 no-code and low-code tools for your next project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.integromat.com/en/blog/2019/11/18/every-tool-you-need-to-build-without-code/"&gt;Every Tool You Need to Build Without Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of the tools are known. For example &lt;a href="https://wordpress.com/"&gt;WordPress&lt;/a&gt; is a web site development and hosting tool that has a long and lasting history, starting from a blog engine and evolved to include more versatile flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  My discovery and filtering process
&lt;/h2&gt;

&lt;p&gt;After reading a bit on each service's website, watching some &lt;a href="https://www.youtube.com/"&gt;YouTube&lt;/a&gt; videos when available, I've kept only the ones that I've found the most interesting to do a deeper check. &lt;/p&gt;

&lt;p&gt;But each person has different drivers and I want first to explain my drivers and conditions that led to this smaller &lt;em&gt;filtered&lt;/em&gt; list.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Genuine curiosity. This is my strongest driver of them all. Note to myself, I should be doing this more frequently.&lt;/li&gt;
&lt;li&gt;At the aviation-related organization where I work there is some discussion about automating certain flows of different departments. While all fancy words are thrown into the mix, the typical culture is to buy a big fancy tool when simpler solutions or a bit of code could just suffice. After all, there are so much plethora of fancy services, that the hardest parts of the flow are available as a SAAS and only some glue code is required. The constant problem is that nobody wants to see a console to help make the automation simple.&lt;/li&gt;
&lt;li&gt;Recently I thought of an application that is missing. Like discussed in the podcast, I'm not keen on developing the entire stack and if there would be something that could help me prototype then that would be the best.&lt;/li&gt;
&lt;li&gt;In the past, I had used some PowerShell automation to develop a website for cheap weekend escapes in Europe with &lt;a href="https://www.ryanair.com/"&gt;RyanAir&lt;/a&gt;. I've discussed this in a previous &lt;a href="https://sarafian.github.io/2016/06/27/RyanAirWeekend.html"&gt;post&lt;/a&gt;. For various reasons that are related with restrictions from &lt;a href="https://www.ryanair.com/"&gt;RyanAir&lt;/a&gt;'s API, this stopped being functional but if these &lt;em&gt;low code&lt;/em&gt; tools can help then why not.&lt;/li&gt;
&lt;li&gt;This became important while already in my discovery process. Without going into much detail, because of the &lt;a href="https://en.wikipedia.org/wiki/Coronavirus_disease_2019"&gt;Coronavirus disease 2019&lt;/a&gt; I want to get to somehow in my cell phone notifications of specific emails and calendar events.&lt;/li&gt;
&lt;li&gt;For a long time now I've been contemplating with the idea of having a chat bot representative of myself for recruiters. This could help both of us spare time but I'm not sure the culture is there for Belgium. Regardless, this is still on mind and I would like to give it a try.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;During this process, my main condition was wether the tool or service has a free pricing tier. I quickly noticed that these tools can be very expensive and I'm not going to do full registrations for just exploring them. Also, although this didn't drive my filtering process, I started looking into whether the service provides support for automation pipelines like &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt;. Later on, I discovered &lt;a href="https://www.integromat.com/"&gt;Integromat&lt;/a&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tools and services of interest
&lt;/h2&gt;

&lt;p&gt;At the moment of writing this post, I've not investigated all the services mentioned here. But, I've seen enough to know what to expect. Below, I'll split the tools into groups of how I understand with a technical background and share some insight and comments&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WebSite builders&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This category is about developing a website with visual flows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Observations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://bubble.io/"&gt;Bubble&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Builds web and mobile applications without code. Looks very powerful and requires a lot of digging around&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.wix.com/corvid/"&gt;WIX Corvid&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;An open development platform that lets you build advanced web applications with a visual editor. I haven't checked it yet but from what I read is very good as well.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Everything you would expect is supported by this applications. Form validations, grids, connections with data stores, authentication and authorization. It's all there including a quite a lot of options for design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mobile app builders&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nowadays, there is little difference between a website and a mobile application. Still, the ability to produce an application that is published for Android or IOS is quite the differentiator.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Observations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://bubble.io/"&gt;Bubble&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Builds web and mobile applications without code. Looks very powerful and requires a lot of digging around&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.adalo.com/"&gt;Adalo&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Builds mobile application following the flow of a slide deck. Restricted and focused on creating very presentation-oriented mobile applications. Think of basic mobile applications that exist for marketing purposes or just to provide a presence and an entry into your brand.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;a href="https://www.glideapps.com/"&gt;Glide&lt;/a&gt; and &lt;a href="https://www.sheet2site.com/"&gt;Sheet2Site&lt;/a&gt;
&lt;/td&gt;
&lt;td&gt;I've not worked with them yet, but these tools seem to offer an even simpler case of &lt;a href="https://www.adalo.com/"&gt;Adalo&lt;/a&gt;, where instead of slide-show driven flow, the app will present based on a template, items from a Google spreadsheet. Add picture links on the sheet and you can have a very nice look.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Database like&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Although the tools themselves don't identify themselves as databases, in my view they are or all about data with some very interesting extra features.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Observations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://airtable.com/"&gt;Airtable&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;This the closest to a database concept with rules of validation for columns and linking entities. On top, it can create very interesting and fancy views of the data. It offers API to interact with the data. As far as I've seen it only supports integration with &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://dashdash.com/"&gt;dashdash&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;This is a spreadsheet on steroids. While on &lt;strong&gt;beta&lt;/strong&gt; at this moment of writing this post, what it does is that it can enhance or react upon a column on a row by driving an external API. It can also create the sheet by expanding on the results of an API call. Interesting and very focused for specific needs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Automation workflows&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These tools are all about creating flows that react on some external stimulus, do some data processing and then usually push that data to other external services, very similar to the traditional concept of workflows. For example, you can react upon a tweet, run it through a sentiment analysis engine and notify the appropriate person or group.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Observations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Probably the most mature service of them all. It is the only one that has integrations that allow the flow or zap, as they call it, to execute as a reaction to external events. Developers would know this pattern as a webhook integration which is used quite a lot in the CI/CD world.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.integromat.com/"&gt;Integromat&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Very similar to &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt; and looks more elegant and elaborate. It allows conditional flows in a bit different way. At this moment all flows are scheduled on intervals.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.actiondesk.io/"&gt;ActionDesk&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;I've not checked this yet because I'm still waiting for admission but from what I read this is supposed to be a child of &lt;a href="https://airtable.com/"&gt;Airtable&lt;/a&gt; and &lt;a href="https://dashdash.com/"&gt;dashdash&lt;/a&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What I found limiting on both tools is that they are very simple flow oriented. Normal workflows allow conditional and loop patterns but these tools don't. This could be to avoid driving non-technical profiles away.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notebook style collaborations&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Both &lt;a href="https://www.notion.so/"&gt;Notion&lt;/a&gt; and &lt;a href="https://coda.io/"&gt;Coda&lt;/a&gt; allow the mix of &lt;em&gt;functional&lt;/em&gt; with text. You can create wiki-like content, planning, to-do lists etc. The difference with &lt;a href="https://airtable.com/"&gt;Airtable&lt;/a&gt; is that these tools are more focused on the mix and the page and the data is there just for the embedding. They are quite powerful and act as a self-contained application.&lt;/p&gt;

&lt;p&gt;They remind me a bit of the concept of a &lt;a href="https://jupyter.org/"&gt;Jupyter Notebook&lt;/a&gt;where the mix of text and execution blocks from code is amazing. Opem the notebook, run it and voila you get some very rich page with dynamic table and charts to share and print. With these notebooks, the code is very visible and scary for many people but when I spoke with &lt;a href="https://dashdash.com/"&gt;dashdash&lt;/a&gt;, they showed me an upcoming feature that resembles such a functionality. I think if &lt;a href="https://www.notion.so/"&gt;Notion&lt;/a&gt;, [Code] and &lt;a href="https://dashdash.com/"&gt;dashdash&lt;/a&gt; could provide such a feature, where instead of python code you just see and interact with a grid or chart then this could be a killer feature in my opinion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chatbots&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have tried creating a chatbot then you know that this is not easy when it needs to be proper. It is not just that the logic is difficult but also that hosting the bot can be also very difficult with Facebook's messenger being the most demanding in my opinion to a fault. These tools allow a person to develop a chatbot application in a similar way to creating a website with e.g. &lt;a href="https://bubble.io/"&gt;Bubble&lt;/a&gt; but now instead of screens, you get dialogues.&lt;/p&gt;

&lt;p&gt;Like &lt;a href="https://bubble.io/"&gt;Bubble&lt;/a&gt; and &lt;a href="https://www.wix.com/corvid/"&gt;WIX Corvid&lt;/a&gt;, &lt;a href="https://manychat.com/"&gt;ManyChat&lt;/a&gt; and &lt;a href="https://chatfuel.com/"&gt;chatfuel&lt;/a&gt; can go deep in creating advanced functionality so I skipped this for now. What I ended up using them for is to send messages to messenger to use as notification on my cell phone. When I tried creating my application on Facebook to integrate with &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt; I kind of gave up and I found these tools to be a simpler alternative.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawbacks
&lt;/h2&gt;

&lt;p&gt;To my knowledge, none of these applications has this concept of change management and releases. I believe &lt;a href="https://bubble.io/"&gt;Bubble&lt;/a&gt; has this concept, where you have a developer version website to experiment and the actual &lt;em&gt;production&lt;/em&gt; one. Still, the process of change management, that is being able to review the changes while implementing features, is not there. Maybe it would be too scary for some people but in my opinion, this is a very important feature when collaborating. &lt;/p&gt;

&lt;p&gt;I've also noticed that many of these services can become expensive especially if you need to combine some of them. But this is something to be evaluated on a case by case basis. Like many accelerators, you get what you want fast and cheap but in the long term you might end up paying double and triple the cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Low-Code or No-Code
&lt;/h2&gt;

&lt;p&gt;There seems to be a confusion about whether to use the terms &lt;code&gt;low-code&lt;/code&gt; or &lt;code&gt;no-code&lt;/code&gt;. Although the marketing is oriented towards people who don't want to see any code, most of these tools require some basic understandings of how code works and hence the proper term is &lt;code&gt;low-code&lt;/code&gt;. It is not that one needs to understand code but it is good that some very programming principles like conditions, loops, variables, assignments, HTTP, rest, authentication, authorization etc are understood. Things have changed, and I'm sure that younger people are not so alienating or dismissing to these basic concepts because they are very much familiarized with technology since children. This is also something to keep in mind when trying to understand for who these applications and services are primarily intended for.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I have to admit, I'm convinced. Not entirely but let me elaborate.&lt;/p&gt;

&lt;p&gt;With proper understanding the scope and limitations of these tools you can have some serious things created. You don't have to pay for marketing apps if you have some creativity and you can have a basic interaction through a chat interface. What troubles me the most is the lack of change management. Maybe it's the software engineer inside me that is so concerned. For most basic applications that are oriented to serve information and help the brand grow, this would be an overkill. But when teams are involved and when bidirectional flows are implemented, then I'm concerned. Not sure if I would ever run serious production loads on the likes of &lt;a href="https://bubble.io/"&gt;Bubble&lt;/a&gt;, &lt;a href="https://airtable.com/"&gt;AirTable&lt;/a&gt;, &lt;a href="https://manychat.com/"&gt;ManyChat&lt;/a&gt; and &lt;a href="https://zapier.com/"&gt;Zapier&lt;/a&gt;. I would still advice to use these tools though for rapid prototyping. It is just that I know from experience, how a monster can be created by such tools when the prototype becomes the workhorse. If your company is your one-man show, then don't look elsewhere. There is incredible power here.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>The problem with regional settings/formatting from an expat's viewpoint</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Thu, 02 Jan 2020 22:28:16 +0000</pubDate>
      <link>https://dev.to/sarafian/the-problem-with-regional-settings-formatting-from-an-expat-s-viewpoint-2o3o</link>
      <guid>https://dev.to/sarafian/the-problem-with-regional-settings-formatting-from-an-expat-s-viewpoint-2o3o</guid>
      <description>&lt;p&gt;I'm from Greece which means non latin alphabet in the local language. Like many other Greek people who grew up in the 80s with a passion for technology before it became mainstream, we dislike and often hate Greek in any technology product as often the translations were and still are funny and it was also a safer option before the wide adoption of Unicode. This is not a unique attribute to the Greek technology forum but something quite common especially to countries with non-latin based alphabets.&lt;/p&gt;

&lt;p&gt;Before everything became an online SAAS, this was not such a big problem. Install Windows with English (United States), add the Greek language and the change the date formatting to dd/mm/yyyy. Only problem was with Office applications and especially Excel with numerical values. Depending on the active language there was a problem with &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;,&lt;/code&gt; when enterring numerical values. &lt;/p&gt;

&lt;p&gt;Now that everything's online, location in the operating system is important because it drives the online services and content. We also use the online variant of applications like Excel from different devices and sometimes from different locations.&lt;/p&gt;

&lt;p&gt;In 2011 I've moved to Belgium which has French, Dutch and a bit of German as local languages (Yes I know, oversimplified analysis). I've spoken with many Flemish (the Dutch speaking population) and those with similar age to mine also preferred English as their technology language. It wasn't as intense as with nationalities with non-latin alphabets but it is still recognizable. During the same period I transitioned into smartphones. First it was Windows Phone, then Android 4, then Windows Phone and finally Android. &lt;/p&gt;

&lt;p&gt;To summarize: I live in a country with multiple languages (mainly Dutch and French), prefer all technology stuff in a non local language (English) and I often mix content with a non-latin alphabet language (English+Greek).&lt;/p&gt;

&lt;p&gt;On my Android phone I've never had issues with regions etc. Very simple to be honest. I find the experience on Android a much better one than Windows and Windows Phone mostly because I find that Microsoft tries too much to derive settings and takes control from the user.  You see this difference when accessing an excel file from your home and work computer either on the browser or with the location application. Compared to Android app experience, it is so confusing and unproductive especially when I need to switch languages. For example, when openning the same excel file from the Android app, it just works. No mix up with &lt;code&gt;.&lt;/code&gt; and &lt;code&gt;,&lt;/code&gt; for the decimal point. It just works as with many other things that kind of make the Windows desktop OS feel like buggy.&lt;/p&gt;

&lt;p&gt;Numerical entries should work with the numeric pad but when the decimal function changes all the time then mistakes happen often. To be fair to Microsoft, Android usage doesn't include a numeric pad nor have I used Google OS with a full desktop keyboard. So the "my just works" could be incorrect but my point is still that it should still work everywhere this simple.&lt;/p&gt;

&lt;p&gt;The above example with Excel is one of the problems. I focused on it because it is the easiest one to explain especially to people who are used to only one language in their life in technology products. Let's go over a more complicated example which is derived by a mix of being expat and IT organizational policies. &lt;/p&gt;

&lt;p&gt;Let's take Office 365 as an example. First time you login with your professional account it needs to initialize to the profile. Part of the initialization is about localization and regions for which the user is not asked. My current employer utilizes a sort of a randomization for proxies that have IPs from different countries. You can immediately recognize this from the first access to &lt;code&gt;google.com&lt;/code&gt; or &lt;code&gt;maps.google.com&lt;/code&gt;. My proxy is one with a French IP.&lt;/p&gt;

&lt;p&gt;Let's compare the Google and Microsoft experience.&lt;/p&gt;

&lt;p&gt;Google search:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Browse to &lt;code&gt;google.com&lt;/code&gt; and you get redirected to google's french website.&lt;/li&gt;
&lt;li&gt;Scroll down and choose English. Easy to recognize. It is not even written in French.&lt;/li&gt;
&lt;li&gt;Done. That's it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Office 365:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Browse to any of their services.&lt;/li&gt;
&lt;li&gt;Authenticate with organization account.&lt;/li&gt;
&lt;li&gt;Profile gets initialized and everything is in French.&lt;/li&gt;
&lt;li&gt;Go to Outlook and change language relatively easily to English.&lt;/li&gt;
&lt;li&gt;Go to any office app or onedrive and get mixes toolbars with french and english.&lt;/li&gt;
&lt;li&gt;Wonder why the setting I've already changed in step 4 isn't working. &lt;/li&gt;
&lt;li&gt;Go home, access the same account and it is still in French.&lt;/li&gt;
&lt;li&gt;Navigate in settings that are all in French? Not easy if you don't know French.&lt;/li&gt;
&lt;li&gt;Ask IT. They haven't thought about it.&lt;/li&gt;
&lt;li&gt;Google it. Yes it is in English.&lt;/li&gt;
&lt;li&gt;Follow the instructions &lt;a href="https://sarafian.github.io/tips/2019/04/23/change-language-office-com.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2F2019-04-23-onedrive-french.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsarafian.github.io%2Fassets%2Fimages%2Fposts%2F2019-04-23-onedrive-french.PNG" alt="OneDrive"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every action within each of the Word, Excel, Powerpoint, OneNote etc applications of the Office 365 has the same behavior.&lt;/p&gt;

&lt;p&gt;Here is another problem which is also the reason I decided to write about this. I recently formatted my Windows OS. I wanted to play nice and be accurate with the information I provided. I usually set all the English United States and add the Greek language but I though maybe things have changed. This is what I did:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chose Belgium as region instead of United States that I usually do&lt;/li&gt;
&lt;li&gt;Added English (International), Greek and removed French and Dutch keyboards&lt;/li&gt;
&lt;li&gt;Chose English (UK) for the formatting, because it matches better the date and metric and it is in English compared to the Belgium counterparts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Somehow the Windows OS adds a third language (English UK) no matter how many times I've removed it just because the formatting is English UK. But I don't want another entry in my keyboard. I need to rotate between an English and Greek and an additional English language creates problems because you often end up switching from English to English but from international layout to UK layout.&lt;/p&gt;

&lt;p&gt;I'm not saying that Google is perfect but considering the user experience it is much better, less confusing and less frustrating than the experience with Microsoft. It is not about which product is better or not but how much and how hard the system tries to help the user and instead ends up working against him or her. It seems to me that Google has better realized their global customer reach than Microsoft and has chosen to leave some UX aspects to manual or I could be mistaken because an android phone is much simpler compared to a desktop keyboard. Still, the small device makes the big device look like buggy.&lt;/p&gt;

&lt;p&gt;Why is this important? Because movement for work is ever increasing in the world without staying within the boundaries of one country. Take the European Union for example which combined is a much bigger population than USA with incredible variety. To help understand non-EU citizens, this is EU again over simplified.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each member country has a strong history and is very opinionated about regional things.&lt;/li&gt;
&lt;li&gt;None of the remaining member countries (BREXIT) has English as official language. &lt;/li&gt;
&lt;li&gt;English is the professional language because the rest of the world speaks English as well and because the French, Germans, Spanish and Italians had no intention of speaking of anything else and English is a global necessity.&lt;/li&gt;
&lt;li&gt;There is a freedom of movement to live and work, kind of similar to the EU area being one country.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this trillion dollar economy there is a problem which technology doesn't seem to have solved. I understand that it is not easy because localization and regional support is not an easy problem to tackle. Most of us take this for granted but like date/time it is much more of a challenge than we most understand. DateTime has to function otherwise things break but regional settings don't, like I've experienced. Date/Time related solutions are focused on functional accuracy and got it mostly correct where regional settings solutions are focused on UX and it depends on who you ask if they got it correctly. In a world that seems to globalize, until we all agree into one English international language, settings and metric system, it seems to me that something is being done wrongly.&lt;/p&gt;

&lt;p&gt;My proposals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let the user specify independently the location, region and input methods. Don't derive any conclusions and don't take any actions on behalf of the user.&lt;/li&gt;
&lt;li&gt;Drive this with a smaller scope. Give the user control per application or even better per resource. Do it like the portable applications have been doing.&lt;/li&gt;
&lt;li&gt;If possible, do this with an override settings not to upset the status quo.&lt;/li&gt;
&lt;li&gt;Most importantly, &lt;strong&gt;make it easy to find or control&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm aware that this could be similar to the feature requests to the Microsoft Office team before the introduction of the ribbon bar. 90% of them were already available but users didn't know where they were. I'm sure that some of the solutions issues are like this and there is already a solution through some option somewhere, like the one explained for office 365. Regardless, I stand by  &lt;strong&gt;making it easy to find or control&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'm really interested into your opinions about this topic. Do you face similar problems? If yes please mention origin, location and your tricks and tips in your comments?  &lt;/p&gt;

&lt;p&gt;Some explanations were over simplified to avoid losing focus into complicated issues in the European Union. I hope you understand.&lt;/p&gt;

</description>
      <category>region</category>
      <category>global</category>
      <category>microsoft</category>
      <category>google</category>
    </item>
    <item>
      <title>Building Careers with Empathy with Scott Hanselman</title>
      <dc:creator>Alex Sarafian</dc:creator>
      <pubDate>Fri, 18 Oct 2019 07:04:15 +0000</pubDate>
      <link>https://dev.to/sarafian/building-careers-with-empathy-with-scott-hanselman-2eoe</link>
      <guid>https://dev.to/sarafian/building-careers-with-empathy-with-scott-hanselman-2eoe</guid>
      <description>&lt;p&gt;I thought to share visibility on this career and life video both the perspective of the person growing but also from when you become a coach.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/6eSpILu7wpg"&gt;
&lt;/iframe&gt;
 &lt;/p&gt;

&lt;p&gt;There are a couple of important topics I would like to put focus on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You, the experienced person have "life to spare" when a stupid question is required to be asked. Your younger and just starting counterpart doesn't. So don't be afraid to take a hit&lt;/li&gt;
&lt;li&gt;Always understand where your code is being executed. This is for me a big problem currently in the industry.&lt;/li&gt;
&lt;li&gt;Visibility and sharing of knowledge.&lt;/li&gt;
&lt;li&gt;Luck is necessary. Skill as well. Having skills is a lucky thing to be born with.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Especially on the topic of luck and skill, it is very rare when an American, especially with a successful career, recognizes that it is not just a matter of hard work but also luck and coincidence are necessary to succeed in life. If it is not luck then it is lack of unlucky moments. This is something that we tend to forget when we judge other people and personally frustrates me. There can be many things that could have gone wrong for a person but also many things that just go right to others. If you are one of the lucky ones, then you should be respectful to those who weren't.&lt;/p&gt;

&lt;p&gt;I also find this "building careers" series of interviews happening at Microsoft very interesting.&lt;/p&gt;

&lt;p&gt;PS, There is something about &lt;a href="https://www.hanselman.com/"&gt;Scott Hanselman's&lt;/a&gt; presence that puts me off but it is just me. Nevertheless, I find most of what he says and writes about exceptionally insightful with a lot of honestly, pragmatism and simple reasoning. &lt;/p&gt;

</description>
      <category>career</category>
      <category>management</category>
      <category>interview</category>
    </item>
  </channel>
</rss>
