How to mock a call to an exe file with Pester?

I found a way to mock the call to this executable files:

function Create-Object
{
   $exp = '& "C:\temp\my.exe"'
   Invoke-Expression -Command $exp
}

And the test with the mock should looks like:

Describe "Create-NewObject" {
    Context "Create-Object" {
        It "Runs" {
            Mock Invoke-Expression {return {$true}} -ParameterFilter {($Command -eq '& "C:\temp\my.exe"')
            Create-Object| Should Be  $true
        }
    }
}

Yes, unfortunately, as of Pester 4.8.1:

  • you cannot mock external executables by their full paths (e.g, C:\Windows\System32\cmd.exe)
  • you can mock them by file name only (e.g., cmd), but beware that in older Pester versions the mock is only called for invocations that explicitly use the .exe extension (e.g., cmd.exe) - see this (obsolete) GitHub issue

Your own workaround is effective, but it involves Invoke-Expression, which is awkward; Invoke-Expression should generally be avoided

Here's a workaround that uses a helper function, Invoke-External, which wraps the invocation of external programs and, as a function, can itself be mocked, using a -ParameterFilter to filter by executable path:

In your code, define the Invoke-External function and then use it to make your call to c:\temp\my.exe:

# Helper function for invoking an external utility (executable).
# The raison d'être for this function is to allow 
# calls to external executables via their *full paths* to be mocked in Pester.
function Invoke-External {
  param(
    [Parameter(Mandatory=$true)]
    [string] $LiteralPath,
    [Parameter(ValueFromRemainingArguments=$true)]
    $PassThruArgs
  )
  & $LiteralPath $PassThruArgs
}

# Call c:\temp\my.exe via invoke-External
# Note that you may pass arguments to pass the executable as usual (none here):
Invoke-External c:\temp\my.exe

Then, to mock the call to c:\temp\my.exe in your Pester tests:

Mock Invoke-External -ParameterFilter { $LiteralPath -eq 'c:\temp\my.exe' } `
  -MockWith { $true }

Note: If you only have one call to an external executable in your code, you can omit the
-ParameterFilter argument.