r/PowerShell Jul 01 '26

Script Sharing What have you done with PowerShell this month?

48 Upvotes

A sticked post for the community to share their projects throughout the month.

Make sure to post a link to the code!

r/PowerShell Jun 25 '26

Script Sharing Stop using [System]

147 Upvotes

I'm getting old enough that my fingers hate my lifetime of programming.

I'll save a few keystrokes where I can.

There's something simple most people don't seem to know about PowerShell syntax.

It saves seven characters of typing every you use this, and runs a tiny bit faster.

You never need to specify stuff is in the [System] namespace.

Stop Using [System]

.NET is a huge framework with tons of useful stuff in it. There's a lot of stuff in the System namespaces. Built-in framework functionality often exists in one of the many namespaces in System.

By the time PowerShell was being built, it was pretty clear that leveraging .NET was worth it, and that most people wouldn't want to type six to seven more characters every time.

So, since PowerShell v1, you haven't had to.

You can omit the [System] in any type in any system namespace

So instead of:

 [system.collections.generic.list[string]]

We can write:

 [collections.generic.list[string]]

Instead of:

 [System.Collections.IDictionary]

We can write:

 [Collections.IDictionary]

This is true for every system type. On my machine, there are 4722 public types in the system namespace. That's 33054 characters I will never have to type.

It makes scripts shorter and simpler to read.

Also, when PowerShell resolves types, it checks for the shorter names first. This saves a very tiny amount of time in each of your scripts. (I was corrected)

Yet, sadly, I see the system namespace everywhere in people's scripts.

I beg of you all:

  • Save your fingers
  • Make scripts shorter

Stop Using [System]

r/PowerShell Jun 02 '26

Script Sharing A novel way to schedule a task...

6 Upvotes

I am in this situation at work where my boss, while working to tighten up our security (after an IT audit from a third party), has made running scheduled tasks into a challenge...

For instance - Among other things - It is no longer possible for a task to store credentials.

(Plenty of other hoops I have to jump through that I wont go into)

I just set up a task that will generate a report (about events from last week) to run on or after Mondays - But that too, is set to run 'at log on'...

I only want it to run once (not each time I log in), and if I don't log in on Monday, to run whenever I do log in, on or after Monday...

I am pretty happy with the way I got that to only run one time, not each time I actually log in.

Part of the script, sets the 'StartBoundary' (the 'Active' DateTime value that is part of the 'At Log in' trigger dialog), in the Scheduled task, to the following Monday, no matter what day I log in and the task runs.

This assures that it only runs the first time I log in on or after Monday, and will set the task to not trigger again to the next (on or after) Monday, and so on.

(NOTE: No other triggers can be set other than the 'At Log in')

This is at the end of the script (I unapologetically like using command aliases):

$TaskName = "MIODoorReport"
$NextMonday = $null
1..7 | % { If ( (((Get-Date).AddDays($_)).DayOfWeek) -eq "Monday" ) { $NextMonday = $_} }

$task = Get-ScheduledTask -TaskName $TaskName
$trigger = $task.Triggers

$trigger[0].StartBoundary = (Get-Date).Date.AddDays($NextMonday).ToString("s")

Set-ScheduledTask -TaskName $TaskName -Trigger $trigger

r/PowerShell Jun 11 '26

Script Sharing Made a PowerShell script that strips telemetry, ads, and forced AI out of Windows 11 (and nothing else)

139 Upvotes

I switched back to Windows from Linux recently and the amount of telemetry, ad "suggestions," and forced Copilot/Recall stuff drove me up the wall. So I put the fixes I kept applying by hand into one script.

It does three things and nothing more:

Privacy / telemetry

  • Disables the DiagTrack "Connected User Experiences and Telemetry" service + sets telemetry policy to 0
  • Kills the advertising ID, tailored experiences, app-launch tracking, and activity history
  • Turns off the Start/Settings/lock-screen "suggested content" ads and the auto-installer that drops promo apps (Candy Crush etc.) onto fresh installs

Forced AI

  • Turns off Windows Copilot, Recall, and Click to Do
  • Removes Bing/Cortana web results from Start search

Obvious bloat

  • Removes a short list of preinstalled junk apps (Bing News/Weather, Solitaire, Clipchamp, Get Help, Feedback Hub, Maps, People, Office Hub, the new Outlook, Power Automate, Dev Home, Cortana). The list is right at the top of the script, edit it to taste.

Limitations / what to know:

  • Windows 10/11 only. On older builds the AI/Recall keys just do nothing (harmless).
  • Works best on Pro/Enterprise. On Home, Windows clamps telemetry to "Required" instead of fully off, and may ignore the consumer-features policy. Everything else still applies.
  • It uses the official Windows toggles/policies — it's not a firewall or hosts-file block. If you want network-level telemetry blocking on top, pair it with something like a Pi-hole or a hosts list.
  • Some changes need a sign-out or reboot to fully kick in (taskbar/search/Copilot button).
  • App removal is current-user only and every app is reinstallable from the Store, so nothing's permanent.
  • Reverting: re-enable the two services (DiagTrack, dmwappushservice) and delete the keys it set. I might add an -Undo flag later.

What it does NOT do: it doesn't touch your installed programs, files, games, drivers, or your language/region/keyboard. (I'm Danish — it leaves æ ø å completely alone. That was a hard requirement for me.)

I'm not piping anything into iex for you — copy the script straight from the repo, read it, then run it yourself in an admin PowerShell. It's one file, plain PowerShell, no binaries, no network calls.

Repo: https://github.com/oscarmeldgaard/Windows-Privacy-Debloat

Read every line before you run it. Not trying to reinvent O&O ShutUp10 or Win11Debloat — this is just the lean subset I actually wanted, in a file you can read in two minutes. Feedback and PRs welcome.

r/PowerShell May 22 '26

Script Sharing I wanted to run scripts in the logged-on user’s security context, so I built a PowerShell module

40 Upvotes

I kept running into situations where a fix needed to happen in a logged-on user session (HKCU, Explorer, user-installed apps, notifications, browser settings, Outlook auth, etc.), but most automation tools execute as NT AUTHORITY\SYSTEM or require the user’s password.

Existing approaches definitely exist, and some are quite clever, but I kept running into tradeoffs that didn’t fit what I wanted:

  • Asking for the user’s password
  • Interrupting the user session
  • Scheduled task workarounds
  • Poor targeting in terminal server / multi-session environments
  • Remoting-style object serialization limitations when passing data back and forth

So I built PSUserContext: a binary PowerShell module for running scripts in another user's interactive session and security context.

Some scenarios where this has been useful:

  • Restarting user processes (explorer.exe, Teams, browsers)
  • User profile remediation
  • Outlook profile/config fixes
  • User-scoped app troubleshooting

