<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2026-05-16T17:06:26+00:00</updated><id>/feed.xml</id><title type="html">FoxDeploy.com</title><subtitle>Write an awesome description for your new site here. You can edit this line in _config.yml. It will appear in your document head meta (for Google search results) and in your feed.xml site description.</subtitle><entry><title type="html">New Mod Released - Fox Revolt Fun++ for Royal Revolt Survivors</title><link href="/blog/fox-revolt-fun-plus-plus-royal-revolt-survivors-mod.html" rel="alternate" type="text/html" title="New Mod Released - Fox Revolt Fun++ for Royal Revolt Survivors" /><published>2026-05-16T00:00:00+00:00</published><updated>2026-05-16T00:00:00+00:00</updated><id>/blog/fox-revolt-fun-plus-plus-royal-revolt-survivors-mod</id><content type="html" xml:base="/blog/fox-revolt-fun-plus-plus-royal-revolt-survivors-mod.html"><![CDATA[<p><img src="../assets/images/2026/fox-revolt-fun-plus-plus-hero.png" alt="" /></p>

<p>Hi folks!  Normally this is the part where I talk about PowerShell, Azure, troubleshooting some strange Microsoft account portal that insists reality is optional, or another little tool I made because I saw a workflow and thought “what if this had fewer sharp edges?”</p>

<p>Today is a little different.</p>

<p>I released a new mod!</p>

<p>And not just “I changed one JSON value and now the sword is blue” kind of mod, either.  This is the first mod I wrote from scratch on my own, for a game that, as far as I can tell, no one else had modded yet.</p>

<p>So please imagine me standing on a very small podium, holding a very small trophy, while Unity stack traces rain gently in the background.</p>

<h2 id="introducing-fox-revolt-fun">Introducing Fox Revolt Fun++</h2>

<p><strong>Fox Revolt Fun++</strong> is an unofficial, fun-first, BepInEx balance mod for <strong>Royal Revolt Survivors</strong>.</p>

<p>The goal is pretty simple: make runs feel faster, more generous, and less punishing, while still leaving the core game intact.  It gives you a little more attack speed, better healing, more meaningful level-up scaling, and some co-op kindness so your friend going down does not immediately become a group tax audit.</p>

<p>Download it here:</p>

<blockquote>
  <p><strong><a href="https://github.com/1RedOne/Fox-Revolt-Fun-Plus-Plus">Fox Revolt Fun++ on GitHub</a></strong></p>
</blockquote>

<p>Grab the newest release from the Releases page, unzip it into your BepInEx plugins folder, and then go forth and make the numbers more fun.</p>

<h2 id="what-it-changes">What It Changes</h2>

<p>The short version is this:</p>

<ul>
  <li>Faster combat</li>
  <li>Stronger healing</li>
  <li>Better passive health regeneration</li>
  <li>Friendlier co-op revives</li>
  <li>Better scaling from level-up picks</li>
  <li>A much more exciting version of Moe’s Cheers ability</li>
  <li>A config file, because hard-coded balance values are where fun goes to become a spreadsheet crime scene</li>
</ul>

<p>Or, if you prefer the technical version:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FoxRevoltFunPlusPlus.dll
</code></pre></div></div>

<p>I made a dll!</p>

<p>That little DLL patches several player stat and ability behaviors at runtime using BepInEx.  Which sounds very normal until you remember that the first few hours of Unity modding mostly feel like walking through someone else’s house in the dark while carrying a plate of spaghetti.</p>

<h2 id="faster-combat">Faster Combat</h2>

<p>The mod improves player attack pacing in two ways.</p>

<p>First, it adds a base attack speed bonus:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BasePlayerAttackSpeedBonus = 0.15
</code></pre></div></div>

<p>That means you get an extra 15 percent attack speed on top of whatever bonuses you buy in the store.</p>

<p>Second, level-up picks now contribute a small speed and area bonus over the run.  The first few picks matter more, then later picks keep helping without turning the screen into an overclocked leaf blower.</p>

<p>Default scaling:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>First three effective level-up picks: +3% speed and area each
Later effective level-up picks:      +0.5% speed and area each
</code></pre></div></div>

<p>The design goal here is “early level-ups feel great” and not “the entire combat model becomes pudding by minute twelve.”</p>

<h2 id="stronger-healing">Stronger Healing</h2>

<p>Healing gets a nice bump:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HealingMultiplier = 3.0
</code></pre></div></div>

<p>This makes recovery feel much less stingy, especially when a run starts going sideways and you are trying to keep the dream alive through the ancient tactical art of “please no, please no, please no.”</p>

<h2 id="better-health-regeneration">Better Health Regeneration</h2>

<p>The mod also injects an added health regeneration multiplier into player stats:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HealthRegenerationMultiplier = 2.0
</code></pre></div></div>

<p>With a fully buffed Recharge ring, you can go from 0 to full health in about 30 seconds now.</p>

<p>Just don’t get hit.</p>

<p>I realize that advice has the same energy as “have you tried winning?” but there it is.</p>

<h2 id="co-op-revives-are-less-mean-now">Co-Op Revives Are Less Mean Now</h2>

<p>Royal Revolt Survivors has a co-op rescue world event where reviving a teammate originally punished the rescuer with a health penalty.</p>

<p>Fox Revolt Fun++ patches that behavior so rescuing a friend no longer turns into “congratulations, you helped, now suffer.”</p>

<p>The revived player comes back with configurable health:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CoopReviveHealthPercent = 0.5
</code></pre></div></div>

<p>I have tested this locally.  Online play is still in the “probably? maybe? let me know if the machine spirits become upset” category.</p>

<h2 id="moe-cheers-buff">Moe Cheers Buff</h2>

<p>Moe’s special move, Cheers / DrinkBrew, got special attention because its original effects felt weak and included some health-related penalties that were not exactly screaming “good times.”</p>

<p>So I fixed it.</p>

<p>Let’s get drank.</p>

<p>The mod:</p>

<ul>
  <li>Adds <code class="language-plaintext highlighter-rouge">+1</code> max/current charge</li>
  <li>Halves recharge time</li>
  <li>Halves cooldown</li>
  <li>Triples positive Cheers stat effects</li>
  <li>Doubles Cheers buff duration</li>
  <li>Removes negative health-related Cheers penalties</li>
</ul>

<p>Now it feels more like a special move and less like a suspicious beverage from a side quest.</p>

<h2 id="installing-bepinex">Installing BepInEx</h2>

<p>Fox Revolt Fun++ is a BepInEx plugin, so you need BepInEx installed first.</p>

<p>Download BepInEx here:</p>

<blockquote>
  <p><strong><a href="https://github.com/BepInEx/BepInEx">BepInEx on GitHub</a></strong></p>
</blockquote>

<p>Unzip the BepInEx package into the game’s install folder, alongside files like:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Steam\steamapps\common\Royal Revolt Survivors\rrw.exe
Steam\steamapps\common\Royal Revolt Survivors\UnityPlayer.dll
</code></pre></div></div>

<p>The BepInEx files, including <code class="language-plaintext highlighter-rouge">winhttp.dll</code>, should be in that same folder.</p>

<p>Launch the game once, then quit.  After that, check for the BepInEx log file:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Steam\steamapps\common\Royal Revolt Survivors\BepInEx\LogOutput.log
</code></pre></div></div>

<p>If that file exists, you’re golden.</p>

<h2 id="installing-fox-revolt-fun">Installing Fox Revolt Fun++</h2>

<p>Download the newest release from the Fox Revolt Fun++ releases page, then extract the mod DLL into the BepInEx plugins folder:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Steam\steamapps\common\Royal Revolt Survivors\BepInEx\plugins\FoxRevoltFunPlusPlus.dll
</code></pre></div></div>

<p>Launch the game, start a run, and enjoy the gently enhanced chaos.</p>

<p>If you’re installing on Steam Deck: yes, I see you.  Steam Deck support is on my mind, and the setup should be similar to other BepInEx-on-Proton workflows, but I want to test it properly before I write the “click exactly these things” version and accidentally send someone into Linux folder-path jazz.</p>

<h2 id="configuration">Configuration</h2>

<p>The mod reads its tuning values from:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BepInEx/config/buffs.json
</code></pre></div></div>

<p>If the file does not exist, the mod creates it with default values.</p>

<p>Current default config:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"HealingMultiplier"</span><span class="p">:</span><span class="w"> </span><span class="mf">3.0</span><span class="p">,</span><span class="w">
  </span><span class="nl">"BasePlayerAttackSpeedBonus"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.15</span><span class="p">,</span><span class="w">
  </span><span class="nl">"EarlyLevelPickSpeedAreaBonus"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.03</span><span class="p">,</span><span class="w">
  </span><span class="nl">"LaterLevelPickSpeedAreaBonus"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.005</span><span class="p">,</span><span class="w">
  </span><span class="nl">"HealthRegenerationMultiplier"</span><span class="p">:</span><span class="w"> </span><span class="mf">2.0</span><span class="p">,</span><span class="w">
  </span><span class="nl">"CoopReviveHealthPercent"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.5</span><span class="p">,</span><span class="w">
  </span><span class="nl">"MoeWarriorIdContains"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Hero_Monk"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"MoeSecretMoveAbilityIdContains"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Cheers,DrinkBrew"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"MoeSecretMoveExtraCharges"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
  </span><span class="nl">"MoeSecretMoveRechargeTimeMultiplier"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.5</span><span class="p">,</span><span class="w">
  </span><span class="nl">"MoeSecretMoveCooldownMultiplier"</span><span class="p">:</span><span class="w"> </span><span class="mf">0.5</span><span class="p">,</span><span class="w">
  </span><span class="nl">"CheersAbilityIdContains"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Cheers,DrinkBrew"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"CheersBuffStatMultiplier"</span><span class="p">:</span><span class="w"> </span><span class="mf">3.0</span><span class="p">,</span><span class="w">
  </span><span class="nl">"CheersBuffDurationMultiplier"</span><span class="p">:</span><span class="w"> </span><span class="mf">2.0</span><span class="p">,</span><span class="w">
  </span><span class="nl">"CheersRemoveHealthPenalty"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
  </span><span class="nl">"CheersBuffNegativeStats"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
  </span><span class="nl">"VerboseLogging"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
  </span><span class="nl">"HeartbeatLogging"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>If you want a more relaxed run, turn the numbers up.  If you want a more vanilla-ish experience, turn them down.  If you set everything to 50 and the game becomes a physics presentation, I support you emotionally but possibly not technically.</p>

<h2 id="how-it-works">How It Works</h2>

<p>Royal Revolt Survivors is a Unity game, which means BepInEx can load a plugin DLL into the game process and let us patch behavior at runtime.</p>

<p>That sentence is doing a lot of work.</p>

<p>The practical version is:</p>

<ul>
  <li>Build a C# BepInEx plugin</li>
  <li>Load it into the game</li>
  <li>Find the right Unity / IL2CPP types</li>
  <li>Patch the right methods</li>
  <li>Add logging</li>
  <li>Launch the game</li>
  <li>Watch everything explode</li>
  <li>Add more logging</li>
  <li>Repeat until the fun number goes up and the crash number goes down</li>
</ul>

<p>I learned a lot making this.  Some of that learning was peaceful.  Some of it involved staring at method names and wondering if I was reading code or a prophecy.</p>

<h2 id="why-this-one-feels-special">Why This One Feels Special</h2>

<p>This is my first mod written from scratch, by me, for a game that did not appear to have an existing modding scene.</p>

<p>That made every little breakthrough feel enormous.</p>

<p>Getting BepInEx to load?  Huge.</p>

<p>Finding the right stat hooks?  Huge.</p>

<p>Seeing the plugin actually change gameplay?  Absolutely massive.</p>

<p>At some point the project crossed that magical line from “I am poking at a process and hoping” into “wait, I can actually shape the game now,” which is one of those feelings that keeps programmers voluntarily walking back into the puzzle room.</p>

<h2 id="build-and-deployment">Build And Deployment</h2>

<p>The project builds a BepInEx plugin DLL:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>FoxRevoltFunPlusPlus.dll
</code></pre></div></div>

<p>The deploy target copies the built DLL to:</p>

<div class="language-text highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BepInEx/plugins/FoxRevoltFunPlusPlus.dll
</code></pre></div></div>

<p>But if you’re just here to play the mod, you probably don’t care about that part.  Click Releases, download the newest bits, and go have a faster, friendlier run.</p>

<h2 id="tldr">TL;DR</h2>

<p>I made a mod for <strong>Royal Revolt Survivors</strong>.</p>

<p>It is called <strong>Fox Revolt Fun++</strong>.</p>

<p>It makes combat faster, healing stronger, co-op revives nicer, level-ups more exciting, and Moe’s Cheers ability significantly less rude.</p>

<p>Download it here:</p>

<blockquote>
  <p><strong><a href="https://github.com/1RedOne/FoxRevoltFunPlusPlus">https://github.com/1RedOne/FoxRevoltFunPlusPlus</a></strong></p>
</blockquote>

<p>And if you try it, please let me know how it feels.  Especially if you find a weird edge case, a broken interaction, or a build where Moe becomes too powerful and starts making eye contact with the renderer.</p>]]></content><author><name>Stephen Owen</name></author><category term="programming" /><category term="tools" /><category term="gaming" /><category term="Royal Revolt Survivors" /><category term="BepInEx" /><category term="Unity" /><category term="Mods" /><category term="CSharp" /><summary type="html"><![CDATA[I released Fox Revolt Fun++, an unofficial fun-first balance mod for Royal Revolt Survivors, and somehow it looks like I may be the first person to mod this game. Maybe I'm the only one playing it?.]]></summary></entry><entry><title type="html">New Tool - Quick Web Tools</title><link href="/blog/new-tool-released-quickwebtools.html" rel="alternate" type="text/html" title="New Tool - Quick Web Tools" /><published>2026-05-14T00:00:00+00:00</published><updated>2026-05-14T00:00:00+00:00</updated><id>/blog/new-tool-released-quickwebtools</id><content type="html" xml:base="/blog/new-tool-released-quickwebtools.html"><![CDATA[<p><img src="/assets/images/2026/quickwebtools-hero.png" alt="" /></p>

<h2 id="introducing-quick-web-tools">Introducing Quick Web Tools</h2>

<p>I just shipped a new tool: <strong><a href="https://www.foxdeploy.com/QuickWebTools">Quick Web Tools</a></strong>.</p>

<h3 id="what-it-does">What it does</h3>

<p>I always need to make minor text conversions to help with queries, parsing data, you name it.  So I decided to just make a tool to help me do this more easily!</p>

<p>Right now, it will convert a list of items into a ready to use Kusto <code class="language-plaintext highlighter-rouge">in ("abc","cde","xyz")</code> style query component.  Tomorrow…who knows!</p>

<h3 id="how-to-use-it">How to use it</h3>

<ul>
  <li>Open <strong><a href="https://www.foxdeploy.com/QuickWebTools">Quick Web Tools</a></strong></li>
</ul>

<h3 id="notes">Notes</h3>

<p>As always, no analytics, no saving, no copying.  All conversions happen locally and nothing leaves your box.</p>]]></content><author><name>Stephen Owen</name></author><category term="programming" /><category term="tools" /><category term="QuickWebTools" /><category term="Tooling" /><summary type="html"><![CDATA[A ever growing set of tools for common text manipulation needs]]></summary></entry><entry><title type="html">Fixing the ‘You’re at your device limit’ Error in Minecraft for Windows (with no devices showing)</title><link href="/blog/how-to-fix-overlimit-devices-error-in-xbox.html" rel="alternate" type="text/html" title="Fixing the ‘You’re at your device limit’ Error in Minecraft for Windows (with no devices showing)" /><published>2026-05-01T00:00:00+00:00</published><updated>2026-05-01T00:00:00+00:00</updated><id>/blog/how-to-fix-overlimit-devices-error-in-xbox</id><content type="html" xml:base="/blog/how-to-fix-overlimit-devices-error-in-xbox.html"><![CDATA[<p>Recently, I ran into a <em>weird</em> issue but at this point in my life I feel like I only encounter these.</p>

<p>I launched <strong>Minecraft for Windows</strong> on my PC (signed into my Game Pass account, active subscription, everything totally normal)… and got this:</p>

<p><img src="../assets/images/2026/xboxlogin-error.png" alt="where are my devices" /></p>

<blockquote>
  <p><em>“You’re at your limit for the number of devices you can use with Xbox Account.”</em></p>
</blockquote>

<p>Alright, fair enough. I’ve been around the block. I’ve owned a <em>lot</em> of PCs over the years.</p>

<p>So I clicked <strong>Manage Devices</strong>… and saw <strong>nothing</strong>.</p>

<p><img src="../assets/images/2026/xboxlogin-nodevices.png" alt="empty list of devices?  But I thought I had too many devices!" /></p>

<p>An empty list?  Secret Stones?  Imprisioning war?</p>

<p><img src="../assets/images/2026/headerimage.png" alt="Minecraft device limit error placeholder" /></p>

<hr />

<h2 id="whats-going-on">What’s Going On?</h2>

<p>At first, I suspected this was triggered by a recent hardware change. I had just upgraded my motherboard, which can make your machine look like a brand new device from Microsoft’s perspective.  And I was prompted to login to my Microsoft account which had me like “no time for this, I need to see how good my games look with the new hardware!”</p>

<p>But the <em>real</em> issue turned out to be something much more interesting…phantom device list?</p>

<p>Possible internal api-version differences between systems?  Leading question to inspire you to read more?  Secret Dungeon?  Magic Stones?</p>

<hr />

<h2 id="the-fix-workaround">The Fix (Workaround)</h2>

<p>Here’s the trick:</p>

<p><strong>Don’t trust the browser-based device management page.</strong></p>

<p>Instead, use the <strong>Microsoft Store app itself</strong>, which appears to use a newer backend.</p>

<h3 id="steps">Steps</h3>

<ol>
  <li>Open the <strong>Microsoft Store</strong> (not the Xbox app, not Game Pass)</li>
  <li>Try installing <strong>Minecraft</strong> (or any app)</li>
  <li>When the install fails:
    <ul>
      <li>Click the <strong>error message</strong></li>
      <li>Or click <strong>Manage Devices</strong></li>
    </ul>
  </li>
  <li>This opens an <strong>internal Store dialog</strong></li>
  <li>Suddenly… your real device list appears</li>
  <li>Remove old devices until you’re under the limit</li>
  <li>Retry the install</li>
</ol>

<p>Unfortunalely I forgot to take screenshots but it looked like this:</p>

<p><img src="../assets/images/2026/xboxlogin-installerror.png" alt="where are my devices" /></p>

<p>Then clicking the Error looked like this:</p>

<p><img src="../assets/images/2026/xboxstore-devicelist.png" alt="where are my devices" /></p>

<p><em>Again, I forgot to take a screenshot of the exact list view, and can’t find my way back to it, but this is what it looked like.  <strong>Importantly, this is _not_ the same list view you see clicking the user icon / profile icon in the upper right</strong></em></p>

<p><strong>Warning</strong>: this UX you’ll see when there is an install error if different than what you see if you’d click here</p>

<p><img src="../assets/images/2026/xbox-wronglist.png" alt="where are my devices" /></p>

<p>This won’t brick your system but this entry point to the manage devices experience might show an empty list for you.</p>

<h2 id="how-we-actually-discovered-this">How We Actually Discovered This</h2>

<p>This wasn’t something I stumbled into alone.</p>

<p>Huge shout out to <strong>Darryl from Xbox Support</strong> who was a boss for the following reasons:</p>

<ul>
  <li>Picked up on the <strong>first ring</strong></li>
  <li>On a <strong>Saturday afternoon</strong></li>
  <li>Stayed on the call for about an hour</li>
</ul>

<p>Our big take away was that we should be sure we were also logged into the Microsoft store since some Xbox games (all?) on PC seem to install from there and that’s where the real logging and error behavior can be observed</p>

<p>👉 <em>Log into the Microsoft Store using a different account and observe the behavior.</em></p>

<p>That let us watch the <strong>entire device-check flow happen in real time</strong>, and it became obvious that the Store UI was calling into a different (newer) backend than the public website.</p>

<p>Absolute legend.</p>

<h2 id="why-this-might-be-happening-from-a-dev-who-doesnt-work-on-this-team-pure-speculation">Why This Might be happening from a dev who doesn’t work on this team (pure speculation)</h2>

<p>If you’ve worked on large-scale services, this pattern is instantly recognizable.</p>

<p>You can’t just change production APIs. Too many customers depend on existing behavior.  Like, no matter how something works, someone builds a whole production workflow based on the count of whitespace characters in your response, or uses undocumented properties of items to store the entirety of the Bee Movie.  (Real issue I had to solve)</p>

<p>Anyway you don’t want to break users so you don’t changet the GA Prod Api, but instead add a new preview-api where you can begin to change things.  So my theory of whats happening here is that the device management process for Microsoft accounts</p>

<ul>
  <li>Maybe introduced a <strong>new API version</strong></li>
  <li>Gradually roll it out</li>
  <li>Update newer clients (like the Microsoft Store)</li>
  <li>Leave older endpoints in place for compatibility</li>
</ul>

<p>If I had to guess then</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">accounts.microsoft.com/devices</code> → older API</li>
  <li>Microsoft Store internal device management → newer API</li>
</ul>

<p>Only one of those reflects reality.  Or maybe my account (and a few others who left comments in the feedback hub) are too old or have something else going on and so the list the device view doesn’t reflect reality.</p>

<h2 id="tldr">TL;DR</h2>

<p>If you see:</p>

<blockquote>
  <p><em>“You’re at your device limit”</em></p>
</blockquote>

<p>…but your device list is empty</p>

<p>Try uninstalling Minecraft from Xbox or Microsoft Store, then reinstall Minecraft from the Microsoft Store and closely look for an ‘Error’ button to appear in the store UX.</p>

<p>If you use the pop-up that appears when you encoutner an install error from within the store it has a different manage devices experience which seems to actually list your devices.</p>]]></content><author><name>Stephen Owen</name></author><category term="programming" /><category term="Xbox" /><category term="Minecraft" /><category term="Microsoft Store" /><category term="Troubleshooting" /><summary type="html"><![CDATA[Hit the 'You're at your device limit' error in Minecraft for Windows—but your device list is empty? Here's the real cause and a simple workaround using the Microsoft Store.]]></summary></entry><entry><title type="html">FickleFox Balatro Mod!</title><link href="/blog/ficklefox-balatro-mod.html" rel="alternate" type="text/html" title="FickleFox Balatro Mod!" /><published>2025-12-12T00:00:00+00:00</published><updated>2025-12-12T00:00:00+00:00</updated><id>/blog/ficklefox-balatro-mod</id><content type="html" xml:base="/blog/ficklefox-balatro-mod.html"><![CDATA[<p><img src="../assets\images\2025\FickleFox.webp" alt="" /></p>

<p>Hi folks!  I know that you mostly know me from my consulting days, or my blog posts about PowerShell and making tools or building services.  But I also am a gamer, and more recently, a modder, and I wanted to share about my Balatro Mod, Fickle Fox, here!</p>

<h1 id="fickle-fox">Fickle Fox</h1>

<p>An animal themed, vanilla friendly, configurable Balatro mod!</p>

<p><a href="https://discord.com/channels/1116389027176787968/1343279563563597854"><img src="https://img.shields.io/badge/Discord-%235865F2.svg?style=for-the-badge&amp;logo=discord&amp;logoColor=white" alt="Discord" /></a> 
<a href="https://github.com/1RedOne/FickleFox"><img src="https://img.shields.io/github/followers/1RedOne.svg?style=social&amp;label=Download&amp;maxAge=2592000" alt="GitHub followers" /></a></p>

<blockquote>
  <p>Download the mod here! <a href="https://github.com/1RedOne/FickleFox">FickleFox</a></p>
</blockquote>

<p><em>Report issues or suggest ideas in the Discord!  Or file an issue on the repo!</em></p>

<h1 id="whats-the-purpose-of-this-mod">What’s the purpose of this mod</h1>
<p>The themes and goals here are cute art and fun new options for all phases of the game, <em>especially late game / naninf</em>.</p>

<p>I felt that it would be fun if there were more long term options available for late / end-game, and especially if these new jokers were fun or changed the way you play the game!</p>

<h1 id="whats-in-this-mod">What’s in this mod</h1>
<p>This mod contains a lot of fun stuff, including 40+ fun and original Joker ideas, all of which have lovingly handcrafted art and deep interactions with each other as well as the full set of original Jokers from the base game!</p>

<h3 id="40-new-jokers">40+ new jokers!</h3>
<h3 id="5-new-boosters">5+ new boosters</h3>
<h3 id="new-editions-vouchers-decks-and-more">New Editions, Vouchers, Decks and more!</h3>

<p><img src="../assets\images\2025\jokerSample.webp" alt="" />
<em>Just a sampling of the Joker’s you will discover!</em></p>
<details>
    <summary><b>Mod Spoilers</b></summary>    

    * Golden Repeater - a golden retriever!  Has a chance to repeat gold cards and sometimes make a copy of them!
    * Lucky Repeater - an irish setter,  Has a chance to repeat lucky cards and sometimes make a copy of them!
    * Pear Pair - a pair of birds.  gains in strength when you play multiple cards at a time, like pairs, two pairs or more
    * Fickle Fox - a fox with a stolen bag of money - fickley applies gold seals to your cards
    * Benevolance - a fox deity (love this design) - applies additional boons to your Gold Sealed cards when they are held in hand
    * A Kuma - a loveable bear with a strange connection to the number 10
    * ?????? - goes even further beyond
    * Hachiko - a dog on the subway - interacts with played 8's and 5's, like Walkie Talkie
    * Sun and Moon - a Hemmingway's Cat and Ninetailed Fox - interacts with played 9's and 6's, like Hachiko
    * Felicette - the first cat in space! Try it for yourself
    * Sonar Bat - helps you discover information about unplayed cards in your deck
    * Bandit Loach - a cute little loach fish - steals your money but sometimes upgrades your played hand
    * Holowing Owl - a holographic owl - is always enhanced and interacts nicely with enhanced cards
    * Death of Rats - every x hands, will 'kill' a played High Card.  Gains in power when allowed to trim the deck.  Resets if other than a high card is played
    * Tacocat - a cat taco - rewards played palindromes

</details>
<p><br /></p>

<h2 id="to-do">To do</h2>
<details>
    <summary><b>What's coming</b></summary>
    * Fix incompatibility with the newest Steammodded version

</details>
<p><br /></p>

<h2 id="changelog">Changelog</h2>
<details>
    <summary><b>v 0.5.0 - Half Moon Release</b></summary>    
    * Fixes boot loop issue * 
    * Add progression - unlock system!  Make a new profile to see these unlocks!
    * * Adds new decks with progressive unlock
    * * Adds loads of new fun joker unlocks as well
    * Cleans up card logic
    * Fixes 'Again' messages firing for wrong cards
    * Fixes numerous 'Repeat' or 'Retrigger' cards not working as expected
    * Buffs the Grass Card to make it more viable
    * Buffs Benevolence's Gold Seal interaction
    * Fixes wrong description for FickleFox Joker: Thanks to Discord user [Seals on Everything](https://discord.com/channels/1116389027176787968/1355819401198178455)
    * Adds more configuration
    * * Can now disable Mod specific boosters, the Negatvie booster, and many other things
    * * Adds 'more Mystery' mode which preserves the previous sort of insane behavior of Cam and the funny description of Mochi Cat
    * Fixes the logic for Caffinated and Mochi cat to work!
    * Adds beautiful new shaders to special edition decks!
    * Adds beautiful new version of secretRare shader
    * Adjusted Card Doubling rates for Lucky and Golden Retriever, from 1 ~ 8 to 1 ~ 10 
    * Adjusted card and booster spawn rates

</details>
<p><br /></p>

<h2 id="special-thanks">Special Thanks</h2>

<ul>
  <li>
    <p>Thanks to <strong>OhPahn</strong> for some programming tips especially around custom sounds, and for contributing an adorable doggo joker!  You can learn more about him here, <a href="https://linktr.ee/ohpahn">be sure to check out his music</a> and also his own Balatro mod <a href="https://github.com/ohpahn/opandoras-box">OhPahndora’s Box, with plenty of original tunes!</a></p>
  </li>
  <li>
    <p>Special thanks to <strong>MarioFan597</strong> for his very helpful artistic advice and guidance, and deep knowledge of the Balatro art style and for contributing two jokers and offering advice on countless others.  You can read more from them here, and be sure to check out their very cool Cryptid Friendly mod: <a href="https://github.com/MarioFan597/Ascensio">MarioFan’s Ascensio Mod - Github</a></p>
  </li>
  <li>
    <p>Special thanks to my real life best friend <strong>Akravator</strong> for contributing one of the Secret Jokers in this mod!</p>
  </li>
</ul>

<h2 id="extra-special-thanks">Extra Special Thanks</h2>

<p>And my deepest thanks to my wife, Linzra for brainstorming and creating 95% of all of the art in this mod!!! You can read more about her here</p>

<h1 id="installation-instructions-for-windows">Installation Instructions for Windows</h1>

<p><a href="https://steamcommunity.com/sharedfiles/filedetails/?id=3400691352">Setup Lovely and Steammodded following this guide on Steam</a></p>

<p>Download the newest release from <x></x></p>

<p>Navigate to this path (using the Run Command box or paste into explorer)</p>

<ul>
  <li>%AppData%/Balatro</li>
  <li>If you’re not familiar with app variables you can also navigate here</li>
  <li>
    <ul>
      <li>C:\Users&lt;YourUserName&gt;AppData\Roaming\Balatro</li>
    </ul>
  </li>
</ul>

<p>Create a new folder at this path if it does not exist yet:
 Mods</p>

<p>Unzip the release, it should look like this when done</p>

<p><img src="../assets\images\2025\sampleDir.png" alt="" /></p>

<h2 id="installation-instructions-for-steamdeck">Installation Instructions for Steamdeck</h2>

<p>The steps are surprisingly similar to the Windows release, thanks to the way the Steamdeck’s Proton layer enapsulates a Windows like folder and file structure.</p>

<p>You can follow this guide to get started, <a href="https://steamdeckhq.com/tips-and-guides/how-to-mod-balatro-on-steam-deck/">How to mod Balatro on Steam Deck</a></p>

<ul>
  <li>tested on Steammodded Version <a href="https://github.com/Steamodded/smods/releases/tag/1.0.0-beta-0509c">1.0.0-beta-0509c</a></li>
</ul>]]></content><author><name>Stephen Owen</name></author><category term="programming" /><category term="tools" /><category term="testing" /><category term="nUnit" /><category term="Testing" /><category term="XML" /><category term="SPA" /><category term="DevOps" /><summary type="html"><![CDATA[I forgot to post about my Balatro Mod here on my Blog!]]></summary></entry><entry><title type="html">Fox Tip! Performing Tests against the previous state of files</title><link href="/blog/ado-tip-performing-quality-checks-only-on-changed-files.html" rel="alternate" type="text/html" title="Fox Tip! Performing Tests against the previous state of files" /><published>2025-10-27T00:00:00+00:00</published><updated>2025-10-27T00:00:00+00:00</updated><id>/blog/ado-tip%20performing-quality-checks-only-on-changed-files</id><content type="html" xml:base="/blog/ado-tip-performing-quality-checks-only-on-changed-files.html"><![CDATA[<p>If you’ve noticed the trajectory of my posts, you’ll note that I’ve moved on to now automating things in the cloud, and shifted my focus a bit to the land of CI/CD.</p>

<p>Recently, this issue popped up :</p>

<h2 id="how-do-i-make-sure-people-change-their-contentin-the-right-way">How do I make sure people change their content…in the right way</h2>

<p><img src="assets\images\2025\changeQualityControl.png" alt="Header for this post, reads 'How To Make GitHub Button'" /></p>

<p><em>Post Outline</em></p>

<p>I’m working on a project now in which UX is created on the fly directly from some JSON content that partner teams provide to us.  It’s very cool and fun work.</p>

<p>However…after some time has gone by I began to realize somethings…</p>

<ol>
  <li>We create UX on the fly from partner inputs</li>
  <li>It requires a PR to update this content</li>
  <li>I am not the only one allowed to approve PRs</li>
</ol>

<p>What then would happen if someone alters a json content file after its been in use in testing for months and the new file breaks things?  I’ll tell you what doesn’t happen, people don’t go to the author of the file and ask them why they made a change, no, they instead line up to ask me questions.  Me, the bozo who developed this platform and didn’t think to check for things like that!</p>

<h2 id="the-problem">The problem</h2>

<p>It’s very simple to run a test against <em>all</em> of the code in a repo at check in.  We do this in the Azure world by creating a new pipeline that runs on a hosted pool and we set the input source to be the repo in question with the trigger type being <code class="language-plaintext highlighter-rouge">pr</code>, then at the end of the day, run a PowerShell script to perform your tests (I prefer to do this in Pester).</p>

<p>But I don’t need to just test their <em>current version</em> of the file.  I need instead to compare the file to its previous state in <code class="language-plaintext highlighter-rouge">master</code>, otherwise I won’t be aware of just how much its changed.</p>

<p>I mean, I could know if I looked at the PR, but there are times when it’s not possible to review every PR.</p>

<h2 id="the-setup">The Setup</h2>

<p>We want to:</p>

<ul>
  <li>Get a list of potential files to check <code class="language-plaintext highlighter-rouge">($allJsonFiles)</code></li>
  <li>Retrieve a list of files changed in this PR <code class="language-plaintext highlighter-rouge">($allChangedFiles)</code></li>
  <li>See if any of <code class="language-plaintext highlighter-rouge">$allJsonFiles</code> are in <code class="language-plaintext highlighter-rouge">$allChangedFiles</code>, and if so capture them as <code class="language-plaintext highlighter-rouge">$myChangedJsonFiles</code></li>
  <li>Handle either 0 changed files or many files</li>
  <li>Do some quality checks</li>
  <li>Handling when I need a human set of eyes</li>
  <li>Call it a day and go get lunch.</li>
</ul>

<p>It was very easy to get the list of files I cared about, the interesting thing was seeing what changed in this PR:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w"> </span><span class="nv">$changedFiles</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">git</span><span class="w"> </span><span class="nx">diff</span><span class="w"> </span><span class="nt">--name-only</span><span class="w"> </span><span class="nx">master</span><span class="w">    
</span></code></pre></div></div>

<p>This will give you a list, in linux file format, of all files that changed in your commits/pr versus master.</p>

<p>This actually failed aggresively, as it turns out that ADO pipelines will by default only include the dev branch and won’t mirror master as well.  I added this to fix that particular issue.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> git fetch origin master
$changedFiles = git diff --name-only master    
</code></pre></div></div>

<p>From here, it was simple enough to compare <code class="language-plaintext highlighter-rouge">$allJsonFiles</code> against the list back from <code class="language-plaintext highlighter-rouge">$allChangedFiles</code> and filter things down.  I then ended the <code class="language-plaintext highlighter-rouge">BeforeDiscovery</code> block of my test by publishing <code class="language-plaintext highlighter-rouge">$myChangedJsonFiles</code>.</p>

<p>Next up, it’s very easy to hand a list of resources off to a <code class="language-plaintext highlighter-rouge">Describe</code> block and iterate over them, using this syntax:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Describe</span><span class="w"> </span><span class="s2">"Catalog JSON File - &lt;_.FullName&gt;"</span><span class="w"> </span><span class="nt">-ForEach</span><span class="w"> </span><span class="nv">$jsonFiles</span><span class="w"> </span><span class="p">{</span><span class="w">
    </span><span class="n">BeforeAll</span><span class="w"> </span><span class="p">{</span><span class="w">
      </span><span class="c">#load the json file, convert from json, etc</span><span class="w">
</span></code></pre></div></div>
<h2 id="how-to-get-a-human-to-pay-attention">How to get a human to pay attention</h2>

<p>I decided that certain values in a partner file need to be immutable after their first check in.  We could handle changes to them on a case by case basis, but enshrining this with checks would keep everyone safe.</p>

<p>I found that if I skip a test in ADO, this triggers a warning exit status, which helps to draw human eyes to reviewing the problem.  Here’s how I did it.</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w">    </span><span class="kr">if</span><span class="w"> </span><span class="p">(</span><span class="nv">$difference</span><span class="w"> </span><span class="o">-ge</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> 
            </span><span class="p">{</span><span class="w">
                </span><span class="n">Write-Warning</span><span class="w"> </span><span class="s2">"WARNING - Detected </span><span class="nv">$difference</span><span class="s2"> in status between this file and master.  Does this make sense?"</span><span class="w">
                </span><span class="n">Set-ItResult</span><span class="w"> </span><span class="nt">-Skipped</span><span class="w"> </span><span class="nt">-Because</span><span class="w"> </span><span class="s2">"Human Review Required - Significant change in 'ShouldNeverBeChanged' settings detected, with a count of </span><span class="nv">$difference</span><span class="s2">."</span><span class="w">
                </span><span class="kr">return</span><span class="w">
            </span><span class="p">}</span><span class="w">

</span></code></pre></div></div>

<p>It was that easy!</p>

<p>Time for lunch.</p>]]></content><author><name>Stephen Owen</name></author><category term="scripting" /><category term="Azure DevOps" /><category term="Pipelines" /><category term="CI/CD" /><category term="Quality Checks" /><summary type="html"><![CDATA[In this post, we'll look at a way to track how files are changing from within an Azure DevOps pipelines]]></summary></entry><entry><title type="html">New Tool – nUnit Test Results Viewer</title><link href="/blog/new-tool-released-nUnit-viewer.html" rel="alternate" type="text/html" title="New Tool – nUnit Test Results Viewer" /><published>2025-10-27T00:00:00+00:00</published><updated>2025-10-27T00:00:00+00:00</updated><id>/blog/new-tool-released-nUnit-viewer</id><content type="html" xml:base="/blog/new-tool-released-nUnit-viewer.html"><![CDATA[<p><img src="../assets/images/2025/testViewer.png" alt="" />
Ever find yourself staring at a massive nUnit XML test results file, trying to figure out which tests passed, failed, or were skipped? Isn’t it SPOOOKY when you have to scroll for forever, or try to read test results in Pester?</p>

<p>Ever wish you could see your test results in the same clean, organized view you get when running tests in an Azure DevOps pipeline?</p>

<p>If you’re like me, you’ve probably opened those XML files in a text editor more times than you’d care to admit, scrolling through endless <code class="language-plaintext highlighter-rouge">&lt;test-case&gt;</code> elements, trying to make sense of the results. There has to be a better way 🎃!</p>

<p>Well, now there is.</p>

<h2 id="-introducing-nunit-test-results-viewer-">👻 Introducing: <strong>nUnit Test Results Viewer</strong> 👻</h2>

<p>This single-page application takes your nUnit XML test results and renders them in a beautiful, pipeline-style view that makes it easy to understand your test outcomes at a glance.</p>

<p><img src="../assets/images/2025/nunitViewer.png" alt="nUnit Test Results in a clean, organized view" /></p>

<p>No more squinting at raw XML trying to count passed vs failed tests, or hunting through massive files to find that one test that’s been causing issues.</p>

<p>Think of it as “Azure DevOps Test Results tab,” except it works with any nUnit XML file and runs entirely in your browser.</p>

<h3 id="features">Features</h3>
<ul>
  <li><strong>Pipeline-style test visualization</strong> - See your test results organized just like in Azure DevOps</li>
  <li><strong>Test summary dashboard</strong> - Get an instant overview of passed, failed, and skipped tests</li>
  <li><strong>Expandable test details</strong> - Click into individual tests to see failure messages and stack traces</li>
  <li><strong>Search and filter</strong> - Quickly find specific tests or filter by status</li>
  <li><strong>Runs entirely in your browser</strong> - No installs, no servers, no hassle</li>
  <li><strong>Complete privacy</strong> - Your test results never leave your browser</li>
  <li><strong>Janky CSS</strong> - Look, you get what you pay for.</li>
</ul>

<h3 id="how-to-use-it">How to Use It</h3>
<p>Simply upload your nUnit XML results file or paste the XML content directly into the viewer. The app will parse your test results and display them in an organized, easy-to-read format that mimics the test results view you’re familiar with from Azure DevOps pipelines.</p>

<h3 id="its-completely-private">It’s Completely Private!</h3>
<p>There’s no telemetry, monitoring, or data collection of any kind. Your test results stay completely within your browser tab - nothing is ever sent to a server or stored anywhere.  Don’t believe me?  GOOD!</p>

<p>I mean if you don’t believe me, just check your network traces tab in devtools.</p>

<p>If you’ve ever spent way too long trying to parse XML test results by hand, this tool will save your sanity (and probably some time too).</p>

<p>Give it a try here: <strong><a href="https://www.foxdeploy.com/NUnitTestViewer/">nUnit Test Results Viewer</a></strong><br />
And if you find any bugs, well… at least now you’ll have a nice way to view the test results when you fix them! 😉</p>]]></content><author><name>Stephen Owen</name></author><category term="programming" /><category term="tools" /><category term="testing" /><category term="nUnit" /><category term="Testing" /><category term="XML" /><category term="SPA" /><category term="DevOps" /><summary type="html"><![CDATA[Tired of trying to parse nUnit XML test results by hand? This new single-page application renders your test results in a clean, pipeline-style view that makes it easy to understand your test outcomes at a glance.]]></summary></entry><entry><title type="html">Back to Ignite – See You in San Francisco!</title><link href="/blog/back-to-ignite.html" rel="alternate" type="text/html" title="Back to Ignite – See You in San Francisco!" /><published>2025-10-07T00:00:00+00:00</published><updated>2025-10-07T00:00:00+00:00</updated><id>/blog/back-to-ignite</id><content type="html" xml:base="/blog/back-to-ignite.html"><![CDATA[<p><img src="../assets/images/2025/backToIgnite.png" alt="" /></p>

<p>It’s been <strong>seven years</strong> since I last attended Ignite, and I couldn’t be more excited to finally be heading back!  I miss the energy, the pizza, the inevitable colds you get from conferences.  I especially miss the subzero artic air conditioning which is always on at conventions!</p>

<p>This year, I’ll be helping run the <strong>Configuring a Modern Workplace lab</strong> and spending time at the <strong>Microsoft Booth in the Azure / Configuration areas</strong>. If you’re walking the floor and want to chat about Policy, Configuration, or distributed systems, swing by—I’d love to connect.</p>

<h3 id="why-this-year-matters">Why this year matters</h3>
<p>Ignite has always been about the crowd, the connections, and the energy. After so long away, I can’t wait to see the community again, share stories, and hear how everyone is using these tools in the field.</p>

<p>I’ll also be dropping into the <strong>PowerShell meetups</strong> during the week. PowerShell is still one of my favorite ways to build, automate, and experiment—and I know that crew always brings the best energy.</p>

<h3 id="where-to-find-me">Where to find me</h3>
<ul>
  <li><strong>Configuring a Modern Workplace Lab</strong> – I’ll be co-hosting and helping folks get hands-on.</li>
  <li><strong>Microsoft Booth (Azure / Configuration)</strong> – Stop by, say hi, and let’s talk shop.</li>
  <li><strong>PowerShell Community Meetups</strong> – You know where the cool kids hang out.</li>
</ul>

<hr />

<p>If you’ve ever read one of my blog posts and thought <em>“hey, I should say hi if I ever see him at an event”</em>—this is the time!<br />
I’m looking forward to seeing old friends, meeting new ones, and getting back into the Ignite groove.</p>

<p>See you in San Francisco! ✨</p>

<div class="carousel__holder">
    <div id="carousel0" class="carousel">
        
        
        <div class="carousel__track">
          <ul>
            
          </ul>
        </div>
        <div class="carousel__indicators">
            
        </div>
    </div>
</div>

<style>
.carousel__holder {width: 100%; position: relative; padding-bottom: 50%; margin: 1rem 0 1rem;}
.carousel {
  height: 100%;
  width: 100%;
  overflow: hidden;
  text-align: center;
  position: absolute;
  padding: 0;
}
.carousel__controls,
.carousel__activator {
  display: none;
}


.carousel__control {
  height: 30px;
  width: 30px;
  margin-top: -15px;
  top: 50%;
  position: absolute;
  display: block;
  cursor: pointer;
  border-width: 5px 5px 0 0;
  border-style: solid;
  border-color: #fafafa;
  opacity: 0.35;
  opacity: 1;
  outline: 0;
  z-index: 3;
}
.carousel__control:hover {
  opacity: 1;
}
.carousel__control--backward {
  left: 20px;
  -webkit-transform: rotate(-135deg);
          transform: rotate(-135deg);
}
.carousel__control--forward {
  right: 20px;
  -webkit-transform: rotate(45deg);
          transform: rotate(45deg);
}
.carousel__indicators {
  position: absolute;
  bottom: 20px;
  width: 100%;
  text-align: center;
}
.carousel__indicator {
  height: 15px;
  width: 15px;
  border-radius: 100%;
  display: inline-block;
  z-index: 2;
  cursor: pointer;
  opacity: 0.35;
  margin: 0 2.5px 0 2.5px;
}
.carousel__indicator:hover {
  opacity: 0.75;
}
.carousel__track {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  padding: 0;
  margin: 0;
  transition: -webkit-transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s;
  transition: transform 0.5s ease 0s, -webkit-transform 0.5s ease 0s;
}
.carousel__track .carousel__slide {
  display: block;
  top: 0;
  left: 0;
  right: 0;
  opacity: 1;
}


.carousel--scale .carousel__slide {
  -webkit-transform: scale(0);
          transform: scale(0);
}
.carousel__slide {
  height: 100%;
  position: absolute;
  opacity: 0;
  overflow: hidden;
}
.carousel__slide .overlay {height: 100%;}
.carousel--thumb .carousel__indicator {
  height: 30px;
  width: 30px;
}
.carousel__indicator {
  background-color: #fafafa;
}

</style>

<script>
  function isVisible(el) {
        while (el) {
            if (el === document) {
                return true;
            }

            var $style = window.getComputedStyle(el, null);

            if (!el) {
                return false;
            } else if (!$style) {
                return false;
            } else if ($style.display === 'none') {
                return false;
            } else if ($style.visibility === 'hidden') {
                return false;
            } else if (+$style.opacity === 0) {
                return false;
            } else if (($style.display === 'block' || $style.display === 'inline-block') &&
                $style.height === '0px' && $style.overflow === 'hidden') {
                return false;
            } else {
                return $style.position === 'fixed' || isVisible(el.parentNode);
            }
        }
  }
  
  setInterval(function(){
    var j=0;
    var elements = document.querySelectorAll('#carousel0 .carousel__control--forward');
    for(i=(elements.length - 1);i>-1;i--) {
      if(isVisible(elements[i])) j=i;
    }
    elements[j].click();
  },7000);
  
</script>]]></content><author><name>Stephen Owen</name></author><category term="events" /><category term="community" /><category term="Ignite" /><category term="Microsoft" /><category term="Azure" /><category term="PowerShell" /><summary type="html"><![CDATA[After seven years, I’m returning to Ignite! I’ll be helping run the Configuring a Modern Workplace lab, spending time at the Microsoft Booth in the Azure / Configuration areas, and joining the PowerShell community meetups. Come say hi!]]></summary></entry><entry><title type="html">New Tool – Azure Policy OS Allowlist Viewer</title><link href="/blog/azure-policy-os-viewer.html" rel="alternate" type="text/html" title="New Tool – Azure Policy OS Allowlist Viewer" /><published>2025-10-03T00:00:00+00:00</published><updated>2025-10-03T00:00:00+00:00</updated><id>/blog/azure-policy-os-viewer</id><content type="html" xml:base="/blog/azure-policy-os-viewer.html"><![CDATA[<p><img src="../assets/images/NewToolForYouCover.png" alt="" /></p>

<p>Ever cracked open an Azure Policy JSON file and felt like you needed a PhD in <em>indentation archaeology</em> just to figure out what OSes are allowed?<br />
Ever find yourself squinting at a sea of <code class="language-plaintext highlighter-rouge">anyOf</code> and <code class="language-plaintext highlighter-rouge">allOf</code> blocks like they’re some arcane magical incantation?<br />
Ever thought: <em>“surely there must be a better way than ctrl+F’ing for <code class="language-plaintext highlighter-rouge">Ubuntu</code> for the fifteenth time”</em>?</p>

<p>Yeah, me too. So I built something.</p>

<h3 id="introducing-azure-policy-os-allowlist-viewer-">Introducing: <strong><a href="https://www.foxdeploy.com/PolicyOSView/">Azure Policy OS Allowlist Viewer</a></strong> 🎉</h3>

<p>This little single-page app lets you <strong>paste in a Policy JSON blob</strong> and instantly see:</p>

<ul>
  <li>A <strong>Publisher Allowlist</strong>: the raw, explicit <code class="language-plaintext highlighter-rouge">imagePublisher</code> values your policy permits</li>
  <li>An <strong>OS Version Summary</strong>: a concise cheat sheet of “Versions like 8* / 9<em>” or “Versions NOT like 6</em> / 7*”</li>
</ul>

<p>Think of it as “Clippy for Azure Policy,” except instead of asking if you’re writing a letter, it tells you if you’re about to allow RHEL 6 (spoiler: you’re not).</p>

<p><img src="../assets/images/2025/policyparser.png" alt="Example of parsed policy rules" /></p>

<h3 id="features">Features</h3>
<ul>
  <li>Expand and collapse nested policy clauses like a file tree</li>
  <li>Auto-builds a human-readable summary table for quick reference</li>
  <li>Zero dependencies: runs entirely in your browser</li>
  <li>Total privacy: nothing leaves your tab</li>
</ul>

<h3 id="its-private">It’s private!</h3>
<p>No telemetry, no API calls, no uploads. Everything happens in-memory.<br />
Paste your JSON, hit Parse, and get instant clarity. When you close the tab, it’s gone.</p>

<hr />

<p>If you’ve ever tried explaining to your boss which OSes your policy <em>actually</em> allows and felt like you were doing improv stand-up with JSON, this will save you.</p>

<p>Check it out here: <strong><a href="https://www.foxdeploy.com/PolicyOSView/">https://www.foxdeploy.com/PolicyOSView/</a></strong><br />
And if your summary table shows “Versions NOT like 6* / 7*,” just tell your auditors you know what you don’t like!</p>]]></content><author><name>Stephen Owen</name></author><category term="programming" /><category term="tools" /><category term="AzurePolicy" /><category term="DevOps" /><category term="JSON" /><summary type="html"><![CDATA[Ever get lost in a spaghetti of Azure Policy JSON while trying to remember which OS versions are actually allowed? This new browser-based viewer summarizes your publishers, SKUs, and versions in a clean, searchable view.]]></summary></entry><entry><title type="html">New Tool – Azure DevOps Pipeline Viewer / Editor</title><link href="/blog/new-tool-released-pipeline-viewer.html" rel="alternate" type="text/html" title="New Tool – Azure DevOps Pipeline Viewer / Editor" /><published>2025-08-12T00:00:00+00:00</published><updated>2025-08-12T00:00:00+00:00</updated><id>/blog/new-tool-released-pipeline-viewer</id><content type="html" xml:base="/blog/new-tool-released-pipeline-viewer.html"><![CDATA[<p><img src="../assets/images/2025/pipelineViewHeader.png" alt="" />
Ever find yourself staring at a 2,000-line Azure DevOps pipeline JSON file, wondering if the YAML crowd is secretly laughing at you?  Ever miss the classic pipeline viewer?  Ever wonder why we have to check in pipelines before we can preview them, graphically?</p>

<p>Do you kind of just want to go back to using Orchestrator again, or hell, just go back to 2007 again?  Maybe get back out your old emo clothes?  Do you miss $2 Pabst Blue Ribbons at dive bars, fighting games and Halo and chatting with your friends till 2 AM a few nights a week?  Staying up, just to watch the sunrise?</p>

<p>Yeah… me too. Anyway now I am despressed so I guess I will have to build something new!</p>

<h3 id="well-that-was-depressing-lets-pivot">Well that was depressing, let’s pivot</h3>

<h2 id="introducing-azure-devops-pipeline-viewer--editor-">Introducing: <strong><a href="https://www.foxdeploy.com/AdoPipelineView/">Azure DevOps Pipeline Viewer / Editor</a></strong> 🎉</h2>

<p>This little web app lets you <strong>open, browse, and edit</strong> your ADO pipeline JSON files in a clean, easy to read view.</p>

<p><img src="../assets/images/2025/pipelineView.png" alt="Somehow enumerating files but we can't find them" /></p>

<p>No more having to check your pipeline in or put up with pesky peer reviews, just to see if you got your stages in the right order.</p>

<p>Think of it as “Windows Explorer for your pipeline,” except it won’t randomly decide to apply dark mode at 2 AM.</p>

<h3 id="features">Features</h3>
<ul>
  <li>Expand and collapse pipeline sections like a file tree</li>
  <li>Inline JSON editing without losing your place</li>
  <li>Quick search to jump to the setting you need</li>
  <li>Runs entirely in your browser — no installs required</li>
  <li>Total privacy</li>
</ul>

<h3 id="its-private">It’s private!</h3>
<p>There’s no telemetry, monitoring, exporting, downloading or anything else.  So long as you upload or paste in your pipeline, it will all stay 100% within your browser tab.</p>

<p>If you’ve ever spent ten minutes scrolling to find <em>that one</em> step buried in a nested job definition, this will save your sanity (or at least reduce your coffee bill).</p>

<p>Give it a try here: <strong><a href="https://www.foxdeploy.com/AdoPipelineView/">https://www.foxdeploy.com/AdoPipelineView/</a></strong><br />
And if you break your pipeline JSON, don’t worry — that’s called <em>job security</em>. 😉</p>]]></content><author><name>Stephen Owen</name></author><category term="programming" /><category term="tools" /><category term="AzurePipelines" /><category term="DevOps" /><category term="JSON" /><summary type="html"><![CDATA[Ever find yourself scrolling through a mile-long Azure DevOps pipeline JSON file? This new browser-based viewer/editor makes it a breeze to navigate, search, and edit your pipelines without losing your sanity.]]></summary></entry><entry><title type="html">The Case of the Cursed Release</title><link href="/blog/the-case-of-the-cursed-release.html" rel="alternate" type="text/html" title="The Case of the Cursed Release" /><published>2025-08-07T00:00:00+00:00</published><updated>2025-08-07T00:00:00+00:00</updated><id>/blog/the-case-of-the-cursed-release</id><content type="html" xml:base="/blog/the-case-of-the-cursed-release.html"><![CDATA[<p>Recently, I ran into one of those DevOps nightmares that only shows up when all the stars are aligned just wrong. The kind where you stare at the screen and say, “This should work,” and then it <strong>doesn’t</strong>. And worse <strong>PowerShell lies to you</strong>.  I thought PowerShell and I had something special…how could it treat me of all people like that.</p>

<p>This is the story of how an innocent ZIP file became haunted, how PowerShell 5 doomed a build, and how I barely escaped with my sanity (and deployment pipeline) intact.</p>

<p><img src="../assets/images/2025/cursedrelease.png" alt="A cursed release is born" /></p>

<hr />

<h2 id="observed-behavior-things-looked-fine">Observed behavior: things looked… fine?</h2>

<p>We use YAML Pipelines in ADO which not surprisingly I find that I really enjoy.  This is like the evolution of using System Center (or Opalis) Orchestrator to achieve complex automation.</p>

<p>And if you are surprised that I enjoy this, then you must be new here!</p>

<p><strong>Well</strong>, Recently I needed to add a new folder into a zip we produce in our build process.  I told management that this would be trivially easy, barely an inconvenience, only three days at max.</p>

<p>Previous to this point, all of our artifacts in our build would be single binary files, like .exe and .dll files and things.  We’d take all the built bits, put them into our OUT dir and make a zip file out of the whole mess.  Then our Release would grab the output and push it out to our regions and bam, it all just worked.</p>

<p>But we never added a folder to our build before.</p>

<p>How hard could it be?</p>

<h2 id="step-1-this-should-be-easy-barely-an-inconvenience">Step 1: This should be easy, barely an inconvenience</h2>

<p>I added a simple step to my <code class="language-plaintext highlighter-rouge">PowerShell@2</code> task, copying recursively an entire directory and preserving its output structure</p>

<p>Then I ran my release script, which was super simple, just launching a task on one of my Linux agents to run the task of grabbing my content and pushing it out to the expected location on this storage account.</p>

<p>So I ran my release process and saw that it looks like we see the files, but uploading them to a storage account failed with <code class="language-plaintext highlighter-rouge">Cannot find the specified file</code></p>

<h2 id="what-do-you-mean-you-cant-find-the-files--but-its-right-there">What do you mean you can’t find the files?  But it’s right there!!</h2>

<p><img src="../assets/images/2025/theCaseSafe1.png" alt="Somehow enumerating files but we can't find them" /></p>

<p>I made sure that my output appeared under ‘Artifacts\Published’.</p>

<p><img src="../assets/images/2025/myCoolReleasezip.png" alt="Somehow enumerating files but we can't find them" /></p>

<p>Ok, let me open the zip file too just to be safe.<br />
<img src="../assets/images/2025/sanityCheck.png" alt="Somehow enumerating files but we can't find them" /></p>

<h2 id="step-2-add-logs-like-a-panicked-developer">Step 2: Add logs like a panicked developer</h2>

<p>I cracked open the logs and saw the files were <em>definitely</em> there. PowerShell said so!<br />
And yet… <code class="language-plaintext highlighter-rouge">Set-AzStorage</code> would just give me a shrug emoji and die.</p>

<p>At this point I began adding all sorts of logging, <code class="language-plaintext highlighter-rouge">Get-ChildItem</code>, <code class="language-plaintext highlighter-rouge">ls</code>, <code class="language-plaintext highlighter-rouge">dir</code> and even <code class="language-plaintext highlighter-rouge">[System.IO.FileSearcher]</code> dumps, even ASCII art.</p>

<p>The files seemed to be visible, <strong>but</strong> any operation trying to <em>touch</em> them would explode:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Get-Item</code>? Nope.</li>
  <li><code class="language-plaintext highlighter-rouge">Upload-Item</code>? Also broken.</li>
  <li>Even using <code class="language-plaintext highlighter-rouge">-Include</code> or <code class="language-plaintext highlighter-rouge">-Filter</code>? Instant failure.</li>
</ul>

<p>Check this out for proof!  Even a <code class="language-plaintext highlighter-rouge">Get-ChildItem</code>, the holiest and most chosen of cmdlets would explode.</p>

<h3 id="look-at-this-i-cannot-even-gci-in-here"><em>Look at this, I cannot even GCI in here</em></h3>

<p><img src="../assets/images/2025/cantevenGCI.png" alt="Somehow enumerating files but we can't find them" /></p>

<p>Have you ever seen that?  <code class="language-plaintext highlighter-rouge">Get-ChildItem</code> throwing!?</p>

<h2 id="step-3-this-has-got-to-be-related-to-the-host-environment">Step 3: this has <em>got</em> to be related to the host environment</h2>

<p>At this point I began questioning a lot of things.  My Career choices, political affiliation, even my preference for coffee over tea and bourbon over tequila.</p>

<p>What could this possibly be?</p>

<p>I decided to remote out to one of our Release env boxes, which is in ADO so its really just a container running some remote os to run a PowerShell script and do stuff.</p>

<p>I noticed these are <code class="language-plaintext highlighter-rouge">Linux</code> containers…so I used SSH.  I found here that doing directory commands on the new files were really odd… like I couldn’t <code class="language-plaintext highlighter-rouge">CD</code> into the <code class="language-plaintext highlighter-rouge">myNewFolder</code> folder at all.</p>

<p>But I <em>could</em> <code class="language-plaintext highlighter-rouge">cat</code> or <code class="language-plaintext highlighter-rouge">grep</code> on them using bash commands. However using PowerShell commands would fail.  Now why would that be?</p>

<h3 id="fine-i-guess-i-will-try-reading">Fine, I guess I will try reading</h3>

<p><code class="language-plaintext highlighter-rouge">&gt;ls</code></p>

<p><img src="../assets/images/2025/fineIGuessIllRead.png" alt="" /></p>

<p>Wait a minute…</p>
<h2 id="the-slashes-were-wrong">The Slashes Were Wrong</h2>

<p>The paths weren’t just inconsistent. They were… <strong>interleaved</strong>.</p>

<p>How the hell do you even end up with Slashes in this direction on a Linux machine?!</p>

<p>At this point I was just impressed with the degree of my mess up. I deleted the directory, pushed the zip file back over again and opened it in front of my own eyes.</p>

<p><img src="../assets/images/2025/bustedZip.png" alt="" /></p>

<blockquote>
  <p>zip appears to use backslashes as path separators</p>
</blockquote>

<h2 id="how-did-i-manage-to-get-a-zip-file-wrong">How did I manage to get a Zip file wrong?</h2>

<p>Honestly I was kind of proud of myself.  This was a whole new genre of spectacular disaster.  I was charting new territory here.</p>

<p>I had succeeded in making files exist on a linux box was the full <em>Amuse-bouche</em> of possible characters in their names:</p>
<ul>
  <li>some with backslashes</li>
  <li>some with forward slashes.</li>
  <li>some with <strong>both</strong>.</li>
</ul>

<p>I wouldn’t have been surprised to find that some had a cream filling!</p>

<p>Here’s the crux of the issue then, for some files, the slash wasn’t a <em>path separator</em> - it was part of the <strong>literal file name</strong>.</p>

<p>In Linux, a slash facing the wrong way doesn’t mean that the file is safely nestled in a folder like that guy inside of the Bantha in Star Wars, it means a file <strong>named</strong> <code class="language-plaintext highlighter-rouge">"Controllers\HomeController.cs"</code>.</p>

<p>Like, no folder at all. Just one cursed file.</p>

<h2 id="root-cause-powershell-v5-zips-wrong">Root cause: PowerShell v5 Zips Wrong™</h2>

<p>The ZIP file had been created using PowerShell 5 in a Windows container. And here’s where the real goblin comes in:</p>

<blockquote>
  <p>PowerShell v5’s <code class="language-plaintext highlighter-rouge">Compress-Archive</code> writes entries with <strong>Windows-style backslashes</strong>.<br />
Not as path separators. As actual <strong>filename characters</strong>.</p>
</blockquote>

<p>When you unzip that on Linux? Congratulations, you’ve just summoned a cursed archive where:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Controllers\HomeController.cs</code> is a file, not a folder + file</li>
  <li>Nothing works because <strong>no tools expect this</strong></li>
  <li>PowerShell is confused, .NET is confused, <em>I’m</em> confused</li>
</ul>

<p><a href="https://superuser.com/questions/1382839/zip-files-expand-with-backslashes-on-linux-no-subdirectories?utm_source=chatgpt.com">Yes</a>, <a href="https://stackoverflow.com/questions/27289115/system-io-compression-zipfile-net-4-5-output-zip-in-not-suitable-for-linux-mac?utm_source=chatgpt.com">this</a> <a href="https://github.com/MicrosoftDocs/PowerShell-Docs/issues/4975?utm_source=chatgpt.com">has</a> <a href="https://mikebridge.github.io/post/windows-tar-gzip-for-linux/?utm_source=chatgpt.com">been</a> <a href="https://qa.fmod.com/t/bug-fmod-engine-download-uses-backslashes-in-archives-which-do-not-expand-correctly-on-linux/21977?utm_source=chatgpt.com">a</a> <a href="https://stackoverflow.com/questions/27289115/system-io-compression-zipfile-net-4-5-output-zip-in-not-suitable-for-linux-mac?utm_source=chatgpt.com">known</a> <a href="https://mikebridge.github.io/post/windows-tar-gzip-for-linux/?utm_source=chatgpt.com">bug</a> <a href="https://superuser.com/questions/1382839/zip-files-expand-with-backslashes-on-linux-no-subdirectories?utm_source=chatgpt.com">for</a> <a href="https://github.com/MicrosoftDocs/PowerShell-Docs/issues/4975?utm_source=chatgpt.com"><em>years</em></a>.</p>

<p>But PowerShell v5 is built into Windows and I do not think this particular thing is getting fixed because you never know, some company out there making critical life saving widgets might have built their entire production line workflow depending on this behavior of zip files.</p>

<p>I don’t know, not my department.</p>

<h2 id="wrapping-it-all-up">Wrapping it all up</h2>

<ul>
  <li><code class="language-plaintext highlighter-rouge">Get-ChildItem</code> could see the file just fine, since PowerShell is slash agnostic</li>
  <li>But <code class="language-plaintext highlighter-rouge">$_ .FullName</code> or <code class="language-plaintext highlighter-rouge">.ToString()</code> rewrote the slashes to forward ones</li>
  <li>So <code class="language-plaintext highlighter-rouge">Upload</code> failed because it passed the wrong path</li>
  <li><code class="language-plaintext highlighter-rouge">-Include</code> and <code class="language-plaintext highlighter-rouge">-Filter</code> (which hit the provider layer) failed completely due to the implicit conversion of slash direction</li>
  <li>Meanwhile piping into <code class="language-plaintext highlighter-rouge">Where-Object</code> <em>worked</em>, because it stayed object-based and so PowerShell could navigate around that</li>
</ul>

<p>This led to the haunting bug where <strong>I could see a file, but not act on it</strong>.<br />
Even <code class="language-plaintext highlighter-rouge">Copy-Item</code> and <code class="language-plaintext highlighter-rouge">Test-Path</code> failed.</p>

<p>And yes you are right, I could have fixed this by using <code class="language-plaintext highlighter-rouge">-LiteralPath</code> but I really wanted to fix the underlying issue.  You deserve a cookie for thinking about this as a fix, treat yo’ self.</p>

<h2 id="the-fix-powershell-core-v7-to-the-rescue">The Fix: PowerShell Core (v7+) to the Rescue</h2>

<p>Once I figured this out (after many wasted hours and caffeine), the fix was simple:</p>

<p><strong>Run the ZIP creation step in PowerShell Core</strong>.</p>

<p>PowerShell 7 uses <code class="language-plaintext highlighter-rouge">System.IO.Compression.ZipArchive</code> in a way that correctly encodes folders using <strong>forward slashes</strong> as expected. And not as part of the file name. Wild, right?</p>

<p>Suddenly:</p>

<ul>
  <li>Files extracted into real folders</li>
  <li>Uploads worked</li>
  <li>Slashes stayed in their lane</li>
  <li>I slept better</li>
</ul>

<p>It was literally as simple as adding <code class="language-plaintext highlighter-rouge">pwsh: true</code> to my YAML pipeline file.</p>

<h2 id="why-the-eff-is-this-even-a-difference-in-windows-and-linux">Why the eff is this even a difference in Windows and Linux?</h2>

<p>This is really interesting.  I’d heard a lawsuit was involved in some distant point in the path but maybe not, maybe it was all just as simple as ‘This is how IBM did it’.  In any case, <a href="https://www.os2museum.com/wp/why-does-windows-really-use-backslash-as-path-separator/">you can read for yourself here</a></p>

<h2 id="final-thoughts-dont-let-this-happen-to-you">Final Thoughts: Don’t Let This Happen to You</h2>

<p>This was a perfect example of a cross-platform edge case that <em>seemed</em> fine—until it hit a different environment. PowerShell did what it was told… it just told no one what it actually did.</p>

<p>If you’re:</p>

<ul>
  <li>Using <strong>Windows-based build agents</strong></li>
  <li>Creating ZIPs in <strong>PowerShell v5</strong></li>
  <li>Deploying those ZIPs on <strong>Linux containers</strong></li>
</ul>

<blockquote>
  <p><strong>Switch to PowerShell Core now.</strong> Save yourself. Save your pipeline. Save your sanity.</p>
</blockquote>

<p>This bug was never fixed in Windows PowerShell.<br />
The fix is easy—just <strong>use the modern shell</strong>.</p>

<p>But if you’re like me, you can still use PowerShell ISE just to annoy your coworkers.</p>]]></content><author><name>Stephen Owen</name></author><category term="programming" /><category term="PowerShell" /><category term="DevOps" /><category term="AzurePipelines" /><summary type="html"><![CDATA[Everything looked fine...until our Linux container refused to touch our build artifacts. Turns out PowerShell v5 zipped up our files with backslashes in their *names*. This post dives into a cursed bug with a surprisingly simple fix.]]></summary></entry></feed>