<?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: arnostorg</title>
    <description>The latest articles on DEV Community by arnostorg (@arnostorg).</description>
    <link>https://dev.to/arnostorg</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1724213%2Fbf22ff52-4243-4658-b3c1-0722d1a13b17.webp</url>
      <title>DEV Community: arnostorg</title>
      <link>https://dev.to/arnostorg</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arnostorg"/>
    <language>en</language>
    <item>
      <title>Three Windows CLI Myths I Believed Until I Taught Them</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Sun, 18 Oct 2026 13:25:41 +0000</pubDate>
      <link>https://dev.to/arnostorg/three-windows-cli-myths-i-believed-until-i-taught-them-3ljd</link>
      <guid>https://dev.to/arnostorg/three-windows-cli-myths-i-believed-until-i-taught-them-3ljd</guid>
      <description>&lt;p&gt;Teaching is a myth detection machine. Ideas that feel true when you’re solo break when twenty learners follow them literally. Here are three Windows CLI myths I believed—and what replaced them after I tried teaching them out loud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Myth 1: “CMD is obsolete; skip it.”
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What I believed:&lt;/strong&gt; PowerShell is the curriculum. CMD is history trivia.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teaching revealed:&lt;/strong&gt; Learners hit vendor &lt;code&gt;.bat&lt;/code&gt; files, constrained images, and support scripts in the first month. Skipping CMD didn’t make them modern. It made them brittle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replacement:&lt;/strong&gt; Teach CMD as a &lt;strong&gt;constrained toolkit&lt;/strong&gt; for file ops and legacy glue, then graduate to PowerShell for structured automation. No shame lane.&lt;/p&gt;