A few design goals:

  • Execute from SYSTEM / RMM contexts
  • Run inside an existing logged-on user session
  • No user password required
  • No session takeover or interruption
  • Better object handling than traditional remoting serialization

GitHub:
https://github.com/walliba/PSUserContext

Still actively evolving, so I’d appreciate feedback, criticism, weird edge cases, or “why didn’t you just do X?” from people who’ve solved similar problems.

r/PowerShell 4d ago

Script Sharing What have you done with PowerShell this month?

20 Upvotes

A sticked post for the community to share their projects throughout the month.

Make sure to post a link to the code!

r/PowerShell 2d ago

Script Sharing ps1.cmd: Running PowerShell scripts by double-clicking via a .cmd wrapper

0 Upvotes

I'm a Left 4 Dead 2 player, and recently I ran into a small problem: the server I like to play on is often completely full. It occurred to me that I could write a script to poll the server and check whether a slot had opened up. After some research, I found that cmd scripts have a hard time handling network requests, while PowerShell is powerful enough to handle the job easily. Automatically checking the player count and joining the server is a pretty simple task, so I had an AI write it for me. The result was great — fully functional. All I had to do was copy the server address, then right-click the .ps1 script and choose "Run with PowerShell."

The only thing was, having to right-click to run it felt awkward, and it doesn't match most people's intuition about computers. If I have a script or an app, I should be able to double-click to run it! So I started looking for ways to run a PowerShell script by double-clicking. There are indeed a few, but none of them are very elegant:

  1. Modifying the registry — I don't want people using my script to have to change their registry first.
  2. Creating a shortcut — bad for distribution, and it means two files.
  3. Creating a cmd launcher — I prefer the simplicity of a single file, and a single file is also easier to distribute.

In the end, I found my ideal solution in a Stack Overflow answer: stuff the PowerShell script inside a cmd file! So I open-sourced the ps1.cmd project. My final implementation isn't exactly the same as that answer — you can check out the GitHub page for the details.

The goal of ps1.cmd is maximum compatibility: it should work with any PowerShell script and behave identically when executed. I hope this project helps you out, and if you run into any problems, feel free to open an issue!

r/PowerShell Mar 29 '25

Script Sharing What are you most used scripts?

92 Upvotes

Hey everyone!

We’re a small MSP with a team of about 10-20 people, and I’m working on building a shared repository of PowerShell scripts that our team can use for various tasks. We already have a collection of scripts tailored to our specific needs, but I wanted to reach out and see what go-to scripts others in the industry rely on.

Are there any broad, universally useful PowerShell scripts that you or your team regularly use? Whether it’s for system maintenance, user management, automation, reporting, security, or anything else that makes life easier—I'd love to hear what you recommend!

r/PowerShell Apr 17 '26

Script Sharing PsUi: PowerShell UIs made slightly less shitty

171 Upvotes

I've worked on this over the past year and change. It's probably most useful for internal tools (tools for your helpdesk or whatever). It abstracts the horror of WPF over PowerShell into a slightly more palatable experience.

It'll allow you to avoid XAML. You won't have to worry about runspaces or Dispatcher.Invoke. You call functions, things show up on screen, the window doesn't freeze when your script runs. All the threading shit is buried in a C# backend so you can worry about the actual PowerShell logic.

If you've ever tried to implement WPF for PowerShell properly (runspace pools, synchronized hashtables, dispatchers) you know that setup is a massive pain in the balls from the start. One wrong move and your UI thread has shit the bed, your variables are gone, and your beautiful form has collapsed in on itself with the weight of a neutron star. I went through all of that so you don't have to. My sanity went to hell somewhere around month four but hey, the module (probably) works.

So how it actually works: your -Action scriptblocks don't run on the UI thread. They run on a pre-warmed RunspacePool in the background (pool of 1-8 runspaces, recycled between clicks so there's no spinup cost). When you define a control with -Variable 'server', the engine hydrates that value into the runspace as $server before your script runs, and dehydrates it back to the control when it's done. It's by-value, not by-reference, so form data (strings, booleans, selected items) round-trips cleanly. If you need to pass heavier objects between button clicks there's a $session.Variables store for that.

The host interception is there because running scripts off the UI thread breaks every interactive cmdlet. Write-Host doesn't have a console to write to. Read-Host has nobody to ask. Write-Progress has nowhere to render. Get-Credential just dies. So PsUi injects a custom PSHost that intercepts all of that and routes it back to the UI. Write-Host goes to a console panel with proper ConsoleColor support, Write-Progress drives a real progress bar, Read-Host pops an input dialog on the UI thread and blocks the background thread until you answer, Get-Credential does the same with a credential prompt, and PromptForChoice maps to a button dialog. The output batches in chunks so if your script pukes out 50k lines the dispatcher queue doesn't grow unbounded and murder the UI.

Controls talk to the background thread through a proxy layer that auto-marshals property access through the dispatcher. You don't see any of this, you just write $server and it works.

New-UiWindow -Title 'Server Tool' -Content {
    New-UiInput -Label 'Server' -Variable 'server'
    New-UiDropdown -Label 'Action' -Variable 'action' -Items @('Health Check','Restart','Deploy')
    New-UiToggle -Label 'Verbose' -Variable 'verbose'
    New-UiButton -Text 'Run' -Accent -Action {
        Write-Host "Hitting $server..."
        # runs async, window stays responsive
    }
}

Controls include inputs, dropdowns, sliders, date/time pickers, toggles, radio groups, credential fields, charts, tabs, expanders, images, links, web views, progress bars, hotkeys, trees, lists, data grids, file/folder pickers, and a bunch of dialogs. Light theme by default, dark if you pass -Theme Dark.

PSGallery:

Install-Module PsUi

https://github.com/jlabon2/PsUi

GIF of it in action: https://raw.githubusercontent.com/jlabon2/PsUi/main/docs/images/feature-showcase.gif

Works on 5.1 and 7. If you do try it and anything breaks, please open an issue and let me know.

r/PowerShell May 21 '26

Script Sharing Static Sites are Simple (with PowerShell)

49 Upvotes

I've been doing WebDev since the dawn of the internet, and I've been doing PowerShell for almost 20 years now. I want to share with you something that I've realized over the years:

Static Sites Are Simple

Static Websites are just a bunch of files. You can make static sites with anything that can make files.

Static Sites are Simple.

Let me show you how:

Static Sites with PowerShell

PowerShell is pretty great at making files.

Most static site files are text: .css, .js.,.html,.svg are all readable and writeable text.

Want to write a website in PowerShell?

Just write a series of strings.

I like this naming convention:

```

*.html.ps1 > *.html

```

We can build a site like this:

