discovery-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Discovery Patterns for ServiceNow

ServiceNow Discovery 模式

Discovery automatically populates the CMDB by scanning networks and systems.
Discovery通过扫描网络和系统自动填充CMDB。

Discovery Architecture

Discovery 架构

Discovery Schedule
MID Server
Probes (collect data)
Sensors (process data)
Identification Rules (match/create CIs)
CMDB Population
Discovery 调度任务
MID Server
探针(收集数据)
传感器(处理数据)
识别规则(匹配/创建CI)
填充CMDB

Key Tables

核心表

TablePurpose
discovery_schedule
Discovery schedules
discovery_credentials
Discovery credentials
discovery_range
IP ranges to scan
cmdb_identification_rule
CI identification
ecc_agent
MID Server records
discovery_status
Discovery run status
表名用途
discovery_schedule
Discovery调度任务
discovery_credentials
Discovery凭证
discovery_range
待扫描IP范围
cmdb_identification_rule
CI识别规则
ecc_agent
MID Server记录
discovery_status
Discovery运行状态

Discovery Schedules (ES5)

Discovery 调度任务(ES5)

Create Discovery Schedule

创建Discovery调度任务

javascript
// Create discovery schedule (ES5 ONLY!)
var schedule = new GlideRecord('discovery_schedule');
schedule.initialize();

// Basic info
schedule.setValue('name', 'Data Center Discovery');
schedule.setValue('description', 'Weekly discovery of data center infrastructure');

// Type
schedule.setValue('discover', 'IP');  // IP, CI, Cloud Resources

// Schedule
schedule.setValue('run_type', 'weekly');
schedule.setValue('run_dayofweek', 'sunday');
schedule.setValue('run_time', '02:00:00');

// MID Server
schedule.setValue('mid_server', getMIDServerSysId('DataCenterMID'));

// Enable
schedule.setValue('active', true);

var scheduleSysId = schedule.insert();

// Add IP range
addDiscoveryRange(scheduleSysId, '10.0.0.0', '10.0.255.255', 'Data Center Network');
javascript
// 创建Discovery调度任务(仅支持ES5!)
var schedule = new GlideRecord('discovery_schedule');
schedule.initialize();

// 基本信息
schedule.setValue('name', '数据中心Discovery');
schedule.setValue('description', '每周扫描数据中心基础设施');

// 类型
schedule.setValue('discover', 'IP');  // IP、CI、云资源

// 调度设置
schedule.setValue('run_type', 'weekly');
schedule.setValue('run_dayofweek', 'sunday');
schedule.setValue('run_time', '02:00:00');

// MID Server
schedule.setValue('mid_server', getMIDServerSysId('DataCenterMID'));

// 启用
schedule.setValue('active', true);

var scheduleSysId = schedule.insert();

// 添加IP范围
addDiscoveryRange(scheduleSysId, '10.0.0.0', '10.0.255.255', '数据中心网络');

Add Discovery Range

添加扫描范围

javascript
// Add IP range to discovery schedule (ES5 ONLY!)
function addDiscoveryRange(scheduleSysId, startIP, endIP, name) {
    var range = new GlideRecord('discovery_range');
    range.initialize();
    range.setValue('schedule', scheduleSysId);
    range.setValue('name', name);
    range.setValue('type', 'range');
    range.setValue('range_start', startIP);
    range.setValue('range_end', endIP);
    range.setValue('active', true);
    return range.insert();
}

// Add CIDR range
function addDiscoveryCIDR(scheduleSysId, cidr, name) {
    var range = new GlideRecord('discovery_range');
    range.initialize();
    range.setValue('schedule', scheduleSysId);
    range.setValue('name', name);
    range.setValue('type', 'cidr');
    range.setValue('range', cidr);  // e.g., '10.0.0.0/24'
    range.setValue('active', true);
    return range.insert();
}
javascript
// 为Discovery调度任务添加IP范围(仅支持ES5!)
function addDiscoveryRange(scheduleSysId, startIP, endIP, name) {
    var range = new GlideRecord('discovery_range');
    range.initialize();
    range.setValue('schedule', scheduleSysId);
    range.setValue('name', name);
    range.setValue('type', 'range');
    range.setValue('range_start', startIP);
    range.setValue('range_end', endIP);
    range.setValue('active', true);
    return range.insert();
}

