Dynamically populate Custom Tool fields with PowerShell

You are here:

When delegating administrative tasks using Custom Tools, you may need to query or modify information before the web form is presented to the user. The possibilities are limitless, but some examples of this might be:

  • Getting a list of available datastores before provisioning a VM
  • Enumerating a filtered list of shares on a remote host to allow a Help Desk person to grant access
  • Allow an application support tech to run more specific troubleshooting tools based on quick preliminary, real-time analysis
  • Show a list of tickets for a server from an external ticketing system, then force a valid ticket before performing an API action

Example with code

In the following example, we need a tool that will allow a user to see a real-time list of Windows services on a remote computer and then choose to view, start or stop one of those services. We’ll need to do the following:

  1. Create the custom fields needed to capture user input
  2. Create a preprocessor custom tool to query Windows services and dynamically populate a custom field
  3. Create the main custom tool that a delegated user will run to manage Windows services

First, create two ListBox custom fields called ServiceAction and ServiceListBox by going to Settings > Custom fields > New

For the ServiceAction field, add the following static lookup values.

For ServiceListBox, add a dummy lookup value in case the preprocessor script doesn’t grab the desired data.

Once added, you should see both custom fields listed like below.

Next, save the following PowerShell snippet as PreprocessorSample.ps1.

# The preprocessor script only accepts one argument
param([string]$sfData)

# Convert JSON from System Frontier into a "databus" object that will store everything sent back to SF
$dataBus = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($sfData)) | ConvertFrom-Json

# Gather data and perform actions needed to populate custom tool fields.
# Select properties from object collections for ListBox and CheckBox custom field types. The first
# property returned will be the value used while the second property will be displayed. If only
# one property is selected, it will be used for both the value of the custom field and what's
# displayed.
# For any other custom field data types, directly populate them like so: $dataBus.MyCustomTextField = "Here's my text"

# If the calling tool is being run against one or more computers, using the TargetHostname variable,
# an array of one or more names will be present in the TargetHostname property of the databus.
# For example, if a single computer name was passed in, you can access it like so: $dataBus.TargetHostname[0]
# Where [0] would retrieve the first and only computer name in the array.

# Check to see that the databus contains the property we are looking for first
if ([bool]($dataBus.PSobject.Properties.name -match "ServiceListBox"))
{
# Create an array to store our collected Windows service list data
$serviceList = @()

# The first property (Name) will used as the value of the ServiceListBox custom field and will
# be passed to the final custom tool code if selected by the user.
# The second property (DisplayName) is what the user will see in the ListBox, unless only one
# property is returned or selected.
$serviceList = Get-Service -ComputerName $dataBus.TargetHostname[0] | select Name,DisplayName

# Set the value of our custom field to the collected data
$dataBus.ServiceListBox = $serviceList
}

# Check to see that the databus contains the property we are looking for first
if ([bool]($dataBus.PSobject.Properties.name -match "UserSID"))
{
# Create an array to store our collected Windows service list data
$userSID = @()

# The first property (Name) will used as the value of the ServiceListBox custom field and will
# be passed to the final custom tool code if selected by the user.
# The second property (DisplayName) is what the user will see in the ListBox, unless only one
# property is returned or selected.
$userSID = Get-Service -ComputerName $dataBus.TargetHostname[0] | select Name,DisplayName

# Set the value of our custom field to the collected data
# In this example, $CurrentUser is a command-line variable populated by the Arguments section
# of our custom tool with the SF variable {$CurrentUser}. We could grab information about
# the user running the custom tool to make some decisions before the form loads.
$dataBus.UserSID = (Get-ADUser -Identity $CurrentUser | select -ExpandProperty SID).Value
}

# Return a JSON representation of the updated databus
# Be sure not to write any other data to the output stream.
$dataBus | ConvertTo-Json -Compress

Add your new preprocessor script by going to Tools > Create Tool. Give it a name like “Preprocessor Example” and choose the Preprocessor category (this is important).

Be sure to add permissions for roles that will need to run this tool. You’ll also want to explicitly map credentials for it, as this will be the context it runs under.

Now, save the following PowerShell snippet as DynamicFieldSample.ps1.

param([string]$ComputerName, [string]$ServiceName, [string]$Action)