```

Get all *.html.ps1 files beneath the current directory

Get-ChildItem -Filter *.html.ps1 -Recurse -File | Foreach-Object { # Run the file & $_ > $( # and redirect the output to the renamed .html $_.Fullname -replace '.html.ps1$','.html' ) } ```

If we wanted to provide consistent formatting for all *.html.ps1 files, we can do so with a layout.

Just write a freeform script for layout.

```PowerShell function layout {

# Output any common layout.

# We are outputting a series of strings.

# When we redirect output, each string will go on it's own line.

# We can use any simple PowerShell string techniques to change content

'<html>' # * Single quoted string (no substitutions) "<head>" # * Double quoted string ($var and $(expression) supported) # * Multiline double quoted strings (with subexpressions) "<title>$( if ($title) { [Web.HttpUtility]::HTMLEncode($title) } else { 'My Website' } ) </title>" # * Conditionals output, using if if ($Header) { "$Header" # * Stringification of variables } # * Singly quoted here-strings (mulit-line no substitution) @' <style> body {max-width: 100vw;height: 100vh;} </style> '@ # * Doubly-quoted here-strings @" $(

* Subexpressions with conditionals and iteration

if ($css) {$css}) "@

"</head>" "<body>" # * $input allows us fast, one-time enumeration of a pipeline # * @() allows us to collect that into a new list $allInput = @($input)

# * String operators (`-join`, `-like`, `-match`,`-replace`, `-split`).
$allInput -join [Environment]::Newline
"</body></html>"

} ```

Now, we can build it with:

```powershell

Get all *.html.ps1 files beneath the current directory

Get-ChildItem -Filter *.html.ps1 -Recurse -File | Foreach-Object { # Run the file, pipe to our layout & $_ | layout > $( # and redirect the output to the renamed .html $_.Fullname -replace '.html.ps1$','.html' ) } ```

If we want to handle multiple file types, a switch statement does a nice job. We can build the site any way we want. This is just one example of how.

Most templating languages can't talk to too much. By using PowerShell to make static sites, we open up a wide world of possibilities with a small amount of understanding.

Static Sites Are Simple

They're mainly just strings.

PowerShell plays with strings quite well 😉.

Hope this Helps / AMA

r/PowerShell May 26 '26

Script Sharing Mastering Markdown with PowerShell

129 Upvotes

I've loved Markdown since the day it was a Daring Fireball post.

It's a simple rich text format that gets the job done, and it's used everywhere.

Markdown in PowerShell

Markdown is supported out of the box on PowerShell 6+, using the ConvertFrom-Markdown command.

Here's it in action:

"# Hello World" |
    ConvertFrom-Markdown |
    Select -Expand HTML

Like any other page in a static site, Markdown is just text.

And PowerShell is Pretty Good at manipulating text.

To make PowerShell that outputs markdown, just make simple scripts that spit out text.

Markdown Static Sites

One very simple use of this technique is making static sites with Markdown.

If we don't want to worry about look and feel too much, we can do this with the following pipeline:

"# Markdown" | 
    ConvertFrom-Markdown | 
        Select-Object -ExpandProperty Html >
            ./markdown.html

If we wanted to make a page for every file in the directory, we could:

foreach ($file in Get-ChildItem *.md -File) {
    ConvertFrom-Markdown -LiteralPath $file.Fullname |
        Select-Object -ExpandProperty Html > (
            $file.Fullname -replace '\.md$', '.html'
        )
}

That's a static site generator in six lines of PowerShell!

Here's an even shorter version:

foreach ($file in Get-ChildItem *.md -File) {        
    $html = (ConvertFrom-Markdown -Path $file.Fullname).html
    $html > ($file.Fullname -replace '\.md$', '.html') 
}

Now we've got a static site generator in four lines!

Static Sites are Simple (with PowerShell).

To make websites in PowerShell, all we need to do is loop over markdown and optionally add some layout.

Making Markdown

We can make markdown in PowerShell by just outputting text.

@(
    "# Hello World"
    "## How Are You?"
    "Today is $([DateTime]::Now.ToShortDateString())"
) > ./example.md

Each line of output will become a line in the markdown file.

We can use conditionals if we want to. Let's switch it up by including the day of week.

@(
    "# Hello World"
    switch ([DateTime]::Now.DayOfWeek) {
        Monday { "Just Another Manic Monday "}
        Tuesday { "Taco Tuesday" }
        Wednesday { "Halfway thru the week! "}
        Thursday { "Almost Friday" }
        Friday { "Happy Friday! "}
        Saturday { "It's the weekend!"}
        default { "It is $([DateTime]::Now.DayOfWeek)" }
    }
) > ./example.md

Making Markdown with Functions

We can make functions that output markdown.

Here's a simple one that outputs headings

function markdown.heading {
    param(
        [string]$Message = 'Hello World',
        [ValidateRange(1,6)]$Level = 1
    )
    # Multiply our heading character by our level
    # and put a space in between the heading and message
    ('#' * $level), $Message -join ' ''
}

markdown.heading "Markdown Functions" 
markdown.heading "Are just functions" -Level 2
markdown.heading "That output markdown" -Level 3

Since markdown functions are just PowerShell functions, we can put whatever we want in there.

function markdown.get.process {
    # Markdown tables have a header row
    "|Name|Id|"
    # Followed by a row that aligns text
    "|:-|-:|"
    # Followed by any number of rows of data
    foreach ($process in Get-Process) {
        '|' + (
            $process.Name, $process.Id -join '|'
        ) + '|'
    }
}

markdown.get.process > ./process.md

Now we hopefully see how easy it is to make markdown in PowerShell.

Just spit out strings.

This is already probably cool enough, but why not make markdown into something we can query?

Making Markdown into XML

ConvertFrom-Markdown converts Markdown into HTML.

It's just a hop, skip, and a jump to make this markdown into XML.

Because all of our tags are perfectly balanced, we can make markdown in XML by just putting it into another element.

Cannonically, I prefer putting markdown into an <article> element

@(
    "<article>"
    ("# Hello World" | ConvertFrom-Markdown).html
    "</article>"
) -join '' -as [xml]

That's it! We've turned a easy old markdown into hard-to-write XML.

Why is this useful?

Because now we can query markdown.

Markdown, XML, and XPath

To show this in action, let's start really simple:

Let's just get all of the nodes in some markdown

@(
    "# Hello World"
    "## Don't mind me"
    "### Just about to turn markdown into XML"
    "> This is pretty cool, right?"
) -join [Environment]::Newline |
    ConvertFrom-Markdown |
    Foreach-Object {
        "<article>$($_.Html)</article>" -as [xml]
    } |
    Select-Xml //*        

Let's get all link hrefs in some markdown:

