D.R.
D.R.

Reputation: 21204

PowerShell Param() statement + error trap

We're using the following statement to enable TeamCity to recognize errors in our PowerShell deployment scripts:

trap { $host.SetShouldExit(1) }

This works fine, however, since Param(...) needs to be the very first statement we have to use this order:

Param(
    ...
)

Set-StrictMode -Version 2.0
$ErrorActionPreference = "Stop"
trap { $host.SetShouldExit(1) }

Is there any way to also trap errors during the Param() evaluation? E.g. if we omit a mandatory parameter, TeamCity is not able to detect this at the moment.

Upvotes: 2

Views: 4513

Answers (4)

Sebastian J.
Sebastian J.

Reputation: 762

Actually I had the same question and ended up on combining both approaches:

  1. Use -Command calling to powershell.exe to allow to trap the Parameter error
  2. Use trap within the Powershell script to handle errors within - and use $LASTEXITCODE to counter balance Powershell's behavior

Calling side in BAT/CMD:

@echo off
powershell -NoLogo -NonInteractive -Command "& {trap {Write-Error $_; exit 2}; scipt.ps1 %1 %2 %3 %4 %5 %6 %7 %8 %9 ; exit $LASTEXITCODE}"
IF %ERRORLEVEL% NEQ 0 Exit /B %ERRORLEVEL%
Goto :EOF

:EOF

The PowerShell script

Param(
    ...
)

Set-StrictMode -Version 2.0
$ErrorActionPreference = "Stop"
trap { Exit(1) }

...

That way one can decide between Param errors (exit code 2) and errors in the script itself (exit code 1)

Upvotes: 1

Phil C
Phil C

Reputation: 431

This is yet another annoying oversight of Powershell. I find the best way to workaround this Powershell bug is to roll your own mandatory verification. It's more code, but clear, simple and fail-safe.

First remove the mandatory flag from the param declaration and check for null or empty at the beginning of the script.

param (
    [string] $required_param
)
# Check required params
if ([string]::IsNullOrEmpty($required_param)) {
    Write-Host "The required_param is required."
    exit 1;
}

Plus you can call your script with the regular File argument:

powershell -File foo.ps1

Hope this helps.

Upvotes: 4

Keith Hill
Keith Hill

Reputation: 201692

Try putting the trap in the TeamCity string to execute. For instance, say I have a script with a param block at the top of the script (foo.ps1) with a mandatory parameter that I don't supply e.g.:

param([Parameter(Mandatory)][int]$num, [bool]$bool)

Then I can execute it like so from CMD and get an error exit code:

C:\> cmd /c Powershell.exe -NonInteractive -Command "& {trap {exit 1}; c:\foo.ps1}"
C:\> %ERRORLEVEL%
1

BTW you might find this blog post an interesting read.

Upvotes: 1

HAL9256
HAL9256

Reputation: 13473

If I understand you correctly, you want to execute a PowerShell script, and have TeamCity see the error returned. I think that this is very similar to how I catch and return errors in my scripts that need to be run with scheduled tasks.

How I do it is first make functions/cmdlts for everything you want to do. Then execute those functions in a try..catch block. e.g.

#My test function
Function test{
Param( [Parameter(Mandatory=$true)] [int]$a )
Process
    {
        Write-Host "Hi $a"
    }
}

#Execute Function
Try{
    test 1234 -ErrorAction "Stop"
}
Catch
{
    #Error encountered
    Write-Host "Error Encountered: exiting"
    #Return Bad error code
    Exit 1
}

This should catch any parameters that are incorrect.

This may not be applicable, but other people's reference, for scheduled tasks, I run my scheduled tasks with the following command:

powershell.exe -Command ". C:\Scripts\Run_PS1.ps1 ; exit $LASTEXITCODE"

This will run powershell, execute the script, and then correctly return the last exit code back to the scheduled task.

Hope this helps you out.

Upvotes: 0

Related Questions