<?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>Forem: Mark Wragg</title>
    <description>The latest articles on Forem by Mark Wragg (@markwragg).</description>
    <link>https://forem.com/markwragg</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%2F18115%2Fcefc76f8-2201-40ea-85be-44a52313d897.png</url>
      <title>Forem: Mark Wragg</title>
      <link>https://forem.com/markwragg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/markwragg"/>
    <language>en</language>
    <item>
      <title>Two ways to use Pester to Mock objects with strongly typed parameters</title>
      <dc:creator>Mark Wragg</dc:creator>
      <pubDate>Thu, 24 Oct 2024 17:43:16 +0000</pubDate>
      <link>https://forem.com/markwragg/two-ways-to-use-pester-to-mock-objects-with-strongly-typed-parameters-31n7</link>
      <guid>https://forem.com/markwragg/two-ways-to-use-pester-to-mock-objects-with-strongly-typed-parameters-31n7</guid>
      <description>&lt;p&gt;When writing Pester unit tests, it's pretty common to want to &lt;code&gt;Mock&lt;/code&gt; cmdlets so that you can validate they've been called when expected, and the expected number of times.&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="n"&gt;Mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Some-Command"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-MockWith&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;"Should invoke Some-Command the expected number of times"&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;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Invoke&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Some-Command"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Times&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Exactly&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;Some commands however can be difficult to &lt;code&gt;Mock&lt;/code&gt; because one of more of their input parameters requires a specific type of object. An example of this is the Azure storage cmdlet &lt;code&gt;New-AzStorageContext&lt;/code&gt;. This creates a &lt;code&gt;Microsoft.WindowsAzure.Commands.Storage.AzureStorageContext&lt;/code&gt; type object, which other storage cmdlets then expect as an input. &lt;/p&gt;

&lt;p&gt;There's two ways to handle this:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Use New-MockObject
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;New-MockObject&lt;/code&gt; Pester cmdlet allows you to create an object of a specified type, with the properties and methods that you require. For &lt;code&gt;New-AzStorageContext&lt;/code&gt; you could do something like this:&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;Mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;New-AzStorageContext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-MockWith&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;New-MockObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Microsoft.WindowsAzure.Commands.Storage.AzureStorageContext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Properties&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;StorageAccountName&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="s1"&gt;'somestorageaccount'&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Context&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;StorageAccountName&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="s1"&gt;'somestorageaccount'&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;However for &lt;code&gt;New-MockObject&lt;/code&gt; to work, the type you want to fake has to be available on the system (i.e the relevant module/cmdlets must be installed). &lt;/p&gt;

&lt;h2&gt;
  
  
  2. Use -RemoveParameterType
&lt;/h2&gt;