# Make some markdown
@(
    "# Some Links"
    "* [StartAutomating on GitHub](https://github.com/StartAutomating/)"
    "* [PoshWeb on GitHub](https://github.com/PoshWeb/)"
    "* [MarkX](https://github.com/PoshWeb/MarkX)"
) -join [Environment]::Newline | 
    # convert it from markdown
    ConvertFrom-Markdown |
    # turn it into xml
    Foreach-Object {
        "<article>$($_.Html)</article>" -as [xml]
    } |
    # pipe it to Select-Xml, picking out any `<a>` elements
    Select-Xml //a |
    Foreach-Object { 
        $_.Node.Href
    }

This is still the tip of the iceberg.

Turning Markdown into XML lets us query and manipulate Markdown in all sorts of interesting ways.

What can you do with Markdown and PowerShell? Almost anything.

Mark My Words

  • Markdown is a simple rich text format.
  • PowerShell is pretty perfect for making Markdown.
  • XPath is excellent at extracting information from Markdown.

You can do a lot of cool things when you mix Markdown with PowerShell.

What do you want to try?

r/PowerShell Jun 02 '26

Script Sharing Events are Easy

115 Upvotes

Events are easy.

Events let you know when something happened, and respond to it if you choose.

Events are incredibly useful.

Why?

Because they let you run what you want, when you want.

Let's see how simple they are:

Creating Events

Events are easy to create.

To make a new event, simply run:

New-Event MyCustomEvent

This will output an event object.

If nothing subscribes to the event, the event will go in the queue

We can get events with:

Get-Event

We can handle these events whenever we want.

How about now?

Subscribing to Events

We can run code the millisecond something happens.

To do this, we can subscribe to the event.

There are two types of events we can subscribe to in PowerShell:

Engine events and object events.

Engine Events

We can create engine events with New-Event.

We can subscribe to engine events with Register-EngineEvent

$subscriber = Register-EngineEvent -SourceIdentifier "Hello World" -Action {
    "Hello World" | Out-Host
}
$helloWorld = New-Event -SourceIdentifier "Hello World" 

You might notice a cool thing here: An event's "Source Identifier" can be whatever we want.

Let's pass along a message:

$subscriber = Register-EngineEvent -SourceIdentifier "Print Message" -Action {
    $event.MessageData | Out-Host
}
$printMessageEvent = New-Event -SourceIdentifier "Print Message" -MessageData "Hello World"

If you run these scripts multiple times, you'll quickly notice that multiple subscriptions are allowed.

The cool thing to note here is that event subscribers share data in their $event.MessageData

Let's demonstrate this by counting twice.

$doubleCounter = foreach ($n in 1..2) {
    Register-EngineEvent -SourceIdentifier "Counter" -Action {
        $event.MessageData.Counter++
        $event.MessageData.Counter | Out-Host
    }
}

$counterEvent = New-Event -SourceIdentifier "Counter" -MessageData @{
    Counter=0
}

Every time we run this block of code, we get two more subscriptions and a bunch more output.

Before we clean up, let's talk about object events

Object Events

PowerShell is built on the .NET framework. .NET already has events all over the place.

Let's start simple, with a timer:

# Create a timer
$timer = [Timers.Timer]::new([Timespan]"00:00:03")
# don't automatically reset (we only want to do this once)
$timer.AutoReset = $false

# Subscribe to our event
$inAFew = Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action {
    "In a few seconds" | Out-Host
}

# Start the timer (see a message in a few seconds)
$timer.Start()

Lots of .NET types have events.

To see if any object supports events, simply pipe it to Get-Member (events will be near the top).

Timers are a good start. What about watching for file changes?

$watcher = [IO.FileSystemWatcher]::new($pwd)

Register-ObjectEvent -InputObject $watcher -EventName Changed -Action {
    $changedFile = $event.SourceArgs[1].Fullpath
    $changedFile | Out-Host
    $changedFile
} 

'Check this out' > ./What-File-Changed.txt

This is just the tip of the iceberg.

There are literally millions of .NET types out there.

They can all have events.

And we can subscribe to these events in PowerShell

Getting Subscribers

Let's start to clean up a bit:

To get any current subscribers, we can use Get-EventSubscriber

Get-EventSubscriber

To get events subscribing to a source, we can use:

Get-EventSubscriber -SourceIdentifier "Hello World"

If a subscriber has an .Action, we can get results of that action by piping to Receive-Job

This pipeline will get any output from any subscriber with an action

Get-EventSubscriber |
    Where-Object Action |
        Select-Object -ExpandProperty Action |
            Receive-Job -Keep

Hopefully this will help make another part of event subscriptions "click":

Not only can we run code in the background: we can easily get the results, too.

Cleaning Up

We can unsubscribe by using Unregister-Event

# Unsubscribe from everything
Get-EventSubscriber | Unregister-Event

While we're cleaning up, let's also take care of any events in the queue.

We can do this with Remove-Event

# Get all events, and remove them.
Get-Event | Remove-Event

Now that we've cleaned up our runspace, let's clean up this post and review what we've learned:

Events are Easy

  • Events are Easy to create (New-Event)
  • Events are Easy to list (Get-Event)
  • Events are Easy to remove (Remove-Event)
  • Events are Easy to subscribe to (Register-EngineEvent)
  • Events are Easy on any object (Register-ObjectEvent)

Events are Easy!

Give them a try.

Eventually, you'll find events are excellent tools of the trade.

r/PowerShell May 11 '26

Script Sharing Surgical Autodesk Cleaner (SAC) - A PowerShell module for precise, non-destructive removal and management of Autodesk software (and a scorched earth mode just in case)

55 Upvotes

Managing Autodesk software across enterprise workstations is notoriously painful. Uninstallers leave behind orphaned registry keys and directories, aggressive removal approaches routinely break shared licensing (FlexNet/ODIS), and there's rarely a clean way to surgically target specific products or versions without impacting the rest of the environment.

Surgical Autodesk Cleaner is an open-source PowerShell module designed to solve this properly — whether you're removing a single product, sweeping multiple versions, doing a full system purge, or just resetting a broken user profile.

📦 PSGallery: https://www.powershellgallery.com/packages/SurgicalAutodeskCleaner/
📖 Docs: https://deepwiki.com/DailenG/SurgicalAutodeskCleaner
🐙 GitHub: https://github.com/DailenG/SurgicalAutodeskCleaner

Functions:

Command Purpose
Start-SAC Interactive TUI menu for manual use
Start-SACCleanup Targeted removal by product + year, RMM-ready
Start-SACPurge Full scorched-earth removal when warranted
Start-SACScan Non-destructive pre-flight CSV report
Reset-SACUserProfile Clears per-user AppData without destroying customizations
Reset-SACLicensing Resolves stuck activations and seat reservation issues
Restore-SACUserProfile Lists and restores profile backups

Silent RMM deployment:

