0

I am unable to stop a PowerShell script if the batch scripts which are being called by this PowerShell scripts throws an error.

bat 1:

PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& '%PowerShellScriptPath%\CallInstall.ps1'";

CallInstall.ps1 calls few batch files and vbs files, in the event of failure of a prerequisite the bat2 calls a vbs based message box to display an error. Ideally at this time the execution should stop and the bat1 should start the remaining process but in my case CallInstall.ps1 still executes all the batch and vbs scripts before going back to bat1.

CallInstall.ps1:

[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
[System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null

Set-Location $PSScriptRoot

$ScriptsHome = Get-Item '.\ScriptInstall\*'

#Define Form
$Form = New-Object System.Windows.Forms.Form
$Form.width = 1000
$Form.height = 200
$Form.Text = "** Installation in Progress**"
$Form.Font = New-Object System.Drawing.Font("Times New Roman" ,12, [System.Drawing.FontStyle]::Regular)
$Form.MinimizeBox = $False
$Form.MaximizeBox = $False
$Form.WindowState = "Normal"
$Form.StartPosition = "CenterScreen"
$Form.Opacity = .8
$Form.BackColor = "Gray"

# Init ProgressBar
$ProgressBar = New-Object System.Windows.Forms.ProgressBar
$ProgressBar.Maximum = $ScriptsHome.Count
$ProgressBar.Minimum = 0
$ProgressBar.Location = new-object System.Drawing.Size(10,70)
$ProgressBar.size = new-object System.Drawing.Size(967,10)
$Form.Controls.Add($ProgressBar)
#$Form.Controls.Add($MessagesLabel)

#Running Script Name
#$Label = New-Object System.Windows.Forms.Label
#$Label.AutoSize = $true
#$Label.Location = New-Object System.Drawing.Point(10,50) 
#$Form.Controls.Add($Label)

#Define Array messages
#Array
$Messages = @("Message 1",
              "Message 2",
              "Message 3",
              "Message 4",
              "Message 5",
            )
$MessagesLabel = New-Object System.Windows.Forms.Label
$MessagesLabel.AutoSize = $true
$MessagesLabel.Location = New-Object System.Drawing.Point(10,50)
$Form.Controls.Add($MessagesLabel)

# Add_Shown action    
$ShownFormAction = {
    $Form.Activate()

    foreach ($script in $ScriptsHome) {
        $ProgressBar.Increment(1)
        $MessagesLabel.Text = $Messages[$ProgressBar.Value - 1]
        Start-Process $script.FullName -Wait -WindowStyle Hidden
    }
    $Form.Dispose()
}
$Form.Add_Shown($ShownFormAction)

# Show Form
$Form.ShowDialog()

#Create Logs
Invoke-Expression -Command .\LogScript.ps1

Inside the ScriptInstall folder there are 10 batch and vbs scripts on one of the batch script:

:error
cscript %base_dir%\fail.vbs > %Log%
:match
findstr /I /c:"xxxx" c:\match.txt
if %errorlevel% == 0 (
    goto nextStep
) else (
    goto ErrorCheck
)

and in fail.vbs:

Dim vbCrLf : vbCrLf = Chr(13) & Chr(10) 
Set WshShell = WScript.CreateObject("WScript.Shell")
MsgBox "Installation Fail !!!" & vbCrLf & "Message1" & vbCrLf & "Click OK to Exit" , 16, "Fail"

Ideally upon pressing ok on this fail.vbs box CallInstall.ps1 should not proceed with rest of the scripts in ScriptInstall folder but it does otherwise. It continues with remaining scripts in ScriptInstall folder and then returns the execution to bat1.

1
  • If possible, it will be much easier to maintain the logic and stop/continue steps, if you move as much of the logic into one script type, instead of calling PowerShell from bat, then calling other batch files to call vbscript. In your instance 'as-is', with no OK/cancel, you need to return a non-zero error code from your vbscript, like this: WScript.Quit 1 Commented Sep 8, 2016 at 11:12

4 Answers 4

2

You could work with exitcodes and change your scripts like this:

The PowerShell Script:

foreach ($script in $ScriptsHome) {
    $ProgressBar.Increment(1)
    $MessagesLabel.Text = $Messages[$ProgressBar.Value - 1]
    $process = Start-Process $script.FullName -Wait -WindowStyle Hidden -passthru
    if($process.ExitCode -ne 0){break}
}

The Batch Script:

:error
cscript %base_dir%\fail.vbs > %Log%
Exit /b 1
Sign up to request clarification or add additional context in comments.

7 Comments

i tried this modification as well with echo yes > c:\batchpass.txt in the first batch file but the powershell exits after calling the first script.
I am not sure what your question is. But I assume the powershell exits because you batch file did not exit with 0. Could you post the complete code of that batch file? What happens if you just execute your batch file. Does it what it is supposed to do?
The batch file has net stop "Acronis VSS Provider" net stop "COM+ System Application"
If you run you batch script on the command line on its own, not triggered by the powershell script. What happens then? and what is the %errorlevel% of it? if %errorlevel% is not 0, the problem is in your batch script and not with the modified powershell script.
Yes the errorlevel is non 0 but the problem is i am creating these scripts by keeping in mind that some server may have some services and some may not have those same services , either way i have to include all the possible windows services before using the final installation script.
|
1

Exit will quit from Powershell. So, if you are running interactively, this is unexpected. Use Return instead, to stop executing the remaining lines of codes:

For ($i=0; $i -lt 5; $i++){
    Write-Host
    $input = $(Read-Host "Enter a number between 1 and 5")

    If ($input -In (1..5)){
        $MyIntNum = $input -as [int]
        Break
    }ElseIf($input -eq '0'){
        Return 
    }
    Else{
        Write-Host 'Please try again ...'
    }
}

Write-Host
Write-Host "You entered $input"

Output when you enter any number other than 0:

Enter a number between 1 and 5: 9
Please try again ...

Enter a number between 1 and 5: 7
Please try again ...

Enter a number between 1 and 5: 4

You entered 4

Result when you enter 0:

Enter a number between 1 and 5: 0

Comments

0

The general approach is to exit from the batch scripts with a non-zero exit code in case of an error and check the exit status in the PowerShell code, as @A189198 already showed in his answer.

I would, however, drop the VBScript entirely (you can display message boxes from PowerShell too), and capturing a Process object also isn't required since PowerShell automatically provides the information via the automatic variable $LastExitCode.

Change the error handling in your batch code to something like this:

if %errorlevel% neq 0 exit /b 1

and change this foreach loop:

foreach ($script in $ScriptsHome) {
    $ProgressBar.Increment(1)
    $MessagesLabel.Text = $Messages[$ProgressBar.Value - 1]
    Start-Process $script.FullName -Wait -WindowStyle Hidden
}
$Form.Dispose()

to this:

foreach ($script in $ScriptsHome) {
    $ProgressBar.Increment(1)
    $MessagesLabel.Text = $Messages[$ProgressBar.Value - 1]
    Start-Process $script.FullName -Wait -WindowStyle Hidden
    if ($LastExitCode -ne 0) {
        [Windows.Forms.MessageBox]::Show("Installation Fail!`nMessage1`nClick OK to Exit", 'Fail', 0, 'Error')
        break
    }
}
$Form.Dispose()

6 Comments

i apologize for the delayed response. I tried this modification but only 1st script executes and then the powershell exits after calling the message box. The first batch script contains echo yes > c:\batchpass.txt I don't understand what is it that i am not doing correctly.
Apparently your first batch script already returns a non-zero exit code, so the PowerShell script terminates as you requested. If the batch script contains nothing but the echo statement this might be caused by an error when writing to the output file. Otherwise you need to show the code of your batch file.
Yes you are absolutely correct. In my first batch file i am using net stop command to stop various services. Some of these services are generic windows services which i am trying to stop, but eventually sometimes it happens that some service which is already stopped gives an error upon execution of script. Any method to deal with this.
Please post a new question for that.
I am not asking for how to deal with the error which occurs if the service i am trying to stop is already stopped. What i wanted to say was, that this might be a problem due to which the $LastExitCode terminates the powershell script. How and what to modify in the poweshell script keeping this in mind?
|
0

Thanks for every one for showing me the way to do it.I have found the solution. I have changed the foreach loop in the powershell script from

foreach ($script in $ScriptsHome) {
    $ProgressBar.Increment(1)
    $MessagesLabel.Text = $Messages[$ProgressBar.Value - 1]
    Start-Process $script.FullName -Wait -WindowStyle Hidden
}
$Form.Dispose()

to

foreach ($script in $ScriptsHome) {
        $ProgressBar.Increment(1)
        $MessagesLabel.Text = $Messages[$ProgressBar.Value - 1]
        #$Label.Text     = "$($script.Name)"   
        Start-Process $script.FullName -Wait -WindowStyle Hidden

        if (Select-String -Path C:\exitloop.txt "fail") 
        {
         break 
        } else {continue
        }
        }
    $Form.Dispose()

and in the ScriptInstall folder where there are 10 batch and vbs scripts in the batch scripts i have changed the code to.

:error
cscript %base_dir%\fail.vbs > %Log%
echo fail > c:\exitloop.txt
exit
:match
findstr /I /c:"xxxx" c:\match.txt
if %errorlevel% == 0 (
    goto nextStep
) else (
    goto ErrorCheck
)

so whenever there is a condition failure in the batch file the batch file will generate a txt file with text "fail" this happens before termination of that particular batch file. Immediately after that the control will go back to the powershell script which will check if "fail" exist in c:\exitloop.txt if yes this will stop the execution of the powershell script itself else it will continue calling the batch and vbs files. Thanks

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.