&lt;h2&gt;
  
  
  Myth 2: “If they learn Bash on Linux/WSL first, Windows will be easy.”
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What I believed:&lt;/strong&gt; Transfer will Just Happen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teaching revealed:&lt;/strong&gt; Quoting, path shapes, and pipeline semantics don’t transfer automatically. Learners who only practiced Bash treated PowerShell as broken Bash and blamed themselves.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replacement:&lt;/strong&gt; Platform-honest practice on the shell they’ll use this week. Add Git Bash/WSL as an explicit second contract—not as the “real” one. (Related rant energy, calmer delivery.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Myth 3: “Tab completion + copy-paste is enough to become dangerous-in-a-good-way.”
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What I believed:&lt;/strong&gt; Ergonomics unlock competence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What teaching revealed:&lt;/strong&gt; Learners could assemble commands they couldn’t debug. Exit codes, encoding, and Execution Policy inspection were missing. They looked fluent until the first red error without a screenshot twin.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Replacement:&lt;/strong&gt; Every module needs recovery reps. Completion is allowed; semantics are required.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I “tried” these myths
&lt;/h2&gt;

&lt;p&gt;Not in a lab coat—in cohorts and office hours. I taught the myth version, watched the failure mode, then changed the lesson. The bruise patterns repeated enough to retire the myths.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I do differently in materials now
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Name the shell on every example.&lt;/li&gt;
&lt;li&gt;Put non-ASCII and spaces in paths on purpose.&lt;/li&gt;
&lt;li&gt;Force &lt;code&gt;where&lt;/code&gt; / &lt;code&gt;Get-Command&lt;/code&gt; and exit code checks early.&lt;/li&gt;
&lt;li&gt;Keep soft links to practice environments instead of launch-blog energy.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How the myths showed up in office hours
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;“I skipped CMD and now this vendor script is hieroglyphs.”&lt;/li&gt;
&lt;li&gt;“I practiced on Ubuntu; PowerShell quoting feels random.”&lt;/li&gt;
&lt;li&gt;“I tab-completed everything; why did CI fail with exit 1?”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each sentence is a curriculum smell. If your materials produce those office-hour patterns, update the materials—don’t blame the learner’s grit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replacement myths I refuse to install
&lt;/h2&gt;

&lt;p&gt;I also won’t install the reverse dogma (“never learn Linux,” “PowerShell is always wrong,” “GUIs are cheating”). Operator culture should be greedy for tools and precise about contracts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Invite for fellow instructors
&lt;/h2&gt;

&lt;p&gt;If you’ve retired a CLI myth after teaching it, keep a changelog. Curriculum honesty compounds. Myths hate changelogs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fourth almost-myth I nearly included
&lt;/h2&gt;

&lt;p&gt;“Windows Terminal settings are the same thing as shell knowledge.” They’re not. Host configuration helps; it doesn’t teach exit codes. I cut it for length—but if you’re building a course, don’t let dockets of JSON themes replace fundamentals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing challenge
&lt;/h2&gt;

&lt;p&gt;Pick one myth you still teach “because everyone says it.” Teach the opposite for one cohort week—with measurement. Keep whichever version produces colder-prompt competence. Loyalty to slogans is optional; loyalty to outcomes isn’t.&lt;/p&gt;

&lt;p&gt;If you want a place that assumes Windows-first operators deserve serious drills, I’m building that practice surface as &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt;—free interactive browser-terminal learning for CMD, PowerShell, and Bash.&lt;/p&gt;

&lt;p&gt;Myths feel efficient. Teaching makes them expensive. Pay the cost once in curriculum design, or pay it forever in office hours.&lt;/p&gt;

</description>
      <category>windows</category>
      <category>cli</category>
      <category>teaching</category>
      <category>learning</category>
    </item>
    <item>
      <title>Oh My Posh Looks Cool. Here’s When It’s Worth the Setup Cost</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Sat, 17 Oct 2026 13:28:53 +0000</pubDate>
      <link>https://dev.to/arnostorg/oh-my-posh-looks-cool-heres-when-its-worth-the-setup-cost-4cbd</link>
      <guid>https://dev.to/arnostorg/oh-my-posh-looks-cool-heres-when-its-worth-the-setup-cost-4cbd</guid>
      <description>&lt;p&gt;Oh My Posh makes a Windows prompt look like a conference talk. Glyphs, segments, Git status, cloud context—eye candy with a purpose. I ran it, loved it, over-invested, then ripped most of it out. This retrospective is about &lt;strong&gt;when the setup cost is worth it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The real costs (not the install one-liner)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Font dependency.&lt;/strong&gt; Nerd Fonts (or equivalent) across terminals, VS Code, remote sessions. Miss one host and your prompt becomes mojibake theater.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Startup tax.&lt;/strong&gt; Heavy segments that shell out to git/network on every prompt add friction on slow disks and large repos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cognitive load for demos.&lt;/strong&gt; Students stare at your diamonds instead of your command.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portability.&lt;/strong&gt; Your brain expects segments that aren’t on locked corporate shells.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Install is easy. Habitat change isn’t.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it &lt;em&gt;was&lt;/em&gt; worth it for me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Daily driver machine I control end-to-end.&lt;/li&gt;
&lt;li&gt;Work where &lt;strong&gt;repo/branch awareness&lt;/strong&gt; prevents wrong-directory deploys.&lt;/li&gt;
&lt;li&gt;A prompt theme with &lt;strong&gt;few segments&lt;/strong&gt; (path + git + error) rather than a Christmas tree.&lt;/li&gt;
&lt;li&gt;After the shell fundamentals were already boring and solid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last point matters. Prompt bling on top of confused exit codes is cosplay.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it wasn’t
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Teaching sessions (I switched to a plain prompt).&lt;/li&gt;
&lt;li&gt;Jump boxes and customer machines.&lt;/li&gt;
&lt;li&gt;CI-like terminals.&lt;/li&gt;
&lt;li&gt;Any machine where installing fonts was a ticket.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also: when I realized I was tuning theme JSON instead of finishing the task that made me open the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  A pragmatic middle path
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use Oh My Posh (or a minimal PS prompt function) on &lt;strong&gt;personal/dev&lt;/strong&gt; profiles only.&lt;/li&gt;
&lt;li&gt;Keep a &lt;code&gt;-NoProfile&lt;/code&gt; / plain profile muscle for teaching and support.&lt;/li&gt;
&lt;li&gt;Cap segments ruthlessly. If a segment doesn’t prevent mistakes, it’s decoration.&lt;/li&gt;
&lt;li&gt;Measure prompt time on your heaviest repo. If you feel it, cut it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Retrospective verdict
&lt;/h2&gt;

&lt;p&gt;Oh My Posh is worth the setup cost when it &lt;strong&gt;reduces wrong-context errors&lt;/strong&gt; and you control the surface area. It’s not worth it as identity, as a teaching default, or as a substitute for learning the shell underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  My “worth it” segment budget
&lt;/h2&gt;

&lt;p&gt;Allowed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;current path (shortened),&lt;/li&gt;
&lt;li&gt;git branch + dirty state,&lt;/li&gt;
&lt;li&gt;last command success/fail marker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Denied (for me):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;weather,&lt;/li&gt;
&lt;li&gt;Kubernetes context on every prompt when I’m not on-call for it,&lt;/li&gt;
&lt;li&gt;multiple cloud account glyphs,&lt;/li&gt;
&lt;li&gt;clocks I can see on the taskbar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your budget may differ. The point is having a budget.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rollback plan
&lt;/h2&gt;

&lt;p&gt;Keep a &lt;code&gt;prompt_plain&lt;/code&gt; profile (or &lt;code&gt;-NoProfile&lt;/code&gt; habit) you can switch to in one click. If your bling can’t be disabled during an incident, it’s an operational liability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Teaching tax, restated
&lt;/h2&gt;

&lt;p&gt;Every glyph you add is something a learner might think is required knowledge. If it isn’t, hide it when you teach. Cool prompts are for machines you own; classrooms need the signal-to-noise ratio of a runway, not a festival.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ninety-day keep/kill (prompt edition)
&lt;/h2&gt;

&lt;p&gt;Kept: path + git + error marker on personal pwsh.&lt;br&gt;&lt;br&gt;
Killed: network segments, excessive glyphs, identical theme forced onto teaching demos.&lt;br&gt;&lt;br&gt;
Maybe later: a second theme for “focus mode” with path only.&lt;/p&gt;

&lt;p&gt;The retrospective isn’t anti-beauty. It’s pro-mistake-reduction accounting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Font failure mode (so you’re not surprised)
&lt;/h2&gt;

&lt;p&gt;Remote desktop to a box without Nerd Fonts and your prompt becomes tofu boxes. If that box is a customer jump host, you just spent cognitive budget on cosmetics during an incident. Keep a plain profile reachable in one switch.&lt;/p&gt;

&lt;p&gt;I’m biased toward plain prompts in learning products for that reason—see the deliberately un-fancy practice UX in &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt;. Make the skill loud. Keep the chrome quiet until it earns a slot.&lt;/p&gt;

&lt;p&gt;Cool is allowed. Cost accounting is required.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>windows</category>
      <category>terminal</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Should Corporates Ban Personal PowerShell Profiles?</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Fri, 16 Oct 2026 13:23:56 +0000</pubDate>
      <link>https://dev.to/arnostorg/should-corporates-ban-personal-powershell-profiles-1ki8</link>
      <guid>https://dev.to/arnostorg/should-corporates-ban-personal-powershell-profiles-1ki8</guid>
      <description>&lt;h1&gt;
  
  
  Should Corporates Ban Personal PowerShell Profiles?
&lt;/h1&gt;

&lt;p&gt;Personal PowerShell profiles are cozy. They also scare security teams: persistent custom code on jump boxes, shadowing built-ins, sneaky aliases that change what a runbook means, credentials that “temporarily” landed in a profile in 2019 and never left.&lt;/p&gt;

&lt;p&gt;So—&lt;strong&gt;should corporates ban them?&lt;/strong&gt; I don’t think the binary question is the useful one. The useful one is: what risk are you actually managing, and what operator freedom are you willing to trade?&lt;/p&gt;

&lt;h2&gt;
  
  
  The steelman for bans / lockdowns
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shared admin hosts&lt;/strong&gt; shouldn’t depend on per-user surprise behavior.&lt;/li&gt;
&lt;li&gt;Profiles can hide &lt;strong&gt;malware-ish persistence&lt;/strong&gt; among legitimate UX.&lt;/li&gt;
&lt;li&gt;Audit and change control get harder when every shell is unique.&lt;/li&gt;
&lt;li&gt;Junior admins copy internet profiles that override &lt;code&gt;curl&lt;/code&gt;, truncate history, or phone home for prompt themes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your environment is high-assurance and shared, “no arbitrary profile code” is a defensible default.&lt;/p&gt;

&lt;h2&gt;
  
  
  The steelman for allowing constrained profiles
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Experts are faster with carefully chosen functions.&lt;/li&gt;
&lt;li&gt;Absolute bans push work into &lt;strong&gt;shadow workarounds&lt;/strong&gt; (USB scripts, personal laptops, unexplained binaries).&lt;/li&gt;
&lt;li&gt;Teaching and onboarding sometimes &lt;em&gt;need&lt;/em&gt; a controlled profile to demonstrate good patterns.&lt;/li&gt;
&lt;li&gt;Not all hosts are equal: a developer laptop ≠ a tier-0 jump box.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A blanket ban across every Windows box treats unequal risk as equal.&lt;/p&gt;

&lt;h2&gt;
  
  
  A third option: policy by tier
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Profile stance&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tier-0 / break-glass&lt;/td&gt;
&lt;td&gt;Locked: signed profiles only or none&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared ops jump boxes&lt;/td&gt;
&lt;td&gt;Controlled: company-blessed profile repo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Developer endpoints&lt;/td&gt;
&lt;td&gt;Allowed: guidance + secret scanning education&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Training sandboxes&lt;/td&gt;
&lt;td&gt;Encouraged: teach clean vs dirty profiles&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is more work than a meme policy. It’s also more aligned with how incidents actually happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Norms that beat pure prohibition
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No secrets in profiles. Ever. Use secret stores.&lt;/li&gt;
&lt;li&gt;Don’t shadow critical commands without extreme cause.&lt;/li&gt;
&lt;li&gt;Prefer dot-sourced company modules over 500-line personal novels.&lt;/li&gt;
&lt;li&gt;Demonstrate scripts with &lt;code&gt;pwsh -NoProfile&lt;/code&gt; when reproducibility matters.&lt;/li&gt;
&lt;li&gt;Code review the blessed profile the same way you review other tooling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I’m asking the community
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Failure stories I’ve heard (composites)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An alias redefining a common command caused a runbook to skip a step on one admin’s laptop only.&lt;/li&gt;
&lt;li&gt;A “temporary” credential in a profile synced via a dotfiles repo.&lt;/li&gt;
&lt;li&gt;A prompt theme calling network APIs slowed every shell on a restricted VLAN until it looked like an outage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these require assuming malice. They require assuming profiles are code.&lt;/p&gt;

&lt;h2&gt;
  
  
  A question for security and platform teams
&lt;/h2&gt;

&lt;p&gt;If you ban profiles but don’t provide a blessed, reviewed module of shared helpers, you’re not removing customization—you’re pushing it underground. Pair controls with an official path for ergonomics.&lt;/p&gt;

&lt;h2&gt;
  
  
  My personal vote (not a policy template)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ban or lock on tier-0.&lt;/li&gt;
&lt;li&gt;Curate on shared ops hosts.&lt;/li&gt;
&lt;li&gt;Guide and educate on developer laptops.&lt;/li&gt;
&lt;li&gt;Always provide a blessed alternative for common ergonomics.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only ban, you outsource UX to shadow IT. If you only allow, you outsource risk to hope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discuss framing for mixed audiences
&lt;/h2&gt;

&lt;p&gt;Security folks hear “ban.” Developers hear “trust me.” Platform folks hear “tiered control plane.” If your org can only have one conversation, have the tiered one—it forces everyone to name which machines they’re actually talking about.&lt;/p&gt;

&lt;p&gt;I’m not selling a product feature here so much as an ops culture question—though I’ll admit clean-shell teaching is part of why I care about profile hygiene when building lessons for &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discuss:&lt;/strong&gt; In your org, are personal PowerShell profiles banned, ignored, or curated—and which failure mode have you actually seen: malware persistence, runbook confusion, or death-by-tooling-rigidity?&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>security</category>
      <category>enterprise</category>
      <category>discuss</category>
    </item>
    <item>
      <title>PowerShell Remove-Item: Dry-Run Deletes with -WhatIf Before You Nuke Folders</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Fri, 16 Oct 2026 07:24:16 +0000</pubDate>
      <link>https://dev.to/arnostorg/powershell-remove-item-dry-run-deletes-with-whatif-before-you-nuke-folders-14ec</link>
      <guid>https://dev.to/arnostorg/powershell-remove-item-dry-run-deletes-with-whatif-before-you-nuke-folders-14ec</guid>
      <description>&lt;p&gt;You are about to wipe a folder on a locked work laptop. Recycle Bin is policy-disabled. There is no "oops, restore from backup" button for the next ten minutes. &lt;code&gt;Remove-Item&lt;/code&gt; will do exactly what you typed — including the path you thought you typed. The only free safety net is a dry run.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mental model: preview, then destroy
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Remove-Item&lt;/code&gt; (aliases: &lt;code&gt;rm&lt;/code&gt;, &lt;code&gt;del&lt;/code&gt;, &lt;code&gt;ri&lt;/code&gt;) deletes files and folders. Two common parameters change &lt;em&gt;how sure&lt;/em&gt; you are before anything is gone:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Switch&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;When to use it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-WhatIf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Prints what &lt;em&gt;would&lt;/em&gt; be deleted. Touches nothing.&lt;/td&gt;
&lt;td&gt;Always before a recursive or wildcard delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-Confirm&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Asks Yes/No/All for each target (or a batch prompt)&lt;/td&gt;
&lt;td&gt;Interactive cleanup when you want a human gate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-Recurse&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Walks into folders&lt;/td&gt;
&lt;td&gt;Folder trees — and the place most people regret speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-Force&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Overrides read-only / hidden / some prompts&lt;/td&gt;
&lt;td&gt;Only after &lt;code&gt;-WhatIf&lt;/code&gt; looked correct&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;On Windows PowerShell 5.1 and PowerShell 7 the switches work the same for this workflow. The difference that matters is you, not the version: dry-run first, then remove the safety switch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 1: dry-run with -WhatIf
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs\&lt;/span&gt;&lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="nf"&gt;tmp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You get lines like &lt;code&gt;What if: Performing the operation "Remove File" on target "C:\Logs\old.tmp".&lt;/code&gt; Read every path. If one of them is &lt;code&gt;C:\Logs&lt;/code&gt; itself or a sibling you did not mean, stop. Fix the pattern. Run &lt;code&gt;-WhatIf&lt;/code&gt; again until the list is boring and correct.&lt;/p&gt;

&lt;p&gt;Wildcard preview for a whole tree of junk:&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-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Temp\BuildCache&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&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;Where-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Extension&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.tmp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'.log'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'.bak'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Piping into &lt;code&gt;Remove-Item -WhatIf&lt;/code&gt; still only &lt;em&gt;simulates&lt;/em&gt;. Nothing is deleted until you drop &lt;code&gt;-WhatIf&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 2: -Confirm when you want a human gate
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Staging\&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Confirm&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell prompts before each item (or offers Yes to All). Use this when the set is small and you are watching the screen. Do &lt;strong&gt;not&lt;/strong&gt; rely on &lt;code&gt;-Confirm&lt;/code&gt; inside a scheduled task or a script that runs unattended — there is nobody to answer, and depending on host settings the call can hang or fail.&lt;/p&gt;

&lt;p&gt;For scripts, prefer the &lt;code&gt;-WhatIf&lt;/code&gt; review in a terminal, then a second run without it. For interactive one-offs at a desk, &lt;code&gt;-Confirm&lt;/code&gt; is fine.&lt;/p&gt;

&lt;p&gt;Combine both when you are nervous:&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;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Staging\export-2026-10-15&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Confirm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-WhatIf&lt;/code&gt; wins: you still get a preview and no delete. Drop &lt;code&gt;-WhatIf&lt;/code&gt; when the preview is approved; keep &lt;code&gt;-Confirm&lt;/code&gt; if you still want click-through safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 3: delete a folder tree carefully
&lt;/h2&gt;

&lt;p&gt;A non-empty folder refuses a bare &lt;code&gt;Remove-Item&lt;/code&gt; without &lt;code&gt;-Recurse&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fails if C:\Logs\OldRuns still has files&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs\OldRuns&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The careful pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1) Preview the tree&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs\OldRuns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&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;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FullName&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# 2) Dry-run the delete&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs\OldRuns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# 3) Only then&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs\OldRuns&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On locked corporate images, deleted items often skip the Recycle Bin entirely when removed from PowerShell. Treat step 2 as mandatory, not optional theater.&lt;/p&gt;