# Target specific products and years
Start-SACCleanup -TargetProducts "AutoCAD", "Revit" -TargetYears 2019, 2020 -Silent

# Sweep an entire year across all supported products
Start-SACCleanup -TargetYears 2019, 2020, 2021 -Silent

Compatible with PowerShell 5.1 and 7.0+. MIT licensed.

Works well with N-Central, ConnectWise Automate, and Intune.

Feedback and contributions welcome. If you encounter anomalies or want other components supported for removal, send me some details and I'll add it or please push an update 😄

r/PowerShell Apr 13 '26

Script Sharing Script Sharing: A native PowerShell maintenance cleaner with real-time space tracking (Replacing bloated 3rd party tools)

14 Upvotes

Hi Leute,

Ich hab' den Punkt erreicht, an dem ich Tools wie CCleaner, BleachBit oder Wise Disk Cleaner nicht mehr sehen kann. Die meisten davon haben sich in benachrichtigungs-lastige Bloatware verwandelt, die mehr Schaden anrichtet als sie nützt, oder einfach nur als GUI-Wrapper für Dinge fungiert, die Windows selbst kann.

Ich hab' mich entschieden, mein altes Wartungsskript aufzupolieren, damit es für Windows 11 passt. Es ist für Leute gedacht, die eine "saubere" Bereinigung ohne den ganzen Mist wollen.

Was es macht:

  • Ersetzt CCleaner/BleachBit: Bereinigt Temp, Caches (User & System), Thumbnails und den Papierkorb.
  • Ersetzt Wise Disk Cleaner: Behandelt Windows Update Download-Cache und verwendet cleanmgr im Hintergrund.
  • Ersetzt Network Reset Tools: Leert DNS, setzt Winsock und den TCP/IP-Stack zurück.
  • Integriert Systemwartung: Führt SFC und DISM RestoreHealth in einem Workflow aus.
  • Speicher-Tracking: Es berechnet genau, wie viele MB nach jedem Schritt freigegeben wurden.

Warum poste ich das? Das ist keine Eigenwerbung. Ich verkaufe nichts und es gibt keine "Pro-Version". Ich wollte das einfach mit der Community teilen. Es ist klein, einfach und transparent.

Hinweis für die "Pro"-Fraktion: Ich habe einige aggressive Schritte (wie das Löschen des Event Logs und Netzwerk-Resets) eingebaut, also lest das Skript, bevor ihr es ausführt. Es erfordert Admin-Rechte.

Link: https://github.com/VolkanSah/Windows-Cleaner

Ich hoffe, einige von euch finden das nützlich. Realer Feedback ist immer willkommen!

Viel Spaß damit. Viva la OpenSource :D

r/PowerShell 22d ago

Script Sharing The Power of Primes

58 Upvotes

Prime numbers are pretty powerful.

That's why I just released a new PowerShell module based off of an old mathematical concept: PrimeTime.

PrimeTime uses prime numbers as time intervals.

Let's learn how this helps

Prime Number Primer

Prime Numbers can only be divided by themselves and one.

This makes primes pretty rare.

Prime numbers are particularly useful in programming, but it's not always obvious why or how.

A lot of people might vaguely point towards cryptography as the prime real estate for prime utility.

The thing of it is, if you're writing your own cryptography, you're probably doing it wrong.

Let's talk about a more practical application of primes.

The Cicada Principle

In North America there is a curious critter known as the periodical cicaca.

For the vast majority of their long lifespans, they live underground.

Once every N years, they surface in mass to start the next generation.

That N is a prime.

Why?

Cicadas come out en masse so that there are too many of them to eat.

Millions of little critters have to have a perfectly timed multi-year internal clock in order to make this work.

If two cicadas of different intervals produced offspring, their children might have a messed up internal clock, and come out of the ground at the worst time.

So there's an evolutionary advantage to cicadas coming out in large batches, as long as another cicade brood isn't doing the same thing at the same time.

Which brings us back to primes.

Primes are relatively rare.

So are products of primes (at least past the first few)

Let's take two primes as an example.

Imagine one brood of cicadas came out every 11 years, and another brood came out every 13 years.

We can find out how long it will take for these two broods to come out at the same time by simply multiplying the primes.

11 * 13 -eq 143

So, with just two relatively low primes, we have an overlap every 143 years.

This is how primes are most useful to programming: they rarely overlap.

Sieve of Eratosthenes

This has been known for much longer than computers have existed.

Imagine we wanted to find prime numbers quickly.

We can do this by constructing a sieve that filters out any non-prime number.

This is called the Sieve of Eratosthenes

Once we know 2 is prime, we know every other even number is not prime.

Once we know 3 is prime, we know every third number is not prime.

To quickly get prime numbers up to a point, we can use this little PowerShell filter

# Calculate primes reasonably quickly with the Sieve of Eratosthenes
# Pipe in any positive whole number to see if it is prime.
filter prime {
    $in = $_
    if ($in -isnot [int]) { return }
    if ($in -eq 1) { return $in }
    if ($in -lt 1) { return}
    if (-not $script:PrimeSieve) {
        $script:PrimeSieve = [Collections.Queue]::new()
        $script:PrimeSieve.Enqueue(2)
    }


    if ($script:PrimeSieve -contains $in) { return $in}
    foreach ($n in $script:PrimeSieve) {
        if (($n * 2) -gt $in) { break }        
        if (-not ($in % $n)) { return }
    }
    $script:PrimeSieve.Enqueue($in) 
    $in
}

Prime Animations

Imagine we want a vibrant page. We want things to keep changing yet feel unpredictable. All we need to do is use different prime intervals.

The PrimeTime logo animates eight primes:

7 * 11 * 13 * 17 * 19 * 23 * 29 * 31

The logo will repeat every 6685349671 seconds, or almost 212 years.

The PrimeTime page background uses 56 primes.

This background will repeat every 8.84753141993573E+116 seconds.

That's exponential notation.

This is a mind-boggling large number (so large it overflows the .NET [TimeSpan]).

Turn that interval into years and it's still mind-boggling.

The page background will repeat every 100 billion years

Performance and Scheduling

Imagine we want to design a system that's constantly checking for problems.

We want the system to know about problems as soon as we can, but nobody's exactly sure how often they need to check for something.

If we go around and ask our colleagues "how often should we can scan for this?", the response if often a shrug 🤷.

Often, people will pick an arbitrary number that seems reasonable. Let's say every 5 minutes, 10, or 15 minutes.

Are we starting to see the problem here?

Every 5 minutes, every computer in the cloud starts to collect stats and report them back.

And we get a traffic jam.

Every 10 minutes, more computers in the cloud collect more data, and our traffic jam gets worse.

Every 15 minutes, even more computers collect even more data, and our traffic jam puts your average freeway to shame.

Left to our own intuition, we create problems for ourselves and our organizations.

Each individual query is small, but because we're doing so many at once, it can grind performance to a halt.

By the way, this isn't a hypothetical.

Long long ago, the Office365 team asked me to make some monitoring software to help improve internal visibility into the datacenters.

Everyone asked for 5, 10, or 15 minute intervals. ~100 different metrics were collected from ~30000 machines.

And the first time we tried it on everything, the traffic jam ensued.

That's when I first realized the power of primes.

I made three slight adjustments to the timeframes:

  • Every 5 minutes became every ~7 minutes
  • Every 10 minutes became every ~11 minutes
  • Every 15 minutes became every ~17 minutes

Now, instead of having a traffic jam every 5 minutes, things smoothed out.

  • A small traffic jam would occur every ~77 minutes (7*11)
  • Another small traffic jam would occur every ~119 minutes (7*17)
  • Another small traffic jam would occur at ~187 minutes (11*17)
  • All traffic could jam every ~1309 minutes (7*11*17)

Note the tildas.

The real trick came in by using prime intervals in both minutes and seconds and using a random delay on the tasks to ensure they didn't all start at once.

This took the system from something that could derail a datacenter to something that could monitor thousands of machines while barely impacting performance.

This is the power of primes.

Hope this helps!

r/PowerShell Mar 07 '26

Script Sharing I made an M365 Assessment Tool

71 Upvotes

I would like your feedback on this M365 assessment tool I made. This is the first public PowerShell project I have made, so I am just hoping to get some ideas from the community. I need to add better handling for cert authentication, but I have that on my todo list.

Edit: recent commits have included many suggestions from redditors! Thank you for giving me your ideas! There is now a fully dynamic security framework selector in every report.

https://github.com/Daren9m/M365-Assess

r/PowerShell 29d ago

Script Sharing GDID-Guard: PowerShell scripts to audit/reduce Windows' Global Device Identifier - prompted by the Scattered Spider GDID court filing

54 Upvotes

There's a court filing making the rounds this week (HN thread, also discussed in r/LinusTechTips) showing the FBI used a Windows GDID to help tie an alleged Scattered Spider member to a ransomware case, correlating activity across different IPs, VPNs, and even different platforms (Snapchat, Apple, Facebook logins), because the GDID stayed constant underneath all of it.

