Simple Powershell scripts to poll for files and run programs

# Polls directory until trigger.run file does not exist
# Run with a single argument for the run environment
# Environments are dev, sit, uat, prd
# command line example:
#
# powershell.exe c:\app\postman\poll_trigger_file.ps1 dev
#
# Modification Log (most recent first)
# ===========================
# Date Author Description
# ======== ===== =========
# 20180531 Simon Vollett Infra 616100: Polls for trigger file and finishes when the file does not exist or it has taken too long to finish.
#
trap [Exception] {
write-error $("TRAPPED: " + $_)
get-date
exit 1
}

Function Get-TimeStamp {
return "[{0:yyyyMMdd HH:mm:ss}]" -f (Get-Date)
}

Function LogMsg {
Param ($Message)
"$(Get-TimeStamp): $Message"; Write-EventLog -LogName Application -Source Application -EntryType Information -EventId 0 -Message "$(Get-TimeStamp): $Message"
}

$runenv = $args[0]
LogMsg("runenv=$runenv")
$script = "poll_trigger_file.ps1"

if (!$runenv) {
$msg = "$script : No run environment parameter presented to power shell script."; LogMsg($msg)
exit 1
}

switch ($runenv) {
'dev' { $runfolder = "c:\app\postman\" + $runenv }
'sit' { $runfolder = "c:\app\postman\" + $runenv }
'uat' { $runfolder = "c:\app\postman\" + $runenv }
'prd' { $runfolder = "c:\app\postman\" + $runenv }
default {
$msg = "$script $runenv : Invalid run environment parameter presented to power shell script: $runenv"; LogMsg("$msg")
exit 1
}
}
LogMsg("runfolder=$runfolder")
$trigger = $runfolder + "\trigger.run"
LogMsg("triggerfile=$trigger")

$poll_duration = 60
$max_poll_attempts = 180
$poll_attempts = 0
$msg = "$script $runenv : Start polling for non-existence of trigger file: $trigger"; LogMsg("$msg")
while ((Test-Path $trigger) -And $poll_attempts -lt $max_poll_attempts) {
Start-Sleep -s $poll_duration
$poll_attempts = $poll_attempts + 1
}

If ($poll_attempts -ge $max_poll_attempts) {
$msg = "$script $runenv : ERROR: Trigger file: $trigger still exists after $max_poll_attempts poll attempts, exiting."; LogMsg("$msg")
exit 1
}
Else {
$msg = "$script $runenv : SUCCESS: Trigger file: $trigger not found, processing can continue."; LogMsg("$msg")
exit 0
}

#######################################################################################################

# PostMan Paf script
# Run with a single argument for the run environment
# Environments are dev, sit, uat, prd
# command line example:
#
# powershell.exe c:\app\postman\run-pafsql.ps1 dev
#
# Modification Log (most recent first)
# ===========================
# Date		    Author		               Description
# ========		=====		               =========
# 20180516      Simon Vollett              Infra 616100 - Bug fixes so that:
#                                                         1) We wait for SQLLoader to finish before exiting this script.
#                                                         2) Script failure causes script to finish WITHOUT deleting trigger file.
#                                                         3) Supply -PassThru option to Start-Process calls so that a process object is returned and can be used to wait for process to finish
#                                                         4) Various extra log entries, input data tests and comments
#
trap [Exception] {
    write-error $("TRAPPED: " + $_)
    get-date
    exit 1
}

Function LogMsg {
    Param ($Message)
    "$Message"; Write-EventLog -LogName Application -Source Application -EntryType Information -EventId 0 -Message $Message
}

$runenv = $args[0]
"runenv=$runenv"
$script = "run-pafsql.ps1"

if (!$runenv) {
    $msg = "$script : No run environment parameter presented to power shell script."; LogMsg($msg)
    exit 1
}

switch ($runenv) {
    'dev' { $runfolder = "c:\app\postman\" + $runenv }
    'sit' { $runfolder = "c:\app\postman\" + $runenv }
    'uat' { $runfolder = "c:\app\postman\" + $runenv }
    'prd' { $runfolder = "c:\app\postman\" + $runenv }
    default {
        $msg = "$script $runenv : Invalid run environment parameter presented to power shell script: $runenv"; LogMsg("$msg")
        exit 1
    }
}
"runfolder=$runfolder"
sl $runfolder

# Due to licence restrictions we may only run one Postman process at any time. As the postman installation services all environments (dev/sit/uat/prd)
# a run for one environment should block a run for other environments so we must check to see if any Postman process is running before creating a new one.
# If a Postman process is already running we should wait for it to finish before we continue. There will be one sqlldr process called after each postman
# process. Note, that there is no technical reason why we cannot run multiple sqlldr processes simultaneously, however in the interests of simplicity
# lets treat the postman and subsequent sqlldr process as a single operation that must be completed before the next postman/sqlldr combo kicks off.
# At this point then, if a postman or sqlldr process is detected, exit this script with success and retain the trigger file, the scheduled job that runs this script
# is polled every 10 mins so we will retest every 10 minutes until postman/sqlldr processes have completed.
$postman_process = (Get-Process | where {$_.ProcessName -eq "postman"})
$sqlldr_process  = (Get-Process | where {$_.ProcessName -eq "sqlldr"})
if ($postman_process -Or $sqlldr_process) {
    $msg = "$script $runenv : A postman or sqlldr process is already running. Exiting."; LogMsg("$msg")
    exit 0
}

# No blocking processes, please continue
$msg = "$script $runenv : No postman or sqlldr process is detected, safe to continue."; LogMsg("$msg")

# Unpack the parameters in the trigger file
$trigger = $runfolder + "\trigger.run"
if (test-path $trigger) {
    $msg = "$script $runenv : trigger file: $trigger exists"; LogMsg("$msg")
    $params = import-csv -Path $trigger
    $pmd = $params.PMD + ".pmd"
    $pmdnoext = $params.PMD
    $dbuser = $params.DBUser
    $passwd = $params.Passwd
    $database = $params.Database
    $env = $pmdnoext.Substring($pmdnoext.Length - 3, 3)
    $pmdNoEnv = $pmdnoext.Substring(1, $pmdnoext.Length - 4)
    
    # clean up old files
    $file = $params.PMD + ".bad"
    if (test-path $file){remove-item $file}
    $file = $params.PMD + ".log"
    $newFile = $params.PMD + "." + (Get-Date -format yyyyMMddHHmm) + ".log"
    if (test-path $file){move-item $file $newFile}
    $file = $pmdNoEnv + "Rpt" + $env + ".txt"
    $newFile = $file + "." + (Get-Date -format yyyyMMddHHmm) + ".txt"
    if (test-path $file){move-item $file $newFile}
    $file = $params.PMD + ".txt"
    if (test-path $file){remove-item $file}
    $file = $params.PMD + ".str"
    if (test-path $file){remove-item $file}

    $msg = "$script $runenv :Trigger file = $trigger `n Param file = $pmd `n DB User = $dbuser `n Password = $passwd `n Database = $database"; LogMsg("$msg")

    $msg = "$script $runenv :Start-Process -filepath c:\dms\postman\postman.exe -argumentlist  /x $runfolder\$pmd -PassThru"; LogMsg("$msg")
    $postman_process = Start-Process -filepath "c:\dms\postman\postman.exe" -argumentlist " /x $runfolder\$pmd" -PassThru
    $msg = "$script $runenv :Waiting for Postman process to complete..."; LogMsg("$msg")
    Wait-Process -InputObject $postman_process
    $msg = "$script $runenv :Postman process finished."; LogMsg("$msg")

    $postman_process_exit_code = $postman_process.ExitCode
    $msg = "$script $runenv :postman process exit code is: $postman_process_exit_code"; LogMsg("$msg")
    if ($postman_process.ExitCode -ne 0)  {
        $msg = "$script $runenv :PostMan process failed."; LogMsg("$msg")
        # DO NOT REMOVE THE TRIGGER FILE IN EVENT OF FAILURE, OTHERWISE REST OF CTRL-M PROCESS WILL CONTINUE ASSUMING SUCCESS
        exit 1
    } 
    $msg = "$script $runenv :PostMan process completed succesfully."; LogMsg("$msg")

    $sqlldrargs = "$dbuser/$passwd@$database control=$runfolder\$pmdnoext.ctl data=$runfolder\$pmdnoext.txt log=$runfolder\$pmdnoext.log"
    $msg = "$script $runenv :SQLLDR process starting with args: ($sqlldrargs)"; LogMsg("$msg")
    $sqlldr_process = Start-Process -filepath "C:\app\oracle\product\11.2.0\client_1\BIN\sqlldr.exe" -argumentlist " $sqlldrargs" -PassThru
    $msg = "$script $runenv :Waiting for sqlldr process to complete..."; LogMsg("$msg")
    Wait-Process -InputObject $sqlldr_process
    $msg = "$script $runenv :sqlldr process finished."; LogMsg("$msg")

    if ($sqlldr_process.ExitCode -ne 0) {
        $msg = "$script $runenv :sqlldr process failed."; LogMsg("$msg")
        # DO NOT REMOVE THE TRIGGER FILE IN EVENT OF FAILURE, OTHERWISE REST OF CTRL-M PROCESS WILL CONTINUE ASSUMING SUCCESS
        exit 1
    } 
    $msg = "$script $runenv :sqlldr process completed succesfully."; LogMsg("$msg")

    # Only remove trigger file upon successful completion
    $msg = "$script $runenv :Entire process completed succesfully, removing trigger file."; LogMsg("$msg")
    remove-item $trigger
    exit 0
}
Else {
    $msg = "$script $runenv : trigger file: $trigger does not exist, nothing to run. Exiting."; LogMsg("$msg")
    exit 0
}