Skip to content

Commit a59cfcb

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into main
2 parents 8e55fcb + 111a9d9 commit a59cfcb

File tree

18 files changed

+1097
-0
lines changed

18 files changed

+1097
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Email is been used to set the cc and subjed where we got from the UI Page and this will be attached to the Notification to run dymanically
2+
3+
4+
(function runMailScript( /* GlideRecord */ current, /* TemplatePrinter */ template,
5+
/* Optional EmailOutbound */
6+
email, /* Optional GlideRecord */ email_action,
7+
/* Optional GlideRecord */
8+
event) {
9+
10+
11+
// In this we get the data in the 4th parameter so that we use the parm2 to get the object of data and the used in the certain purpose
12+
13+
var obj = JSON.parse(event.parm2);
14+
email.addAddress("cc", obj.cc);
15+
email.setSubject(obj.subject);
16+
17+
template.print(" <h5 style='margin: 0px;'>Hi Team,</h5><br><p>Details are : </p>" + obj.body);
18+
19+
})(current, template, email, email_action, event);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
Notificaiton for this proble
3+
4+
Table : Incident (incident)
5+
6+
When to Send
7+
Send when - Event is fried
8+
Event name - SendEamilInForm
9+
10+
Who will receive
11+
Event parm 1 contains recipient - True
12+
13+
What it will contain
14+
// This will hold the email script which we use to populate the subjec and the body.
15+
Message HTML - ${mail_script:IncidentFormScript}
16+
Email template - Unsubscribe and Preferences
17+
Content type - HTML only
18+
19+
*/
20+
21+
// Name of the Email Script will be populated when the notification has been triggered.
22+
${mail_script:IncidentFormScript}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
Send Email On Form for every Record
2+
3+
Script Type: UI Action, Table: incident, Form button: True, Client: True, Show update: True, OnClick: functionName()
4+
5+
Script Type: UI Page Category: General
6+
7+
Script Type: Email Script
8+
9+
Event Registry : Table: incident, Fired by: UI Page, Event Name: SendEmailInForm
10+
11+
Notification : Table: incident, Type: EMAIL, Category: Uncategorized,
12+
13+
Goal: To Send Email on Form Directly by population some field and then customize the body and trigger it.
14+
15+
Walk through of code: So to send the Email directly on each and every record there will be a UI Action which will help to populate the UI Page which we use some field to be populate in the UI Page directly to the particulat HTML content and these are the fields will be populate (Caller Email as the To and then Short Description as the Subjet of the Email) and othe field will be CC and Body which the user want to decide what data can be filled out and then send.
16+
17+
<img width="1908" height="417" alt="UIAction_INC_fomr" src="https://github.com/user-attachments/assets/0ec5afb2-8375-41b8-a346-4fe5ee55913f" />
18+
19+
20+
UI Page - This will have 5 components
21+
1. To Caller
22+
2. CC
23+
3. Subject
24+
4. Body
25+
5. Send button
26+
27+
<img width="804" height="434" alt="UI Page Email template" src="https://github.com/user-attachments/assets/1d1ff563-7430-4ec3-b391-9f55912ad4e1" />
28+
29+
30+
31+
Once the Send button has been triggered this will call the Processing Script where the event will trigger once this will call the Event Registry event("SendEmailInForm") which we use for this problem statment.Where the Notification will trigger when the Event is fried and then for the email content we uset the Email Script which dynamic content will be populated which we got from the UI page as the event parm2 and then will send the email to the respective caller.
32+
33+
<img width="1477" height="759" alt="Notification_Contains" src="https://github.com/user-attachments/assets/ddc91bbf-aeba-4de2-8db4-2fba9d823fba" />
34+
<img width="1522" height="377" alt="Notification_Receive" src="https://github.com/user-attachments/assets/b2934470-6c90-4b52-be6d-7f2397b8609a" />
35+
<img width="1705" height="952" alt="Notification1" src="https://github.com/user-attachments/assets/d74cfe59-dd3e-42b7-b95a-b0134169b679" />
36+
37+
38+
39+
<img width="808" height="278" alt="Email Preview" src="https://github.com/user-attachments/assets/75d4c1ca-36e8-4e01-8d37-6f1fad0ecfc1" />
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// This function will creat the model object and then route to the UI page which we configured to show the field details to fill by the user
2+
3+
/*
4+
Table- Incident (incident)
5+
Form button - True
6+
Client -True
7+
Show Update - True
8+
Onclick - Function name (sendEmail)
9+
10+
11+
12+
*/
13+
function sendEmail(){
14+
var modalT = new GlideModal("SendEmailEvent", false, 1200);
15+
modalT.setTitle("Send Email");
16+
modalT.setPreference("sysparm_sys_id", g_form.getUniqueValue());
17+
modalT.render();
18+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
3+
<style>
4+
body {
5+
font-family: Arial, sans-serif;
6+
background-color: #f8f9fa;
7+
display: flex;
8+
justify-content: center;
9+
align-items: center;
10+
height: 100vh;
11+
margin: 0;
12+
}
13+
14+
.email-form {
15+
background: #fff;
16+
padding: 20px 25px;
17+
border-radius: 8px;
18+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
19+
width: 850px;
20+
}
21+
22+
.email-form h2 {
23+
text-align: center;
24+
margin-bottom: 15px;
25+
color: #333;
26+
}
27+
28+
label {
29+
display: block;
30+
margin-top: 10px;
31+
font-weight: bold;
32+
color: #555;
33+
}
34+
35+
input[type="text"],
36+
input[type="email"],
37+
textarea {
38+
width: 100%;
39+
padding: 8px;
40+
margin-top: 5px;
41+
border: 1px solid #ccc;
42+
border-radius: 5px;
43+
box-sizing: border-box;
44+
font-size: 14px;
45+
}
46+
47+
textarea {
48+
resize: none;
49+
height: 100px;
50+
}
51+
52+
button {
53+
width: 100%;
54+
background-color: #007bff;
55+
color: white;
56+
padding: 10px;
57+
border: none;
58+
border-radius: 5px;
59+
margin-top: 15px;
60+
cursor: pointer;
61+
font-size: 16px;
62+
}
63+
64+
button:hover {
65+
background-color: #0056b3;
66+
}
67+
</style>
68+
<body>
69+
70+
<!-- Getting the sys_id From the Form UI View -->
71+
<g:evaluate var="jvar_sysId" expression="RP.getWindowProperties().get('sysparm_sys_id')" />
72+
73+
74+
<!-- GlideRecord Query to current INC Ticket -->
75+
76+
<g:evaluate jelly="true" object="true" var="jvar_gr">
77+
var gr_inc = new GlideRecord('incident');
78+
gr_inc.addQuery('sys_id', '${jvar_sysId}');
79+
gr_inc.query();
80+
gr_inc;
81+
</g:evaluate>
82+
83+
<j:while test="${gr_inc.next()}">
84+
<j:set var="jvar_short_desc" value="${gr_inc.getValue('short_description')}"></j:set>
85+
<j:set var="jvar_num" value="${gr_inc.getValue('number')}"></j:set>
86+
<j:set var="jvar_email" value="${gr_inc.caller_id.email}"></j:set>
87+
</j:while>
88+
89+
90+
<g:ui_form>
91+
<!-- <h2>Send Email</h2> -->
92+
93+
<label for="to">To Caller:</label>
94+
<input type="email" id="to" name="to" value="${jvar_email}" placeholder="Caller recipient email" />
95+
96+
<label for="bcc">CC:</label>
97+
<input type="email" id="cc" name="cc" placeholder="Enter CC email" />
98+
99+
<label for="subject">Subject:</label>
100+
<input type="text" id="subject" name="subject" value="${jvar_short_desc}" placeholder="Short Description will be poulated" />
101+
102+
<label for="body">Body:</label>
103+
<textarea id="body" name="body" placeholder="Body to send email" >${jvar_num}</textarea>
104+
105+
<button type="submit">Send</button>
106+
</g:ui_form>
107+
</body>
108+
109+
</j:jelly>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Getting the value from the HTML and the make the body and trigger the event for further process.
2+
3+
var obj={};
4+
obj.body = body.toString();
5+
obj.cc = cc.toString();
6+
obj.subject = subject.toString();
7+
8+
// Event Trigger and passing the paramenters
9+
/*
10+
Parm 1 : will have the to receipient
11+
Parm 2 : will have the cc, subject and body
12+
*/
13+
gs.eventQueue("SendEmailInForm",current,to,JSON.stringify(obj));
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Key features
2+
Automatic problem creation: The script uses a GlideAggregate query to count the number of incidents opened for a specific CI.
3+
Time-based threshold: Problems are only created if more than five incidents are opened within a 60-minute window.
4+
Targeted incidents: The script focuses on incidents related to the same CI, making it effective for identifying recurring infrastructure issues.
5+
Customizable conditions: The number of incidents and the time frame are easily configurable within the script.
6+
Efficient performance: The use of GlideAggregate ensures the database is queried efficiently, minimizing performance impact.
7+
8+
How it works
9+
The script is designed to be executed as a server-side script, typically within a Business Rule. When an incident is inserted or updated, the script performs the following actions:
10+
Queries incidents: It executes a GlideAggregate query on the incident table.
11+
Sets conditions: The query is filtered to count all incidents that meet the following conditions:
12+
Same CI: The incident's cmdb_ci matches the cmdb_ci of the current record.
13+
Within the last hour: The opened_at time is within the last 60 minutes.
14+
Evaluates count: After the query is run, the script checks if the count of matching incidents exceeds the threshold (in this case, 5).
15+
Creates problem: If the threshold is exceeded, a new problem record is initialized.
16+
The short_description is automatically populated with a descriptive message.
17+
The cmdb_ci is linked to the new problem record.
18+
The new record is then inserted into the database.
19+
Implementation steps
20+
Create a Business Rule:
21+
Navigate to System Definition > Business Rules.
22+
Click New.
23+
Configure the Business Rule:
24+
Name: Auto Create Problem from Multiple Incidents
25+
Table: Incident [incident]
26+
Advanced: true
27+
When to run: Select after and check the Insert and Update checkboxes. This ensures the script runs after an incident has been saved.
28+
Filter conditions: Optionally, you can add conditions to limit when the script runs (e.g., cmdb_ci is not empty).
29+
Add the script:
30+
Navigate to the Advanced tab.
31+
Copy and paste the script into the Script field.
32+
Customize (optional):
33+
Number of incidents: Change the > 5 value to adjust the threshold.
34+
Time frame: Adjust the gs.minutesAgoStart(60) value to change the time window.
35+
Other conditions: If you need to check for specific incident statuses or categories, add more addQuery lines to the GlideAggregate call.
36+
Save the Business Rule.
37+
Customization examples
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var incidentCheck = new GlideAggregate('incident');
2+
incidentCheck.addQuery('cmdb_ci', current.cmdb_ci); // Or any specific CI
3+
incidentCheck.addQuery('opened_at', '>', 'javascript:gs.minutesAgoStart(60)');
4+
incidentCheck.addAggregate('COUNT');
5+
incidentCheck.query();
6+
7+
if (incidentCheck.next() && parseInt(incidentCheck.getAggregate('COUNT')) > 5) {
8+
var problem = new GlideRecord('problem');
9+
problem.initialize();
10+
problem.short_description = 'Multiple incidents reported for CI: ' + current.cmdb_ci.getDisplayValue();
11+
problem.cmdb_ci = current.cmdb_ci;
12+
problem.insert();
13+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Background Script — Copy Source User’s Groups to Specific Users
2+
3+
Working:
4+
It retrieves all groups of the source user.
5+
Loops through all active users (except the source).
6+
Checks whether the user is already a member of that group.
7+
If not, it inserts a new record in sys_user_grmember.
8+
9+
Note:
10+
sourceUserSysId → sys_id of the user whose groups you want to copy.
11+
The 3 entries in targetUserSysIds → sys_ids of the target users.
12+
It checks for duplicates, so no errors even if the user is already in that group.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Background script in ServiceNow
2+
// Copies all group memberships from one user to specific other users
3+
4+
var sourceUserSysId = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // sys_id of the source user
5+
var targetUserSysIds = [
6+
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', // target user 1
7+
'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', // target user 2
8+
'cccccccccccccccccccccccccccccc' // target user 3
9+
];
10+
11+
var sourceGroups = [];
12+
13+
// Step 1: Fetch all groups of the source user
14+
var grMember = new GlideRecord('sys_user_grmember');
15+
grMember.addQuery('user', sourceUserSysId);
16+
grMember.query();
17+
18+
while (grMember.next()) {
19+
sourceGroups.push(grMember.group.toString());
20+
}
21+
gs.info('Source user belongs to ' + sourceGroups.length + ' groups.');
22+
23+
// Step 2: For each target user, add them to each group (if not already a member)
24+
for (var i = 0; i < targetUserSysIds.length; i++) {
25+
var targetUserId = targetUserSysIds[i];
26+
27+
for (var j = 0; j < sourceGroups.length; j++) {
28+
var groupId = sourceGroups[j];
29+
30+
var existing = new GlideRecord('sys_user_grmember');
31+
existing.addQuery('user', targetUserId);
32+
existing.addQuery('group', groupId);
33+
existing.query();
34+
35+
if (!existing.next()) {
36+
var newMember = new GlideRecord('sys_user_grmember');
37+
newMember.initialize();
38+
newMember.user = targetUserId;
39+
newMember.group = groupId;
40+
newMember.insert();
41+
42+
gs.info('Added user [' + targetUserId + '] to group [' + groupId + ']');
43+
} else {
44+
gs.info('User [' + targetUserId + '] already in group [' + groupId + ']');
45+
}
46+
}
47+
}
48+
49+
gs.info('--- Group replication completed successfully ---');
50+

0 commit comments

Comments
 (0)