This guide demonstrates how to use the Register-ToolWrapper function to create standardized wrapper functions for external tools with consistent error handling and command detection.
The Register-ToolWrapper function provides:
- Cached command detection - Uses
Test-CachedCommandfor performance - Standardized error handling - Consistent warnings when tools are missing
- Install hints - Helpful installation instructions
- Idempotent registration - Uses
Set-AgentModeFunctioninternally - Custom warning messages - Optional custom messages for missing tools
# Register a wrapper for a tool (function name matches command name)
Register-ToolWrapper -FunctionName 'bat' -CommandName 'bat' -InstallHint 'Install with: scoop install bat'# Register with a custom warning message
Register-ToolWrapper `
-FunctionName 'http' `
-CommandName 'http' `
-WarningMessage 'httpie (http) not found' `
-InstallHint 'Install with: scoop install httpie'# Register multiple tools at once
Register-ToolWrapper -FunctionName 'bat' -CommandName 'bat' -InstallHint 'Install with: scoop install bat'
Register-ToolWrapper -FunctionName 'fd' -CommandName 'fd' -InstallHint 'Install with: scoop install fd'
Register-ToolWrapper -FunctionName 'zoxide' -CommandName 'zoxide' -InstallHint 'Install with: scoop install zoxide'
Register-ToolWrapper -FunctionName 'delta' -CommandName 'delta' -InstallHint 'Install with: scoop install delta'
Register-ToolWrapper -FunctionName 'tldr' -CommandName 'tldr' -InstallHint 'Install with: scoop install tldr'# ===============================================
# modern-cli.ps1
# Modern CLI tools helper functions
# ===============================================
# bat - cat clone with syntax highlighting and Git integration
Register-ToolWrapper -FunctionName 'bat' -CommandName 'bat' -InstallHint 'Install with: scoop install bat'
# fd - find files and directories
Register-ToolWrapper -FunctionName 'fd' -CommandName 'fd' -InstallHint 'Install with: scoop install fd'
# http - command-line HTTP client
Register-ToolWrapper `
-FunctionName 'http' `
-CommandName 'http' `
-WarningMessage 'httpie (http) not found' `
-InstallHint 'Install with: scoop install httpie'
# zoxide - smarter cd command
Register-ToolWrapper -FunctionName 'zoxide' -CommandName 'zoxide' -InstallHint 'Install with: scoop install zoxide'
# delta - syntax-highlighting pager for git
Register-ToolWrapper -FunctionName 'delta' -CommandName 'delta' -InstallHint 'Install with: scoop install delta'
# tldr - simplified man pages
Register-ToolWrapper -FunctionName 'tldr' -CommandName 'tldr' -InstallHint 'Install with: scoop install tldr'
# procs - modern replacement for ps
Register-ToolWrapper -FunctionName 'procs' -CommandName 'procs' -InstallHint 'Install with: scoop install procs'
# dust - more intuitive du command
Register-ToolWrapper -FunctionName 'dust' -CommandName 'dust' -InstallHint 'Install with: scoop install dust'# ===============================================
# security-tools.ps1
# Security scanning and analysis tools
# ===============================================
# Dependencies: bootstrap, env
# Tier: standard
# gitleaks - Git secrets scanner
Register-ToolWrapper `
-FunctionName 'Invoke-GitLeaks' `
-CommandName 'gitleaks' `
-InstallHint 'Install with: scoop install gitleaks'
# trufflehog - Secrets scanner
Register-ToolWrapper `
-FunctionName 'Invoke-TruffleHog' `
-CommandName 'trufflehog' `
-InstallHint 'Install with: scoop install trufflehog'
# osv-scanner - Vulnerability scanner
Register-ToolWrapper `
-FunctionName 'Invoke-OsvScanner' `
-CommandName 'osv-scanner' `
-InstallHint 'Install with: scoop install osv-scanner'# Register wrappers with custom function names (different from command names)
Register-ToolWrapper `
-FunctionName 'Invoke-GitLeaks' `
-CommandName 'gitleaks' `
-InstallHint 'Install with: scoop install gitleaks'
Register-ToolWrapper `
-FunctionName 'Invoke-TruffleHog' `
-CommandName 'trufflehog' `
-InstallHint 'Install with: scoop install trufflehog'
# Use the functions
Invoke-GitLeaks -Repository "C:\Projects\MyRepo"
Invoke-TruffleHog -Path "C:\Projects\MyRepo"# Register wrapper for a specific command type (default is 'Application')
Register-ToolWrapper `
-FunctionName 'Get-GitStatus' `
-CommandName 'git' `
-CommandType 'Application' `
-InstallHint 'Install with: scoop install git'# Only register if Register-ToolWrapper is available
if (Get-Command Register-ToolWrapper -ErrorAction SilentlyContinue) {
Register-ToolWrapper -FunctionName 'bat' -CommandName 'bat' -InstallHint 'Install with: scoop install bat'
}
else {
# Fallback: manual registration
if (Test-CachedCommand 'bat') {
Set-AgentModeFunction -Name 'bat' -Body { bat @args }
}
else {
Write-MissingToolWarning -Tool 'bat' -InstallHint 'Install with: scoop install bat'
}
}# ❌ OLD: Manual wrapper with repetitive code
if (Test-CachedCommand 'bat') {
function global:bat {
param([Parameter(ValueFromRemainingArguments)]$Arguments)
bat @Arguments
}
}
else {
Write-MissingToolWarning -Tool 'bat' -InstallHint 'Install with: scoop install bat'
}
if (Test-CachedCommand 'fd') {
function global:fd {
param([Parameter(ValueFromRemainingArguments)]$Arguments)
fd @Arguments
}
}
else {
Write-MissingToolWarning -Tool 'fd' -InstallHint 'Install with: scoop install fd'
}# ✅ NEW: Standardized wrapper registration
Register-ToolWrapper -FunctionName 'bat' -CommandName 'bat' -InstallHint 'Install with: scoop install bat'
Register-ToolWrapper -FunctionName 'fd' -CommandName 'fd' -InstallHint 'Install with: scoop install fd'Benefits:
- 65% code reduction - From 58 lines to 20 lines (as demonstrated in
modern-cli.ps1) - Consistent error handling - All wrappers use the same warning pattern
- Easier maintenance - Single function to update for all wrappers
- Better performance - Uses cached command detection
# ===============================================
# api-tools.ps1
# API development and testing tools
# ===============================================
# Dependencies: bootstrap, env
# Tier: standard
# Load module dependencies first
if (Get-Command Import-FragmentModule -ErrorAction SilentlyContinue) {
Import-FragmentModule `
-FragmentRoot $PSScriptRoot `
-ModulePath @('dev-tools-modules', 'api', 'api-helpers.ps1') `
-Context "Fragment: api-tools (api-helpers.ps1)"
}
# Register tool wrappers
Register-ToolWrapper `
-FunctionName 'Invoke-Bruno' `
-CommandName 'bruno' `
-InstallHint 'Install with: scoop install bruno'
Register-ToolWrapper `
-FunctionName 'Invoke-Hurl' `
-CommandName 'hurl' `
-InstallHint 'Install with: scoop install hurl'
Register-ToolWrapper `
-FunctionName 'Start-HttpToolkit' `
-CommandName 'httptoolkit' `
-InstallHint 'Install with: scoop install httptoolkit'The Register-ToolWrapper function handles errors automatically:
- Missing tool: Displays warning with install hint (does not throw error)
- Function already exists: Returns
$false(idempotent) - Invalid parameters: Returns
$falsesilently
# Register wrapper and check result
$success = Register-ToolWrapper `
-FunctionName 'bat' `
-CommandName 'bat' `
-InstallHint 'Install with: scoop install bat'
if (-not $success) {
Write-Warning "Failed to register bat wrapper (function may already exist)"
}# ✅ GOOD: Descriptive function names
Register-ToolWrapper -FunctionName 'Invoke-GitLeaks' -CommandName 'gitleaks' -InstallHint '...'
Register-ToolWrapper -FunctionName 'Invoke-TruffleHog' -CommandName 'trufflehog' -InstallHint '...'
# ❌ AVOID: Generic names
Register-ToolWrapper -FunctionName 'tool1' -CommandName 'gitleaks' -InstallHint '...'# ✅ GOOD: Specific install instructions
Register-ToolWrapper -FunctionName 'bat' -CommandName 'bat' -InstallHint 'Install with: scoop install bat'
# ❌ AVOID: Vague hints
Register-ToolWrapper -FunctionName 'bat' -CommandName 'bat' -InstallHint 'Install the tool'# Group related tools together
# Security tools
Register-ToolWrapper -FunctionName 'Invoke-GitLeaks' -CommandName 'gitleaks' -InstallHint '...'
Register-ToolWrapper -FunctionName 'Invoke-TruffleHog' -CommandName 'trufflehog' -InstallHint '...'
# API tools
Register-ToolWrapper -FunctionName 'Invoke-Bruno' -CommandName 'bruno' -InstallHint '...'
Register-ToolWrapper -FunctionName 'Invoke-Hurl' -CommandName 'hurl' -InstallHint '...'# Use custom warnings for clarity when command name differs from tool name
Register-ToolWrapper `
-FunctionName 'http' `
-CommandName 'http' `
-WarningMessage 'httpie (http) not found' `
-InstallHint 'Install with: scoop install httpie'Instead of hardcoding install hints, you can use the Get-ToolInstallHint function from Command.psm1 to dynamically resolve install commands from the centralized requirements system. This provides:
- Platform-specific install commands - Automatically resolves Windows/Linux/macOS commands
- Centralized maintenance - Update install commands in one place (
requirements/external-tools/*.psd1) - Consistent formatting - All hints follow the same "Install with: ..." pattern
- Fallback support - Falls back to default commands if requirements aren't available
# Import Command module for Get-ToolInstallHint
if (-not (Get-Command Get-ToolInstallHint -ErrorAction SilentlyContinue)) {
$repoRoot = if (Get-Command Get-RepoRoot -ErrorAction SilentlyContinue) {
Get-RepoRoot -ScriptPath $PSScriptRoot -ErrorAction SilentlyContinue
}
else {
Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
}
if ($repoRoot) {
$commandModulePath = Join-Path $repoRoot 'scripts' 'lib' 'utilities' 'Command.psm1'
if (Test-Path -LiteralPath $commandModulePath) {
Import-Module $commandModulePath -DisableNameChecking -ErrorAction SilentlyContinue
}
}
}
# Use Get-ToolInstallHint to get install hint from requirements
$installHint = if (Get-Command Get-ToolInstallHint -ErrorAction SilentlyContinue) {
$repoRoot = if (Get-Command Get-RepoRoot -ErrorAction SilentlyContinue) {
Get-RepoRoot -ScriptPath $PSScriptRoot -ErrorAction SilentlyContinue
}
else {
$null
}
Get-ToolInstallHint -ToolName 'gitleaks' -RepoRoot $repoRoot
}
else {
"Install with: scoop install gitleaks"
}
# Use with Write-MissingToolWarning
if (-not (Test-CachedCommand 'gitleaks')) {
if (Get-Command Write-MissingToolWarning -ErrorAction SilentlyContinue) {
Write-MissingToolWarning -Tool 'gitleaks' -InstallHint $installHint
}
else {
Write-Warning "gitleaks not found. $installHint"
}
return $null
}# ===============================================
# security-tools.ps1
# Security scanning and analysis tools
# ===============================================
# Dependencies: bootstrap, env
# Tier: standard
try {
# Idempotency check
if (Get-Command Test-FragmentLoaded -ErrorAction SilentlyContinue) {
if (Test-FragmentLoaded -FragmentName 'security-tools') { return }
}
# Import Command module for Get-ToolInstallHint
if (-not (Get-Command Get-ToolInstallHint -ErrorAction SilentlyContinue)) {
$repoRoot = if (Get-Command Get-RepoRoot -ErrorAction SilentlyContinue) {
Get-RepoRoot -ScriptPath $PSScriptRoot -ErrorAction SilentlyContinue
}
else {
Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
}
if ($repoRoot) {
$commandModulePath = Join-Path $repoRoot 'scripts' 'lib' 'utilities' 'Command.psm1'
if (Test-Path -LiteralPath $commandModulePath) {
Import-Module $commandModulePath -DisableNameChecking -ErrorAction SilentlyContinue
}
}
}
# Gitleaks wrapper
function Invoke-GitLeaksScan {
param(
[string]$RepositoryPath,
[string]$ReportPath
)
if (-not (Test-CachedCommand 'gitleaks')) {
$installHint = if (Get-Command Get-ToolInstallHint -ErrorAction SilentlyContinue) {
$repoRoot = if (Get-Command Get-RepoRoot -ErrorAction SilentlyContinue) {
Get-RepoRoot -ScriptPath $PSScriptRoot -ErrorAction SilentlyContinue
}
else {
$null
}
Get-ToolInstallHint -ToolName 'gitleaks' -RepoRoot $repoRoot
}
else {
"Install with: scoop install gitleaks"
}
if (Get-Command Write-MissingToolWarning -ErrorAction SilentlyContinue) {
Write-MissingToolWarning -Tool 'gitleaks' -InstallHint $installHint
}
else {
Write-Warning "gitleaks not found. $installHint"
}
return $null
}
# Tool implementation...
}
}
catch {
Write-ProfileError -ErrorRecord $_ -Context "Fragment: security-tools"
}Create a requirements file for your tools (e.g., requirements/external-tools/security-tools.psd1):
@{
ExternalTools = @{
'gitleaks' = @{
Version = 'latest'
Description = 'Find secrets in git repositories'
Required = $false
InstallCommand = @{
Windows = 'scoop install gitleaks'
Linux = 'See: https://github.com/gitleaks/gitleaks'
MacOS = 'brew install gitleaks'
}
}
'trufflehog' = @{
Version = 'latest'
Description = 'Find secrets in code and history'
Required = $false
InstallCommand = @{
Windows = 'scoop install trufflehog'
Linux = 'See: https://github.com/trufflesecurity/trufflehog'
MacOS = 'brew install trufflehog'
}
}
}
}Then load it in requirements/load-requirements.ps1:
# Security Tools (automated loading)
$securityToolsPath = Join-Path $scriptDir 'external-tools' 'security-tools.psd1'
if (Test-Path $securityToolsPath) {
try {
$securityToolsConfig = Import-PowerShellDataFile $securityToolsPath -ErrorAction Stop
if ($securityToolsConfig.ExternalTools) {
foreach ($tool in $securityToolsConfig.ExternalTools.Keys) {
$ExternalTools[$tool] = $securityToolsConfig.ExternalTools[$tool]
}
}
}
catch {
Write-Warning "Failed to load Security tools from $securityToolsPath : $($_.Exception.Message)"
}
}- Centralized Configuration - All install commands in one place
- Platform Awareness - Automatically resolves platform-specific commands
- Easy Updates - Change install command once, affects all usages
- Consistent Formatting - All hints follow "Install with: ..." pattern
- Graceful Fallback - Works even if requirements aren't loaded
Use Get-ToolInstallHint when:
- Tool has platform-specific install commands
- Tool is defined in requirements system
- You want centralized maintenance
- Tool may have different install methods (scoop, brew, apt, etc.)
Use hardcoded hints when:
- Tool has a single, universal install command
- Tool is not in requirements system
- You need maximum simplicity for simple wrappers
You can combine both patterns:
# Get install hint from requirements
$installHint = if (Get-Command Get-ToolInstallHint -ErrorAction SilentlyContinue) {
$repoRoot = if (Get-Command Get-RepoRoot -ErrorAction SilentlyContinue) {
Get-RepoRoot -ScriptPath $PSScriptRoot -ErrorAction SilentlyContinue
}
else {
$null
}
Get-ToolInstallHint -ToolName 'gitleaks' -RepoRoot $repoRoot
}
else {
"Install with: scoop install gitleaks"
}
# Use with Register-ToolWrapper
Register-ToolWrapper `
-FunctionName 'Invoke-GitLeaksScan' `
-CommandName 'gitleaks' `
-InstallHint $installHintRegister-ToolWrapperusesTest-CachedCommandinternally for fast command detection- Functions are registered using
Set-AgentModeFunctionfor idempotent registration - Missing tools display warnings but do not throw errors (graceful degradation)
- All wrappers automatically pass through arguments using
@args - The function is backward compatible - check for availability before using
Get-ToolInstallHintis available inscripts/lib/utilities/Command.psm1and can be imported by any fragmentGet-ToolInstallHintautomatically usesResolve-InstallCommandfor platform-specific resolution- Requirements are cached by
Import-Requirements, so multiple calls toGet-ToolInstallHintare efficient