Execution
4.0.0
Common execution helpers, self-elevation and stub-script wrapper for PowerShell.
Minimum PowerShell version
5.1
Installation Options
Owners
Copyright
(c) 2026 mtb.me. All rights reserved.
Package Details
Author(s)
- Manuel
Tags
Execution Self-Elevation Stub PowerShell Windows
Functions
Clear-TempDirectories ConvertTo-SplatHashtable Exit-AndWaitOnUI Format-SplatHashtable Get-QuotedPath Invoke-Process Invoke-StubScript Invoke-WhenFileChanged Remove-ItemSafe Restart-SelfElevated Set-PSScriptID Start-NativeExecution Test-CalledFromPrompt
PSEditions
Dependencies
This module has no dependencies.
Release Notes
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [v4.0.0] - 2026-05-04
### Added
- Pester 5.x test suite under `tests/`. Covers public and private
functions; `Restart-SelfElevated`, `Exit-AndWaitOnUI`,
`Get-ScriptIsCalledFromUI` and `Invoke-WhenFileChanged` are
intentionally excluded with the rationale documented at the top of
`tests/Execution.Tests.ps1`.
- GitHub Actions workflow `.github/workflows/test.yml`. Runs
`Test-ModuleManifest`, `Import-Module`, `Invoke-ScriptAnalyzer`
(Severity Error,Warning) and `Invoke-Pester` against a
`windows-latest` runner under both Windows PowerShell 5.1 and
PowerShell 7.
### Changed
- Restructure the module into a Public/Private layout with a thin dot-sourcing
loader. Each function lives in its own `.ps1` file under
`src/Execution/Public/` or `src/Execution/Private/`.
- Drop the `SmartLogging` runtime dependency. All `Log <level>` calls are
replaced with the matching native PowerShell streams (`Write-Verbose`,
`Write-Host`, `Write-Warning`, `Write-Error`, `Write-Debug`).
- Drop the `Common` runtime dependency. The single consumer
(`Get-FileHashFromCommand`) now relies on a private SHA256 helper inlined
into the module.
- Modernize across all functions: `New-Object` -> `[Type]::new(...)`,
`[System.Collections.ArrayList]` -> `[System.Collections.Generic.List[T]]`,
`$global:PSScriptInfos` -> module-local `$script:PSScriptInfos`,
`$null -ne $x` ordering, `[OutputType(...)]` and comment-based help on
every Public function.
- Audit every function for `Set-StrictMode -Version Latest` compliance.
Trivial null/member-existence guards added in `Set-PSScriptID`,
`Restart-SelfElevated` / `Exit-AndWaitOnUI` (for the missing
`$PSVersionTable.Platform` member on Windows PowerShell 5.1),
`Get-ScriptIsCalledFromUI`, `Test-CalledFromPrompt`,
`Start-NativeExecution` (snapshot of `$LASTEXITCODE`),
`Clear-TempDirectories` (`@()`-wrap of empty Get-ChildItem result),
and `Format-SplatHashtable` (null-value branch).
- Modernize verbose / debug / host output across every function: drop
function-name-as-first-line headers, leading-space indentation, and
`->`-arrow `$Var: value` echo patterns. Fine-grained step traces
moved from `Write-Verbose` to `Write-Debug`. `Write-Host` reserved
for genuinely user-facing status messages without decorative
prefixes.
### Fixed
- `Set-PSScriptID`: fix `$callerInvocation.BoundParameters[$key]`
interpolation in the default branch of the parameter switch and remove
dead commented-out trace lines.
- `Get-FileHashFromCommand`: log `$Executable` (was `$Command`, undefined)
and correct the misleading `checksum:` labels on the trailing trace
lines.
- `Start-NativeExecution`: drop the dead `$wrapperScriptBlock` assignment
before the `if ($calledFromPrompt)` branch and flip
`if ($Error -ne $null)` to `if ($null -ne $Error)`.
- `Clear-TempDirectories`: read the user-profile root from the registry
(`HKLM:\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\
ProfilesDirectory`) with a fallback to `$env:SystemDrive\Users` instead
of the hardcoded `C:/Users`. The function now declares
`[CmdletBinding(SupportsShouldProcess, ConfirmImpact='High')]` and
gates each destructive call with `$PSCmdlet.ShouldProcess(...)`.
- `Remove-ItemSafe`: declare
`[CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')]`,
gate the `Remove-Item` calls with `$PSCmdlet.ShouldProcess(...)`, and
normalize the `$path` references to the capitalized `$Path`.
- `Invoke-WhenFileChanged`: ensure the `FileSystemWatcher` is disposed and
the event handler is unregistered in a `finally` block, so the loop
cleans up on natural return as well as Ctrl-C / exception. Removed the
redundant top-level `process` and `end` blocks.
- `Set-PSScriptID`: dynamic parameters (declared via the caller's
`DynamicParam` block) are now forwarded as `-Name value` again. The
earlier null-guard skipped them entirely; the binder admits them to
`BoundParameters` even though they never appear in the static
parameter list, so the function now falls through to the same
formatting the `default` switch branch produces.
- `Invoke-WhenFileChanged`: `$global:FileChanged = $false` moved into
the `try` block so a `Resolve-Path` / `Split-Path` failure cannot
leave a stray global behind. The existing `Remove-Variable -Scope
Global -Name FileChanged -ErrorAction SilentlyContinue` in `finally`
copes with the variable not existing yet.
- `Set-PSScriptID`: when called transitively via `Invoke-StubScript`
(the V4 wrapper pattern), the function now records the user's stub
as `ScriptPath`, not `Invoke-StubScript.ps1`. It walks the call stack
past any frame whose `ScriptName` lives inside the module's source
tree and picks the first frame outside; fallback to the immediate
caller preserves the V3 direct-call pattern. Fix is symmetric: the
record's `ScriptPath` now comes from `$frame.ScriptName` (the file
this frame's code lives in), not `$frame.InvocationInfo.PSCommandPath`
(which would be one level too high after the walk-up).
- `Invoke-StubScript`: `-WhatIf`, `-Confirm`, `-Verbose`, `-Debug`,
`-WarningAction`, `-InformationAction` and `-ProgressAction` (PS 7.4+
only) now actually propagate into the payload, including from a
`[CmdletBinding(SupportsShouldProcess)]` stub that calls
`Invoke-StubScript` without explicit forwarding. The earlier attempts
-- module-scoped `$PSDefaultParameterValues`, and then function-local
`$WhatIfPreference` written to `$global:` -- both broke on the
cross-module case because PowerShell's parameter binder does not
propagate the matching preference variables across module boundaries.
The function now resolves the effective preferences with this
priority: (1) the parameter bound directly on `Invoke-StubScript`,
(2) the caller frame's `$WhatIfPreference` / `$ConfirmPreference` /
`$VerbosePreference` / `$DebugPreference` / `$WarningPreference` /
`$InformationPreference` / `$ProgressPreference` read via
`(Get-PSCallStack)[1].GetFrameVariables()`, (3) the documented
defaults (`$false` for WhatIf, `High` for Confirm,
`SilentlyContinue` for Verbose / Debug / InformationAction,
`Continue` for WarningAction / ProgressAction). The chosen values
are written into the matching `$global:` preference variables for
the duration of the payload and restored unconditionally in
`finally`. `-ErrorAction` is intentionally not forwarded; the
function commits to `$ErrorActionPreference = 'Stop'` for its
try/catch contract. The payload is invoked with `&` instead of `.`;
the SessionState binding is what makes stub-scope variables visible,
the call operator is fine. Help block updated to match.
### Removed
- **Breaking**: `Clear-TempDirectories -TryRun` is gone. Use the standard
`-WhatIf` switch instead.
- **Breaking**: `RequiredModules` no longer lists `SmartLogging` or
`Common`. The module now has zero runtime dependencies.
## [v3.0.1] - 2026-04-16
### Fixed
- Add missing `Get-ScriptIsCalledFromUI` cmdlet
## [v3.0.0] - 2026-04-16
### Added
- Add hashtable splatting support
### Fixed
- Remove deprecated support for psScriptID
## [v2.1.1] - 2025-12-29
### Fixed
- Remove set PSScriptID in stacktrace 1
## [v2.1.0] - 2025-12-29
### Changed
- Refactoring to using `PSScriptID` explicit
## [v2.0.2] - 2024-04-28
### Fixed
- Fix parsing bound parameters
## [2.0.1] - 2024-04-27
### Changed
- Only reformatted release notes.
## [v2.0.0] - 2024-04-27
### Changed
- Simplify usage and fix issues when invoke multiple scripts inside (#3).
- Add prefix to mutex files in windows temp folder (#2).
## [v1.7.0] - 2020-03-09
### Fixed
- Better $LASTERRORCODE handling when PowerShell scripts are called from batch files.
FileList
- Execution.nuspec
- Execution.psd1
- Execution.psm1
- Private\Add-ItemWhenExists.ps1
- Private\Get-CanonicalPath.ps1
- Private\Get-Checksum.ps1
- Private\Get-FileHashFromCommand.ps1
- Private\Get-ScriptIsCalledFromUI.ps1
- Public\Clear-TempDirectories.ps1
- Public\ConvertTo-SplatHashtable.ps1
- Public\Exit-AndWaitOnUI.ps1
- Public\Format-SplatHashtable.ps1
- Public\Get-QuotedPath.ps1
- Public\Invoke-Process.ps1
- Public\Invoke-StubScript.ps1
- Public\Invoke-WhenFileChanged.ps1
- Public\Remove-ItemSafe.ps1
- Public\Restart-SelfElevated.ps1
- Public\Set-PSScriptID.ps1
- Public\Start-NativeExecution.ps1
- Public\Test-CalledFromPrompt.ps1
Version History
| Version | Downloads | Last updated |
|---|---|---|
| 5.3.2 | 20 | 5/11/2026 |
| 5.3.1 | 135 | 5/8/2026 |
| 5.3.0 | 103 | 5/7/2026 |
| 5.2.1 | 48 | 5/6/2026 |
| 5.2.0 | 85 | 5/6/2026 |
| 5.1.0 | 105 | 5/5/2026 |
| 5.0.0 | 7 | 5/5/2026 |
| 4.0.0 (current version) | 70 | 5/4/2026 |
| 3.0.1 | 497 | 4/16/2026 |
| 3.0.0 | 7 | 4/16/2026 |
| 2.1.1 | 1,663 | 12/29/2025 |
| 2.1.0 | 6 | 12/29/2025 |
| 2.0.2 | 75,833 | 4/28/2024 |
| 2.0.1 | 328 | 4/27/2024 |
| 2.0.0 | 11 | 4/26/2024 |
| 1.7.0 | 23,958 | 3/9/2020 |
| 1.6.2 | 447 | 2/5/2020 |
| 1.6.1 | 86 | 2/3/2020 |
| 1.6.0 | 42 | 2/3/2020 |
| 1.5.1 | 2,278 | 4/24/2019 |
| 1.5.0 | 201 | 4/1/2019 |
| 1.4.4 | 51 | 3/31/2019 |
| 1.4.3 | 43 | 3/31/2019 |
| 1.4.2 | 45 | 3/31/2019 |
| 1.4.1 | 43 | 3/30/2019 |
| 1.4.0 | 42 | 3/30/2019 |
| 1.3.0 | 43 | 3/30/2019 |
| 1.2.2 | 43 | 3/29/2019 |
| 1.2.1 | 42 | 3/29/2019 |
| 1.2.0 | 67 | 3/28/2019 |
| 1.1.0 | 48 | 3/27/2019 |
| 1.0.2 | 46 | 3/26/2019 |
| 1.0.1 | 104 | 3/17/2019 |
| 1.0.0 | 68 | 3/17/2019 |