asset-management

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Asset Management for ServiceNow

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
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

核心表

TablePurpose
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
表名用途
alm_asset
资产基础表
alm_hardware
硬件资产表
alm_license
软件许可证表
alm_consumable
消耗品资产表
ast_contract
资产合同表
cmdb_ci
配置项表

Hardware Assets (ES5)

硬件资产(ES5)

Create Hardware Asset

创建硬件资产

javascript
// 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();
javascript
// 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

资产生命周期状态

javascript
// 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') };
}
javascript
// 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)

软件许可证(ES5)

Create License Record

创建许可证记录

javascript
// 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.00);
license.setValue('cost_per_unit', 50.00);

// Vendor
license.setValue('vendor', vendorSysId);
license.setValue('contract', contractSysId);

license.insert();
javascript
// 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.00);
license.setValue('cost_per_unit', 50.00);

// Vendor
license.setValue('vendor', vendorSysId);
license.setValue('contract', contractSysId);

license.insert();

License Allocation

许可证分配

javascript
// 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();
}
javascript
// 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)

资产发现集成(ES5)

Match Discovered CI to Asset

将发现的CI匹配到资产

javascript
// 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;
}
javascript
// 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)

资产报表(ES5)

Asset Inventory Summary

资产库存汇总

javascript
// 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;
}
javascript
// 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

MCP工具集成

Available Tools

可用工具

ToolPurpose
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
工具用途
snow_query_table
查询资产和许可证
snow_cmdb_search
在CMDB中搜索配置项
snow_execute_script_with_output
测试资产脚本
snow_find_artifact
查找资产配置

Example Workflow

示例工作流

javascript
// 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'
});
javascript
// 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

最佳实践

  1. Asset Tags - Unique, scannable identifiers
  2. Lifecycle Tracking - Track all state changes
  3. CI Linking - Connect assets to CMDB
  4. License Compliance - Monitor allocation vs rights
  5. Warranty Tracking - Alert before expiration
  6. Financial Accuracy - Maintain cost data
  7. Regular Audits - Verify physical inventory
  8. ES5 Only - No modern JavaScript syntax
  1. 资产标签 - 唯一、可扫描的标识符
  2. 生命周期跟踪 - 跟踪所有状态变更
  3. CI关联 - 将资产与CMDB关联
  4. 许可证合规性 - 监控分配量与授权量
  5. 保修跟踪 - 在到期前触发提醒
  6. 财务准确性 - 维护成本数据
  7. 定期审计 - 核实实物库存
  8. 仅支持ES5 - 不使用现代JavaScript语法