&lt;p&gt;PowerShell 7 tip: same switches. If you delete large trees often, preview with &lt;code&gt;Get-ChildItem&lt;/code&gt; first so you see count and depth before &lt;code&gt;Remove-Item&lt;/code&gt; walks them again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 4: the footgun — wrong path, wildcards, and -Force
&lt;/h2&gt;

&lt;p&gt;These are the tickets that start with "I only meant to clear temp files."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong path / too-broad wildcard&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Looks local. If you are in C:\ and mistype, you can match far more than you think.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Always prefer an absolute path for destructive work:&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;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Apps\MyService\cache\&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;code&gt;-Force&lt;/code&gt; hides warnings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-Force&lt;/code&gt; clears the read-only bit and pushes through some confirmation paths. It does &lt;strong&gt;not&lt;/strong&gt; make a bad path safe. Combining &lt;code&gt;-Recurse -Force&lt;/code&gt; without a prior &lt;code&gt;-WhatIf&lt;/code&gt; is how a typo in &lt;code&gt;C:\Logs&lt;/code&gt; becomes &lt;code&gt;C:\Log&lt;/code&gt; or worse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hidden / system files&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&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;Where-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-like&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'*.tmp'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;-Force&lt;/code&gt; on &lt;code&gt;Get-ChildItem&lt;/code&gt; to &lt;em&gt;see&lt;/em&gt; hidden targets in the preview. Use &lt;code&gt;-Force&lt;/code&gt; on &lt;code&gt;Remove-Item&lt;/code&gt; only after that list looks right.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Providers other than the filesystem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Remove-Item&lt;/code&gt; also works on registry keys, certificates, and other providers. A path that starts with &lt;code&gt;HKLM:\&lt;/code&gt; or &lt;code&gt;Cert:\&lt;/code&gt; is not a folder on disk. If your muscle memory is filesystem-only, pause when the provider prefix is not &lt;code&gt;C:\&lt;/code&gt; / &lt;code&gt;\\server\share&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A safe default ritual
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Write the command with a full path.&lt;/li&gt;
&lt;li&gt;Append &lt;code&gt;-WhatIf&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Read the preview like a change ticket.&lt;/li&gt;
&lt;li&gt;Re-run the same line without &lt;code&gt;-WhatIf&lt;/code&gt; (add &lt;code&gt;-Confirm&lt;/code&gt; if you still want prompts).&lt;/li&gt;
&lt;li&gt;Keep &lt;code&gt;-Force&lt;/code&gt; off until a read-only/hidden block is a known, reviewed exception.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That ritual is slower than a one-liner. It is also how you keep your job and the team's night quiet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice deletes somewhere that cannot hurt production
&lt;/h2&gt;

&lt;p&gt;The scary part of &lt;code&gt;Remove-Item&lt;/code&gt; is that real machines forgive typos slowly. In &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master's interactive PowerShell lessons&lt;/a&gt; you can run &lt;code&gt;Remove-Item&lt;/code&gt;, &lt;code&gt;-WhatIf&lt;/code&gt;, and &lt;code&gt;-Confirm&lt;/code&gt; in a live browser terminal with instant feedback — no install, no VM, no Recycle Bin policy surprises. The same &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;free Windows command line practice site&lt;/a&gt; covers CMD and Bash when you hop between shells.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your turn:&lt;/strong&gt; what is the worst almost-delete &lt;code&gt;-WhatIf&lt;/code&gt; ever saved you from? Drop the story (sanitized paths welcome) in the comments.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>scripting</category>
      <category>windows</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Tab Completion Won’t Save You From Not Understanding Exit Codes</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Thu, 15 Oct 2026 13:38:01 +0000</pubDate>
      <link>https://dev.to/arnostorg/tab-completion-wont-save-you-from-not-understanding-exit-codes-4an6</link>
      <guid>https://dev.to/arnostorg/tab-completion-wont-save-you-from-not-understanding-exit-codes-4an6</guid>
      <description>&lt;p&gt;I tried an experiment on myself: lean hard on tab completion and IntelliSense-ish shell helpers for two weeks, and deliberately &lt;em&gt;not&lt;/em&gt; study exit codes beyond vibes. I wanted to see how far ergonomics carry you.&lt;/p&gt;

&lt;p&gt;Far enough to look productive. Not far enough to be safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  The seductive part
&lt;/h2&gt;

&lt;p&gt;Tab completion reduces spelling errors. It surfaces parameters. It makes PowerShell feel modern. Students love it. I love it. This post is not anti-completion.&lt;/p&gt;

&lt;p&gt;It’s anti-&lt;strong&gt;substituting UX for semantics&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I got burned
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pipelines that “looked fine”
&lt;/h3&gt;

&lt;p&gt;A native tool failed halfway. The screen still printed something. Because I didn’t check &lt;code&gt;$LASTEXITCODE&lt;/code&gt; / &lt;code&gt;%ERRORLEVEL%&lt;/code&gt;, a later step ran on partial output. Tab completion had helped me type the broken pipeline faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  CI vs laptop gap
&lt;/h3&gt;

&lt;p&gt;Locally, aliases and profile helpers padded mistakes. In CI, bare shells told the truth. Completion wasn’t available in the same way; exit codes suddenly mattered and I had no muscle memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  False green in batch wrappers
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;.bat&lt;/code&gt; called a tool, ignored failure, exited 0 by accident of flow. The wrapper “completed.” Completion never enters that story. Semantics do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tiny model that actually saves you
&lt;/h2&gt;

&lt;p&gt;Processes signal outcome with an &lt;strong&gt;exit code&lt;/strong&gt;. By convention, &lt;code&gt;0&lt;/code&gt; means success; non-zero means failure (with program-specific meanings).&lt;/p&gt;

&lt;p&gt;PowerShell complications worth learning early:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;$LASTEXITCODE&lt;/code&gt; for native executables.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-not $?&lt;/code&gt; / &lt;code&gt;$true&lt;/code&gt; &lt;code&gt;$false&lt;/code&gt; patterns for shell-level success.&lt;/li&gt;
&lt;li&gt;Cmdlet errors vs native exit codes—different channels.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CMD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="kd"&gt;mytool&lt;/span&gt;&lt;span class="err"&gt;.exe&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;%ERRORLEVEL%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PowerShell:&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;mytool.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$LASTEXITCODE&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Put that reflex before you chase prettier prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The i_tried rule I kept afterward
&lt;/h2&gt;

&lt;p&gt;For every new tool, I practice one happy run &lt;strong&gt;and&lt;/strong&gt; one forced failure, then read the code. Tab-complete the flags. Still read the code.&lt;/p&gt;

&lt;p&gt;When teaching, I now introduce completion as a speed tool &lt;em&gt;after&lt;/em&gt; a first intentional failure exercise. Otherwise learners optimize for “command accepted by the completer,” not “operation succeeded.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Product note
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Two-week experiment protocol (replicable)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Week A: completion on, exit-code checks off (honor system).&lt;/li&gt;
&lt;li&gt;Week B: completion still on, but every native call followed by an explicit status check in a learning log.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My log’s Week A was full of “looked fine.” Week B caught three silent partial failures I’d have pasted into a ticket as “weird output.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Teaching script you can steal
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run a command that succeeds; show &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Run a command that fails; show non-zero.&lt;/li&gt;
&lt;li&gt;Chain with &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; / &lt;code&gt;||&lt;/code&gt; (CMD) or PowerShell equivalents carefully.&lt;/li&gt;
&lt;li&gt;Only then celebrate tab completion as speed—not as truth.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  PowerShell-specific footgun
&lt;/h2&gt;

