
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎07-17-2024 11:47 PM
Hello,
I'm looking for additional information about following 3 properties:
1. sn_sec_cmn.filterOutDecommissionedCI
My understanding is that if we have this property enabled, ServiceNow will not mach an vulnerability to retired CI, instead it will create new in Unclassed Hardware Class. If we disable this option then it will try to match an vulnerability to the retired CI. Is that correct ?
If above is correct and we had in the past this option set to true so system created many unmatched entries and created CIs in Unclassed Hardware Class , what is the best practice to get rid of these Cis ?
2. sn_sec_cmn.ignoreCIClass
This property defines which CI classes to ignore when running Security Operations CMDB CI lookup rules. What does it mean exactly ? Does it mean that during CMDB CI Lookup rules some classes can be ignored for matching process ?
IF for example I will add to this property cmdb_ci_lb_list, it will not try to find a much between vulnerability and CIs from this class, but my understanding is that "thanks" to this option system will create new CIs in Uncassed Hardware class and we will have Unmatched set at the end ? Is this is correct ?
3. sn_sec_cmn.autoPromoteFields
Can you provide me with detailed information what is it for and in which situation we should adjust this property ?
Thank you,
Zbigniew
Solved! Go to Solution.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎07-18-2024 05:32 AM
Hey there - great questions.
1. sn_sec_cmn.filterOutDecommissionedCI
- Correct - there's actually a notable enhancement here - in that it checks the older "Install Status" on potential target CI records, along with the newer CSDM "Life Cycle Stage Status" value
- If the "Install Status" is <Retired> or the CSDM "Life Cycle Stage Status" is <Retired> on a given CI, it will not be a candidate for the SecOps CI Lookup rules (i.e. it will be skipped)
- Unfortunately, changing the value on it - is not retroactive - it's more point in time
- There is a Re-Apply function on the SecOps CI Lookup Rules that may help if a retrofit is desired
- Notable tip:
- We may see a series of CIs in CMDB that appear to be "Retired" and a duplicate entry that is Not Retired
- We may also see that some CIs appear as Retired, but are still valid / live on the wire according to our 3rd party vuln scanner
- In our CI Lookup Rules, we can shape the matching logic to first attempt to match on "valid CIs" (i.e. not Retired).. then, if no match occurs, attempt to match to any Retired CIs as a fallback.. then, if no match occurs proceed to the creation of the CI (via IRE)
- This way, you have a fallback path - you still put preference to matching to valid CIs, but before giving up match to a retired CI if it exists - especially handy for higher fidelity attributes like DNS, FQDN, Hostname - not ideal for IP Addr, MAC addr
2. sn_sec_cmn.ignoreCIClass
- You are correct, when a host is brought in from the 3rd party scanner - and the SecOps CI Lookup Rules are invoked to attempt to find a matching CI in the CMDB, we can shape what CI Classes (or tables) we want to exclude matching on
- This may be useful, where our CI Lookup Rules are searching the entire [cmdb_ci] tables and we want to ignore certain CI Classes that may cause incorrect matches
- E.g. Web Sites, DNS, Certification Classes
- Notable tip: For Host / Infrastructure VR (e.g. Servers, Computers, Network Gear)
- You may want to look at shaping the CI Lookup Rules, to start with searching the Hardware table (and any table that extends hardware) ... i.e. [cmdb_ci_hardware]...
- This way, you are not querying the entire [cmdb_ci] table .. and then playing the game of ignoring irrelevant classes
- Start with the known good subset of CMDB (hardware and extended tables)
- If a match does not occur - the system doesn't actually directly go and create an Unclassed HW CI record
- The payload of the host / asset, is sent to ServiceNow CMDB IRE
- Then, IRE has it's own series of Lookup Rules (IRE Identifier Rules) that it runs to attempt to find a CI
- If IRE does not find a CI, then it inserts
- Only when the VR Scanner provides a Host with IP and another attribute, would it insert into Unclassed HW
- More details on this available at: https://www.servicenow.com/community/secops-articles/the-more-you-know-secops-and-cmdb-interactions-...
3. sn_sec_cmn.autoPromoteFields
- I actually like to refer to this as the "walk-up" property... which results in a "indirect match" to a CI
- When the SecOps CI Lookup Rules land on a "lower level CI" - such as an IP Address, IP NIC, IP Network Adapter, Virtual Network Adapter
- Instead of matching to that lower level device, attempt to "walk-up" to it's Parent CI
- Think of it as, the vuln scanner is reporting a "Windows vulnerability" .. that does not exist on the NIC or Network Adapter, but rather -- it exists on the actual Windows Server that the CI is connected to
- The way to setup the property, is to define comma separated values with
- ["the target lower level CI Class":"the reference field that has the actual CI you should walk-up to"]
- ["cmdb_ci_nic":"cmdb_ci"]

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-05-2024 08:06 AM
Hey there - your observations are correct.
Unfortunately, that property, if turned on - will be bound to all of the CI Lookup Rules and there isn't an easy way to shim it selectively onto specific rules.
------------------------------------------------------------------------
Curious - what observations have you seen in your environment?
Do you have scenarios, where a potential host is seen by your scanner, and the corresponding CI, has:
- x1 entry in CMDB -> retired
- x2 entries in CMDB -> one retired, one operational
If you need to turn that property off, you can add to the GlideRecord query in your existing CI Lookup Rules
- Operational Status or CSDM Lifecycle field
- SortBy, explicit "is / match", etc.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-05-2024 11:36 PM
Hello,
In my situation we have 1 operational CIs + 1 -2 retired Cis.
I will try going the way you described above. Thank you so much 🙂
Best regards,
Zbigniew

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-06-2024 02:42 AM - edited ‎08-06-2024 02:46 AM
Hello @andy_ojha
We ended up with following script that working fine for matching between DNS (Qualys) and Hostname (servicenow CMDB):
(function process(rule, sourceValue, sourcePayload) {
gs.log("Debug: Starting rule processing for sourceValue: " + sourceValue); // Log initial input
var sourceField = {};
var ignore = global.SecProperty.getProperty("sn_sec_cmn.ignoreCIClass", "");
sourceField[rule.source_field] = sourceValue;
var hostname = sourceValue.split('.')[0];
gs.log("Debug: Extracted hostname: " + hostname); // Log extracted hostname
var cmdbci = new GlideRecord("cmdb_ci");
cmdbci.addQuery("name", hostname);
if (!gs.nil(ignore)) {
cmdbci.addQuery('sys_class_name', 'NOT IN', ignore);
}
cmdbci.query();
if (cmdbci.hasNext()) {
gs.log("Debug: Found matching CI for hostname."); // Log if a match is found
var cmdbci = _queryMatch(cmdbci, rule, sourceValue); // Adjusted to use the query result directly
if (cmdbci) {
gs.log("Debug: Matched CI sys_id: " + cmdbci.getUniqueValue()); // Log the sys_id of the matched CI
return cmdbci.getUniqueValue();
}
} else {
gs.log("Debug: No existing CI matched for hostname: " + hostname); // Log if no match is found
}
return null; // Optionally create a new CI or return null
})(rule, sourceValue, sourcePayload);

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-06-2024 07:43 AM
Hey there - Sorry about that...
Appears our old trick is no longer compatible 😞
What's happening now, is when the system detects multiple CIs are candidates for a match (even with our OrderBy) --> it is overriding that...
- You can also see this reflected on the Discovered Item, on the field "Other Matched CIs"
The Script Include "CIIdentify" and function "logDupWhileIdentifying" are controlling this behavior - In the logs, you'll see something like
- "Found duplicate CI while identifying rule 'Custom Test Retired ' 15100d22c3738210c8c37e2a05013190 source values={"DNS":"server1234.test.org"} deciding to return this CI 'a57b6fc31b158150cbd142e8b04bcb77'"
1) In the Lookup Rule itself, perform two lookups
a) Happy-path -> try to find non-retired first and return those values
b) Fallback and return any value we find
2) Split our Lookup Rules apart - which can be useful for troubleshooting and tuning
- On the Discovered Items you could see which CI Lookup Rules won on each record
- Retired Rules vs Non-Retired Rules, etc.
cmdbci.addEncodedQuery("operational_status!=6"); // Not Retired
// _queryMatch function checks if the query returns 0, 1 or more than 1 CI.
// it returns:
// null: if no CI found
// ci record: if a unique CI was found
// the first CI record found: if more than 1 CI was found and log a duplicate error message
// To avoid specific CI classes ,add the class names, comma separated, to the property sn_sec_cmn.ignoreCIClass
(function process(rule, sourceValue, sourcePayload) {
var sourceField = {};
var ignore = global.SecProperty.getProperty("sn_sec_cmn.ignoreCIClass", "");
sourceField[rule.source_field] = sourceValue;
gs.info('VR Log - Incoming Host for testing: ' + sourceValue);
var hostname = sourceValue.split(".")[0];
gs.info('VR Log - Parsed host: ' + hostname);
// *** ACTIVE CI SEARCH ***
var cmdbci = new GlideRecord("cmdb_ci");
cmdbci.addQuery("name", hostname);
if (!gs.nil(ignore))
cmdbci.addQuery('sys_class_name', 'NOT IN', ignore);
//cmdbci.orderBy("operational_status"); //Ascending -> Retired = 6, Operational = 1
cmdbci.addEncodedQuery("operational_status!=6"); // Not Retired
cmdbci.query();
cmdbci = _queryMatch(cmdbci, rule, sourceField);
if (cmdbci)
return cmdbci.getUniqueValue();
return null;
})(rule, sourceValue, sourcePayload);

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎08-07-2024 02:22 AM
Hello @andy_ojha
Thank you for your reply and solution. It looks to be working fine :')
At the end Im going to use two rules:
1. Rule which will be queering All Not Retired Cis - if no match found then
2. Rule which will be queering All Cis including also Retired Cis.
Thank you for your script , all hints as they helped me to develop final solution. Really appreciate that 🙂
Best regards,
Zbigniew