Execution

4.0.0

Common execution helpers, self-elevation and stub-script wrapper for PowerShell.

Minimum PowerShell version

5.1

Installation Options

Copy and Paste the following command to install this package using PowerShellGet More Info

Install-Module -Name Execution -RequiredVersion 4.0.0

Copy and Paste the following command to install this package using Microsoft.PowerShell.PSResourceGet More Info

Install-PSResource -Name Execution -Version 4.0.0

You can deploy this package directly to Azure Automation. Note that deploying packages with dependencies will deploy all the dependencies to Azure Automation. Learn More

Manually download the .nupkg file to your system's default download location. Note that the file won't be unpacked, and won't include any dependencies. Learn More

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

Desktop Core

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

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
Show less