&lt;p&gt;Cmdlet errors and native exit codes aren’t the same channel. A pipeline can look chatty while &lt;code&gt;$LASTEXITCODE&lt;/code&gt; still says the native tool failed. Completion won’t narrate that. Your checklist must.&lt;/p&gt;

&lt;h2&gt;
  
  
  Incident postmortem one-liner
&lt;/h2&gt;

&lt;p&gt;“The command looked correct and the completer accepted it” is not a root cause. “We didn’t check the exit code before the next step” often is. Write that on a card. Completion stays; accountability stays harder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pairing exercise (five minutes)
&lt;/h2&gt;

&lt;p&gt;Driver types a failing command on purpose. Navigator must state the exit code before suggesting a fix. No googling until the code is spoken aloud. It feels pedantic. It builds the reflex completion can’t.&lt;/p&gt;

&lt;p&gt;Speed without a status check is just faster fiction.&lt;/p&gt;

&lt;p&gt;Interactive drills are perfect for this: hide the next step behind a checked exit code. That’s a pattern I use while refining &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt;—completion optional, outcome mandatory.&lt;/p&gt;

&lt;p&gt;Ergonomics help you type. Exit codes tell you whether you should have.&lt;/p&gt;

</description>
      <category>cli</category>
      <category>powershell</category>
      <category>windows</category>
      <category>learning</category>
    </item>
    <item>
      <title>Batch .bat in 2026: Legacy Glue, Not a Personality</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Wed, 14 Oct 2026 13:28:09 +0000</pubDate>
      <link>https://dev.to/arnostorg/batch-bat-in-2026-legacy-glue-not-a-personality-271p</link>
      <guid>https://dev.to/arnostorg/batch-bat-in-2026-legacy-glue-not-a-personality-271p</guid>
      <description>&lt;p&gt;I still write &lt;code&gt;.bat&lt;/code&gt; files in 2026. I also refuse to build an identity around them. That distinction—&lt;strong&gt;legacy glue vs personality&lt;/strong&gt;—is the retrospective I wish someone had handed me earlier.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where &lt;code&gt;.bat&lt;/code&gt; still appears (unironically)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Vendor installers and unwrap scripts.&lt;/li&gt;
&lt;li&gt;Scheduled tasks authored a decade ago that still pay the bills.&lt;/li&gt;
&lt;li&gt;Tiny wrappers that set env vars and launch something else.&lt;/li&gt;
&lt;li&gt;Locked images where PowerShell scripts are political and CMD isn’t.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your job touches Windows estates, you will read batch. Pretending otherwise is aesthetic, not operational.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I no longer use batch for
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Nontrivial logic (nested delayed expansion temples).&lt;/li&gt;
&lt;li&gt;JSON / HTTP workflows.&lt;/li&gt;
&lt;li&gt;Anything that needs testable functions and clear error objects.&lt;/li&gt;
&lt;li&gt;Team-shared automation when PowerShell is available.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Writing clever batch to prove cleverness is a personality choice. Production doesn’t owe you applause.&lt;/p&gt;

&lt;h2&gt;
  
  
  Glue patterns that aged okay
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Thin wrapper:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;@echo &lt;span class="na"&gt;off&lt;/span&gt;
&lt;span class="nb"&gt;setlocal&lt;/span&gt;
&lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="kd"&gt;APP_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kd"&gt;prod&lt;/span&gt;
&lt;span class="s2"&gt;"C:\Program Files\App\app.exe"&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;exit&lt;/span&gt; &lt;span class="na"&gt;/b &lt;/span&gt;&lt;span class="nv"&gt;%ERRORLEVEL%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explicit failure:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="kd"&gt;some&lt;/span&gt;&lt;span class="na"&gt;-tool&lt;/span&gt;.exe &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;exit&lt;/span&gt; &lt;span class="na"&gt;/b &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Boring. Copyable. Reviewable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrospective rules I keep
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prefer PowerShell (or a real language) for new automation&lt;/strong&gt; when the environment allows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep batch short&lt;/strong&gt; when you must maintain it—delegate to something saner quickly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comment the why&lt;/strong&gt;, especially quoting and &lt;code&gt;setlocal&lt;/code&gt; choices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Don’t teach batch as a first language for beginners&lt;/strong&gt; beyond survival file ops and reading existing glue.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Teaching without contempt
&lt;/h2&gt;

&lt;p&gt;Calling batch “ancient trash” shames juniors who just opened a vendor script. Calling it “beautiful” traps them in a cul-de-sac. Better: &lt;strong&gt;classify it as glue&lt;/strong&gt;. You learn enough to untangle it, then you graduate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading legacy batch without drowning
&lt;/h2&gt;

&lt;p&gt;When you inherit a 400-line &lt;code&gt;.bat&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find the entry points and &lt;code&gt;goto&lt;/code&gt; labels.&lt;/li&gt;
&lt;li&gt;Note every &lt;code&gt;setlocal&lt;/code&gt; / &lt;code&gt;endlocal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Track &lt;code&gt;ERRORLEVEL&lt;/code&gt; after external calls.&lt;/li&gt;
&lt;li&gt;Extract the “real work” (usually one &lt;code&gt;.exe&lt;/code&gt; with flags).&lt;/li&gt;
&lt;li&gt;Decide whether to wrap, rewrite, or quarantine.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Often the right 2026 move is a PowerShell rewrite &lt;em&gt;plus&lt;/em&gt; a one-line &lt;code&gt;.bat&lt;/code&gt; shim for callers that still expect a &lt;code&gt;.bat&lt;/code&gt; path. Glue on the outside, sense on the inside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Personality check
&lt;/h2&gt;

&lt;p&gt;If you enjoy delayed-expansion puzzles more than shipping the installer’s outcome, notice that. Fascination is fine; production ownership is a different scoreboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatibility shim pattern
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;@echo &lt;span class="na"&gt;off&lt;/span&gt;
&lt;span class="kd"&gt;pwsh&lt;/span&gt; &lt;span class="na"&gt;-NoProfile -File &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="vm"&gt;%~dp0&lt;/span&gt;&lt;span class="s2"&gt;tools\task.ps1"&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;exit&lt;/span&gt; &lt;span class="na"&gt;/b &lt;/span&gt;&lt;span class="nv"&gt;%ERRORLEVEL%&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Callers keep a &lt;code&gt;.bat&lt;/code&gt; path; logic lives in something testable. That’s legacy glue with a 2026 brain—not a personality built out of &lt;code&gt;goto&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When rewrite is the wrong first move
&lt;/h2&gt;

&lt;p&gt;If a &lt;code&gt;.bat&lt;/code&gt; is called from fifteen undocumented scheduled tasks, a clever rewrite without inventory is how you create an outage. Inventory callers, add logging, shim carefully, then rewrite the core. Legacy glue rewards patience more than contempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation stub worth pasting above legacy scripts
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="c"&gt;REM Owner: platform-team&lt;/span&gt;
&lt;span class="c"&gt;REM Purpose: thin launcher only — logic in tools\task.ps1&lt;/span&gt;
&lt;span class="c"&gt;REM Last verified: 2026-09&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines prevent the next engineer from assuming the &lt;code&gt;.bat&lt;/code&gt; is the product.&lt;/p&gt;

&lt;p&gt;Glue is honorable when it’s thin, labeled, and temporary-by-intent—even if temporary lasts years.&lt;/p&gt;

&lt;p&gt;That framing matches how I sequence Windows CLI practice in &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt;: respect the artifact, don’t romanticize the dialect.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I disabled in my own habits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Clever &lt;code&gt;goto&lt;/code&gt; forests.&lt;/li&gt;
&lt;li&gt;Environment mutation without &lt;code&gt;setlocal&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Silent error ignoring.&lt;/li&gt;
&lt;li&gt;Using batch where a checked-in PowerShell task would be clearer for the team.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;.bat in 2026 is a compatibility surface.&lt;/strong&gt; Use it like duct tape: proud when it holds, eager to replace it when you can engineer a joint.&lt;/p&gt;

</description>
      <category>cmd</category>
      <category>batch</category>
      <category>windows</category>
      <category>legacy</category>
    </item>
    <item>
      <title>PowerShell Out-File vs Set-Content: Encoding Is the Real Difference</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Wed, 14 Oct 2026 07:26:52 +0000</pubDate>
      <link>https://dev.to/arnostorg/powershell-out-file-vs-set-content-encoding-is-the-real-difference-m9l</link>
      <guid>https://dev.to/arnostorg/powershell-out-file-vs-set-content-encoding-is-the-real-difference-m9l</guid>
      <description>&lt;p&gt;&lt;code&gt;Set-Content&lt;/code&gt; and &lt;code&gt;Out-File&lt;/code&gt; both put text into a file. On a quiet English UTF-8 machine they look interchangeable. On a Czech log, a CSV opened in Excel, or a schedule that later runs under &lt;code&gt;powershell.exe -File&lt;/code&gt;, they are not. The bug is almost never the path. It is the encoding you never asked for.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shortest honest comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;Out-File&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;Set-Content&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Default job&lt;/td&gt;
