Skip to content

Overhaul windows.ps1: fix breaking bugs, speed up run time, add answer-key-driven coverage - #1

Open
Felipezwp wants to merge 2 commits into
tanav-malhotra:mainfrom
Felipezwp:improve-windows-script
Open

Overhaul windows.ps1: fix breaking bugs, speed up run time, add answer-key-driven coverage#1
Felipezwp wants to merge 2 commits into
tanav-malhotra:mainfrom
Felipezwp:improve-windows-script

Conversation

@Felipezwp

Copy link
Copy Markdown

Summary

Restructures windows/windows.ps1 end-to-end, keeping the original authorship/GPL header. Changes were driven by a review of past CyberPatriot answer keys (2024–2025 training/round keys) plus a line-by-line audit of the script. Three categories of change: critical fixes, performance, and new scored coverage.

Critical fixes (image-breaking / point-losing)

  • Removed RpcSs from the service-disable list. Nearly everything in Windows depends on the RPC service; sc config RpcSs start= disabled renders the image unusable.
  • No longer opens inbound TCP 80 unconditionally. Opening un-needed firewall ports can lose points; the rule is now gated behind a "does the README require a web server?" prompt.
  • The keep-RDP answer is now honored. Previously the script asked about RDP, then unconditionally stopped/disabled TermService/SessionEnv/UmRdpService in the later services section.
  • The logged-in user is exempt from the bulk password change (changing it can break auto-logon / lock you out mid-round). Passwords now use Set-LocalUser instead of net user, which fails on names with spaces or >20 chars.
  • Administrator rename fixed: wmic is deprecated/removed on current Win11; the follow-up net localgroup /delete Administrator + net user Administrator /active:no ran after the rename so they always failed. Now Rename-LocalUser + Disable-LocalUser, and the new name is prompted rather than hardcoded.
  • $input is a reserved PowerShell automatic variable — the Read-Host loops assigned to it; renamed.
  • Safer defaults: pressing Enter no longer deletes users or force-restarts the machine; destructive actions require an explicit y. Unauthorized users are disabled (reversible) unless deletion is confirmed.
  • IPv6 DisabledComponents set to the documented 0xFF instead of 0xFFFFFFFF (invalid; causes boot delays).
  • secedit config files are written back as UTF-16 (secedit's export encoding) instead of ANSI, to a temp path instead of C:\.

Performance (run time cut substantially)

  • All prompts moved to the start — after ~60s of questions the script runs unattended instead of stalling on scattered Read-Host calls between slow stages.
  • One secedit export/apply pass instead of three (complexity, reversible encryption, URA now share it); redundant net accounts calls dropped.
  • One recursive scan of C:\Users instead of two, classified into media/images/suspicious afterward.
  • Removed the synchronous Windows Update COM search (IsInstalled=0, can take 5+ min); replaced with a background UsoClient StartScan. The registry settings are what score.
  • Removed both gpupdate /force calls (~30–60s each).
  • One wildcard auditpol call (/category:* /success:enable /failure:enable) replaces 18 calls plus an interactive prompt — setting both satisfies every Success/Failure variant seen in answer keys.
  • Services/features are checked for existence first (one Get-Service / Get-WindowsOptionalFeature call) instead of ~50 blind sc.exe spawns and unconditional dism runs.
  • ~55 hardcoded netsh firewall lines became a data-driven, idempotent New-NetFirewallRule loop, and LOLBin blocking is optional (it isn't scored in any reviewed key).

New coverage (items answer keys score that the script didn't touch)

  • Installed-program audit: inventories registry uninstall keys and flags ~35 commonly prohibited apps (Wireshark, CCleaner, TeamViewer, netcat, ophcrack, AnyDesk, torrent clients, …) with uninstall strings. "Removed " appears in essentially every answer key.
  • Persistence/backdoor report: Run/RunOnce keys, startup folders, non-Microsoft scheduled tasks, listening TCP ports with owning process, non-default SMB shares, hosts file entries — covers scored items like "netcat backdoor removed", "PowerShell script persistence removed", "File share X disabled".
  • Suspicious-file flagging (files named password/credit, .pcap, loose .exes in profiles) — reported, not auto-deleted, since these are often forensics evidence.
  • Added scored settings: prevent users installing printer drivers, disable print-driver download over HTTP, no shutdown without logon, shell protocol protected mode, FIPS algorithms, LmCompatibilityLevel=5 + NoLMHash, WDigest off, WinRM AllowRemoteShellAccess=0, PowerShell 2.0 removal, Defender cloud/network protection + PUA, RDP SecurityLayer=2 (SSL — was 1/Negotiate), account lockout duration, password history 24, missing-authorized-user creation, Xbox/Fax/Spooler service handling.
  • Closing manual checklist for what a script can't do: forensics questions first, README groups, third-party app updates, Windows Update, reboot.

Testing

  • Script parses clean under PowerShell 5.1 (Parser::ParseFile, zero errors).
  • ⚠️ Not yet executed on a live competition image — please run on a practice VM before using in a scored round.

🤖 Generated with Claude Code

… coverage

Critical fixes:
- Remove RpcSs from the service-disable list (disabling RPC breaks Windows)
- Stop opening inbound port 80 unconditionally; gate it behind a README prompt
- Honor the keep-RDP choice consistently (TermService was disabled regardless)
- Exempt the logged-in user from password changes (auto-logon lockout risk)
- Replace deprecated wmic Administrator rename with Rename-LocalUser and drop
  the post-rename net commands that always failed
- Rename the reserved $input automatic variable
- Require explicit 'y' for destructive actions (user deletion, restart)
- IPv6 DisabledComponents 0xFFFFFFFF -> documented 0xFF value
- Write secedit config back as UTF-16 instead of ANSI

Performance:
- Ask all prompts up front so the run is unattended after setup
- One secedit export/apply pass instead of three; drop redundant net accounts
- Single recursive scan of C:\Users instead of two
- Drop synchronous Windows Update COM search (5+ min); use UsoClient StartScan
- Drop both gpupdate /force calls
- One wildcard auditpol call instead of 18 plus an interactive prompt
- Only touch services/features that exist (skip blind sc/dism calls)
- Data-driven registry and firewall loops; LOLBin blocks optional and idempotent

New coverage informed by past answer keys:
- Installed-program audit flagging commonly prohibited software
- Persistence report: Run keys, startup folders, scheduled tasks, listening
  ports with owning process, non-default SMB shares, hosts file
- Suspicious file flagging (password/PII files, pcaps, loose exes) without
  auto-deleting potential forensics evidence
- Added scored settings: printer driver restrictions, FIPS, LmCompatibilityLevel,
  WDigest, remote shell access, PowerShell 2.0 removal, Defender cloud/network
  protection, RDP SecurityLayer SSL, lockout duration, password history, and more
- Closing manual checklist (forensics questions, README groups, app updates)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Felipezwp, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e723b25f-43e9-4e61-a80f-35e6e4a1b305

📥 Commits

Reviewing files that changed from the base of the PR and between 5e1d4fe and c49718f.

📒 Files selected for processing (1)
  • windows/windows.ps1
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
putComment timed out

Every round's README differs: software that is a removable "hacking tool" on
one image (e.g. Wireshark) is required business software on another, and
stopping a README-critical service triggers a scoring penalty. New up-front
exemption prompts capture this per round:

- Untouchable accounts (e.g. mail service accounts like IME_ADMIN): never
  removed, disabled, demoted, or password-reset (resets can break services)
- Critical services: never stopped/disabled, ensured running and automatic
- Required software: excluded from prohibited-program flagging with a
  reminder to update instead of remove
- Separate mail-server question so SMTP isn't coupled to the web choice

Also, informed by CCS scoring engine research and community guides:

- Never touch services matching CCS/CyberPatriot (scoring client)
- Ensure Security Center (wscsvc) runs ("Action Center enabled" READMEs)
- Report Windows Defender exclusion paths/extensions/processes (planted
  exclusions silently override every scan policy)
- Detect and fix DisableCMD/DisableTaskMgr/DisableRegistryTools sabotage
- Save a gpresult baseline before making changes
- Expand the closing checklist: penalties are recoverable by reverting,
  quality updates only (no Feature Updates/Insider/Reset this PC), never
  touch the CCS client, review scenario app (mail/web) security settings

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Felipezwp

Copy link
Copy Markdown
Author

Pushed a second commit that makes round-specific decisions README-driven, since every round's README differs (e.g. one Server 2022 round required Wireshark, IIS, RDP, and MailEnable to stay, and forbade touching the IME_ADMIN/IME_USER accounts — the previous flagging/password logic would have cost points there):

  • New up-front prompts for README exemptions: untouchable accounts (never removed/demoted/password-reset), critical services (never stopped, ensured running), and required software (excluded from prohibited-app flagging, with a reminder to update instead of remove).
  • The script now refuses to touch any service matching CCS/CyberPatriot — tampering with the scoring client kills scoring feedback.
  • Added sabotage checks informed by scoring-engine research and community guides: Defender exclusion paths/extensions/processes report, DisableCMD/DisableTaskMgr/DisableRegistryTools auto-fix, and a gpresult baseline snapshot before changes.
  • Mail server split into its own question instead of being coupled to the web-server choice; Security Center (wscsvc) ensured running.

General policy items (password age/length/lockout, audit policy, UAC, SMB signing, etc.) stay unconditional since those score the same every round.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant