How to retrieve exit codes

I have a script that is working great, but I would like the addition of retrieving exit codes. My script uninstalls one program and installs another using the Start-Process cmdlet, but the exit code is not displaying. I read that there is a bug in the Start-Process cmdlet and that is why it is not displaying an exit code.

Basically all I am doing is the following:

$p=start-process -filepath msiexec -argumentlist ‘parameter1’, ‘parameter2’, ‘parameter3’ -nonewwindow -wait

if ($p.exitcode -eq 0)
{
write-output “the program was installed successfully”
}

I used the following method as well, but it is still not displaying the exit code:

$p = [System.Diagnostics.Process]::Start(“program.exe”, “parameter1”)

$p.ExitCode

Does anyone have any good techniques for grabbing exit codes?

Thanks

This was a bug that I remember seeing a while back. Tobias Weltner posted it on Connect here:

https://connect.microsoft.com/PowerShell/feedback/details/520554/start-process-does-not-return-exitcode-property

The article states this was fixed in PS version 4.0. What version do you have?

Also, check here for workarounds:

http://stackoverflow.com/questions/10262231/obtaining-exitcode-using-start-process-and-waitforexit-instead-of-wait

You need to use the parameter -PassThru on Start-Process to get anything returned

Ahhhh -Passthru that was it, thanks.

Also, how do I get Write-Warning to display the exit code?

I am trying something like this and it isn’t working:

Write-Warning -Message “Exit code: $(($InstallSCEP).ExitCode)”

I’ve also tried:

Write-Warning -Message “Exit code: $InstallSCEP.ExitCode”

and

Write-Warning -Message “Exit code: $($InstallSCEP.ExitCode)”

But nothing seems to work to display the exit code with Write-Warning.

Thanks for again for your help

If you have a value in $InstallSCEP.ExitCode, then the first and third options will display the value. I should note that the third option would be preferred, since the first has unnecessary parenthesis. I took the liberty of trying out Start-Process and it’s parameters in PS 3.0 (on Server 2012) and PS 4.0 (on Windows 8.1).

PowerShell 3.0 (on Server 2012)
PS C:> $PSVersionTable.PSVersion.Major
3
PS C:> $x = Start-Process calc.exe -PassThru
PS C:> $x.ExitCode # While calc.exe is running
PS C:> # Nothing returned, as we’d suspect
PS C:> $x.ExitCode # After calc.exe is closed
PS C:> # Nothing returned --> have to use -Wait in PS 3.0
PS C:>
PS C:>
PS C:> $y = Start-Process calc.exe -PassThru -Wait
PS C:> $y.ExitCode
0
PS C:> Write-Warning -Message “Exit Code: $($y.ExitCode).”
WARNING: Exit Code: 0.

PowerShell 4.0 (on Windows 8.1)
PS C:> $PSVersionTable.PSVersion.Major
4
PS C:> $x = Start-Process calc.exe -PassThru
PS C:> $x.ExitCode # While calc.exe is running
PS C:> # Nothing returned, as we’d suspect
PS C:> $x.ExitCode # After calc.exe is closed
0
PS C:> # Wait is not required in PS 4.0
PS C:> Write-Warning -Message “Exit Code: $($x.ExitCode).”
WARNING: Exit Code: 0.

When i run your code, I do not get an exit code value, until I used the -wait parameter, then all was good.

Thanks

However, I still cannot get my exit code to display.

Here is my script:

$ComputerName = @("$env:COMPUTERNAME")

Foreach ($Computer in $ComputerName)
{
If (Test-Connection -ComputerName $Computer -Count 1 -Quiet)
{
$NewLine

    Write-Output "$Computer is online!"

    $NewLine

    Write-Output "Please wait ..."

    #--------- Check if the SCCM 2012 R2 Client is Installed ---------#

    $CM12R2ClientInstalled = Get-WmiObject -Class Win32_Product -ComputerName $Computer | 
        Where-Object -FilterScript { $_.Name -eq "Configuration Manager Client" -and $_.Version -ge "5.00.7958.1000" }
    
    $CM12ClientService = Get-Service -Name CcmExec -ComputerName $Computer

    If (($CM12R2ClientInstalled -ne $null) -and ($CM12ClientService -ne $null))
    {
        $NewLine

        Write-Output "The $($CM12R2ClientInstalled.Name) $($CM12R2ClientInstalled.Version) is installed on $Computer"
        
        #---------- Check if the FCS Client is Installed ----------#

        $FCSInstalled = Get-WmiObject -Class Win32Reg_AddRemovePrograms -ComputerName $Computer | 
            Where-Object -FilterScript { $_.DisplayName -match "Forefront" }

        Foreach ($FCS in $FCSInstalled)
        {
            If ($FCS)
            {
                $NewLine

                Write-Output "$($FCS.DisplayName) is installed!"

                $NewLine

                Write-Output "Preparing to uninstall $($FCS.DisplayName)"

                #-------- Uninstall the FCS Client ---------#

                $UninstallFCS = Start-Process -FilePath MsiExec -ArgumentList "/X$($FCS.ProdID)" -NoNewWindow -Wait -PassThru

                If ($($UninstallFCS.ExitCode) -eq '0')
                {
                    $NewLine 
    
                    Write-Output "$($FCS.DisplayName) uninstalled successfully!"

                    $NewLine

                    #--------- Check if the SCEP Client is Installed ----------#

                    $SCEPInstalled = Get-WmiObject -Class Win32Reg_AddRemovePrograms -ComputerName $Computer | 
                        Where-Object -FilterScript { $_.DisplayName -eq "System Center Endpoint Protection" }
                    
                    If ($SCEPInstalled -eq $null)
                    {
                        $NewLine

                        Write-Output "The System Center Endpoint Protection client is not installed on $Computer"

                        #---------- Install the SCEP Client ---------#

                        $InstallSCEP = Start-Process -FilePath "C:\Windows\ccmsetup\SCEPInstall.exe" -ArgumentList  '/s', '/q', '/NoSigsUpdateAtInitialExp', '/policy "C:\Windows\CCM\EPAMPolicy.xml"' -NoNewWindow -Wait -PassThru

                        If ($($InstallSCEP.ExitCode) -eq '0')
                        {
                            $NewLine 
    
                            Write-Output "System Center Endpoint Protection installed successfully!"

                            $NewLine
                        }

                        Else
                        {
                            $NewLine
    
                            Write-Warning -Message "System Center Endpoint Protection failed to install on $Computer with exit error: $($InstallSCEP.ExitCode)"

                            $NewLine
                        }
                    }

                    Else
                    {
                        $NewLine

                        Write-Output "The System Center Endpoint Protection client is already installed on $Computer!"

                        $NewLine
                    }
                }

                Else
                {
                    $NewLine
    
                    Write-Warning -Message "$($FCS.DisplayName) failed to uninstall on $Computer with exit error: $($FCS.ExitCode)"

                    $NewLine
                } 
            }

            Else
            {
                $NewLine

                Write-Output "Microsoft Forefront Client Security is not installed on $Computer!"

                $NewLine
            }
        }
    }

    Else 
    {
        $NewLine

        Write-Output "The System Center Configuration Manager 2012 R2 client is not installed on $Computer!"

        $NewLine
    }
}

Else
{
    $NewLine

    Write-Warning -Message "$Computer is not reachable and may be offline!"

    $NewLine
}

}

WOW!!

Okay, I see what my problem was. I should have been using $UninstallFCS.ExitCode, not $FCS.ExitCode on this line:

Write-Warning -Message “$($FCS.DisplayName) failed to uninstall on $Computer with exit error: $($FCS.ExitCode)”

My script is now working as expected.