<?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: Mark Wragg</title>
    <description>The latest articles on DEV Community by Mark Wragg (@markwragg).</description>
    <link>https://dev.to/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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F18115%2Fcefc76f8-2201-40ea-85be-44a52313d897.png</url>
      <title>DEV Community: Mark Wragg</title>
      <link>https://dev.to/markwragg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/markwragg"/>
    <language>en</language>
    <item>
      <title>A PowerShell currency conversion module</title>
      <dc:creator>Mark Wragg</dc:creator>
      <pubDate>Mon, 26 Oct 2026 14:41:24 +0000</pubDate>
      <link>https://dev.to/markwragg/a-powershell-currency-conversion-module-5ghe</link>
      <guid>https://dev.to/markwragg/a-powershell-currency-conversion-module-5ghe</guid>
      <description>&lt;ul&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/markwragg/PowerShell-CurrencyConverter" rel="noopener noreferrer"&gt;https://github.com/markwragg/PowerShell-CurrencyConverter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two and a half years ago, I published a module to the &lt;a href="https://www.powershellgallery.com/packages/currencyconverter" rel="noopener noreferrer"&gt;PowerShell Gallery&lt;/a&gt; (the official Microsoft nuget repository for PowerShell scripts and modules) called &lt;a href="https://github.com/markwragg/PowerShell-CurrencyConverter" rel="noopener noreferrer"&gt;CurrencyConverter&lt;/a&gt;. It came from another module I was working on called &lt;a href="https://github.com/markwragg/PowerShell-AzCostTools" rel="noopener noreferrer"&gt;AzCostTools&lt;/a&gt;, in which I found I had a need to convert cost data that I was exporting out of Azure, into a local currency.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I originally blogged about this here: &lt;a href="https://wragg.io/Perform-currency-conversion-with-PowerShell/" rel="noopener noreferrer"&gt;https://wragg.io/Perform-currency-conversion-with-PowerShell/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I wanted my &lt;a href="https://github.com/markwragg/PowerShell-AzCostTools" rel="noopener noreferrer"&gt;AzCostTools&lt;/a&gt; module to be able to convert currency without the user having to sign up for a service and provide an API key, which led me to &lt;a href="https://www.exchangerate-api.com/" rel="noopener noreferrer"&gt;ExchangeRate-API&lt;/a&gt;, which provides an open API for currency conversion. CurrencyConverter uses this by default when converting Fiat (traditional, government-issued) currencies. This API refreshes daily, so you are not necessarily getting an exact exchange rate, but probably something that is close enough for general use. You can sign up to ExchangeRate-API if you want rates that are updated more frequently, and CurrencyConverter then supports this, you just provide your key via the &lt;code&gt;-ApiKey&lt;/code&gt; parameter. &lt;/p&gt;

&lt;p&gt;A short while after I published the module, someone raised an &lt;a href="https://github.com/markwragg/PowerShell-CurrencyConverter/issues/1" rel="noopener noreferrer"&gt;issue on GitHub asking if it could support Crypto currencies&lt;/a&gt;. ExchangeRate-API didn't offer this, but I discovered there was an open API for crypto currencies provided by &lt;a href="https://api.coinbase.com/v2" rel="noopener noreferrer"&gt;CoinBase&lt;/a&gt;, so I added some additional cmdlets to wrap this API and allow for the conversion of these currencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Because the module is published to the PowerShell Gallery, you can install it using PowerShell's package management cmdlets:&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;Install-Module&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CurrencyConverter&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you'd like to inspect the code directly, get it from &lt;a href="https://github.com/markwragg/PowerShell-CurrencyConverter" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The module is cross-platform, and has been tested on Windows (via Windows PowerShell and PowerShell 7), MacOS and Linux.&lt;/p&gt;

&lt;p&gt;When I write a PowerShell module that wraps an API, I try to go beyond just returning the results of that API (because if that was all it did, you might as well just use &lt;code&gt;Invoke-RestMethod&lt;/code&gt;). Although it is nice that PowerShell cmdlets allow you to extrapolate away the need for a user to know how to craft an API request (by providing parameter inputs instead), and also potentially finesse the results, returned as PowerShell objects that can then be further interrogated and manipulated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cmdlets
&lt;/h2&gt;

