Basics of Writing your own Blueprint

The Blueprints architecture is open and allows you to deploy custom software, set custom settings, and do other custom work on PC Assets.

A few things to consider

  1. There are a TON of Blueprints already written. Make sure to search the Public Library to see if the blueprint you want already exists.
  2. Blueprints should be relatively atomic. They should do one specific thing. If you need multiple unrelated things done, write a blueprint for each thing instead of one "master blueprint".
  3. The existing Blueprints are all open. You can go review the PowerShell source code of all of the existing Blueprints - this can make writing your own blueprint much simpler!

Basic Details

The basic details of a Blueprint are things like Name, Description and Notes. These basic details help people understand the Blueprints intent.

Blueprints come in several main parts

The four main parts of a Blueprint are:

  1. Properties - a configurable block of variables that can be set at the time a Modifier is built

  2. Validator - a Powershell script used to determine if the Blueprint work is done or not

  3. Worker - a Powershell script used to actually do the work of the Blueprint

  4. Payload - an optional file that will be downloaded and available to the Worker during execution

Payload Details

Many blueprints have a Payload. A payload is a downloadable file (usually an archive or installer) that contains necessary files to do the Blueprint’s work. A payload may be an MSI, EXE, ZIP, or any file type, but must be a single downloadable file at a canonical and unchanging URL that does not require any credentials to access.

The payload details are made up of three elements:

  1. Payload Filename - the name that the Payload URL file will be saved to on the local machine. This is useful in the script, especially if the URL does not present a useful or obvious name. This Payload Filename can be used in the Worker to reference the Payload File for work (such as installing an MSI or extracting a .ZIP). Examples might include payload.zip, chrome.msi, or hp_driver.exe.

  2. Payload URL - a complete URL that is generically and correctly accessible via HTTP or HTTPS, including the protocol string. Examples include http://some.location.to/afile.zip and https://drive.google.com/a/garbage/download-link

  3. Payload Checksum - the expected SHA2 checksum of the Payload Filename if it has been successfully downloaded from the Payload URL. This is a sanity and security check. If the SHA2 entered in the Payload Checksum does not match the runtime calculated SHA2 of the downloaded Payload URL, the Worker will fail to execute and Blueprint will not work. You can calculate the SHA2 of a file using any number of tools, including via Powershell and also via this free Windows 10 Store tool.

SHA2 is also known by the name SHA-256.

Make sure to enter the correct Checksum, or computers will never successfully validate the payload.

Predefined Constants

There are several predefined constants available for use in Validators and Workers.

 

Predefined Variable

Variable Set To

Useful For

$CLOUDSET_NAME

Name of the ASSET as configured in the K12Panel Web UI. Example value could be “ADMIN-DESK-01”

Useful if you need a Worker script to know the Web UI name that has been configured for an ASSET in the cloud.

$CLOUDSET_CHECKEDOUTUSER

Email address of the USER that the asset is checked out to, or ““ if no user.

If you need a handle on the email address to do things like promote the user to admin (via a worker) or check to see if the currently-logged-in-user is the responsible party.

$VALIDATED_WORK_DONE

Internal and understood by Agent

Responding from a Validator

$VALIDATED_WORK_NEEDED

Internal and understood by Agent

Responding from a Validator

$VALIDATED_WORK_INDETERMINATE

Internal and understood by Agent

Responding from a Validator

$VALIDATED_RUN_ALWAYS

Internal and understood by Agent

Responding from a Validator

$BLUEPRINT_VERSION

Obtained from blueprint’s version field.

Manipulating downloaded file within blueprint

$BLUEPRINT_FILENAME

Obtained from blueprint’s filename field.

Verifying installed version against blueprint’s version within validator.

$BLUEPRINT_CHECKSUM

Obtained from blueprint’s checksum field name.

Undetermined but here for potential future use.

 

Configurable Properties

Properties are configurable variables that the Blueprint exposes to the Modifier. You can enter any variables here that should be customizable on a Modifier-by-Modifier instance.

Only expose variables that may need to be customized by the Modifier. DO NOT expose variables as properties that are Blueprint-specific but don’t change Modifier-to-Modifier.

Properties will take the form of $key=value and $key="String Value".

Comments are prepended with a # and should include a description of the property.

Examples properties block:

# Location of the printer
$printerlocation="Customer Service Department"
# Name of the printer that users will see in in shared printer dialog
$printersharename="HP Enterprise M553"
# Name of the printer that users will see in their print dialog
$printercommonname="HP Enterprise M553"
# Port name that the printer will use. Use TCP: or UPNP:
$printerportname="TCP_10.0.0.60"
# Printer's IP Address
$PrinterIPAddress="10.0.0.60"

Note that the VALUES you provide in the blueprint are fully customizable on a Modifier-by-Modifier basis. DO NOT expose variables that should not be exposed to the Modifier. Adding unnecessary variables to the Properties block adds unneeded complexity and opportunities for a Modifier configuration to inadvertently break the Blueprint.

DO NOT add script variables as Properties unless they should be exposed to the Modifier for change.

Variables that should not be exposed as Properties include things like specific instructions to execute from within the Payload. Any variable such as this should be hardcoded into the Validator and/or the Worker (wherever it is used) since it should not be changed by the Modifier.

Validator

The Validator is a PowerShell script that is used for two different purposes. This one script is very important in determining how much work that a computer needs to do (for both processing and network bandwidth).

