-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathReset_WindowsUpdate.cmd
More file actions
1973 lines (1807 loc) · 80.9 KB
/
Copy pathReset_WindowsUpdate.cmd
File metadata and controls
1973 lines (1807 loc) · 80.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
@echo off
setlocal EnableDelayedExpansion
:: ============================================================
:: Windows Update Reset & Repair Tool - Windows 11
:: Full-screen interactive TUI with color-coded menu and step toggles
::
:: References:
:: https://github.com/matbanik/rwu
:: https://matbanik.info/reset-windows-update-guide
:: https://support.microsoft.com/en-us/windows/troubleshoot-problems-updating-windows
:: https://learn.microsoft.com/en-us/troubleshoot/windows-client/installing-updates-features-roles/additional-resources-for-windows-update
:: https://www.elevenforum.com/t/reset-windows-update-in-windows-11.3808
:: Run as Administrator - Right-click > Run as administrator
:: Creates log on the Desktop (or user profile root as fallback)
:: ============================================================
:: Version: bump this before each GitHub release (semver: MAJOR.MINOR.PATCH)
set "ver=1.1.1"
:: ============================================================
:: OPTIONS (change these before running if needed)
:: ============================================================
:: Set to 1 to export and delete WU registry policies (Step 6)
set "RESET_WU_POLICIES=0"
:: Set to 1 to reset BITS/WU service security descriptors (Step 7)
set "RESET_SERVICE_SDDL=0"
:: Set to 1 to enable debug trace logging to Desktop\RWU_Debug.log
set "DEBUG=0"
:: Test mode: TUI navigation only, no workloads, no admin required
set "_TESTMODE=0"
:: Automated key sequence for testing (period-separated errorlevel values)
:: _AUTOKEYS is left UNDEFINED unless /autokeys is passed.
:: This is critical: :Choice uses 'if not defined _AUTOKEYS' to decide
:: whether to call real choice.exe or pop from the autokey sequence.
set /a _AUTOKEY_POS=0
:: ============================================================
:: EARLY HELP CHECK (runs before admin so users can view usage)
:: ============================================================
set "_CLI_MODE=0"
if not "%~1"=="" set "_CLI_MODE=1"
if /I "%~1"=="/help" goto :ShowHelp
if /I "%~1"=="/?" goto :ShowHelp
if /I "%~1"=="-help" goto :ShowHelp
if /I "%~1"=="--help" goto :ShowHelp
:: Early /testmode detection — scan all args before admin check
:: so testmode can skip elevation requirement
for %%A in (%*) do (
if /I "%%~A"=="/testmode" set "_TESTMODE=1"
)
:: ============================================================
:: INITIALIZATION (admin check, log setup, timestamp)
:: ============================================================
:: Check for admin privileges (fltmc is more reliable than net session)
:: Skipped in test mode - TUI navigation only, no system changes
if not "!_TESTMODE!"=="1" (
fltmc >nul 2>&1
if !errorlevel! neq 0 (
echo.
echo *** ERROR: This script must be run as Administrator! ***
echo Right-click the file and choose "Run as administrator"
echo.
if not "!_CLI_MODE!"=="1" pause
exit /b 1
)
)
:: Set log file path with fallback
set "DESKTOP=%USERPROFILE%\Desktop"
if not exist "%DESKTOP%" set "DESKTOP=%USERPROFILE%"
set "LOGFILE=%DESKTOP%\WU_Reset_Log.txt"
set "DEBUGLOG=%DESKTOP%\RWU_Debug.log"
:: Generate timestamp for backups (PowerShell - wmic is deprecated on Win11)
for /f "usebackq" %%I in (`powershell -NoProfile -Command "Get-Date -Format 'yyyyMMdd-HHmmss'"`) do set "TIMESTAMP=%%I"
:: Fallback if PowerShell failed
if not defined TIMESTAMP set "TIMESTAMP=%DATE:~-4%%DATE:~4,2%%DATE:~7,2%-%TIME:~0,2%%TIME:~3,2%%TIME:~6,2%"
:: Strip spaces from pre-10AM timestamps (" 9" -> "09")
if defined TIMESTAMP set "TIMESTAMP=%TIMESTAMP: =0%"
if not defined TIMESTAMP set "TIMESTAMP=unknown"
:: Failure counter (script execution errors)
set /a WARN_COUNT=0
set /a FAIL_COUNT=0
:: Diagnostic findings counter (system health issues found during scan)
set /a DIAG_FINDINGS=0
:: ANSI escape character for spinner and screen control
for /f "delims=" %%a in ('powershell -NoProfile -Command "[char]27"') do set "ESC=%%a"
set /a _SP=0
:: ============================================================
:: CLI ARGUMENT PARSER (for non-interactive / AI agent usage)
:: ============================================================
:: Common variables are initialized above. If CLI mode, parse and dispatch.
if "%_CLI_MODE%"=="1" goto :ParseArgs
:: Console window title and size (interactive only)
title Windows Update Reset Tool %ver%
if not "!_TESTMODE!"=="1" (
mode con: cols=80 lines=35 >nul 2>&1 || (
echo [WARN] Could not set console size. Layout may vary. >> "%LOGFILE%" 2>nul
)
)
:: Initialize debug log if enabled
if "!DEBUG!"=="1" call :DebugInit
call :Trace "INIT: interactive mode, testmode=!_TESTMODE!, goto :MainMenu"
goto :MainMenu
:: --- CLI Argument Parsing ---
:ParseArgs
set "_CLI_ACTION="
set "_CLI_STEP="
:ParseArgsLoop
if "%~1"=="" goto :RunCLI
if /I "%~1"=="/help" goto :ShowHelp
if /I "%~1"=="/?" goto :ShowHelp
if /I "%~1"=="-help" goto :ShowHelp
if /I "%~1"=="--help" goto :ShowHelp
if /I "%~1"=="/diag" (
if defined _CLI_ACTION (
echo ERROR: Conflicting actions: /!_CLI_ACTION! and /diag
echo Only one action allowed. Use /help for usage.
endlocal & exit /b 1
)
set "_CLI_ACTION=diag" & shift & goto :ParseArgsLoop
)
if /I "%~1"=="/reset" (
if defined _CLI_ACTION (
echo ERROR: Conflicting actions: /!_CLI_ACTION! and /reset
echo Only one action allowed. Use /help for usage.
endlocal & exit /b 1
)
set "_CLI_ACTION=reset" & shift & goto :ParseArgsLoop
)
if /I "%~1"=="/policy" ( set "RESET_WU_POLICIES=1" & shift & goto :ParseArgsLoop )
if /I "%~1"=="/sddl" ( set "RESET_SERVICE_SDDL=1" & shift & goto :ParseArgsLoop )
if /I "%~1"=="/debug" ( set "DEBUG=1" & shift & goto :ParseArgsLoop )
if /I "%~1"=="/testmode" ( set "_TESTMODE=1" & shift & goto :ParseArgsLoop )
if /I "%~1"=="/autokeys" ( set "_AUTOKEYS=%~2" & shift & shift & goto :ParseArgsLoop )
if /I "%~1"=="/step" (
if defined _CLI_ACTION (
echo ERROR: Conflicting actions: /!_CLI_ACTION! and /step
echo Only one action allowed. Use /help for usage.
endlocal & exit /b 1
)
if "%~2"=="" (
echo ERROR: /step requires a step number. Example: /step 3
endlocal & exit /b 1
)
set "_CLI_ACTION=step"
set "_CLI_STEP=%~2"
shift & shift & goto :ParseArgsLoop
)
if /I "%~1"=="/fix" (
if defined _CLI_ACTION (
echo ERROR: Conflicting actions: /!_CLI_ACTION! and /fix
echo Only one action allowed. Use /help for usage.
endlocal & exit /b 1
)
if "%~2"=="" (
echo ERROR: /fix requires a target. Example: /fix dism
echo Valid targets: dism, sfc, combo, chkdsk, proxy
endlocal & exit /b 1
)
set "_CLI_ACTION=fix"
set "_CLI_FIX=%~2"
shift & shift & goto :ParseArgsLoop
)
if /I "%~1"=="/logdir" (
if "%~2"=="" (
echo ERROR: /logdir requires a path. Example: /logdir "C:\Temp"
endlocal & exit /b 1
)
set "_CLI_LOGDIR=%~2"
shift & shift & goto :ParseArgsLoop
)
echo ERROR: Unknown argument: %~1
echo Run with /help for usage.
endlocal & exit /b 1
:RunCLI
:: Apply custom log directory if specified
if defined _CLI_LOGDIR (
if not exist "!_CLI_LOGDIR!" (
echo ERROR: Log directory does not exist: !_CLI_LOGDIR!
endlocal & exit /b 1
)
set _CLI_LOGDIR 2>nul | findstr /C:"!" >nul 2>&1 && (
echo ERROR: Log path cannot contain '!' characters.
endlocal & exit /b 1
)
set "LOGFILE=!_CLI_LOGDIR!\WU_Reset_Log.txt"
set "DEBUGLOG=!_CLI_LOGDIR!\RWU_Debug.log"
)
:: Initialize debug log if enabled (CLI mode)
if "!DEBUG!"=="1" call :DebugInit
call :Trace "INIT: CLI mode, action=!_CLI_ACTION!"
if not defined _CLI_ACTION (
if "!_TESTMODE!"=="1" (
:: No action specified but testmode active - enter interactive TUI
call :Trace "INIT: testmode active, no CLI action, entering TUI"
set "_CLI_MODE=0"
goto :MainMenu
)
echo ERROR: No action specified. Use /diag, /reset, /step N, or /fix TARGET.
echo Run with /help for usage.
endlocal & exit /b 1
)
if /I "!_CLI_ACTION!"=="diag" goto :DiagnosticsOnly
if /I "!_CLI_ACTION!"=="reset" goto :FullReset
if /I "!_CLI_ACTION!"=="step" (
if /I "!_CLI_STEP!"=="0" goto :DiagnosticsOnly
if /I "!_CLI_STEP!"=="1" goto :RunStopServices
if /I "!_CLI_STEP!"=="2" goto :RunStopServices
if /I "!_CLI_STEP!"=="1-2" goto :RunStopServices
if /I "!_CLI_STEP!"=="3" goto :RunStep3
if /I "!_CLI_STEP!"=="4" goto :RunStep4
if /I "!_CLI_STEP!"=="5" goto :RunStep5
if /I "!_CLI_STEP!"=="6" goto :RunStep6
if /I "!_CLI_STEP!"=="7" goto :RunStep7
if /I "!_CLI_STEP!"=="8" goto :RunStep8
if /I "!_CLI_STEP!"=="9" goto :RunNetwork
if /I "!_CLI_STEP!"=="9-10" goto :RunNetwork
if /I "!_CLI_STEP!"=="10" goto :RunNetwork
if /I "!_CLI_STEP!"=="11" goto :RunFinalize
if /I "!_CLI_STEP!"=="11-14" goto :RunFinalize
if /I "!_CLI_STEP!"=="finalize" goto :RunFinalize
echo ERROR: Unknown step: !_CLI_STEP!
echo Valid steps: 0, 1-2, 3, 4, 5, 6, 7, 8, 9-10, 11-14, finalize
endlocal & exit /b 1
)
if /I "!_CLI_ACTION!"=="fix" (
if /I "!_CLI_FIX!"=="dism" goto :RunFixDISM
if /I "!_CLI_FIX!"=="sfc" goto :RunFixSFC
if /I "!_CLI_FIX!"=="combo" goto :RunFixCombo
if /I "!_CLI_FIX!"=="chkdsk" goto :RunFixCHKDSK
if /I "!_CLI_FIX!"=="proxy" goto :RunFixProxy
echo ERROR: Unknown fix target: !_CLI_FIX!
echo Valid targets: dism, sfc, combo, chkdsk, proxy
endlocal & exit /b 1
)
echo ERROR: Unknown action: !_CLI_ACTION!
endlocal & exit /b 1
:: ============================================================
:: MAIN MENU
:: ============================================================
:MainMenu
call :Trace "entering :MainMenu"
:: Toggle state is read directly below via ANSI-colored labels
call :BlankScreen
color 0A
echo.
echo: ================================================================
echo:
echo: Windows Update Reset ^& Repair Tool v%ver%
echo: ________________________________________________________
echo:
echo: [1] Diagnostics Only
echo: Collect full system health snapshot, no changes.
echo:
echo: [2] Full WU Reset
echo: Run standard reset ^(Steps 0-14^). Steps 6/7
echo: only run if their toggles are ON below.
echo:
echo: [3] Advanced ^>
echo: Pick individual steps to run.
echo:
echo: [S] System Fixes ^>
echo: DISM, SFC, CHKDSK — repair underlying system issues.
echo: ________________________________________________________
echo:
:: Build colored toggle labels (OFF=gray, ON=yellow)
if "!RESET_WU_POLICIES!"=="1" (set "_WU_COL=!ESC![93m[ON]!ESC![92m") else (set "_WU_COL=!ESC![90m[OFF]!ESC![92m")
if "!RESET_SERVICE_SDDL!"=="1" (set "_SDDL_COL=!ESC![93m[ON]!ESC![92m") else (set "_SDDL_COL=!ESC![90m[OFF]!ESC![92m")
if "!DEBUG!"=="1" (set "_DBG_COL=!ESC![93m[ON]!ESC![92m") else (set "_DBG_COL=!ESC![90m[OFF]!ESC![92m")
<nul set /p "=!ESC![10C[4] Delete WU policy keys after backup !_WU_COL!"
echo.
<nul set /p "=!ESC![10C[5] Reset BITS/WU service permissions !_SDDL_COL!"
echo.
echo: [6] Change Log Folder
echo: [7] Help
<nul set /p "=!ESC![10C[8] Debug trace log !_DBG_COL!"
echo.
echo: ________________________________________________________
echo:
echo: [0] Exit
echo:
echo: ================================================================
for %%F in ("%LOGFILE%") do set "_LOGNAME=%%~nxF"&set "_LOGDIR=%%~dpF"
if defined _LOGDIR set "_LOGDIR=!_LOGDIR:~0,-1!"
echo: Log: ...\!_LOGNAME!
echo: Dir: !_LOGDIR!
echo: ================================================================
echo.
call :Trace "MainMenu: waiting for choice"
call :Choice /C:12345678S0 /N /M " Choose an option [1,2,3,4,5,6,7,8,S,0]: "
if not defined _AUTOKEYS set "_erl=!errorlevel!"
call :Trace "MainMenu: choice returned !_erl!"
if !_erl!==10 ( call :Trace "MainMenu: exit" & endlocal & exit /b 0 )
if !_erl!==9 ( call :Trace "MainMenu: goto :SystemFixesMenu" & goto :SystemFixesMenu )
if !_erl!==8 ( call :Trace "MainMenu: goto :ToggleDebug" & goto :ToggleDebug )
if !_erl!==7 ( call :Trace "MainMenu: goto :ShowHelp" & goto :ShowHelp )
if !_erl!==6 ( call :Trace "MainMenu: goto :ChangeLogFolder" & goto :ChangeLogFolder )
if !_erl!==5 ( call :Trace "MainMenu: goto :ToggleSDDL" & goto :ToggleSDDL )
if !_erl!==4 ( call :Trace "MainMenu: goto :ToggleWUPolicy" & goto :ToggleWUPolicy )
if !_erl!==3 ( call :Trace "MainMenu: goto :AdvancedMenu" & goto :AdvancedMenu )
if !_erl!==2 ( call :Trace "MainMenu: goto :FullReset" & goto :FullReset )
if !_erl!==1 ( call :Trace "MainMenu: goto :DiagnosticsOnly" & goto :DiagnosticsOnly )
call :Trace "MainMenu: no match, looping"
goto :MainMenu
:: ============================================================
:: HELP SCREEN (shared by CLI /help and menu [7])
:: ============================================================
:ShowHelp
:: CLI mode: dump all help at once (terminal scrolls)
if "!_CLI_MODE!"=="1" goto :ShowHelpFull
:: Interactive mode: paginate across two screens
call :Trace "entering :ShowHelp (interactive, page 1)"
:: --- Page 1: Actions, Fix Targets, Step Numbers ---
call :BlankScreen
echo.
echo ================================================================
echo Windows Update Reset ^& Repair Tool v%ver% - Help (1/2)
echo ================================================================
echo.
echo INTERACTIVE: Run with no arguments for the menu UI.
echo CLI: Reset_WindowsUpdate.cmd [action] [options]
echo.
echo ACTIONS: STEP NUMBERS:
echo /diag Diagnostics only 0 System Diagnostics
echo /reset Full reset (0-14) 1-2 Stop services
echo /step N Run specific step 3 Delete BITS queue
echo /fix T Run system fix 4 Rename cache folders
echo 5 Reset BITS queue
echo FIX TARGETS: 6 Reset WU policies
echo dism DISM RestoreHealth 7 Reset service SDDL
echo sfc System File Checker 8 Re-register DLLs
echo combo DISM then SFC 9-10 Network reset
echo chkdsk Schedule disk check 11-14 or finalize
echo proxy Reset WinHTTP proxy
echo.
echo ================================================================
echo.
call :Choice /C:NM /N /M " [N]ext page [M]ain Menu: "
if not defined _AUTOKEYS set "_erl=!errorlevel!"
if !_erl!==2 goto :MainMenu
:: --- Page 2: Options, Examples, Notes ---
call :Trace "ShowHelp: page 2"
call :BlankScreen
echo.
echo ================================================================
echo Windows Update Reset ^& Repair Tool v%ver% - Help (2/2)
echo ================================================================
echo.
echo OPTIONS:
echo /policy Enable policy reset
echo /sddl Enable SDDL reset
echo /debug Enable debug trace log
echo /logdir P Set log folder
echo: /help /? This help
echo.
echo WARNING: /policy and /sddl bypass confirmation prompts.
echo They delete registry keys and overwrite service permissions.
echo.
echo EXAMPLES:
echo Reset_WindowsUpdate.cmd /diag
echo Reset_WindowsUpdate.cmd /reset /policy /sddl
echo Reset_WindowsUpdate.cmd /step 3
echo Reset_WindowsUpdate.cmd /fix combo
echo Reset_WindowsUpdate.cmd /diag /logdir "C:\Temp"
echo.
echo NOTES:
echo - Admin required (except /help). Log: WU_Reset_Log.txt
echo - Steps 6/7 skipped unless /policy or /sddl is set
echo - /logdir must exist; exclamation mark in path rejected
echo - CLI exits: 0=success, 1=failure, 2=warnings only
echo.
echo ================================================================
echo.
echo Press any key to return to Main Menu...
if not "!_TESTMODE!"=="1" pause >nul
goto :MainMenu
:: --- CLI mode: single dump (no pagination) ---
:ShowHelpFull
echo.
echo ================================================================
echo Windows Update Reset ^& Repair Tool v%ver% - Help
echo ================================================================
echo.
echo INTERACTIVE: Run with no arguments for the menu UI.
echo CLI: Reset_WindowsUpdate.cmd [action] [options]
echo.
echo ACTIONS: STEP NUMBERS:
echo /diag Diagnostics only 0 System Diagnostics
echo /reset Full reset (0-14) 1-2 Stop services
echo /step N Run specific step 3 Delete BITS queue
echo /fix T Run system fix 4 Rename cache folders
echo 5 Reset BITS queue
echo FIX TARGETS: 6 Reset WU policies
echo dism DISM RestoreHealth 7 Reset service SDDL
echo sfc System File Checker 8 Re-register DLLs
echo combo DISM then SFC 9-10 Network reset
echo chkdsk Schedule disk check 11-14 or finalize
echo proxy Reset WinHTTP proxy
echo.
echo OPTIONS:
echo /policy Enable policy reset
echo /sddl Enable SDDL reset
echo /debug Enable debug trace log
echo /logdir P Set log folder
echo: /help /? This help
echo WARNING: /policy and /sddl bypass confirmation prompts.
echo They delete registry keys and overwrite service permissions.
echo.
echo EXAMPLES:
echo Reset_WindowsUpdate.cmd /diag
echo Reset_WindowsUpdate.cmd /reset /policy /sddl
echo Reset_WindowsUpdate.cmd /step 3
echo Reset_WindowsUpdate.cmd /fix combo
echo Reset_WindowsUpdate.cmd /diag /logdir "C:\Temp"
echo.
echo NOTES:
echo - Admin required (except /help). Log: WU_Reset_Log.txt
echo - Steps 6/7 skipped unless /policy or /sddl is set
echo - /logdir must exist; exclamation mark in path rejected
echo - CLI exits: 0=success, 1=failure, 2=warnings only
echo.
echo ================================================================
endlocal
exit /b 0
:: --- Debug toggle ---
:ToggleDebug
call :Trace "entering :ToggleDebug"
if "!DEBUG!"=="0" (
set "DEBUG=1"
call :DebugInit
call :Trace "DEBUG enabled via menu toggle"
) else (
call :Trace "DEBUG disabled via menu toggle"
set "DEBUG=0"
)
goto :MainMenu
:: --- Toggle with confirmation ---
:ToggleWUPolicy
if "!RESET_WU_POLICIES!"=="0" (
call :BlankScreen
echo.
echo ================================================================
echo WARNING: Delete WU Policy Registry Keys
echo ================================================================
echo.
echo This will DELETE Windows Update registry policies.
echo This can remove WSUS, Intune, and WUfB configuration.
echo Do not enable on work/school-managed PCs unless instructed.
echo.
echo Note: This only enables Step 6 for the next action you run.
echo.
echo ================================================================
echo.
call :Choice /C:YN /N /M " Enable WU Policy Reset? [Y/N]: "
if not defined _AUTOKEYS set "_erl=!errorlevel!"
if !_erl!==1 set "RESET_WU_POLICIES=1"
) else (
set "RESET_WU_POLICIES=0"
)
goto :MainMenu
:ToggleSDDL
if "!RESET_SERVICE_SDDL!"=="0" (
call :BlankScreen
echo.
echo ================================================================
echo WARNING: Reset BITS/WU Service Permissions
echo ================================================================
echo.
echo This will OVERWRITE BITS and WU service ACLs with hardcoded
echo default SDDLs. Build-specific or vendor ACLs will be lost.
echo Originals are logged first.
echo Do not enable unless standard reset failed or instructed.
echo.
echo Note: This only enables Step 7 for the next action you run.
echo.
echo ================================================================
echo.
call :Choice /C:YN /N /M " Enable Service SDDL Reset? [Y/N]: "
if not defined _AUTOKEYS set "_erl=!errorlevel!"
if !_erl!==1 set "RESET_SERVICE_SDDL=1"
) else (
set "RESET_SERVICE_SDDL=0"
)
goto :MainMenu
:: ============================================================
:: ADVANCED MENU - Pick individual steps
:: ============================================================
:AdvancedMenu
call :Trace "entering :AdvancedMenu"
call :BlankScreen
echo.
echo: ================================================================
echo: Advanced: Run Individual Steps
echo: ================================================================
echo:
echo: Diagnostics:
echo: [1] Step 0 - System Diagnostics
echo:
echo: Core Reset:
echo: [2] Step 1-2 - Record config + Stop services
echo: [3] Step 3 - Delete BITS queue data
echo: [4] Step 4 - Rename WU cache folders ^(run 2 first^)
echo: [5] Step 5 - Reset BITS transfer queue
if "!RESET_WU_POLICIES!"=="1" (
echo: [6] Step 6 - Reset WU policies
) else (
<nul set /p "=!ESC![10C!ESC![90m[OFF] Step 6 - Reset WU policies!ESC![92m"
echo.
)
if "!RESET_SERVICE_SDDL!"=="1" (
echo: [7] Step 7 - Reset service permissions
) else (
<nul set /p "=!ESC![10C!ESC![90m[OFF] Step 7 - Reset service permissions!ESC![92m"
echo.
)
echo: [8] Step 8 - Re-register WU DLLs
echo:
echo: Network:
echo: [9] Step 9-10 - Reset Winsock + Flush DNS
echo:
echo: Finalize:
echo: [A] Step 11-14 - Restart services + post-reset checks
echo: ________________________________________________________
echo: NOTE: If you stop services or run repair steps,
echo: run [A] Finalize before exiting.
echo:
echo: [0] Back to Main Menu
echo:
echo: ================================================================
echo.
call :Choice /C:1234567890A /N /M " Choose a step [1-9,A,0]: "
if not defined _AUTOKEYS set "_erl=!errorlevel!"
if !_erl!==11 goto :RunFinalize
if !_erl!==10 goto :MainMenu
if !_erl!==9 goto :RunNetwork
if !_erl!==8 goto :RunStep8
if !_erl!==7 goto :RunStep7
if !_erl!==6 goto :RunStep6
if !_erl!==5 goto :RunStep5
if !_erl!==4 goto :RunStep4
if !_erl!==3 goto :RunStep3
if !_erl!==2 goto :RunStopServices
if !_erl!==1 goto :DiagnosticsOnly
goto :AdvancedMenu
:: ============================================================
:: SYSTEM FIXES MENU
:: ============================================================
:SystemFixesMenu
call :Trace "entering :SystemFixesMenu"
call :BlankScreen
echo.
echo: ================================================================
echo: System Fixes: Repair Underlying System Issues
echo: ================================================================
echo:
echo: These commands repair system-level corruption that
echo: prevents Windows Update from functioning correctly.
echo: Run them AFTER a WU reset if updates still fail.
echo:
echo: [1] DISM - Repair Component Store
echo: Repairs the Windows system image. (10-30 min)
echo: Requires internet to download repairs.
echo:
echo: [2] SFC - Scan ^& Repair System Files
echo: Scans and repairs protected OS files. (5-15 min)
echo:
echo: [3] DISM + SFC Combo (recommended)
echo: Runs DISM first, then SFC - correct order. (15-45 min)
echo:
echo: [4] CHKDSK - Schedule Disk Check
echo: Schedules disk repair on next reboot. (30-120 min)
echo: Requires reboot. Do NOT interrupt once started.
echo:
echo: [5] Reset Proxy Settings
echo: Resets WinHTTP proxy to direct connection.
echo: ________________________________________________________
echo:
echo: [0] Back to Main Menu
echo:
echo: ================================================================
echo.
call :Choice /C:123450 /N /M " Choose a fix [1-5,0]: "
if not defined _AUTOKEYS set "_erl=!errorlevel!"
if !_erl!==6 goto :MainMenu
if !_erl!==5 goto :RunFixProxy
if !_erl!==4 goto :RunFixCHKDSK
if !_erl!==3 goto :RunFixCombo
if !_erl!==2 goto :RunFixSFC
if !_erl!==1 goto :RunFixDISM
goto :SystemFixesMenu
:: ============================================================
:: CHANGE LOG FOLDER
:: ============================================================
:: NOTE: Input is read with delayed expansion OFF to protect special chars.
:: Paths containing ! are explicitly rejected since the rest of the script
:: uses EnableDelayedExpansion which would mangle them.
:ChangeLogFolder
call :BlankScreen
echo.
echo: ================================================================
echo: Change Log Output Folder
echo: ================================================================
echo:
echo: Current log file:
echo: %LOGFILE%
echo:
echo: Enter a new folder path, or type 0 to go back.
echo: The folder must already exist. Cannot contain '!'.
echo: Quotes are OK if pasted.
echo:
echo: Examples:
echo: C:\Temp
echo: D:\Diagnostics
echo: C:\Users\YourName\Documents
echo:
echo: [0] Back to Main Menu
echo: ================================================================
echo.
:: Read input with delayed expansion OFF to protect ! in paths
setlocal DisableDelayedExpansion
set "_newpath="
set /p "_newpath= New folder path (or 0): "
if not defined _newpath endlocal & goto :MainMenu
if "%_newpath%"=="0" endlocal & goto :MainMenu
:: Strip surrounding quotes if pasted from Explorer
set "_newpath=%_newpath:"=%"
:: Trim trailing backslash
if "%_newpath:~-1%"=="\" set "_newpath=%_newpath:~0,-1%"
:: Validate path exists
if not exist "%_newpath%\" (
echo.
echo ERROR: Folder "%_newpath%" does not exist.
echo Press any key to try again...
pause >nul
endlocal & goto :ChangeLogFolder
)
:: Reject paths containing ! (delayed expansion would mangle them).
:: Use 'set _newpath' which safely outputs name=value without parsing
:: metacharacters like & | < > in the path string.
set _newpath 2>nul | findstr /C:"!" >nul 2>&1 && (
echo.
echo ERROR: Path cannot contain '!' characters.
echo Press any key to try again...
pause >nul
endlocal & goto :ChangeLogFolder
)
:: Promote path out of DisableDelayedExpansion scope
endlocal & set "LOGFILE=%_newpath%\WU_Reset_Log.txt"
echo.
echo Log file set to: %LOGFILE%
echo Press any key to return to menu...
pause >nul
goto :MainMenu
:: ============================================================
:: FLOW TARGETS - These set up the log and jump to step code
:: ============================================================
:DiagnosticsOnly
call :Trace "entering :DiagnosticsOnly"
set "_FULLRESET=0"
set "_STOP_AFTER=Step0"
set "_RUN_LABEL=Diagnostics Only"
if "!_TESTMODE!"=="1" (
call :Trace "TESTMODE: skip workload, goto :StepDone"
goto :StepDone
)
call :InitLog
goto :Step0
:FullReset
call :Trace "entering :FullReset"
set "_FULLRESET=1"
set "_STOP_AFTER=Step14"
set "_RUN_LABEL=Full WU Reset (standard flow; optional steps by toggle)"
if "!_TESTMODE!"=="1" (
call :Trace "TESTMODE: skip workload, goto :StepDone"
goto :StepDone
)
call :InitLog
goto :Step0
:: --- Initialize the log file header ---
:: Regenerate timestamp each run so backups don't collide
:InitLog
for /f "usebackq" %%I in (`powershell -NoProfile -Command "Get-Date -Format 'yyyyMMdd-HHmmss'"`) do set "TIMESTAMP=%%I"
if defined TIMESTAMP set "TIMESTAMP=!TIMESTAMP: =0!"
echo. >> "%LOGFILE%"
echo ============================================================ >> "%LOGFILE%"
echo Windows Update Reset Log >> "%LOGFILE%"
echo Action: !_RUN_LABEL! >> "%LOGFILE%"
echo Computer: %COMPUTERNAME% >> "%LOGFILE%"
echo User: %USERNAME% >> "%LOGFILE%"
echo Date: %DATE% %TIME% >> "%LOGFILE%"
echo Backup Timestamp: !TIMESTAMP! >> "%LOGFILE%"
echo ============================================================ >> "%LOGFILE%"
echo. >> "%LOGFILE%"
echo NOTICE: This log may contain system identifiers, network >> "%LOGFILE%"
echo configuration, and license details. Treat as sensitive if >> "%LOGFILE%"
echo sharing outside the immediate troubleshooting context. >> "%LOGFILE%"
echo. >> "%LOGFILE%"
exit /b
:: --- Run individual steps from Advanced menu ---
:: Each target sets _STOP_AFTER to prevent fall-through
:RunStopServices
set "_STOP_AFTER=Step2"
set "_RUN_LABEL=Steps 1-2: Record config + Stop services"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunStopServices" & goto :StepDone )
call :InitLog
goto :Step1
:RunStep3
set "_STOP_AFTER=Step3"
set "_RUN_LABEL=Step 3: Delete BITS queue data"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunStep3" & goto :StepDone )
call :InitLog
goto :Step3
:RunStep4
set "_STOP_AFTER=Step4"
set "_RUN_LABEL=Step 4: Rename WU cache folders"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunStep4" & goto :StepDone )
call :InitLog
goto :Step4
:RunStep5
set "_STOP_AFTER=Step5"
set "_RUN_LABEL=Step 5: Reset BITS transfer queue"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunStep5" & goto :StepDone )
call :InitLog
goto :Step5
:RunStep6
set "_STOP_AFTER=Step6"
set "_RUN_LABEL=Step 6: WU policy reset (runs only if toggle ON)"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunStep6" & goto :StepDone )
call :InitLog
goto :Step6
:RunStep7
set "_STOP_AFTER=Step7"
set "_RUN_LABEL=Step 7: Service permissions reset (runs only if toggle ON)"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunStep7" & goto :StepDone )
call :InitLog
goto :Step7
:RunStep8
set "_STOP_AFTER=Step8"
set "_RUN_LABEL=Step 8: Re-register WU DLLs"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunStep8" & goto :StepDone )
call :InitLog
goto :Step8
:RunNetwork
set "_STOP_AFTER=Step10"
set "_RUN_LABEL=Steps 9-10: Reset Winsock + Flush DNS"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunNetwork" & goto :StepDone )
call :InitLog
goto :Step9
:RunFinalize
set "_STOP_AFTER=Step14"
set "_RUN_LABEL=Steps 11-14: Restart services + post-reset checks"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunFinalize" & goto :StepDone )
call :InitLog
goto :Step11
:: --- System Fix flow targets ---
:: Each sets _STOP_AFTER and _RUN_LABEL, then jumps to workload
:RunFixDISM
set "_STOP_AFTER=FixDISM"
set "_RUN_LABEL=System Fix: DISM Repair Component Store"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunFixDISM" & goto :StepDone )
call :InitLog
goto :FixDISM
:RunFixSFC
set "_STOP_AFTER=FixSFC"
set "_RUN_LABEL=System Fix: SFC System File Checker"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunFixSFC" & goto :StepDone )
call :InitLog
goto :FixSFC
:RunFixCombo
set "_STOP_AFTER=FixSFC"
set "_RUN_LABEL=System Fix: DISM + SFC Combo (recommended order)"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunFixCombo" & goto :StepDone )
call :InitLog
goto :FixDISM
:RunFixCHKDSK
set "_STOP_AFTER=FixCHKDSK"
set "_RUN_LABEL=System Fix: Schedule CHKDSK on Next Reboot"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunFixCHKDSK" & goto :StepDone )
call :InitLog
goto :FixCHKDSK
:RunFixProxy
set "_STOP_AFTER=FixProxy"
set "_RUN_LABEL=System Fix: Reset WinHTTP Proxy Settings"
if "!_TESTMODE!"=="1" ( call :Trace "TESTMODE: skip RunFixProxy" & goto :StepDone )
call :InitLog
goto :FixProxy
:: -----------------------------------------------
:: STEP 0: Capture system diagnostics
:: -----------------------------------------------
:Step0
echo [STEP 0] Capturing system diagnostics...
echo ------------------------------------------------------------ >> "%LOGFILE%"
echo [STEP 0] System Diagnostics >> "%LOGFILE%"
echo ------------------------------------------------------------ >> "%LOGFILE%"
echo. >> "%LOGFILE%"
call :Spin
:: --- 0a: OS Identity ---
echo --- 0a: OS Version and Build --- >> "%LOGFILE%"
ver >> "%LOGFILE%" 2>&1
powershell -NoProfile -Command "Get-ComputerInfo | Select-Object OsName, OsVersion, OsBuildNumber, WindowsVersion, OsArchitecture, OsProductType, OsRegisteredUser, OsInstallDate, OsLastBootUpTime | Format-List" >> "%LOGFILE%" 2>&1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0b: Windows Edition and Activation ---
echo --- 0b: Edition and Activation Status --- >> "%LOGFILE%"
powershell -NoProfile -Command "Get-CimInstance SoftwareLicensingProduct -Filter 'ApplicationID=''55c92734-d682-4d71-983e-d6ec3f16059f'' AND PartialProductKey IS NOT NULL' | Select-Object Name, @{N='LicenseStatus';E={switch([int]$_.LicenseStatus){0{'Unlicensed'}1{'Licensed'}2{'OOB Grace'}3{'OOT Grace'}4{'Non-Genuine Grace'}5{'Notification'}6{'Extended Grace'}default{$_.LicenseStatus}}}}, Description | Format-List" >> "%LOGFILE%" 2>&1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0c: Insider Program Status ---
echo --- 0c: Windows Insider Status --- >> "%LOGFILE%"
reg query "HKLM\SOFTWARE\Microsoft\WindowsSelfHost\Applicability" /v BranchName >nul 2>&1
if !errorlevel! equ 0 (
echo Insider Program: ENROLLED >> "%LOGFILE%"
reg query "HKLM\SOFTWARE\Microsoft\WindowsSelfHost\Applicability" /v BranchName >> "%LOGFILE%" 2>&1
reg query "HKLM\SOFTWARE\Microsoft\WindowsSelfHost\Applicability" /v Ring >> "%LOGFILE%" 2>&1
reg query "HKLM\SOFTWARE\Microsoft\WindowsSelfHost\Applicability" /v ContentType >> "%LOGFILE%" 2>&1
set /a DIAG_FINDINGS+=1
) else (
echo Insider Program: Not enrolled >> "%LOGFILE%"
)
echo. >> "%LOGFILE%"
call :Spin
:: --- 0d: Hardware - CPU and RAM ---
echo --- 0d: CPU and Memory --- >> "%LOGFILE%"
powershell -NoProfile -Command "Get-CimInstance Win32_Processor | Select-Object Name, NumberOfCores, NumberOfLogicalProcessors | Format-List" >> "%LOGFILE%" 2>&1
powershell -NoProfile -Command "$m = Get-CimInstance Win32_PhysicalMemory; $total = ($m | Measure-Object Capacity -Sum).Sum / 1GB; Write-Output \" Total RAM: $total GB Sticks: $($m.Count)\"; $m | Select-Object DeviceLocator, @{N='CapacityGB';E={[math]::Round($_.Capacity/1GB)}}, Speed, Manufacturer | Format-Table -AutoSize | Out-String -Width 200" >> "%LOGFILE%" 2>&1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0e: Disk Health (SMART + Reliability) ---
echo --- 0e: Disk Health --- >> "%LOGFILE%"
powershell -NoProfile -Command "Get-PhysicalDisk | Select-Object FriendlyName, MediaType, BusType, HealthStatus, OperationalStatus, @{N='SizeGB';E={[math]::Round($_.Size/1GB,1)}} | Format-Table -AutoSize | Out-String -Width 200" >> "%LOGFILE%" 2>&1
powershell -NoProfile -Command "Get-PhysicalDisk | Get-StorageReliabilityCounter -ErrorAction SilentlyContinue | Select-Object DeviceId, ReadErrorsTotal, WriteErrorsTotal, Wear, Temperature, PowerOnHours | Format-Table -AutoSize | Out-String -Width 200" >> "%LOGFILE%" 2>&1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0f: Disk Space (all drives) ---
echo --- 0f: Disk Space --- >> "%LOGFILE%"
powershell -NoProfile -Command "$disks = Get-CimInstance Win32_LogicalDisk -Filter 'DriveType=3' | Select-Object DeviceID, @{N='SizeGB';E={[math]::Round($_.Size/1GB,1)}}, @{N='FreeGB';E={[math]::Round($_.FreeSpace/1GB,1)}}, @{N='FreePercent';E={[math]::Round($_.FreeSpace/$_.Size*100,1)}}; $disks | Format-Table -AutoSize | Out-String -Width 200; $crit = $disks | Where-Object { $_.FreePercent -lt 5 }; foreach ($d in $crit) { Write-Output \" FINDING: $($d.DeviceID) critically low ($($d.FreePercent)%% free)\" }; if ($crit) { exit 1 } else { exit 0 }" >> "%LOGFILE%" 2>&1
if !errorlevel! neq 0 set /a DIAG_FINDINGS+=1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0g: Component Store Health (quick check) ---
echo --- 0g: Component Store Health --- >> "%LOGFILE%"
:: Capture DISM output to temp file to avoid scanning the entire appended log
set "_DISM_TMP=%TEMP%\rwu_dism_%RANDOM%.txt"
DISM /Online /Cleanup-Image /CheckHealth > "!_DISM_TMP!" 2>&1
set "_dism_erl=!errorlevel!"
type "!_DISM_TMP!" >> "%LOGFILE%"
echo DISM CheckHealth exit code: !_dism_erl! >> "%LOGFILE%"
if !_dism_erl! neq 0 (
echo FINDING: Component store needs repair >> "%LOGFILE%"
set /a DIAG_FINDINGS+=1
)
:: Check only the DISM temp output for "repairable" (not the whole log)
findstr /I "repairable" "!_DISM_TMP!" >nul 2>&1
if !errorlevel! equ 0 if !_dism_erl! equ 0 (
echo FINDING: Component store is repairable >> "%LOGFILE%"
set /a DIAG_FINDINGS+=1
)
del "!_DISM_TMP!" >nul 2>&1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0h: Pending Reboot Check ---
echo --- 0h: Pending Reboot Flags --- >> "%LOGFILE%"
set "_reboot_needed=0"
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending" >nul 2>&1
if !errorlevel! equ 0 (echo CBS RebootPending: YES >> "%LOGFILE%"& set "_reboot_needed=1") else (echo CBS RebootPending: No >> "%LOGFILE%")
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootInProgress" >nul 2>&1
if !errorlevel! equ 0 (echo CBS RebootInProgress: YES >> "%LOGFILE%"& set "_reboot_needed=1") else (echo CBS RebootInProgress: No >> "%LOGFILE%")
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired" >nul 2>&1
if !errorlevel! equ 0 (echo WU RebootRequired: YES >> "%LOGFILE%"& set "_reboot_needed=1") else (echo WU RebootRequired: No >> "%LOGFILE%")
reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager" /v PendingFileRenameOperations >nul 2>&1
if !errorlevel! equ 0 (echo PendingFileRename: YES >> "%LOGFILE%"& set "_reboot_needed=1") else (echo PendingFileRename: No >> "%LOGFILE%")
if "!_reboot_needed!"=="1" (
echo FINDING: Pending reboot detected >> "%LOGFILE%"
set /a DIAG_FINDINGS+=1
)
echo. >> "%LOGFILE%"
call :Spin
:: --- 0i: Windows Update Configuration (registry) ---
echo --- 0i: Windows Update Registry Config --- >> "%LOGFILE%"
echo --- AU Settings --- >> "%LOGFILE%"
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" >> "%LOGFILE%" 2>&1
echo. >> "%LOGFILE%"
echo --- WU Server (WSUS) --- >> "%LOGFILE%"
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" >nul 2>&1
if !errorlevel! equ 0 (
echo WSUS/WUfB policy detected: >> "%LOGFILE%"
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v WUServer >> "%LOGFILE%" 2>&1
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v WUStatusServer >> "%LOGFILE%" 2>&1
reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v DisableWindowsUpdateAccess >> "%LOGFILE%" 2>&1
set /a DIAG_FINDINGS+=1
) else (
echo No WSUS/WUfB policy configured ^(OK for home/standard use^) >> "%LOGFILE%"
)
echo. >> "%LOGFILE%"
call :Spin
:: --- 0j: Recent Windows Update Failures (Event Log) ---
echo --- 0j: Recent WU Failures (last 10, past 30 days) --- >> "%LOGFILE%"
powershell -NoProfile -Command "$ev = Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-WindowsUpdateClient'; Level=2,3; StartTime=(Get-Date).AddDays(-30)} -MaxEvents 10 -ErrorAction SilentlyContinue; if ($ev) { $ev | Format-Table TimeCreated, Id, LevelDisplayName, Message -AutoSize -Wrap | Out-String -Width 200; Write-Output \" FINDING: $($ev.Count) WU error events in the last 30 days\"; exit 1 } else { Write-Output ' No WU error events in the last 30 days'; exit 0 }" >> "%LOGFILE%" 2>&1
if !errorlevel! neq 0 set /a DIAG_FINDINGS+=1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0k: Recent System Crashes - Bugchecks (BSODs) ---
echo --- 0k: Recent Bugchecks / BSODs (last 5, past 30 days) --- >> "%LOGFILE%"
powershell -NoProfile -Command "$ev = Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-WER-SystemErrorReporting'; StartTime=(Get-Date).AddDays(-30)} -MaxEvents 5 -ErrorAction SilentlyContinue; if ($ev) { $ev | Format-Table TimeCreated, Message -AutoSize -Wrap | Out-String -Width 200 } else { Write-Output ' No bugcheck events in the last 30 days' }" >> "%LOGFILE%" 2>&1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0k2: Kernel-Power (Event 41) - Unexpected Power Loss / Hard Resets ---
echo --- 0k2: Unexpected Power Loss / Hard Resets (Event 41, last 10, past 30 days) --- >> "%LOGFILE%"
powershell -NoProfile -Command "$ev = Get-WinEvent -FilterHashtable @{LogName='System'; ProviderName='Microsoft-Windows-Kernel-Power'; Id=41; StartTime=(Get-Date).AddDays(-30)} -MaxEvents 10 -ErrorAction SilentlyContinue; if ($ev) { $ev | Format-Table TimeCreated, Id, @{N='BugcheckCode';E={$_.Properties[0].Value}}, @{N='PowerButtonTimestamp';E={$_.Properties[4].Value}} -AutoSize | Out-String -Width 200; Write-Output \" FINDING: $($ev.Count) unexpected power loss events\"; exit 1 } else { Write-Output ' No Kernel-Power Event 41 in the last 30 days'; exit 0 }" >> "%LOGFILE%" 2>&1
if !errorlevel! neq 0 set /a DIAG_FINDINGS+=1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0k3: Unexpected Shutdown (Event 6008) ---
echo --- 0k3: Unexpected/Dirty Shutdowns (Event 6008, last 10, past 30 days) --- >> "%LOGFILE%"
powershell -NoProfile -Command "$ev = Get-WinEvent -FilterHashtable @{LogName='System'; Id=6008; StartTime=(Get-Date).AddDays(-30)} -MaxEvents 10 -ErrorAction SilentlyContinue; if ($ev) { $ev | Format-Table TimeCreated, Message -AutoSize -Wrap | Out-String -Width 200; Write-Output \" FINDING: $($ev.Count) unexpected/dirty shutdown events\"; exit 1 } else { Write-Output ' No unexpected shutdown events in the last 30 days'; exit 0 }" >> "%LOGFILE%" 2>&1
if !errorlevel! neq 0 set /a DIAG_FINDINGS+=1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0k4: Critical Events (Level 1 = Critical, any source) ---
echo --- 0k4: All Critical System Events (last 10, past 30 days) --- >> "%LOGFILE%"
powershell -NoProfile -Command "$ev = Get-WinEvent -FilterHashtable @{LogName='System'; Level=1; StartTime=(Get-Date).AddDays(-30)} -MaxEvents 10 -ErrorAction SilentlyContinue; if ($ev) { $ev | Format-Table TimeCreated, ProviderName, Id, Message -AutoSize -Wrap | Out-String -Width 200 } else { Write-Output ' No critical events in the last 30 days' }" >> "%LOGFILE%" 2>&1
echo. >> "%LOGFILE%"
call :Spin
:: --- 0k5: Memory Dump Files ---
echo --- 0k5: Memory Dump Files --- >> "%LOGFILE%"
echo --- Full Memory Dump --- >> "%LOGFILE%"
powershell -NoProfile -Command "$sr = $env:SystemRoot; if (Test-Path \"$sr\MEMORY.DMP\") { $f = Get-Item \"$sr\MEMORY.DMP\"; Write-Output (' MEMORY.DMP: ' + [math]::Round($f.Length/1MB) + ' MB, Last written: ' + $f.LastWriteTime) } else { Write-Output ' MEMORY.DMP: Not found' }" >> "%LOGFILE%" 2>&1
echo --- Minidump Files (last 10) --- >> "%LOGFILE%"
powershell -NoProfile -Command "$sr = $env:SystemRoot; if (Test-Path \"$sr\Minidump\") { $dumps = Get-ChildItem \"$sr\Minidump\*.dmp\" -ErrorAction SilentlyContinue | Sort-Object LastWriteTime -Descending | Select-Object -First 10; if ($dumps) { $dumps | Format-Table Name, @{N='SizeKB';E={[math]::Round($_.Length/1KB)}}, LastWriteTime -AutoSize | Out-String -Width 200 } else { Write-Output ' Minidump folder exists but no .dmp files found' } } else { Write-Output ' Minidump folder: Not found' }" >> "%LOGFILE%" 2>&1
echo --- Crash Dump Settings --- >> "%LOGFILE%"
reg query "HKLM\SYSTEM\CurrentControlSet\Control\CrashControl" /v CrashDumpEnabled >> "%LOGFILE%" 2>&1
reg query "HKLM\SYSTEM\CurrentControlSet\Control\CrashControl" /v DumpFile >> "%LOGFILE%" 2>&1
reg query "HKLM\SYSTEM\CurrentControlSet\Control\CrashControl" /v MinidumpDir >> "%LOGFILE%" 2>&1