Available scripts & functions
-
Deletes selected junk files and directories from a copied disk tree, with conservative defaults and full WhatIf/Confirm support.
Read more
Clear-DiskJunk scans a target path and removes only the junk categories you explicitly allow.
By default it runs in conservative mode and targets:
- browser-caches
- safe-temp-files
Conservative mode avoids deleting generic directory names such as cache, temp, log, or logs unless you explicitly include
DANGEROUS-broad-temp-cache-logs.
The function is designed for very large trees. It streams matches as they are found instead of accumulating all results in memory.
Use -PassThru to emit one result object per matched item. Without -PassThru it emits only a final summary object.
safe-temp-files deletes:
- *.tmp files older than 30 days
- Office temp files (~$*.??? and ~$*.????)
DANGEROUS-broad-temp-cache-logs expands matching to broad generic temp/cache/log locations and broad *.log / *.tmp file cleanup.
.EXAMPLE
Clear-DiskJunk -Path D:\MountedDisk -WhatIf
Shows what would be deleted using the conservative default categories.
.EXAMPLE
Clear-DiskJunk -Path D:\MountedDisk -IncludeCategory browser-caches,DANGEROUS-broad-temp-cache-logs -Confirm
Prompts before deleting and includes the dangerous broad cleanup category.
.EXAMPLE
Clear-DiskJunk -Path D:\MountedDisk -ExcludePath 'D:\MountedDisk\Users\Nick\AppData\Local\Google\*' -PassThru |
Export-Csv C:\temp\diskjunk-results.csv -NoTypeInformation
Streams one result object per matched item and saves them.
.PARAMETER Path
Root path to scan.
.PARAMETER IncludeCategory
Cleanup categories to include.
Allowed values:
- browser-caches
- safe-temp-files
- DANGEROUS-broad-temp-cache-logs
Default:
- browser-caches
- safe-temp-files
.PARAMETER ExcludePath
Paths or wildcard patterns to exclude. Matches are tested against both full Windows paths and root-relative forward-slash paths.
.PARAMETER TmpOlderThanDays
Age threshold for *.tmp deletion in the safe-temp-files category. Default is 30.
.PARAMETER PassThru
Emits one object per matched item as it is processed. Useful for logging and large-scale runs.
.OUTPUTS
Without -PassThru:
A summary object.
With -PassThru:
One result object per matched item, followed by a final summary object.
.NOTES
- Supports -WhatIf and -Confirm.
- Intended primarily for copies of Windows disks, not live system cleanup.
- Broad cleanup can remove data you may later want for troubleshooting or forensics.
-
Shows a compact, admin-friendly timeline of recent boots, shutdowns,
crashes, and update-related restart signals from the System log.
Read more
Use this for first-pass reboot and shutdown triage. It helps answer
whether a recent restart was clean, unexpected, crash-related, planned
by an administrator or process, or associated with Windows Updates.
.OUTPUTS
Produces one PSCustomObject per matching event:
Level : Event level text.
Time : Event time.
Kind : Event category. One of:
Boot, NormalShutdown, PlannedShutdownOrRestart,
WindowsUpdatesInstallStarted, WindowsUpdatesInstallCompleted,
WindowsUpdatesRestartRequired, WindowsUpdatesRestart
BugCheck, CrashDump, AbnormalShutdown,
UnexpectedShutdownFollowup, Other
Description : First line of the event message with source metadata
appended as "(id <n> from <provider>)".
Intentionally excludes noise about Microsoft Defender updates.
.EXAMPLE
PS C:\> Get-BootShutdownEvents |ft
Level Time Kind Description
Info 15/3 6:00:47 WindowsUpdatesInstallStart Installation Started: Windows has started installing the following update: 2026-03 Cumulative Update for Microsoft ...
Info 15/3 6:19:54 WindowsUpdatesRestart The process C:\WINDOWS\system32\shutdown.exe (SRV2) has initiated the restart of computer SRV2 ...
Info 15/3 6:22:06 NormalShutdown The Event log service was stopped. (id 6006 from EventLog)
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)
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)
Info 15/3 6:22:22 Boot The Event log service was started. (id 6005 from EventLog)
Info 15/3 6:22:44 WindowsUpdatesRestart The process C:\WINDOWS\servicing\TrustedInstaller.exe (SRV2) has initiated the restart of computer SRV2...
Info 15/3 6:22:45 NormalShutdown The Event log service was stopped. (id 6006 from EventLog)
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)
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)
Info 15/3 6:22:59 Boot The Event log service was started. (id 6005 from EventLog)
Info 15/3 6:23:20 WindowsUpdatesInstallCompl Installation Successful: Windows successfully installed the following update: 2026-03 Cumulative Update for Microsoft ...
-
A collection of helper functions for Domain Controllers
Read more
Search-ADUserAnyProperty
Search Active Directory users by a pattern across multiple common attributes.
Read more
This function wraps Get-ADUser with a wide LDAP filter that checks a user-supplied
pattern against multiple commonly used identifier attributes (e.g. sAMAccountName,
userPrincipalName, displayName, cn, givenName, sn, mail, proxyAddresses).
It's intended as a convenient "search anywhere that matters" for finding users when
you only know part of a name, email, alias, or login.
Results include useful profile fields: Display Name, Department, Job Title, State,
Company, OU (derived from DistinguishedName), and all proxyAddresses flattened into
a comma-separated list. Optionally you can also search phone fields and/or restrict
the search scope with -SearchBase.
.PARAMETER Pattern
The text pattern to search for (wildcards are automatically added at both ends).
.PARAMETER SearchBase
Optional LDAP distinguished name to scope the search.
.PARAMETER IncludePhones
If specified, phone-related attributes are included in the search (makes the search a bit slower)
.EXAMPLE
# Find any user whose name, alias, or email contains "nick"
Search-ADUserAnyProperty -Pattern 'nick'
.EXAMPLE
# Search within a specific OU, also matching phone numbers
Search-ADUserAnyProperty -Pattern '2103' -IncludePhones -SearchBase 'OU=Athens,OU=Users,DC=corp,DC=example,DC=com'
.EXAMPLE
# Export results to CSV
Search-ADUserAnyProperty -Pattern 'nick' |
Export-Csv C:\temp\ad-search.csv -NoTypeInformation -Encoding UTF8
-
A collection of helper functions for handling files
Read more
Get-HardLinks
Lists files in the current directory that have >1 hardlink, and shows all link paths
Read more
.EXAMPLE
Get-HardLinks|Format-List
New-ZipFromFolder
Creates a zip file from a folder, keeping the folder as the top-level entry and allowing for exclusions.
Read more
Packages the source folder into a zip file whose top-level folder name
matches the source folder name. Allows for recursive exclusions based
on file name, folder name, or relative path.
Creates a sibling staging folder next to the source folder and removes
it before returning. On NTFS volumes, included files are staged as
hardlinks unless DontUseHardLinks is set. Hardlinking is super-fast.
.PARAMETER Exclude
Wildcard patterns used to skip files or folders anywhere under the
source folder. A pattern can match an item name or a relative path.
.PARAMETER NoCompression
When set, writes the archive without compression.
.PARAMETER Fast
When set, writes the archive with the fastest compression level.
.PARAMETER DontUseHardLinks
When set, stages included files by copying them; otherwise the function
uses hardlinks when the source volume supports them.
.EXAMPLE
New-ZipFromFolder .\App .\App.zip `
-Exclude '*.bak','*.tmp','.git'
Creates the zip while skipping matching files and folders under App.
Delete-OldFiles
Deletes old files under a directory tree, with WhatIf support.
Read more
Attempts to remove files under Root whose LastWriteTime is older than Cutoff.
Use this when you need recursive age-based cleanup with WhatIf support and
optional cleanup of child folders left empty by the cleanup.
Skips reparse points (junctions/symlinks/mount points) so cleanup stays inside
the intended tree.
By default, non-root child folders will be removed when they have no
remaining files or child folders after file cleanup. Root is not
removed. When LeaveEmptyFolders is set, folders are not removed.
Deletion failures for individual files or folders are reported as warnings.
Other matching files and folders may still be processed. Permission limits,
locked files, and enumeration errors can leave matching files or folders in
place.
.OUTPUTS
None. Does not write objects to the pipeline.
Writes scan and deletion status to the host.
Writes warnings for failed file or folder removals.
.PARAMETER Root
Directory tree to clean. The path must identify an existing directory.
.PARAMETER Cutoff
Files with LastWriteTime earlier than this value are candidates for removal.
.PARAMETER LeaveEmptyFolders
When set, only matching files are removed; otherwise, non-root child folders
left empty by the cleanup scope may also be removed.
.EXAMPLE
Delete-OldFiles -Root C:\Temp -Cutoff (Get-Date).AddMonths(-6) -WhatIf
Shows the files and folders that would be removed under C:\Temp.
.EXAMPLE
Delete-OldFiles -Root C:\Temp -Cutoff (Get-Date).AddMonths(-6) `
-LeaveEmptyFolders
Removes old files under C:\Temp but does not remove empty folders.
Get-DiskInfo
Gets Win32_LogicalDisk information for one disk.
Read more
Popular properties: FreeSpace, Size, VolumeName, DriveType
.PARAMETER Disk Disk device ID, for example C:.
Test-NonReparseDirectory
Returns true only for real directories, not junctions/symlinks.
Read more
.PARAMETER LiteralPath Directory path to test without wildcard expansion.
Clear-OldTempFiles
Deletes old files from common Windows temporary file locations.
Read more
Attempts to remove old files from the current process TEMP and TMP
locations, the Windows temp location, and detected user temp folders under
C:\Users.
Skips reparse points (junctions/symlinks/mount points) so cleanup stays inside
the intended trees.
Use this as a safer temp cleanup entry point when you need age-based cleanup
across the usual system and user temp locations, WhatIf support, and optional
cleanup of child folders left empty by the cleanup.
The cutoff is calculated from the current time and MonthsOld. By default,
non-root child folders inside each temp root may also be removed when they
have no remaining detected files or child folders after file cleanup. Temp
root folders themselves are not removed.
Deletion failures for individual files or folders are reported as warnings.
Other matching files and folders may still be processed. Permission limits,
locked files, missing profiles, and enumeration errors can leave matching
files or folders in place. Run elevated to cover system and other-user temp
locations where required.
.OUTPUTS
None. Does not write objects to the pipeline.
Writes cutoff, scan, and deletion status to the host.
Writes warnings for failed file or folder removals.
.PARAMETER MonthsOld
Age threshold in months. Files older than the calculated cutoff are
candidates for removal.
.PARAMETER LeaveEmptyFolders
When set, only matching files are removed; otherwise, non-root child folders
left empty by the cleanup will also be removed.
.EXAMPLE
Clear-OldTempFiles -WhatIf
Shows the old temp files and folders that would be removed.
.EXAMPLE
Clear-OldTempFiles -MonthsOld 3 -LeaveEmptyFolders
Removes temp files older than the calculated cutoff and keeps folders.
-
A collection of helper functions for Networking
Read more
Get-RemoteIpOnLowListeningTcpPort
Lists remote IPs observed on local listening TCP ports.
Read more
.OUTPUTS
Produces one psCustomObject per remote IP:
RemoteAddress : The remote IP address.
LocalPorts : The local listening port or ports observed.
States : The TCP state or states observed.
ConnectionCount : The number of matching TCP connection rows.
.DESCRIPTION
Reports remote IPs that currently have, or still have visible closed TCP
rows for, non-loopback local listening TCP ports below the configured
port limit.
Use this when you need a compact connection inventory by remote IP,
rather than raw connection rows. The result is a point-in-time view of
the TCP table. Connections removed by Windows before the function runs
are not reported.
By default, loopback, wildcard, and the server's own IP addresses are
excluded from remote addresses. This avoids reporting connections from
the server to itself.
.PARAMETER MaxListeningPortExclusive
Upper exclusive local listening port limit. Only listening TCP ports
below this value are considered.
.PARAMETER States
TCP states to include. Use names accepted by the State property, such
as Established, TimeWait, CloseWait, LastAck, FinWait1, and FinWait2.
.PARAMETER IncludeLocalMachineConnections
When set, connections whose remote address is one of the server's own
IP addresses may be included. Otherwise, they are excluded.
.EXAMPLE
Get-RemoteIpOnLowListeningTcpPort
Returns one row per remote IP, with the observed local ports, observed
TCP states, and matching connection-row count.
.EXAMPLE
Get-RemoteIpOnLowListeningTcpPort -Verbose
Returns the same objects and writes the matched connection details to
the verbose stream.
Watch-RemoteIpOnLowListeningTcpPort
Watches and optionally reports remote IPs observed on local listening TCP ports.
Read more
Maintains a cumulative record of remote IPs observed on non-loopback local
listening TCP ports below the configured port limit.
The watch continues until interrupted, for example with Ctrl+C. By default,
it runs silently and does not produce success-stream output.
For each remote IP, the function records the first and last observation time.
Local ports and TCP states are accumulated for the lifetime of the stored
state.
When ShowReport is specified, the cumulative report is displayed periodically.
Report generation is controlled separately from connection sampling to avoid
repeatedly constructing a potentially large formatted report.
When StateFile is provided, the cumulative state is saved in CLIXML format.
If the file already exists, its observations are loaded and collection
continues from that state. This allows the watch to be stopped and resumed.
The parent directory of StateFile is created when necessary. State is first
written to a temporary file and then moved over the configured state file to
reduce the risk of leaving a partially written file.
.OUTPUTS
None by default.
When ShowReport is specified, the function writes a formatted report directly
to the host. The report contains:
RemoteAddress : The remote IP address.
LocalPorts : Local listening port or ports observed.
States : TCP state or states observed.
FirstSeen : First time the remote IP was observed.
LastSeen : Most recent time the remote IP was observed.
The formatted report is host output and is not written to the success-output
pipeline.
.PARAMETER Seconds
Number of seconds between TCP connection sampling cycles.
The default is 10 seconds.
.PARAMETER MaxListeningPortExclusive
Upper exclusive local listening port limit. Only listening TCP ports below
this value are considered.
The default is 49152.
.PARAMETER States
TCP states to include, such as Established, TimeWait, CloseWait, LastAck,
FinWait1, and FinWait2.
.PARAMETER IncludeLocalMachineConnections
Includes connections whose remote address is one of the server's own IP
addresses.
By default, loopback, unspecified, and local-machine remote addresses are
excluded.
.PARAMETER StateFile
Path to the CLIXML file used to load and save the cumulative observations.
The file contains structured state, not the formatted on-screen report.
.PARAMETER SaveIntervalSeconds
Minimum number of seconds between writes to StateFile.
The default is 60 seconds. This parameter has no effect when StateFile is not
specified.
.PARAMETER ShowReport
Displays the cumulative report periodically.
By default, reporting is disabled. Collection and StateFile updates continue
normally without this switch.
.PARAMETER ReportIntervalSeconds
Minimum number of seconds between displayed reports when ShowReport is
specified.
The default is 300 seconds. This parameter does not affect the connection
sampling interval.
.EXAMPLE
Watch-RemoteIpOnLowListeningTcpPort
Samples TCP connections every 10 seconds and maintains cumulative observations
in memory. It produces no regular report and does not persist the observations.
.EXAMPLE
Watch-RemoteIpOnLowListeningTcpPort `
-StateFile C:\IT\log\seen_tcp_connections.clixml
Samples TCP connections every 10 seconds, loads any existing observations from
the CLIXML file, and saves the cumulative state at intervals of at least
60 seconds. It does not display the cumulative report.
.EXAMPLE
Watch-RemoteIpOnLowListeningTcpPort `
-Seconds 5 `
-StateFile C:\Temp\observed-connections.clixml `
-ShowReport `
-ReportIntervalSeconds 300
Samples connections every 5 seconds, saves cumulative state to the CLIXML file,
and displays the cumulative report no more than once every 5 minutes.
Test-IpReachability
Probe point-in-time ICMP reachability for one or more IP targets.
Read more
Sends one or more ICMP echo attempts to each target and returns one output
object per unique target IP.
When a ping attempt cannot be performed due to an internal runtime error,
the target result's lastStatus is set to a string beginning with
"PROGRAM EXCEPTION:".
.OUTPUTS
[pscustomobject]
One object per unique target IP with properties:
- ip (string): The target IP string as provided/normalized.
- responded (bool): $true if any attempt succeeded; otherwise $false.
- attempts (int): Number of attempts made for that target.
- respondedOnAttempt (Nullable[int]): Attempt number of first success;
otherwise $null.
- rttMs (Nullable[long]): Round-trip time in milliseconds for the
successful response; otherwise $null.
- lastStatus (string): Final status observed for the target. For runtime
errors, begins with "PROGRAM EXCEPTION:".
.PARAMETER Ip
One or more target IPs to probe.
Accepts:
- A single value convertible to string.
- An enumerable of values convertible to string.
- A single string containing multiple targets separated by commas and/or
whitespace.
.PARAMETER Retry
Number of additional attempts per target after the first attempt.
.PARAMETER TimeoutMs
Timeout in milliseconds for each attempt.
.EXAMPLE
Test-IpReachability -Ip '10.1.11.50,10.1.11.55 10.1.11.56' `
-Retry 1 -TimeoutMs 500 -Verbose
Test-TcpPort
Quickly tests whether a TCP connection can be established.
Read more
Tests TCP connectivity from the current machine to the specified target
and ports, and returns one result object per requested port.
The target MAY be specified as an IP address or a hostname. If name
resolution fails, the function throws a terminating error.
Ports are accepted in multiple input forms.
The -TimeoutMs value is a single overall time budget (in milliseconds) for
the entire batch of ports, not a per-port timeout.
.OUTPUTS
System.Management.Automation.PSCustomObject
One object per normalized port, with these properties:
- port (int) The TCP port tested.
- open (bool) $true if a connection was established; otherwise $false.
- detail (string) "connected" on success; otherwise an error identifier
or "timeout" if the overall time budget was reached.
Objects are emitted in ascending port order.
.PARAMETER Target
Target host to test.
.PARAMETER Ports
Ports to test. Accepts:
- a single integer
- an array of integers
- a string containing one or more port numbers
- an enumerable of values convertible to integers
.PARAMETER TimeoutMs
Overall time budget for the entire batch, in milliseconds. Defaults to
200. When the budget is exhausted, remaining ports are reported as
"timeout".
.EXAMPLE
Test-TcpPort -Target '10.1.11.1' -Ports 80,443,4444
.EXAMPLE
Test-TcpPort -Target 'google.com' -Ports '80,443,4444' `
-TimeoutMs 1000
Test-NetConnectivityToHost
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. - If -HostFriendlyName is passed, it is used to refer to the host in all messages. 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
Split-IpByReachability
Splits input IPs into Alive vs NotAlive based on whether they respond to pings
Read more
Runs Test-IpReachability for the provided targets and returns a single object
containing two string arrays:
- AliveIps: IPs that responded ($true)
- DeadIps: IPs that did not respond ($false) or hit errors/timeouts
.INPUTS
Same accepted shapes as Test-IpReachability -Ip.
.OUTPUTS
[pscustomobject] with:
- AliveIps ([string[]])
- DeadIps ([string[]])
- Results ([pscustomobject[]]) raw per-IP results (handy for lastStatus/rtt)
Test-NetConnectivityToNetwork
Assesses reachability of a network by pinging a list of hosts that are known to reply.
Read more
Given a human-friendly network description (e.g. "10.11.x.y/16") and a list of
IP addresses that are expected to respond to ICMP, this function probes them
(using Split-IpByReachability) and outputs the results using:
Write-Warning "[<level>] ..."
(<level> is one of pass, notice, failure)
If -ReturnListOfAliveHosts is used, the function does not emit warnings and
instead returns the list of responsive hosts.
Test-ShareLikelyUp
QUICKLY tests whether the host of a UNC share is LIKELY reachable over SMB.
Read more
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.
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.
.PARAMETER SharePath
UNC share path whose host will be tested.
.PARAMETER DnsCidrs
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.
.PARAMETER TcpTimeoutMs
For the connection test to TCP port 445 (SMB).
.OUTPUTS
A PSCustomObject with the test outcome and discovered details.
.EXAMPLE
Test-ShareLikelyUp -SharePath '\\server01\share'
.EXAMPLE
Test-ShareLikelyUp -SharePath '\\192.168.1.2\foo'
.EXAMPLE
Test-ShareLikelyUp -SharePath '\\server01.contoso.local\share' -DnsCidrs '10.30.0.0/16'
-
A collection of helper functions for Processes & Tasks
Read more
Quote-Win32Arg
Quotes a string so it can be safely passed as a single argument to a Windows process via CreateProcess, following the exact Win32 command-line parsing rules. It ensures arguments containing spaces, quotes, or trailing backslashes are preserved exactly as intended when reconstructed by the target program. 'simple' => simple 'hello world' => "hello world" 'He said "hello"' => "He said \"hello\"" 'C:\Temp\' => "C:\Temp\\" 'C:\Path With Spaces\' => "C:\Path With Spaces\\" 'C:\X\"Y"\Z\' => "C:\X\\\"Y\\\"\Z\\"
Join-Win32CommandLine
Constructs a valid Win32 command-line string from a list of arguments.
Read more
Iterates through a collection of arguments, applies Win32 escaping to each (via Quote-Win32Arg), and joins them with spaces. This creates a single string safe for use with APIs like System.Diagnostics.Process or CreateProcess.
['git', 'commit', '-m', 'Msg'] => git commit -m Msg
['app.exe', 'C:\Program Files\', '/v'] => app.exe "C:\Program Files\\" /v
['echo', '', 'foo'] => echo "" foo
.PARAMETER ArgumentList
The collection of objects (strings) to be joined. Objects are converted to strings before quoting.
ConvertTo-PowerShellSingleQuotedString
Escapes a value as a PowerShell single-quoted string literal.
ConvertTo-PowerShellEncodedCommand
Encodes PowerShell source text for powershell.exe -EncodedCommand.
New-DetachedPSScriptRemoteCommandLine
Builds the remote powershell.exe command line for Invoke-DetachedPSScript.
New-ScheduledTaskForPSScript
Registers a Windows Scheduled Task that runs a PowerShell script as SYSTEM.
Read more
Creates or updates a scheduled task that runs the script specified by
-ScriptPath using Windows PowerShell (powershell.exe).
The task is registered under -TaskPath and -TaskName (a default name is
chosen when -TaskName is not provided). If a task with the same name
already exists at that path, it is replaced.
The task runs as the built-in SYSTEM account with highest run level. Task
settings limit concurrent executions by ignoring new starts while an
instance is already running, and apply -ExecutionTimeLimit to each run.
Depending on the script path and provided arguments, the function MAY
create a .cmd wrapper file in the script's folder and configure the task
to execute that wrapper instead of invoking powershell.exe directly.
If -ScheduleType is Manual, the task is created without a trigger and
will only run when started manually (or by other tooling).
Supports -WhatIf and -Confirm. If confirmation is declined (or -WhatIf is
used), no task is registered and no wrapper file is created.
.OUTPUTS
Microsoft.Management.Infrastructure.CimInstance
A scheduled task object returned by Register-ScheduledTask when the task
is registered. If ShouldProcess declines the action, no output is
produced.
.PARAMETER ScriptPath
Path to an existing PowerShell script file. The path MUST exist or the
function throws before making changes.
.PARAMETER ScheduleType
Selects how (or whether) the task is triggered.
Valid values:
- Startup: runs at system startup.
- Daily: runs daily at -Time.
- Weekly: runs weekly on -Day at -Time.
- Hourly: repeats every hour starting shortly after creation time.
- EveryMinute: repeats every minute starting shortly after creation time.
- Manual: no trigger is created.
.PARAMETER Time
Time of day in HH:mm (24-hour) format. Required for Daily and Weekly.
.PARAMETER Day
One or more weekdays. Required for Weekly.
.PARAMETER TaskPath
Scheduled task folder path in Task Scheduler (for example '\enLogic\').
Defaults to '\enLogic\'.
.PARAMETER TaskName
Scheduled task name. If omitted, a name is derived from the script file
name.
.PARAMETER ScriptArguments
Argument values passed to the script. Provide either -ScriptArguments or
-RawArgumentsAvoidMe, not both.
Elements MAY be $null. How the script receives $null depends on the
invocation mode chosen by the function.
.PARAMETER RawArgumentsAvoidMe
A raw argument string appended to the invocation. Intended for advanced
cases. Provide either -ScriptArguments or -RawArgumentsAvoidMe, not both.
.PARAMETER ExecutionTimeLimit
Maximum runtime allowed for each task invocation. Defaults to 2 hours.
.PARAMETER StartItNow
If set, the function attempts to start the task immediately after it is
registered. If starting fails, the task remains created and an error is
written.
.EXAMPLE
New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Health.ps1' `
-ScheduleType Startup -TaskPath '\enLogic\'
.EXAMPLE
New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Report.ps1' `
-ScheduleType Daily -Time '02:30' -TaskName 'Daily Report' `
-ScriptArguments @('Full','EU')
.EXAMPLE
New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Cleanup.ps1' `
-ScheduleType Weekly -Day Monday,Thursday -Time '03:00' `
-ExecutionTimeLimit (New-TimeSpan -Minutes 30) -StartItNow
.EXAMPLE
New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\OnDemand.ps1' `
-ScheduleType Manual -TaskName 'Run On Demand'
.NOTES
Registers the task to run as SYSTEM with highest privileges, and sets
MultipleInstances to IgnoreNew.
For Hourly and EveryMinute schedules, the first run is anchored to a
start time shortly after the function is invoked (not aligned to clock
boundaries).
Invoke-DetachedScriptLocally
Runs a PowerShell script in the background as SYSTEM user.
Read more
The script runs elevated as a scheduled task under the local SYSTEM account,
and does not depend on the current terminal staying open or the user staying
logged-in. Note: SYSTEM has very limited network access. In many environments,
it cannot access normal user-mapped drives, user profile locations, remote
file shares, SharePoint/OneDrive sync paths owned by a user, or network
resources that require the user's credentials.
.PARAMETER ScriptPath
The local path of the .ps1 script to run.
.PARAMETER ArgumentList
Optional arguments to pass to the script.
.PARAMETER LogPath
Optional path for redirected script output. If omitted, a log file is created
under the TEMP directory of the caller.
.EXAMPLE
Invoke-DetachedScriptLocally -ScriptPath 'C:\Scripts\Foo.ps1'
.EXAMPLE
Invoke-DetachedScriptLocally -ScriptPath 'C:\Scripts\Foo.ps1' -ArgumentList 'server01', 'full'
Runs the script as SYSTEM and passes two arguments.
.EXAMPLE
Invoke-DetachedScriptLocally -ScriptPath 'C:\Scripts\Foo.ps1' -LogPath 'C:\Temp\Foo.log' -Verbose
Runs the script as SYSTEM and writes verbose messages about cleanup of old idle
tasks.
Invoke-DetachedPSScript
Executes a PowerShell script locally or on a remote host as a detached process.
Read more
If Computer refers to the local machine, the script is executed through
Invoke-DetachedScriptLocally. This means that:
the script runs elevated as a scheduled task under the local SYSTEM account,
and does not depend on the current terminal staying open or the user staying
logged-in. Note: SYSTEM has very limited network access. In many environments,
it cannot access normal user-mapped drives, user profile locations, remote
file shares, SharePoint/OneDrive sync paths owned by a user, or network
resources that require the user's credentials.
If Computer refers to a remote machine, the script is copied if needed and then
started remotely through CIM/WMI using Win32_Process.Create. Again the script
does not depend on the current terminal staying open or the user staying
logged-in or even the controller-computer being powered-on. This method also
avoids leaving a disconnected PowerShell remoting session after execution
completes.
.PARAMETER Script
Path to a .ps1 script.
.PARAMETER ScriptBlock
For local execution, it is written to:
C:\ProgramData\TempForDetachedScripts\Scripts
For remote execution, it is written locally first, copied to the remote TEMP
directory (old generated remote temp scripts are cleaned up).
.PARAMETER LogFile
Optional log file path. For local execution, if omitted, a log file is created
under:
C:\ProgramData\TempForDetachedScripts\Logs
For remote execution, if supplied, Start-Transcript is used on the remote host.
.OUTPUTS
For local execution, returns task information from Invoke-DetachedScriptLocally
plus ComputerName, Status, and ExecutionMode.
For remote execution, returns a PSCustomObject with:
ComputerName, ProcessId, ReturnValue, Status, and ExecutionPath.
Get-ProcessesWithMatchingCommandLine
List processes with command lines matching a like expression (e.g. "*myScript.ps1*")
Read more
.EXAMPLE
Get-ProcessesWithMatchingCommandLine "*myScript.ps1*"
Test-ExeFound
Tests whether an executable can be resolved either as a full path or via PATH/PATHEXT.
Read more
Accepts either:
- A rooted path (e.g. C:\Tools\uchardet or C:\Tools\uchardet.exe), in which case it checks existence and,
if no extension was given, also tries common executable extensions (.exe/.cmd/.bat/.com).
- A bare command name (e.g. uchardet), in which case it resolves it the same way PowerShell would when
launching a process (Get-Command + PATHEXT).
Returns $true if the executable can be found, otherwise $false.
Get-TopRamProcess
Returns the processes consuming the most resident physical memory.
Read more
Returns at least MinProcesses processes, ordered by working-set size.
Processes continue to be included until their combined working sets reach
TargetPercentOfUsedRam percent of currently used physical RAM, or until
MaxProcesses processes have been included. Estimated non-process RAM is
included in the ranking as a synthetic entry named [non-process].
Command lines are excluded by default because retrieving them requires an
additional CIM/WMI query. Use IncludeCommandLine when they are required.
.PARAMETER MinProcesses
Minimum number of processes to return.
The default is 10.
.PARAMETER MaxProcesses
Maximum number of processes to return, even when the requested RAM target
has not been reached.
MaxProcesses cannot be less than MinProcesses.
The default is 100.
.PARAMETER TargetPercentOfUsedRam
Target percentage of currently used physical RAM to cover with the
cumulative working sets of the returned processes.
This is a target rather than an exact limit. The final process is included
in full, so the reported cumulative percentage normally exceeds the
requested percentage slightly.
The default is 25.
.PARAMETER IncludeCommandLine
Retrieves and returns the command line for each selected process.
This requires an additional CIM/WMI query and therefore adds work on an
already stressed system. Command lines may also expose passwords, tokens,
connection strings, or other sensitive values.
Some command lines may be unavailable because of permissions, protected
processes, or processes terminating during collection.
.OUTPUTS
PSCustomObject with the following properties:
PID
Name
RAM_MB
RAM_PercentOfTotal
RAM_PercentOfUsed
CumulativeUsedRAMPct
CommandLine
CommandLine is null unless IncludeCommandLine is specified.
.NOTES
RAM usage is based on each process's working set. A working set represents
physical pages currently resident for that process, but it can contain
shared pages such as DLL code. Summing process working sets can therefore
count the same physical pages more than once. CumulativeUsedRAMPct is an
approximate diagnostic value and can exceed 100 percent.
Not all used physical RAM belongs to user-visible processes. Kernel pools,
drivers, the file cache, modified pages, memory compression, Hyper-V guest
memory, and other operating-system allocations may consume substantial
memory. The function estimates that gap as:
used physical RAM minus the summed working sets of all readable
processes
The estimate is exposed as the synthetic [non-process] entry. When summed
working sets exceed used RAM because of shared pages, the synthetic entry
is reported as zero.
Process state can change during collection. A process may terminate after
it is enumerated, and Windows could theoretically reuse its PID before the
optional command-line query. Such races cannot be eliminated by a snapshot
function.
The function creates and sorts a small object for every process before
selecting the result set. This is normally minor, but its cost increases on
systems running unusually large numbers of processes.
When IncludeCommandLine is used, the additional CIM/WMI query consumes more
CPU and memory and may involve provider activity at a time when the system
is already under pressure.
.EXAMPLE
Get-TopRamProcess
Returns at least 10 entries and continues until their combined RAM usage
approximately covers 25 percent of currently used RAM, up to a maximum of
100 entries. The ranking may include the synthetic [non-process] entry.
.EXAMPLE
Get-TopRamProcess -MinProcesses 5 -MaxProcesses 50 `
-TargetPercentOfUsedRam 40
Returns at least 5 and at most 50 processes, targeting approximately
40 percent of currently used RAM.
.EXAMPLE
Get-TopRamProcess -IncludeCommandLine
Includes process command lines using an additional CIM/WMI query.
-
A collection of helper functions for handling text files
Read more
Edit-TextFile
Searches and replaces text in files while maintaining the existing text encoding (but will switch ASCII to UTF8 if replacement is unicode).
Read more
Performs an in-place regex (or literal) search/replace on a text file,
while preserving the file's actual encoding. For _really_ hard cases it
may mistake the encoding. In such cases it may fail to find the pattern
and/or change the encoding of the input file.
You may pass wildcards like "*.txt" to -File.
To apply one substitution use `-Patern 'a' -Replacement 'b'`. To apply
multiple substitutions use `-ReplaceMap` (see examples).
Without -Literal considers Pattern(s) to be a regex pattern.
By default keeps a backup with .bak extension. To skip the Backup
use -Backup "". To change the extension use -Backup "ext".
If the sampled bytes are pure 7-bit ASCII and no BOM is present, the
function by default assumes a UTF8 encoding (even though ASCII is also
valid). This is intentional: it allows replacements to introduce Unicode
without changing the reported encoding unexpectedly. Use -DontPreferUTF8
to force ASCII encoding.
.OUTPUTS
Produces a psCustomObject for each evaluated file:
File = The file path
Changed = True/False
EncodingStr = Human readable encoding.
EncodingObj = The output of Get-TextFileEncoding
Details = Human readable outcome. E.g.:
"Changes made"
"Pattern(s) not found"
"Skipped too big file ..."
"Ignored empty file"
"No files matched pattern"
.PARAMETER MaxFileSize
Files larger than these many bytes are ignored.
.PARAMETER PreferISOEncodings
When set, ISO encodings are selected when multiple encodings represent
the text equivalently; otherwise, Windows encodings are selected.
.EXAMPLE
Edit-TextFile -file .\ansi.txt -Pattern "foo" -Replacement="_FOO_"
.EXAMPLE
Edit-TextFile -file .\ansi.txt -Pattern "foo?" -Replacement="_FOO_?" -Literal
.EXAMPLE
Edit-TextFile -file .\ansi.txt -ReplaceMap ([ordered]@{"foo"="_FOO_"; "bar"="_BAR_"})
.NOTES
The operation writes modified content to temporary storage before
replacing the target file. Original files are backed up prior to the
modification. If a terminating error occurs during the file swap, the
target file might remain in its prior state and intermediate temporary
files might remain on the storage volume.
Files exceeding the configured maximum size limit or containing no
data are skipped. Substitutions are evaluated sequentially.
Get-NewlineStyle
Detect newline style in a decoded string. Returns 'CRLF','LF','CR','Mixed','None','NotChecked'.
Get-TextFileEncoding
Detect (if possible) or guess the encoding of Text Files.
Read more
Uses uchardet (CLI) and simple BOM/ASCII checks.
Returns an object like this:
File : C:\tempansi.txt
Type : NON-ASCII-TEXT
BOMBytes : {}
UCharDetEncoding : ISO-8859-1
EncodingDescription : CP1252
DotNetEncodingObj : System.Text.SBCSCodePageEncoding
NewlineStyle :
BytesRead : 22
UCharDetTimeMs : 0
TotalTimeMs : 55
.PARAMETER
-DontPreferUTF8: If the sampled bytes are pure 7-bit ASCII and no BOM
is present, the function returns UTF-8 by default (even though ASCII
is also valid). This is intentional: it allows later writes/replacements
to introduce Unicode without changing the reported encoding unexpectedly.
Use -DontPreferUTF8 to return ASCII instead.
In other words: The default UTF-8 return value is not a strict
"encoding detection" result; it is a compatibility policy for downstream
editing workflows.
-PreferISOEncodings: by default we return Windows encodings instead of ISO ones
WHEN BOTH PRODUCE THE SAME TEXT. This switch overides that behavior.
.NOTES
- Will fail for pathological files (e.g. BOM indicates UTF-8
but file is UTF-16).
- It consumes RAM to read the file's bytes, possible twice.
(That's why -MaxBytes is by default 512KB)
- It may fail in very hard cases like:
- Files larger than 512KB that appear as ASCII in the first
-MaxBytes and then have some ANSI or UTF-8 bytes.
- Files with ambiguous ASCII encodings (e.g. ISO-8859-1 /
CP1252)
- Respects -ErrorAction by emitting non-terminating errors.
- By default (without -PreferISOEncodings) it will assume a file
is encoded with a Windows(CP) encoding if it can be either
an ISO encoding (e.g. ISO-8859-1) or a windows one (e.g. CP1251)
(Since a lot of these encodings are very similar, a file with plenty
of text but none of the few characters that are encoded
differently between the ISO/CP encodings can be encoded with both giving
exactly the same bytes)
For reference these are the default encoding for Notepad,
PS5 & PS7 per windows version:
| | PS 5.1 | PS 5.1 | PS 7 either
Operating System | Notepad | > a.txt | Out-File | > or Out-File
2016 (1607 LTSC) | ANSI | ANSI | UTF-16 LE*| UTF-8*
2019 (1809 LTSC) | ANSI | ANSI | UTF-16 LE*| UTF-8*
2022 (21H2 LTSC) | UTF-8* | ANSI | UTF-16 LE*| UTF-8*
2025 (24H2 LTSC) | UTF-8* | ANSI | UTF-16 LE*| UTF-8*
*: UTF-8 always without BOM, UTF-16 always with BOM
TODO:
Offer help on how to install uchardet if not found.
Remove-TypographyUnicodeFromTextFile
Substitutes Unicode typography characters with ASCII characters in one or more target text files. Mimics the interface of Edit-TextFile.
Read more
Modifies the specified file or files (if you use wildcards like *.txt)
in place. Useful for eliminating unnecessary Unicode typography from code.
You may pass wildcards like "*.ps1" to -File.
By default keeps a backup with .bak extension. To skip the Backup
use -Backup "". To change the extension use -Backup "ext".
.OUTPUTS
Produces a psCustomObject for each evaluated file:
File = The file path
Changed = True/False
EncodingStr = Human readable encoding.
EncodingObj = The output of Get-TextFileEncoding
Details = Human readable outcome. E.g.:
"Changes made"
"Pattern(s) not found"
"Skipped too big file ..."
"Ignored empty file"
"No files matched pattern"
.PARAMETER MaxFileSize
Files larger than these many bytes are ignored.
.PARAMETER PreferISOEncodings
When set, ISO encodings are selected when multiple encodings represent
the text equivalently; otherwise, Windows encodings are selected.
.NOTES
Why we have to do the changes in three batches instead of all together:
By default, PowerShell hashtables (@{} and [ordered]@{}) use culture-sensitive
linguistic comparison.
Because 0x200B, 0x200C, and 0x200D are invisible formatting characters,
the linguistic comparer gives them a sorting weight of zero. Therefore,
PowerShell evaluates them as the exact same string and throws a "Duplicate keys"
error when building the hashtable.
Replace-FileBytesSafely
Replaces a file's contents with specified bytes, optionally retaining a backup.
Read more
Behavior and guarantees:
- Writes the new content to -TmpPath first, then attempts to replace -ResolvedPath with it.
- Primary path uses [IO.File]::Replace(), which is the best option on local NTFS:
* Readers see either the old or the new file, not a partially-written file.
* A backup at -BakPath is created/overwritten as part of the replace.
- If Replace() fails (common on non-NTFS volumes, SMB shares with varying semantics, or transient locks
e.g. AV/OneDrive/indexing), it falls back to Copy-Item + Move-Item with best-effort rollback:
* This fallback is NOT atomic. It is provided for compatibility and "works in more places".
* If the move fails after the backup copy, the function attempts to restore from -BakPath.
Backup semantics:
- -BakPath is always used as the safety copy when swapping.
- If -UserBackup is $true, -BakPath is considered caller-visible and is preserved.
- If -UserBackup is $false, -BakPath is a transient safety backup and may be deleted on success.
Cleanup:
- Always attempts to delete -TmpPath in a finally block.
- Does not promise preservation of metadata/streams in the fallback path (ACLs, ADS, timestamps, etc.)
beyond what the underlying filesystem/provider naturally keeps.
.PARAMETER ResolvedPath
The existing target file to be replaced (must be on the same volume as -TmpPath for best behavior).
.PARAMETER TmpPath
A temp file path in the same directory as the target (recommended) containing the new bytes to commit.
.PARAMETER BakPath
Path for the backup copy used during the swap. May be a user-requested backup (kept) or a transient one.
.PARAMETER UserBackup
Indicates whether -BakPath is user-requested (keep it) or internal/transient (delete on success).
.PARAMETER Bytes
The final bytes to be written/committed to the target file.
.NOTES
- Intended for "in-place update" workflows: generate full new content, then commit in one swap.
- For OneDrive/SMB scenarios, transient failures are normal; callers may want a small retry policy
around the Replace() stage (if not implemented inside this function).
Read-FirstBytes
Safe(shared) read of up to Count bytes from the start of a file.
Test-ExeFound
Tests whether an executable can be resolved either as a full path or via PATH/PATHEXT.
Read more
Accepts either:
- A rooted path (e.g. C:\Tools\uchardet or C:\Tools\uchardet.exe), in which case it checks existence and,
if no extension was given, also tries common executable extensions (.exe/.cmd/.bat/.com).
- A bare command name (e.g. uchardet), in which case it resolves it the same way PowerShell would when
launching a process (Get-Command + PATHEXT).
Returns $true if the executable can be found, otherwise $false.
Resolve-FileFromPath
Resolve a path to exactly one existing FileSystem file ([IO.FileInfo]) or return $null.
Read more
Accepts a path (or FileInfo/DirectoryInfo) and enforces strict "one real file" semantics:
- Must exist
- Must be FileSystem provider
- Must not be a directory
- If wildcards are used, they must match exactly one item
On failure, emits a tagged _Write-FunctionError ([RFFP-*]) including both the original input and (when available)
the resolved full path, then returns $null (caller decides whether to stop via -ErrorAction).
.OUTPUTS
System.IO.FileInfo or $null.
Test-BufferIsValidUtf8
Validates that a byte[] buffer is UTF-8, while intentionally tolerating an incomplete final UTF-8 sequence.
Read more
Returns $true if the buffer contains no invalid UTF-8 sequences in its body.
-
Only relevant to mazars (Install/Update mazars-prepare-laptop-code)
-
Requires -Version 5.1
Requires -RunAsAdministrator
-
Continuously pings a host, or a small set of public hosts, and displays live connection-quality statistics.
Read more
Out-PingStats is an interactive terminal monitor for ICMP latency and packet loss.
When you specify -Target, it continuously pings that host and renders live graphs and summaries for:
- recent RTT values
- RTT histogram
- rolling loss percentage
- rolling one-way jitter estimate
- rolling RTT 95th percentile
When you omit -Target, it probes a few well-known Internet hosts in parallel and treats the result as a rough
"Internet reachability and quality" indicator rather than a measurement for one exact destination.
The display updates continuously until you stop it, typically with Ctrl+C.
This command is intended for human monitoring in a console window. Its primary output is a live screen display,
not pipeline-friendly structured objects.
For best-looking graphs, use a monospace font with good Unicode block-character support. DejaVu Sans Mono works
well. Consolas usually forces lower-resolution graph characters.
.INTERACTIVE CONTROLS
While the monitor is running, you can use:
Ctrl-H Toggle RTT histogram
Ctrl-R Toggle recent-RTT graph
Ctrl-L Toggle loss graph
Ctrl-J Toggle jitter graph
Ctrl-S Toggle graph character set / font mode
.PARAMETER Target
Host name or IP address to probe.
If omitted, the command monitors general Internet quality by pinging several public hosts in parallel.
.PARAMETER Title
Custom title shown at the top of the screen.
By default, the title is derived from -Target, or shows a generic Internet-oriented title when -Target is omitted.
.PARAMETER GraphMax
Upper Y-axis limit for RTT graphs.
By default, the command chooses a sensible value automatically.
.PARAMETER PingsPerSec
Deprecated. Currently has no practical effect.
.PARAMETER GraphMin
Lower Y-axis limit for RTT graphs.
By default, the command chooses a sensible value automatically.
.PARAMETER HistBucketsCount
Number of buckets to use in the RTT histogram.
.PARAMETER AggregationSeconds
Number of seconds per aggregation period for the slower trend graphs such as loss, jitter, and RTT 95th percentile.
.PARAMETER HistSamples
Number of recent samples to include in the RTT histogram.
If omitted, the default is at least 100 samples and otherwise about one minute of samples.
.PARAMETER Visual
Reserved legacy parameter. Do not rely on it.
.PARAMETER DebugMode
Enables diagnostic behavior and reduces screen-clearing behavior to help troubleshoot parsing, aggregation,
or rendering issues.
.PARAMETER DebugData
Enables extra debug-data collection.
.PARAMETER HighResFont
Controls graph-character mode.
-1 = auto-detect
0 = force low-resolution characters
1 = force high-resolution characters
Use low-resolution mode for terminals or fonts that do not render the Unicode block characters cleanly.
.PARAMETER UpdateScreenEvery
How often, in seconds, the screen is refreshed.
Lower values make the display more responsive but may increase CPU use.
.PARAMETER BarGraphSamples
How many recent samples to show in the scrolling bar graphs.
By default, the command derives this from the current console width.
.EXAMPLE
Out-PingStats google.com
Continuously monitors latency, loss, jitter, and latency distribution to google.com.
.EXAMPLE
Out-PingStats 1.1.1.1 -Title "Cloudflare DNS"
Monitors 1.1.1.1 and shows a custom title.
.EXAMPLE
Out-PingStats
Shows a rough live view of general Internet quality by probing several public hosts in parallel.
.EXAMPLE
Out-PingStats 8.8.8.8 -GraphMin 0 -GraphMax 100 -AggregationSeconds 60
Monitors 8.8.8.8 with fixed RTT graph limits and 1-minute aggregation windows.
.NOTES
This command starts background jobs and cleans them up when it exits.
It also writes temporary screen/statistics data files under $env:TEMP.
Loss, jitter, and percentile values are intended for operational monitoring, not for strict scientific measurement.
.OUTPUTS
None. This command is designed for interactive console display.
.INPUTS
None. This command does not accept pipeline input.
-
Safe* and automatic DISM + SFC repairs made easy.
Read more
Runs CHKDSK, DISM(CheckHealth/RestoreHealth) and SFC with preflight checks, concise console output, and logging.
Designed to minimize risk* and be thourough.
*: REGARDING SAFETY
This script is safe to run on Windows installations with no weird customizations,
Don't use it on boxes with OEM-customized, but still WRP-protected components,
or older apps that replace protected system binaries.
.PARAMETER Source
Optional, one or more DISM sources, e.g. 'WIM:D:\sources\install.wim:1','ESD:E:\sources\install.esd:6'.
.PARAMETER ScratchDirectory
Optional scratch directory for servicing if supported (offloads staging from C:).
.PARAMETER MinFreeSystemGB
Minimum free GB on system drive before running heavy servicing (default 4GB).
.PARAMETER MinFreeScratchGB
Minimum free GB on ScratchDirectory if provided. (default 4GB)
.PARAMETER LimitAccess
Use only -Source and avoid Windows Update (WU/WSUS). Use this along with -Source. PREFER TO AVOID THIS OPTION.
.EXAMPLE
.\Run-DismSfc.ps1 -Source 'WIM:D:\sources\install.wim:1'
-
Minimize copy-pasting and typing while using an LLM like Toula-the-fixer to troubleshoot issues.
Read more
HOW TO USE ME
Begin by opening a terminal and dot-sourcing this script. E.g.:
$p="C:\IT\bin";$f="Start-Copy4Toula.ps1";mkdir $p -force >$null
iwr -useb https://ndemou.github.io/scripts/$f -out $p\$f
. C:\IT\bin\Start-Copy4Toula.ps1
Then repeat these steps:
1. Copy code from the LLM
2. Run `q` in the terminal (it will execute the code _and_ copy back the results)
3. Go back to the LLM and paste the output.
If you run commands directly, or accidentally press ctrl-C you can
run `q -CopyOnly` to copy all output since the last time you run either `q`.
DETAILS
The script maintains two transcript files:
- `$env:TEMP\TTFtrans-$PID.full.txt` has the cumulative raw history of the full session.
- `$env:TEMP\TTFtrans-$PID.txt` has just the most recent chunk of output.
`q` will copy up to 5000 lines by default. You can change the limit:
$global:SctMaxLinesToCopy = 8000
The output of some rare legacy tools may not appear in the transcript.
It's extremely rare though and you can always copy-paste manually.
.EXAMPLE
. .\Start-Copy4Toula.ps1
q
q
-
Prints a detailed warning every time it finds RAM, CPU or Disks are stressed
Read more
There are two modes of operation: monitoring and log file analysis.
In monitor mode (the default) it prints a detailed warning every
time it finds RAM, CPU or Disks are stressed.
In monitor mode these switches may be used.
-MonitorVolumes: Will also monitor IO stress of Volumes
-DontMonitorDisks: Will NOT monitor IO stress of disks
In log analysis (invoked if you supply a -LogFile) it creates a
summary report based on the contents of the log file.
In log analysis mode these arguments may be used.
-Granularity
-LogsToIgnoreRegex
.EXAMPLE
Download & Setup to always run on startup
$dir="C:\IT\bin";$f="Test-ForCpuRamDiskStress.ps1"
if (-not (test-path $dir\$f)) {
"Downloading"; mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f
if (-not (Get-ScheduledTask -TaskPath '\enLogic\' -TaskName 'Execute Test-ForCpuRamDiskStress.ps1' -ErrorAction SilentlyContinue)) {
$dir="C:\IT\bin";$f="helpers-processes.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f
. $dir\$f
"Setting up scheduled task on startup"
New-ScheduledTaskForPSScript -ScriptPath 'C:\IT\bin\Test-ForCpuRamDiskStress.ps1' `
-ScheduleType Startup -TaskPath '\enLogic\' `
-ScriptArguments @('-LogDir','c:\it\log','-LogBaseName','CpuRamDiskStress')
"Starting task"
Start-ScheduledTask -TaskPath '\enLogic\' -TaskName 'Execute Test-ForCpuRamDiskStress.ps1'
sleep 2
Get-ScheduledTask -TaskPath '\enLogic\' -TaskName 'Execute Test-ForCpuRamDiskStress.ps1'
if (test-path C:\it\log\CpuRamDiskStress.*) {
"Last 20 lines of latest log file"
cat (ls C:\it\log\CpuRamDiskStress.*|sort -Property LastWriteTime|select -last 1) | select -last 20
} else { echo "ERROR: No logs found: C:\it\log\CpuRamDiskStress.*" }
.EXAMPLE
Get statistics for a particular date
& $bin\Test-ForCpuRamDiskStress.ps1 -Granularity 10m -LogFile C:\it\log\CpuRamDiskStress.2026-01-14.log
.EXAMPLE
If you want to run only once:
& C:\IT\bin\Test-ForCpuRamDiskStress.ps1 -LogDir c:\it\log -LogBaseName 'CpuRamDiskStress'
.EXAMPLE
What you see if memory is under pressure.
C:\IT\bin\Test-ForCpuRamDiskStress.ps1 | Tee-Object "C:\it\temp\CpuRamDiskStress.log"
20:12:47 HIGH <HOSTNAME> Reasons:
- 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.
- High classification gate satisfied: Available memory(%) minimum 0,5 is below the 10% gate threshold.
Measurements:
- Time window: 18 secs (9 samples)
- Available memory: average 68,3%, minimum 0,5%
- Committed memory: average 31,9%, maximum 67,0%
- Paging file usage: maximum 73%
- Page Reads/sec (hard faults): average 319, maximum 1.789
- Page Writes/sec: average 23, maximum 203
- Transition Faults/sec: average 1.281, maximum 6.797
- Disk read latency: average 0,0 ms
- Disk write latency: average 0,0 ms
- Disk queue length: average 7,3
- Standby cache memory: Normal 58 MB, Reserve 222 MB, Core 0 MB
- File cache memory: 4 MB
- Modified page list: 134 MB
- Compressed memory: 0 MB
-
Ensures all ndemou.github.io/scripts are up-to-date.
Read more
Existing files that differ are replaced and a backup is created.
Identical files are left unchanged.
-
Ensures all health-check scripts and PS Modules are installed & up-to-date.
Read more
Missing files are created. Existing files that differ are replaced.
Identical files are left unchanged. If this script updates itself,
it re-invokes the updated copy. When replacing a file, backup copies
are created in the backups directory.
Will set PSGallery as Trusted.
The updater also tracks a small "release marker" for the currently
installed code and for the target update source. A release marker is a
stable identifier for a specific release source, typically derived from
GitHub release metadata or from a manually supplied zip file name plus
its content hash. These markers are cached locally and let the updater
decide whether the requested update is already installed, whether it can
skip re-downloading or reapplying files, and when `-Reinstall` should
force the update to run again.
.PARAMETER Reinstall
Forces reinstall even when installed release matches target release.
.PARAMETER UpdateFromZip
Overides the default which is to fetch the latest GitHub release.
.PARAMETER Version
Explicit semantic version to associate with `-UpdateFromZip` when the zip
file name does not already embed a version token such as `v4.4.3`.
Use `X.Y.Z` or `vX.Y.Z`.
.PARAMETER ForceRefreshReleaseMetadata
Overides the default which is to cache latest-release metadata locally
for a few minutes (to avoid querying GitHub on every run).
.PARAMETER Config
Hashtable or PowerShell data file path for customized installs. `Options.InstallDir`
sets the install root; `ConfigFiles` writes named .psd1 files under the config folder.
.PARAMETER SelfRerunCount
Internal use only. Tracks the one-time self-rerun pass count.
.PARAMETER PersistReleaseMarker
Internal use only. Carries the resolved release marker across self-rerun.
.PARAMETER Config
Optional installer customization. Pass either a hashtable or the path to a PowerShell data file.
The top-level Options branch changes installer behavior. The top-level ConfigFiles branch
creates PowerShell data files under the installation config directory.
.PARAMETER GenerateConfigPsd1
Creates a template PowerShell data file named GetComputerHealth.install.psd1 in the current
working directory, then exits. Customize that file and pass its path to -Config.
.PARAMETER ScheduleDailyInvokationAt
Creates or updates a daily scheduled task for Invoke-GetComputerHealth.ps1
at the specified 24-hour time in HH:mm format, then exits.
.EXAMPLE
.\Update-GetHealthCode.ps1
Checks the locally cached latest-release metadata, refreshes it from
GitHub when needed, and installs the latest published release when it is
newer than the currently installed release marker.
.EXAMPLE
.\Update-GetHealthCode.ps1 -UpdateFromZip C:\Downloads\GetComputerHealth-v4.4.3.zip
.EXAMPLE
.\Update-GetHealthCode.ps1 -ScheduleDailyInvokationAt 07:12
-
Records MAC,IP address pairs observed in the local IPv4 neighbor cache.
Read more
The script keeps a running inventory of observed MAC,IP address pairs, with
first seen time and last seen time for each pair.
It is intended for passive local-link observation. It does not scan the
network and should not be used as proof that all devices in a VLAN were
found.
When StateFile is supplied, the output file is created or replaced as a
PowerShell CLIXML file. The parent directory is created when needed. If the
script stops normally or is interrupted, it attempts one final write. A
terminating error can leave the latest observations not written, and may
leave a temporary file beside the target file.
When StateFile is not supplied, the script only prints newly discovered
MAC,IP pairs to the screen and keeps the in-memory inventory only for the
current run.
.OUTPUTS
Produces no pipeline output.
Creates or updates a CLIXML file containing:
GeneratedAt : Timestamp of the file generation.
SeenMACs : List of records, one per MAC,IP address pair.
MAC : MAC address.
IP : IPv4 address.
FirstSeenTimestamp : First time this MAC,IP pair was observed.
LastSeenTimestamp : Most recent time this MAC,IP pair was observed.
.PARAMETER StateFile
Optional path of the CLIXML inventory file to create or update. When omitted, no existing state is loaded and no state file is written.
.PARAMETER PollSeconds
Number of seconds between neighbor-cache observations.
.PARAMETER IdleWriteSeconds
Maximum seconds between writes when no new MAC,IP pair has been observed.
.PARAMETER ActiveWriteSeconds
Maximum seconds between writes while new MAC,IP pair observations exist.
.EXAMPLE
.\Watch-SeenMacAddresses.ps1
Starts passive observation without loading or writing a state file.
.EXAMPLE
.\Watch-SeenMacAddresses.ps1 -StateFile 'C:\it\log\seen_MAC_addresses.clixml'
Starts passive observation and persists observations to the specified CLIXML file.
.EXAMPLE
.\Watch-SeenMacAddresses.ps1 -StateFile 'C:\it\log\seen_MAC_addresses.clixml' -PollSeconds 15 -ActiveWriteSeconds 30
Polls every 15 seconds and writes changed data at most every 30 seconds.
-
Installs Windows Updates using the supported WUA COM API, with optional download, controlled reboot (now or scheduled), and detailed logging.
Read more
SPECIAL SHOW UPDATE HISTORY MODE
If -ShowHistory is used, the script does NOT install/download/reboot.
Instead it queries Windows Update history (same source as the GUI "View update history"),
optionally filtered, and then exits.
NORMAL INSTALL UPDATES MODE
By default(without -ShowHistory) it installs Windows updates like this:
- Installs already downloaded updates if any.
- With -Download, will also download all required updates.
- With -Reboot, will reboot after installation if needed (or regardless with -RebootAnyway).
Batches "normal" updates together; installs "exclusive" updates one-by-one; accepts EULAs.
# Regarding Robustness
- Service start is retried up to 3x with exponential delays (5s, 10s, 20s) before failing.
- Pending reboot detection uses WU `RebootRequired` and CBS `RebootPending`.
- Post-download refresh search has a catch/fallback: if the refresh search throws, proceeds using the initial search results (with a warning).
- Uses only supported, inbox components (no extra modules, no `UsoClient`, PS 5.1-safe syntax).
- Reboot is first tried without /f and after a few minutes with /f.
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,
the script will ensure continuation of installations after the reboot like this:
- Create a temporary scheduled task that runs this script again
at startup with -XXX_ResumeAfterReboot.
- On that second automated run with -XXX_ResumeAfterReboot: The startup
task is removed and the script continues as normal (install + maybe reboot).
# Logging
Logs everything to `WindowsUpdateHelper-YYYY-MM-DD.log`
1. If C:\IT\LOG exists, log is created there.
2. Else if C:\IT\LOGS exists, there.
3. Else in the system temp folder.
.EXAMPLE
The fastest way to bring a new installation up-to-date:
**CAUTION**: WILL REBOOT WITHOUT WAITING / WITHOUT ASKING
Download & first run
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force
$p="C:\it\bin";mkdir $p -force >$null
$f="WindowsUpdatesHelper.ps1";iwr -useb https://wiki.enlogic.gr/pub/KnowledgeBase/PublicFiles/$f -OutFile $p\$f
& C:\it\bin\WindowsUpdatesHelper.ps1 -Download -Reboot
2nd Run (REPEAT UNTIL YOU GET 0 Updates Found)
& c:\it\bin\WindowsUpdatesHelper.ps1 -Download -Reboot -Interactive
It will also install updates that MAY ask you to accept EULAs or make choices
.EXAMPLE
Display the logs from the last 10 executions of this script
& 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)): '}
.EXAMPLE
**CAUTION**: An unfortunate side-effect of this script is that the updates
it installs are not visible in the GUI (Settings -> Windows Updates).
The only way to view them:
& c:\it\bin\WindowsUpdatesHelper.ps1 -ShowHistory | ft
You may add -IncludeAV if you want to also view (the very frequent) Antivirus udpates
.PARAMETER Download
Perform online scan and download applicable updates that are not yet downloaded, then proceed to install everything downloaded.
.PARAMETER Reboot
After installation, reboot only if updates require it (or regardless if -RebootAnyway is also used).
.PARAMETER Interactive
If specified, the script will include updates flagged as InstallationBehavior.CanRequestUserInput
(Like some drivers/firmware that show GUI prompts and wait for user actions -- e.g. clicking "Accept").
Without this switch, such updates are skipped.
Alias: -CanRequestUserInput
.PARAMETER RebootAnyway
Reboot regardless of whether updates require it (implies -Reboot).
.PARAMETER XXX_ResumeAfterReboot
DO NOT USE THIS SWITCH. It is used INTERNALLY to continue installations after a reboot.
.PARAMETER AbortReboot
Abort a reboot initiated by this script
.PARAMETER XXX_RebootNow
DO NOT USE THIS SWITCH. It is used INTERNALLY to force a reboot.
.PARAMETER XXX_RebootArmedAt
DO NOT USE THIS SWITCH. It is used INTERNALLY to avoid rebooting if a reboot already occured after this time.
.PARAMETER ShowHistory
List Windows Update history (no install/download/reboot) and exit.
.PARAMETER MaxResults
(ShowHistory mode) Maximum number of matching history entries to output. Default: 30. Use 0 to return all matches found (within MaxScanEntries).
.PARAMETER LastDays
(ShowHistory mode) Only include history entries from the last N days.
.PARAMETER IncludeAV
(ShowHistory mode) Include KB2267602 (Defender definitions) entries (excluded by default).
.PARAMETER MaxScanEntries
(ShowHistory mode) Safety cap: maximum number of history rows to scan. Default: 10000.
.PARAMETER ListRecentLogs
List this script's log files and exit. Returns FileInfo objects sorted by LastWriteTime (oldest -> newest; most recent last).
By default it returns the most recent 10 log files.
.PARAMETER ListAll
Used only with -ListRecentLogs. If specified, returns all log files that can be found (instead of only the most recent 10).
.PARAMETER InstallOptional
Installs an optional update (needs the update ID)
.EXAMPLE
Install any already downloaded updates and reboot if needed:
.\WindowsUpdatesHelper.ps1 -Reboot
.EXAMPLE
Download, Install and if needed reboot:
.\WindowsUpdatesHelper.ps1 -Download -Reboot
.EXAMPLE
Download, Install and reboot regardless of whether updates require it:
.\WindowsUpdatesHelper.ps1 -Download -Reboot -RebootAnyway
.EXAMPLE
Show latest Windows Update history entries:
.\WindowsUpdatesHelper.ps1 -ShowHistory
.EXAMPLE
Show latest Windows Update history entries, include AV updates:
.\WindowsUpdatesHelper.ps1 -ShowHistory -LastDays 14 -IncludeAV
.EXAMPLE
List the most recent 10 log files created by this script (most recent last):
.\WindowsUpdatesHelper.ps1 -ListRecentLogs
Deletes selected junk files and directories from a copied disk tree, with conservative defaults and full WhatIf/Confirm support.
Read more
Clear-DiskJunk scans a target path and removes only the junk categories you explicitly allow.
By default it runs in conservative mode and targets:
- browser-caches
- safe-temp-files
Conservative mode avoids deleting generic directory names such as cache, temp, log, or logs unless you explicitly include
DANGEROUS-broad-temp-cache-logs.
The function is designed for very large trees. It streams matches as they are found instead of accumulating all results in memory.
Use -PassThru to emit one result object per matched item. Without -PassThru it emits only a final summary object.
safe-temp-files deletes:
- *.tmp files older than 30 days
- Office temp files (~$*.??? and ~$*.????)
DANGEROUS-broad-temp-cache-logs expands matching to broad generic temp/cache/log locations and broad *.log / *.tmp file cleanup.
.EXAMPLE
Clear-DiskJunk -Path D:\MountedDisk -WhatIf
Shows what would be deleted using the conservative default categories.
.EXAMPLE
Clear-DiskJunk -Path D:\MountedDisk -IncludeCategory browser-caches,DANGEROUS-broad-temp-cache-logs -Confirm
Prompts before deleting and includes the dangerous broad cleanup category.
.EXAMPLE
Clear-DiskJunk -Path D:\MountedDisk -ExcludePath 'D:\MountedDisk\Users\Nick\AppData\Local\Google\*' -PassThru |
Export-Csv C:\temp\diskjunk-results.csv -NoTypeInformation
Streams one result object per matched item and saves them.
.PARAMETER Path
Root path to scan.
.PARAMETER IncludeCategory
Cleanup categories to include.
Allowed values:
- browser-caches
- safe-temp-files
- DANGEROUS-broad-temp-cache-logs
Default:
- browser-caches
- safe-temp-files
.PARAMETER ExcludePath
Paths or wildcard patterns to exclude. Matches are tested against both full Windows paths and root-relative forward-slash paths.
.PARAMETER TmpOlderThanDays
Age threshold for *.tmp deletion in the safe-temp-files category. Default is 30.
.PARAMETER PassThru
Emits one object per matched item as it is processed. Useful for logging and large-scale runs.
.OUTPUTS
Without -PassThru:
A summary object.
With -PassThru:
One result object per matched item, followed by a final summary object.
.NOTES
- Supports -WhatIf and -Confirm.
- Intended primarily for copies of Windows disks, not live system cleanup.
- Broad cleanup can remove data you may later want for troubleshooting or forensics.
Shows a compact, admin-friendly timeline of recent boots, shutdowns,
crashes, and update-related restart signals from the System log.
Read more
Use this for first-pass reboot and shutdown triage. It helps answer
whether a recent restart was clean, unexpected, crash-related, planned
by an administrator or process, or associated with Windows Updates.
.OUTPUTS
Produces one PSCustomObject per matching event:
Level : Event level text.
Time : Event time.
Kind : Event category. One of:
Boot, NormalShutdown, PlannedShutdownOrRestart,
WindowsUpdatesInstallStarted, WindowsUpdatesInstallCompleted,
WindowsUpdatesRestartRequired, WindowsUpdatesRestart
BugCheck, CrashDump, AbnormalShutdown,
UnexpectedShutdownFollowup, Other
Description : First line of the event message with source metadata
appended as "(id <n> from <provider>)".
Intentionally excludes noise about Microsoft Defender updates.
.EXAMPLE
PS C:\> Get-BootShutdownEvents |ft
Level Time Kind Description
Info 15/3 6:00:47 WindowsUpdatesInstallStart Installation Started: Windows has started installing the following update: 2026-03 Cumulative Update for Microsoft ...
Info 15/3 6:19:54 WindowsUpdatesRestart The process C:\WINDOWS\system32\shutdown.exe (SRV2) has initiated the restart of computer SRV2 ...
Info 15/3 6:22:06 NormalShutdown The Event log service was stopped. (id 6006 from EventLog)
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)
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)
Info 15/3 6:22:22 Boot The Event log service was started. (id 6005 from EventLog)
Info 15/3 6:22:44 WindowsUpdatesRestart The process C:\WINDOWS\servicing\TrustedInstaller.exe (SRV2) has initiated the restart of computer SRV2...
Info 15/3 6:22:45 NormalShutdown The Event log service was stopped. (id 6006 from EventLog)
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)
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)
Info 15/3 6:22:59 Boot The Event log service was started. (id 6005 from EventLog)
Info 15/3 6:23:20 WindowsUpdatesInstallCompl Installation Successful: Windows successfully installed the following update: 2026-03 Cumulative Update for Microsoft ...
A collection of helper functions for Domain Controllers
Read more
Search-ADUserAnyProperty
Search Active Directory users by a pattern across multiple common attributes.
Read more
This function wraps Get-ADUser with a wide LDAP filter that checks a user-supplied
pattern against multiple commonly used identifier attributes (e.g. sAMAccountName,
userPrincipalName, displayName, cn, givenName, sn, mail, proxyAddresses).
It's intended as a convenient "search anywhere that matters" for finding users when
you only know part of a name, email, alias, or login.
Results include useful profile fields: Display Name, Department, Job Title, State,
Company, OU (derived from DistinguishedName), and all proxyAddresses flattened into
a comma-separated list. Optionally you can also search phone fields and/or restrict
the search scope with -SearchBase.
.PARAMETER Pattern
The text pattern to search for (wildcards are automatically added at both ends).
.PARAMETER SearchBase
Optional LDAP distinguished name to scope the search.
.PARAMETER IncludePhones
If specified, phone-related attributes are included in the search (makes the search a bit slower)
.EXAMPLE
# Find any user whose name, alias, or email contains "nick"
Search-ADUserAnyProperty -Pattern 'nick'
.EXAMPLE
# Search within a specific OU, also matching phone numbers
Search-ADUserAnyProperty -Pattern '2103' -IncludePhones -SearchBase 'OU=Athens,OU=Users,DC=corp,DC=example,DC=com'
.EXAMPLE
# Export results to CSV
Search-ADUserAnyProperty -Pattern 'nick' |
Export-Csv C:\temp\ad-search.csv -NoTypeInformation -Encoding UTF8
A collection of helper functions for handling files
Read more
Get-HardLinks
Lists files in the current directory that have >1 hardlink, and shows all link paths
Read more
.EXAMPLE
Get-HardLinks|Format-List
New-ZipFromFolder
Creates a zip file from a folder, keeping the folder as the top-level entry and allowing for exclusions.
Read more
Packages the source folder into a zip file whose top-level folder name
matches the source folder name. Allows for recursive exclusions based
on file name, folder name, or relative path.
Creates a sibling staging folder next to the source folder and removes
it before returning. On NTFS volumes, included files are staged as
hardlinks unless DontUseHardLinks is set. Hardlinking is super-fast.
.PARAMETER Exclude
Wildcard patterns used to skip files or folders anywhere under the
source folder. A pattern can match an item name or a relative path.
.PARAMETER NoCompression
When set, writes the archive without compression.
.PARAMETER Fast
When set, writes the archive with the fastest compression level.
.PARAMETER DontUseHardLinks
When set, stages included files by copying them; otherwise the function
uses hardlinks when the source volume supports them.
.EXAMPLE
New-ZipFromFolder .\App .\App.zip `
-Exclude '*.bak','*.tmp','.git'
Creates the zip while skipping matching files and folders under App.
Delete-OldFiles
Deletes old files under a directory tree, with WhatIf support.
Read more
Attempts to remove files under Root whose LastWriteTime is older than Cutoff.
Use this when you need recursive age-based cleanup with WhatIf support and
optional cleanup of child folders left empty by the cleanup.
Skips reparse points (junctions/symlinks/mount points) so cleanup stays inside
the intended tree.
By default, non-root child folders will be removed when they have no
remaining files or child folders after file cleanup. Root is not
removed. When LeaveEmptyFolders is set, folders are not removed.
Deletion failures for individual files or folders are reported as warnings.
Other matching files and folders may still be processed. Permission limits,
locked files, and enumeration errors can leave matching files or folders in
place.
.OUTPUTS
None. Does not write objects to the pipeline.
Writes scan and deletion status to the host.
Writes warnings for failed file or folder removals.
.PARAMETER Root
Directory tree to clean. The path must identify an existing directory.
.PARAMETER Cutoff
Files with LastWriteTime earlier than this value are candidates for removal.
.PARAMETER LeaveEmptyFolders
When set, only matching files are removed; otherwise, non-root child folders
left empty by the cleanup scope may also be removed.
.EXAMPLE
Delete-OldFiles -Root C:\Temp -Cutoff (Get-Date).AddMonths(-6) -WhatIf
Shows the files and folders that would be removed under C:\Temp.
.EXAMPLE
Delete-OldFiles -Root C:\Temp -Cutoff (Get-Date).AddMonths(-6) `
-LeaveEmptyFolders
Removes old files under C:\Temp but does not remove empty folders.
Get-DiskInfo
Gets Win32_LogicalDisk information for one disk.
Read more
Popular properties: FreeSpace, Size, VolumeName, DriveType
.PARAMETER Disk Disk device ID, for example C:.
Test-NonReparseDirectory
Returns true only for real directories, not junctions/symlinks.
Read more
.PARAMETER LiteralPath Directory path to test without wildcard expansion.
Clear-OldTempFiles
Deletes old files from common Windows temporary file locations.
Read more
Attempts to remove old files from the current process TEMP and TMP
locations, the Windows temp location, and detected user temp folders under
C:\Users.
Skips reparse points (junctions/symlinks/mount points) so cleanup stays inside
the intended trees.
Use this as a safer temp cleanup entry point when you need age-based cleanup
across the usual system and user temp locations, WhatIf support, and optional
cleanup of child folders left empty by the cleanup.
The cutoff is calculated from the current time and MonthsOld. By default,
non-root child folders inside each temp root may also be removed when they
have no remaining detected files or child folders after file cleanup. Temp
root folders themselves are not removed.
Deletion failures for individual files or folders are reported as warnings.
Other matching files and folders may still be processed. Permission limits,
locked files, missing profiles, and enumeration errors can leave matching
files or folders in place. Run elevated to cover system and other-user temp
locations where required.
.OUTPUTS
None. Does not write objects to the pipeline.
Writes cutoff, scan, and deletion status to the host.
Writes warnings for failed file or folder removals.
.PARAMETER MonthsOld
Age threshold in months. Files older than the calculated cutoff are
candidates for removal.
.PARAMETER LeaveEmptyFolders
When set, only matching files are removed; otherwise, non-root child folders
left empty by the cleanup will also be removed.
.EXAMPLE
Clear-OldTempFiles -WhatIf
Shows the old temp files and folders that would be removed.
.EXAMPLE
Clear-OldTempFiles -MonthsOld 3 -LeaveEmptyFolders
Removes temp files older than the calculated cutoff and keeps folders.
A collection of helper functions for Networking
Read more
Get-RemoteIpOnLowListeningTcpPort
Lists remote IPs observed on local listening TCP ports.
Read more
.OUTPUTS
Produces one psCustomObject per remote IP:
RemoteAddress : The remote IP address.
LocalPorts : The local listening port or ports observed.
States : The TCP state or states observed.
ConnectionCount : The number of matching TCP connection rows.
.DESCRIPTION
Reports remote IPs that currently have, or still have visible closed TCP
rows for, non-loopback local listening TCP ports below the configured
port limit.
Use this when you need a compact connection inventory by remote IP,
rather than raw connection rows. The result is a point-in-time view of
the TCP table. Connections removed by Windows before the function runs
are not reported.
By default, loopback, wildcard, and the server's own IP addresses are
excluded from remote addresses. This avoids reporting connections from
the server to itself.
.PARAMETER MaxListeningPortExclusive
Upper exclusive local listening port limit. Only listening TCP ports
below this value are considered.
.PARAMETER States
TCP states to include. Use names accepted by the State property, such
as Established, TimeWait, CloseWait, LastAck, FinWait1, and FinWait2.
.PARAMETER IncludeLocalMachineConnections
When set, connections whose remote address is one of the server's own
IP addresses may be included. Otherwise, they are excluded.
.EXAMPLE
Get-RemoteIpOnLowListeningTcpPort
Returns one row per remote IP, with the observed local ports, observed
TCP states, and matching connection-row count.
.EXAMPLE
Get-RemoteIpOnLowListeningTcpPort -Verbose
Returns the same objects and writes the matched connection details to
the verbose stream.
Watch-RemoteIpOnLowListeningTcpPort
Watches and optionally reports remote IPs observed on local listening TCP ports.
Read more
Maintains a cumulative record of remote IPs observed on non-loopback local
listening TCP ports below the configured port limit.
The watch continues until interrupted, for example with Ctrl+C. By default,
it runs silently and does not produce success-stream output.
For each remote IP, the function records the first and last observation time.
Local ports and TCP states are accumulated for the lifetime of the stored
state.
When ShowReport is specified, the cumulative report is displayed periodically.
Report generation is controlled separately from connection sampling to avoid
repeatedly constructing a potentially large formatted report.
When StateFile is provided, the cumulative state is saved in CLIXML format.
If the file already exists, its observations are loaded and collection
continues from that state. This allows the watch to be stopped and resumed.
The parent directory of StateFile is created when necessary. State is first
written to a temporary file and then moved over the configured state file to
reduce the risk of leaving a partially written file.
.OUTPUTS
None by default.
When ShowReport is specified, the function writes a formatted report directly
to the host. The report contains:
RemoteAddress : The remote IP address.
LocalPorts : Local listening port or ports observed.
States : TCP state or states observed.
FirstSeen : First time the remote IP was observed.
LastSeen : Most recent time the remote IP was observed.
The formatted report is host output and is not written to the success-output
pipeline.
.PARAMETER Seconds
Number of seconds between TCP connection sampling cycles.
The default is 10 seconds.
.PARAMETER MaxListeningPortExclusive
Upper exclusive local listening port limit. Only listening TCP ports below
this value are considered.
The default is 49152.
.PARAMETER States
TCP states to include, such as Established, TimeWait, CloseWait, LastAck,
FinWait1, and FinWait2.
.PARAMETER IncludeLocalMachineConnections
Includes connections whose remote address is one of the server's own IP
addresses.
By default, loopback, unspecified, and local-machine remote addresses are
excluded.
.PARAMETER StateFile
Path to the CLIXML file used to load and save the cumulative observations.
The file contains structured state, not the formatted on-screen report.
.PARAMETER SaveIntervalSeconds
Minimum number of seconds between writes to StateFile.
The default is 60 seconds. This parameter has no effect when StateFile is not
specified.
.PARAMETER ShowReport
Displays the cumulative report periodically.
By default, reporting is disabled. Collection and StateFile updates continue
normally without this switch.
.PARAMETER ReportIntervalSeconds
Minimum number of seconds between displayed reports when ShowReport is
specified.
The default is 300 seconds. This parameter does not affect the connection
sampling interval.
.EXAMPLE
Watch-RemoteIpOnLowListeningTcpPort
Samples TCP connections every 10 seconds and maintains cumulative observations
in memory. It produces no regular report and does not persist the observations.
.EXAMPLE
Watch-RemoteIpOnLowListeningTcpPort `
-StateFile C:\IT\log\seen_tcp_connections.clixml
Samples TCP connections every 10 seconds, loads any existing observations from
the CLIXML file, and saves the cumulative state at intervals of at least
60 seconds. It does not display the cumulative report.
.EXAMPLE
Watch-RemoteIpOnLowListeningTcpPort `
-Seconds 5 `
-StateFile C:\Temp\observed-connections.clixml `
-ShowReport `
-ReportIntervalSeconds 300
Samples connections every 5 seconds, saves cumulative state to the CLIXML file,
and displays the cumulative report no more than once every 5 minutes.
Test-IpReachability
Probe point-in-time ICMP reachability for one or more IP targets.
Read more
Sends one or more ICMP echo attempts to each target and returns one output
object per unique target IP.
When a ping attempt cannot be performed due to an internal runtime error,
the target result's lastStatus is set to a string beginning with
"PROGRAM EXCEPTION:".
.OUTPUTS
[pscustomobject]
One object per unique target IP with properties:
- ip (string): The target IP string as provided/normalized.
- responded (bool): $true if any attempt succeeded; otherwise $false.
- attempts (int): Number of attempts made for that target.
- respondedOnAttempt (Nullable[int]): Attempt number of first success;
otherwise $null.
- rttMs (Nullable[long]): Round-trip time in milliseconds for the
successful response; otherwise $null.
- lastStatus (string): Final status observed for the target. For runtime
errors, begins with "PROGRAM EXCEPTION:".
.PARAMETER Ip
One or more target IPs to probe.
Accepts:
- A single value convertible to string.
- An enumerable of values convertible to string.
- A single string containing multiple targets separated by commas and/or
whitespace.
.PARAMETER Retry
Number of additional attempts per target after the first attempt.
.PARAMETER TimeoutMs
Timeout in milliseconds for each attempt.
.EXAMPLE
Test-IpReachability -Ip '10.1.11.50,10.1.11.55 10.1.11.56' `
-Retry 1 -TimeoutMs 500 -Verbose
Test-TcpPort
Quickly tests whether a TCP connection can be established.
Read more
Tests TCP connectivity from the current machine to the specified target
and ports, and returns one result object per requested port.
The target MAY be specified as an IP address or a hostname. If name
resolution fails, the function throws a terminating error.
Ports are accepted in multiple input forms.
The -TimeoutMs value is a single overall time budget (in milliseconds) for
the entire batch of ports, not a per-port timeout.
.OUTPUTS
System.Management.Automation.PSCustomObject
One object per normalized port, with these properties:
- port (int) The TCP port tested.
- open (bool) $true if a connection was established; otherwise $false.
- detail (string) "connected" on success; otherwise an error identifier
or "timeout" if the overall time budget was reached.
Objects are emitted in ascending port order.
.PARAMETER Target
Target host to test.
.PARAMETER Ports
Ports to test. Accepts:
- a single integer
- an array of integers
- a string containing one or more port numbers
- an enumerable of values convertible to integers
.PARAMETER TimeoutMs
Overall time budget for the entire batch, in milliseconds. Defaults to
200. When the budget is exhausted, remaining ports are reported as
"timeout".
.EXAMPLE
Test-TcpPort -Target '10.1.11.1' -Ports 80,443,4444
.EXAMPLE
Test-TcpPort -Target 'google.com' -Ports '80,443,4444' `
-TimeoutMs 1000
Test-NetConnectivityToHost
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. - If -HostFriendlyName is passed, it is used to refer to the host in all messages. 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
Split-IpByReachability
Splits input IPs into Alive vs NotAlive based on whether they respond to pings
Read more
Runs Test-IpReachability for the provided targets and returns a single object
containing two string arrays:
- AliveIps: IPs that responded ($true)
- DeadIps: IPs that did not respond ($false) or hit errors/timeouts
.INPUTS
Same accepted shapes as Test-IpReachability -Ip.
.OUTPUTS
[pscustomobject] with:
- AliveIps ([string[]])
- DeadIps ([string[]])
- Results ([pscustomobject[]]) raw per-IP results (handy for lastStatus/rtt)
Test-NetConnectivityToNetwork
Assesses reachability of a network by pinging a list of hosts that are known to reply.
Read more
Given a human-friendly network description (e.g. "10.11.x.y/16") and a list of
IP addresses that are expected to respond to ICMP, this function probes them
(using Split-IpByReachability) and outputs the results using:
Write-Warning "[<level>] ..."
(<level> is one of pass, notice, failure)
If -ReturnListOfAliveHosts is used, the function does not emit warnings and
instead returns the list of responsive hosts.
Test-ShareLikelyUp
QUICKLY tests whether the host of a UNC share is LIKELY reachable over SMB.
Read more
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.
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.
.PARAMETER SharePath
UNC share path whose host will be tested.
.PARAMETER DnsCidrs
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.
.PARAMETER TcpTimeoutMs
For the connection test to TCP port 445 (SMB).
.OUTPUTS
A PSCustomObject with the test outcome and discovered details.
.EXAMPLE
Test-ShareLikelyUp -SharePath '\\server01\share'
.EXAMPLE
Test-ShareLikelyUp -SharePath '\\192.168.1.2\foo'
.EXAMPLE
Test-ShareLikelyUp -SharePath '\\server01.contoso.local\share' -DnsCidrs '10.30.0.0/16'
A collection of helper functions for Processes & Tasks
Read more
Quote-Win32Arg
Quotes a string so it can be safely passed as a single argument to a Windows process via CreateProcess, following the exact Win32 command-line parsing rules. It ensures arguments containing spaces, quotes, or trailing backslashes are preserved exactly as intended when reconstructed by the target program. 'simple' => simple 'hello world' => "hello world" 'He said "hello"' => "He said \"hello\"" 'C:\Temp\' => "C:\Temp\\" 'C:\Path With Spaces\' => "C:\Path With Spaces\\" 'C:\X\"Y"\Z\' => "C:\X\\\"Y\\\"\Z\\"
Join-Win32CommandLine
Constructs a valid Win32 command-line string from a list of arguments.
Read more
Iterates through a collection of arguments, applies Win32 escaping to each (via Quote-Win32Arg), and joins them with spaces. This creates a single string safe for use with APIs like System.Diagnostics.Process or CreateProcess.
['git', 'commit', '-m', 'Msg'] => git commit -m Msg
['app.exe', 'C:\Program Files\', '/v'] => app.exe "C:\Program Files\\" /v
['echo', '', 'foo'] => echo "" foo
.PARAMETER ArgumentList
The collection of objects (strings) to be joined. Objects are converted to strings before quoting.
ConvertTo-PowerShellSingleQuotedString
Escapes a value as a PowerShell single-quoted string literal.
ConvertTo-PowerShellEncodedCommand
Encodes PowerShell source text for powershell.exe -EncodedCommand.
New-DetachedPSScriptRemoteCommandLine
Builds the remote powershell.exe command line for Invoke-DetachedPSScript.
New-ScheduledTaskForPSScript
Registers a Windows Scheduled Task that runs a PowerShell script as SYSTEM.
Read more
Creates or updates a scheduled task that runs the script specified by
-ScriptPath using Windows PowerShell (powershell.exe).
The task is registered under -TaskPath and -TaskName (a default name is
chosen when -TaskName is not provided). If a task with the same name
already exists at that path, it is replaced.
The task runs as the built-in SYSTEM account with highest run level. Task
settings limit concurrent executions by ignoring new starts while an
instance is already running, and apply -ExecutionTimeLimit to each run.
Depending on the script path and provided arguments, the function MAY
create a .cmd wrapper file in the script's folder and configure the task
to execute that wrapper instead of invoking powershell.exe directly.
If -ScheduleType is Manual, the task is created without a trigger and
will only run when started manually (or by other tooling).
Supports -WhatIf and -Confirm. If confirmation is declined (or -WhatIf is
used), no task is registered and no wrapper file is created.
.OUTPUTS
Microsoft.Management.Infrastructure.CimInstance
A scheduled task object returned by Register-ScheduledTask when the task
is registered. If ShouldProcess declines the action, no output is
produced.
.PARAMETER ScriptPath
Path to an existing PowerShell script file. The path MUST exist or the
function throws before making changes.
.PARAMETER ScheduleType
Selects how (or whether) the task is triggered.
Valid values:
- Startup: runs at system startup.
- Daily: runs daily at -Time.
- Weekly: runs weekly on -Day at -Time.
- Hourly: repeats every hour starting shortly after creation time.
- EveryMinute: repeats every minute starting shortly after creation time.
- Manual: no trigger is created.
.PARAMETER Time
Time of day in HH:mm (24-hour) format. Required for Daily and Weekly.
.PARAMETER Day
One or more weekdays. Required for Weekly.
.PARAMETER TaskPath
Scheduled task folder path in Task Scheduler (for example '\enLogic\').
Defaults to '\enLogic\'.
.PARAMETER TaskName
Scheduled task name. If omitted, a name is derived from the script file
name.
.PARAMETER ScriptArguments
Argument values passed to the script. Provide either -ScriptArguments or
-RawArgumentsAvoidMe, not both.
Elements MAY be $null. How the script receives $null depends on the
invocation mode chosen by the function.
.PARAMETER RawArgumentsAvoidMe
A raw argument string appended to the invocation. Intended for advanced
cases. Provide either -ScriptArguments or -RawArgumentsAvoidMe, not both.
.PARAMETER ExecutionTimeLimit
Maximum runtime allowed for each task invocation. Defaults to 2 hours.
.PARAMETER StartItNow
If set, the function attempts to start the task immediately after it is
registered. If starting fails, the task remains created and an error is
written.
.EXAMPLE
New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Health.ps1' `
-ScheduleType Startup -TaskPath '\enLogic\'
.EXAMPLE
New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Report.ps1' `
-ScheduleType Daily -Time '02:30' -TaskName 'Daily Report' `
-ScriptArguments @('Full','EU')
.EXAMPLE
New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\Cleanup.ps1' `
-ScheduleType Weekly -Day Monday,Thursday -Time '03:00' `
-ExecutionTimeLimit (New-TimeSpan -Minutes 30) -StartItNow
.EXAMPLE
New-ScheduledTaskForPSScript -ScriptPath 'C:\Ops\OnDemand.ps1' `
-ScheduleType Manual -TaskName 'Run On Demand'
.NOTES
Registers the task to run as SYSTEM with highest privileges, and sets
MultipleInstances to IgnoreNew.
For Hourly and EveryMinute schedules, the first run is anchored to a
start time shortly after the function is invoked (not aligned to clock
boundaries).
Invoke-DetachedScriptLocally
Runs a PowerShell script in the background as SYSTEM user.
Read more
The script runs elevated as a scheduled task under the local SYSTEM account,
and does not depend on the current terminal staying open or the user staying
logged-in. Note: SYSTEM has very limited network access. In many environments,
it cannot access normal user-mapped drives, user profile locations, remote
file shares, SharePoint/OneDrive sync paths owned by a user, or network
resources that require the user's credentials.
.PARAMETER ScriptPath
The local path of the .ps1 script to run.
.PARAMETER ArgumentList
Optional arguments to pass to the script.
.PARAMETER LogPath
Optional path for redirected script output. If omitted, a log file is created
under the TEMP directory of the caller.
.EXAMPLE
Invoke-DetachedScriptLocally -ScriptPath 'C:\Scripts\Foo.ps1'
.EXAMPLE
Invoke-DetachedScriptLocally -ScriptPath 'C:\Scripts\Foo.ps1' -ArgumentList 'server01', 'full'
Runs the script as SYSTEM and passes two arguments.
.EXAMPLE
Invoke-DetachedScriptLocally -ScriptPath 'C:\Scripts\Foo.ps1' -LogPath 'C:\Temp\Foo.log' -Verbose
Runs the script as SYSTEM and writes verbose messages about cleanup of old idle
tasks.
Invoke-DetachedPSScript
Executes a PowerShell script locally or on a remote host as a detached process.
Read more
If Computer refers to the local machine, the script is executed through
Invoke-DetachedScriptLocally. This means that:
the script runs elevated as a scheduled task under the local SYSTEM account,
and does not depend on the current terminal staying open or the user staying
logged-in. Note: SYSTEM has very limited network access. In many environments,
it cannot access normal user-mapped drives, user profile locations, remote
file shares, SharePoint/OneDrive sync paths owned by a user, or network
resources that require the user's credentials.
If Computer refers to a remote machine, the script is copied if needed and then
started remotely through CIM/WMI using Win32_Process.Create. Again the script
does not depend on the current terminal staying open or the user staying
logged-in or even the controller-computer being powered-on. This method also
avoids leaving a disconnected PowerShell remoting session after execution
completes.
.PARAMETER Script
Path to a .ps1 script.
.PARAMETER ScriptBlock
For local execution, it is written to:
C:\ProgramData\TempForDetachedScripts\Scripts
For remote execution, it is written locally first, copied to the remote TEMP
directory (old generated remote temp scripts are cleaned up).
.PARAMETER LogFile
Optional log file path. For local execution, if omitted, a log file is created
under:
C:\ProgramData\TempForDetachedScripts\Logs
For remote execution, if supplied, Start-Transcript is used on the remote host.
.OUTPUTS
For local execution, returns task information from Invoke-DetachedScriptLocally
plus ComputerName, Status, and ExecutionMode.
For remote execution, returns a PSCustomObject with:
ComputerName, ProcessId, ReturnValue, Status, and ExecutionPath.
Get-ProcessesWithMatchingCommandLine
List processes with command lines matching a like expression (e.g. "*myScript.ps1*")
Read more
.EXAMPLE
Get-ProcessesWithMatchingCommandLine "*myScript.ps1*"
Test-ExeFound
Tests whether an executable can be resolved either as a full path or via PATH/PATHEXT.
Read more
Accepts either:
- A rooted path (e.g. C:\Tools\uchardet or C:\Tools\uchardet.exe), in which case it checks existence and,
if no extension was given, also tries common executable extensions (.exe/.cmd/.bat/.com).
- A bare command name (e.g. uchardet), in which case it resolves it the same way PowerShell would when
launching a process (Get-Command + PATHEXT).
Returns $true if the executable can be found, otherwise $false.
Get-TopRamProcess
Returns the processes consuming the most resident physical memory.
Read more
Returns at least MinProcesses processes, ordered by working-set size.
Processes continue to be included until their combined working sets reach
TargetPercentOfUsedRam percent of currently used physical RAM, or until
MaxProcesses processes have been included. Estimated non-process RAM is
included in the ranking as a synthetic entry named [non-process].
Command lines are excluded by default because retrieving them requires an
additional CIM/WMI query. Use IncludeCommandLine when they are required.
.PARAMETER MinProcesses
Minimum number of processes to return.
The default is 10.
.PARAMETER MaxProcesses
Maximum number of processes to return, even when the requested RAM target
has not been reached.
MaxProcesses cannot be less than MinProcesses.
The default is 100.
.PARAMETER TargetPercentOfUsedRam
Target percentage of currently used physical RAM to cover with the
cumulative working sets of the returned processes.
This is a target rather than an exact limit. The final process is included
in full, so the reported cumulative percentage normally exceeds the
requested percentage slightly.
The default is 25.
.PARAMETER IncludeCommandLine
Retrieves and returns the command line for each selected process.
This requires an additional CIM/WMI query and therefore adds work on an
already stressed system. Command lines may also expose passwords, tokens,
connection strings, or other sensitive values.
Some command lines may be unavailable because of permissions, protected
processes, or processes terminating during collection.
.OUTPUTS
PSCustomObject with the following properties:
PID
Name
RAM_MB
RAM_PercentOfTotal
RAM_PercentOfUsed
CumulativeUsedRAMPct
CommandLine
CommandLine is null unless IncludeCommandLine is specified.
.NOTES
RAM usage is based on each process's working set. A working set represents
physical pages currently resident for that process, but it can contain
shared pages such as DLL code. Summing process working sets can therefore
count the same physical pages more than once. CumulativeUsedRAMPct is an
approximate diagnostic value and can exceed 100 percent.
Not all used physical RAM belongs to user-visible processes. Kernel pools,
drivers, the file cache, modified pages, memory compression, Hyper-V guest
memory, and other operating-system allocations may consume substantial
memory. The function estimates that gap as:
used physical RAM minus the summed working sets of all readable
processes
The estimate is exposed as the synthetic [non-process] entry. When summed
working sets exceed used RAM because of shared pages, the synthetic entry
is reported as zero.
Process state can change during collection. A process may terminate after
it is enumerated, and Windows could theoretically reuse its PID before the
optional command-line query. Such races cannot be eliminated by a snapshot
function.
The function creates and sorts a small object for every process before
selecting the result set. This is normally minor, but its cost increases on
systems running unusually large numbers of processes.
When IncludeCommandLine is used, the additional CIM/WMI query consumes more
CPU and memory and may involve provider activity at a time when the system
is already under pressure.
.EXAMPLE
Get-TopRamProcess
Returns at least 10 entries and continues until their combined RAM usage
approximately covers 25 percent of currently used RAM, up to a maximum of
100 entries. The ranking may include the synthetic [non-process] entry.
.EXAMPLE
Get-TopRamProcess -MinProcesses 5 -MaxProcesses 50 `
-TargetPercentOfUsedRam 40
Returns at least 5 and at most 50 processes, targeting approximately
40 percent of currently used RAM.
.EXAMPLE
Get-TopRamProcess -IncludeCommandLine
Includes process command lines using an additional CIM/WMI query.
A collection of helper functions for handling text files
Read more
Edit-TextFile
Searches and replaces text in files while maintaining the existing text encoding (but will switch ASCII to UTF8 if replacement is unicode).
Read more
Performs an in-place regex (or literal) search/replace on a text file,
while preserving the file's actual encoding. For _really_ hard cases it
may mistake the encoding. In such cases it may fail to find the pattern
and/or change the encoding of the input file.
You may pass wildcards like "*.txt" to -File.
To apply one substitution use `-Patern 'a' -Replacement 'b'`. To apply
multiple substitutions use `-ReplaceMap` (see examples).
Without -Literal considers Pattern(s) to be a regex pattern.
By default keeps a backup with .bak extension. To skip the Backup
use -Backup "". To change the extension use -Backup "ext".
If the sampled bytes are pure 7-bit ASCII and no BOM is present, the
function by default assumes a UTF8 encoding (even though ASCII is also
valid). This is intentional: it allows replacements to introduce Unicode
without changing the reported encoding unexpectedly. Use -DontPreferUTF8
to force ASCII encoding.
.OUTPUTS
Produces a psCustomObject for each evaluated file:
File = The file path
Changed = True/False
EncodingStr = Human readable encoding.
EncodingObj = The output of Get-TextFileEncoding
Details = Human readable outcome. E.g.:
"Changes made"
"Pattern(s) not found"
"Skipped too big file ..."
"Ignored empty file"
"No files matched pattern"
.PARAMETER MaxFileSize
Files larger than these many bytes are ignored.
.PARAMETER PreferISOEncodings
When set, ISO encodings are selected when multiple encodings represent
the text equivalently; otherwise, Windows encodings are selected.
.EXAMPLE
Edit-TextFile -file .\ansi.txt -Pattern "foo" -Replacement="_FOO_"
.EXAMPLE
Edit-TextFile -file .\ansi.txt -Pattern "foo?" -Replacement="_FOO_?" -Literal
.EXAMPLE
Edit-TextFile -file .\ansi.txt -ReplaceMap ([ordered]@{"foo"="_FOO_"; "bar"="_BAR_"})
.NOTES
The operation writes modified content to temporary storage before
replacing the target file. Original files are backed up prior to the
modification. If a terminating error occurs during the file swap, the
target file might remain in its prior state and intermediate temporary
files might remain on the storage volume.
Files exceeding the configured maximum size limit or containing no
data are skipped. Substitutions are evaluated sequentially.
Get-NewlineStyle
Detect newline style in a decoded string. Returns 'CRLF','LF','CR','Mixed','None','NotChecked'.
Get-TextFileEncoding
Detect (if possible) or guess the encoding of Text Files.
Read more
Uses uchardet (CLI) and simple BOM/ASCII checks.
Returns an object like this:
File : C:\tempansi.txt
Type : NON-ASCII-TEXT
BOMBytes : {}
UCharDetEncoding : ISO-8859-1
EncodingDescription : CP1252
DotNetEncodingObj : System.Text.SBCSCodePageEncoding
NewlineStyle :
BytesRead : 22
UCharDetTimeMs : 0
TotalTimeMs : 55
.PARAMETER
-DontPreferUTF8: If the sampled bytes are pure 7-bit ASCII and no BOM
is present, the function returns UTF-8 by default (even though ASCII
is also valid). This is intentional: it allows later writes/replacements
to introduce Unicode without changing the reported encoding unexpectedly.
Use -DontPreferUTF8 to return ASCII instead.
In other words: The default UTF-8 return value is not a strict
"encoding detection" result; it is a compatibility policy for downstream
editing workflows.
-PreferISOEncodings: by default we return Windows encodings instead of ISO ones
WHEN BOTH PRODUCE THE SAME TEXT. This switch overides that behavior.
.NOTES
- Will fail for pathological files (e.g. BOM indicates UTF-8
but file is UTF-16).
- It consumes RAM to read the file's bytes, possible twice.
(That's why -MaxBytes is by default 512KB)
- It may fail in very hard cases like:
- Files larger than 512KB that appear as ASCII in the first
-MaxBytes and then have some ANSI or UTF-8 bytes.
- Files with ambiguous ASCII encodings (e.g. ISO-8859-1 /
CP1252)
- Respects -ErrorAction by emitting non-terminating errors.
- By default (without -PreferISOEncodings) it will assume a file
is encoded with a Windows(CP) encoding if it can be either
an ISO encoding (e.g. ISO-8859-1) or a windows one (e.g. CP1251)
(Since a lot of these encodings are very similar, a file with plenty
of text but none of the few characters that are encoded
differently between the ISO/CP encodings can be encoded with both giving
exactly the same bytes)
For reference these are the default encoding for Notepad,
PS5 & PS7 per windows version:
| | PS 5.1 | PS 5.1 | PS 7 either
Operating System | Notepad | > a.txt | Out-File | > or Out-File
2016 (1607 LTSC) | ANSI | ANSI | UTF-16 LE*| UTF-8*
2019 (1809 LTSC) | ANSI | ANSI | UTF-16 LE*| UTF-8*
2022 (21H2 LTSC) | UTF-8* | ANSI | UTF-16 LE*| UTF-8*
2025 (24H2 LTSC) | UTF-8* | ANSI | UTF-16 LE*| UTF-8*
*: UTF-8 always without BOM, UTF-16 always with BOM
TODO:
Offer help on how to install uchardet if not found.
Remove-TypographyUnicodeFromTextFile
Substitutes Unicode typography characters with ASCII characters in one or more target text files. Mimics the interface of Edit-TextFile.
Read more
Modifies the specified file or files (if you use wildcards like *.txt)
in place. Useful for eliminating unnecessary Unicode typography from code.
You may pass wildcards like "*.ps1" to -File.
By default keeps a backup with .bak extension. To skip the Backup
use -Backup "". To change the extension use -Backup "ext".
.OUTPUTS
Produces a psCustomObject for each evaluated file:
File = The file path
Changed = True/False
EncodingStr = Human readable encoding.
EncodingObj = The output of Get-TextFileEncoding
Details = Human readable outcome. E.g.:
"Changes made"
"Pattern(s) not found"
"Skipped too big file ..."
"Ignored empty file"
"No files matched pattern"
.PARAMETER MaxFileSize
Files larger than these many bytes are ignored.
.PARAMETER PreferISOEncodings
When set, ISO encodings are selected when multiple encodings represent
the text equivalently; otherwise, Windows encodings are selected.
.NOTES
Why we have to do the changes in three batches instead of all together:
By default, PowerShell hashtables (@{} and [ordered]@{}) use culture-sensitive
linguistic comparison.
Because 0x200B, 0x200C, and 0x200D are invisible formatting characters,
the linguistic comparer gives them a sorting weight of zero. Therefore,
PowerShell evaluates them as the exact same string and throws a "Duplicate keys"
error when building the hashtable.
Replace-FileBytesSafely
Replaces a file's contents with specified bytes, optionally retaining a backup.
Read more
Behavior and guarantees:
- Writes the new content to -TmpPath first, then attempts to replace -ResolvedPath with it.
- Primary path uses [IO.File]::Replace(), which is the best option on local NTFS:
* Readers see either the old or the new file, not a partially-written file.
* A backup at -BakPath is created/overwritten as part of the replace.
- If Replace() fails (common on non-NTFS volumes, SMB shares with varying semantics, or transient locks
e.g. AV/OneDrive/indexing), it falls back to Copy-Item + Move-Item with best-effort rollback:
* This fallback is NOT atomic. It is provided for compatibility and "works in more places".
* If the move fails after the backup copy, the function attempts to restore from -BakPath.
Backup semantics:
- -BakPath is always used as the safety copy when swapping.
- If -UserBackup is $true, -BakPath is considered caller-visible and is preserved.
- If -UserBackup is $false, -BakPath is a transient safety backup and may be deleted on success.
Cleanup:
- Always attempts to delete -TmpPath in a finally block.
- Does not promise preservation of metadata/streams in the fallback path (ACLs, ADS, timestamps, etc.)
beyond what the underlying filesystem/provider naturally keeps.
.PARAMETER ResolvedPath
The existing target file to be replaced (must be on the same volume as -TmpPath for best behavior).
.PARAMETER TmpPath
A temp file path in the same directory as the target (recommended) containing the new bytes to commit.
.PARAMETER BakPath
Path for the backup copy used during the swap. May be a user-requested backup (kept) or a transient one.
.PARAMETER UserBackup
Indicates whether -BakPath is user-requested (keep it) or internal/transient (delete on success).
.PARAMETER Bytes
The final bytes to be written/committed to the target file.
.NOTES
- Intended for "in-place update" workflows: generate full new content, then commit in one swap.
- For OneDrive/SMB scenarios, transient failures are normal; callers may want a small retry policy
around the Replace() stage (if not implemented inside this function).
Read-FirstBytes
Safe(shared) read of up to Count bytes from the start of a file.
Test-ExeFound
Tests whether an executable can be resolved either as a full path or via PATH/PATHEXT.
Read more
Accepts either:
- A rooted path (e.g. C:\Tools\uchardet or C:\Tools\uchardet.exe), in which case it checks existence and,
if no extension was given, also tries common executable extensions (.exe/.cmd/.bat/.com).
- A bare command name (e.g. uchardet), in which case it resolves it the same way PowerShell would when
launching a process (Get-Command + PATHEXT).
Returns $true if the executable can be found, otherwise $false.
Resolve-FileFromPath
Resolve a path to exactly one existing FileSystem file ([IO.FileInfo]) or return $null.
Read more
Accepts a path (or FileInfo/DirectoryInfo) and enforces strict "one real file" semantics:
- Must exist
- Must be FileSystem provider
- Must not be a directory
- If wildcards are used, they must match exactly one item
On failure, emits a tagged _Write-FunctionError ([RFFP-*]) including both the original input and (when available)
the resolved full path, then returns $null (caller decides whether to stop via -ErrorAction).
.OUTPUTS
System.IO.FileInfo or $null.
Test-BufferIsValidUtf8
Validates that a byte[] buffer is UTF-8, while intentionally tolerating an incomplete final UTF-8 sequence.
Read more
Returns $true if the buffer contains no invalid UTF-8 sequences in its body.
Only relevant to mazars (Install/Update mazars-prepare-laptop-code)
Requires -Version 5.1
Requires -RunAsAdministrator
Continuously pings a host, or a small set of public hosts, and displays live connection-quality statistics.
Read more
Out-PingStats is an interactive terminal monitor for ICMP latency and packet loss.
When you specify -Target, it continuously pings that host and renders live graphs and summaries for:
- recent RTT values
- RTT histogram
- rolling loss percentage
- rolling one-way jitter estimate
- rolling RTT 95th percentile
When you omit -Target, it probes a few well-known Internet hosts in parallel and treats the result as a rough
"Internet reachability and quality" indicator rather than a measurement for one exact destination.
The display updates continuously until you stop it, typically with Ctrl+C.
This command is intended for human monitoring in a console window. Its primary output is a live screen display,
not pipeline-friendly structured objects.
For best-looking graphs, use a monospace font with good Unicode block-character support. DejaVu Sans Mono works
well. Consolas usually forces lower-resolution graph characters.
.INTERACTIVE CONTROLS
While the monitor is running, you can use:
Ctrl-H Toggle RTT histogram
Ctrl-R Toggle recent-RTT graph
Ctrl-L Toggle loss graph
Ctrl-J Toggle jitter graph
Ctrl-S Toggle graph character set / font mode
.PARAMETER Target
Host name or IP address to probe.
If omitted, the command monitors general Internet quality by pinging several public hosts in parallel.
.PARAMETER Title
Custom title shown at the top of the screen.
By default, the title is derived from -Target, or shows a generic Internet-oriented title when -Target is omitted.
.PARAMETER GraphMax
Upper Y-axis limit for RTT graphs.
By default, the command chooses a sensible value automatically.
.PARAMETER PingsPerSec
Deprecated. Currently has no practical effect.
.PARAMETER GraphMin
Lower Y-axis limit for RTT graphs.
By default, the command chooses a sensible value automatically.
.PARAMETER HistBucketsCount
Number of buckets to use in the RTT histogram.
.PARAMETER AggregationSeconds
Number of seconds per aggregation period for the slower trend graphs such as loss, jitter, and RTT 95th percentile.
.PARAMETER HistSamples
Number of recent samples to include in the RTT histogram.
If omitted, the default is at least 100 samples and otherwise about one minute of samples.
.PARAMETER Visual
Reserved legacy parameter. Do not rely on it.
.PARAMETER DebugMode
Enables diagnostic behavior and reduces screen-clearing behavior to help troubleshoot parsing, aggregation,
or rendering issues.
.PARAMETER DebugData
Enables extra debug-data collection.
.PARAMETER HighResFont
Controls graph-character mode.
-1 = auto-detect
0 = force low-resolution characters
1 = force high-resolution characters
Use low-resolution mode for terminals or fonts that do not render the Unicode block characters cleanly.
.PARAMETER UpdateScreenEvery
How often, in seconds, the screen is refreshed.
Lower values make the display more responsive but may increase CPU use.
.PARAMETER BarGraphSamples
How many recent samples to show in the scrolling bar graphs.
By default, the command derives this from the current console width.
.EXAMPLE
Out-PingStats google.com
Continuously monitors latency, loss, jitter, and latency distribution to google.com.
.EXAMPLE
Out-PingStats 1.1.1.1 -Title "Cloudflare DNS"
Monitors 1.1.1.1 and shows a custom title.
.EXAMPLE
Out-PingStats
Shows a rough live view of general Internet quality by probing several public hosts in parallel.
.EXAMPLE
Out-PingStats 8.8.8.8 -GraphMin 0 -GraphMax 100 -AggregationSeconds 60
Monitors 8.8.8.8 with fixed RTT graph limits and 1-minute aggregation windows.
.NOTES
This command starts background jobs and cleans them up when it exits.
It also writes temporary screen/statistics data files under $env:TEMP.
Loss, jitter, and percentile values are intended for operational monitoring, not for strict scientific measurement.
.OUTPUTS
None. This command is designed for interactive console display.
.INPUTS
None. This command does not accept pipeline input.
Safe* and automatic DISM + SFC repairs made easy.
Read more
Runs CHKDSK, DISM(CheckHealth/RestoreHealth) and SFC with preflight checks, concise console output, and logging.
Designed to minimize risk* and be thourough.
*: REGARDING SAFETY
This script is safe to run on Windows installations with no weird customizations,
Don't use it on boxes with OEM-customized, but still WRP-protected components,
or older apps that replace protected system binaries.
.PARAMETER Source
Optional, one or more DISM sources, e.g. 'WIM:D:\sources\install.wim:1','ESD:E:\sources\install.esd:6'.
.PARAMETER ScratchDirectory
Optional scratch directory for servicing if supported (offloads staging from C:).
.PARAMETER MinFreeSystemGB
Minimum free GB on system drive before running heavy servicing (default 4GB).
.PARAMETER MinFreeScratchGB
Minimum free GB on ScratchDirectory if provided. (default 4GB)
.PARAMETER LimitAccess
Use only -Source and avoid Windows Update (WU/WSUS). Use this along with -Source. PREFER TO AVOID THIS OPTION.
.EXAMPLE
.\Run-DismSfc.ps1 -Source 'WIM:D:\sources\install.wim:1'
Minimize copy-pasting and typing while using an LLM like Toula-the-fixer to troubleshoot issues.
Read more
HOW TO USE ME
Begin by opening a terminal and dot-sourcing this script. E.g.:
$p="C:\IT\bin";$f="Start-Copy4Toula.ps1";mkdir $p -force >$null
iwr -useb https://ndemou.github.io/scripts/$f -out $p\$f
. C:\IT\bin\Start-Copy4Toula.ps1
Then repeat these steps:
1. Copy code from the LLM
2. Run `q` in the terminal (it will execute the code _and_ copy back the results)
3. Go back to the LLM and paste the output.
If you run commands directly, or accidentally press ctrl-C you can
run `q -CopyOnly` to copy all output since the last time you run either `q`.
DETAILS
The script maintains two transcript files:
- `$env:TEMP\TTFtrans-$PID.full.txt` has the cumulative raw history of the full session.
- `$env:TEMP\TTFtrans-$PID.txt` has just the most recent chunk of output.
`q` will copy up to 5000 lines by default. You can change the limit:
$global:SctMaxLinesToCopy = 8000
The output of some rare legacy tools may not appear in the transcript.
It's extremely rare though and you can always copy-paste manually.
.EXAMPLE
. .\Start-Copy4Toula.ps1
q
q
Prints a detailed warning every time it finds RAM, CPU or Disks are stressed
Read more
There are two modes of operation: monitoring and log file analysis.
In monitor mode (the default) it prints a detailed warning every
time it finds RAM, CPU or Disks are stressed.
In monitor mode these switches may be used.
-MonitorVolumes: Will also monitor IO stress of Volumes
-DontMonitorDisks: Will NOT monitor IO stress of disks
In log analysis (invoked if you supply a -LogFile) it creates a
summary report based on the contents of the log file.
In log analysis mode these arguments may be used.
-Granularity
-LogsToIgnoreRegex
.EXAMPLE
Download & Setup to always run on startup
$dir="C:\IT\bin";$f="Test-ForCpuRamDiskStress.ps1"
if (-not (test-path $dir\$f)) {
"Downloading"; mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f
if (-not (Get-ScheduledTask -TaskPath '\enLogic\' -TaskName 'Execute Test-ForCpuRamDiskStress.ps1' -ErrorAction SilentlyContinue)) {
$dir="C:\IT\bin";$f="helpers-processes.ps1";mkdir $dir -force >$null;iwr -useb https://ndemou.github.io/scripts/$f -out $dir\$f
. $dir\$f
"Setting up scheduled task on startup"
New-ScheduledTaskForPSScript -ScriptPath 'C:\IT\bin\Test-ForCpuRamDiskStress.ps1' `
-ScheduleType Startup -TaskPath '\enLogic\' `
-ScriptArguments @('-LogDir','c:\it\log','-LogBaseName','CpuRamDiskStress')
"Starting task"
Start-ScheduledTask -TaskPath '\enLogic\' -TaskName 'Execute Test-ForCpuRamDiskStress.ps1'
sleep 2
Get-ScheduledTask -TaskPath '\enLogic\' -TaskName 'Execute Test-ForCpuRamDiskStress.ps1'
if (test-path C:\it\log\CpuRamDiskStress.*) {
"Last 20 lines of latest log file"
cat (ls C:\it\log\CpuRamDiskStress.*|sort -Property LastWriteTime|select -last 1) | select -last 20
} else { echo "ERROR: No logs found: C:\it\log\CpuRamDiskStress.*" }
.EXAMPLE
Get statistics for a particular date
& $bin\Test-ForCpuRamDiskStress.ps1 -Granularity 10m -LogFile C:\it\log\CpuRamDiskStress.2026-01-14.log
.EXAMPLE
If you want to run only once:
& C:\IT\bin\Test-ForCpuRamDiskStress.ps1 -LogDir c:\it\log -LogBaseName 'CpuRamDiskStress'
.EXAMPLE
What you see if memory is under pressure.
C:\IT\bin\Test-ForCpuRamDiskStress.ps1 | Tee-Object "C:\it\temp\CpuRamDiskStress.log"
20:12:47 HIGH <HOSTNAME> Reasons:
- 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.
- High classification gate satisfied: Available memory(%) minimum 0,5 is below the 10% gate threshold.
Measurements:
- Time window: 18 secs (9 samples)
- Available memory: average 68,3%, minimum 0,5%
- Committed memory: average 31,9%, maximum 67,0%
- Paging file usage: maximum 73%
- Page Reads/sec (hard faults): average 319, maximum 1.789
- Page Writes/sec: average 23, maximum 203
- Transition Faults/sec: average 1.281, maximum 6.797
- Disk read latency: average 0,0 ms
- Disk write latency: average 0,0 ms
- Disk queue length: average 7,3
- Standby cache memory: Normal 58 MB, Reserve 222 MB, Core 0 MB
- File cache memory: 4 MB
- Modified page list: 134 MB
- Compressed memory: 0 MB
Ensures all ndemou.github.io/scripts are up-to-date.
Read more
Existing files that differ are replaced and a backup is created.
Identical files are left unchanged.
Ensures all health-check scripts and PS Modules are installed & up-to-date.
Read more
Missing files are created. Existing files that differ are replaced.
Identical files are left unchanged. If this script updates itself,
it re-invokes the updated copy. When replacing a file, backup copies
are created in the backups directory.
Will set PSGallery as Trusted.
The updater also tracks a small "release marker" for the currently
installed code and for the target update source. A release marker is a
stable identifier for a specific release source, typically derived from
GitHub release metadata or from a manually supplied zip file name plus
its content hash. These markers are cached locally and let the updater
decide whether the requested update is already installed, whether it can
skip re-downloading or reapplying files, and when `-Reinstall` should
force the update to run again.
.PARAMETER Reinstall
Forces reinstall even when installed release matches target release.
.PARAMETER UpdateFromZip
Overides the default which is to fetch the latest GitHub release.
.PARAMETER Version
Explicit semantic version to associate with `-UpdateFromZip` when the zip
file name does not already embed a version token such as `v4.4.3`.
Use `X.Y.Z` or `vX.Y.Z`.
.PARAMETER ForceRefreshReleaseMetadata
Overides the default which is to cache latest-release metadata locally
for a few minutes (to avoid querying GitHub on every run).
.PARAMETER Config
Hashtable or PowerShell data file path for customized installs. `Options.InstallDir`
sets the install root; `ConfigFiles` writes named .psd1 files under the config folder.
.PARAMETER SelfRerunCount
Internal use only. Tracks the one-time self-rerun pass count.
.PARAMETER PersistReleaseMarker
Internal use only. Carries the resolved release marker across self-rerun.
.PARAMETER Config
Optional installer customization. Pass either a hashtable or the path to a PowerShell data file.
The top-level Options branch changes installer behavior. The top-level ConfigFiles branch
creates PowerShell data files under the installation config directory.
.PARAMETER GenerateConfigPsd1
Creates a template PowerShell data file named GetComputerHealth.install.psd1 in the current
working directory, then exits. Customize that file and pass its path to -Config.
.PARAMETER ScheduleDailyInvokationAt
Creates or updates a daily scheduled task for Invoke-GetComputerHealth.ps1
at the specified 24-hour time in HH:mm format, then exits.
.EXAMPLE
.\Update-GetHealthCode.ps1
Checks the locally cached latest-release metadata, refreshes it from
GitHub when needed, and installs the latest published release when it is
newer than the currently installed release marker.
.EXAMPLE
.\Update-GetHealthCode.ps1 -UpdateFromZip C:\Downloads\GetComputerHealth-v4.4.3.zip
.EXAMPLE
.\Update-GetHealthCode.ps1 -ScheduleDailyInvokationAt 07:12
Records MAC,IP address pairs observed in the local IPv4 neighbor cache.
Read more
The script keeps a running inventory of observed MAC,IP address pairs, with
first seen time and last seen time for each pair.
It is intended for passive local-link observation. It does not scan the
network and should not be used as proof that all devices in a VLAN were
found.
When StateFile is supplied, the output file is created or replaced as a
PowerShell CLIXML file. The parent directory is created when needed. If the
script stops normally or is interrupted, it attempts one final write. A
terminating error can leave the latest observations not written, and may
leave a temporary file beside the target file.
When StateFile is not supplied, the script only prints newly discovered
MAC,IP pairs to the screen and keeps the in-memory inventory only for the
current run.
.OUTPUTS
Produces no pipeline output.
Creates or updates a CLIXML file containing:
GeneratedAt : Timestamp of the file generation.
SeenMACs : List of records, one per MAC,IP address pair.
MAC : MAC address.
IP : IPv4 address.
FirstSeenTimestamp : First time this MAC,IP pair was observed.
LastSeenTimestamp : Most recent time this MAC,IP pair was observed.
.PARAMETER StateFile
Optional path of the CLIXML inventory file to create or update. When omitted, no existing state is loaded and no state file is written.
.PARAMETER PollSeconds
Number of seconds between neighbor-cache observations.
.PARAMETER IdleWriteSeconds
Maximum seconds between writes when no new MAC,IP pair has been observed.
.PARAMETER ActiveWriteSeconds
Maximum seconds between writes while new MAC,IP pair observations exist.
.EXAMPLE
.\Watch-SeenMacAddresses.ps1
Starts passive observation without loading or writing a state file.
.EXAMPLE
.\Watch-SeenMacAddresses.ps1 -StateFile 'C:\it\log\seen_MAC_addresses.clixml'
Starts passive observation and persists observations to the specified CLIXML file.
.EXAMPLE
.\Watch-SeenMacAddresses.ps1 -StateFile 'C:\it\log\seen_MAC_addresses.clixml' -PollSeconds 15 -ActiveWriteSeconds 30
Polls every 15 seconds and writes changed data at most every 30 seconds.
Installs Windows Updates using the supported WUA COM API, with optional download, controlled reboot (now or scheduled), and detailed logging.
Read more
SPECIAL SHOW UPDATE HISTORY MODE
If -ShowHistory is used, the script does NOT install/download/reboot.
Instead it queries Windows Update history (same source as the GUI "View update history"),
optionally filtered, and then exits.
NORMAL INSTALL UPDATES MODE
By default(without -ShowHistory) it installs Windows updates like this:
- Installs already downloaded updates if any.
- With -Download, will also download all required updates.
- With -Reboot, will reboot after installation if needed (or regardless with -RebootAnyway).
Batches "normal" updates together; installs "exclusive" updates one-by-one; accepts EULAs.
# Regarding Robustness
- Service start is retried up to 3x with exponential delays (5s, 10s, 20s) before failing.
- Pending reboot detection uses WU `RebootRequired` and CBS `RebootPending`.
- Post-download refresh search has a catch/fallback: if the refresh search throws, proceeds using the initial search results (with a warning).
- Uses only supported, inbox components (no extra modules, no `UsoClient`, PS 5.1-safe syntax).
- Reboot is first tried without /f and after a few minutes with /f.
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,
the script will ensure continuation of installations after the reboot like this:
- Create a temporary scheduled task that runs this script again
at startup with -XXX_ResumeAfterReboot.
- On that second automated run with -XXX_ResumeAfterReboot: The startup
task is removed and the script continues as normal (install + maybe reboot).
# Logging
Logs everything to `WindowsUpdateHelper-YYYY-MM-DD.log`
1. If C:\IT\LOG exists, log is created there.
2. Else if C:\IT\LOGS exists, there.
3. Else in the system temp folder.
.EXAMPLE
The fastest way to bring a new installation up-to-date:
**CAUTION**: WILL REBOOT WITHOUT WAITING / WITHOUT ASKING
Download & first run
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Unrestricted -Force
$p="C:\it\bin";mkdir $p -force >$null
$f="WindowsUpdatesHelper.ps1";iwr -useb https://wiki.enlogic.gr/pub/KnowledgeBase/PublicFiles/$f -OutFile $p\$f
& C:\it\bin\WindowsUpdatesHelper.ps1 -Download -Reboot
2nd Run (REPEAT UNTIL YOU GET 0 Updates Found)
& c:\it\bin\WindowsUpdatesHelper.ps1 -Download -Reboot -Interactive
It will also install updates that MAY ask you to accept EULAs or make choices
.EXAMPLE
Display the logs from the last 10 executions of this script
& 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)): '}
.EXAMPLE
**CAUTION**: An unfortunate side-effect of this script is that the updates
it installs are not visible in the GUI (Settings -> Windows Updates).
The only way to view them:
& c:\it\bin\WindowsUpdatesHelper.ps1 -ShowHistory | ft
You may add -IncludeAV if you want to also view (the very frequent) Antivirus udpates
.PARAMETER Download
Perform online scan and download applicable updates that are not yet downloaded, then proceed to install everything downloaded.
.PARAMETER Reboot
After installation, reboot only if updates require it (or regardless if -RebootAnyway is also used).
.PARAMETER Interactive
If specified, the script will include updates flagged as InstallationBehavior.CanRequestUserInput
(Like some drivers/firmware that show GUI prompts and wait for user actions -- e.g. clicking "Accept").
Without this switch, such updates are skipped.
Alias: -CanRequestUserInput
.PARAMETER RebootAnyway
Reboot regardless of whether updates require it (implies -Reboot).
.PARAMETER XXX_ResumeAfterReboot
DO NOT USE THIS SWITCH. It is used INTERNALLY to continue installations after a reboot.
.PARAMETER AbortReboot
Abort a reboot initiated by this script
.PARAMETER XXX_RebootNow
DO NOT USE THIS SWITCH. It is used INTERNALLY to force a reboot.
.PARAMETER XXX_RebootArmedAt
DO NOT USE THIS SWITCH. It is used INTERNALLY to avoid rebooting if a reboot already occured after this time.
.PARAMETER ShowHistory
List Windows Update history (no install/download/reboot) and exit.
.PARAMETER MaxResults
(ShowHistory mode) Maximum number of matching history entries to output. Default: 30. Use 0 to return all matches found (within MaxScanEntries).
.PARAMETER LastDays
(ShowHistory mode) Only include history entries from the last N days.
.PARAMETER IncludeAV
(ShowHistory mode) Include KB2267602 (Defender definitions) entries (excluded by default).
.PARAMETER MaxScanEntries
(ShowHistory mode) Safety cap: maximum number of history rows to scan. Default: 10000.
.PARAMETER ListRecentLogs
List this script's log files and exit. Returns FileInfo objects sorted by LastWriteTime (oldest -> newest; most recent last).
By default it returns the most recent 10 log files.
.PARAMETER ListAll
Used only with -ListRecentLogs. If specified, returns all log files that can be found (instead of only the most recent 10).
.PARAMETER InstallOptional
Installs an optional update (needs the update ID)
.EXAMPLE
Install any already downloaded updates and reboot if needed:
.\WindowsUpdatesHelper.ps1 -Reboot
.EXAMPLE
Download, Install and if needed reboot:
.\WindowsUpdatesHelper.ps1 -Download -Reboot
.EXAMPLE
Download, Install and reboot regardless of whether updates require it:
.\WindowsUpdatesHelper.ps1 -Download -Reboot -RebootAnyway
.EXAMPLE
Show latest Windows Update history entries:
.\WindowsUpdatesHelper.ps1 -ShowHistory
.EXAMPLE
Show latest Windows Update history entries, include AV updates:
.\WindowsUpdatesHelper.ps1 -ShowHistory -LastDays 14 -IncludeAV
.EXAMPLE
List the most recent 10 log files created by this script (most recent last):
.\WindowsUpdatesHelper.ps1 -ListRecentLogs