Coding your own Module

Bell scripts are placed in the same directory on the root level. In the examples below we use ext for an extension of a script, for Powershell it is ps1 (and in the examples below, we use Powershell scripts as examples, but Python files (.py) can be also used and even mixed with .ps1 files). There are 2 required scripts: login.ext, audit.ext, all other scripts are optional.

login.ext processes the login request:


The login logic is completely encapsulated inside the script. It can use predefined hard-coded logins, it can have it's own database or users/logins, or, which is better, it can use Active Directory. The framework is unaware of what method is used.


When login is successful (second example), the script should output 2 lines. The first line is semicolon-separated list of security "groups". That list is passed to every other script, so any script can decide if an operation should be denied or not.

You can put AD group names as is, but usually such group names are long and might change, so it makes sense to 'translate' them with some short names. In the example above AD groups are translated into "RO" (those who can read everything), and "RW" (those who can do more dangerous things. Download any module to check the example with AD.

The second line in the cortege for the root element. Corteges are explained below, they are used to define tree's contents.

A cortege consists of 4 |-separated fields: name, which is a name you can see in GUI, element class, element type, and tags.



In this example there are 2 scripts, but quite often there is just one. Why do we need more than one script? This is useful because you can 'plug' additional functionality to an existing module, you can add tree elements (properties) without modifying the existing script. All you need to know is the class name. What happens if we run the script?

All scripts have 4 parameters: user, group (list of groups created once for the session by login.ext), name of the caller element and tags.


So we can see that both scripts had returned the corteges. Name is displayed in a tree, class in used to identify, what script(s) to run. Type defines a type of element: folder for a tree, and leaves elements are text, html, file and chart. Tags are used to pass the context from one script to another. Tags typically are key=value pairs, where multiple key=values are separated with ~. Values can contain a sign '=', the first = is interpreted as key/value separator, while all successive equal signs are interpreted as parts of the value. Sometimes tags contain passwords, it is recommended to write them in the following format: ###secretname###, and the value for the secret is stored in config.js file and is not sent to a client (and can not be debugged using F12-console)

When a 'leaf' element is executed, the bell framework searches for the script called .ext, so only one script is executed. This is because a report is 'atomic' and there is nothing to merge. Nice reports are typically produced by the elements of the type 'html'.



Note how context is passed thru tags. Formatting to HTML is easily achieved in Powershell. lets check how that script works step by step.

param ([string]$usr, [string]$grp, [string]$name, [string]$tags)
. $PSScriptRoot/MSSQLquery.ps1
parse $tags

$conn = $tagval.Conn
$dbname = $tagval.dbname

In the beginning, we add the common MSSQL module. Function 'parse' parses tags into a hash table $tagval. Demo SQL module doesn't have any security, so $grp is ignored. Next, we populate $Header as the table header and $q as the SQL query to get the biggest tables. Finally, we do:

'text' scripts return plain text as is:

$d = MSSQLquery $conn $q | Select-Object -Property * -ExcludeProperty "ItemArray", "RowError", "RowState", "Table", "HasErrors"
$d | ConvertTo-HTML -Title "Rows" -Head $Header -body '<h2>Top 30 tables, by row count, desc</h2>'


And finally, 'chart' returns chart data in the following format:
Line 1 - chart type: word 'Line' or 'Bar', optionally followed by ,'startAtzero' - this fixed Ymin=0
Line 2 - title
Line 3 - X axis name
Line 4 - Y axis name
Line 5 - Column names, comma separated.
Next - values, comma separated. Values must be int or float, first column 'must' be datetime (format with 'T'), scale is auto-calculated.

Code sample (query is in $q):

Instant SQL server cpu for the last seconds
X - time
Y - CPU pct
MSSQLchart $conn $q


audit.'ext' is executed after every operation. Bell framework passes the following information to a script: all 4 parameters, like for any other script, followed by status code (0 - success). Audit script must be present, it can be empty if you don't need it. Typically, it logs all information into a file or a database. You can find working examples in the modules.

Finally, you can force download of a file (useful for the bug files). Specify type='file'. Script should output full path to a file

Update v0.70:
You can override the default order of elements in a folder (which is names alphabetically, case-insensitive) by providing a numeric priority. Priority is a number from 0 to 99999 appended to a name after ';' sign. Default priority is 100. In a simple scenario, to put an element on top, append ;1 to a name. If you provide a priority to all elements you can force any order you want. Elements with the same priority are ordered as before.

Update v0.71:
Script can generate images and save them to the current default directory. Current directory is cleaned every time before running a script. Different workers have different working directories so collisions are avoided.

Update v0.72:
Secrets in tags (###) are resolved using the config.js, but if not found there server executes script secret.ps1 or (in a scripts directory). This script gets secret name in the 1st parameter and should return the value using Write-Host or print. All errors, raised by this script are handled and logged.