asset-management
SKILL.md
Asset Management for ServiceNow
Asset Management tracks hardware and software assets throughout their lifecycle.
Asset Architecture
Asset (alm_asset)
├── Hardware Asset (alm_hardware)
│ └── Consumable (alm_consumable)
└── License (alm_license)
CI (cmdb_ci) ←→ Asset (alm_asset)
↑
One CI can have multiple assets over time
Key Tables
| Table | Purpose |
|---|---|
alm_asset |
Base asset table |
alm_hardware |
Hardware assets |
alm_license |
Software licenses |
alm_consumable |
Consumable assets |
ast_contract |
Asset contracts |
cmdb_ci |
Configuration items |
Hardware Assets (ES5)
Create Hardware Asset
// Create hardware asset (ES5 ONLY!)
var asset = new GlideRecord("alm_hardware")
asset.initialize()
// Basic info
asset.setValue("display_name", "Dell Latitude 5520")
asset.setValue("asset_tag", "ASSET-" + generateAssetTag())
asset.setValue("serial_number", "SN123456789")
// Model
asset.setValue("model", getModelSysId("Dell Latitude 5520"))
asset.setValue("model_category", getModelCategorySysId("Laptop"))
// Status and substatus
asset.setValue("install_status", 1) // Installed
asset.setValue("substatus", "in_use")
// Assignment
asset.setValue("assigned_to", userSysId)
asset.setValue("assigned", new GlideDateTime())
asset.setValue("location", locationSysId)
asset.setValue("department", departmentSysId)
// Financial
asset.setValue("cost", 1299.99)
asset.setValue("cost_center", costCenterSysId)
// Dates
asset.setValue("purchase_date", "2024-01-15")
asset.setValue("warranty_expiration", "2027-01-15")
// Link to CI if exists
asset.setValue("ci", cmdbCiSysId)
asset.insert()
Asset Lifecycle States
// Asset install_status values
var ASSET_STATUS = {
INSTALLED: 1, // In use
ON_ORDER: 2, // Ordered, not received
IN_STOCK: 6, // In inventory
IN_TRANSIT: 7, // Being shipped
IN_MAINTENANCE: 8, // Under repair
RETIRED: 9, // End of life
DISPOSED: 10, // Disposed of
}
// Transition asset status (ES5 ONLY!)
function transitionAssetStatus(assetSysId, newStatus, notes) {
var asset = new GlideRecord("alm_hardware")
if (!asset.get(assetSysId)) {
return { success: false, message: "Asset not found" }
}
var currentStatus = parseInt(asset.getValue("install_status"), 10)
// Validate transition
var validTransitions = {
2: [6, 7], // On Order -> In Stock, In Transit
7: [6, 1], // In Transit -> In Stock, Installed
6: [1, 7, 9], // In Stock -> Installed, In Transit, Retired
1: [8, 6, 9], // Installed -> In Maintenance, In Stock, Retired
8: [1, 6, 9], // In Maintenance -> Installed, In Stock, Retired
9: [10], // Retired -> Disposed
}
if (!validTransitions[currentStatus] || validTransitions[currentStatus].indexOf(newStatus) === -1) {
return {
success: false,
message: "Invalid transition from " + currentStatus + " to " + newStatus,
}
}
// Update status
asset.setValue("install_status", newStatus)
// Handle specific transitions
if (newStatus === 1) {
asset.setValue("installed", new GlideDateTime())
} else if (newStatus === 9) {
asset.setValue("retired", new GlideDateTime())
asset.setValue("assigned_to", "")
} else if (newStatus === 10) {
asset.setValue("disposed", new GlideDateTime())
}
// Add work note
if (notes) {
asset.work_notes = notes
}
asset.update()
return { success: true, asset_tag: asset.getValue("asset_tag") }
}
Software Licenses (ES5)
Create License Record
// Create software license (ES5 ONLY!)
var license = new GlideRecord("alm_license")
license.initialize()
// Basic info
license.setValue("display_name", "Microsoft Office 365 E3")
license.setValue("product", getProductSysId("Microsoft Office 365"))
license.setValue("license_type", "per_user") // per_user, per_device, site, enterprise
// Quantities
license.setValue("rights", 500) // Total licenses purchased
license.setValue("used", 0) // Will be calculated
license.setValue("remaining", 500) // Will be calculated
// Dates
license.setValue("start_date", "2024-01-01")
license.setValue("end_date", "2024-12-31")
// Cost
license.setValue("cost", 25000.0)
license.setValue("cost_per_unit", 50.0)
// Vendor
license.setValue("vendor", vendorSysId)
license.setValue("contract", contractSysId)
license.insert()
License Allocation
// Allocate license to user (ES5 ONLY!)
function allocateLicense(licenseSysId, userSysId) {
var license = new GlideRecord("alm_license")
if (!license.get(licenseSysId)) {
return { success: false, message: "License not found" }
}
// Check availability
var remaining = parseInt(license.getValue("remaining"), 10)
if (remaining <= 0) {
return { success: false, message: "No licenses available" }
}
// Check if user already has this license
var existing = new GlideRecord("alm_entitlement_user")
existing.addQuery("licensed_by", licenseSysId)
existing.addQuery("user", userSysId)
existing.query()
if (existing.hasNext()) {
return { success: false, message: "User already has this license" }
}
// Create entitlement
var entitlement = new GlideRecord("alm_entitlement_user")
entitlement.initialize()
entitlement.setValue("licensed_by", licenseSysId)
entitlement.setValue("user", userSysId)
entitlement.setValue("allocated", new GlideDateTime())
entitlement.insert()
// Update license counts
updateLicenseCounts(licenseSysId)
return {
success: true,
message: "License allocated",
entitlement: entitlement.getUniqueValue(),
}
}
function updateLicenseCounts(licenseSysId) {
var license = new GlideRecord("alm_license")
if (!license.get(licenseSysId)) return
// Count allocations
var ga = new GlideAggregate("alm_entitlement_user")
ga.addQuery("licensed_by", licenseSysId)
ga.addAggregate("COUNT")
ga.query()
var used = 0
if (ga.next()) {
used = parseInt(ga.getAggregate("COUNT"), 10)
}
var rights = parseInt(license.getValue("rights"), 10)
license.setValue("used", used)
license.setValue("remaining", rights - used)
license.update()
}
Asset Discovery Integration (ES5)
Match Discovered CI to Asset
// Match discovered CI to existing asset (ES5 ONLY!)
function matchCIToAsset(ciSysId) {
var ci = new GlideRecord("cmdb_ci_computer")
if (!ci.get(ciSysId)) {
return null
}
var serialNumber = ci.getValue("serial_number")
var assetTag = ci.getValue("asset_tag")
// Try to find matching asset
var asset = new GlideRecord("alm_hardware")
// Match by serial number first
if (serialNumber) {
asset.addQuery("serial_number", serialNumber)
asset.query()
if (asset.next()) {
return linkAssetToCI(asset, ci)
}
}
// Match by asset tag
if (assetTag) {
asset = new GlideRecord("alm_hardware")
asset.addQuery("asset_tag", assetTag)
asset.query()
if (asset.next()) {
return linkAssetToCI(asset, ci)
}
}
// No match - create new asset
return createAssetFromCI(ci)
}
function linkAssetToCI(asset, ci) {
asset.setValue("ci", ci.getUniqueValue())
asset.update()
ci.setValue("asset", asset.getUniqueValue())
ci.update()
return asset.getUniqueValue()
}
function createAssetFromCI(ci) {
var asset = new GlideRecord("alm_hardware")
asset.initialize()
asset.setValue("display_name", ci.getDisplayValue())
asset.setValue("serial_number", ci.getValue("serial_number"))
asset.setValue("asset_tag", ci.getValue("asset_tag"))
asset.setValue("model", ci.getValue("model_id"))
asset.setValue("ci", ci.getUniqueValue())
asset.setValue("install_status", 1)
var assetSysId = asset.insert()
ci.setValue("asset", assetSysId)
ci.update()
return assetSysId
}
Asset Reports (ES5)
Asset Inventory Summary
// Get asset inventory summary (ES5 ONLY!)
function getAssetInventorySummary() {
var summary = {
by_status: {},
by_category: {},
by_location: {},
total_value: 0,
}
// By status
var ga = new GlideAggregate("alm_hardware")
ga.addAggregate("COUNT")
ga.addAggregate("SUM", "cost")
ga.groupBy("install_status")
ga.query()
while (ga.next()) {
var status = ga.install_status.getDisplayValue()
summary.by_status[status] = {
count: parseInt(ga.getAggregate("COUNT"), 10),
value: parseFloat(ga.getAggregate("SUM", "cost")) || 0,
}
summary.total_value += summary.by_status[status].value
}
// By model category
ga = new GlideAggregate("alm_hardware")
ga.addAggregate("COUNT")
ga.groupBy("model_category")
ga.query()
while (ga.next()) {
var category = ga.model_category.getDisplayValue() || "Uncategorized"
summary.by_category[category] = parseInt(ga.getAggregate("COUNT"), 10)
}
// By location
ga = new GlideAggregate("alm_hardware")
ga.addQuery("install_status", 1) // Only installed
ga.addAggregate("COUNT")
ga.groupBy("location")
ga.query()
while (ga.next()) {
var location = ga.location.getDisplayValue() || "Unknown"
summary.by_location[location] = parseInt(ga.getAggregate("COUNT"), 10)
}
return summary
}
MCP Tool Integration
Available Tools
| Tool | Purpose |
|---|---|
snow_query_table |
Query assets and licenses |
snow_cmdb_search |
Search CMDB for CIs |
snow_execute_script_with_output |
Test asset scripts |
snow_find_artifact |
Find asset configurations |
Example Workflow
// 1. Query hardware assets
await snow_query_table({
table: "alm_hardware",
query: "install_status=1",
fields: "asset_tag,display_name,assigned_to,location,model",
})
// 2. Check license compliance
await snow_execute_script_with_output({
script: `
var license = new GlideRecord('alm_license');
license.addQuery('remainingRELATIVELT@integer@0');
license.query();
while (license.next()) {
gs.info('Over-allocated: ' + license.display_name);
}
`,
})
// 3. Find assets nearing warranty expiration
await snow_query_table({
table: "alm_hardware",
query: "warranty_expirationBETWEENjavascript:gs.beginningOfToday()@javascript:gs.daysAgoEnd(-30)",
fields: "asset_tag,display_name,warranty_expiration,assigned_to",
})
Best Practices
- Asset Tags - Unique, scannable identifiers
- Lifecycle Tracking - Track all state changes
- CI Linking - Connect assets to CMDB
- License Compliance - Monitor allocation vs rights
- Warranty Tracking - Alert before expiration
- Financial Accuracy - Maintain cost data
- Regular Audits - Verify physical inventory
- ES5 Only - No modern JavaScript syntax
Weekly Installs
52
Repository
groeimetai/snow-flowGitHub Stars
53
First Seen
Jan 22, 2026
Security Audits
Installed on
gemini-cli48
opencode47
github-copilot47
codex47
cursor47
claude-code46