Middleware Hooks
As of PoshBot v0.11.0
, it is possible to define custom middleware hooks to be executed at certain events during the command processing life cycle.
These middleware hooks can add centralized authentication logic, custom logging solutions, advanced whitelisting or blacklisting, or any other custom processes.
The middleware is added to the bot configuration under the property MiddlewareConfiguration
and can optionally be saved to disk using Save-PoshBotConfiguration.
The command New-PoshBotConfiguration has also been modified to support these life cycle hooks.
The new command New-PoshBotMiddlewareHook will create an object that can be added to this MiddlewareConfiguration
property.
How Middleware Works
At various stages of the command processing life cycle, PoshBot provides the ability for custom scripts to be executed to determine if the command should continue executing.
PoshBot will pass in a CommandExecutionContext
object that contains information about the command, who initiated it, and other metadata.
The middleware can inspect (and modify) this information as appropriate.
If the middleware determines the command should continue processing, it MUST return this CommandExecutionContext
back to the output stream.
PoshBot will pass this object to the next middleware definition.
If the middleware needs to stop execution of the command, simply return nothing to the output stream or raise a terminating exception with the throw
statement.
MiddlewareConfiguration
The MiddlewareConfiguration
property contains six child properties that contain paths to PowerShell scripts that will be executed during the processing of a command.
More than one middleware hook can be added to each property and will be executed in the order they are added.
PreReceive
Array of middleware scripts that will run before PoshBot "receives" the message from the backend implementation. This middleware will receive the original message sent from the chat network and have a chance to modify, analyze, and optionally drop the message before PoshBot continues processing it.
PostReceive
Array of middleware scripts that will run after a message is "received" from the backend implementation. This middleware runs after messages have been parsed and matched with a registered command in PoshBot.
PreExecute
Array of middleware scripts that will run before a command is executed. This middleware is a good spot to run extra authentication or validation processes before commands are executed.
PostExecute
Array of middleware scripts that will run after PoshBot commands have been executed. This middleware is a good spot for custom logging solutions to write command history to a custom location.
PreResponse
Array of middleware script that will run before command responses are sent to the backend implementation. This middleware is a good spot for modifying or sanitizing responses before they are sent to the chat network.
PostResponse
Array of middleware scripts that will run after command responses have been sent to the backend implementation. This middleware runs after all processing is complete for a command and is a good spot for additional custom logging.
Authoring Middleware
To add middleware, you need a PoshBot configuration object first. The code below will create a configuration with default values.
$config = New-PoshBotConfiguration
Next, a new middleware hook is defined using New-PoshBotMiddlewareHook.
This command takes the name of the middleware hook and the path to the PowerShell script to execute.
The script must accept the parameters $Context
and $Bot
in that order.
PoshBot will dynamically pass in these objects when running the middleware.
The $Context
object will contain details about the current command that will be executed, who initiated the command, and other metadata you can use to determine if the command should continue to be processed.
The $Bot
object is the current PoshBot instance and is made available if the middleware needs logging functionality or deeper integration with PoshBot internals.
c:/poshbot/middleware/prereceive.ps1
param(
$Context,
$Bot
)
$Bot.LogInfo('Preparing to receive message')
if ($Context.Message.Text -match "^!about*") {
$Bot.LogInfo('Dropping [!about] about command')
return
} else {
$Context
}
$preReceiveHook = New-PoshBotMiddlewareHook -Name 'prereceive' -Path 'c:/poshbot/middleware/prereceive.ps1'
In the example above, the middleware is performing basic blacklisting by inspecting the raw text message that came from the chat network and doing a regex comparison.
If a match is found, the script returns immediately without returning the $Context
object.
Otherwise the $Context
object is returned normally.
This middleware is then added to the bot configuration object with the code below.
When adding middleware to the MiddlewareConfiguration
property, use the Add()
method, passing in the middleware object, and the type of middleware. The types are PreReceive
, PostReceive
, PreExecute
, PostExecute
, PreResponse
, and PostResponse
.
$config.MiddlewareConfiguration.Add($preReceiveHook, 'PreReceive')
Similarly, middleware can be removed using the Remove()
method.
$config.MiddlewareConfiguration.Remove($preReceiveHook, 'PreReceive')
A new instance of PoshBot is created and starting using the configuration object below.
$backend = New-PoshBotSlackBackend -Configuration $config.BackendConfiguration
$bot = New-PoshBotInstance -Backend $backend -Configuration $config
$bot | Start-PoshBot
Examples
PreReceive Example
A simple example of dropping all messages from users Sally and Bob.
c:/poshbot/middleware/dropuser.ps1
param(
$Context,
$Bot
)
$blacklistedUsers = @('sally', 'bob')
$user = $Context.Message.FromName
$Bot.LogDebug('Running user drop middleware')
if ($blacklistedUsers -contains $user) {
$Bot.LogInfo("Dropping message from [$user]")
return
}
$Context
$userDropHook = New-PoshBotMiddlewareHook -Name 'dropuser' -Path 'c:/poshbot/middleware/dropuser.ps1'
$config.MiddlewareConfiguration.Add($userDropHook, 'PreReceive')
PostReceive Example
Example of logging all messages initiated from a certain user.
c:/poshbot/middleware/logmessages.ps1
param(
$Context,
$Bot
)
$user = $Context.Message.FromName
if ($user -eq 'Bob') {
$Bot.LogInfo("Logging message from [$user]")
$userMessagesLog = Join-Path -Path $Bot.Configuration.LogDirectory -ChildPath "$user-messages.json"
$Context.ToJson() | Out-File -FilePath $userMessagesLog -Append -Force
}
$Context
$userLogHook = New-PoshBotMiddlewareHook -Name 'logmessages' -Path 'c:/poshbot/middleware/logmessages.ps1'
$config.MiddlewareConfiguration.Add($userLogHook, 'PostReceive')
PreExecute Example
Example of performing custom authentication logic using Active Directory to determine if a user can run a command.
c:/poshbot/middleware/adauth.ps1
param(
$Context,
$Bot
)
$user = $Context.Message.FromName
$adGroup = 'botusers'
$userGroups = (New-Object System.DirectoryServices.DirectorySearcher("(&(objectCategory=User)(samAccountName=$user)))")).FindOne().GetDirectoryEntry().memberOf
if (-not ($userGroups -contains $adGroup)) {
$Bot.LogInfo("User [$user] is not in AD group [$adGroup]. Bot commands cannot be run.")
return
} else {
$Context
}
$adAuthHook = New-PoshBotMiddlewareHook -Name 'adauth' -Path 'c:/poshbot/middleware/adauth.ps1'
$config.MiddlewareConfiguration.Add($adAuthHook, 'PreExecute')
PostExecute Example
Example of custom logging of all command and results results.
c:/poshbot/middleware/logcommandresults.ps1
param(
$Context,
$Bot
)
$resultsLog = Join-Path -Path $Bot.Configuration.LogDirectory -ChildPath 'commandresults.json'
$commandResult = [pscustomobject]@{
ParsedCommand = $Context.ParsedCommand.Summarize()
Results = $context.Result.Summarize()
} | ConvertTo-Json -Depth 15 -Compress
$commandResult | Out-File -FilePath $resultsLog -Append -Force
$Context
$commandResultsHook = New-PoshBotMiddlewareHook -Name 'commandresults' -Path 'c:/poshbot/middleware/logcommandresults.ps1'
$config.MiddlewareConfiguration.Add($commandResultsHook, 'PostExecute')
PreResponse Example
Example of inspecting command response for Social Security numbers and stripping them if present.
c:/poshbot/middleware/sanitizeresponses.ps1
param(
$Context,
$Bot
)
if ($Context.Response.Text -match '\d\d\d-\d\d-\d\d\d\d') {
$Bot.LogInfo('Sanitizing response')
$Context.Response.Text -replace '\d\d\d-\d\d-\d\d\d\d', '###-##-####'
}
$Context
$sanitizeResponsesHook = New-PoshBotMiddlewareHook -Name 'sanitizeresponses' -Path 'c:/poshbot/middleware/sanitizeresponses.ps1'
$config.MiddlewareConfiguration.Add($sanitizeResponsesHook, 'PreResponse')
PostResponse Example
Example of logging all command responses.
c:/poshbot/middleware/logcommandresponses.ps1
param(
$Context,
$Bot
)
$responseLog = Join-Path -Path $Bot.Configuration.LogDirectory -ChildPath 'responses.json'
$Context.Response.Summarize() |
ConvertTo-Json -Depth 10 -Compress |
Out-File -FilePath $responseLog -Append -Force
$Context
$commandResponseHook = New-PoshBotMiddlewareHook -Name 'commandresponses' -Path 'c:/poshbot/middleware/logcommandresponses.ps1'
$config.MiddlewareConfiguration.Add($commandResponseHook, 'PostResponse')
Performance
Middleware runs in the main PoshBot session and not as PowerShell jobs like commands. This means middleware should be written to execute as quickly as possible to not slow down PoshBots` command processing loop.