// 添加CIDR范围
function addDiscoveryCIDR(scheduleSysId, cidr, name) {
    var range = new GlideRecord('discovery_range');
    range.initialize();
    range.setValue('schedule', scheduleSysId);
    range.setValue('name', name);
    range.setValue('type', 'cidr');
    range.setValue('range', cidr);  // 例如:'10.0.0.0/24'
    range.setValue('active', true);
    return range.insert();
}

Discovery Credentials (ES5)

Discovery 凭证(ES5)

Create Credentials

创建凭证

javascript
// Create Windows credential (ES5 ONLY!)
var cred = new GlideRecord('discovery_credentials');
cred.initialize();
cred.setValue('name', 'Windows Domain Admin');
cred.setValue('type', 'windows');
cred.setValue('user_name', 'domain\\admin');
cred.setValue('password', '');  // Set via secure method
cred.setValue('active', true);

// Credential order
cred.setValue('order', 100);

// Assign to credential affinity
cred.setValue('credential_alias', credentialAliasSysId);

cred.insert();
javascript
// 创建Windows凭证(仅支持ES5!)
var cred = new GlideRecord('discovery_credentials');
cred.initialize();
cred.setValue('name', 'Windows域管理员');
cred.setValue('type', 'windows');
cred.setValue('user_name', 'domain\\admin');
cred.setValue('password', '');  // 通过安全方式设置
cred.setValue('active', true);

// 凭证优先级
cred.setValue('order', 100);

// 关联凭证亲和性
cred.setValue('credential_alias', credentialAliasSysId);

cred.insert();

Credential Affinity

凭证亲和性

javascript
// Create credential affinity (map credentials to IP ranges) (ES5 ONLY!)
var affinity = new GlideRecord('dscy_credentials_affinity');
affinity.initialize();
affinity.setValue('credential', credentialSysId);
affinity.setValue('range', discoveryRangeSysId);
affinity.setValue('order', 100);
affinity.insert();
javascript
// 创建凭证亲和性(将凭证映射到IP范围)(仅支持ES5!)
var affinity = new GlideRecord('dscy_credentials_affinity');
affinity.initialize();
affinity.setValue('credential', credentialSysId);
affinity.setValue('range', discoveryRangeSysId);
affinity.setValue('order', 100);
affinity.insert();

Custom Probes and Sensors (ES5)

自定义探针与传感器(ES5)

Custom Probe

自定义探针

javascript
// Create custom probe script (ES5 ONLY!)
// Probes run on MID Server to collect data

// Table: discovery_probes_script
var probe = new GlideRecord('discovery_probes_script');
probe.initialize();
probe.setValue('name', 'Custom Application Version');
probe.setValue('active', true);

// Probe script (runs on MID Server - ES5 ONLY!)
probe.setValue('script',
    'var output = {};\n' +
    '\n' +
    '// Command to run\n' +
    'var cmd = "cat /opt/myapp/version.txt";\n' +
    '\n' +
    'try {\n' +
    '    var result = Packages.com.service_now.mid.probe.tpcon.OperatingSystemCommand.execute(cmd);\n' +
    '    output.app_version = result.getOutput().trim();\n' +
    '    output.success = true;\n' +
    '} catch (e) {\n' +
    '    output.success = false;\n' +
    '    output.error = e.message;\n' +
    '}\n' +
    '\n' +
    'output;'
);

probe.insert();
javascript
// 创建自定义探针脚本(仅支持ES5!)
// 探针在MID Server上运行以收集数据

// 表:discovery_probes_script
var probe = new GlideRecord('discovery_probes_script');
probe.initialize();
probe.setValue('name', '自定义应用版本探针');
probe.setValue('active', true);

