2222 Maximum age (in days) files must be older than to be removed from temp
2323 locations. Default: 7. Set to 0 to remove everything (use with caution).
2424
25+ . PARAMETER DestructiveMode
26+ When specified, enables destructive operations (disk cleanup, network reset,
27+ CHKDSK repair) without interactive prompts. Use with caution in automated
28+ scenarios. Without this flag, destructive operations require confirmation.
29+
2530. EXAMPLE
2631 .\system-maintenance.ps1 -RunWindowsUpdate -MaxTempFileAgeDays 14
2732
33+ . EXAMPLE
34+ .\system-maintenance.ps1 -DestructiveMode -WhatIf
35+ Preview destructive operations in non-interactive mode.
36+
2837. EXAMPLE
2938 .\system-maintenance.ps1 -WhatIf
3039 Preview all destructive operations without executing them.
3847[CmdletBinding (SupportsShouldProcess = $true , ConfirmImpact = ' Medium' )]
3948param (
4049 [switch ] $RunWindowsUpdate ,
41- [ValidateRange (0 , 3650 )][int ] $MaxTempFileAgeDays = 7
50+ [ValidateRange (0 , 3650 )][int ] $MaxTempFileAgeDays = 7 ,
51+ [switch ] $DestructiveMode
4252)
4353
4454Set-StrictMode - Version Latest
@@ -58,15 +68,8 @@ function Get-LogFilePath {
5868
5969$script :LogFile = Get-LogFilePath
6070
61-
62- # Store the script-level PSCmdlet for use in nested scriptblocks (set in Begin block)
63- $script :ScriptPSCmdlet = $null
64-
65- Begin {
66- if ($null -eq $script :ScriptPSCmdlet -and $null -ne $PSCmdlet ) {
67- $script :ScriptPSCmdlet = $PSCmdlet
68- }
69- }
71+ # Store the script-level PSCmdlet for use in nested scriptblocks
72+ $script :ScriptPSCmdlet = $PSCmdlet
7073
7174# Helper to perform a confirmation check that works even when invoked inside
7275# nested scriptblocks. Uses the script-scoped PSCmdlet reference.
@@ -96,7 +99,12 @@ function Invoke-Step {
9699 Write-Log " BEGIN: $Title "
97100 try {
98101 if ($Destructive.IsPresent -and $ConfirmTarget ) {
99- if (-not ($PSCmdlet.ShouldProcess ($ConfirmTarget , $Title ))) {
102+ # Use script-scoped PSCmdlet with null check
103+ if ($null -eq $script :ScriptPSCmdlet ) {
104+ Write-Log - Message " SKIP: $Title (PSCmdlet not available)" - Level ' WARN'
105+ return
106+ }
107+ if (-not ($script :ScriptPSCmdlet.ShouldProcess ($ConfirmTarget , $Title ))) {
100108 Write-Log - Message " SKIP: $Title (not confirmed)" - Level ' WARN'
101109 return
102110 }
@@ -136,41 +144,7 @@ function Invoke-Step {
136144Write-Log " Starting system maintenance and health checks. Params: RunWindowsUpdate=$RunWindowsUpdate , MaxTempFileAgeDays=$MaxTempFileAgeDays "
137145
138146# --- Destructive Mode Selection ---
139- $DestructiveMode = $false
140- $DestructiveExplanation = @"
141- ==================== DESTRUCTIVE MODE WARNING ====================
142- This script can perform several potentially destructive operations:
143-
144- 1. Disk cleanup (Temp, Cache):
145- - Deletes files from system/user temp folders and Windows Update/Delivery Optimization caches.
146- - Danger: May remove files needed by some applications or pending updates.
147- 2. Network reset:
148- - Resets Winsock, IP stack, and flushes DNS.
149- - Danger: May disrupt network connectivity and require a reboot.
150- 3. CHKDSK repair:
151- - Schedules disk repair on next reboot if errors are found.
152- - Danger: Can cause data loss if disk is failing or interrupted.
153-
154- By default, these steps are run in safe (non-destructive) mode. To enable all destructive operations, choose 'Destructive' when prompted.
155- ==================================================================
156- "@
157-
158- # Only prompt if running interactively and not -WhatIf
159- if (-not $WhatIfPreference -and $Host.UI.RawUI -and $Host.Name -ne ' ServerRemoteHost' ) {
160- Write-Host $DestructiveExplanation - ForegroundColor Yellow
161- $choice = Read-Host " Run in [S]tandard (safe) or [D]estructive (dangerous) mode? [S/D] (default: S)"
162- if ($choice -match ' ^[Dd]' ) {
163- $DestructiveMode = $true
164- Write-Host " Destructive mode ENABLED. Proceeding with all operations." - ForegroundColor Red
165- }
166- else {
167- Write-Host " Standard (safe) mode selected. Destructive steps will be skipped or require extra confirmation." - ForegroundColor Green
168- }
169- }
170- else {
171- # Non-interactive or WhatIf: default to Standard
172- $DestructiveMode = $false
173- }
147+ # Note: Now controlled via -DestructiveMode parameter (no longer prompts interactively)
174148
175149# ---------------------- Windows Update (optional) ----------------------
176150if ($RunWindowsUpdate ) {
@@ -246,10 +220,13 @@ Invoke-Step -Title 'CHKDSK read-only scan and user review' -ScriptBlock {
246220 $affectedSectors | ForEach-Object { Write-Host $_ - ForegroundColor Yellow }
247221 }
248222 Write-Host " Please back up any important files before continuing." - ForegroundColor Yellow
249- $null = Read-Host " Press Enter to continue with disk cleanup or Ctrl+C to abort"
223+ # Use ShouldContinue for non-interactive compatibility
224+ if (-not $script :ScriptPSCmdlet.ShouldContinue (" Continue with disk cleanup after reviewing disk errors?" , " Disk errors were found on $sysDrive " )) {
225+ Write-Output " User chose not to continue with disk cleanup. Exiting maintenance."
226+ return
227+ }
250228 # After user review, offer to schedule repair
251- $scheduleRepair = Read-Host " Would you like to schedule a disk repair on next reboot? [y/N]"
252- if ($scheduleRepair -match ' ^[Yy]' ) {
229+ if ($script :ScriptPSCmdlet.ShouldContinue (" Schedule a disk repair on next reboot?" , " CHKDSK repair" )) {
253230 $repairOutput = cmd / c " chkdsk $sysDrive /F /R" 2>&1 | Out-String
254231 Write-Output $repairOutput
255232 Write-Output ' Repair scheduled. A reboot will be required to complete the repair.'
@@ -266,8 +243,7 @@ Invoke-Step -Title 'CHKDSK read-only scan and user review' -ScriptBlock {
266243 }
267244}
268245
269- if ($DestructiveMode ) {
270- Invoke-Step - Title ' Disk cleanup (Temp, Cache)' - Destructive - ConfirmTarget ' Clean temporary and cache files' - ScriptBlock {
246+ Invoke-Step - Title ' Disk cleanup (Temp, Cache)' - Destructive - ConfirmTarget ' Clean temporary and cache files' - ScriptBlock {
271247 try {
272248 $paths = @ ($env: TEMP , " $env: WINDIR \Temp" , " $env: LOCALAPPDATA \Temp" ) | Where-Object { Test-Path $_ }
273249 $threshold = (Get-Date ).AddDays(-1 * [int ]$MaxTempFileAgeDays )
@@ -287,7 +263,7 @@ if ($DestructiveMode) {
287263 # Windows Update download cache
288264 $wuCache = " $env: WINDIR \SoftwareDistribution\Download"
289265 if (Test-Path $wuCache ) {
290- if (Confirm-Action - Target ' Windows Update download cache' - Action ' Clear cache' ) {
266+ if ($ script :ScriptPSCmdlet .ShouldProcess ( ' Windows Update download cache' , ' Clear cache' ) ) {
291267 # Stop services using proper PowerShell cmdlets
292268 $wuService = Get-Service - Name wuauserv - ErrorAction SilentlyContinue
293269 $bitsService = Get-Service - Name bits - ErrorAction SilentlyContinue
@@ -326,7 +302,7 @@ if ($DestructiveMode) {
326302 # Delivery Optimization
327303 $doPath = " $env: ProgramData \Microsoft\Windows\DeliveryOptimization\Cache"
328304 if (Test-Path $doPath ) {
329- if (Confirm-Action - Target ' Delivery Optimization cache' - Action ' Clear cache' ) {
305+ if ($ script :ScriptPSCmdlet .ShouldProcess ( ' Delivery Optimization cache' , ' Clear cache' ) ) {
330306 Get-ChildItem $doPath - Recurse - Force - ErrorAction SilentlyContinue | Remove-Item - Recurse - Force - ErrorAction SilentlyContinue
331307 Write-Output ' Cleared Delivery Optimization cache'
332308 }
@@ -337,7 +313,6 @@ if ($DestructiveMode) {
337313 Write-Output " Disk cleanup error: $ ( $_.Exception.Message ) "
338314 }
339315 }
340- }
341316
342317Invoke-Step - Title ' Drive optimization (trim/defrag)' - ScriptBlock {
343318 try {
@@ -376,13 +351,13 @@ Invoke-Step -Title 'Drive optimization (trim/defrag)' -ScriptBlock {
376351 }
377352
378353 if ($isSSD ) {
379- if (Confirm-Action - Target " ${letter} : (SSD)" - Action ' ReTrim volume' ) {
354+ if ($ script :ScriptPSCmdlet .ShouldProcess ( " ${letter} : (SSD)" , ' ReTrim volume' ) ) {
380355 Optimize-Volume - DriveLetter $letter - ReTrim - Verbose:$false | Out-Null
381356 Write-Output " Trimmed ${letter} : (SSD)"
382357 }
383358 }
384359 else {
385- if (Confirm-Action - Target " ${letter} : (HDD)" - Action ' Defragment volume' ) {
360+ if ($ script :ScriptPSCmdlet .ShouldProcess ( " ${letter} : (HDD)" , ' Defragment volume' ) ) {
386361 Optimize-Volume - DriveLetter $letter - Defrag - Verbose:$false | Out-Null
387362 Write-Output " Defragmented ${letter} : (HDD)"
388363 }
@@ -418,7 +393,7 @@ Invoke-Step -Title 'Service health checks (BITS, wuauserv, CryptSvc)' -ScriptBlo
418393 if ($null -ne $svc ) {
419394 Write-Output (" {0}: {1}" -f $svc.Name , $svc.Status )
420395 if ($svc.Status -ne ' Running' ) {
421- if (Confirm-Action - Target $ svc.Name - Action ' Start service' ) {
396+ if ($ script :ScriptPSCmdlet .ShouldProcess ( $ svc.Name , ' Start service' ) ) {
422397 Start-Service $svc - ErrorAction SilentlyContinue
423398 Write-Output " Started service: $ ( $svc.Name ) "
424399 }
0 commit comments