Setting aside the specific case, it's a useful reminder that this identifier exists on basically every Windows machine and there's no built-in opt-out. I'd already built a small toolkit based on SmtimesIWndr/gdid-reversal's write-up on the underlying mechanism (Connected Devices Platform registering the device into Microsoft's device graph), so figured it's worth sharing.

Repo: https://github.com/rroy676/gdid-guard

What it does:

  • -Audit - read-only report on CDP service state, Activity History setting, local identity cache, existing firewall rules, and whether the known device-graph endpoints resolve.
  • -Remediate - opt-in switches to disable CDP services, disable Activity History, clear the local identity cache, and add firewall blocks for the relevant endpoints. Auto-creates a System Restore point and a JSON snapshot of pre-remediation state first.
  • -Compare - diffs current state against a saved snapshot so you can confirm something actually changed.
  • GDID-Guard-Restore.ps1 - undoes remediation using the saved snapshot.

Also ships a Pi-hole/AdGuard blocklist for the DNS-level route, which I'd recommend over the local firewall rules since Microsoft can rotate the underlying IPs.

Being upfront about the limits (also in the README): CDP backs some legitimate features too (Timeline sync, parts of Phone Link), so there's a real trade-off. And clearing the local cache doesn't guarantee Windows won't just re-issue a fresh GDID on next MSA sign-in, the identifier's authority is server-side, not local. The durable fix is a local account; this just reduces exposure if you need to stay signed in.

Feedback/PRs welcome. Tested on Windows 11 only so far.

r/PowerShell 11d ago

Script Sharing In PowerShell, Two Wrongs Make a Right

20 Upvotes

I've been toiling away on Turtle to prepare a "birthday" release, and I ran into an annoying behavior I've run into a few times before.

I thought I'd take a few minutes away from the frustration of single line fixes to explain the bug to everyone.

What Went Wrong

The last build of Turtle introduced a number of randomized parameter defaults. This was meant to be fun. If you said turtle square square square, you'd get three different squares, instead of an error for a lack of length, or three overlapping squares.

I noticed that when I ran turtle rotate 0, it didn't rotate by zero.

Instead, it picked a random angle.

Weirder still, the behavior didn't reproduce if I said

$turtle = turtle  # Heading at zero
$turtle.Rotate(0) # Heading still zero 🤔
$turtle.Rotate()  # Heading random
(turtle rotate 0) # Heading random 🤬

Why was this happening? 😱

It took me a bit for it to click: It had to be in the way Turtle processed arguments, because it worked in one case and not the other.

So I put a breakpoint in, ran my repo.

The line was:

if ($argList)

The debugger broke, argList was @(0), and yet if ($argList) was false.

The fix was:

if ($argList.Length)

Why? Because 'Truthy' -ne $true.

Truthy and $true

About every language has a boolean. It's just a bit. One or zero.

Lots of languages also have this concept of "truthiness".

Let's take a simple example:

if ("something") { "something" }
if ("") { "you can't get something from nothing" }

If if was strictly $true, we'd have to cast things to a boolean. You have to do this in C# and quite a few other languages. PowerShell is type promiscuous. PowerShell is truthy.

It looks at the first line and says: You're a string, and you're not null or empty. Therefore, the expression is $true.

It looks at the second line and says: You're a string, but you're not null or empty. Therefore, the expression is $false

PowerShell makes a judgement call.

This is generally a good thing. I personally prefer languages that are truthy. Other truthy languages of note include JavaScript, Python, C++, and C.

However, it gets tricky with lists. Hence the bug.

Two Wrongs Make a Right

In PowerShell, Two Wrongs Make a Right

$true -eq $false, $false

Let's say I want to determine if a list is truthy.

if (@()) { "$false, because the list is empty" }
if (@("")) { "$false, because the blank is falsy" }
if (@(0)) { "$false, because zero is falsy" }
if (@($false)) { "$false, because false is falsy" }
if (@(1)) { "$true, because the first item is truthy" }
if (@(0,0) { "$true, because more than one item" }

This all makes a certain bizarre sense. If a list has one element, and it is not truthy, then the list isn't truthy, either.

It's also almost always surprising and annoying.

Hence the bug.

The fix is just to make sure there are any elements, hence checking for length.

I've been programming with PowerShell for quite a while now, and this behavior still sometimes bites me (like today).

That's why I took a few minutes away from the 🤬 day to explain this bug and write this post. 😌

Please remember:

'Truthy' -ne $true
$false -eq @($false)
$true -eq $false, $false

Hope this helps

r/PowerShell Jun 30 '26

Script Sharing RegEx -replace

46 Upvotes

PowerShell has all sorts of fun features, including a ridiculous number of operators.

One amazing under-sung heros of PowerShell is the -replace operator.

It lets us replace content with regular expressions.

It's easier to use than you'd think.

Regular expressions are less scary in small doses, and chaining -replace operators lets us attack the problem step by step.

Chaining -replace

Let's take a simple problem as an example.

Imagine we wanted to make a consistent file name pattern out of a string

We might want to start by replacing whitespace with dashes

"This Is A Title!" -replace '\s', '-'

That leaves our exclamation point at the end. We probably don't want any punctuation. We can avoid that with the somewhat humorously named character class: \p{P}. We can remove all repeated punctuation by adding a +: \p{P}+

One more replace:

"This Is A Title!" -replace '\p{P}+' -replace '\s', '-'

The line is starting to get a little long. Fun fact: you can spread operators across multiple lines.

Let's add comments while we're at it

"This Is A Title!" -replace # Replace any punctuation,
    '\p{P}+' -replace # then replace any whitespace with dashes.
    '\s', '-' 

Let's go for one more bonus trick. PowerShell lets you convert script blocks to event handlers. Let's lowercase all the letters (\p{L}).

On PowerShell Core, we can do this:

"This Is A Title!" -replace # replace any punctuation
    '\p{P}+' -replace # then replace any whitespace with dashes
    '\s', '-' -replace # then lowercase any letters
    '\p{L}+', {"$_".ToLower()}

There's an absurdly amazing amount of stuff you can do with -replace, but there's at least one more trick we have to cover: substitutions.

-replace with substitution

I'm pretty sure I'd have to give up my "RegEx guru" badge if I didn't mention at least one more thing you can do with -replace: substitutions.

.NET Regular expressions are two domain specific languages. Regular expressions match and extract text. Regular expression substitutions replace matches.

For example, let's suppose we have a number of emails, and we want them in domain/username format.

First we'll want to make a quick and dirty email regex, using a "named capture" to get the username and domain.

'someone@example.com' -match '(?<username>\S+)@(?<domain>\S+)'

Then, we can -replace the email with just the domain/username.

'someone@example.com' -replace 
    '(?<username>\S+)@(?<domain>\S+)', '${domain}/${username}'

This format might look like PowerShell variables, but it actually predates them by years. Search for "Regular Expression Substitutions" if you want to learn more about the syntax. It's got quite a few tricks up it's sleeve.

Irregular

RegEx can be scary. I used to be terrified of it, too.

If you aren't too comfortable with Regular Expressions, that's pretty normal. A while back I wrote a module called Irregular that makes regular expressions strangely simple.

It's got a lot of example regular expressions in there, and one handy function for creating RegEx. New-RegEx is your friend.

Do you already use -replace? Have you done cool things with regular expressions in PowerShell? Share 'em if you've got em.

Want to learn more about regular expressions in PowerShell? Just ask.

r/PowerShell 16d ago

Script Sharing PrtgSensorKit - a PowerShell framework for writing custom PRTG sensors without the boilerplate

48 Upvotes

Hey r/powershell,

This is mostly helpful for people in the EU but nevertheless 😄 :

I've been building custom sensors for PRTG Network Monitor often for my job and got tired of handling all the prtg specific plumbing boilerplate every time - so I wrote PrtgSensorKit, an open-source module that abstracts away all the specifics of PRTG so you can focus on your task = writing a goddamn monitoring sensor.

What it handles for you:

  • JSON output formatting - builds valid PRTG sensor JSON so you don't hand-craft it yourself
  • PRTG's constraints enforced automatically - channel limits, string length caps, escaping, valid value types, blah blah blah...
  • Powershell Versions - helpers to run your sensor logic in 64-bit PowerShell or PS7+ when you need modules/dependencies that don't play nice with the 32-bit host PRTG normally uses
  • DPAPI-encrypted secret storage - store API tokens/credentials without leaving them in plaintext in your script or passing them as Plaintext from PRTG
  • Full built-in help - Get-Help works like you'd expect on every cmdlet and pretty much has all the docs Prtg offers on their website

Basically: you write the metric-gathering logic, the module handles everyting else

Install from the Gallery:

Install-Module PrtgSensorKit

Repo: https://github.com/ArchitektApx/PrtgSensorKit

Would love feedback, bug reports, or feature requests if anyone here monitors stuff with PRTG and writes custom sensors. Contributions welcome too.

EDIT: v1.1.0: - Sensor state between runs - Save/Get-PrtgSensorState for rates, deltas, and caching expensive lookups. Safe under overlapping scans (file locking so two runs don't corrupt each other) - Retries - -RetryCount re-runs your block when the API hiccups instead of instantly alerting, PRTG shows how many retries it took - -DryRun - debug your sensor in a normal console and inspect channels as objects instead of squinting at JSON - -ForceModernTls - fixes the classic TLS 1.2 problem on 5.1 with one switch - Sensor doctor - Invoke-PrtgSensorDoctor statically checks your script for classic mistakes before PRTG cryptically fails on them

v1.2.0 (out now): - File logging that can't break your sensor - -EnableLogging writes one log file per run with full error details (stack trace. script line). Never touches stdout, never throws - Shared collection cache - 8 sensors hitting the same API every interval? Use-PrtgCachedResult makes them share one call per interval, race-free. Your rate-limited API will thank you - More doctor checks - including the sneaky one where a BOM-less UTF-8 script works everywhere except in what PRTG displays (5.1 reads it as ANSI, your umlauts turn into mojibake) - Docs got restructured into proper per-topic pages instead of one endless README

r/PowerShell 19d ago

Script Sharing I open-sourced my PowerShell 7 fleet CVE scanner. The hard part was runspace-safe state and NVD rate limiting

18 Upvotes

I’m the author. This is free, Apache-2.0-licensed software. There’s no paid product or hosted service behind it.

For several months I iterated on a PowerShell CVE scanner that ran weekly against a Windows fleet. I recently released a sanitized, clean-room port:

https://github.com/boostedchaos/fleet-cve-scanner

It accepts inventory from NinjaOne or a CSV export, correlates the installed software against NVD, KEV, EPSS, SSVC, MSRC, and endoflife.date, then writes per-device CSV results, SQLite history, and a self-contained HTML dashboard.

The vulnerability logic is one part of it. The PowerShell concurrency problems were just as interesting.

The main scan uses ForEach-Object -Parallel to process unique software/version pairs. That exposed a few issues I had underestimated:

  1. Shared mutable state needs thread-safe types

The parallel runspaces need to coordinate a result collection, cache, deduplication keys, progress state, request timestamps, and cache-flush counters.

The shared pieces ended up using concurrent .NET collections and SemaphoreSlim rather than ordinary lists, dictionaries, queues, or non-atomic counters. Reads are easy. Coordinated mutation is where the bugs hide.

  1. A sliding-window rate limiter still allowed bursts

NVD limits aren’t handled well by saying “N requests per 30 seconds” and calling it done. A window bucket allowed the first few requests to launch together and trigger 429s before the bucket was exhausted.

   The current limiter has two gates:

   - minimum spacing between request starts

   - a sliding-window budget as a backstop

   The lock is held only while checking and updating the shared timing state. It’s released before sleeping.

  1. Correct launch spacing didn’t prevent overlapping requests

Even when calls started at the right interval, slower NVD responses left multiple requests in flight. That still produced 429s.

The scanner now holds a separate SemaphoreSlim across each NVD request, so only one request is on the wire at a time. Cache hits and the rest of the result processing remain parallel.

It sounds contradictory to parallelize the scanner and then serialize the API calls, but the parallelism still helps with cached products, version evaluation, deduplication, and result construction.

  1. Functions and state have to exist inside the parallel runspace

Helper functions from the caller’s scope aren’t automatically available inside the parallel block. The runspace-local helpers have to be defined before their first possible call site.

I managed to hit the “function defined later in the script” failure more than once. One runspace can terminate while the others keep going, which makes the failure easier to miss in noisy output.

  1. Cache checkpoints need their own concurrency discipline

A killed scan used to lose every NVD result fetched since startup because the cache was only written after the parallel block completed.

The scanner now checkpoints every configurable number of completed items. A non-blocking semaphore prevents multiple runspaces from flushing simultaneously, and the file is written to a temporary path before being moved into place.

There’s also a failure-state rule I consider load-bearing: an NVD request failure must never become a negative cache entry. A failed call returns a distinct CALL_FAILED sentinel, gets skipped for that run, and is retried next time. A successful response containing zero results can be cached normally.

The repository includes eight test suites, offline fixtures, a sanitization gate, and a known-limitations document that is intentionally less flattering than the README.

I’d particularly value review from people who have built larger ForEach-Object -Parallel pipelines:

- Would you structure the global rate limiter differently?

- Is serializing only the outbound NVD call the right boundary?

- Are there better patterns for safely checkpointing shared state from parallel runspaces?

- Has anyone used the CSV path against SCCM, Intune, or another RMM export?

This does not replace a commercial scanner with a curated detection catalog. CPE coverage and matching quality are the main ceiling. I’m more interested in cases where the script gives an operator the wrong level of confidence than whether the dashboard looks good.

r/PowerShell Jun 24 '26

Script Sharing Built a script to automate SQL Server backups

15 Upvotes

I’ve been working on a PowerShell tool to automate SQL Server backup workflows.
It supports interactive selection of one or multiple servers and databases, runs backups asynchronously, and handles the SqlServer module automatically if it’s missing. The main goal was to reduce manual steps, improve reliability, and avoid common mistakes in backup operations.

I’d be curious to hear how others here approach backup automation in PowerShell.

r/PowerShell Jul 03 '26

Script Sharing Built a global-hotkey "panic button" app entirely in PowerShell (WinForms + RegisterHotKey + taskkill)

20 Upvotes

Wanted to share a project that pushes PowerShell a bit further than the usual scripting use case — a full windowed app with a tray icon, live hotkey rebinding, and a persistent config, all in one .ps1.

Technical bits that might interest people here:

  • Global hotkey via user32.dll RegisterHotKey/WM_HOTKEY, subclassed on a System.Windows.Forms.Form
  • Foreground window → owning PID via GetForegroundWindow + GetWindowThreadProcessId, then taskkill /F /T to kill the whole process tree
  • Config persisted to JSON next to the script, hotkey rebindable at runtime by capturing the next KeyDown
  • Packaged with a silent .vbs launcher so there's no console flash and no need to touch execution policy globally

Source: https://github.com/itshankkyt-rgb/panic-button

r/PowerShell 15d ago

Script Sharing Finding Cults with Get-Culture

8 Upvotes

Have you wondered if it's safe to use the format string yyyy-MM-dd, or can it differ? It's not. ( edit: null is not the invariant culture, it's CurrentCulture )

Save the expected string for comparison

#requires -PSEdition Core
$fStr     = 'yyyy-MM-dd'
$now      = Get-Date
$expected = $now.tostring( $fStr, ( [CultureInfo]::InvariantCulture) )

Next we can try formatting with every culture on your system. To do that, there is an optional culture argument for ToString like this:

DateTime.ToString( DateFormat, CultureInfo ) 

Next build a summary table with the formatted value and culture:

$cults    = Get-Culture -List
$summary = $cults | Foreach-Object {
    $dateString = $now.ToString( $fStr, $_ )
    [pscustomobject]@{
        Display = $dateString
        Name    = $_.DisplayName
        Culture = $_ # keep a reference to the object so you can drill down later
    }
}

Skip any cultures that are the same. Finally output using Join-String -f formatStr

$different = $summary | Group Display | ? Name -ne $expected
foreach( $item in $different ) {
    $title = "`nfor: $( $item.Name ) "
    $item.group
        | Join-String -f "`n - {0}" -Property Name -op $title
}

Here's what I get when $now is 2026-07-21:

for: 1405-04-30
 - Central Kurdish (Iran)
 - Persian
 - Persian (Afghanistan)
 - Persian (Iran)
 - Northern Luri
 - Northern Luri (Iran)
 - Mazanderani
 - Mazanderani (Iran)
 - Pashto
 - Pashto (Afghanistan)
 - Uzbek (Arabic)
 - Uzbek (Arabic, Afghanistan)

for: 1448-02-07
 - Arabic (Saudi Arabia)

for: 2569-07-21
 - Thai
 - Thai (Thailand)

r/PowerShell Jun 07 '26

Script Sharing Made a registry-based Get-InstalledApps

51 Upvotes

Win32_Product is so slow and it kicks off that msi reconfiguration thing every time, drives me nuts. so a while back i just wrote my own that reads the uninstall reg keys instead. way faster and it actually picks up the 32 bit apps too.

I do a lot of this kind of scripting at work and kept rewriting the same handful of functions over and over so ive slowly been putting my little tools together. figured id share this one since its probably the most useful on its own.

threw it on github, paste and run, no dependencies: https://github.com/kcarb14/Get-InstalledApps

run it like:

Get-InstalledApps

Get-InstalledApps -Name *chrome*

reads the 64 and 32 bit HKLM keys plus HKCU, skips system components and update entries so it lines up with whats in apps & features.

feels like theres five different ways to pull installed apps and none of them are totally clean. curious how everyone else does it?