| name | change-management |
| description | Create and transition ServiceNow change requests (normal/standard/emergency), change tasks, affected CIs, approval routing, CAB scheduling, and conflict detection across maintenance windows. |
| license | Apache-2.0 |
| compatibility | Designed for Snow-Code and ServiceNow development |
| metadata | {"author":"serac","version":"1.0.0","category":"servicenow"} |
| tools | ["snow_change_manage","snow_change_query","snow_query_table","snow_artifact_manage"] |
Change Management for ServiceNow
Change Management ensures controlled modifications to IT infrastructure through standardized processes and approvals.
Change Types
| Type | Approval | Risk | Example |
|---|
| Standard | Pre-approved | Low | Password reset template |
| Normal | CAB approval | Medium | Server patching |
| Emergency | Post-implementation | High | Production outage fix |
Change Request Structure
Change Request: CHG0010001
├── Risk Assessment
│ ├── Impact: Medium
│ ├── Risk: Low
│ └── Conflict Status: Clear
├── Schedule
│ ├── Planned Start: 2024-03-15 22:00
│ └── Planned End: 2024-03-15 23:00
├── Approvals
│ ├── Manager Approval: Approved
│ └── CAB Approval: Pending
├── Change Tasks
│ ├── Task 1: Backup current config
│ ├── Task 2: Apply patches
│ └── Task 3: Verify functionality
└── Affected CIs
├── PROD-WEB-001
└── PROD-DB-001
Creating Changes
Normal Change (ES5)
var change = new GlideRecord("change_request")
change.initialize()
change.setValue("short_description", "Apply security patches to web servers")
change.setValue("description", "Monthly security patch deployment for production web tier")
change.setValue("type", "normal")
change.setValue("category", "Software")
change.setValue("priority", 3)
change.setValue("risk", "low")
change.setValue("impact", 2)
var startDate = new GlideDateTime()
startDate.addDaysLocalTime(7)
startDate.setValue("2024-03-15 22:00:00")
change.setValue("start_date", startDate)
var endDate = new GlideDateTime(startDate)
endDate.addSeconds(3600)
change.setValue("end_date", endDate)
change.setValue("assignment_group", getGroupSysId("Change Management"))
change.setValue("assigned_to", getOnCallUser())
change.setValue(
"implementation_plan",
"1. Take backup of current configuration\\n" +
"2. Stop web services\\n" +
"3. Apply security patches\\n" +
"4. Restart services\\n" +
"5. Verify functionality",
)
change.setValue(
"backout_plan",
"1. Stop web services\\n" + "2. Restore from backup\\n" + "3. Restart services\\n" + "4. Verify rollback successful",
)
change.setValue(
"test_plan",
"1. Check web server response\\n" + "2. Verify all pages load\\n" + "3. Run automated health checks",
)
var changeSysId = change.insert()
Emergency Change (ES5)
var emergencyChange = new GlideRecord("change_request")
emergencyChange.initialize()
emergencyChange.setValue("short_description", "Emergency: Fix production database connection leak")
emergencyChange.setValue("type", "emergency")
emergencyChange.setValue("priority", 1)
emergencyChange.setValue("risk", "high")
emergencyChange.setValue("impact", 1)
emergencyChange.setValue(
"justification",
"Production database connections exhausted causing service outage. " + "Immediate fix required to restore service.",
)
emergencyChange.setValue("start_date", new GlideDateTime())
var endDate = new GlideDateTime()
endDate.addSeconds(7200)
emergencyChange.setValue("end_date", endDate)
emergencyChange.insert()
gs.eventQueue("change.emergency.created", emergencyChange)
Standard Change (ES5)
function createStandardChange(templateName, variables) {
var template = new GlideRecord("std_change_producer")
template.addQuery("name", templateName)
template.query()
if (!template.next()) {
gs.error("Standard change template not found: " + templateName)
return null
}
var change = new GlideRecord("change_request")
change.initialize()
change.setValue("short_description", template.getValue("short_description"))
change.setValue("description", template.getValue("description"))
change.setValue("type", "standard")
change.setValue("std_change_producer", template.getUniqueValue())
for (var key in variables) {
if (variables.hasOwnProperty(key) && change.isValidField(key)) {
change.setValue(key, variables[key])
}
}
return change.insert()
}
createStandardChange("Password Reset", {
requested_by: userSysId,
cmdb_ci: applicationSysId,
})
Change Tasks
Creating Change Tasks (ES5)
function addChangeTask(changeSysId, taskConfig) {
var task = new GlideRecord("change_task")
task.initialize()
task.setValue("change_request", changeSysId)
task.setValue("short_description", taskConfig.description)
task.setValue("order", taskConfig.order)
task.setValue("assignment_group", taskConfig.group)
task.setValue("planned_start_date", taskConfig.start)
task.setValue("planned_end_date", taskConfig.end)
return task.insert()
}
var tasks = [
{ description: "Pre-implementation backup", order: 100, group: "Database Team" },
{ description: "Apply patches", order: 200, group: "Server Team" },
{ description: "Verify functionality", order: 300, group: "QA Team" },
{ description: "Update documentation", order: 400, group: "Change Management" },
]
for (var i = 0; i < tasks.length; i++) {
addChangeTask(changeSysId, tasks[i])
}
Affected CIs
Linking CIs to Change (ES5)
function addAffectedCI(changeSysId, ciSysId) {
var task = new GlideRecord("task_ci")
task.initialize()
task.setValue("task", changeSysId)
task.setValue("ci_item", ciSysId)
return task.insert()
}
var servers = ["server1_sys_id", "server2_sys_id", "db_sys_id"]
for (var i = 0; i < servers.length; i++) {
addAffectedCI(changeSysId, servers[i])
}
Approvals
Check Approval Status (ES5)
function getApprovalStatus(changeSysId) {
var approvals = []
var approval = new GlideRecord("sysapproval_approver")
approval.addQuery("sysapproval", changeSysId)
approval.query()
while (approval.next()) {
approvals.push({
approver: approval.approver.getDisplayValue(),
state: approval.state.getDisplayValue(),
comments: approval.getValue("comments"),
sys_updated_on: approval.getValue("sys_updated_on"),
})
}
return approvals
}
Request Approval (ES5)
function requestApproval(changeSysId, approverSysId) {
var approval = new GlideRecord("sysapproval_approver")
approval.initialize()
approval.setValue("sysapproval", changeSysId)
approval.setValue("approver", approverSysId)
approval.setValue("state", "requested")
return approval.insert()
}
Change Conflict Detection
Check for Conflicts (ES5)
function checkChangeConflicts(changeSysId) {
var change = new GlideRecord("change_request")
if (!change.get(changeSysId)) return []
var conflicts = []
var startDate = change.getValue("start_date")
var endDate = change.getValue("end_date")
var affected = new GlideAggregate("task_ci")
affected.addQuery("task", changeSysId)
affected.groupBy("ci_item")
affected.query()
while (affected.next()) {
var ciSysId = affected.ci_item.toString()
var otherChanges = new GlideRecord("change_request")
otherChanges.addQuery("sys_id", "!=", changeSysId)
otherChanges.addQuery("state", "NOT IN", "closed,cancelled")
otherChanges.addQuery("start_date", "<=", endDate)
otherChanges.addQuery("end_date", ">=", startDate)
otherChanges.addJoinQuery("task_ci", "sys_id", "task").addCondition("ci_item", ciSysId)
otherChanges.query()
while (otherChanges.next()) {
conflicts.push({
change: otherChanges.getValue("number"),
ci: ciSysId,
start: otherChanges.getValue("start_date"),
end: otherChanges.getValue("end_date"),
})
}
}
return conflicts
}
State Transitions
Change States
| State | Next States | Conditions |
|---|
| New | Assess | Submitted |
| Assess | Authorize, Cancelled | Assessment complete |
| Authorize | Scheduled, Cancelled | Approvals complete |
| Scheduled | Implement, Cancelled | Within maintenance window |
| Implement | Review, Cancelled | Tasks completed |
| Review | Closed | PIR complete |
| Closed | - | Final state |
Transition Change (ES5)
function transitionChange(changeSysId, newState, notes) {
var change = new GlideRecord("change_request")
if (!change.get(changeSysId)) {
gs.error("Change not found: " + changeSysId)
return false
}
var currentState = change.getValue("state")
var validTransitions = {
"-5": ["-4", "4"],
"-4": ["-3", "4"],
"-3": ["-2", "4"],
"-2": ["-1", "4"],
"-1": ["0", "4"],
0: ["3"],
}
if (!validTransitions[currentState] || validTransitions[currentState].indexOf(newState) === -1) {
gs.error("Invalid state transition: " + currentState + " -> " + newState)
return false
}
change.setValue("state", newState)
if (notes) {
change.work_notes = notes
}
change.update()
return true
}
MCP Tool Integration
Available Change Tools
| Tool | Purpose |
|---|
snow_change_manage (action='create') | Create change |
snow_change_manage (action='create_task') | Add tasks |
snow_change_query (action='get') | Get details |
snow_change_manage (action='update_state') | Transition state |
snow_change_query (action='search') | Find changes |
snow_change_manage (action='schedule_cab') | Schedule CAB |
Example Workflow
var changeId = await snow_change_manage({
action: "create",
short_description: "Database upgrade",
type: "normal",
risk: "medium",
})
await snow_change_manage({
action: "create_task",
sys_id: changeId,
short_description: "Backup database",
})
var conflicts = await snow_change_query({
action: "search",
query: "stateNOT INclosed,cancelled^start_date<=2024-03-21 02:00:00^end_date>=2024-03-20 22:00:00",
})
await snow_change_manage({
action: "update_state",
sys_id: changeId,
state: "assess",
})
Best Practices
- Complete Documentation - Implementation, backout, test plans
- Risk Assessment - Accurate risk and impact ratings
- CI Linking - All affected CIs attached
- Proper Scheduling - Within maintenance windows
- Task Breakdown - Clear implementation steps
- Approval Chain - All required approvals
- Conflict Check - Verify no overlapping changes
- PIR - Post-implementation review for lessons learned