Skip to content

Commit 8db9a1c

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into update-set-scope-validation
2 parents 7844a15 + af03b70 commit 8db9a1c

File tree

2 files changed

+110
-0
lines changed
  • Server-Side Components/Script Includes/Sends Slack/Teams notifications when specific fields change on configured tables

2 files changed

+110
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# AuditFieldChangeNotifier
2+
### Description
3+
A ServiceNow Script Include that audits changes to specific fields and sends real-time notifications to Slack or Microsoft Teams using a webhook.
4+
It helps teams monitor important updates like priority or assignment changes without needing to check the platform.
5+
---
6+
### 🔧 Features
7+
- Monitors field-level changes on any table
8+
- Sends rich notifications to Slack/Teams
9+
- Easy to configure via system properties
10+
- Can be reused across multiple tables via Business Rules
11+
---
12+
### 🧩 How to Use
13+
1. **Create a System Property**
14+
- Name: `x_custom.audit_notifier.webhook_url`
15+
- Value: Your Slack or Teams webhook URL
16+
2. **Create a Script Include**
17+
- Name: `AuditFieldChangeNotifier`
18+
- Paste the provided Script Include code
19+
3. **Create a Business Rule**
20+
- Table: e.g. `incident`
21+
- When: `after update`
22+
- Add this script:
23+
```js
24+
(function executeRule(current, previous) {
25+
var notifier = new AuditFieldChangeNotifier();
26+
notifier.notifyOnFieldChange(current, previous, ['priority', 'state', 'assigned_to']);
27+
})(current, previous);
28+
```
29+
4. **Test It**
30+
- Update one of the watched fields.
31+
- A message should appear in your Slack/Teams channel like:
32+
```
33+
🛠️ ServiceNow — Field Update Notification
34+
Record: Incident INC0010001
35+
Description: Unable to access VPN
36+
• priority changed from 4 - Low → 2 - High
37+
• assigned_to changed from John → Alex
38+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Script Include: AuditFieldChangeNotifier
3+
* Description: Sends Slack/Teams notifications when specific fields change on configured tables.
4+
* Usable in: Business Rule (after update)
5+
*/
6+
var AuditFieldChangeNotifier = Class.create();
7+
AuditFieldChangeNotifier.prototype = {
8+
initialize: function () {
9+
// Slack or Teams webhook URL (store in sys_properties for security)
10+
this.webhookUrl = gs.getProperty('x_custom.audit_notifier.webhook_url', '');
11+
// Default app name
12+
this.appName = gs.getProperty('x_custom.audit_notifier.app_name', 'ServiceNow');
13+
},
14+
/**
15+
* Send notification if the specified fields have changed
16+
* @param {GlideRecord} current - Current record
17+
* @param {GlideRecord} previous - Previous record
18+
* @param {Array} fieldsToWatch - Array of field names to monitor
19+
*/
20+
notifyOnFieldChange: function (current, previous, fieldsToWatch) {
21+
try {
22+
if (!this.webhookUrl) {
23+
gs.warn('[AuditFieldChangeNotifier] Webhook URL not configured.');
24+
return;
25+
}
26+
var changes = [];
27+
fieldsToWatch.forEach(function (field) {
28+
if (current[field] + '' !== previous[field] + '') {
29+
changes.push({
30+
field: field,
31+
oldValue: previous[field] + '',
32+
newValue: current[field] + ''
33+
});
34+
}
35+
});
36+
if (changes.length === 0)
37+
return; // No relevant field changed
38+
var payload = this._buildPayload(current, changes);
39+
this._sendWebhook(payload);
40+
} catch (e) {
41+
gs.error('[AuditFieldChangeNotifier] Error: ' + e.message);
42+
}
43+
},
44+
/**
45+
* Build payload for Slack/Teams message
46+
*/
47+
_buildPayload: function (current, changes) {
48+
var shortDesc = current.short_description ? current.short_description + '' : '(No short description)';
49+
var tableName = current.getTableName();
50+
var recordUrl = gs.getProperty('glide.servlet.uri') + tableName + '.do?sys_id=' + current.sys_id;
51+
var changeLines = changes.map(function (c) {
52+
return `• *${c.field}* changed from _${c.oldValue}_ → *${c.newValue}*`;
53+
}).join('\n');
54+
return JSON.stringify({
55+
text: `🛠️ *${this.appName}* — Field Update Notification\n\n*Record:* <${recordUrl}|${tableName}> \n*Description:* ${shortDesc}\n\n${changeLines}\n\n_Updated by ${gs.getUserDisplayName()}_`
56+
});
57+
},
58+
/**
59+
* Send payload to webhook
60+
*/
61+
_sendWebhook: function (payload) {
62+
var r = new sn_ws.RESTMessageV2();
63+
r.setEndpoint(this.webhookUrl);
64+
r.setHttpMethod('POST');
65+
r.setRequestHeader('Content-Type', 'application/json');
66+
r.setRequestBody(payload);
67+
var response = r.execute();
68+
if (response.getStatusCode() >= 400)
69+
gs.error('[AuditFieldChangeNotifier] Webhook error: ' + response.getBody());
70+
},
71+
type: 'AuditFieldChangeNotifier'
72+
};

0 commit comments

Comments
 (0)