&lt;td&gt;Capture pipeline &lt;em&gt;output&lt;/em&gt; (what would print on screen)&lt;/td&gt;
&lt;td&gt;Write &lt;em&gt;string content&lt;/em&gt; into a file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default encoding (Windows PowerShell 5.1)&lt;/td&gt;
&lt;td&gt;Unicode (UTF-16 LE)&lt;/td&gt;
&lt;td&gt;Default (often ANSI / system code page)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Default encoding (PowerShell 7+)&lt;/td&gt;
&lt;td&gt;utf8NoBOM&lt;/td&gt;
&lt;td&gt;utf8NoBOM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overwrite vs append&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;-Append&lt;/code&gt; supported&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;Add-Content&lt;/code&gt; to append&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Great at&lt;/td&gt;
&lt;td&gt;Redirecting formatted cmdlet output&lt;/td&gt;
&lt;td&gt;Writing known strings you control&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you memorize one row, memorize the 5.1 defaults. That is where most "my script worked on my laptop" tickets start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 1: capture a command's screen output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Descending&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;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-First&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;20&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;Out-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Reports\top-logs.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Out-File&lt;/code&gt; is the file version of what you see. Objects still go through formatting first, so you get a readable table (or list), not a serialized object dump. That is exactly what you want for a human-readable report, and exactly what you do &lt;strong&gt;not&lt;/strong&gt; want if the next step is another script parsing fields.&lt;/p&gt;

&lt;p&gt;Need the same idea as &lt;code&gt;&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;gt;&amp;gt;&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-Service&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;Out-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Reports\services.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-Process&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;Out-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Reports\services.txt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Append&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recipe 2: write the text you mean
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Set-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Apps\config.env&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="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s1"&gt;'APP_ENV=prod'&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s1"&gt;'LOG_LEVEL=info'&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;-Encoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;utf8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Set-Content&lt;/code&gt; replaces the whole file with the values you pass. No formatting layer. No surprise table headers. Pass an array and you get one line per element (plus a trailing newline, which is usually what you want).&lt;/p&gt;

&lt;p&gt;Always name &lt;code&gt;-Encoding&lt;/code&gt; when the file will leave your machine. Prefer:&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-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\note.txt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Příliš žluťoučký kůň'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Encoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;utf8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On PowerShell 7, &lt;code&gt;utf8&lt;/code&gt; is fine. On Windows PowerShell 5.1, &lt;code&gt;utf8&lt;/code&gt; still writes a BOM. If a downstream tool hates BOMs, write bytes yourself or move the write to pwsh 7 with &lt;code&gt;utf8NoBOM&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 3: the encoding trap in one demo
&lt;/h2&gt;

