I haven't found a root cause solution to the issue. But you aren't the only person to tell me that exit() doesn't always work. I do have a work-around now however.
I had to enlist my husband, a real programmer, on this. Now I owe him a banana cream pie.
This little Powershell program actually solves another JMP-specific problem that may be of interest to somebody. One of my scripts wants to open up an html address and get tabular information from there. BUT, the location is password protected. I could not find a way for JMP to pass my credentials to a web site in JSL, it just fails. However, it just works without the credentials if I have recently opened the site and entered the credentials in internet explorer. JMP seems to use the IE cookies. Anyway, that is the whole reason this program has a command line option called "loginpage". It's superfluous to the JMP exiting issue but it optionally opens IE at a certain web page, passes the hardcoded credentials if needed and then closes IE.
"waitforlog" IS relevant. The way this scheme works is that when the JMP script runs it posts a certain log file at the end when it's done. unlike exit() this seems to occur reliably. This program deletes any previous version of that file, opens JMP, run the script then waits for the file to reappear. When it does it knows it can kill JMP and it has worked out the process id of the instance of JMP that it opened and kills just that instance.
I had an earlier workaround using taskkill to periodically kill all open JMPs but it seems that it's not easy in a simple batch file to know what particular instance you just started so you can kill that specific instance with taskkill. Since I have many scheduled jobs and also want to use this machine to open JMP and do some manual work while the jobs run in the background it wasn't a very good solution to just be killing off JMP instances willy nilly. Powershell seems to have a special power to identify a specific instance of a program you just started.
Anyway this Powershell solution is working for me now, for both issues....
Here's an example of the syntax in a .bat file running it....(with the last two things optional)
powershell "&"C:\SCHEDULED\runJMPscript.ps1" -script 'C:\SCHEDULED\yourJSLscript.JSL' -waitforlog -loginpage
Like I said, I didn't write this myself and the login part is based on something I found in another forum about starting IE and getting it to do more things that were possible just in a simple batch file. Still, it's fairly comprehensible. Note that the location of JMP is hardcoded in there and you'd need to alter your script to make it create the log file with the name that's the script name with .log extension.
#*****************************************************************************
#
# RunJmpScript.ps1 - PowerShell script used to run a Jmp command
#
# Usage:
#
# powershell.exe RunJmpScript.ps1 [-loginpage] -script scriptname [-waitforlog]
#
#*****************************************************************************
param ([switch]$loginpage, [string]$script = "unknown", [switch]$waitforlog)
#
# Check the command-line options for errors
#
Write-Host "loginpage: $loginpage"
Write-Host "script: $script"
Write-Host "waitforlog: $waitforlog"
$scriptexists = (Test-Path $script -PathType Leaf)
if (!($scriptexists))
{
Write-Host "Error: Must specify the location of a Jmp script file using -script <path>"
exit 1
}
#
# Retrieve the login page info if needed
#
if ($loginpage)
{
# Define some variables that will change based on your configuration
# I recommend storing these an XML file and reading them in at execution
# time, but for the sake of this exercise i'm keeping it simple.
$username = "fill in username here"
$password = "fill in pwd here"
$url = "fill in URL here"
# Create the IE com object
$ie = new-object -com InternetExplorer.Application
# Navigate to the login page
$ie.navigate($url)
# Wait for the page to finish loading
do {sleep 1} until (-not ($ie.Busy))
#$ie.visible = $true #Uncomment this for debugging
# Assign the DOM to the $doc variable
$doc = $ie.document
# Fill in login info
try {
# Find the username field and set the value to that of our variable
$usernameField = $doc.getElementById('USER')
$usernameField.value = $username
# Find the password field and set the value to that of the result
# of a call to the get-password function with the paramter defined at top
$passwordField = $doc.getElementById('PASSWORD')
$passwordField.value = $password
# Find and click the submit button
$submitButton = $doc.getElementById('Submit')
$submitButton.click()
# Wait until login is complete
do {sleep 1} until (-not ($ie.Busy))
} catch {$null}
# Wait for the page to finish loading
do {sleep 1} until (-not ($ie.Busy))
# Close IE
$ie.quit()
}
#
# Remove the current log file if we are going to monitor it
#
$logfile = $script + ".log"
if ($waitforlog)
{
if (Test-Path $logfile -PathType Leaf)
{
Write-Host "Removing existing log file $logfile"
Remove-Item $logfile
}
}
#
# Execute the Jmp command, using the specified script
#
$exe = "C:\Program Files\SAS\JMP\9\jmp.exe"
$exeargs = "`"" + $script + "`""
Write-Host "Starting process $exe with argument: $exeargs"
$jmp = start-process $exe "$exeargs" -passthru
#
# See if we need to wait for this to write out a log file.
#
if ($waitforlog)
{
$logfile = $script + ".log"
$idval = $jmp.Id
Write-Host "Waiting for log file $logfile from process $idval"
while (!(Test-Path $Logfile -PathType Leaf))
{
# If the process exits, we can just quit now
if ($jmp.HasExited)
{
exit 0
}
# Otherwise, wait for a bit, and try again
Start-Sleep -s 1
}
Write-Host "Stopping external program $idval"
Stop-Process $idval
}
exit 0