// 探针脚本(在MID Server上运行 - 仅支持ES5!)
probe.setValue('script',
    'var output = {};\n' +
    '\n' +
    '// 要执行的命令\n' +
    'var cmd = "cat /opt/myapp/version.txt";\n' +
    '\n' +
    'try {\n' +
    '    var result = Packages.com.service_now.mid.probe.tpcon.OperatingSystemCommand.execute(cmd);\n' +
    '    output.app_version = result.getOutput().trim();\n' +
    '    output.success = true;\n' +
    '} catch (e) {\n' +
    '    output.success = false;\n' +
    '    output.error = e.message;\n' +
    '}\n' +
    '\n' +
    'output;'
);

probe.insert();

Custom Sensor

自定义传感器

javascript
// Create custom sensor (ES5 ONLY!)
// Sensors run on ServiceNow instance to process probe results

// Table: discovery_sensors_script
var sensor = new GlideRecord('discovery_sensors_script');
sensor.initialize();
sensor.setValue('name', 'Process Custom Application Version');
sensor.setValue('active', true);
sensor.setValue('probe', probeSysId);

// Sensor script (runs on instance - ES5 ONLY!)
sensor.setValue('script',
    '(function process(result, source) {\n' +
    '    var output = JSON.parse(result.output);\n' +
    '    \n' +
    '    if (!output.success) {\n' +
    '        gs.warn("Custom app discovery failed: " + output.error);\n' +
    '        return;\n' +
    '    }\n' +
    '    \n' +
    '    // Find or create CI\n' +
    '    var ci = source.getDeviceRecord();\n' +
    '    if (ci) {\n' +
    '        ci.u_custom_app_version = output.app_version;\n' +
    '        ci.update();\n' +
    '        gs.info("Updated CI with app version: " + output.app_version);\n' +
    '    }\n' +
    '})(result, source);'
);

sensor.insert();
javascript
// 创建自定义传感器(仅支持ES5!)
// 传感器在ServiceNow实例上运行以处理探针结果

// 表:discovery_sensors_script
var sensor = new GlideRecord('discovery_sensors_script');
sensor.initialize();
sensor.setValue('name', '处理自定义应用版本');
sensor.setValue('active', true);
sensor.setValue('probe', probeSysId);

// 传感器脚本(在实例上运行 - 仅支持ES5!)
sensor.setValue('script',
    '(function process(result, source) {\n' +
    '    var output = JSON.parse(result.output);\n' +
    '    \n' +
    '    if (!output.success) {\n' +
    '        gs.warn("自定义应用发现失败: " + output.error);\n' +
    '        return;\n' +
    '    }\n' +
    '    \n' +
    '    // 查找或创建CI\n' +
    '    var ci = source.getDeviceRecord();\n' +
    '    if (ci) {\n' +
    '        ci.u_custom_app_version = output.app_version;\n' +
    '        ci.update();\n' +
    '        gs.info("已更新CI应用版本: " + output.app_version);\n' +
    '    }\n' +
    '})(result, source);'
);

sensor.insert();

Identification Rules (ES5)

识别规则(ES5)

CI Identification Rule

CI识别规则

javascript
// Create identification rule (ES5 ONLY!)
var rule = new GlideRecord('cmdb_identifier');
rule.initialize();

rule.setValue('name', 'Server Identification');
rule.setValue('table', 'cmdb_ci_server');
rule.setValue('active', true);

// Priority (lower = higher priority)
rule.setValue('order', 100);

// Identification entries (criteria)
rule.insert();

// Add identification criteria
var entry = new GlideRecord('cmdb_identifier_entry');
entry.initialize();
entry.setValue('identifier', rule.getUniqueValue());
entry.setValue('criterion_attributes', 'serial_number');  // Match by serial
entry.setValue('search_type', 'equals');
entry.setValue('active', true);
entry.insert();
javascript
// 创建识别规则(仅支持ES5!)
var rule = new GlideRecord('cmdb_identifier');
rule.initialize();

rule.setValue('name', '服务器识别规则');
rule.setValue('table', 'cmdb_ci_server');
rule.setValue('active', true);

// 优先级(数值越小优先级越高)
rule.setValue('order', 100);

// 识别条目(匹配条件)
rule.insert();

// 添加识别条件
var entry = new GlideRecord('cmdb_identifier_entry');
entry.initialize();
entry.setValue('identifier', rule.getUniqueValue());
entry.setValue('criterion_attributes', 'serial_number');  // 通过序列号匹配
entry.setValue('search_type', 'equals');
entry.setValue('active', true);
entry.insert();

