PowerShell

Windows Client Security Baseline Toolkit

Knowing what to secure on Windows clients is rarely the problem.
Knowing the actual state of a device, and proving it usually is.

To help with that, I maintain a small PowerShell‑based toolkit for assessing and hardening Windows 10/11 clients.

https://github.com/DeploymentBunny/Files/tree/master/Tools/CheckWindowsClientSecurityBaseline


What is this?

A no‑agent, PowerShell‑only toolkit that lets you:

  • Assess key Windows client security controls
  • Get results as objects, not screenshots
  • Write JSON, text, and log files
  • Remediate findings in a controlled, opt‑in way
  • Use exit codes for automation

No dashboards.
No magic.
Just facts.


Two scripts, on purpose

Baseline assessment

Check-WindowsClientSecurityBaseline.ps1

  • Evaluates core Windows 10/11 security controls
  • Returns True, False, Unknown, or NA
  • Designed for filtering, exporting, and automation

Example:

$r = .\Check-WindowsClientSecurityBaseline.ps1
$r | Where-Object { $_.Status -eq 'False' }


Remediation

Remediate-WindowsClientSecurityBaseline.ps1

  • Applies explicit remediation switches
  • Supports -WhatIf and -Confirm
  • Returns a structured summary
  • Signals reboot requirements via exit codes

Which brings us to…


⚠️ WARNING: This script has opinions

The remediation script changes security‑critical Windows settings.

Not “logs a warning”.
Not “politely suggests”.
It flips switches.

Before running it on anything important:

  • ✅ Test it
  • ✅ Read the code
  • ✅ Expect reboots
  • ✅ Expect GPO / MDM to push back

And seriously:, use-WhatIf FIRST

.\Remediate-WindowsClientSecurityBaseline.ps1 -HardenRecommended -WhatIf -Verbose

About testing

This script has not been tested to insanity 😄
It works in labs and real environments — but not against:

  • Every OEM image
  • Every legacy app
  • Every “special exception” created since 2007

If you run it blindly on production:

  • Things may snap back
  • Reboots may happen
  • Change meetings may appear

What does it check?

The baseline focuses on controls that actually matter:

  • UEFI & Secure Boot
  • TPM & BitLocker
  • VBS, Credential Guard, HVCI
  • LSA protection / LSASS PPL
  • Defender real‑time protection & EDR
  • NTLM hardening
  • SMB1
  • Firewall profiles and inbound rules
  • WDigest & cached logons
  • WDAC / AppLocker presence

In other words: the boring but important stuff.



-HardenRecommended

PowerShell

-HardenRecommended

Applies a conservative, high‑value subset, including:

  • Defender protection + EDR
  • Firewall profiles + inbound block
  • LSA protection / LSASS PPL
  • Disable WDigest
  • Cached logons = 1
  • Disable SMB1
  • Harden NTLM

Still: try it with -WhatIf. Always.


Baseline‑driven remediation

You can remediate directly from baseline results:

$b = .\Check-WindowsClientSecurityBaseline.ps1
.\Remediate-WindowsClientSecurityBaseline.ps1 -BaselineResult $b -AutoFromBaseline -WhatIf

Only failed checks are targeted.
No guesswork. No “enable everything”.


How to use this without regret

  1. Run the baseline
  2. Look at the results
  3. Use -WhatIf
  4. Test on non‑important machines
  5. Re‑run the baseline

If you can’t explain why a switch exists — don’t enable it.


Final thoughts

This won’t replace GPO or Intune.
It will give you visibility, evidence, and control when you need it.

Read the code. Test first.
You’ve been warned 😉

Until next time
/DeploymentBunny

3 replies »

  1. There are some issues. Running on PowerShell 7.6.1 x64 with elevated admin rights, domain joined, domain account:

    VERBOSE: [2026-05-08 13:59:08] [WARN] Secure Boot Certificate Updated?: Unknown – Unable to validate Secure Boot certificate. Parameter cannot be processed because the parameter name ‘Task’ is ambiguous. Possible matches include: -TaskName -TaskPath.

    VERBOSE: [2026-05-08 13:59:12] [WARN] WDigest Credential Caching disabled?: Unknown – Unable to read WDigest credential caching setting. The property ‘UseLogonCredential’ cannot be found on this object. Verify that the property exists.

    VERBOSE: [2026-05-08 13:59:14] [WARN] Current User member of Local Administrators group?: Unknown – Unable to evaluate current user local Administrators membership. net localgroup Administrators failed. Exit code: 2 VERBOSE: [2026-05-08 13:59:14] [WARN] Extra Local Users in Administrators group?: Unknown – Unable to evaluate additional local user memberships in local Administrators. net localgroup Administrators failed. Exit code: 2

    The last one is probably because it is run on Polish Windows, so you need to somehow use localized names for groups (in Polish it’s Administratorzy)

    Like

    • It is tested on powershell 5.1 and on US English. The challenge is using powershell to grab the local admin group only works when the device has a connection to the DC, it checks the sid, if that doesn’t work then the entire command fails. I will flip to use an other way. The certificate issue in the beginning does not make any sense, but i will check if I can reproduce the issue, thanks for reaching out!

      Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.