&lt;p&gt;The alternative option is to use the &lt;code&gt;-RemoveParameterType&lt;/code&gt; parameter on the &lt;code&gt;Mock&lt;/code&gt; that needs to receive the strongly typed object. This removes the strong typing on the specified input parameter and means that you can therefore &lt;code&gt;Mock&lt;/code&gt; the source object's output as just a &lt;code&gt;[pscustomobject]&lt;/code&gt;. For example:&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;Mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;New-AzStorageContext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-MockWith&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="n"&gt;pscustomobject&lt;/span&gt;&lt;span class="p"&gt;]@{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;StorageAccountName&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="s1"&gt;'somestorageaccount'&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Context&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;StorageAccountName&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="s1"&gt;'somestorageaccount'&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;And then on the receiving &lt;code&gt;Mock&lt;/code&gt; you do:&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;Mock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get-AzStorageTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-RemoveParameterType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Context'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-MockWith&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="n"&gt;pscustomobject&lt;/span&gt;&lt;span class="p"&gt;]@{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;Name&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="s1"&gt;'sometable'&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;CloudTable&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;Name&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="s1"&gt;'somename'&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;This also negates the need for the type to be available on the system where your tests execute.&lt;/p&gt;

&lt;p&gt;For more on &lt;a href="https://pester.dev/docs/usage/mocking" rel="noopener noreferrer"&gt;Mocking with Pester see here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>pester</category>
      <category>testing</category>
      <category>azure</category>
    </item>
    <item>
      <title>How to remove null or empty string values from a list in Terraform</title>
      <dc:creator>Mark Wragg</dc:creator>
      <pubDate>Tue, 22 Oct 2024 10:36:31 +0000</pubDate>
      <link>https://forem.com/markwragg/how-to-remove-null-or-empty-string-values-from-a-list-in-terraform-1e3b</link>
      <guid>https://forem.com/markwragg/how-to-remove-null-or-empty-string-values-from-a-list-in-terraform-1e3b</guid>
      <description>&lt;p&gt;I was recently implementing a change to a Terraform &lt;code&gt;azurerm_key_vault&lt;/code&gt; Key Vault resource to allow a specified list of IP addresses on the firewall. The IP addresses would be provided via an Azure DevOps variable, which would contain a comma-separated list. This list is then turned into a list value in Terraform via the &lt;code&gt;split&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;I wanted the change to the resource to continue to work if the variable was not specified, but when no value was provided the result would be an empty string, and this was not a valid value for the &lt;code&gt;ip_rules&lt;/code&gt; property of the Key Vault resource, which requires either &lt;code&gt;null&lt;/code&gt; or a list of values.&lt;/p&gt;

&lt;p&gt;The solution was to use the &lt;a href="https://developer.hashicorp.com/terraform/language/functions/compact" rel="noopener noreferrer"&gt;compact function&lt;/a&gt;. This takes a list of strings and removes any null or empty string elements:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_key_vault"&lt;/span&gt; &lt;span class="s2"&gt;"keyvault"&lt;/span&gt; &lt;span class="p"&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;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyVaultName&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;
  &lt;span class="nx"&gt;resource_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rgName&lt;/span&gt;
  &lt;span class="nx"&gt;sku_name&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"standard"&lt;/span&gt;
  &lt;span class="nx"&gt;tenant_id&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azurerm_client_config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tenant_id&lt;/span&gt;

  &lt;span class="nx"&gt;network_acls&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;default_action&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Deny"&lt;/span&gt;
    &lt;span class="nx"&gt;ip_rules&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;compact&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;split&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="nx"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyVaultAllowedIPs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compact function appears to have been a part of Terraform since at least version 1.1 but looking at the documentation it appears that it only started to remove &lt;code&gt;null&lt;/code&gt; values from strings (as well as empty strings) as of version 1.5.&lt;/p&gt;

&lt;p&gt;At time of writing the current production release of Terraform is 1.9.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>devops</category>
      <category>azure</category>
      <category>infrastructureascode</category>
    </item>
    <item>
      <title>Redirect Out-File to TestDrive: in your PowerShell Pester test scripts with this one weird trick</title>
      <dc:creator>Mark Wragg</dc:creator>
      <pubDate>Sat, 19 Oct 2024 14:01:19 +0000</pubDate>
      <link>https://forem.com/markwragg/redirect-out-file-to-testdrive-in-your-powershell-pester-test-scripts-with-this-one-weird-trick-cjm</link>
      <guid>https://forem.com/markwragg/redirect-out-file-to-testdrive-in-your-powershell-pester-test-scripts-with-this-one-weird-trick-cjm</guid>
      <description>&lt;p&gt;I was writing some &lt;a href="https://pester.dev/" rel="noopener noreferrer"&gt;Pester&lt;/a&gt; unit tests recently for a PowerShell script that creates a modified version of a template file before it is then uploaded via an API and deleted. The script uses &lt;code&gt;Out-File&lt;/code&gt; to output the updated file and because it only exists temporarily the location it writes to is hard coded in the script.&lt;/p&gt;

&lt;p&gt;I wanted to write some tests that would validate the file was created and with the expected updated values. I could have just let the script write the file to it's default location and validate it there, but I'd have to mock &lt;code&gt;Remove-Item&lt;/code&gt; to stop it deleting the file and then have my test script remove it afterwards. Another approach might have been to do some refactoring, have the output file and input parameter of the script, or break the script up into smaller functions, but I didn't particularly want to change the script.&lt;/p&gt;

&lt;p&gt;Pester provides an automatic location &lt;a href="https://pester.dev/docs/usage/testdrive" rel="noopener noreferrer"&gt;TestDrive:&lt;/a&gt; that can be used to isolate file operations somewhere unique and that it automatically cleans up when the test completes, so all I needed to do was override the behaviour of &lt;code&gt;Out-File&lt;/code&gt; to write to &lt;code&gt;TestDrive:&lt;/code&gt;. You can do that with a &lt;code&gt;Mock&lt;/code&gt;, and the one-weird-trick here is to store the &lt;code&gt;Out-File&lt;/code&gt; command into a variable so that we can use it within the &lt;code&gt;Mock&lt;/code&gt;, but change it's input parameters:&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="nv"&gt;$OutFile&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;Get-Command&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="s1"&gt;'Out-File'&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;Out-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ParameterFilter&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;$FilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'file.txt'&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="nt"&gt;-MockWith&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;$InputObject&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;$PesterBoundParameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'InputObject'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$FilePath&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;Join-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$TestDrive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'file.txt'&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="nv"&gt;$OutFile&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="nv"&gt;$InputObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-FilePath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FilePath&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="s1"&gt;'Should update the file with the expected values'&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;$FilePath&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;Join-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$TestDrive&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'file.txt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nv"&gt;$FilePath&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;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-FileContentMatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'expectedstring1'&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nv"&gt;$FilePath&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;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-FileContentMatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'expectedstring2'&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nv"&gt;$FilePath&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;Should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-FileContentMatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'expectedstring3'&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;It is necessary to put the command into a variable because once a command is mocked in a test script, calling it would invoke the &lt;code&gt;Mock&lt;/code&gt; rather than the command, so you'd end up in a recursive loop. Note how the &lt;code&gt;Mock&lt;/code&gt; uses &lt;code&gt;$PesterBoundParameters&lt;/code&gt; to access the parameters that were passed to the command in the script, but we then override what would have been provided for &lt;code&gt;-FilePath&lt;/code&gt; with our &lt;code&gt;TestDrive:&lt;/code&gt; pathed value.&lt;/p&gt;

&lt;p&gt;My script still mocked &lt;code&gt;Remove-Item&lt;/code&gt; btw, so we could check that it had been called the expected number of times. There was no need to let it actually do a file removal because the clean up of &lt;code&gt;TestDrive:&lt;/code&gt; takes care of that for us. It's usually best to mock away the destructive behaviour of cmdlets when testing so that if the script has been badly modified in some way you don't risk invoking the actual behaviour for the purpose of running your tests.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>pester</category>
      <category>devops</category>
      <category>testing</category>
    </item>
    <item>
      <title>Hi, I'm Mark Wragg</title>
      <dc:creator>Mark Wragg</dc:creator>
      <pubDate>Fri, 05 May 2017 14:30:21 +0000</pubDate>
      <link>https://forem.com/markwragg/hi-im-mark-wragg</link>
      <guid>https://forem.com/markwragg/hi-im-mark-wragg</guid>
      <description>&lt;p&gt;👋 Hi! I am an Azure DevOps Engineer from the UK. I live in Basingstoke with my wife and three small humans. &lt;/p&gt;

&lt;p&gt;I've worked full-time in IT since graduating with a Degree in Computing in 2003, with the exception of a year out to give Teacher Training a whirl. Much of my initial IT career experience was working in front-line operations roles, supporting infrastructure and SaaS applications hosted in private data centres and the cloud. Since 2017 I've worked as a DevOps Engineer and for the last few years as a contractor. My experience is predominantly with Microsoft technologies but I can generally turn a quick hand to any tool and I have experience with AWS and Azure as well as a variety of DevOps toolsets.&lt;/p&gt;

&lt;p&gt;You can follow me on Twitter &lt;a href="https://twitter.com/markwragg" rel="noopener noreferrer"&gt;@markwragg&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I am particularly passionate about PowerShell and have spoken twice at &lt;a href="https://psday.uk/" rel="noopener noreferrer"&gt;PSDay.UK&lt;/a&gt;, the UK's annual PowerShell Conference. If you'd like to view my talks they can be found here:&lt;/p&gt;

&lt;h4&gt;
  
  
  Public Speaking
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=V7PYt9tWFw8" rel="noopener noreferrer"&gt;Measure all the things with Influx, Grafana and PowerShell&lt;/a&gt; &lt;em&gt;-- PSDay Birmingham 2019&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.youtube.com/watch?v=BbOiQCgDDR8&amp;amp;feature=youtu.be" rel="noopener noreferrer"&gt;Mastering PowerShell Testing with Pester&lt;/a&gt; &lt;em&gt;-- PSDay London 2018&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/markwragg/Presentations/tree/master/20180925_Southampton-PSUG" rel="noopener noreferrer"&gt;How to Develop Cross-Platform Compatible Modules using PowerShell Code&lt;/a&gt; &lt;em&gt;-- Southampton PowerShell Usergroup 2018 (slides only, not recorded)&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Books
&lt;/h4&gt;

&lt;p&gt;I also made voluntary contributions to the following books, which raised funds for the DevOps Collective OnRamp scholarship:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://leanpub.com/powershell-conference-book" rel="noopener noreferrer"&gt;The PowerShell Conference Book volume 1&lt;/a&gt; &lt;em&gt;-- contributed a chapter on PowerShell code testing with Pester&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://leanpub.com/psconfbook2" rel="noopener noreferrer"&gt;The PowerShell Conference Book volume 2&lt;/a&gt; &lt;em&gt;-- contributed a chapter on monitoring with Influx, Grafana and PowerShell&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Open Source
&lt;/h4&gt;

&lt;p&gt;I maintain a number of Open Source code repositories for tools that I've developed that I felt could be useful to the wider community. You can find those in my profile on &lt;a href="https://github.com/markwragg" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Some that are particularly popular include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/markwragg/PowerShell-Influx" rel="noopener noreferrer"&gt;PowerShell-Influx&lt;/a&gt; &lt;em&gt;-- a PowerShell module for sending metrics into the time-series platform Influx.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/markwragg/Test-ActiveDirectory" rel="noopener noreferrer"&gt;Test-ActiveDirectory&lt;/a&gt; &lt;em&gt;-- a set of Pester tests for validating the health of a deployment of Active Directory.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/markwragg/Powershell-SlackBot" rel="noopener noreferrer"&gt;PowerShell-SlackBot&lt;/a&gt; &lt;em&gt;-- a PowerShell module for hosting a chat bot for Slack using PowerShell and TCP Sockets. The chat bot can then be configured to listen to and respond to specific messages and run PowerShell commands that are initiated from within a chat window.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any other burning questions about me, feel free to get in touch! :)&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