Custom Identification Script

自定义识别脚本

javascript
// Identification script for complex matching (ES5 ONLY!)
// Table: cmdb_identifier_script

var script = new GlideRecord('cmdb_identifier_script');
script.initialize();
script.setValue('name', 'Custom Server Match');
script.setValue('table', 'cmdb_ci_server');
script.setValue('active', true);

script.setValue('script',
    '(function identify(source) {\n' +
    '    var serial = source.getValue("serial_number");\n' +
    '    var hostname = source.getValue("name");\n' +
    '    \n' +
    '    // Try serial match first\n' +
    '    var gr = new GlideRecord("cmdb_ci_server");\n' +
    '    if (serial) {\n' +
    '        gr.addQuery("serial_number", serial);\n' +
    '        gr.query();\n' +
    '        if (gr.next()) {\n' +
    '            return gr.getUniqueValue();\n' +
    '        }\n' +
    '    }\n' +
    '    \n' +
    '    // Try hostname + IP match\n' +
    '    gr = new GlideRecord("cmdb_ci_server");\n' +
    '    gr.addQuery("name", hostname);\n' +
    '    gr.addQuery("ip_address", source.getValue("ip_address"));\n' +
    '    gr.query();\n' +
    '    if (gr.next()) {\n' +
    '        return gr.getUniqueValue();\n' +
    '    }\n' +
    '    \n' +
    '    // No match - return null to create new CI\n' +
    '    return null;\n' +
    '})(source);'
);

script.insert();
javascript
// 用于复杂匹配的识别脚本(仅支持ES5!)
// 表:cmdb_identifier_script

var script = new GlideRecord('cmdb_identifier_script');
script.initialize();
script.setValue('name', '自定义服务器匹配');
script.setValue('table', 'cmdb_ci_server');
script.setValue('active', true);

script.setValue('script',
    '(function identify(source) {\n' +
    '    var serial = source.getValue("serial_number");\n' +
    '    var hostname = source.getValue("name");\n' +
    '    \n' +
    '    // 优先尝试序列号匹配\n' +
    '    var gr = new GlideRecord("cmdb_ci_server");\n' +
    '    if (serial) {\n' +
    '        gr.addQuery("serial_number", serial);\n' +
    '        gr.query();\n' +
    '        if (gr.next()) {\n' +
    '            return gr.getUniqueValue();\n' +
    '        }\n' +
    '    }\n' +
    '    \n' +
    '    // 尝试主机名+IP匹配\n' +
    '    gr = new GlideRecord("cmdb_ci_server");\n' +
    '    gr.addQuery("name", hostname);\n' +
    '    gr.addQuery("ip_address", source.getValue("ip_address"));\n' +
    '    gr.query();\n' +
    '    if (gr.next()) {\n' +
    '        return gr.getUniqueValue();\n' +
    '    }\n' +
    '    \n' +
    '    // 无匹配项 - 返回null以创建新CI\n' +
    '    return null;\n' +
    '})(source);'
);

script.insert();

Discovery Status (ES5)

Discovery 状态(ES5)

Monitor Discovery Status

监控Discovery运行状态

javascript
// Check discovery run status (ES5 ONLY!)
function getDiscoveryStatus(scheduleSysId) {
    var status = new GlideRecord('discovery_status');
    status.addQuery('dscheduler', scheduleSysId);
    status.orderByDesc('sys_created_on');
    status.setLimit(1);
    status.query();

    if (status.next()) {
        return {
            state: status.state.getDisplayValue(),
            started: status.getValue('started'),
            completed: status.getValue('completed'),
            devices_found: status.getValue('devices_found'),
            devices_completed: status.getValue('devices_completed'),
            errors: status.getValue('error_count')
        };
    }
    return null;
}
javascript
// 检查Discovery运行状态(仅支持ES5!)
function getDiscoveryStatus(scheduleSysId) {
    var status = new GlideRecord('discovery_status');
    status.addQuery('dscheduler', scheduleSysId);
    status.orderByDesc('sys_created_on');
    status.setLimit(1);
    status.query();

    if (status.next()) {
        return {
            state: status.state.getDisplayValue(),
            started: status.getValue('started'),
            completed: status.getValue('completed'),
            devices_found: status.getValue('devices_found'),
            devices_completed: status.getValue('devices_completed'),
            errors: status.getValue('error_count')
        };
    }
    return null;
}

