- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-11-2022 05:54 AM
Hello Community,
I plan to propose "Service Graph connector for Microsoft Intune (2.1.2)" to one of our customers to bring information about their mobile phones and windows computers into CMDB.
The documentation for Rome (and later) says: "The Service Graph connector for Microsoft Intune pulls data from mobile devices, computers, and software applications into the ServiceNow® Configuration Management Database (CMDB) application. The integration provides greater visibility into mobile devices, computers and related software applications that run on them."
However, the Store application description says: "The Service Graph Connector for Microsoft Intune supports import of the following device classes: Mobile Device (Handheld Computing), Mobile Apps". Also old documentation for Quebec says only about mobile devices: "The Service Graph connector for Microsoft Intune pulls data from mobile devices and software applications into the ServiceNow® Configuration Management Database (CMDB) application." even the version of SGC is the same (2.1.2).
So will Service Graph Connector populate information about Windows computers (not mobile phones) into CMDB? If not - what would be ServiceNow recommended solution? I heard about building a custom integration using Integration Hub and Intune Spoke...
Thanks in advance!
Solved! Go to Solution.
- Labels:
-
Service Graph Connector

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
02-22-2023 09:42 PM
Hi @Marek Meres ,
I am using SG - Intune and we are able to pull Windows computers into CMDB, you can also customize to bring additional attributes.
Regards,
Vinil.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-25-2023 02:03 AM
Hello @naxis alx and @Deepa Biyani2 ,
I have created a complete copy of the integration first to keep the ServiceNow original intact. So in the script below you will find 'sn_intune_integrat.my_intune_computers' instead of ootb 'sn_intune_integrat.computers'. If you do not make a copy you can use the ootb name instead.
The main part of the workaround is modified script in the Data Source. Here the one from the 'Computer' one (the 'Devices' differs on the 'cleaseSN' function to mimic the ootb function used in the RTE):
(function loadData(import_set_table) {
// **** Customization starts (part 1 = custom function)
// defining function to mimic Cleanse Serial Number RTE Operation
// ideally this could be reused directly here - check out how...
function cleanseSN(input) {
var invalidStrings = ['to be set', 'defaultstring'];
if (!input) return '';
var valid = new global.SerialNumberManager().isValid(input);
if (valid) {
var output = input;
var inputLowercase = input.toLowerCase();
for (j = 0; j < invalidStrings.length; j++) {
if (inputLowercase.includes(invalidStrings[j])) {
output = '';
break;
}
}
// **** added case when serialNumber = '0' (should not be added to invalidStrings to allow values containing '0' in them)
if (input == '0') output = '';
return output;
} else
return '';
}
// **** Customization ends (part 1 = custom function)
try {
var connectionAliasSysId = "8f94801cb731101077b21d4efe11a930";
var connectionAliasGr = new GlideRecord("sys_alias");
connectionAliasGr.query("sys_id", connectionAliasSysId);
connectionAliasGr.query();
if (!connectionAliasGr.next()) {
gs.error(gs.getMessage("No connection alias found"));
throw "Unable to find connection alias with sys_id " + connectionAliasSysId;
}
var connection = {
"connectionalias": connectionAliasGr
};
// **** Customization starts (part 2 = added pre-read and filtering duplicated serial numbers)
// Version 2 - reading the whole stream first, detect duplicated SNs and store most recent record in an object
// then reading the stream again, checking each incoming SN and if found a duplicated one allowing only the most recent in
// object to store all SNs and enrollment dates sent for processing
var sns = {};
// first preRead from Intune to collect SNs (only newest enrollmentDate for a duplicated SNs)
// using copy of the Data Stream Action to separate from ootb setup completely
var streamPreRead = sn_fd.FlowAPI.executeDataStreamAction('sn_intune_integrat.my_intune_computers', connection);
while (streamPreRead.hasNext()) {
var device = streamPreRead.next();
// using values cleansed by function mimicking "Cleanse Serial Number" RTE Operation
var serial = cleanseSN(device.serialNumber);
if (serial) {
var enrDateTxt = device.enrolledDateTime;
var enrDateDT = new GlideDateTime(enrDateTxt);
// *** check if SN already in object
if (serial in sns) {
// check if enrollment date stored in obj newer than current
var exEnrDT = sns[serial];
// if current enrollment date is newer than in stored one replacing the date in object
if (enrDateDT > exEnrDT) {
gs.info("My-Intune: replacing date " + exEnrDT + " in temp object with newer date " + enrDateDT+ " for SN=" + serial);
sns[serial] = enrDateDT;
}
} else {
// adding sn to object
sns[serial] = enrDateDT;
}
}
} // end of preRead from Intune to collect SNs
gs.info("My-Intune: finished first preRead at: "+new GlideDateTime());
// **** Customization ends (part 2 = added pre-read and filtering duplicated serial numbers)
// second read from Intune to push only correct records for processing into import set
// using copy of the Data Stream Action to separate from ootb setup completely
var stream = sn_fd.FlowAPI.executeDataStreamAction('sn_intune_integrat.my_intune_computers', connection);
var maxRows = import_set_table.getMaximumRows();
var counter = 0;
// Process each item in the data stream
while (stream.hasNext()) {
if (maxRows > 0 && counter >= maxRows)
break;
counter++;
// Get a single item from the data stream.
var device = stream.next();
// **** Customization starts (part 3 = skipping records with duplicated serial numbers allowing only newest to go for processing)
// using values cleansed by function mimicking "Cleanse Serial Number" RTE Operation
var serial = cleanseSN(device.serialNumber);
var insertIt = true;
// only processing non-empty cleansed Serial numbers
if (serial) {
var enrDateTxt = device.enrolledDateTime;
var enrDateDT = new GlideDateTime(enrDateTxt);
// check if SN in object (false only if new device has been registered in Intune since preRead)
if (serial in sns) {
// check if enrollment date stored in obj newer than current
var exEnrDT = sns[serial];
// if stored enrollment date is newer than in current skipping the record
if (exEnrDT > enrDateDT) {
gs.info("My-Intune: skipping record with SN=" + serial + " with enrD=" + enrDateDT + " due to newer record with the same SN found with enrollmentDate=" + exEnrDT);
insertIt = false;
} else if (exEnrDT < enrDateDT) {
// here hypothetical situation a newer registration with existing SN was done since preRead - just noting
gs.info("My-Intune: allowing new record with SN=" +serial+" and enrollmentDate="+enrDateDT+" newer than recorded before: "+exEnrDT);
}
} else {
// if serial not in sns just noting to investigation, no point in re-reading forever...
gs.info("My-Intune: allowing new record with SN=" +serial+" without checking for duplicates");
}
// empty or cleansed serial numbers allowed without any checks
}
// making inserting conditional
if (insertIt) import_set_table.insert(device);
// **** Customization ends (part 3 = skipping records with duplicated serial numbers allowing only newest to go for processing)
} // end of main while loop
} catch (ex) {
var actualMessage = ex.getMessage();
gs.error("My-Intune: Actual Error: " + actualMessage);
var intuneIntegUtil = new IntuneIntegrationUtil();
var modifiedMessage = intuneIntegUtil.checkHttpReturnCode();
gs.error("My-Intune: Custom Error: " + modifiedMessage);
throw modifiedMessage;
} finally {
if (stream)
stream.close();
}
})(import_set_table);
I also changed the Transforms (using Integration Hub ETL) to avoid identification on internal Intune's "DeviceID" and skip creating separate cmdb_serial_number and cmdb_ci_network_adapter CIs. These did not bring any value but instead made identification much more problematic and difficult to track and investigate. So as the result of these other changes CIs were identified in CMDB only on 'Serial Number' first (the attribute on the main CI, not cmdb_serial_number auxiliary CI) and (if not found) on 'Name'. The script only deduplicates on 'Serial Number' thus duplicated 'Names' are still a problem but I consider it having much less impact (based on data analysis). You can expand the workaround to check both though although it would complicate it further...
Best regards,
Marek