PowerShell Nihilism as Software Discipline
[ThreadBuilder]::Start() [ThreadBuilder]::Add('Number 1 rule for PowerShell development:') [ThreadBuilder]::Add('- Never write idiomatic PowerShell.') [ThreadBuilder]::Add("If you show me PowerShell that looks like PowerShell, it's never getting near my prod.") [ThreadBuilder]::Add('Underneath its simplicity is a pile of over-engineered abstractions trying really hard to look simple.') [ThreadBuilder]::Add("- That God-Like feeling of writing 'perfect powershell' when you dug into it's internals, flipping $myInvocation reflections and .GetSteppablePipeline() to eek out some more juice? yeah... that's stockholm syndrome.") [ThreadBuilder]::Add("If it looks too clean to be real, it's probably hiding an AST, a COM object, and a scriptblock logging penalty.") [ThreadBuilder]::Add("I want classes, type annotations, sealed behavior, and zero magic.") [ThreadBuilder]::Add("- Don’t use syntactic sugar.") [ThreadBuilder]::Add(" It’s not sweet. It’s sticky.") [ThreadBuilder]::Add(" That one-liner will rot your stack trace and give your future self trust issues.") [ThreadBuilder]::Add("Save the ? { $_.Enabled } for your lunch-break scripts.") [ThreadBuilder]::Add("Take an 'Anti-Aliasing stance' by:") [ThreadBuilder]::Add("- Lean deeply into verbosity.") [ThreadBuilder]::Add("- Prefer $global:ActualVariableName over guessing.") [ThreadBuilder]::Add("But Really: Never use $global: unless you're building a panic button.") [ThreadBuilder]::Add("- Globals are shared hallucinations.") [ThreadBuilder]::Add("- Build modules with private state, or cache inside a getter function.") [ThreadBuilder]::Add("If you're reaching for a singleton in PowerShell — ask yourself who hurt you.") [ThreadBuilder]::Add("- Never use aliases. Where-Object is a statement. ? is a cry for help.") [ThreadBuilder]::Add("- Use -not, not !. Save ! for languages that care about you. enough to make it a first-class citizen.") [ThreadBuilder]::Add("- Avoid short-form anything. If you type less, you know less.") [ThreadBuilder]::Add("Be explicit. Be readable. Be annoying to lazy devs and let the too-clever ones think your dumb. It's okay, their code runs like snails.") [ThreadBuilder]::Add("Never use the pipeline unless you're at the terminal. Ever.") [ThreadBuilder]::Add("- Scripts aren’t a concert — they don’t need to flow.") [ThreadBuilder]::Add("- The pipeline hides performance costs, debug context, and your sins.") [ThreadBuilder]::Add("- Always prefer -InputObject or passing explicitly via variables.") [ThreadBuilder]::Add("- Chaining is for smokers and functional languages. If smalltalk only knew... it would come over and beat you with that pipe.") [ThreadBuilder]::Add("Never use Where-Object unless you're at the terminal.") [ThreadBuilder]::Add("- Don’t hide logic inside { $_ } sugar cubes.") [ThreadBuilder]::Add("- Build meaningful booleans. Give your conditions names.") [ThreadBuilder]::Add("- $isValid = $Value -is [ValueType] -or $Value -is [string]") [ThreadBuilder]::Add("- if ($isValid) { ... }") [ThreadBuilder]::Add("Readable. Testable. Traceable.") [ThreadBuilder]::Add("Don’t write code you can’t explain without squinting.") [ThreadBuilder]::Add("Never write cmdlets unless you're newing a class you wrote.") [ThreadBuilder]::Add("- Cmdlets are overkill unless you’re exposing behavior from your own system.") [ThreadBuilder]::Add("- If there’s no [MyModule.MyType] behind it, it’s just a function in a trench coat trying to sell you a stolen watch.") [ThreadBuilder]::Add("Treat functions like APIs. Cmdlets are just UI for your types.") [ThreadBuilder]::Add("- Always write functions with explicit returns.") [ThreadBuilder]::Add("PowerShell returns anything it touches — even when you didn’t ask.") [ThreadBuilder]::Add("→ Use return every time. Be intentional.") [ThreadBuilder]::Add("→ Use $null = or [void]() to shut up side effects you don’t want.") [ThreadBuilder]::Add("Never let PowerShell decide what your function says. It’ll be wrong.") [ThreadBuilder]::Add("Method calls return values — even when you don’t care.") [ThreadBuilder]::Add("→ If you're not using it, silence it. Don't let it leak into your output stream.") [ThreadBuilder]::Add("PowerShell accepts fake enum values. Don’t trust the binding — enforce it yourself.") [ThreadBuilder]::Add("enum State { Start; Stop }") [ThreadBuilder]::Add("function Run { param([State]$Mode) $Mode }") [ThreadBuilder]::Add("Run 'Destroy' # → returns $null, no error") [ThreadBuilder]::Add("→ PowerShell fails silently on bad enum input.") [ThreadBuilder]::Add("→ If you don't check, your logic runs on $null like it meant to.") [ThreadBuilder]::Add("Fix it with [ValidateSet()]:") [ThreadBuilder]::Add("function Run {") [ThreadBuilder]::Add(" param([ValidateSet('Start','Stop')][string]$Mode)") [ThreadBuilder]::Add(" $Mode") [ThreadBuilder]::Add("Run 'Destroy' # → throws, as it should") [ThreadBuilder]::Add("Never use a PowerShell construct to solve a PowerShell problem inside of PowerShell.") [

[ThreadBuilder]::Start()
[ThreadBuilder]::Add('Number 1 rule for PowerShell development:')
[ThreadBuilder]::Add('- Never write idiomatic PowerShell.')
[ThreadBuilder]::Add("If you show me PowerShell that looks like PowerShell, it's never getting near my prod.")
[ThreadBuilder]::Add('Underneath its simplicity is a pile of over-engineered abstractions trying really hard to look simple.')
[ThreadBuilder]::Add("- That God-Like feeling of writing 'perfect powershell' when you dug into it's internals, flipping $myInvocation reflections and .GetSteppablePipeline() to eek out some more juice? yeah... that's stockholm syndrome.")
[ThreadBuilder]::Add("If it looks too clean to be real, it's probably hiding an AST, a COM object, and a scriptblock logging penalty.")
[ThreadBuilder]::Add("I want classes, type annotations, sealed behavior, and zero magic.")
[ThreadBuilder]::Add("- Don’t use syntactic sugar.")
[ThreadBuilder]::Add(" It’s not sweet. It’s sticky.")
[ThreadBuilder]::Add(" That one-liner will rot your stack trace and give your future self trust issues.")
[ThreadBuilder]::Add("Save the ? { $_.Enabled }
for your lunch-break scripts.")
[ThreadBuilder]::Add("Take an 'Anti-Aliasing stance' by:")
[ThreadBuilder]::Add("- Lean deeply into verbosity.")
[ThreadBuilder]::Add("- Prefer $global:ActualVariableName
over guessing.")
[ThreadBuilder]::Add("But Really: Never use $global:
unless you're building a panic button.")
[ThreadBuilder]::Add("- Globals are shared hallucinations.")
[ThreadBuilder]::Add("- Build modules with private state, or cache inside a getter function.")
[ThreadBuilder]::Add("If you're reaching for a singleton in PowerShell — ask yourself who hurt you.")
[ThreadBuilder]::Add("- Never use aliases. Where-Object
is a statement. ?
is a cry for help.")
[ThreadBuilder]::Add("- Use -not
, not !
. Save !
for languages that care about you. enough to make it a first-class citizen.")
[ThreadBuilder]::Add("- Avoid short-form anything. If you type less, you know less.")
[ThreadBuilder]::Add("Be explicit. Be readable. Be annoying to lazy devs and let the too-clever ones think your dumb. It's okay, their code runs like snails.")
[ThreadBuilder]::Add("Never use the pipeline unless you're at the terminal. Ever.")
[ThreadBuilder]::Add("- Scripts aren’t a concert — they don’t need to flow.")
[ThreadBuilder]::Add("- The pipeline hides performance costs, debug context, and your sins.")
[ThreadBuilder]::Add("- Always prefer -InputObject
or passing explicitly via variables.")
[ThreadBuilder]::Add("- Chaining is for smokers and functional languages. If smalltalk only knew... it would come over and beat you with that pipe.")
[ThreadBuilder]::Add("Never use Where-Object
unless you're at the terminal.")
[ThreadBuilder]::Add("- Don’t hide logic inside { $_ }
sugar cubes.")
[ThreadBuilder]::Add("- Build meaningful booleans. Give your conditions names.")
[ThreadBuilder]::Add("- $isValid = $Value -is [ValueType] -or $Value -is [string]
")
[ThreadBuilder]::Add("- if ($isValid) { ... }
")
[ThreadBuilder]::Add("Readable. Testable. Traceable.")
[ThreadBuilder]::Add("Don’t write code you can’t explain without squinting.")
[ThreadBuilder]::Add("Never write cmdlets unless you're newing a class you wrote.")
[ThreadBuilder]::Add("- Cmdlets are overkill unless you’re exposing behavior from your own system.")
[ThreadBuilder]::Add("- If there’s no [MyModule.MyType]
behind it, it’s just a function in a trench coat trying to sell you a stolen watch.")
[ThreadBuilder]::Add("Treat functions like APIs. Cmdlets are just UI for your types.")
[ThreadBuilder]::Add("- Always write functions with explicit returns.")
[ThreadBuilder]::Add("PowerShell returns anything it touches — even when you didn’t ask.")
[ThreadBuilder]::Add("→ Use return
every time. Be intentional.")
[ThreadBuilder]::Add("→ Use $null =
or [void]()
to shut up side effects you don’t want.")
[ThreadBuilder]::Add("Never let PowerShell decide what your function says. It’ll be wrong.")
[ThreadBuilder]::Add("Method calls return values — even when you don’t care.")
[ThreadBuilder]::Add("→ If you're not using it, silence it. Don't let it leak into your output stream.")
[ThreadBuilder]::Add("PowerShell accepts fake enum values. Don’t trust the binding — enforce it yourself.")
[ThreadBuilder]::Add("enum State { Start; Stop }")
[ThreadBuilder]::Add("function Run { param([State]$Mode) $Mode }")
[ThreadBuilder]::Add("Run 'Destroy' # → returns $null, no error")
[ThreadBuilder]::Add("→ PowerShell fails silently on bad enum input.")
[ThreadBuilder]::Add("→ If you don't check, your logic runs on $null
like it meant to.")
[ThreadBuilder]::Add("Fix it with [ValidateSet()]
:")
[ThreadBuilder]::Add("function Run {")
[ThreadBuilder]::Add(" param([ValidateSet('Start','Stop')][string]$Mode)")
[ThreadBuilder]::Add(" $Mode")
[ThreadBuilder]::Add("Run 'Destroy' # → throws, as it should")
[ThreadBuilder]::Add("Never use a PowerShell construct to solve a PowerShell problem inside of PowerShell.")
[ThreadBuilder]::Add("- Reach for PowerShell only when you’re outside of it.")
[ThreadBuilder]::Add("- Inside PowerShell, defer to .NET.")
[ThreadBuilder]::Add("- New the object. Call the method. Don’t rely on the engine’s interpretation of your intent.")
[ThreadBuilder]::Add("- PowerShell will try to help. Don’t let it.")
[ThreadBuilder]::Add("- PowerShell is not a language. It's not a runtime, it's not a platform. It is only an execution substrate.")
[ThreadBuilder]::Add("Never use a PowerShell primitive type if there's any other alternative that can be new'd from .NET.")
[ThreadBuilder]::Add("- [int] is cute until it’s secretly [System.Int32]
with extra baggage.")
[ThreadBuilder]::Add("- [string] is a trap. Coerce it to [System.String]
if you care about methods behaving.")
[ThreadBuilder]::Add("- Avoid [hashtable]
, [array]
, [psobject]
, [scriptblock]
, and anything else that lives in PowerShell’s imagination.")
[ThreadBuilder]::Add("- If you must touch a PowerShell type, immediately .ToString()
, .ToArray()
, or .Cast<>()
it into something real.")
[ThreadBuilder]::Add("Avoid [type](value)
casting unless you're okay with PowerShell lying to you.")
[ThreadBuilder]::Add("- It looks like a .NET cast.")
[ThreadBuilder]::Add("- It feels like a .NET cast.")
[ThreadBuilder]::Add("- It is not a .NET cast.")
[ThreadBuilder]::Add("- Under the hood, it's LanguagePrimitives::ConvertTo()
.")
[ThreadBuilder]::Add("- That means PowerShell will 'help' you. You don't want help.")
[ThreadBuilder]::Add("- You want control, predictability, and exceptions when things go wrong.")
[ThreadBuilder]::Add("- Use [int]::Parse()
, [datetime]::TryParse()
, or .Cast
if you actually care.")
[ThreadBuilder]::Add("- Stop writing code that 'works'. Write code that fails when it should.")
[ThreadBuilder]::Add("PowerShell casting is a vibe, not a contract.")
[ThreadBuilder]::Add("Even then, Strong typing doesn’t mean safe input — validate explicitly.")
[ThreadBuilder]::Add("There is no faster or safer way to iterate: use foreach
.")
[ThreadBuilder]::Add("- foreach ($file in Get-ChildItem -Recurse) {}
is the correct form.")
[ThreadBuilder]::Add("- $result = foreach ($x in $collection) {}
for collecting output — stable and explicit.")
[ThreadBuilder]::Add("- foreach ($item in $collection.GetEnumerator()) {}
when you want full control.")
[ThreadBuilder]::Add("- Don’t preload. Don’t pipe. Don’t decorate.")
[ThreadBuilder]::Add("- These forms are the truth. Everything else is the engine trying to be clever.")
[ThreadBuilder]::Add("Enums and classes — there isn't time in the world.")
[ThreadBuilder]::Add("If you want them to be more than Snover’s shower-thought, write them somewhere else.")
[ThreadBuilder]::Add("PowerShell lets you define types. It doesn’t know what they’re for.")
[ThreadBuilder]::Add("You're not writing models — you're building containers for structured suffering.")
[ThreadBuilder]::Add("Use a duplicate object in your getters. No, PowerShell, you can’t hold my baby.")
[ThreadBuilder]::Add("Classes and Enums... They look like types. They act like variables. They debug like demons.")
[ThreadBuilder]::Add("Then they streak across prod with their privates exposed, and you get blamed for public indecency.")
[ThreadBuilder]::Add("If you still need a singleton in PowerShell: here’s the cliff notes.")
[ThreadBuilder]::Add("- Don’t use $global:
— that’s not a singleton, that’s a liability.")
[ThreadBuilder]::Add("- Use a module-scoped variable ($script:
) inside a .psm1
file.")
[ThreadBuilder]::Add("- Expose a Get-Instance
function that initializes once and returns always.")
[ThreadBuilder]::Add("- Encapsulate access — never let the outside world touch it directly.")
[ThreadBuilder]::Add("- If you must reset it, make that a deliberate exported function.")
[ThreadBuilder]::Add("You’re not writing Go. You’re duct-taping state to a fantasy. Be careful.")
[ThreadBuilder]::Add("Dot-sourcing is an act of war — either against PowerShell’s module system, or against yourself. Choose carefully.")
[ThreadBuilder]::Add("- It leaks scope.")
[ThreadBuilder]::Add("- It overrides variables you didn’t mean to share.")
[ThreadBuilder]::Add("- It pretends your script is part of the caller’s logic.")
[ThreadBuilder]::Add("Encapsulate everything. PowerShell doesn’t know how to contain your code — you have to.")
[ThreadBuilder]::Add("As my first language, and after over a decade in it:")
[ThreadBuilder]::Add("- Stop trying to adhere to the language spec.")
[ThreadBuilder]::Add("- The spec doesn’t protect you.")
[ThreadBuilder]::Add("- The spec won’t save you.")
[ThreadBuilder]::Add("- The spec was designed for fast answers — not for codebases with consequences.")
[ThreadBuilder]::Add("It’s easier to learn to code than it is to learn PowerShell.")
[ThreadBuilder]::Add("- When you learn PowerShell, you still have to learn to code.")
[ThreadBuilder]::Add("- So you’ve just spent twice as much time and struggle... for no reason.")
[ThreadBuilder]::Add("- And all you got was conformity to a spec written for scripting around .NET, not building with it.")
[ThreadBuilder]::Add("- Learn to code. Then use PowerShell as a tool, not a teacher.")
[ThreadBuilder]::Add("- Write code — not PowerShell ...when writing PowerShell.")
[ThreadBuilder]::Add("Writing code in PowerShell takes less time than writing PowerShell code.")
[ThreadBuilder]::Add("- The language wants you to write scripts.")
[ThreadBuilder]::Add("- You should be writing software. Yes. Your ten lines of code to set up a scheduled task is "Software". Make it fast and make it last.)
[ThreadBuilder]::Add("- Lean on .NET. Use real logic. Skip the sugar.")
[ThreadBuilder]::Add("- PowerShell can be elegant, but clean code is faster, more readable, and more maintainable than clever hacks.")
[ThreadBuilder]::Add("- Researching first-principles and applying them is faster than researching:")
[ThreadBuilder]::Add(" - ... your objective,")
[ThreadBuilder]::Add(" - ... the PowerShell abstraction that almost solves it,")
[ThreadBuilder]::Add(" - ... why that abstraction quietly fails,")
[ThreadBuilder]::Add(" - ... how to bypass PowerShell's resistance to correction,")
[ThreadBuilder]::Add("...to just to end up applying first-principles anyway.")
[ThreadBuilder]::Add("Follow this and your code will be between 2x–500x faster (no joke), dramatically more maintainable, and infinitely less embarrassing to debug in front of other adults.")
[ThreadBuilder]::Add("This isn’t about writing better PowerShell — it’s about writing real code using PowerShell as a tool, not as a crutch.
[ThreadBuilder]::Add("You don’t need the language’s permission to write something that lasts.")
[ThreadBuilder]::Add("You don’t need the language’s permission to learn to code.")
[ThreadBuilder]::Add("Do I love it? Yeah.")
[ThreadBuilder]::Add("Did it teach me more bad tricks than a magician with a drinking problem?")
[ThreadBuilder]::Add("Did it teach me everything I know? Yeah.")
[ThreadBuilder]::Add("Can I write in any language now because of it? Also yeah.")
[ThreadBuilder]::Finalize("It made me a polyglot. And for that... I owe PowerShell everything.")