&lt;p&gt;Run this on Windows PowerShell 5.1 and open both files in a hex editor or Notepad++:&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="s1"&gt;'café'&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;Out-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\via-outfile.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\via-setcontent.txt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'café'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typical result on 5.1:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;via-outfile.txt&lt;/code&gt; → UTF-16 LE (often starts with &lt;code&gt;FF FE&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;via-setcontent.txt&lt;/code&gt; → system ANSI (on Czech Windows, usually Windows-1250)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Neither is "wrong." Both are wrong if you &lt;em&gt;assumed&lt;/em&gt; UTF-8. A later &lt;code&gt;Get-Content&lt;/code&gt; without &lt;code&gt;-Encoding&lt;/code&gt;, a Python script that opens as UTF-8, or Git treating the file as binary will all look like random corruption.&lt;/p&gt;

&lt;p&gt;Force the contract:&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="s1"&gt;'café'&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;Out-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\via-outfile.txt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Encoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;utf8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\via-setcontent.txt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'café'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Encoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;utf8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same string, same encoding, same future.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 4: when Out-File is the wrong tool
&lt;/h2&gt;

&lt;p&gt;This pattern looks neat and silently loses structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Fragile: formatting depends on console width and host&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-ChildItem&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;Out-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\files.txt&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Get-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\files.txt&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;ForEach-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Substring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;10&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="c"&gt;# will break&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If another command must read the file, write data, not a screenshot of data:&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-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&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;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LastWriteTime&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;Export-Csv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\files.csv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-NoTypeInformation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Encoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;utf8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, for simple line lists:&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&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="n"&gt;Set-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\names.txt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Encoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;utf8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rule of thumb: &lt;code&gt;Out-File&lt;/code&gt; for eyes, &lt;code&gt;Set-Content&lt;/code&gt; / &lt;code&gt;Export-Csv&lt;/code&gt; / &lt;code&gt;ConvertTo-Json&lt;/code&gt; for machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three traps worth knowing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Host width changes &lt;code&gt;Out-File&lt;/code&gt; layout.&lt;/strong&gt; Wide tables wrap differently when the window is narrow. A report that looked fine in an expanded console can become unreadable when a scheduled task runs with a default width. Fix with &lt;code&gt;Out-File -Width 200&lt;/code&gt; (or higher) when you care about columns.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;gt;&lt;/code&gt; is &lt;code&gt;Out-File&lt;/code&gt; with the same defaults.&lt;/strong&gt; In Windows PowerShell 5.1, &lt;code&gt;&amp;gt;&lt;/code&gt; creates UTF-16 files. Redirecting a UTF-8-looking string does not make a UTF-8 file. Prefer the cmdlet form with &lt;code&gt;-Encoding&lt;/code&gt; whenever the file is shared.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;Set-Content&lt;/code&gt; overwrites; it does not append.&lt;/strong&gt; To add lines, use &lt;code&gt;Add-Content&lt;/code&gt; (and still pass &lt;code&gt;-Encoding&lt;/code&gt; so the first write and later appends agree). Mixing &lt;code&gt;Out-File -Encoding utf8&lt;/code&gt; with a later bare &lt;code&gt;Add-Content&lt;/code&gt; is a classic way to glue two encodings into one "corrupted" log.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Pick one default and stick to it
&lt;/h2&gt;

&lt;p&gt;For new scripts on mixed 5.1 / 7 fleets:&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;$utf8&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="kr"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;$PSVersionTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PSVersion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Major&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-ge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&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="s1"&gt;'utf8NoBOM'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'utf8'&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;Set-Content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;\app.log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"started &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="n"&gt;Get-Date&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Format&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;o&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Encoding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$utf8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or standardize on PowerShell 7 for anything that writes text other tools will read. The command names stay the same. The encoding defaults finally stop fighting you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice both without nuking a real config
&lt;/h2&gt;

&lt;p&gt;Encoding bugs are ugly to debug on production shares. In &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master's interactive PowerShell lessons&lt;/a&gt; you can try &lt;code&gt;Out-File&lt;/code&gt;, &lt;code&gt;Set-Content&lt;/code&gt;, and &lt;code&gt;-Encoding&lt;/code&gt; in a live browser terminal with instant feedback — no install, no VM. The same &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;free Windows command line practice site&lt;/a&gt; also covers CMD and Bash when you hop between shells.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your turn:&lt;/strong&gt; have you been bitten by a UTF-16 &lt;code&gt;Out-File&lt;/code&gt; landing in a UTF-8 pipeline? Drop the weirdest encoding mix-up you've hit in the comments.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>scripting</category>
      <category>windows</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I Built Interactive CLI Drills — Learners Quit at Prompt #3</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:45:33 +0000</pubDate>
      <link>https://dev.to/arnostorg/i-built-interactive-cli-drills-learners-quit-at-prompt-3-3dp</link>
      <guid>https://dev.to/arnostorg/i-built-interactive-cli-drills-learners-quit-at-prompt-3-3dp</guid>
      <description>&lt;h1&gt;
  
  
  I Built Interactive CLI Drills — Learners Quit at Prompt #3
&lt;/h1&gt;

&lt;p&gt;I built what I wanted as a learner: interactive CLI drills in the browser. Type commands. Get feedback. No “install fifteen tools first.” Then the analytics (and the hallway conversations) said something rude: &lt;strong&gt;a chunk of learners quit at prompt #3.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a show-and-tell about that product bruise—and what I changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I shipped first
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Short missions for CMD, PowerShell, and Bash-oriented tasks on Windows-friendly paths.&lt;/li&gt;
&lt;li&gt;Immediate correctness checks.&lt;/li&gt;
&lt;li&gt;A clean terminal UI that feels like practice, not a MOOC video.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The thesis: skill is built at the prompt. Screenshots weren’t enough (I had already burned myself on that experiment).&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt #3: the cliff
&lt;/h2&gt;

&lt;p&gt;Patterns in the drop-off:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prompt #1&lt;/strong&gt; was a win (list files, print a string). Dopamine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt #2&lt;/strong&gt; introduced one new concept. Still okay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompt #3&lt;/strong&gt; combined concepts—or required recovery from error—without a scaffold. Confidence cratered.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It wasn’t “students are lazy.” It was &lt;strong&gt;difficulty curve arrogance.&lt;/strong&gt; I had optimized for correctness of the skill model, not for the emotional runway of a first session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Product fixes that mattered
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Smaller concept steps
&lt;/h3&gt;

&lt;p&gt;One idea per prompt until the streak feels earned. Combine later in a “mission boss,” not at step three.&lt;/p&gt;

&lt;h3&gt;
  
  
  Intentional recovery prompts
&lt;/h3&gt;

&lt;p&gt;Instead of only happy paths, add a safe failure that teaches &lt;code&gt;ERRORLEVEL&lt;/code&gt; / &lt;code&gt;$LASTEXITCODE&lt;/code&gt; early—&lt;em&gt;after&lt;/em&gt; a success, not instead of one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shell labeling everywhere
&lt;/h3&gt;

&lt;p&gt;Ambiguity across CMD vs PowerShell was silent quit fuel. Labels and prompts now scream which contract you’re in.&lt;/p&gt;

&lt;h3&gt;
  
  
  Softer first-session definition of done
&lt;/h3&gt;

&lt;p&gt;A complete first session can be six tiny wins. Heroics can be session two.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I’d still defend
&lt;/h2&gt;

&lt;p&gt;Interactive &amp;gt; passive for CLI. The quit data didn’t kill the thesis; it killed my pacing ego.&lt;/p&gt;

&lt;p&gt;Also: soft CTAs beat launch-speak. The product exists to train operators, not to win a landing-page award.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it lives
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Instrumentation that changed my mind
&lt;/h2&gt;

&lt;p&gt;I stopped celebrating completion rate alone. I started watching:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;median time-to-first-success,&lt;/li&gt;
&lt;li&gt;drop-off by prompt index,&lt;/li&gt;
&lt;li&gt;repeat visits within 48 hours,&lt;/li&gt;
&lt;li&gt;qualitative “I felt dumb” comments (painful, gold).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prompt #3 was the cliff on the first curriculum graph. After re-pacing, the cliff moved later—and got shorter. That’s product work, not vibes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What “showdev” means here
&lt;/h2&gt;

&lt;p&gt;Not a launch. A build diary: interactive Windows CLI practice is the medium; curriculum pacing is the hard problem; soft CTA is intentional. If you’re building a trainer, steal the quit-index chart idea before you polish marketing copy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Design smell: “clever” early combines
&lt;/h2&gt;

&lt;p&gt;If prompt #3 needs two new ideas &lt;em&gt;and&lt;/em&gt; perfect quoting &lt;em&gt;and&lt;/em&gt; an error recovery, you didn’t write a drill—you wrote a hazing ritual. Split it. Clever can wait until the streak feels real.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I almost did wrong next
&lt;/h2&gt;

&lt;p&gt;I almost responded to quit data by adding badges and streaks—gamification as a bandage. Maybe later. First fix was honesty about pacing. If the third prompt is a cliff, glitter won’t pave it. Make the third prompt a fair win, then earn the harder combines.&lt;/p&gt;

&lt;p&gt;The drills are free and browser-based: &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt;—interactive terminal learning for CMD, PowerShell, and Bash. If you try it, watch where &lt;em&gt;you&lt;/em&gt; want to bail. That spot is probably my next design ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open build question
&lt;/h2&gt;

&lt;p&gt;For those who’ve built coding or ops trainers: do you gate progress strictly, or let learners skip and return? I’m still torn between “force the reps” and “don’t imprison adults.”&lt;/p&gt;

&lt;p&gt;Show-and-tell, not victory lap: prompt #3 humbled the roadmap.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>learning</category>
      <category>cli</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Aliases vs Functions in Your PowerShell Profile — Pick Deliberately</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Mon, 12 Oct 2026 14:07:36 +0000</pubDate>
      <link>https://dev.to/arnostorg/aliases-vs-functions-in-your-powershell-profile-pick-deliberately-2kc</link>
      <guid>https://dev.to/arnostorg/aliases-vs-functions-in-your-powershell-profile-pick-deliberately-2kc</guid>
      <description>&lt;p&gt;Your PowerShell profile is a sharp tool. It can make every session yours—or make every script you demo mysteriously unreproducible on a clean machine. The alias-vs-function choice is where that fork shows up.&lt;/p&gt;

&lt;p&gt;Ninety days of pruning my profile taught me: &lt;strong&gt;most “clever” aliases should have been functions—or deleted.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What each one is for
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Aliases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Short names for commands: &lt;code&gt;gcb&lt;/code&gt; → &lt;code&gt;Get-Clipboard&lt;/code&gt; (example pattern).&lt;/li&gt;
&lt;li&gt;Fine for &lt;strong&gt;interactive&lt;/strong&gt; sugar.&lt;/li&gt;
&lt;li&gt;Weak at parameterization beyond what the target already offers.&lt;/li&gt;
&lt;li&gt;Easy to shadow real commands if you’re careless.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Functions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Named blocks with parameters, validation, help.&lt;/li&gt;
&lt;li&gt;Can wrap multi-step workflows.&lt;/li&gt;
&lt;li&gt;Can be documented and tested.&lt;/li&gt;
&lt;li&gt;Still profile-scoped if you define them only there—but they’re honest about complexity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Retrospective: what I kept as aliases
&lt;/h2&gt;

&lt;p&gt;Only high-frequency, low-surprise renames that mirror muscle memory across machines I control—and never names that collide with built-ins I might need when teaching.&lt;/p&gt;

&lt;p&gt;If I hesitated about the name, it didn’t deserve alias status.&lt;/p&gt;

&lt;h2&gt;
  
  
  What became functions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Anything with a default path.&lt;/li&gt;
&lt;li&gt;Anything that combined &lt;code&gt;Set-Location&lt;/code&gt; + &lt;code&gt;git status&lt;/code&gt; + branch name.&lt;/li&gt;
&lt;li&gt;Anything that needed &lt;code&gt;-WhatIf&lt;/code&gt; or explicit parameters.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="kr"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Enter-Repo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="kr"&gt;param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Mandatory&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;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="nv"&gt;$Name&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;Set-Location&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="bp"&gt;$HOME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"repos\&lt;/span&gt;&lt;span class="nv"&gt;$Name&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="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;Readable. Greppable. Not &lt;code&gt;er&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The reproducibility rule
&lt;/h2&gt;

&lt;p&gt;If a blog post, teammate, or student needs your session tricks to follow along, your profile has leaked into the lesson. Prefer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Project scripts&lt;/strong&gt; and checked-in helpers for shared workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Profile&lt;/strong&gt; for personal ergonomics only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit calls&lt;/strong&gt; in teaching: type the real cmdlet names.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I demo with a clean profile more often now. Slower fingers, clearer talk track.&lt;/p&gt;

&lt;h2&gt;
  
  
  Corporate angle (foreshadowing a longer debate)
&lt;/h2&gt;

&lt;p&gt;Personal profiles on locked jump boxes can be a blessing or an audit headache. Deliberate choices—small surface, no secrets in profiles, no shadowing &lt;code&gt;curl&lt;/code&gt;/&lt;code&gt;Invoke-WebRequest&lt;/code&gt; confusion—age better than a 400-line fireworks file.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I disabled
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Aliases that shortened already-short cmdlets.&lt;/li&gt;
&lt;li&gt;Prompt logic that called the network.&lt;/li&gt;
&lt;li&gt;Anything that loaded heavy modules synchronously at startup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Startup time is UX. So is predictability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Profile load hygiene checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Time your startup occasionally (&lt;code&gt;Measure-Command { pwsh -NoLogo -Command exit }&lt;/code&gt; vs with profile).&lt;/li&gt;
&lt;li&gt;Keep secrets out; use a secret manager.&lt;/li&gt;
&lt;li&gt;Prefer &lt;code&gt;Remove-Alias&lt;/code&gt; mistakes fixed early over shipping collisions.&lt;/li&gt;
&lt;li&gt;Split “interactive sugar” from “automation libraries”—libraries belong in modules you can import deliberately.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Teaching demo trick
&lt;/h2&gt;

&lt;p&gt;Open two panes: left with your profile, right with &lt;code&gt;-NoProfile&lt;/code&gt;. Run the same demo commands in both when recording. If they diverge, your lesson has a hidden dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple decision tree
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Need a new name only? → Alias (maybe).&lt;/li&gt;
&lt;li&gt;Need parameters, defaults, or multiple steps? → Function.&lt;/li&gt;
&lt;li&gt;Need teammates to run it? → Module or repo script, not your profile.&lt;/li&gt;
&lt;li&gt;Need it in a screenshot lesson? → Use the real cmdlet names.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tape that tree above your &lt;code&gt;Microsoft.PowerShell_profile.ps1&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The “demo debt” metric
&lt;/h2&gt;

&lt;p&gt;Every alias in your teaching profile is a potential demo debt item: something that works for you and fails for them. I keep a sticky note count of demo debt. When it rises above three, I strip the profile and re-record. Painful once; cheaper than confusing a cohort.&lt;/p&gt;

&lt;h2&gt;
  
  
  One alias I deleted and didn’t miss
&lt;/h2&gt;

&lt;p&gt;I had a two-letter alias for &lt;code&gt;Set-Location&lt;/code&gt; to a deep project path. It saved keystrokes and destroyed transfer: every teammate asked why &lt;code&gt;cd&lt;/code&gt; “didn’t work like yours.” Deleting it slowed me for a day and clarified every demo after.&lt;/p&gt;

&lt;p&gt;For learning environments, I want the opposite of mystery meat profiles: explicit prompts and skills you can practice cold. That’s the ethos I design toward in &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep aliases tiny. Put logic in functions—or in repos. Pick deliberately.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>windows</category>
      <category>productivity</category>
      <category>devtools</category>
    </item>
    <item>
      <title>PowerShell Sort-Object: Order Files by Size, Date, or Name in One Pipeline</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Mon, 12 Oct 2026 07:30:04 +0000</pubDate>
      <link>https://dev.to/arnostorg/powershell-sort-object-order-files-by-size-date-or-name-in-one-pipeline-15ob</link>
      <guid>https://dev.to/arnostorg/powershell-sort-object-order-files-by-size-date-or-name-in-one-pipeline-15ob</guid>
      <description>&lt;p&gt;A disk is filling up and you need to know which files are eating it. Or a log folder has 400 files and you want the newest one. Explorer can sort a column, but it can't sort by two things at once, it can't cut the list to the top 10, and it can't hand that list to the next command. &lt;code&gt;Sort-Object&lt;/code&gt; can.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one-liner that answers "what's taking all the space?"
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Descending&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;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-First&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Get-ChildItem -File&lt;/code&gt; sends file &lt;strong&gt;objects&lt;/strong&gt; down the pipeline. &lt;code&gt;-File&lt;/code&gt; skips folders, which matters (see the traps below).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Sort-Object Length&lt;/code&gt; sorts by the &lt;code&gt;Length&lt;/code&gt; property, which is the size in bytes. It compares numbers, not text.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-Descending&lt;/code&gt; puts the biggest first. Without it you get the smallest first, which is rarely what you want at 2 a.m.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Select-Object -First 10&lt;/code&gt; keeps the top ten and shows only the two columns you care about.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Swap &lt;code&gt;Length&lt;/code&gt; for &lt;code&gt;LastWriteTime&lt;/code&gt; or &lt;code&gt;Name&lt;/code&gt; and the same line sorts by date or name. That's the whole idea: pick a property, pick a direction, cut the list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 1: newest files first
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LastWriteTime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Descending&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;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-First&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;LastWriteTime&lt;/code&gt; is a real &lt;code&gt;DateTime&lt;/code&gt;, so you get true chronological order. No guessing whether &lt;code&gt;01/02&lt;/code&gt; means January or February.&lt;/p&gt;

&lt;p&gt;Need just the single newest file to open it?&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;$latest&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-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Logs\&lt;/span&gt;&lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="nf"&gt;log&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LastWriteTime&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;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Last&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="n"&gt;notepad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$latest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FullName&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recipe 2: top 10 largest files on a whole tree, in MB
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;D:\Shares&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Recurse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ErrorAction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SilentlyContinue&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Descending&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;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-First&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FullName&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="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;'MB'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Expression&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;math&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;Round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Length&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;1MB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;1&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;The &lt;code&gt;@{ Name = ...; Expression = ... }&lt;/code&gt; part is a calculated property. It turns raw bytes into something a human can read without changing what you sorted on. &lt;code&gt;-ErrorAction SilentlyContinue&lt;/code&gt; keeps "access denied" folders from flooding the screen.&lt;/p&gt;

&lt;p&gt;On PowerShell 7 you can skip &lt;code&gt;Select-Object -First&lt;/code&gt; and use &lt;code&gt;Sort-Object Length -Top 10&lt;/code&gt;, which is shorter and avoids sorting the entire list in memory just to keep ten rows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recipe 3: sort by two properties at once
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Extension&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Length&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Files are grouped by extension first (&lt;code&gt;.csv&lt;/code&gt;, then &lt;code&gt;.log&lt;/code&gt;, then &lt;code&gt;.zip&lt;/code&gt;), and inside each group they're ordered by size. This is the thing Explorer can't do.&lt;/p&gt;

&lt;p&gt;Want the groups in A to Z order but the biggest file first inside each group? Use hashtables to set the direction per property:&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-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-File&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Expression&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;'Extension'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Descending&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                                  &lt;/span&gt;&lt;span class="p"&gt;@{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Expression&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;'Length'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Descending&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;$true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Recipe 4: keep the newest 5 backups, delete the rest
&lt;/h2&gt;

&lt;p&gt;This is where sorting stops being cosmetic and starts doing ops work:&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-ChildItem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;D:\Backups\&lt;/span&gt;&lt;span class="o"&gt;*.&lt;/span&gt;&lt;span class="nf"&gt;bak&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LastWriteTime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Descending&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;Select-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Skip&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="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Remove-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-WhatIf&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sort newest first, skip the five you want to keep, delete everything else. &lt;code&gt;-WhatIf&lt;/code&gt; prints what &lt;em&gt;would&lt;/em&gt; be removed. Read that list carefully, then run the same line without &lt;code&gt;-WhatIf&lt;/code&gt;. Drop this into a scheduled task and you have backup rotation in four lines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three traps worth knowing
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Numbers stored as text sort like text.&lt;/strong&gt; If you read values from a CSV or a file name, they're strings, and strings sort character by character:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s1"&gt;'9'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'10'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="c"&gt;# 10, 100, 9&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cast inside a script block to sort them as numbers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="s1"&gt;'9'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'10'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&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;Sort-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="c"&gt;# 9, 10, 100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same thing bites with names like &lt;code&gt;log1.txt&lt;/code&gt;, &lt;code&gt;log10.txt&lt;/code&gt;, &lt;code&gt;log2.txt&lt;/code&gt;. Pad numbers with zeros when you create files (&lt;code&gt;log001.txt&lt;/code&gt;) and the problem never shows up.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Name sorting depends on culture.&lt;/strong&gt; &lt;code&gt;Sort-Object&lt;/code&gt; uses your current culture and ignores case by default. On a Czech system, &lt;code&gt;ch&lt;/code&gt; is a separate letter that sorts &lt;em&gt;after&lt;/em&gt; &lt;code&gt;h&lt;/code&gt;, so &lt;code&gt;chyba.txt&lt;/code&gt; lands after &lt;code&gt;hosts.txt&lt;/code&gt;. If a script must produce the same order on every machine, say so explicitly with &lt;code&gt;Sort-Object Name -Culture 'en-US'&lt;/code&gt; or add &lt;code&gt;-CaseSensitive&lt;/code&gt; when case matters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;Name&lt;/code&gt; vs &lt;code&gt;FullName&lt;/code&gt; on recursive listings.&lt;/strong&gt; With &lt;code&gt;-Recurse&lt;/code&gt;, &lt;code&gt;Sort-Object Name&lt;/code&gt; mixes files from every folder into one alphabetical list, so two &lt;code&gt;config.json&lt;/code&gt; files from different projects end up next to each other with no hint of where they live. Sort by &lt;code&gt;FullName&lt;/code&gt; to keep each folder's files together, or by &lt;code&gt;DirectoryName, Name&lt;/code&gt; to make that grouping explicit.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Bonus trap: folders have no &lt;code&gt;Length&lt;/code&gt; property. If you forget &lt;code&gt;-File&lt;/code&gt;, all the folders bunch up at one end of a size sort and look like zero-byte files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the pipeline version beats clicking column headers
&lt;/h2&gt;

&lt;p&gt;Explorer's column sort is fine for a glance. But it can't combine two sort keys, it can't stop at the top 10, it can't recurse a whole share into one list, and it can't pass the result on to &lt;code&gt;Remove-Item&lt;/code&gt;, &lt;code&gt;Copy-Item&lt;/code&gt; or &lt;code&gt;Export-Csv&lt;/code&gt;. &lt;code&gt;Sort-Object&lt;/code&gt; sits in the middle of a pipeline, so the answer to "which files?" becomes the input to "now do something with them". Once that clicks, you stop sorting to look and start sorting to act.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practice it without touching real files
&lt;/h2&gt;

&lt;p&gt;Recipe 4 deletes things, so it's worth getting the pipeline right somewhere safe first. In &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master's interactive PowerShell lessons&lt;/a&gt; you can practice &lt;code&gt;Get-ChildItem&lt;/code&gt;, &lt;code&gt;Sort-Object&lt;/code&gt; and the rest of the pipeline in a live browser terminal with instant feedback, no install and no VM. The same &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;free command line learning platform&lt;/a&gt; also covers Windows CMD and Bash if you switch between systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Your turn:&lt;/strong&gt; what do you sort by most often, size, date, or something weirder? Drop your favorite &lt;code&gt;Sort-Object&lt;/code&gt; line in the comments.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>scripting</category>
      <category>windows</category>
      <category>beginners</category>
    </item>
    <item>
      <title>The UTF-8 / Code Page Surprise That Corrupted My Log Parser</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Sun, 11 Oct 2026 13:30:41 +0000</pubDate>
      <link>https://dev.to/arnostorg/the-utf-8-code-page-surprise-that-corrupted-my-log-parser-1g5d</link>
      <guid>https://dev.to/arnostorg/the-utf-8-code-page-surprise-that-corrupted-my-log-parser-1g5d</guid>
      <description>&lt;h1&gt;
  
  
  The UTF-8 / Code Page Surprise That Corrupted My Log Parser
&lt;/h1&gt;

&lt;p&gt;The parser wasn’t wrong. The bytes were fine. My shell lied about what “text” meant—and I shipped a log tool that mangled non-ASCII lines until a Czech filename in a support zip made the bug undeniable.&lt;/p&gt;

&lt;p&gt;This is a diagnostic post about &lt;strong&gt;Windows code pages, PowerShell encoding defaults, and why “just use UTF-8” is a process, not a slogan.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The failure symptom
&lt;/h2&gt;

&lt;p&gt;A small PowerShell script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ran an external tool that emitted logs.&lt;/li&gt;
&lt;li&gt;Captured output / read a &lt;code&gt;.log&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;Parsed timestamps and paths with regex.&lt;/li&gt;
&lt;li&gt;Wrote a summary CSV.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On my machine: green. On a colleague’s machine: paths with diacritics became &lt;code&gt;??&lt;/code&gt; or mojibake, and the CSV “couldn’t find” files that Explorer showed clearly.&lt;/p&gt;

&lt;p&gt;Classic encoding heisenbug: &lt;strong&gt;locale + shell + redirect + tool&lt;/strong&gt; disagreed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The moving parts (Windows edition)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System ANSI code page&lt;/strong&gt; (legacy) still influences some apps and CMD behaviors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OEM code page&lt;/strong&gt; shows up in consoles historically (&lt;code&gt;chcp&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PowerShell 5.1&lt;/strong&gt; vs &lt;strong&gt;PowerShell 7&lt;/strong&gt; differ in how often UTF-8 saves you by default.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirects and pipelines&lt;/strong&gt; to native executables can re-encode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File reads&lt;/strong&gt; without &lt;code&gt;-Encoding&lt;/code&gt; use defaults you didn’t consciously pick.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only test with ASCII, you never meet these parts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The diagnostic sequence that found it
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Look at raw bytes&lt;/strong&gt;, not the rendered console string. A hex glance (or reading as byte array) showed UTF-8 sequences that the parser later interpreted as something else.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the console code page:&lt;/strong&gt; &lt;code&gt;chcp&lt;/code&gt; in CMD; in PowerShell, inspect &lt;code&gt;[Console]::OutputEncoding&lt;/code&gt; and &lt;code&gt;$OutputEncoding&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check how the file was read/written:&lt;/strong&gt; &lt;code&gt;Get-Content&lt;/code&gt; / &lt;code&gt;Set-Content&lt;/code&gt; / &lt;code&gt;Out-File&lt;/code&gt; encoding parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ask which PowerShell edition&lt;/strong&gt; ran in CI vs laptop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reproduce with a non-ASCII fixture&lt;/strong&gt; checked into the repo (the missing test).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The smoking gun was a 5.1 path writing a file with a default that wasn’t UTF-8, then a later step reading it as UTF-8 (or vice versa). ASCII tests stayed green.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixes that are boring and correct
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pin encoding at every boundary: &lt;code&gt;Get-Content -Encoding utf8&lt;/code&gt;, &lt;code&gt;Export-Csv -Encoding utf8&lt;/code&gt;, etc. (know when &lt;code&gt;utf8BOM&lt;/code&gt; matters for Excel-adjacent humans).&lt;/li&gt;
&lt;li&gt;Prefer PowerShell 7 where allowed for friendlier defaults—but &lt;strong&gt;still pin&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;For CMD-era tools, know &lt;code&gt;chcp 65001&lt;/code&gt; is a blunt instrument with side effects; don’t sprinkle it as superstition.&lt;/li&gt;
&lt;li&gt;Add a CI fixture: &lt;code&gt;Contrôle-Über-škoda.log&lt;/code&gt; or similar. If CI can’t round-trip it, you don’t ship.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Teaching takeaway
&lt;/h2&gt;

&lt;p&gt;Encoding is not an advanced elective. It’s a diagnostic literacy topic that belongs next to PATH and exit codes—especially for Windows learners who live across CMD and PowerShell.&lt;/p&gt;

&lt;h2&gt;
  
  
  Minimal reproduction you can keep in a repo
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create a file with a non-ASCII name and UTF-8 contents.&lt;/li&gt;
&lt;li&gt;Read/write it through your script on PowerShell 5.1 and 7.&lt;/li&gt;
&lt;li&gt;Compare hashes / byte lengths.&lt;/li&gt;
&lt;li&gt;Fail CI if they diverge from the expected encoding.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If that sounds heavy for a “small parser,” remember: the corruption only shows up for the customers you care about most—the ones whose languages don’t fit in seven-bit nostalgia.&lt;/p&gt;

&lt;h2&gt;
  
  
  Console rendering ≠ file encoding
&lt;/h2&gt;

&lt;p&gt;Another trap: the console can display substitutions while the file on disk is fine (or the reverse). Always pin the layer you’re judging—screen, pipeline, or bytes on disk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Empathy note for global teams
&lt;/h2&gt;

&lt;p&gt;If your tooling assumes ASCII filenames, you’re quietly failing colleagues and customers whose names, cities, and documents don’t. Encoding literacy is inclusion work wearing debugging clothes.&lt;/p&gt;

&lt;p&gt;I now treat “non-ASCII path survives the pipeline” as a required drill, not a niche. Interactive lessons in &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt; are a natural place to force that fixture early, before someone corrupts a customer export.&lt;/p&gt;

&lt;p&gt;If your parser only ever saw ASCII, you don’t have a parser. You have a happy path.&lt;/p&gt;

</description>
      <category>powershell</category>
      <category>encoding</category>
      <category>windows</category>
      <category>debugging</category>
    </item>
    <item>
      <title>Why “Learn Linux First” Advice Hurts Windows-First Juniors</title>
      <dc:creator>arnostorg</dc:creator>
      <pubDate>Sat, 10 Oct 2026 13:32:37 +0000</pubDate>
      <link>https://dev.to/arnostorg/why-learn-linux-first-advice-hurts-windows-first-juniors-33lp</link>
      <guid>https://dev.to/arnostorg/why-learn-linux-first-advice-hurts-windows-first-juniors-33lp</guid>
      <description>&lt;h1&gt;
  
  
  Why “Learn Linux First” Advice Hurts Windows-First Juniors
&lt;/h1&gt;

&lt;p&gt;The advice is everywhere: if you want to be a real engineer, learn Linux first. Shell on Ubuntu. Dotfiles. Package managers that feel “clean.” Come back to Windows later, if you must.&lt;/p&gt;

&lt;p&gt;For some careers, that path is fine. For &lt;strong&gt;Windows-first juniors&lt;/strong&gt;—students on school-issued Windows laptops, IT helpdesk tracks, .NET shops, enterprise ops—the advice often delays competence and sneaks in shame.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hidden curriculum in “Linux first”
&lt;/h2&gt;

&lt;p&gt;It implies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows shells are a side quest.&lt;/li&gt;
&lt;li&gt;CMD/PowerShell knowledge is provisional.&lt;/li&gt;
&lt;li&gt;Seriousness is measured by distro fluency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meanwhile their actual homework, internships, and first jobs keep handing them &lt;code&gt;powershell.exe&lt;/code&gt;, Group Policy realities, and vendor &lt;code&gt;.bat&lt;/code&gt; files. They’re told to practice somewhere else.&lt;/p&gt;

&lt;p&gt;That’s not rigor. That’s misaligned reps.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Windows-first learners actually need early
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Paths, permissions, and process basics on the OS they own.&lt;/li&gt;
&lt;li&gt;CMD survival skills for constrained machines.&lt;/li&gt;
&lt;li&gt;PowerShell object pipelines (not Bash cosplay).&lt;/li&gt;
&lt;li&gt;Encoding, Execution Policy, and PATH diagnostics they’ll hit in week two.&lt;/li&gt;
&lt;li&gt;Permission to use Git Bash/WSL as &lt;em&gt;tools&lt;/em&gt;, not as moral upgrades.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can teach excellent operator habits on Windows. Transfer to Linux later is real—and easier when the person already understands exit codes, redirection, and “read the error.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the advice comes from (charitably)
&lt;/h2&gt;

&lt;p&gt;Many mentors lived Linux-heavy careers. Cloud images are Linux. Tooling docs assume Bash. None of that makes “abandon your daily driver” good pedagogy for a junior who only has a Windows laptop and four hours a week.&lt;/p&gt;

&lt;p&gt;Charity doesn’t require copying their biography.&lt;/p&gt;

&lt;h2&gt;
  
  
  A better framing than culture war
&lt;/h2&gt;

&lt;p&gt;Don’t replace “Linux first” with “Windows forever.” Replace it with &lt;strong&gt;platform-honest sequencing&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Gain fluency on the machine you can touch daily.&lt;/li&gt;
&lt;li&gt;Learn concepts that transfer (pipelines, processes, files, networking basics).&lt;/li&gt;
&lt;li&gt;Add Linux deliberately when your goals need it (cloud, containers, specific jobs).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cross-training is strength. Displacement-as-identity is noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I tell students now
&lt;/h2&gt;

&lt;p&gt;If your world is Windows, practice Windows deeply. Use a browser-based or local lab that doesn’t pretend the shell is something else. When a README assumes Bash, translate consciously—or enter the Bash contract on purpose (Git Bash/WSL)—without calling it “real” and yourself “fake.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Transfer that &lt;em&gt;does&lt;/em&gt; work
&lt;/h2&gt;

&lt;p&gt;Once someone can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;read errors calmly,&lt;/li&gt;
&lt;li&gt;check exit codes,&lt;/li&gt;
&lt;li&gt;reason about paths and permissions,&lt;/li&gt;
&lt;li&gt;say which shell contract they’re in,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;…then Linux practice accelerates. The transferable core is operator temperament plus fundamentals—not a specific distro badge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Harm reduction if a mentor still pushes Linux-first
&lt;/h2&gt;

&lt;p&gt;Negotiate a split: keep daily Windows practice; add a weekend Ubuntu VM or WSL track labeled as &lt;em&gt;cross-training&lt;/em&gt;. Dual track beats abandonment. The injury happens when Windows practice stops entirely in the name of purity.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I’m not claiming
&lt;/h2&gt;

&lt;p&gt;I’m not claiming Linux skills are optional forever in cloud-heavy careers. I’m claiming &lt;strong&gt;sequencing and dignity&lt;/strong&gt; matter. Windows-first juniors aren’t broken. Misaligned practice is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Signal vs noise in mentor advice
&lt;/h2&gt;

&lt;p&gt;Mentor advice often encodes the mentor’s job market year. Cloud-heavy 2018 advice isn’t automatically correct for a 2026 Windows helpdesk apprenticeship. Ask: “What OS will this student touch daily for the next ninety days?” Sequence to that. Add Linux as intentional breadth, not as an entrance exam to self-respect.&lt;/p&gt;

&lt;p&gt;That’s the stance behind the Windows-friendly drills I work on in &lt;a href="https://windows-cli.arnost.org/en" rel="noopener noreferrer"&gt;CMD Master&lt;/a&gt;: meet learners where their keyboards already are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discuss:&lt;/strong&gt; Did “learn Linux first” help you, delay you, or both—and what does your first job actually run?&lt;/p&gt;

</description>
      <category>windows</category>
      <category>learning</category>
      <category>career</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