&lt;p&gt;CurrencyConverter's initial cmdlets were as follows:&lt;/p&gt;

&lt;h3&gt;
  
  
  Convert-Currency
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Convert-Currency&lt;/code&gt; allows you to convert a decimal value between two currencies, and returns a decimal value result. You can provide the value via the &lt;code&gt;-Value&lt;/code&gt; parameter, or via the pipeline (which can be one or more values):&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;Convert-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GBP&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;74.778300
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;200&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;Convert-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EUR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;JPY&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;17584.342200
26376.513300
35168.684400
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that there's parameter validation on the &lt;code&gt;-From&lt;/code&gt; and &lt;code&gt;-To&lt;/code&gt; parameters with the codes for all of the supported currencies, so you can just tab through the various codes (and it will reject ones that are not supported). &lt;/p&gt;

&lt;h3&gt;
  
  
  Get-Currency
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Get-Currency&lt;/code&gt; allows you to list all supported currencies:&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;Get-Currency&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code Name                          Country
---- ----                          -------
AED  UAE Dirham                    United Arab Emirates
AFN  Afghan Afghani                Afghanistan
ALL  Albanian Lek                  Albania
AMD  Armenian Dram                 Armenia
ANG  Netherlands Antillian Guilder Netherlands Antilles
AOA  Angolan Kwanza                Angola
ARS  Argentine Peso                Argentina
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which you can also use to discover a currency, by providing its code or country, 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;Get-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Country&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Singapore&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code Name             Country
---- ----             -------
SGD  Singapore Dollar Singapore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Format-Currency
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Format-Currency&lt;/code&gt; returns a formatted string for a specified currency, including the currency symbol and rounded to two decimal places:&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="mi"&gt;100&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;Format-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$100.00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which you can chain from &lt;code&gt;Convert-Currency&lt;/code&gt; (or any PowerShell script or command that returns a decimal value):&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="mi"&gt;100&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;Convert-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EUR&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;Format-Currency&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;€89.21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the destination currency is included as a &lt;code&gt;NoteProperty&lt;/code&gt; output from &lt;code&gt;Convert-Currency&lt;/code&gt; which then allows it to be received as an input by &lt;code&gt;Format-Currency&lt;/code&gt; and avoids it having to be specified manually. If you were just providing a value directly to &lt;code&gt;Format-Currency&lt;/code&gt; then you'd need to specify the currency as an input:&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="mi"&gt;100&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;Format-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EUR&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;€100.00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In some cultures, the currency symbol is written after the amount. You can have &lt;code&gt;Format-Currency&lt;/code&gt; do this by specifying &lt;code&gt;-SymbolAtEnd&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="mi"&gt;100&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;Format-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EUR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-SymbolAtEnd&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;100.00€
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Get-ExchangeRate
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Get-ExchangeRate&lt;/code&gt; returns all (supported) exchange rates for a specified currency, or a specified exchange rate between two currencies:&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;Get-ExchangeRate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result                : success
provider              : https://www.exchangerate-api.com
documentation         : https://www.exchangerate-api.com/docs/free
terms_of_use          : https://www.exchangerate-api.com/terms
time_last_update_unix : 1792972951
time_last_update_utc  : Mon, 26 Oct 2026 00:02:31 +0000
time_next_update_unix : 1793060461
time_next_update_utc  : Tue, 27 Oct 2026 00:21:01 +0000
time_eol_unix         : 0
base_code             : USD
rates                 : @{USD=1; AED=3.6725; AFN=64.826446; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note this returns the full API result, and the actual exchange rates are in the &lt;code&gt;rates&lt;/code&gt; property when using the Open API, or &lt;code&gt;conversion_rates&lt;/code&gt; when using an API key. If you just want to return the exchange rates (regardless of which API you're using) then specify &lt;code&gt;-Rates&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="n"&gt;Get-ExchangeRate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GBP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Rates&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GBP : 1
AED : 4.910876
AFN : 86.523878
ALL : 108.353838
AMD : 482.971946
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Convert-CryptoCurrency, Get-CryptoCurrency, Get-CryptoExchangeRate
&lt;/h3&gt;

&lt;p&gt;Crypto currencies have their own set of cmdlets, which work largely the same as those above, but against the Coinbase API. The cmdlets for these are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Convert-CryptoCurrency&lt;/code&gt; - E.g &lt;code&gt;100 | Convert-CryptoCurrency -From GBP -To BTC&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Get-CryptoCurrency&lt;/code&gt; - E.g &lt;code&gt;Get-CryptoCurrency -Name Omni&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Get-CryptoExchangeRate&lt;/code&gt; - E.g &lt;code&gt;Get-CryptoExchangeRate -From GBP -To BTC&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These allow conversion between Fiat and crypto currencies.&lt;/p&gt;

&lt;p&gt;You can use &lt;code&gt;Format-Currency&lt;/code&gt; with a crypto currency as well:&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="mf"&gt;23.45&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;Convert-CryptoCurrency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BTC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ETH&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;Format-Currency&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ξ4,270.89
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set-CurrencyDefault, Get-CurrencyDefault
&lt;/h3&gt;

&lt;p&gt;Over the last week (with the aid of AI) I've added some extra functionality to the module. You can now save defaults via a new &lt;code&gt;Set-CurrencyDefault&lt;/code&gt; cmdlet. This is useful if you're always converting to or from the same currencies (more likely from than to perhaps) or if you want to use an ExchangeRate-API API key and not provide it every time you use the cmdlet. 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;Set-CurrencyDefault&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GBP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-APIKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;yourapikeyhere&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are saved as JSON under your &lt;code&gt;$Home&lt;/code&gt; directory in a folder called &lt;code&gt;.currencyconverter&lt;/code&gt;, so that they will persist if/when you upgrade the module in the future. You can see what defaults you have saved by running &lt;code&gt;Get-CurrencyDefault&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once a default is set, you don't need to specify it anymore, so for example, this will now assume I am converting British Pounds (GBP):&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="mi"&gt;100&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;Convert-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;133.728700
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add-CurrencyMember
&lt;/h3&gt;

&lt;p&gt;I also added a cmdlet called &lt;code&gt;Add-CurrencyMember&lt;/code&gt;. This is inspired by PowerShell's built in &lt;code&gt;Add-Member&lt;/code&gt; cmdlet, which you can use to append a new property to an existing PowerShell object. &lt;code&gt;Add-CurrencyMember&lt;/code&gt; allows you to append one or more additional properties to an object that are a currency conversion of an existing object. This is useful where you have a set of data in PowerShell that you want to convert a currency column of data for. For example, say you have a collection of products (this could have been loaded from a CSV for example, but we'll just create a simple PowerShell array of objects as an 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="nv"&gt;$Products&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="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;Product&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;'Widget'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Price&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="mi"&gt;100&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;Product&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;'Gizmo'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Price&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="mi"&gt;75&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;Product&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;'Sprocket'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Price&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="mi"&gt;125&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;But the &lt;code&gt;Price&lt;/code&gt; was USD, and you wanted it in EUR. You could 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="nv"&gt;$Products&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;Add-CurrencyMember&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Property&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EUR&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$Products&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product  Price PriceEUR
-------  ----- --------
Widget     100    89.21
Gizmo       75    66.91
Sprocket   125   111.52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can specify exactly what you want the new property name to be by providing &lt;code&gt;-MemberName&lt;/code&gt;, and have the results returned immediately to the pipeline via &lt;code&gt;-PassThru&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="nv"&gt;$Products&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;Add-CurrencyMember&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Property&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Price&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;EUR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-MemberName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PriceInEuro&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;br&gt;
plaintext&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product  Price PriceInEuro
-------  ----- -----------
Widget     100       89.21
Gizmo       75       66.91
Sprocket   125      111.52
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that while the default output is two decimal place, the PowerShell object does actually hold the exact decimal value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Product     : Widget
Price       : 100
PriceInEuro : 89.21300

Product     : Gizmo
Price       : 75
PriceInEuro : 66.90975

Product     : Sprocket
Price       : 125
PriceInEuro : 111.51625
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ConvertTo-CurrencyTable
&lt;/h3&gt;

&lt;p&gt;If you need to convert a value to multiple destination currencies, you can now do so via the &lt;code&gt;ConvertTo-CurrencyTable&lt;/code&gt; cmdlet. This outputs a PowerShell object with each currencies value as a named property. 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="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;200&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;ConvertTo-CurrencyTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GBP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;CAD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;EUR&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   GBP    USD    CAD    EUR
   ---    ---    ---    ---
100.00 133.73 187.40 119.30
150.00 200.59 281.09 178.95
200.00 267.46 374.79 238.60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Watch-ExchangeRate
&lt;/h3&gt;

&lt;p&gt;If you want to monitor an exchange rate for change, there's now a &lt;code&gt;Watch-ExchangeRate&lt;/code&gt; cmdlet. This will check a specified rate at a specified interval (60 seconds by default) and stop when it has moved up or down beyond a specified threshold. For example, this will monitor the British Pound to Bitcoin exchange rate, until it rises above 0.0000167346063796:&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;Watch-ExchangeRate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GBP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BTC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-IntervalSeconds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-AboveThreshold&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;0.0000167346063796&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;FT&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;From To  Rate               Timestamp           Triggered
---- --  ----               ---------           ---------
GBP  BTC 0.0000167346063795 26/10/2026 14:32:05     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:12     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:17     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:23     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:29     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:35     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:42     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:48     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:53     False
GBP  BTC 0.0000167346063795 26/10/2026 14:32:58     False
GBP  BTC 0.0000167346063795 26/10/2026 14:33:04     False
GBP  BTC 0.0000167548698867 26/10/2026 14:33:10      True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obviously this is limited by how frequently the exchange rate API provides refreshed rates, and polling the open APIs too frequently may result in your being rate limited.&lt;/p&gt;

&lt;h3&gt;
  
  
  Historical Exchange Rates
&lt;/h3&gt;

&lt;p&gt;Finally, &lt;code&gt;Get-ExchangeRate&lt;/code&gt;, &lt;code&gt;Convert-Currency&lt;/code&gt;, &lt;code&gt;ConvertTo-CurrencyTable&lt;/code&gt; and &lt;code&gt;Add-CurrencyMember&lt;/code&gt; now support a &lt;code&gt;-Date&lt;/code&gt; parameter, which allows you to query a historical rate for a specified currency. This is only supported for Fiat currencies, as historical data comes only from ExchangeRate-API, and also requires you to specify an API key, because historical data is not accessible via the open API. 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;Convert-Currency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;100&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-From&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;USD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-To&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;GBP&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="s1"&gt;'2024-01-15'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ApiKey&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;yourapikeystringhere&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This concludes this overview of the CurrencyConverter module. As previously mentioned, you can get it from the &lt;a href="https://www.powershellgallery.com/packages/currencyconverter" rel="noopener noreferrer"&gt;PowerShell Gallery&lt;/a&gt; or &lt;a href="https://github.com/markwragg/PowerShell-CurrencyConverter" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; where there is also a detailed &lt;a href="https://github.com/markwragg/PowerShell-CurrencyConverter/wiki" rel="noopener noreferrer"&gt;Wiki&lt;/a&gt;, which includes the PowerShell help output for each cmdlet giving further usage explanation and examples.&lt;/p&gt;

&lt;p&gt;If you encounter any bugs or have any suggestions, please do log an issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/markwragg/PowerShell-CurrencyConverter/issues" rel="noopener noreferrer"&gt;https://github.com/markwragg/PowerShell-CurrencyConverter/issues&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Contributions are welcomed.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>opensource</category>
      <category>automation</category>
      <category>tools</category>
    </item>
    <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://dev.to/markwragg/two-ways-to-use-pester-to-mock-objects-with-strongly-typed-parameters-31n7</link>
      <guid>https://dev.to/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://dev.to/markwragg/how-to-remove-null-or-empty-string-values-from-a-list-in-terraform-1e3b</link>
      <guid>https://dev.to/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://dev.to/markwragg/redirect-out-file-to-testdrive-in-your-powershell-pester-test-scripts-with-this-one-weird-trick-cjm</link>
      <guid>https://dev.to/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://dev.to/markwragg/hi-im-mark-wragg</link>
      <guid>https://dev.to/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>
