- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 hours ago
Hi,
My department is noticing that some of our Configuration Items are displaying incorrect locations in the cmdb_ci_list on our production instance. (See Location Issue-1 and Location Issue-5.) Our CI data comes from our NAC, and our Forescout transform map organizes the data and sends it to the cmdb_ci_list. (See Location Issue-2 - Location Issue-4, and the onBefore Transform Script.) The location seems to be based on the third octet of an IP address, but I can't find which transform field maps the third octet to the corresponding location. I tried to manually change the location for one of our CIs as a test in our UAT instance, since it, too, has Forescout. The location changed back to the old one, most likely due to a transform field. I can't seem to find which one it is.
(function runTransformScript(source, map, log, target /*undefined onStart*/ ) {
//ignore = true;
var cmdbUtil = new FSCMDBUtil();
var discoverSource = 'Forescout';
// sanity check
if (!cmdbUtil.sanityCheckOnSource(source)) {
gs.info("The record from Forescout Platform failed in sanity check. Skip creating configuration item");
return;
}
// Validate IP address and MAC address existence
var ipPresent = source.ip != null && source.ip.getDisplayValue().trim() != "";
var macPresent = source.mac != null && source.mac.getDisplayValue().trim() != "";
if (!ipPresent || !macPresent) {
gs.info("Skipping record due to missing IP or MAC address. IP: [" + source.ip + "], MAC: [" + source.mac + "]");
return;
}
var classname = cmdbUtil.getTargetClassName(source);
var value = {};
value.name = cmdbUtil.createNativeNameValue(source);
// Discovery source
value.discovery_source = discoverSource;
var tenant_id = "";
if (source.tenant_id != null) {
tenant_id = source.tenant_id.getDisplayValue();
} else {
tenant_id = source.x_ftpp_now_plat_forescout_tenant_id.getDisplayValue();
}
var sysObjSrcInfo = {};
sysObjSrcInfo.source_name = "Forescout";
//sysObjSrcInfo.source_feed = 'SG-Forescout Hardware';
var source_native_key_ip = "";
if (source.ip_version != null && source.ip_version.getDisplayValue() == "4") {
source_native_key_ip = source.ip;
}
sysObjSrcInfo.source_native_key = tenant_id + '|||' + source.mac + '|||' + source_native_key_ip + '|||' + source.dnsname;
// Tenant ID
//value.x_ftpp_now_plat_forescout_tenant_id = tenant_id;
// DNS Name to Fully qualified domain name
if (source.dnsname != null && source.dnsname.getDisplayValue() != "") {
value.fqdn = source.dnsname.getDisplayValue();
}
// set ip address
if (source.ip != null && source.ip.getDisplayValue() != "") {
value.ip_address = source.ip.getDisplayValue();
}
// User Directory Company to company
if (source.company != null && source.company.getDisplayValue() != "") {
var companyRd = new GlideRecord('core_company');
if (companyRd.canRead()) {
companyRd.addQuery('name', source.company.getDisplayValue());
companyRd.query();
if (companyRd.next()) {
value.company = companyRd.getValue('sys_id');
}
} else {
gs.debug("Forescout user doesn't have read permission to core_company. Skip mapping company");
}
}
// User Directory Department to department
if (source.department != null && source.department.getDisplayValue() != "") {
var departmentRd = new GlideRecord('cmn_department');
if (departmentRd.canRead()) {
departmentRd.addQuery('name', source.department.getDisplayValue());
departmentRd.query();
if (departmentRd.next()) {
value.department = departmentRd.getValue('sys_id');
}
} else {
gs.debug("Forescout user doesn't have read permission to cmn_department. Skip mapping department");
}
}
// Some more mappings for different classes
if (classname == 'cmdb_ci_computer' || classname == 'cmdb_ci_server' || classname == 'cmdb_ci_net_app_server') {
// Operating System to os for computer tables
if (source.os_classification != null && source.os_classification.getDisplayValue() != "") {
value.os = source.os_classification.getDisplayValue();
}
// OS Fingerprint to OS version and OS Service Pack
if (source.osfingerprint != null && source.osfingerprint.getDisplayValue() != "") {
// Example to map one string to multiple columns
// eg: before: Windows 7 64-bit Ultimate Service Pack 1
// eg: after: OS Version: Windows 7 64-bit Ultimate; OS Service Pack: Service Pack 1
var re = /(.*)(Service Pack.*)/i;
var osFields = re.exec(source.osfingerprint.getDisplayValue());
if (osFields) {
value.os_version = osFields[1];
value.os_service_pack = osFields[2];
}
}
}
if (classname == 'cmdb_ci_storage_device') {
// Device Interfaces to Device interface
if (source.device_interfaces != null && source.device_interfaces.getDisplayValue() != "") {
value.device_interface = source.device_interfaces.getDisplayValue();
}
}
if (classname == 'cmdb_ci_vm') {
// Open Ports to TCP Port
if (source.open_ports != null && source.open_ports.getDisplayValue() != "") {
value.tcp_port = source.open_ports.getDisplayValue();
}
}
var item = {};
var i = 0;
item.className = classname;
item.internal_id = i.toString();
item.sys_object_source_info = sysObjSrcInfo;
item.values = value;
var items = [item];
var referencedItems = [];
var relation = [];
var j = 0;
if (source.mac != null && source.mac.getDisplayValue() != "") {
i = i + 1;
var networkAdapterReference = cmdbUtil.createNetworkAdapterReference(source, sysObjSrcInfo.source_native_key, i);
if (source.nicvendor != null && source.nicvendor.getDisplayValue() != "") {
var vendorRd = new GlideRecord('core_company');
if (vendorRd.canRead()) {
vendorRd.addQuery('name', source.nicvendor.getDisplayValue());
gs.debug("Looking for vendor: " + source.nicvendor.getDisplayValue());
vendorRd.query();
if (vendorRd.next()) {
networkAdapterReference.values.manufacturer = vendorRd.getValue('sys_id');
networkAdapterReference.values.mac_manufacturer = vendorRd.getValue('sys_id');
gs.debug("vendor found: " + networkAdapterReference.values.mac_manufacturer);
} else {
vendorRd.name = source.nicvendor.getDisplayValue();
var retVendor = vendorRd.insert();
networkAdapterReference.values.manufacturer = retVendor;
networkAdapterReference.values.mac_manufacturer = retVendor;
gs.debug("vendor not found");
}
} else {
gs.debug("Forescout user doesn't have read permission to core_company. Skip mapping manufacture");
}
}
items[i] = networkAdapterReference;
var naReference = {};
naReference.referenceField = 'cmdb_ci';
naReference.referencedBy = i.toString();
naReference.referenced = '0';
referencedItems[j] = naReference;
var naRelation = {};
naRelation.child = i;
naRelation.parent = 0;
naRelation.type = 'Owns::Owned by';
relation[j] = naRelation;
j = j + 1;
}
if (source.ip != null && source.ip.getDisplayValue() != "") {
i = i + 1;
var ipAddrReference = cmdbUtil.createIPAddressReference(source.ip.getDisplayValue(), sysObjSrcInfo.source_native_key, i);
items[i] = ipAddrReference;
if (source.mac != null && source.mac.getDisplayValue() != "") {
var ipReference = {};
ipReference.referenceField = 'nic';
ipReference.referencedBy = i.toString();
ipReference.referenced = '1';
referencedItems[j] = ipReference;
}
var ipRelation = {};
ipRelation.child = i;
ipRelation.parent = 0;
ipRelation.type = 'Owns::Owned by';
relation[j] = ipRelation;
j = j + 1;
}
if (source.ipv6_address != null && source.ipv6_address.getDisplayValue() != "") {
var ipv6_addresses = source.ipv6_address.getDisplayValue().split(",");
for (var l = 0; l < ipv6_addresses.length; l++) {
if (ipv6_addresses[l] == "") {
continue;
}
gs.debug("Processing ipv6 address: " + ipv6_addresses[l] + " on iteration " + l);
i = i + 1;
gs.debug("is is " + i + " and l is " + l);
var ipv6AddrReference = cmdbUtil.createIPAddressReference(ipv6_addresses[l], sysObjSrcInfo.source_native_key, i);
items[i] = ipv6AddrReference;
if (source.mac != null && source.mac.getDisplayValue() != "") {
ipReference = {};
ipReference.referenceField = 'nic';
ipReference.referencedBy = i.toString();
ipReference.referenced = '1';
referencedItems[j] = ipReference;
}
ipRelation = {};
ipRelation.child = i;
ipRelation.parent = 0;
ipRelation.type = 'Owns::Owned by';
relation[j] = ipRelation;
// l = ipv6_addresses.length;
j = j + 1;
}
}
var record = {};
record.items = items;
record.relations = relation;
record.referenceItems = referencedItems;
////
////
var jsonUtil = new global.JSON();
var input = jsonUtil.encode(record);
gs.info("Transform CI using IRE with payload: " + input);
var output = sn_cmdb.IdentificationEngine.createOrUpdateCI(discoverSource, input);
//var output = sn_cmdb.IdentificationEngine.createOrUpdateCIEnhanced(discoverSource, input, {});
//var output = SNC.IdentificationEngineScriptableApi.createOrUpdateCI(discoverSource, input);
// If update failed, don't map other fields.
var outputCIs = jsonUtil.decode(output);
var outputItem = outputCIs['items'][0];
if ('errors' in outputItem) {
gs.info('IRE failed, skip updating source and other fields');
return;
}
// should have one ci inserted or updated
var ciSysID = outputItem['sysId'];
// map software instance as an example to map json format composite list property to table record
var softwares = source.windows_applications_installed.getDisplayValue();
if (softwares.length > 0) {
var softwareArray = softwares.split(",");
var k;
for (k = 0; k < softwareArray.length; k++) {
var software = softwareArray[k];
var pattern = /Name:\s*(.*)\n.*/;
var results = pattern.exec(software);
if (!results) {
continue;
}
var softwareName = results[1];
var softwareRecord = new GlideRecordSecure('cmdb_software_instance'); // If Software Asset Management package is installed, change the table to cmdb_sam_sw_install
softwareRecord.addQuery('name', softwareName.toString()); // If mapping to cmdb_sam_sw_install table, change name to display_name
softwareRecord.addQuery('installed_on', ciSysID.toString());
softwareRecord.query();
if (softwareRecord.next()) {
gs.debug("Sofware instance with name [" + softwareName + "] and installed on CI [" + ciSysID + "] already exist");
} else {
// map name column
softwareRecord.name = softwareName; // If mapping to cmdb_sam_sw_install table, change name to display_name
softwareRecord.installed_on = ciSysID; // If mapping to cmdb_sam_sw_install table, make sure this configuration item is under Hardware class
var ret = softwareRecord.insert();
gs.debug("Inserted software instance with name [" + softwareName + "] and installed on CI [" + ciSysID + "]");
}
}
}
})(source, map, log, target);
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 hours ago
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 hours ago
Hi @BenFan,
Based on the transform script you shared, I don't see the Location field being mapped or included in the IRE payload.
For example, there isn't any assignment similar to value.location = ...
IRE only updates attributes that are included in the payload. If location is not part of the payload, IRE itself will not update that attribute.
Since the Audit History shows the Location field was updated by NAC_End_User, check
Any Business Rules, Flow Designer flows, or Workflows on the CI tables.
Other Transform Maps, Field Maps, or Transform Scripts that may populate the location field.
Whether the NAC/Forescout integration performs a post-transform update to the CI after IRE processing.
The Audit History and System Logs are the best places to identify which process or integration last modified the field.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 hours ago
Okay thanks.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 hours ago
Hi @BenFan
- From location field Audit history , check by which user it is getting updated
- Check the Field Maps related list on your Transform Map. You may have a map field specifically named u_location, location, or a custom field explicitly designed to parse it
- Since you have customized script, review the code for hardcoded string parsing. Look for substring(), split(), or regular expressions that isolate the third octet of the IP address and dynamically assign it to target.location.
Regards
Tanushree Maiti
ServiceNow Technical Architect
LinkedIn: https://www.linkedin.com/in/tanushreemaiti
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
2 hours ago
So the Forescout CI Transform Map doesn't have location or u_location as a field map. See Location Issue-6 and Location Issue-7.
I do see a business rule called Update location as needed but the script doesn't address location based on the third octet in IP addresses. See Location Issue-8.
There is also another business rule for Forescout asset management, but it doesn't reference location. See Location Issue-9.