Discovery Device Results

Discovery 设备扫描结果

javascript
// Get discovered devices from a run (ES5 ONLY!)
function getDiscoveredDevices(statusSysId) {
    var devices = [];

    var device = new GlideRecord('discovery_device_history');
    device.addQuery('status', statusSysId);
    device.query();

    while (device.next()) {
        devices.push({
            ip_address: device.getValue('source'),
            ci: device.cmdb_ci.getDisplayValue(),
            ci_class: device.getValue('ci_type'),
            state: device.state.getDisplayValue(),
            issues: device.getValue('issue_count')
        });
    }

    return devices;
}
javascript
// 获取某次扫描的设备结果(仅支持ES5!)
function getDiscoveredDevices(statusSysId) {
    var devices = [];

    var device = new GlideRecord('discovery_device_history');
    device.addQuery('status', statusSysId);
    device.query();

    while (device.next()) {
        devices.push({
            ip_address: device.getValue('source'),
            ci: device.cmdb_ci.getDisplayValue(),
            ci_class: device.getValue('ci_type'),
            state: device.state.getDisplayValue(),
            issues: device.getValue('issue_count')
        });
    }

    return devices;
}

MCP Tool Integration

MCP 工具集成

Available Tools

可用工具

ToolPurpose
snow_query_table
Query discovery tables
snow_find_artifact
Find discovery configs
snow_execute_script_with_output
Test discovery scripts
snow_cmdb_search
Search discovered CIs
工具用途
snow_query_table
查询Discovery相关表
snow_find_artifact
查找Discovery配置项
snow_execute_script_with_output
测试Discovery脚本
snow_cmdb_search
搜索已发现的CI

Example Workflow

示例工作流

javascript
// 1. Query active schedules
await snow_query_table({
    table: 'discovery_schedule',
    query: 'active=true',
    fields: 'name,discover,run_type,mid_server'
});

// 2. Check recent discovery status
await snow_execute_script_with_output({
    script: `
        var status = getDiscoveryStatus('schedule_sys_id');
        gs.info(JSON.stringify(status));
    `
});

// 3. Find discovery errors
await snow_query_table({
    table: 'discovery_log',
    query: 'level=error^sys_created_on>=javascript:gs.daysAgo(1)',
    fields: 'message,source,sys_created_on'
});
javascript
// 1. 查询活跃的调度任务
await snow_query_table({
    table: 'discovery_schedule',
    query: 'active=true',
    fields: 'name,discover,run_type,mid_server'
});

// 2. 检查最近的Discovery运行状态
await snow_execute_script_with_output({
    script: `
        var status = getDiscoveryStatus('schedule_sys_id');
        gs.info(JSON.stringify(status));
    `
});

// 3. 查找Discovery错误日志
await snow_query_table({
    table: 'discovery_log',
    query: 'level=error^sys_created_on>=javascript:gs.daysAgo(1)',
    fields: 'message,source,sys_created_on'
});

Best Practices

最佳实践

  1. Credential Security - Use credential vault
  2. Schedule Off-Peak - Minimize network impact
  3. Range Management - Organize by network segment
  4. MID Server - Proper placement and sizing
  5. Identification - Clear matching criteria
  6. Reconciliation - Regular CMDB validation
  7. Monitoring - Track discovery health
  8. ES5 Only - No modern JavaScript syntax
  1. 凭证安全 - 使用凭证保险箱
  2. 非高峰时段调度 - 降低对网络的影响
  3. 扫描范围管理 - 按网络网段划分
  4. MID Server - 合理部署与规划规模
  5. 识别规则 - 明确匹配条件
  6. 数据对账 - 定期验证CMDB
  7. 监控 - 跟踪Discovery运行状态
  8. 仅支持ES5 - 不使用现代JavaScript语法