- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Printer Friendly Page
- Report Inappropriate Content
In part four I reveal my madness! You probably were saying to yourself: where is Bell going with all of this? What could possibly be his motive for beating us to death with SoapUI and Web Services stuff? Has he gone off the rails?
Um, well probably, on that last bit, but there really was a method to what I was about!
One of the things I get asked for, quite-a-bit: Is it possible to add new functionality to the Help-the-Help-Desk (HtHD) script. Short answer: No. Everything is hard-coded by ServiceNow, and though you can modify the script the software on your instance will not recognize the new elements that have been added to the inbound XML. I've tried it. It does not work.
So, noodling on this for awhile it dawned on me that there was actually a way to utilize the HtHD script and change the short answer to Yes! Instead of going the normal route through the ECC Queue, why don't we use a Scripted Web Service that would receive all of our new values and write them to the same record? This, of course, would have to be done after the HtHD normal processing had ended. The ECC Queue is slower than a web service, and that has to be taken into account.
This would require that we add to the HtHD script. No biggy as it is simply a JavaScript file. So using the same methodology that we used when messing with SoapUI we create our own XML and send-to-web-service method, and tack it all onto the end of the HtHD JavaScript file.
Caveat:
1) This can currently only be done via the Microsoft Windows operating system.
Requirements:
1) For this you will need to have completed part 1 and part 3 of this article series. You will need to know how to create and test a Scripted Web Service.
2) We will be modifying the Scripted Web Service you created in part 3.
a. The modified script will need to be able to use the existing OOtB HtHD Script Include to test if the CI record exists to be updated. This SI is documented here Section 2.1.
b. It will need to wait and retry three times before erroring out.
3) Part 3 also adds the new fields to the Computer table that we will be populating from our HtHD modified script.
4) Download and modify the OOtB HtHD script to use WMI to collect our new values and then call into our Scripted Web Service.
5) To test we will be running the HtHD script from the Windows command line (cmd.exe).
Lab 1.1: Modifying the Scripted Web Service
We will be modifying the Scripted Web Service that we created in the last article to utilize the CIIdentifierForHelpDesk script include, and then do a series of retries. The number of retries will be configurable by utilizing a new System Property.
1. Create a new System Properties: Wait Time, Number of Retries.
a. Log onto your instance.
b. Navigate to sys_properties.list. The System Properties list view will be displayed.
c. Click the New button. The new system property form will be displayed.
d. Fill in the form with the following:
i. Name: sws.hthd.number_of_retries
ii. Description: Number of times the HtHD Scripted Web Service will retry an update to a given Configuration Item.
iii. Type: Integer
iv. Value: 3
v. Click Submit to Save your Work. The System Properties list view will be redisplayed.
e. Click the New button. The new system property form will be displayed.
f. Fill in the form with the following:
i. Name: sws.hthd.wait_time
ii. Description: Amount of time in milliseconds to wait between retries
iii. Type: Integer
iv. Value: 5000
2. Modify the Scripted Web Service:
- Use CIIdentiferForHelpDesk.matchOnSerial(...) to locate the appropriate CI to update. This is the same method used by HtHD so we should be pretty safe using it to do what we want. We will be putting this in a retry loop to account for a new CI being placed in CMDB by HtHD (at a retry of 5 seconds wait each that would be a total of a 15 second wait which should be plenty of time).
- Use new System Properties, and handle the wait and retry. Make sure that defaults exist so there are no infinite loops!
- Use the message stacking technique to bring all of the gs.logs together.
- Use try/catch to make sure nothing horrible happens.
a. Navigate to System Web Services -> Scripted Web Services. The Scripted Web Services list view will be displayed.
b. Locate and edit it up the scripted web service UpdateComputerCI we created in the Part 3 article.
c. Replace the Script with the following:
var message = '';
try {
message += '--->soapRequestXML: ' + soapRequestXML + '\n';
xmldoc = new XMLDocument(soapRequestXML);
var serialNumber = xmldoc.getNodeText("//serial_number") + '';
var sys_id = '';
var i = 0; // retry count
// go get our system properties
var numberOfRetries = gs.getProperty('sws.hthd.number_of_retries', 1);
var waitTime = gs.getProperty('sws.hthd.wait_time', 1000);
// start the loop, break if we find a CI
while (i < numberOfRetries) {
// use HtHD matchOnSerial to locate our CI by serial number
sys_id = new CIIdentifierForHelpDesk().matchOnSerial(serialNumber);
i += 1;
if (JSUtil.nil(sys_id)) {
message += '---> having to retry. retry: ' + i + '\n';
// not found, sleep and try again
Packages.java.lang.Thread.sleep(waitTime);
}
else {
// we found it so we can stop
break;
}
}
// We didn't find the CI, throw an error
if (JSUtil.nil(sys_id)) {
throw 'Serial Number: ' + serialNumber + ' not found! Cannot update.';
}
message += '---> sys_id: ' + sys_id + '\n';
// We found the CI, now update it
var cpuSocket = xmldoc.getNodeText("//cpu_socket") + '';
var cpuArchitecture = xmldoc.getNodeText("//cpu_architecture") + '';
var cpuProcessorType = xmldoc.getNodeText("//cpu_processor_type") + '';
var cpuFamily = xmldoc.getNodeText("//cpu_family") + '';
var cpuStatus = xmldoc.getNodeText("//cpu_status") + '';
var computerRecords = new GlideRecord('cmdb_ci_computer');
if (computerRecords.get(sys_id)) {
computerRecords.u_cpu_socket = cpuSocket;
computerRecords.u_cpu_architecture = cpuArchitecture;
computerRecords.u_cpu_processor_type = cpuProcessorType;
computerRecords.u_cpu_family = cpuFamily;
computerRecords.u_cpu_status = cpuStatus;
computerRecords.update();
}
}
catch (err) {
message += '---> ERROR: ' + err + '\n';
}
gs.log(message, 'SWS: UpdateComputerCI');
d. Your Scripted Web Service should now look something like this:
e. Click the Update button to save your work.
Ok, that part is done. Now on to modifying the HtHD Script!
Lab 1.2: Modifying the Help-the-Help-Desk.js File
We will be modifying the HtHD script to include all five of the new CPU data fields we added to the cmdb_ci_computer table.
1. Download the file from your instance to your local account. Location is not really important as long as you know where it is to modify and run it.
2. Rename the downloaded file from helpthehelpdesk.jsdbx to helpthehelpdesk.js.
3. Edit the file in your favorite JavaScript editor (I used Notepad++).
4. Change the "server" variable to be your local instance.
var server = "https://dev00001.service-now.com/";
5. Change the "httpUsername" variable to be your "svcuser" user name.
var httpUsername = "svcuser";
6. Encrypt the password and change the "httpPassword" variable to be your encrypted password value.
a. In your ServiceNow instance navigate to System Definition -> Help the Help Desk. This will display the Properties for HtHD. We will be using the username and password that we created in the Part 1 article.
b. Click on the Save button. This will automatically encrypt your password.
c. Copy the password and place it to one side for use in the next step.
d. Modify the httpPassword line by pasting your encrypted password here. It should look something like this:
var httpPassword = "encrypt:ZZ4moXYz123aBcD=";
6. Change the "DEBUG" value to "true".
var DEBUG = true;
7. Change the g_routines variable to include a call to our new method.
var g_routines = [
[ "OS Check", "win9X()", false ],
[ "Getting OS Configuration", "getMachine()", true ],
[ "Gathering Disk Configuration", "getLogicalDisks()", true ],
[ "Gathering Network Configuration", "getNetworkAdapters()", true ],
[ "Gathering Printer Configuration", "getPrinters()", true ],
[ "Connecting to registry", "connectRegistry()", true ],
[ "Gathering Software Licenses", "getSoftwareLicenses()", true ],
[ "Gathering Microsoft Licenses", " getMicrosoftLicenses()", true ],
[ "Gathering Software Configuration", "getSoftware()", true ],
[ "Communicating", "eccEvent()", true ],
[ "Getting Super Special Information", "UpdateComputerCI()", true ]
];
8. Add the following code to the end of the script:
/*
1. Use Win32 to retrieve local CPU values
2. Call a Scripted Web Service to store those values in CMDB for this box
*/
function UpdateComputerCI() {
var serialNumber = '';
var cpuSocket = '';
var cpuArchitecture = '';
var cpuProcessorType = '';
var cpuFamily = '';
var cpuStatus = '';
// Initialize our WMI query
var items = gCIMV2Service.ExecQuery("Select * from Win32_ComputerSystemProduct");
var enumItems = new Enumerator(items);
for (; !enumItems.atEnd(); enumItems.moveNext()) {
var item = enumItems.item();
serialNumber = item.IdentifyingNumber;
}
// Query for Processor information - specifically for CPU info
var items = gCIMV2Service.ExecQuery("Select * from Win32_Processor");
var enumItems = new Enumerator(items);
for (; !enumItems.atEnd(); enumItems.moveNext()) {
var specialItem = enumItems.item();
debug('---> SocketDesignation: ' + specialItem.SocketDesignation);
cpuSocket = specialItem.SocketDesignation;
debug('---> Status: ' + specialItem.Status);
cpuStatus = specialItem.Status;
debug('---> Family: ' + getFamily(specialItem.Family));
cpuFamily = getFamily(specialItem.Family);
debug('---> ProcessorType: ' + getProcessorType(specialItem.ProcessorType));
cpuProcessorType = getProcessorType(specialItem.ProcessorType);
debug('---> Architecture: ' + getArchitecture(specialItem.Architecture));
cpuArchitecture = getArchitecture(specialItem.Architecture);
}
// Initialize our SOAP XML
xmlSOAP = new ActiveXObject("Microsoft.XMLDOM");
var xmlTitle = xmlSOAP.createProcessingInstruction("xml", "version=\"1.0\"")
xmlSOAP.appendChild(xmlTitle);
// Set up our SOAP Envelope
var soapEnvelope = xmlSOAP.createElement("soap:Envelope");
soapEnvelope.setAttribute("xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/");
soapEnvelope.setAttribute("xmlns:upd", "http://www.service-now.com/UpdateComputerCI");
xmlSOAP.appendChild(soapEnvelope);
// Create the Body tags
var soapBody = xmlSOAP.createElement("soap:Body");
soapEnvelope.appendChild(soapBody);
// Create the Payload tags
var payload = xmlSOAP.createElement("payload");
soapBody.appendChild(payload);
// Add our fields to the payload XML
addField(payload, "serial_number", serialNumber);
addField(payload, "cpu_socket", cpuSocket);
addField(payload, "cpu_architecture", cpuArchitecture);
addField(payload, "cpu_processor_type", cpuProcessorType);
addField(payload, "cpu_family", cpuFamily);
addField(payload, "cpu_status", cpuStatus);
// Send the SOAP XML to the Scripted Web Service
sendRequest(server + "UpdateComputerCI.do?SOAP", null, xmlSOAP);
}
// Return english value of numbered architecture field
// Derived from values found at: https://msdn.microsoft.com/en-us/library/windows/desktop/aa394373(v=vs.85).aspx
function getArchitecture(archIndex) {
var archType = ["x86", "MIPS", "Alpha", "3", "PowerPC", "ARM", "ia64", "7", "8", "x64"];
return archType[archIndex];
}
// Return english value of numbered family field. This is a 1-based value so will be offset by one.
// Derived from values found at: https://msdn.microsoft.com/en-us/library/windows/desktop/aa394373(v=vs.85).aspx
function getFamily(familyIndex) {
var familyType = [
"Other","Unknown","8086","80286","Intel386 Processor","Intel486 Processor",
"8087","80287","80387","80487","Pentium Brand","Pentium Pro","Pentium II",
"Pentium Processor with MMX Technology","Celeron","Pentium II Xeon","Pentium III",
"M1 Family","M2 Family",
"20","21","22","23","AMD Duron Processor Family","K5 Family","K6 Family",
"K6-2","K6-3","AMD Athlon Processor Family","AMD2900 Family","K6-2+","Power PC Family",
"Power PC 601","Power PC 603","Power PC 603+","Power PC 604","Power PC 620","Power PC X704",
"Power PC 750",
"40","41","42","43","44","45","46","47","Alpha Family","Alpha 21064",
"Alpha 21066","Alpha 21164","Alpha 21164PC","Alpha 21164a","Alpha 21264","Alpha 21364","56","57","58","59",
"60","61","62","63","MIPS Family","MIPS R4000","MIPS R4200","MIPS R4400","MIPS R4600","MIPS R10000",
"70","71","72","73","74","75","76","77","78","79",
"SPARC Family","SuperSPARC","microSPARC II","microSPARC IIep","UltraSPARC",
"UltraSPARC II","UltraSPARC IIi","UltraSPARC III","UltraSPARC IIIi","89",
"90","91","92","93","94","95","68040","68xxx Family","68000","68010",
"68020","68030","102","103","104","105","106","107","108","109",
"110","111","Hobbit Family","113","114","115","116","117","118","119",
"Crusoe TM5000 Family","Crusoe TM3000 Family","Efficeon TM8000 Family",
"123","124","125","126","127","Weitek","129",
"Itanium Processor","AMD Athlon 64 Processor Family","AMD Opteron Processor Family",
"133","134","135","136","137","138","139","140","141","142","143",
"PA-RISC Family","PA-RISC 8500","PA-RISC 8000","PA-RISC 7300LC","PA-RISC 7200",
"PA-RISC 7100LC","PA-RISC 7100",
"151","152","153","154","155","156","157","158","159",
"V30 Family","161","162","163","164","165","166","167","168","169",
"170","171","172","173","174","175","Pentium III Xeon Processor",
"Pentium III Processor with Intel SpeedStep Technology","Pentium 4","Intel Xeon",
"AS400 Family","Intel Xeon Processor MP","AMD Athlon XP Family","AMD Athlon MP Family",
"Intel Itanium 2","Intel Pentium M Processor",
"186","187","188","189","K7",
"191","192","193","194","195","196","197","Intel Core i7-2760QM","199",
"IBM390 Family","G4","G5","G6","z/Architecture Base","205","206","207","208","209",
"210","211","212","213","214","215","216","217","218","219",
"220","221","222","223","224","225","226","227","228","229",
"230","231","232","233","234","235","236","237","238","239",
"240","241","242","243","244","245","246","247","248","249",
"i860","i960","252","253","254","255","256","257","258","259",
"SH-3","SH-4","262","263","264","265","266","267","268","269",
"270","271","272","273","274","275","276","277","278","279",
"ARM","StrongARM","282","283","284","285","286","287","288","289",
"290","291","292","293","294","295","296","297","298","299",
"6x86","MediaGX","MII","303","304","305","306","307","308","309",
"310","311","312","313","314","315","316","317","318","319",
"WinChip","321","322","323","324","325","326","327","328","329",
"330","331","332","333","334","335","336","337","338","339",
"340","341","342","343","344","345","346","347","348","349",
"DSP","351","352","353","354","355","356","357","358","359"];
return familyType[familyIndex - 1];
}
// Return english value of Processor Type field. This is a 1-based value so will be offset by one.
// Derived from values found at: https://msdn.microsoft.com/en-us/library/windows/desktop/aa394373(v=vs.85).aspx
function getProcessorType(procTypeIndex) {
var procType = ["Other", "Unknown", "Central Processor", "Math Processor", "DSP Processor", "Video Processor"];
return procType[procTypeIndex - 1];
}
// Return english value of Status Info field. This is a 1-based value so will be offset by one.
// Derived from values found at: https://msdn.microsoft.com/en-us/library/windows/desktop/aa394373(v=vs.85).aspx
function getStatusInfo(statusIndex) {
var statusInfoType = ["Other", "Unknown", "Enabled", "Disabled", "Not Applicable"];
return statusInfoType[statusIndex - 1];
}
NOTE:
I derived this code from initPayload, getMachine, etc. The idea was to not mess with the existing OOtB script too much, but to rather tack the new code to the end; as much as possible. I could have rewritten the whole thing, but instead took a minimalist approach. In the process I stripped out a lot of the checking that probably should have been done, but I needed to leave you something to do! Right?!
Also, I threw in a quick-and-dirty way of translating the resultant coded values from Microsoft into something more useful in ServiceNow.
9. Save.
Lab 1.3: Testing
1. In Microsoft Windows navigate to Start and type in "cmd.exe" in the Search Commands and Files field. Then click on cmd.exe to open a command window. I always open this by right-clicking it to bring up the context menu and choosing "Run as Administrator" just to be safe.
2. Change directories (CD) to where the modified helpthehelpdesk.js now lives (you will probably want to rename this for production purposes).
3. Run the script using CScript. Observe the results.
a. From the command line type the following and hit enter: cscript helpthehelpdesk.js
We are interested with what shows last. Our five new fields should be displayed at the end of the run with their respective values:
4. Checking the HtHD Status: Status
a. Navigate to System Definition -> Help the Help Desk Status. The HtHD status list view will be displayed.
b. Order by Created date descending.
c. Click on the link of the most recent job that was run. The HtHD Status form will be displayed. Since we tested against our own device (laptop, desktop, or whatever) there should be a CI listed with a status of Created CI or Updated CI.
NOTE: If you are seeing this form everything worked as expected. If not see Running HtHD, and follow the instructions to get it working right.
5. Go to the ECC queue. We will just be verifying further that the normal HtHD script functioned.
a. Navigate to ECC -> Queue. The ECC Queue list view will be displayed.
b. Order by Created date descending.
c. Filter for Topic: WMILoader
d. You should see the most recent run of HtHD. This will have a Name: of wmi.script, and a Source of your boxes name.
6. Now to check on whether our Scripted Web Service worked. Navigate to the System Logs -> System Log -> All, and filter on Message: --->soap. This should display the logged messages, and if everything worked should look like this:
7. Go to the CI and view the results.
a. Navigate to Configuration -> Base Items -> Computers. This will display a list view of all Computer CIs.
b. Order by Updated date descending. Your device should be the first record.
c. Edit it up your device by clicking on the link. The Computer CI form should be displayed.
d. Note the values placed in our new fields by the HtHD script. Your form should look something like this:
NOTE: You might want to clear the fields before testing.
Now let's test our retry code!
8. New CI Creation Test
a. Go to Configuration -> Base Items -> Computers. The Computers list view will be displayed.
b. Edit up your computer's CI, and click the Delete button. The Delete Warning form will be displayed. Click the Delete button to delete your CI. This will reset everything for our test.
c. Now from the cmd.exe window re-run our test: cscript helpthehelpdesk.js
d. Navigate to the System Logs -> System Log -> All, and filter on Message: --->soap. This should display the logged messages. You should now see a couple of retries in the log:
NOTE: If you were paying close attention you should have noticed that the HtHD script took a bit longer to run. That is because there is a synchronous connection with the Web Service, and the cscript is waiting on the Scripted Web Service to complete before completing itself. I believe this is a reason that the original HtHD developers chose to go with the ECC Queue which is Asynch. So there is a bit of a trade-off here. You could go with REST. Just saying.
There you go! You now have a way to add additional values to the HtHD Script.
More references you might want to read up on:
I placed all of the files for this article out on the Share here.
Steven Bell
If you find this article helps you, don't forget to log in and "like" it!
Also, if you are not already, I would like to encourage you to become a member of our blog!
Please Share, Like, Comment this blog if you've found it helpful or insightful.
For other Expert Knowledge
Ask A Developer What's In Store For IT Leaders in 2016 ServiceNow Online Learning Courses ServiceNow Foundations: User Interface
- 4,911 Views
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.