Overview of Run Script Actions

You can run the scripts with pre- and post-actions during the patch deployment job execution. Through the run scripts, you can check for a particular condition to determine whether patching should execute or continue. For example, if you want to take a snapshot of the asset and then patch it, if the snapshot is acquired successfully. If the snapshot fails, there is no way to exit or cancel the patch job. Here, you can add a script as part of the pre-action, 

The following are the exit codes for Run Script actions: 

Exit Code 0 and 1

Exit Code 0: This code indicates that the script has passed successfully. Further, depending on the status of other scripts and patches, the job displays Completed or Completed with Failure status. 

Exit Code 1: Indicates that the script has failed and the patch job appears with Completed with Failure status. If applicable, the patch is installed on the target machine.

You can use the exit codes individually or in combination in your scripts as per your requirement. 

The following example demonstrates the use of both exit code 0 and 1. This sample script checks if the software is installed or not. A return code of 0 indicates that a new version of the software can be installed, while a return code of 1 indicates that installation is not required, as the earlier version is already available on the system.

Example: To detect if Notepad++ version 8.1.2 can be installedExample: To detect if Notepad++ version 8.1.2 can be installed

Exit Code 0 and 1

# Sample pre-detection script for Qualys Patch Manager       *
#     This sample script demonstrates detection of installed  *
#     software. It returns 0 if software can be installed    *
#     and returns 1 if installation is not required          *
#                                                            *
#       Return Code                                          *
#        0 - success                                         *
#        1 - failure                                         *
#*************************************************************
# required parameter
[string]$SoftwareName = "notepad++*"
[string]$SoftwareVersion = "8.1.2"
# Print OS info for asset information and troubleshooting
Write-Host "Gathering OS Information..."
$osInfo = Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, ServicePackMajorVersion, OSArchitecture, CSName
$properties = @{
    Caption                 = $osInfo.Caption
    Version                 = $osInfo.Version
    ServicePackMajorVersion = $osInfo.ServicePackMajorVersion
    OSArchitecture          = $osInfo.OSArchitecture
    HostName                = $osInfo.CSNAme
}
$obj = New-Object -TypeName PSObject -Property $properties
Write-Output $obj
Write-Host "Looking for package installation...`n"
# Check install key in both wow64 and normal path. Application can be either 32-bit or 64-bit.
$32bit = Get-ItemProperty HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
$64bit = Get-ItemProperty HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*
$programs = $32bit + $64bit
$packageFound = $false
foreach ($program in $programs) {
    $program = Write-Output $program | Where-Object Displayname -like $SoftwareName
    if ($null -ne $program.DisplayName) {
        $LastModified = (Get-Item $program.uninstallstring).lastwritetime
        $properties = @{
            ProgramName     = $program.DisplayName
            Publisher       = $program.Publisher
            Version         = $program.DisplayVersion
            UninstallString = $program.UninstallString
            LastModified    = $LastModified
        }
        $package = New-Object -TypeName PSObject -Property $properties
        Write-Output $package
        $packageFound = $true
        break;
    }
}
if ($packageFound -eq $false) {
    Write-Host "No installed package found"
    # Package needs to be isntalled
    exit 0
}
Write-Host "Checking installed software version..."
[System.Version] $installedVersion = $package.Version
[System.Version] $ExpectedVersion = $SoftwareVersion
if ($installedVersion -lt $ExpectedVersion) {
    Write-Host "Installed software is older than required version. Patch upgrade needed."
    exit 0
}
else {
    Write-Host "Installed software is up to date."
    exit 1
}>

Exit Code 10 and 11

Exit Code 10: Indicates that the script executed successfully with a system reboot. After execution, agent triggers a system restart as per the job configuration.

Exit Code 11: Indicates that the script execution failed or any errors encoutered while script execution, along with the system reboot in any case.

The following script is an example that returns both exit codes 10 and 11. This sample script demonstrates the installation of software. If the code returned is 10, the software is installed successfully, and if the code returned is 11, the installation fails.

You can use the exit codes individually or in combination in your scripts as per your requirement. 

The following script is an example of both exit codes 10 and 11. This sample script demonstrates the installation of software. If the code returned is 0, the software is installed successfully, and if the code returned is 1, the installation fails.

Example: To install Notepad++ version 8.1.2Example: To install Notepad++ version 8.1.2

Exit Code 10 and 11

