Private/Invoke-RemoteOrLocal.ps1

#Requires -Version 5.1

function Invoke-RemoteOrLocal {
    <#
        .SYNOPSIS
            Executes a scriptblock locally or remotely via Invoke-Command
 
        .DESCRIPTION
            Centralises the local-vs-remote execution decision that is repeated
            across most PSWinOps public functions. When the target computer name
            matches the local machine ($env:COMPUTERNAME, 'localhost', or '.'),
            the scriptblock is invoked directly with the call operator (&).
            Otherwise it is dispatched via Invoke-Command over WinRM.
 
            This eliminates ~300 lines of duplicated if/else blocks across the
            module and provides a single place to maintain the remoting logic.
 
        .PARAMETER ComputerName
            The target computer. When it matches the local machine, the
            scriptblock runs in-process without WinRM overhead.
 
        .PARAMETER ScriptBlock
            The scriptblock to execute. Must accept positional parameters
            matching the ArgumentList array when ArgumentList is provided.
 
        .PARAMETER ArgumentList
            Optional array of arguments passed positionally to the scriptblock.
            For local execution they are splatted; for remote execution they
            are forwarded to Invoke-Command -ArgumentList.
 
        .PARAMETER Credential
            Optional credential for remote execution. Ignored for local calls.
            When not supplied, Invoke-Command runs under the current user context.
 
        .EXAMPLE
            Invoke-RemoteOrLocal -ComputerName $env:COMPUTERNAME -ScriptBlock { Get-Service }
 
            Executes the scriptblock locally via the call operator.
 
        .EXAMPLE
            Invoke-RemoteOrLocal -ComputerName 'SRV01' -ScriptBlock { param($svc) Get-Service -Name $svc } -ArgumentList @('w32time')
 
            Executes the scriptblock on SRV01 via Invoke-Command, passing 'w32time' as argument.
 
        .EXAMPLE
            Invoke-RemoteOrLocal -ComputerName 'SRV01' -ScriptBlock { Get-Process } -Credential $cred
 
            Executes the scriptblock on SRV01 via Invoke-Command with explicit credentials.
 
        .OUTPUTS
            System.Object
            Returns whatever the scriptblock produces.
 
        .NOTES
            Author: Franck SALLET
            Version: 1.1.0
            Last Modified: 2026-04-02
            Requires: PowerShell 5.1+ / Windows only
            Scope: Private - not exported
 
        .LINK
            https://github.com/k9fr4n/PSWinOps
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [string]$ComputerName,

        [Parameter(Mandatory)]
        [scriptblock]$ScriptBlock,

        [Parameter()]
        [object[]]$ArgumentList,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $Credential
    )

    if ($script:LocalComputerNames -contains $ComputerName) {
        Write-Verbose -Message "[Invoke-RemoteOrLocal] Executing locally on '$ComputerName'"
        if ($ArgumentList) {
            return & $ScriptBlock @ArgumentList
        }
        return & $ScriptBlock
    }

    Write-Verbose -Message "[Invoke-RemoteOrLocal] Executing remotely on '$ComputerName' via Invoke-Command"
    $invokeParams = @{
        ComputerName = $ComputerName
        ScriptBlock  = $ScriptBlock
        ErrorAction  = 'Stop'
    }
    if ($ArgumentList) {
        $invokeParams['ArgumentList'] = $ArgumentList
    }
    if ($null -ne $Credential) {
        $invokeParams['Credential'] = $Credential
    }

    Invoke-Command @invokeParams
}