Write-Host "Attemping to '$Action' the '$ServiceName' service on '$ComputerName'..."

switch ($Action)
{
	"Start" { (Get-WmiObject -ComputerName $ComputerName -Class Win32_Service -Filter "Name='$ServiceName'").StartService(); break }
	"Stop" { (Get-WmiObject -ComputerName $ComputerName -Class Win32_Service -Filter "Name='$ServiceName'").StopService(); break }
	default { Get-WmiObject -ComputerName $ComputerName -Class Win32_Service -Filter "Name='$ServiceName'" }
}

This is the main custom tool that a delegated user will run. Add it to System Frontier by going to Tools > Create Tool. Name it “Dynamic Field Sample” and choose a meaningful category, but not Preprocessor.

Click on the Modify button under User Input Fields, select the two custom fields you added earlier, click Add then Done to return to the tool configuration screen.

Modify your Arguments section to capture the current hostname and user input fields in order to pass their values to the command-line of this tool.

Under Preprocessor, choose the “Preprocessor Sample” script that you added earlier. Only custom tools with a category of Preprocessor will appear in this list.

When you’re done, it should look similar to the screenshot below.

Let’s test it

Now, search for a computer in System Frontier, click on it and then click on the Tools tab. You should see the new Dynamic Field Sample tool. Click Open. Here’s what’s happening behind the scenes:

  1. The main tool calls the preprocessor tool, passing it information it needs like the list of target hostnames and custom fields.
  2. The preprocessor script performs it’s magic, updates all the data that was passed in a returns it to the main tool.
  3. The main tool then uses relevant data that was returned to populate custom fields before the web form is presented to the user.
    1. Notice the ServiceListBox field has the list of all Windows services that were returned by the preprocessor tool!
  4. The user makes choices or adds information, if needed and runs the tool.
  5. All values are passed to the command-line of your script and run under elevated credentials.

In this example, starting the SNMP Trap service successfully should return output to the web console like so:

If designed correctly, preprocessor scripts and custom fields can be reusable and modular. All this without the need to write HTML or wire up Windows forms controls.

Don’t forget, you can run custom tools on a list of hostnames, as long as they exist in SF, and the tool will automatically take advantage of multi-threading and parallel execution without additional code.

Built-in variables for the Preprocessor

There are some built-in variables that can be used in a preprocessor as well. These are available on the dataBus.

$dataBus.__SystemFrontierDataBusIDThe ID of the dataBus. Data type is string.
$dataBus.__CurrentUsernameThe name of the user account that is currently running the Custom Tool. Data type is string.
$dataBus.__CustomToolIDThe ID of the Custom Tool being run. Data type is string.
$dataBus.__PreprocessorIDThe ID of the Preprocessor being run. Data type is string.
$dataBus.__CurrentUserRolesThe System Frontier Roles of which the user running the Custom Tool is a member. Data type is string[].

To use these built-in variables in the preprocessor, simply set the custom field name to equal the built-in variable:

$dataBus.MyCustomFieldToGetUser = $dataBus.__CurrentUserName
$dataBus.MyCustomFieldToGetUserRoles = $dataBus.__CurrentUserRoles
$dataBus.MyCustomToolIdentifier = $dataBus.__CustomToolID

Here is an example using the __CurrentUserRoles built-in variable within a Preprocessor script that will either populate the main Custom Tool with complete values if the user is a member of the SFSA role, or limit the data if the user is not a member of the SFSA role:

param([string]$sfData)
$dataBus = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($sfData)) | ConvertFrom-Json

If($dataBus.__CurrentUserRoles.Contains("SFSA"))
{
    # If the user is in the SFSA role, get the name, displayname, and status for all services   
    $dataBus.ServicesStatus = Get-WmiObject -ComputerName $dataBus.TargetHostname[0] -Class Win32_Service | Select name, displayname, status
}
Else
{
    # If the user is not in the SFSA role, get the name, displayname, and status only for the spooler service
    $dataBus.ServicesStatus = Get-WmiObject -ComputerName $dataBus.TargetHostname[0] -Class Win32_Service -Filter "Name='Spooler'" | Select name, displayname, status
}

$dataBus | ConvertTo-Json -Compress
Tags:
Was this article helpful?
Dislike 0