-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
655 lines (654 loc) · 93.4 KB
/
index.html
File metadata and controls
655 lines (654 loc) · 93.4 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
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Nick's Scripts</title>
<link rel="stylesheet" href="./styles.css">
</head>
<body>
<main class="card">
<h1>Available scripts & functions</h2>
<ul class="script-list">
<li class="script-item">
<div class="script-header">
<a class="script-link" href="Clear-DiskJunk.ps1">Clear-DiskJunk.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="Clear-DiskJunk.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for Clear-DiskJunk.ps1" aria-label="Copy download command for Clear-DiskJunk.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Deletes selected junk files and directories from a copied disk tree, with conservative defaults and full WhatIf/Confirm support.</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">Clear-DiskJunk scans a target path and removes only the junk categories you explicitly allow.</p>
<p class="script-details-text">By default it runs in conservative mode and targets:<br>- browser-caches<br>- safe-temp-files</p>
<p class="script-details-text">Conservative mode avoids deleting generic directory names such as cache, temp, log, or logs unless you explicitly include<br>DANGEROUS-broad-temp-cache-logs.</p>
<p class="script-details-text">The function is designed for very large trees. It streams matches as they are found instead of accumulating all results in memory.<br>Use -PassThru to emit one result object per matched item. Without -PassThru it emits only a final summary object.</p>
<p class="script-details-text">safe-temp-files deletes:<br>- *.tmp files older than 30 days<br>- Office temp files (~$*.??? and ~$*.????)</p>
<p class="script-details-text">DANGEROUS-broad-temp-cache-logs expands matching to broad generic temp/cache/log locations and broad *.log / *.tmp file cleanup.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Clear-DiskJunk -Path D:\MountedDisk -WhatIf</p>
<p class="script-details-text">Shows what would be deleted using the conservative default categories.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Clear-DiskJunk -Path D:\MountedDisk -IncludeCategory browser-caches,DANGEROUS-broad-temp-cache-logs -Confirm</p>
<p class="script-details-text">Prompts before deleting and includes the dangerous broad cleanup category.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Clear-DiskJunk -Path D:\MountedDisk -ExcludePath 'D:\MountedDisk\Users\Nick\AppData\Local\Google\*' -PassThru |<br>Export-Csv C:\temp\diskjunk-results.csv -NoTypeInformation</p>
<p class="script-details-text">Streams one result object per matched item and saves them.</p>
<p class="script-details-text">.PARAMETER Path<br>Root path to scan.</p>
<p class="script-details-text">.PARAMETER IncludeCategory<br>Cleanup categories to include.</p>
<p class="script-details-text">Allowed values:<br>- browser-caches<br>- safe-temp-files<br>- DANGEROUS-broad-temp-cache-logs</p>
<p class="script-details-text">Default:<br>- browser-caches<br>- safe-temp-files</p>
<p class="script-details-text">.PARAMETER ExcludePath<br>Paths or wildcard patterns to exclude. Matches are tested against both full Windows paths and root-relative forward-slash paths.</p>
<p class="script-details-text">.PARAMETER TmpOlderThanDays<br>Age threshold for *.tmp deletion in the safe-temp-files category. Default is 30.</p>
<p class="script-details-text">.PARAMETER PassThru<br>Emits one object per matched item as it is processed. Useful for logging and large-scale runs.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>Without -PassThru:<br>A summary object.</p>
<p class="script-details-text">With -PassThru:<br>One result object per matched item, followed by a final summary object.</p>
<p class="script-details-text"><span class="detail-directive">.NOTES</span><br>- Supports -WhatIf and -Confirm.<br>- Intended primarily for copies of Windows disks, not live system cleanup.<br>- Broad cleanup can remove data you may later want for troubleshooting or forensics.</p>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="Get-BootShutdownEvents.ps1">Get-BootShutdownEvents.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="Get-BootShutdownEvents.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for Get-BootShutdownEvents.ps1" aria-label="Copy download command for Get-BootShutdownEvents.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Shows a compact, admin-friendly timeline of recent boots, shutdowns,<br>crashes, and update-related restart signals from the System log.</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">Use this for first-pass reboot and shutdown triage. It helps answer<br>whether a recent restart was clean, unexpected, crash-related, planned<br>by an administrator or process, or associated with Windows Updates.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>Produces one PSCustomObject per matching event:<br>Level : Event level text.<br>Time : Event time.<br>Kind : Event category. One of:<br>Boot, NormalShutdown, PlannedShutdownOrRestart,<br>WindowsUpdatesInstallStarted, WindowsUpdatesInstallCompleted,<br>WindowsUpdatesRestartRequired, WindowsUpdatesRestart<br>BugCheck, CrashDump, AbnormalShutdown,<br>UnexpectedShutdownFollowup, Other<br>Description : First line of the event message with source metadata<br>appended as "(id <n> from <provider>)".</p>
<p class="script-details-text">Intentionally excludes noise about Microsoft Defender updates.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>PS C:\> Get-BootShutdownEvents |ft</p>
<p class="script-details-text">Level Time Kind Description<br>Info 15/3 6:00:47 WindowsUpdatesInstallStart Installation Started: Windows has started installing the following update: 2026-03 Cumulative Update for Microsoft ...<br>Info 15/3 6:19:54 WindowsUpdatesRestart The process C:\WINDOWS\system32\shutdown.exe (SRV2) has initiated the restart of computer SRV2 ...<br>Info 15/3 6:22:06 NormalShutdown The Event log service was stopped. (id 6006 from EventLog)<br>Info 15/3 6:22:12 NormalShutdown The operating system is shutting down at system time 2026 - 03 - 15T04:22:12.144072600Z. (id 13 from Microsoft-Windows-Kernel-General)<br>Info 15/3 6:22:14 Boot The operating system started at system time 2026 - 03 - 15T04:22:14.500000000Z. (id 12 from Microsoft-Windows-Kernel-General)<br>Info 15/3 6:22:22 Boot The Event log service was started. (id 6005 from EventLog)<br>Info 15/3 6:22:44 WindowsUpdatesRestart The process C:\WINDOWS\servicing\TrustedInstaller.exe (SRV2) has initiated the restart of computer SRV2...<br>Info 15/3 6:22:45 NormalShutdown The Event log service was stopped. (id 6006 from EventLog)<br>Info 15/3 6:22:51 NormalShutdown The operating system is shutting down at system time 2026 - 03 - 15T04:22:51.294803800Z. (id 13 from Microsoft-Windows-Kernel-General)<br>Info 15/3 6:22:53 Boot The operating system started at system time 2026 - 03 - 15T04:22:53.500000000Z. (id 12 from Microsoft-Windows-Kernel-General)<br>Info 15/3 6:22:59 Boot The Event log service was started. (id 6005 from EventLog)<br>Info 15/3 6:23:20 WindowsUpdatesInstallCompl Installation Successful: Windows successfully installed the following update: 2026-03 Cumulative Update for Microsoft ...</p>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="helpers-DCs.ps1">helpers-DCs.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="helpers-DCs.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for helpers-DCs.ps1" aria-label="Copy download command for helpers-DCs.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">A collection of helper functions for Domain Controllers</p>
<details class="script-details">
<summary>Read more</summary>
<div class="function-panel">
<div class="function-entry">
<p class="function-name"><strong>Search-ADUserAnyProperty</strong></p>
<p class="function-synopsis">Search Active Directory users by a pattern across multiple common attributes.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">This function wraps Get-ADUser with a wide LDAP filter that checks a user-supplied<br>pattern against multiple commonly used identifier attributes (e.g. sAMAccountName,<br>userPrincipalName, displayName, cn, givenName, sn, mail, proxyAddresses).<br>It's intended as a convenient "search anywhere that matters" for finding users when<br>you only know part of a name, email, alias, or login.</p>
<p class="script-details-text">Results include useful profile fields: Display Name, Department, Job Title, State,<br>Company, OU (derived from DistinguishedName), and all proxyAddresses flattened into<br>a comma-separated list. Optionally you can also search phone fields and/or restrict<br>the search scope with -SearchBase.</p>
<p class="script-details-text">.PARAMETER Pattern<br>The text pattern to search for (wildcards are automatically added at both ends).</p>
<p class="script-details-text">.PARAMETER SearchBase<br>Optional LDAP distinguished name to scope the search.</p>
<p class="script-details-text">.PARAMETER IncludePhones<br>If specified, phone-related attributes are included in the search (makes the search a bit slower)</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br># Find any user whose name, alias, or email contains "nick"<br>Search-ADUserAnyProperty -Pattern 'nick'</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br># Search within a specific OU, also matching phone numbers<br>Search-ADUserAnyProperty -Pattern '2103' -IncludePhones -SearchBase 'OU=Athens,OU=Users,DC=corp,DC=example,DC=com'</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br># Export results to CSV<br>Search-ADUserAnyProperty -Pattern 'nick' |<br>Export-Csv C:\temp\ad-search.csv -NoTypeInformation -Encoding UTF8</p>
</details>
</div>
</div>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="helpers-files.ps1">helpers-files.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="helpers-files.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for helpers-files.ps1" aria-label="Copy download command for helpers-files.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">A collection of helper functions for handling files</p>
<details class="script-details">
<summary>Read more</summary>
<div class="function-panel">
<div class="function-entry">
<p class="function-name"><strong>Get-HardLinks</strong></p>
<p class="function-synopsis">Lists files in the current directory that have >1 hardlink, and shows all link paths</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Get-HardLinks|Format-List</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>New-ZipFromFolder</strong></p>
<p class="function-synopsis">Creates a zip file from a folder, keeping the folder as the top-level entry and allowing for exclusions.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Packages the source folder into a zip file whose top-level folder name<br>matches the source folder name. Allows for recursive exclusions based<br>on file name, folder name, or relative path.</p>
<p class="script-details-text">Creates a sibling staging folder next to the source folder and removes<br>it before returning. On NTFS volumes, included files are staged as<br>hardlinks unless DontUseHardLinks is set. Hardlinking is super-fast.</p>
<p class="script-details-text">.PARAMETER Exclude<br>Wildcard patterns used to skip files or folders anywhere under the<br>source folder. A pattern can match an item name or a relative path.</p>
<p class="script-details-text">.PARAMETER NoCompression<br>When set, writes the archive without compression.</p>
<p class="script-details-text">.PARAMETER Fast<br>When set, writes the archive with the fastest compression level.</p>
<p class="script-details-text">.PARAMETER DontUseHardLinks<br>When set, stages included files by copying them; otherwise the function<br>uses hardlinks when the source volume supports them.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>New-ZipFromFolder .\App .\App.zip `<br>-Exclude '*.bak','*.tmp','.git'</p>
<p class="script-details-text">Creates the zip while skipping matching files and folders under App.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Delete-OldFiles</strong></p>
<p class="function-synopsis">Deletes old files under a directory tree, with WhatIf support.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Attempts to remove files under Root whose LastWriteTime is older than Cutoff.<br>Use this when you need recursive age-based cleanup with WhatIf support and<br>optional cleanup of child folders left empty by the cleanup.</p>
<p class="script-details-text">Skips reparse points (junctions/symlinks/mount points) so cleanup stays inside<br>the intended tree.</p>
<p class="script-details-text">By default, non-root child folders will be removed when they have no<br>remaining files or child folders after file cleanup. Root is not<br>removed. When LeaveEmptyFolders is set, folders are not removed.</p>
<p class="script-details-text">Deletion failures for individual files or folders are reported as warnings.<br>Other matching files and folders may still be processed. Permission limits,<br>locked files, and enumeration errors can leave matching files or folders in<br>place.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>None. Does not write objects to the pipeline.</p>
<p class="script-details-text">Writes scan and deletion status to the host.<br>Writes warnings for failed file or folder removals.</p>
<p class="script-details-text">.PARAMETER Root<br>Directory tree to clean. The path must identify an existing directory.</p>
<p class="script-details-text">.PARAMETER Cutoff<br>Files with LastWriteTime earlier than this value are candidates for removal.</p>
<p class="script-details-text">.PARAMETER LeaveEmptyFolders<br>When set, only matching files are removed; otherwise, non-root child folders<br>left empty by the cleanup scope may also be removed.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Delete-OldFiles -Root C:\Temp -Cutoff (Get-Date).AddMonths(-6) -WhatIf</p>
<p class="script-details-text">Shows the files and folders that would be removed under C:\Temp.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Delete-OldFiles -Root C:\Temp -Cutoff (Get-Date).AddMonths(-6) `<br>-LeaveEmptyFolders</p>
<p class="script-details-text">Removes old files under C:\Temp but does not remove empty folders.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Get-DiskInfo</strong></p>
<p class="function-synopsis">Gets Win32_LogicalDisk information for one disk.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Popular properties: FreeSpace, Size, VolumeName, DriveType<br>.PARAMETER Disk Disk device ID, for example C:.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Test-NonReparseDirectory</strong></p>
<p class="function-synopsis">Returns true only for real directories, not junctions/symlinks.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">.PARAMETER LiteralPath Directory path to test without wildcard expansion.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Clear-OldTempFiles</strong></p>
<p class="function-synopsis">Deletes old files from common Windows temporary file locations.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Attempts to remove old files from the current process TEMP and TMP<br>locations, the Windows temp location, and detected user temp folders under<br>C:\Users.</p>
<p class="script-details-text">Skips reparse points (junctions/symlinks/mount points) so cleanup stays inside<br>the intended trees.</p>
<p class="script-details-text">Use this as a safer temp cleanup entry point when you need age-based cleanup<br>across the usual system and user temp locations, WhatIf support, and optional<br>cleanup of child folders left empty by the cleanup.</p>
<p class="script-details-text">The cutoff is calculated from the current time and MonthsOld. By default,<br>non-root child folders inside each temp root may also be removed when they<br>have no remaining detected files or child folders after file cleanup. Temp<br>root folders themselves are not removed.</p>
<p class="script-details-text">Deletion failures for individual files or folders are reported as warnings.<br>Other matching files and folders may still be processed. Permission limits,<br>locked files, missing profiles, and enumeration errors can leave matching<br>files or folders in place. Run elevated to cover system and other-user temp<br>locations where required.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>None. Does not write objects to the pipeline.</p>
<p class="script-details-text">Writes cutoff, scan, and deletion status to the host.<br>Writes warnings for failed file or folder removals.</p>
<p class="script-details-text">.PARAMETER MonthsOld<br>Age threshold in months. Files older than the calculated cutoff are<br>candidates for removal.</p>
<p class="script-details-text">.PARAMETER LeaveEmptyFolders<br>When set, only matching files are removed; otherwise, non-root child folders<br>left empty by the cleanup will also be removed.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Clear-OldTempFiles -WhatIf</p>
<p class="script-details-text">Shows the old temp files and folders that would be removed.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Clear-OldTempFiles -MonthsOld 3 -LeaveEmptyFolders</p>
<p class="script-details-text">Removes temp files older than the calculated cutoff and keeps folders.</p>
</details>
</div>
</div>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="helpers-networking.ps1">helpers-networking.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="helpers-networking.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for helpers-networking.ps1" aria-label="Copy download command for helpers-networking.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">A collection of helper functions for Networking</p>
<details class="script-details">
<summary>Read more</summary>
<div class="function-panel">
<div class="function-entry">
<p class="function-name"><strong>Test-IpReachability</strong></p>
<p class="function-synopsis">Probe point-in-time ICMP reachability for one or more IP targets.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Sends one or more ICMP echo attempts to each target and returns one output<br>object per unique target IP.</p>
<p class="script-details-text">When a ping attempt cannot be performed due to an internal runtime error,<br>the target result's lastStatus is set to a string beginning with<br>"PROGRAM EXCEPTION:".</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>[pscustomobject]<br>One object per unique target IP with properties:<br>- ip (string): The target IP string as provided/normalized.<br>- responded (bool): $true if any attempt succeeded; otherwise $false.<br>- attempts (int): Number of attempts made for that target.<br>- respondedOnAttempt (Nullable[int]): Attempt number of first success;<br>otherwise $null.<br>- rttMs (Nullable[long]): Round-trip time in milliseconds for the<br>successful response; otherwise $null.<br>- lastStatus (string): Final status observed for the target. For runtime<br>errors, begins with "PROGRAM EXCEPTION:".</p>
<p class="script-details-text">.PARAMETER Ip<br>One or more target IPs to probe.</p>
<p class="script-details-text">Accepts:<br>- A single value convertible to string.<br>- An enumerable of values convertible to string.<br>- A single string containing multiple targets separated by commas and/or<br>whitespace.</p>
<p class="script-details-text">.PARAMETER Retry<br>Number of additional attempts per target after the first attempt.</p>
<p class="script-details-text">.PARAMETER TimeoutMs<br>Timeout in milliseconds for each attempt.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Test-IpReachability -Ip '10.1.11.50,10.1.11.55 10.1.11.56' `<br>-Retry 1 -TimeoutMs 500 -Verbose</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Test-TcpPort</strong></p>
<p class="function-synopsis">Quickly tests whether a TCP connection can be established.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Tests TCP connectivity from the current machine to the specified target<br>and ports, and returns one result object per requested port.</p>
<p class="script-details-text">The target MAY be specified as an IP address or a hostname. If name<br>resolution fails, the function throws a terminating error.</p>
<p class="script-details-text">Ports are accepted in multiple input forms.</p>
<p class="script-details-text">The -TimeoutMs value is a single overall time budget (in milliseconds) for<br>the entire batch of ports, not a per-port timeout.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>System.Management.Automation.PSCustomObject</p>
<p class="script-details-text">One object per normalized port, with these properties:<br>- port (int) The TCP port tested.<br>- open (bool) $true if a connection was established; otherwise $false.<br>- detail (string) "connected" on success; otherwise an error identifier<br>or "timeout" if the overall time budget was reached.</p>
<p class="script-details-text">Objects are emitted in ascending port order.</p>
<p class="script-details-text">.PARAMETER Target<br>Target host to test.</p>
<p class="script-details-text">.PARAMETER Ports<br>Ports to test. Accepts:<br>- a single integer<br>- an array of integers<br>- a string containing one or more port numbers<br>- an enumerable of values convertible to integers</p>
<p class="script-details-text">.PARAMETER TimeoutMs<br>Overall time budget for the entire batch, in milliseconds. Defaults to<br>200. When the budget is exhausted, remaining ports are reported as<br>"timeout".</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Test-TcpPort -Target '10.1.11.1' -Ports 80,443,4444</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Test-TcpPort -Target 'timesheet-gr.forvismazars.com' -Ports '80,443,4444' `<br>-TimeoutMs 1000</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Test-NetConnectivityToHost</strong></p>
<p class="function-synopsis">Test-NetConnectivityToHost validates that basic network reachability to a target host matches an explicit expectation profile. What it checks - ICMP echo (ping): verifies whether the host responds to pings or not. - TCP ports (optional): - OpenPorts: ports that are expected to accept a TCP connection. - ClosedPorts: ports that are expected to refuse or time out (treated as CLOSED/FILTERED). Output / side effects - Outputs discrepancies using Write-Warning "[<level>] <message>" (<level> can be pass or failure). - If -ReturnTrueFalse is used, the function returns $true/$false and emits no warnings. Notes / interpretation - A TCP port is considered OPEN only if a TCP connect completes successfully within the timeout window. - A TCP port is considered CLOSED/FILTERED if the connect fails or does not complete within the timeout. - If OpenPorts/ClosedPorts are omitted, only the ping expectation is validated. - If -SkipPing is used, only port expectations are validated. Example Test-NetConnectivityToHost -TargetHost 10.30.0.2 -RespondsToPing:$true -OpenPorts @(53,88,135,389,445) -ClosedPorts @(22,3389) -PortTimeoutMs 1000 Example (ports only) Test-NetConnectivityToHost -TargetHost 10.30.0.2 -SkipPing -OpenPorts @(443) -PortTimeoutMs 1000 Example (boolean result only) Test-NetConnectivityToHost -TargetHost 10.30.0.2 -RespondsToPing:$true -ReturnTrueFalse</p>
</div>
<div class="function-entry">
<p class="function-name"><strong>Split-IpByReachability</strong></p>
<p class="function-synopsis">Splits input IPs into Alive vs NotAlive based on whether they respond to pings</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Runs Test-IpReachability for the provided targets and returns a single object<br>containing two string arrays:<br>- AliveIps: IPs that responded ($true)<br>- DeadIps: IPs that did not respond ($false) or hit errors/timeouts</p>
<p class="script-details-text"><span class="detail-directive">.INPUTS</span><br>Same accepted shapes as Test-IpReachability -Ip.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>[pscustomobject] with:<br>- AliveIps ([string[]])<br>- DeadIps ([string[]])<br>- Results ([pscustomobject[]]) raw per-IP results (handy for lastStatus/rtt)</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Test-NetConnectivityToNetwork</strong></p>
<p class="function-synopsis">Assesses reachability of a network by pinging a list of hosts that are known to reply.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Given a human-friendly network description (e.g. "10.11.x.y/16") and a list of<br>IP addresses that are expected to respond to ICMP, this function probes them<br>(using Split-IpByReachability) and outputs the results using:<br>Write-Warning "[<level>] ..."<br>(<level> is one of pass, notice, failure)</p>
<p class="script-details-text">If -ReturnListOfAliveHosts is used, the function does not emit warnings and<br>instead returns the list of responsive hosts.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Test-ShareLikelyUp</strong></p>
<p class="function-synopsis">QUICKLY tests whether the host of a UNC share is LIKELY reachable over SMB.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">This is a FAST reachability test, not a definitive share-access test. A positive result means the host likely has SMB available. It does not prove that the share exists or that the current user has access to it.</p>
<p class="script-details-text">Optionally verifies that at least one configured DNS server falls within an expected CIDR range (prefer to pass it so that you don't spend time on failed DNS resolutions), resolves the host to IPv4 and/or IPv6 addresses, and tests whether any resolved address accepts a TCP connection on port 445 within a short timeout. Supports hostnames, IPv4 UNC hosts, and Windows IPv6-literal UNC hosts.</p>
<p class="script-details-text">.PARAMETER SharePath<br>UNC share path whose host will be tested.</p>
<p class="script-details-text">.PARAMETER DnsCidrs<br>Optional CIDR ranges. When specified, at least one configured DNS server must fall within one of these ranges or the test returns a negative result.</p>
<p class="script-details-text">.PARAMETER TcpTimeoutMs<br>For the connection test to TCP port 445 (SMB).</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>A PSCustomObject with the test outcome and discovered details.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Test-ShareLikelyUp -SharePath '\\server01\share'</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Test-ShareLikelyUp -SharePath '\\192.168.1.2\foo'</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Test-ShareLikelyUp -SharePath '\\server01.contoso.local\share' -DnsCidrs '10.30.0.0/16'</p>
</details>
</div>
</div>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="helpers-processes.ps1">helpers-processes.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="helpers-processes.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for helpers-processes.ps1" aria-label="Copy download command for helpers-processes.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">A collection of helper functions for Processes & Tasks</p>
<details class="script-details">
<summary>Read more</summary>
<div class="function-panel">
<div class="function-entry">
<p class="function-name"><strong>Quote-Win32Arg</strong></p>
</div>
<div class="function-entry">
<p class="function-name"><strong>Join-Win32CommandLine</strong></p>
</div>
<div class="function-entry">
<p class="function-name"><strong>New-ScheduledTaskForPSScript</strong></p>
<p class="function-synopsis">Registers a Windows Scheduled Task that runs a PowerShell script as SYSTEM.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Creates or updates a scheduled task that runs the script specified by<br>-ScriptPath using Windows PowerShell (powershell.exe).</p>
<p class="script-details-text">The task is registered under -TaskPath and -TaskName (a default name is<br>chosen when -TaskName is not provided). If a task with the same name<br>already exists at that path, it is replaced.</p>
<p class="script-details-text">The task runs as the built-in SYSTEM account with highest run level. Task<br>settings limit concurrent executions by ignoring new starts while an<br>instance is already running, and apply -ExecutionTimeLimit to each run.</p>
<p class="script-details-text">Depending on the script path and provided arguments, the function MAY<br>create a .cmd wrapper file in the script's folder and configure the task<br>to execute that wrapper instead of invoking powershell.exe directly.</p>
<p class="script-details-text">If -ScheduleType is Manual, the task is created without a trigger and<br>will only run when started manually (or by other tooling).</p>
<p class="script-details-text">Supports -WhatIf and -Confirm. If confirmation is declined (or -WhatIf is<br>used), no task is registered and no wrapper file is created.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>Microsoft.Management.Infrastructure.CimInstance<br>A scheduled task object returned by Register-ScheduledTask when the task<br>is registered. If ShouldProcess declines the action, no output is<br>produced.</p>
<p class="script-details-text">.PARAMETER ScriptPath<br>Path to an existing PowerShell script file. The path MUST exist or the<br>function throws before making changes.</p>
<p class="script-details-text">.PARAMETER ScheduleType<br>Selects how (or whether) the task is triggered.</p>
<p class="script-details-text">Valid values:<br>- Startup: runs at system startup.<br>- Daily: runs daily at -Time.<br>- Weekly: runs weekly on -Day at -Time.<br>- Hourly: repeats every hour starting shortly after creation time.<br>- EveryMinute: repeats every minute starting shortly after creation time.<br>- Manual: no trigger is created.</p>
<p class="script-details-text">.PARAMETER Time<br>Time of day in HH:mm (24-hour) format. Required for Daily and Weekly.</p>
<p class="script-details-text">.PARAMETER Day<br>One or more weekdays. Required for Weekly.</p>
<p class="script-details-text">.PARAMETER TaskPath<br>Scheduled task folder path in Task Scheduler (for example '\enLogic\').<br>Defaults to '\enLogic\'.</p>
<p class="script-details-text">.PARAMETER TaskName<br>Scheduled task name. If omitted, a name is derived from the script file<br>name.</p>
<p class="script-details-text">.PARAMETER ScriptArguments<br>Argument values passed to the script. Provide either -ScriptArguments or<br>-RawArgumentsAvoidMe, not both.</p>
<p class="script-details-text">Elements MAY be $null. How the script receives $null depends on the<br>invocation mode chosen by the function.</p>
<p class="script-details-text">.PARAMETER RawArgumentsAvoidMe<br>A raw argument string appended to the invocation. Intended for advanced<br>cases. Provide either -ScriptArguments or -RawArgumentsAvoidMe, not both.</p>
<p class="script-details-text">.PARAMETER ExecutionTimeLimit<br>Maximum runtime allowed for each task invocation. Defaults to 2 hours.</p>
<p class="script-details-text">.PARAMETER StartItNow<br>If set, the function attempts to start the task immediately after it is<br>registered. If starting fails, the task remains created and an error is<br>written.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Health.ps1' `<br>-ScheduleType Startup -TaskPath '\enLogic\'</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Report.ps1' `<br>-ScheduleType Daily -Time '02:30' -TaskName 'Daily Report' `<br>-ScriptArguments @('Full','EU')</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Cleanup.ps1' `<br>-ScheduleType Weekly -Day Monday,Thursday -Time '03:00' `<br>-ExecutionTimeLimit (New-TimeSpan -Minutes 30) -StartItNow</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\OnDemand.ps1' `<br>-ScheduleType Manual -TaskName 'Run On Demand'</p>
<p class="script-details-text"><span class="detail-directive">.NOTES</span><br>Registers the task to run as SYSTEM with highest privileges, and sets<br>MultipleInstances to IgnoreNew.</p>
<p class="script-details-text">For Hourly and EveryMinute schedules, the first run is anchored to a<br>start time shortly after the function is invoked (not aligned to clock<br>boundaries).</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Invoke-DetachedPSScript</strong></p>
<p class="function-synopsis">Executes a PowerShell script on a remote host as a detached process without leaving a disconnected session after execution completes.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">The script or script block is executed on the remote host. Unlike<br>`Invoke-Command -InDisconnectedSession` once the execution terminates<br>it does not leave a disconnected session on the target.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>Produces a PSCustomObject representing the process start result:<br>ComputerName : The target host name.<br>ProcessId : The ID of the newly created remote process.<br>ReturnValue : The system code from the process creation attempt.<br>Status : The outcome of the initiation (e.g., "Success").<br>ExecutionPath : The path to the script being executed on the target.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Get-ProcessesWithMatchingCommandLine</strong></p>
<p class="function-synopsis">.DESCRIPTION List processes with command lines matching a like expression (e.g. "*myScript.ps1*") .EXAMPLE Get-ProcessesWithMatchingCommandLine "*myScript.ps1*"</p>
</div>
<div class="function-entry">
<p class="function-name"><strong>Test-ExeFound</strong></p>
</div>
</div>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="helpers-text-files.ps1">helpers-text-files.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="helpers-text-files.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for helpers-text-files.ps1" aria-label="Copy download command for helpers-text-files.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">A collection of helper functions for handling text files</p>
<details class="script-details">
<summary>Read more</summary>
<div class="function-panel">
<div class="function-entry">
<p class="function-name"><strong>Edit-TextFile</strong></p>
<p class="function-synopsis">Searches and replaces text in files while maintaining the existing text encoding (but will switch ASCII to UTF8 if replacement is unicode).</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Performs an in-place regex (or literal) search/replace on a text file,<br>while preserving the file's actual encoding. For _really_ hard cases it<br>may mistake the encoding. In such cases it may fail to find the pattern<br>and/or change the encoding of the input file.</p>
<p class="script-details-text">You may pass wildcards like "*.txt" to -File.</p>
<p class="script-details-text">To apply one substitution use `-Patern 'a' -Replacement 'b'`. To apply<br>multiple substitutions use `-ReplaceMap` (see examples).</p>
<p class="script-details-text">Without -Literal considers Pattern(s) to be a regex pattern.</p>
<p class="script-details-text">By default keeps a backup with .bak extension. To skip the Backup<br>use -Backup "". To change the extension use -Backup "ext".</p>
<p class="script-details-text">If the sampled bytes are pure 7-bit ASCII and no BOM is present, the<br>function by default assumes a UTF8 encoding (even though ASCII is also<br>valid). This is intentional: it allows replacements to introduce Unicode<br>without changing the reported encoding unexpectedly. Use -DontPreferUTF8<br>to force ASCII encoding.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>Produces a psCustomObject for each evaluated file:<br>File = The file path<br>Changed = True/False<br>EncodingStr = Human readable encoding.<br>EncodingObj = The output of Get-TextFileEncoding<br>Details = Human readable outcome. E.g.:<br>"Changes made"<br>"Pattern(s) not found"<br>"Skipped too big file ..."<br>"Ignored empty file"<br>"No files matched pattern"</p>
<p class="script-details-text">.PARAMETER MaxFileSize<br>Files larger than these many bytes are ignored.</p>
<p class="script-details-text">.PARAMETER PreferISOEncodings<br>When set, ISO encodings are selected when multiple encodings represent<br>the text equivalently; otherwise, Windows encodings are selected.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Edit-TextFile -file .\ansi.txt -Pattern "foo" -Replacement="_FOO_"</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Edit-TextFile -file .\ansi.txt -Pattern "foo?" -Replacement="_FOO_?" -Literal</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Edit-TextFile -file .\ansi.txt -ReplaceMap ([ordered]@{"foo"="_FOO_"; "bar"="_BAR_"})</p>
<p class="script-details-text"><span class="detail-directive">.NOTES</span><br>The operation writes modified content to temporary storage before<br>replacing the target file. Original files are backed up prior to the<br>modification. If a terminating error occurs during the file swap, the<br>target file might remain in its prior state and intermediate temporary<br>files might remain on the storage volume.</p>
<p class="script-details-text">Files exceeding the configured maximum size limit or containing no<br>data are skipped. Substitutions are evaluated sequentially.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Get-NewlineStyle</strong></p>
<p class="function-synopsis">Detect newline style in a decoded string. Returns 'CRLF','LF','CR','Mixed','None','NotChecked'.</p>
</div>
<div class="function-entry">
<p class="function-name"><strong>Get-TextFileEncoding</strong></p>
<p class="function-synopsis">Detect (if possible) or guess the encoding of Text Files.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Uses uchardet (CLI) and simple BOM/ASCII checks.<br>Returns an object like this:<br>File : C:\tempansi.txt<br>Type : NON-ASCII-TEXT<br>BOMBytes : {}<br>UCharDetEncoding : ISO-8859-1<br>EncodingDescription : CP1252<br>DotNetEncodingObj : System.Text.SBCSCodePageEncoding<br>NewlineStyle :<br>BytesRead : 22<br>UCharDetTimeMs : 0<br>TotalTimeMs : 55</p>
<p class="script-details-text"><span class="detail-directive">.PARAMETER</span><br>-DontPreferUTF8: If the sampled bytes are pure 7-bit ASCII and no BOM<br>is present, the function returns UTF-8 by default (even though ASCII<br>is also valid). This is intentional: it allows later writes/replacements<br>to introduce Unicode without changing the reported encoding unexpectedly.<br>Use -DontPreferUTF8 to return ASCII instead.<br>In other words: The default UTF-8 return value is not a strict<br>"encoding detection" result; it is a compatibility policy for downstream<br>editing workflows.<br>-PreferISOEncodings: by default we return Windows encodings instead of ISO ones<br>WHEN BOTH PRODUCE THE SAME TEXT. This switch overides that behavior.</p>
<p class="script-details-text"><span class="detail-directive">.NOTES</span><br>- Will fail for pathological files (e.g. BOM indicates UTF-8<br>but file is UTF-16).<br>- It consumes RAM to read the file's bytes, possible twice.<br>(That's why -MaxBytes is by default 512KB)<br>- It may fail in very hard cases like:<br>- Files larger than 512KB that appear as ASCII in the first<br>-MaxBytes and then have some ANSI or UTF-8 bytes.<br>- Files with ambiguous ASCII encodings (e.g. ISO-8859-1 /<br>CP1252)<br>- Respects -ErrorAction by emitting non-terminating errors.<br>- By default (without -PreferISOEncodings) it will assume a file<br>is encoded with a Windows(CP) encoding if it can be either<br>an ISO encoding (e.g. ISO-8859-1) or a windows one (e.g. CP1251)<br>(Since a lot of these encodings are very similar, a file with plenty<br>of text but none of the few characters that are encoded<br>differently between the ISO/CP encodings can be encoded with both giving<br>exactly the same bytes)</p>
<p class="script-details-text">For reference these are the default encoding for Notepad,<br>PS5 & PS7 per windows version:</p>
<p class="script-details-text">| | PS 5.1 | PS 5.1 | PS 7 either<br>Operating System | Notepad | > a.txt | Out-File | > or Out-File<br>2016 (1607 LTSC) | ANSI | ANSI | UTF-16 LE*| UTF-8*<br>2019 (1809 LTSC) | ANSI | ANSI | UTF-16 LE*| UTF-8*<br>2022 (21H2 LTSC) | UTF-8* | ANSI | UTF-16 LE*| UTF-8*<br>2025 (24H2 LTSC) | UTF-8* | ANSI | UTF-16 LE*| UTF-8*<br>*: UTF-8 always without BOM, UTF-16 always with BOM</p>
<p class="script-details-text">TODO:<br>Offer help on how to install uchardet if not found.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Remove-TypographyUnicodeFromTextFile</strong></p>
<p class="function-synopsis">Substitutes Unicode typography characters with ASCII characters in one or more target text files. Mimics the interface of Edit-TextFile.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Modifies the specified file or files (if you use wildcards like *.txt)<br>in place. Useful for eliminating unnecessary Unicode typography from code.</p>
<p class="script-details-text">You may pass wildcards like "*.ps1" to -File.</p>
<p class="script-details-text">By default keeps a backup with .bak extension. To skip the Backup<br>use -Backup "". To change the extension use -Backup "ext".</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>Produces a psCustomObject for each evaluated file:<br>File = The file path<br>Changed = True/False<br>EncodingStr = Human readable encoding.<br>EncodingObj = The output of Get-TextFileEncoding<br>Details = Human readable outcome. E.g.:<br>"Changes made"<br>"Pattern(s) not found"<br>"Skipped too big file ..."<br>"Ignored empty file"<br>"No files matched pattern"</p>
<p class="script-details-text">.PARAMETER MaxFileSize<br>Files larger than these many bytes are ignored.</p>
<p class="script-details-text">.PARAMETER PreferISOEncodings<br>When set, ISO encodings are selected when multiple encodings represent<br>the text equivalently; otherwise, Windows encodings are selected.</p>
<p class="script-details-text"><span class="detail-directive">.NOTES</span><br>Why we have to do the changes in three batches instead of all together:<br>By default, PowerShell hashtables (@{} and [ordered]@{}) use culture-sensitive<br>linguistic comparison.<br>Because 0x200B, 0x200C, and 0x200D are invisible formatting characters,<br>the linguistic comparer gives them a sorting weight of zero. Therefore,<br>PowerShell evaluates them as the exact same string and throws a "Duplicate keys"<br>error when building the hashtable.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Replace-FileBytesSafely</strong></p>
<p class="function-synopsis">Replaces a file's contents with specified bytes, optionally retaining a backup.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Behavior and guarantees:<br>- Writes the new content to -TmpPath first, then attempts to replace -ResolvedPath with it.<br>- Primary path uses [IO.File]::Replace(), which is the best option on local NTFS:<br>* Readers see either the old or the new file, not a partially-written file.<br>* A backup at -BakPath is created/overwritten as part of the replace.<br>- If Replace() fails (common on non-NTFS volumes, SMB shares with varying semantics, or transient locks<br>e.g. AV/OneDrive/indexing), it falls back to Copy-Item + Move-Item with best-effort rollback:<br>* This fallback is NOT atomic. It is provided for compatibility and "works in more places".<br>* If the move fails after the backup copy, the function attempts to restore from -BakPath.</p>
<p class="script-details-text">Backup semantics:<br>- -BakPath is always used as the safety copy when swapping.<br>- If -UserBackup is $true, -BakPath is considered caller-visible and is preserved.<br>- If -UserBackup is $false, -BakPath is a transient safety backup and may be deleted on success.</p>
<p class="script-details-text">Cleanup:<br>- Always attempts to delete -TmpPath in a finally block.<br>- Does not promise preservation of metadata/streams in the fallback path (ACLs, ADS, timestamps, etc.)<br>beyond what the underlying filesystem/provider naturally keeps.</p>
<p class="script-details-text">.PARAMETER ResolvedPath<br>The existing target file to be replaced (must be on the same volume as -TmpPath for best behavior).</p>
<p class="script-details-text">.PARAMETER TmpPath<br>A temp file path in the same directory as the target (recommended) containing the new bytes to commit.</p>
<p class="script-details-text">.PARAMETER BakPath<br>Path for the backup copy used during the swap. May be a user-requested backup (kept) or a transient one.</p>
<p class="script-details-text">.PARAMETER UserBackup<br>Indicates whether -BakPath is user-requested (keep it) or internal/transient (delete on success).</p>
<p class="script-details-text">.PARAMETER Bytes<br>The final bytes to be written/committed to the target file.</p>
<p class="script-details-text"><span class="detail-directive">.NOTES</span><br>- Intended for "in-place update" workflows: generate full new content, then commit in one swap.<br>- For OneDrive/SMB scenarios, transient failures are normal; callers may want a small retry policy<br>around the Replace() stage (if not implemented inside this function).</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Read-FirstBytes</strong></p>
<p class="function-synopsis">Safe(shared) read of up to Count bytes from the start of a file.</p>
</div>
<div class="function-entry">
<p class="function-name"><strong>Test-ExeFound</strong></p>
<p class="function-synopsis">Tests whether an executable can be resolved either as a full path or via PATH/PATHEXT.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Accepts either:<br>- A rooted path (e.g. C:\Tools\uchardet or C:\Tools\uchardet.exe), in which case it checks existence and,<br>if no extension was given, also tries common executable extensions (.exe/.cmd/.bat/.com).<br>- A bare command name (e.g. uchardet), in which case it resolves it the same way PowerShell would when<br>launching a process (Get-Command + PATHEXT).<br>Returns $true if the executable can be found, otherwise $false.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Resolve-FileFromPath</strong></p>
<p class="function-synopsis">Resolve a path to exactly one existing FileSystem file ([IO.FileInfo]) or return $null.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Accepts a path (or FileInfo/DirectoryInfo) and enforces strict "one real file" semantics:<br>- Must exist<br>- Must be FileSystem provider<br>- Must not be a directory<br>- If wildcards are used, they must match exactly one item</p>
<p class="script-details-text">On failure, emits a tagged _Write-FunctionError ([RFFP-*]) including both the original input and (when available)<br>the resolved full path, then returns $null (caller decides whether to stop via -ErrorAction).</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>System.IO.FileInfo or $null.</p>
</details>
</div>
<div class="function-entry">
<p class="function-name"><strong>Test-BufferIsValidUtf8</strong></p>
<p class="function-synopsis">Validates that a byte[] buffer is UTF-8, while intentionally tolerating an incomplete final UTF-8 sequence.</p>
<details class="script-details function-details">
<summary>Read more</summary>
<p class="script-details-text">Returns $true if the buffer contains no invalid UTF-8 sequences in its body.</p>
</details>
</div>
</div>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="Install-PrepLapCode.ps1">Install-PrepLapCode.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="Install-PrepLapCode.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for Install-PrepLapCode.ps1" aria-label="Copy download command for Install-PrepLapCode.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Only relevant to mazars (Install/Update mazars-prepare-laptop-code)</p>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="Out-PingStats.ps1">Out-PingStats.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="Out-PingStats.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for Out-PingStats.ps1" aria-label="Copy download command for Out-PingStats.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Continuously pings a host, or a small set of public hosts, and displays live connection-quality statistics.</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">Out-PingStats is an interactive terminal monitor for ICMP latency and packet loss.</p>
<p class="script-details-text">When you specify -Target, it continuously pings that host and renders live graphs and summaries for:<br>- recent RTT values<br>- RTT histogram<br>- rolling loss percentage<br>- rolling one-way jitter estimate<br>- rolling RTT 95th percentile</p>
<p class="script-details-text">When you omit -Target, it probes a few well-known Internet hosts in parallel and treats the result as a rough<br>"Internet reachability and quality" indicator rather than a measurement for one exact destination.</p>
<p class="script-details-text">The display updates continuously until you stop it, typically with Ctrl+C.</p>
<p class="script-details-text">This command is intended for human monitoring in a console window. Its primary output is a live screen display,<br>not pipeline-friendly structured objects.</p>
<p class="script-details-text">For best-looking graphs, use a monospace font with good Unicode block-character support. DejaVu Sans Mono works<br>well. Consolas usually forces lower-resolution graph characters.</p>
<p class="script-details-text">.INTERACTIVE CONTROLS<br>While the monitor is running, you can use:<br>Ctrl-H Toggle RTT histogram<br>Ctrl-R Toggle recent-RTT graph<br>Ctrl-L Toggle loss graph<br>Ctrl-J Toggle jitter graph<br>Ctrl-S Toggle graph character set / font mode</p>
<p class="script-details-text">.PARAMETER Target<br>Host name or IP address to probe.</p>
<p class="script-details-text">If omitted, the command monitors general Internet quality by pinging several public hosts in parallel.</p>
<p class="script-details-text">.PARAMETER Title<br>Custom title shown at the top of the screen.</p>
<p class="script-details-text">By default, the title is derived from -Target, or shows a generic Internet-oriented title when -Target is omitted.</p>
<p class="script-details-text">.PARAMETER GraphMax<br>Upper Y-axis limit for RTT graphs.</p>
<p class="script-details-text">By default, the command chooses a sensible value automatically.</p>
<p class="script-details-text">.PARAMETER PingsPerSec<br>Deprecated. Currently has no practical effect.</p>
<p class="script-details-text">.PARAMETER GraphMin<br>Lower Y-axis limit for RTT graphs.</p>
<p class="script-details-text">By default, the command chooses a sensible value automatically.</p>
<p class="script-details-text">.PARAMETER HistBucketsCount<br>Number of buckets to use in the RTT histogram.</p>
<p class="script-details-text">.PARAMETER AggregationSeconds<br>Number of seconds per aggregation period for the slower trend graphs such as loss, jitter, and RTT 95th percentile.</p>
<p class="script-details-text">.PARAMETER HistSamples<br>Number of recent samples to include in the RTT histogram.</p>
<p class="script-details-text">If omitted, the default is at least 100 samples and otherwise about one minute of samples.</p>
<p class="script-details-text">.PARAMETER Visual<br>Reserved legacy parameter. Do not rely on it.</p>
<p class="script-details-text">.PARAMETER DebugMode<br>Enables diagnostic behavior and reduces screen-clearing behavior to help troubleshoot parsing, aggregation,<br>or rendering issues.</p>
<p class="script-details-text">.PARAMETER DebugData<br>Enables extra debug-data collection.</p>
<p class="script-details-text">.PARAMETER HighResFont<br>Controls graph-character mode.</p>
<p class="script-details-text">-1 = auto-detect<br>0 = force low-resolution characters<br>1 = force high-resolution characters</p>
<p class="script-details-text">Use low-resolution mode for terminals or fonts that do not render the Unicode block characters cleanly.</p>
<p class="script-details-text">.PARAMETER UpdateScreenEvery<br>How often, in seconds, the screen is refreshed.</p>
<p class="script-details-text">Lower values make the display more responsive but may increase CPU use.</p>
<p class="script-details-text">.PARAMETER BarGraphSamples<br>How many recent samples to show in the scrolling bar graphs.</p>
<p class="script-details-text">By default, the command derives this from the current console width.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Out-PingStats google.com</p>
<p class="script-details-text">Continuously monitors latency, loss, jitter, and latency distribution to google.com.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Out-PingStats 1.1.1.1 -Title "Cloudflare DNS"</p>
<p class="script-details-text">Monitors 1.1.1.1 and shows a custom title.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Out-PingStats</p>
<p class="script-details-text">Shows a rough live view of general Internet quality by probing several public hosts in parallel.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Out-PingStats 8.8.8.8 -GraphMin 0 -GraphMax 100 -AggregationSeconds 60</p>
<p class="script-details-text">Monitors 8.8.8.8 with fixed RTT graph limits and 1-minute aggregation windows.</p>
<p class="script-details-text"><span class="detail-directive">.NOTES</span><br>This command starts background jobs and cleans them up when it exits.</p>
<p class="script-details-text">It also writes temporary screen/statistics data files under $env:TEMP.</p>
<p class="script-details-text">Loss, jitter, and percentile values are intended for operational monitoring, not for strict scientific measurement.</p>
<p class="script-details-text"><span class="detail-directive">.OUTPUTS</span><br>None. This command is designed for interactive console display.</p>
<p class="script-details-text"><span class="detail-directive">.INPUTS</span><br>None. This command does not accept pipeline input.</p>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="Run-DismSfc.ps1">Run-DismSfc.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="Run-DismSfc.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for Run-DismSfc.ps1" aria-label="Copy download command for Run-DismSfc.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Safe* and automatic DISM + SFC repairs made easy.</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">Runs CHKDSK, DISM(CheckHealth/RestoreHealth) and SFC with preflight checks, concise console output, and logging.<br>Designed to minimize risk* and be thourough.</p>
<p class="script-details-text">*: REGARDING SAFETY</p>
<p class="script-details-text">This script is safe to run on Windows installations with no weird customizations,<br>Don't use it on boxes with OEM-customized, but still WRP-protected components,<br>or older apps that replace protected system binaries.</p>
<p class="script-details-text">.PARAMETER Source<br>Optional, one or more DISM sources, e.g. 'WIM:D:\sources\install.wim:1','ESD:E:\sources\install.esd:6'.</p>
<p class="script-details-text">.PARAMETER ScratchDirectory<br>Optional scratch directory for servicing if supported (offloads staging from C:).</p>
<p class="script-details-text">.PARAMETER MinFreeSystemGB<br>Minimum free GB on system drive before running heavy servicing (default 4GB).</p>
<p class="script-details-text">.PARAMETER MinFreeScratchGB<br>Minimum free GB on ScratchDirectory if provided. (default 4GB)</p>
<p class="script-details-text">.PARAMETER LimitAccess<br>Use only -Source and avoid Windows Update (WU/WSUS). Use this along with -Source. PREFER TO AVOID THIS OPTION.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>.\Run-DismSfc.ps1 -Source 'WIM:D:\sources\install.wim:1'</p>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="Start-Copy4Toula.ps1">Start-Copy4Toula.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="Start-Copy4Toula.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for Start-Copy4Toula.ps1" aria-label="Copy download command for Start-Copy4Toula.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Minimize copy-pasting and typing while using an LLM like Toula-the-fixer to troubleshoot issues.</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">HOW TO USE ME<br>Begin by opening a terminal and dot-sourcing this script. E.g.:</p>
<p class="script-details-text">$p="C:\IT\bin";$f="Start-Copy4Toula.ps1";mkdir $p -force >$null<br>iwr -useb https://ndemou.github.io/scripts/$f -out $p\$f<br>. C:\IT\bin\Start-Copy4Toula.ps1</p>
<p class="script-details-text">Then repeat these steps:<br>1. Copy code from the LLM<br>2. Run `q` in the terminal (it will execute the code _and_ copy back the results)<br>3. Go back to the LLM and paste the output.</p>
<p class="script-details-text">If you run commands directly, or accidentally press ctrl-C you can<br>run `q -CopyOnly` to copy all output since the last time you run either `q`.</p>
<p class="script-details-text">DETAILS<br>The script maintains two transcript files:<br>- `$env:TEMP\TTFtrans-$PID.full.txt` has the cumulative raw history of the full session.<br>- `$env:TEMP\TTFtrans-$PID.txt` has just the most recent chunk of output.</p>
<p class="script-details-text">`q` will copy up to 5000 lines by default. You can change the limit:<br>$global:SctMaxLinesToCopy = 8000</p>
<p class="script-details-text">The output of some rare legacy tools may not appear in the transcript.<br>It's extremely rare though and you can always copy-paste manually.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>. .\Start-Copy4Toula.ps1<br>q<br>q</p>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="Test-ForCpuRamDiskStress.ps1">Test-ForCpuRamDiskStress.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="Test-ForCpuRamDiskStress.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for Test-ForCpuRamDiskStress.ps1" aria-label="Copy download command for Test-ForCpuRamDiskStress.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Prints a detailed warning every time it finds RAM, CPU or Disks are stressed</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">There are two modes of operation: monitoring and log file analysis.</p>
<p class="script-details-text">In monitor mode (the default) it prints a detailed warning every<br>time it finds RAM, CPU or Disks are stressed.</p>
<p class="script-details-text">In monitor mode these switches may be used.<br>-MonitorVolumes: Will also monitor IO stress of Volumes<br>-DontMonitorDisks: Will NOT monitor IO stress of disks</p>
<p class="script-details-text">In log analysis (invoked if you supply a -LogFile) it creates a<br>summary report based on the contents of the log file.</p>
<p class="script-details-text">In log analysis mode these arguments may be used.<br>-Granularity<br>-LogsToIgnoreRegex</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Download & Setup to always run on startup<br>$bin="C:\IT\bin";$log="C:\it\log"<br>$f="Test-ForCpuRamDiskStress.ps1";mkdir $bin -force >$null;mkdir $log -force > $null<br>iwr -useb https://ndemou.github.io/scripts/$f -OutFile $bin\$f</p>
<p class="script-details-text">$f="helpers-processes.ps1"; iwr -useb https://ndemou.github.io/scripts/$f -OutFile $bin\$f; . $bin\$f<br>New-ScheduledTaskForPSScript -ScriptPath "$bin\Test-ForCpuRamDiskStress.ps1" -ScheduleType Startup -ScriptArguments "-LogDir",$log<br>Start-ScheduledTask -TaskPath '\enLogic\' -TaskName 'Execute Test-ForCpuRamDiskStress.ps1'<br><span class="detail-directive">.EXAMPLE</span><br>Get statistics for a particular date<br>& $bin\Test-ForCpuRamDiskStress.ps1 -Granularity 10m -LogFile C:\it\log\CpuRamDiskStress.2026-01-14.log</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>If you want to run only once:<br>& C:\IT\bin\Test-ForCpuRamDiskStress.ps1 -LogDir c:\it\log -LogBaseName 'CpuRamDiskStress'</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>What you see if memory is under pressure.<br>C:\IT\bin\Test-ForCpuRamDiskStress.ps1 | Tee-Object "C:\it\temp\CpuRamDiskStress.log"</p>
<p class="script-details-text">20:12:47 HIGH <HOSTNAME> Reasons:<br>- Available memory minimum 0,5% is below the 5% threshold while average Page Reads/sec is 319, above the 150 threshold. Low headroom with active hard faults indicates real stress.<br>- High classification gate satisfied: Available memory(%) minimum 0,5 is below the 10% gate threshold.<br>Measurements:<br>- Time window: 18 secs (9 samples)<br>- Available memory: average 68,3%, minimum 0,5%<br>- Committed memory: average 31,9%, maximum 67,0%<br>- Paging file usage: maximum 73%<br>- Page Reads/sec (hard faults): average 319, maximum 1.789<br>- Page Writes/sec: average 23, maximum 203<br>- Transition Faults/sec: average 1.281, maximum 6.797<br>- Disk read latency: average 0,0 ms<br>- Disk write latency: average 0,0 ms<br>- Disk queue length: average 7,3<br>- Standby cache memory: Normal 58 MB, Reserve 222 MB, Core 0 MB<br>- File cache memory: 4 MB<br>- Modified page list: 134 MB<br>- Compressed memory: 0 MB</p>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="update-all-github-ndemou-scripts.ps1">update-all-github-ndemou-scripts.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="update-all-github-ndemou-scripts.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for update-all-github-ndemou-scripts.ps1" aria-label="Copy download command for update-all-github-ndemou-scripts.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Ensures all ndemou.github.io/scripts are up-to-date.</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">Existing files that differ are replaced and a backup is created.<br>Identical files are left unchanged.</p>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="Update-GetHealthCode.ps1">Update-GetHealthCode.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="Update-GetHealthCode.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for Update-GetHealthCode.ps1" aria-label="Copy download command for Update-GetHealthCode.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Ensures all health-check scripts and PS Modules are installed & up-to-date.</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">Missing files are created. Existing files that differ are replaced.<br>Identical files are left unchanged. If this script updates itself,<br>it re-invokes the updated copy. When replacing a file, backup copies<br>are created in the backups directory.<br>Will set PSGallery as Trusted.</p>
<p class="script-details-text">The updater also tracks a small "release marker" for the currently<br>installed code and for the target update source. A release marker is a<br>stable identifier for a specific release source, typically derived from<br>GitHub release metadata or from a manually supplied zip file name plus<br>its content hash. These markers are cached locally and let the updater<br>decide whether the requested update is already installed, whether it can<br>skip re-downloading or reapplying files, and when `-Reinstall` should<br>force the update to run again.</p>
<p class="script-details-text">.PARAMETER Reinstall<br>Forces reinstall even when installed release matches target release.</p>
<p class="script-details-text">.PARAMETER UpdateFromZip<br>Overides the default which is to fetch the latest GitHub release.</p>
<p class="script-details-text">.PARAMETER Version<br>Explicit semantic version to associate with `-UpdateFromZip` when the zip<br>file name does not already embed a version token such as `v4.4.3`.<br>Use `X.Y.Z` or `vX.Y.Z`.</p>
<p class="script-details-text">.PARAMETER ForceRefreshReleaseMetadata<br>Overides the default which is to cache latest-release metadata locally<br>for a few minutes (to avoid querying GitHub on every run).</p>
<p class="script-details-text">.PARAMETER SelfRerunCount<br>Internal use only. Tracks the one-time self-rerun pass count.</p>
<p class="script-details-text">.PARAMETER PersistReleaseMarker<br>Internal use only. Carries the resolved release marker across self-rerun.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>.\Update-GetHealthCode.ps1</p>
<p class="script-details-text">Checks the locally cached latest-release metadata, refreshes it from<br>GitHub when needed, and installs the latest published release when it is<br>newer than the currently installed release marker.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>.\Update-GetHealthCode.ps1 -UpdateFromZip C:\Downloads\GetComputerHealth-v4.4.3.zip</p>
</details>
</li>
<li class="script-item">
<div class="script-header">
<a class="script-link" href="WindowsUpdatesHelper.ps1">WindowsUpdatesHelper.ps1</a>
<button class="copy-button" data-copy="$dir="C:\IT\bin";$f="WindowsUpdatesHelper.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f" title="Copy download command for WindowsUpdatesHelper.ps1" aria-label="Copy download command for WindowsUpdatesHelper.ps1"><svg viewBox="0 0 16 16" aria-hidden="true" focusable="false"><path d="M5 2.75A1.75 1.75 0 0 1 6.75 1h5.5A1.75 1.75 0 0 1 14 2.75v6.5A1.75 1.75 0 0 1 12.25 11h-5.5A1.75 1.75 0 0 1 5 9.25zm1.75-.25a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-6.5a.25.25 0 0 0-.25-.25z"></path><path d="M2 5.75C2 4.784 2.784 4 3.75 4h.5a.75.75 0 0 1 0 1.5h-.5a.25.25 0 0 0-.25.25v6.5c0 .138.112.25.25.25h5.5a.25.25 0 0 0 .25-.25v-.5a.75.75 0 0 1 1.5 0v.5A1.75 1.75 0 0 1 9.25 14h-5.5A1.75 1.75 0 0 1 2 12.25z"></path></svg> </button>
</div>
<p class="script-synopsis">Installs Windows Updates using the supported WUA COM API, with optional download, controlled reboot (now or scheduled), and detailed logging.</p>
<details class="script-details">
<summary>Read more</summary>
<p class="script-details-text">SPECIAL SHOW UPDATE HISTORY MODE</p>
<p class="script-details-text">If -ShowHistory is used, the script does NOT install/download/reboot.<br>Instead it queries Windows Update history (same source as the GUI "View update history"),<br>optionally filtered, and then exits.</p>
<p class="script-details-text">NORMAL INSTALL UPDATES MODE</p>
<p class="script-details-text">By default(without -ShowHistory) it installs Windows updates like this:<br>- Installs already downloaded updates if any.<br>- With -Download, will also download all required updates.<br>- With -Reboot, will reboot after installation if needed (or regardless with -RebootAnyway).</p>
<p class="script-details-text">Batches "normal" updates together; installs "exclusive" updates one-by-one; accepts EULAs.</p>
<p class="script-details-text"># Regarding Robustness<br>- Service start is retried up to 3x with exponential delays (5s, 10s, 20s) before failing.<br>- Pending reboot detection uses WU `RebootRequired` and CBS `RebootPending`.<br>- Post-download refresh search has a catch/fallback: if the refresh search throws, proceeds using the initial search results (with a warning).<br>- Uses only supported, inbox components (no extra modules, no `UsoClient`, PS 5.1-safe syntax).<br>- Reboot is first tried without /f and after a few minutes with /f.</p>
<p class="script-details-text">If an update (e.g. Servicing Stack) installs and immediately requires a reboot; subsequent updates will fail with 0x80240030 until reboot. If such failures are detected and the script was run with -Reboot or -RebootAnyway,<br>the script will ensure continuation of installations after the reboot like this:<br>- Create a temporary scheduled task that runs this script again<br>at startup with -XXX_ResumeAfterReboot.<br>- On that second automated run with -XXX_ResumeAfterReboot: The startup<br>task is removed and the script continues as normal (install + maybe reboot).</p>
<p class="script-details-text"># Logging<br>Logs everything to `WindowsUpdateHelper-YYYY-MM-DD.log`<br>1. If C:\IT\LOG exists, log is created there.<br>2. Else if C:\IT\LOGS exists, there.<br>3. Else in the system temp folder.</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>The fastest way to bring a new installation up-to-date:<br>**CAUTION**: WILL REBOOT WITHOUT WAITING / WITHOUT ASKING<br>Download & first run<br>Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force<br>$p="C:\it\bin";mkdir $p -force >$null<br>$f="WindowsUpdatesHelper.ps1";iwr -useb https://wiki.enlogic.gr/pub/KnowledgeBase/PublicFiles/$f -OutFile $p\$f<br>& C:\it\bin\WindowsUpdatesHelper.ps1 -Download -Reboot</p>
<p class="script-details-text">2nd Run (REPEAT UNTIL YOU GET 0 Updates Found)<br>& c:\it\bin\WindowsUpdatesHelper.ps1 -Download -Reboot -Interactive<br>It will also install updates that MAY ask you to accept EULAs or make choices<br><span class="detail-directive">.EXAMPLE</span><br>Display the logs from the last 10 executions of this script<br>& c:\it\bin\WindowsUpdatesHelper.ps1 -ListRecentLogs | %{cat $_.fullname|sls -NotMatch '^(Machine|Host Application|Process ID|Log file|Configuration Name|Username|End time|[A-Z][a-z]*(Versions?|Edition)): '}</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>**CAUTION**: An unfortunate side-effect of this script is that the updates<br>it installs are not visible in the GUI (Settings -> Windows Updates).<br>The only way to view them:<br>& c:\it\bin\WindowsUpdatesHelper.ps1 -ShowHistory | ft<br>You may add -IncludeAV if you want to also view (the very frequent) Antivirus udpates</p>
<p class="script-details-text">.PARAMETER Download<br>Perform online scan and download applicable updates that are not yet downloaded, then proceed to install everything downloaded.</p>
<p class="script-details-text">.PARAMETER Reboot<br>After installation, reboot only if updates require it (or regardless if -RebootAnyway is also used).</p>
<p class="script-details-text">.PARAMETER Interactive<br>If specified, the script will include updates flagged as InstallationBehavior.CanRequestUserInput<br>(Like some drivers/firmware that show GUI prompts and wait for user actions -- e.g. clicking "Accept").<br>Without this switch, such updates are skipped.<br>Alias: -CanRequestUserInput</p>
<p class="script-details-text">.PARAMETER RebootAnyway<br>Reboot regardless of whether updates require it (implies -Reboot).</p>
<p class="script-details-text">.PARAMETER XXX_ResumeAfterReboot<br>DO NOT USE THIS SWITCH. It is used INTERNALLY to continue installations after a reboot.</p>
<p class="script-details-text">.PARAMETER AbortReboot<br>Abort a reboot initiated by this script</p>
<p class="script-details-text">.PARAMETER XXX_RebootNow<br>DO NOT USE THIS SWITCH. It is used INTERNALLY to force a reboot.</p>
<p class="script-details-text">.PARAMETER XXX_RebootArmedAt<br>DO NOT USE THIS SWITCH. It is used INTERNALLY to avoid rebooting if a reboot already occured after this time.</p>
<p class="script-details-text">.PARAMETER ShowHistory<br>List Windows Update history (no install/download/reboot) and exit.</p>
<p class="script-details-text">.PARAMETER MaxResults<br>(ShowHistory mode) Maximum number of matching history entries to output. Default: 30. Use 0 to return all matches found (within MaxScanEntries).</p>
<p class="script-details-text">.PARAMETER LastDays<br>(ShowHistory mode) Only include history entries from the last N days.</p>
<p class="script-details-text">.PARAMETER IncludeAV<br>(ShowHistory mode) Include KB2267602 (Defender definitions) entries (excluded by default).</p>
<p class="script-details-text">.PARAMETER MaxScanEntries<br>(ShowHistory mode) Safety cap: maximum number of history rows to scan. Default: 10000.</p>
<p class="script-details-text">.PARAMETER ListRecentLogs<br>List this script's log files and exit. Returns FileInfo objects sorted by LastWriteTime (oldest -> newest; most recent last).<br>By default it returns the most recent 10 log files.</p>
<p class="script-details-text">.PARAMETER ListAll<br>Used only with -ListRecentLogs. If specified, returns all log files that can be found (instead of only the most recent 10).</p>
<p class="script-details-text">.PARAMETER InstallOptional<br>Installs an optional update (needs the update ID)</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Install any already downloaded updates and reboot if needed:<br>.\WindowsUpdatesHelper.ps1 -Reboot</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Download, Install and if needed reboot:<br>.\WindowsUpdatesHelper.ps1 -Download -Reboot</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Download, Install and reboot regardless of whether updates require it:<br>.\WindowsUpdatesHelper.ps1 -Download -Reboot -RebootAnyway</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Show latest Windows Update history entries:<br>.\WindowsUpdatesHelper.ps1 -ShowHistory</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>Show latest Windows Update history entries, include AV updates:<br>.\WindowsUpdatesHelper.ps1 -ShowHistory -LastDays 14 -IncludeAV</p>
<p class="script-details-text"><span class="detail-directive">.EXAMPLE</span><br>List the most recent 10 log files created by this script (most recent last):<br>.\WindowsUpdatesHelper.ps1 -ListRecentLogs</p>
</details>
</li>
</ul>
<p class="footer">
Source repository:
<a href="https://github.com/ndemou/scripts">github.com/ndemou/scripts</a>
</p>
</main>
<script>
document.addEventListener("click", async (event) => {
const button = event.target.closest(".copy-button");
if (!button) return;
const text = button.getAttribute("data-copy");
if (!text) return;
try {
await navigator.clipboard.writeText(text);
button.classList.add("copied");
setTimeout(() => button.classList.remove("copied"), 1200);
} catch {
button.classList.add("copy-failed");
setTimeout(() => button.classList.remove("copy-failed"), 1200);
}
});
</script>
</body>
</html>