When a Blueprint is used to make a Modifier, the Modifier needs to know whether it has completed the job. The Validator satisfies this requirement. A Validator is used for two things:

  1. The Validator determines if a worker script needs to run (pre-validation).

  2. After a worker has finished, the Validator determines if the worker completed the task successfully (post-validation).

When a Validator is executed, it should produce exactly ONE output. The output can be any of the following:

  1. $VALIDATED_WORK_DONE - the work has already been completed and therefore the worker does not need to run.

  2. $VALIDATED_WORK_NEEDED - the work needs to be run and so the worker will be executed.

  3. $VALIDATED_WORK_INDETERMINATE (the default) - the work cannot be determined and therefore the worker will be skipped (to avoid unnecessary work).

  4. $VALIDATED_RUN_ALWAYS - the worker will be executed every time the system polls. Be careful: this state can lead to “overwork”.

If the Validator’s output cannot be determined (because the output is unrecognized or the Validator is blank), the Validator is considered to have returned $VALIDATED_WORK_INDETERMINATE.

Be careful and make sure to avoid all output to the console, or any non-squelched error messages, or the agent will interpret this as invalid and will return $VALIDATED_WORK_INDETERMINATE. This is probably the most common error of $VALIDATED_WORK_INDETERMINATE being returned.

Write validators carefully! An indiscernible response will be interpreted as a $VALIDATED_WORK_INDETERMINATE response. Either an indiscernible response or an intentional $VALIDATED_WORK_INDETERMINATE response will result in the blueprint worker not being executed.

In your Validator script, simply Write-Output the appropriate output for different tested cases. For example, a Blueprint to install a network printer might check the printer ports to see if it already exists. A different Blueprint to install a piece of software might contain a Validator that checks the registry for a particular key and value to determine if the software has already been installed.

Here’s a sample Validator to check the registry to see if a piece of software has been installed.

Try {
  $currentversion=(Get-ItemProperty -ErrorAction Stop -Path 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\FastStone Image Viewer' -Name DisplayVersion).DisplayVersion
} Catch {
  # something went wrong - let's exit as indeterminate
  Write-Output $VALIDATED_WORK_INDETERMINATE; 
  break
}
Try {
  $installversion=New-Object System.version($installversion) -ErrorAction Stop
} Catch {
  # something went wrong - let's exit as indeterminate
  Write-Output $VALIDATED_WORK_INDETERMINATE; 
  break
}
$currentversion=New-Object System.version($currentversion)

# We have some version info, let's determine if we should do some work
if ($currentversion -ge "$installversion") {Write-Output $VALIDATED_WORK_DONE}
elseif ($currentversion -lt "installversion") {Write-Output $VALIDATED_WORK_NEEDED}
else {Write-Output $VALIDATED_WORK_INDETERMINATE} 

Worker

The Worker PowerShell does the actual work of the Blueprint. It is the reason the Blueprint was made. As a PowerShell script running with Local Administrative access, Workers can install software, change configurations, delete files, and perform all kinds of useful work.

Workers have access to the Preconfigured Properties as well as the Configurable Properties as defined in the Blueprint. Properties are NOT required as some Blueprint Workers do not need Properties to carry out their work. Workers also have access to the Payload file.

Workers run in their own temporary folder directory space. The working directory of the Worker execution is where the Payload file will be downloaded. After execution, a Worker’s temporary directory, along with all content therein, is deleted.

When completed, a Worker’s STDOUT will be the report back to the cloud for the given execution. Workers are not required to produce any useful output from their script. Any output from the Worker script will be reported back to the cloud and be made available in reports for the ASSET. This information is available to anyone who has access to view the ASSET (Reporter or Manager) and therefore should not contain any information that these roles should not see.

The report from a WORKER must be 2000 characters or less. Any output report over 2000 characters will be truncated to 2000 characters.

In this example, GoogleChromeStandaloneEnterprise64.msi is used as the Payload filename:

 msiexec /i GoogleChromeStandaloneEnterprise64.msi /qn

Asset Connectors - a Special Kind of Worker

Any Blueprint can turn itself into an Asset Connector by having the Worker produce a special kind of output in the report.

Any Blueprint Report can be turned into an Asset Connector.

 

If a Worker outputs the following line, the worker’s report will be interpreted by Panel as an Asset Connector:

##ASSETCONNECTOR##[<connector name>][<url>]

EVERY LINE in a Worker Report that begins with ##ASSETCONNECTOR## will be parsed as an Asset Connector.

Here is a short example of how an Asset Connector can be generated (note: this would be the WORKER code in your blueprint):

Add-Type -AssemblyName System.Web
$CONNECTOR_NAME = "Search Hardware Info"
$MANUFACTURER = (Get-WMIObject –class Win32_ComputerSystem).Manufacturer
$MODEL = (Get-WMIObject –class Win32_ComputerSystem).Model
$MAKEMODEL = [System.Web.HttpUtility]::UrlEncode($MANUFACTURER + " " + $MODEL)
$URL = "https://www.google.com/search?q=" + $MAKEMODEL

WRITE-OUTPUT "##ASSETCONNECTOR##[$CONNECTOR_NAME][$URL]" 

A Cautionary Word on Validators and Workers

Validators and Workers run as an elevated service with Local Administration rights and therefore can do substantial harm to the ASSET. This is necessary, as many Modifiers require elevated permissions to install software and change configurations.

WARNING: Modifiers run as Local Administrator. With great power, comes great responsibility.

 

Validators and Workers run as 32bit PowerShell scripts. For technical details, they are interpreted by "C:\Windows\sysnative\windowsPowerShell\v1.0\powershell.exe".