#*************************************************************
# Sample install script for Qualys Patch Manager             *
#     This sample script demonstrate installation of         *
#     software. It returns 0 if software is installed        *
#     successfully and returns 1 if installation fails.      *
#       Return Code                                          *
#        0 - success                                         *
#        1 - failure                                         *
#*************************************************************
[string]$PackageName = "npp.8.1.2.Installer.x64.exe"
[string]$InstallerLocation = $Env:ProgramData + "\Qualys\QualysAgent\PatchManagement\PatchDownloads\"
[string]$Arguments = "/S"
#set this 1 if reboot is required after package installation
[int]$RebootFlag = 1
function Get-QualysScriptReturn {
    param (
        [ValidateRange(0, 1)]
        [Int]
        $Success_Code,
       [ValidateRange(0, 1)]
        [Int]
        $RebootFlag
    )
    return $Success_Code + ($RebootFlag * 10)
}
function Start-Program {
    param (
        [ValidateNotNullOrEmpty()]
        [string]
        $ProgramFullPath,
        [Parameter(Mandatory = $false)]
        [string]
        $Arguments        
    )   
    try {   
        $pinfo = New-Object System.Diagnostics.ProcessStartInfo
        $pinfo.FileName = $ProgramFullPath
        $pinfo.RedirectStandardError = $true
        $pinfo.RedirectStandardOutput = $true
        $pinfo.UseShellExecute = $false
    
        if ($null -ne $Arguments) {
            $pinfo.Arguments = $Arguments
        }     
        $pinfo.WorkingDirectory = Get-Location
        $p = New-Object System.Diagnostics.Process
        $p.StartInfo = $pinfo
        $p.Start() | Out-Null
        $p.WaitForExit()
        $stdout = $p.StandardOutput.ReadToEnd()
        $stderr = $p.StandardError.ReadToEnd()
   
        Write-Host "Process Stdout:`n $stdout"
        Write-Host "Process Stderr:`n $stderr"
        Write-Host "exit code: "$p.ExitCode
        return $p.ExitCode
    }
    catch {
        Write-Host -ForegroundColor DarkRed "Failed to execute program" $_.Exception.Message
        return 1
    }
}
Write-Host "Running install script to install -"$PackageName
Write-Host "Looking package installer..."
$InstallerFullPath = $InstallerLocation + $PackageName
if (Test-Path $InstallerFullPath) {
    Write-Host "Found installer at "$InstallerFullPath
}
else {
    Write-Host "Installer does not exist at "$InstallerFullPath
    exit 1;
}
Write-Host "Launching installer..."
$ReturnCode = Start-Program $InstallerFullPath $Arguments
if ($ReturnCode -eq 0) {
    Write-Host -ForegroundColor Green "Installation successfull..."
    exit Get-QualysScriptReturn 0 $RebootFlag;
}
else {
    Write-Host -ForegroundColor DarkRed "Installation failed. See output for more details."
    exit 1
}

Exit Code 12

This code indicates that the script execution failed and serves as an abort signal for the job execution. For example, suppose a job has five pre-actions configured, and the first pre-action passes successfully, but the second pre-action fails with exit code 12. Then the remaining three pre-actions/post-actions, if any, are not executed and marked as Skipped with exit code 101. As a result, the patches in the job are skipped and not installed. The patch job status appears as Completed with Failure.

The following script is an example that returns exit code 12. The Healthcare providers often use Electronic Medical Record (EMR) systems that run regular backups. If patching starts during these backup windows, it can interfere with data integrity and system performance. So avoid this issue, you can configure a pre-action in the patch job, that checks if the backup flag is On, the script returns exit code 12 and the pre-action executes and patch job execution is aborted.  

Example: EMR Servers during Backup WindowsExample: EMR Servers during Backup Windows

The scheduled tasks update the following status file to indicate backup activity. 

# Before backup
Set-Content -Path "C:\AppStatus\backup.status" -Value "BackupMode=ON"
# After backup
Set-Content -Path "C:\AppStatus\backup.status" -Value "BackupMode=OFF"

The pre-action PowerShell script checks this status:

# pre_patch_check.ps1

$StatusFile = "C:\AppStatus\backup.status"
if (-Not (Test-Path $StatusFile)) {
    Write-Output "Status file not found – assuming unsafe to patch."
    exit 12
}

$StatusLine = Get-Content $StatusFile | Where-Object { $_ -match "BackupMode" }

if ($StatusLine -match "BackupMode\s*=\s*ON") {
    Write-Output "Server is in Backup Mode – canceling patch job."
    exit 12
} else {
    Write-Output "No backup in progress – safe to patch."
    exit 0
}

Exit Code 101

This code implies that the script execution is skipped. This exit code is used between Patch Management application and Cloud Agent to indicate that an earlier pre-action returned exit code 12. As a result, the subsequent pre-actions are marked as Skipped with exit code 101. 

If a job has five pre-actions configured and the second pre-action is skipped with an exit code of 101, then the consecutive three pre-actions continue to execute. The patch job status is Completed with Failure, since exit code 101 is generated only after a pre-action fails with exit code 12.

As the system handles this exit code, you do not have to set it exit code in your script.