Adding sys_id to a report, the easy way

Hi All, long time no post. Figured I’d ease back into this whole blogging thing with an easy post, to start to get the gears turning again!

Little known fact, is that you can actually export in a list the sys_id field, and even add it to a report. The quick and dirty way to do this, is to just export the XML of the sys_report record, update the field_list field and then import back the XML.

There might be a number of different reasons why you want the sys_id in a report, so you can easily match back up to the unique identifier in ServiceNow for the record. It could even be used to reverse craft the URL as well.

Here is an even easier direct user friendly way to add this capability on all List view reports using a UI action. First users need to navigate to the sys_report table and identify their report, then they can just click this simple UI action!

The UI action has two simple lines of code:

current.field_list += ",sys_id";
current.update();

Download and try this UI action in your instance!
AddSysIDToReport sys_remote_update_set_cd2f7e39c3a30210d419de1d050131ab.xml

Log4j MID Server Fix Script

I know many people have been scrambling after the announcement of the Log4J vulnerability, and ServiceNow is not unscathed entirely. The MID server packages that are provided by ServiceNow, even in the latest version at the time of writing contain the vulnerability as a dependency, even though they don’t claim to use them. If you’re on the current MID server patch your Log4J is probably like version 2.14 or older and you need this fix.

The only workaround is to manually stop the service, delete and replace the jar files, and restart the service (described on KB1001211). Rinse and repeat for every MID server, and after every single patch or upgrade to the system, until ServiceNow decides to update it.

If you’re like me and have started going a little crazy, I’ve come up with a decent partially scripted solution for at least Windows MID servers! I hope others can make use of this trick to remediate their issue in a quicker and consistent manner.

Step 1. Download the latest jars of Log4j that are secure from logging.apache.org (currently v2.17.1). Save the ZIP to your desktop, extract and locate the log4j-api.jar, log4j-core.jar, and log4j-slf4j-impl.jar files.
Note: If they aren’t renamed exactly like log4j-core.jar, you will need to rename the file manually.

Step 2. Create a Local update set in your instance.

Step 3. Upload the 3 Jar files as a MID Server Jar file. Navigate to MID Server > JAR Files, click New, and fill out the name, version, description, and upload the file and save. Repeat for the 3 jar files.

Step 4. Create this MID server script file with the name as “Log4j.ps1” and this as the script:

#Run the following command using admin powershell terminal
#Usage>."D:\MyMIDServer\agent\scripts\Log4j.ps1"

#Primary MID Server Install path
$scriptsPath = split-path -parent $MyInvocation.MyCommand.Definition
$agentPath = split-path -parent $scriptsPath
Write-Output "Auto detected agent path as $agentPath"

#Path where all the new jars are located
$extlib = $agentPath + "\extlib\"

$startbat = $agentPath + "\start.bat"
$stopbat = $agentPath + "\stop.bat"

$extfile1 = $extlib + "log4j-api.jar"
$extfile2 = $extlib + "log4j-core.jar"
$extfile3 = $extlib + "log4j-slf4j-impl.jar"
$mainlib = $agentPath + "\lib\"
$file1 = $mainlib + "log4j-api.jar"
$file2 = $mainlib + "log4j-core.jar"
$file3 = $mainlib + "log4j-slf4j-impl.jar"

$file1exist = Test-Path $extfile1
$file2exist = Test-Path $extfile2
$file3exist = Test-Path $extfile3
#Write-Host "($file1exist) -and ($file2exist) -and ($file3exist)"

if (($file1exist) -and ($file2exist) -and ($file3exist)){
  Write-Output "Stopping MID Server Process"
  Start-Process -FilePath $stopbat -Wait -NoNewWindow

  Remove-Item -Path $file1 -Force
  Remove-Item -Path $file2 -Force
  Remove-Item -Path $file3 -Force
  Write-Output "Old Jar Files Removed successfully."

  Copy-Item -Path $extfile1 -Destination $mainlib
  Copy-Item -Path $extfile2 -Destination $mainlib
  Copy-Item -Path $extfile3 -Destination $mainlib
  Write-Output "New Jar Files Copied successfully."

  Start-Sleep -Seconds 1.5
  Write-Output "Starting MID Server Process"
  Start-Process -FilePath $startbat -Wait -NoNewWindow

  Clear-RecycleBin -DriveLetter D -Force -ErrorAction SilentlyContinue
  Get-ChildItem "D:`$Recycle.bin\" -Force | Remove-Item -Recurse -force
  Write-Output "Recycle Bin cleared successfully."
}else{
  Write-Output "New Jar files not detected in extlib folder, restarting MID"
  Start-Process -FilePath $stopbat -Wait -NoNewWindow
  Start-Sleep -Seconds 1.5
  Start-Process -FilePath $startbat -Wait -NoNewWindow
  Write-Output "Re-run script after Jar files have been propogated"
}

Step 5. Restart the MID server service so it force syncs the files.

Step 6. Remote into the server, or connect remotely using PowerShell.

Step 7. Open Powershell terminal as an admin and execute the line below. You will need to change the path to whatever path the MID server agent folder is using.

>. "D:\MyMIDServer\agent\scripts\Log4j.ps1"

Step 8. Validate the results. Open the lib folder and see the updated dates on the jar files.

Step 9. Close and move your update set and re-do steps 5-8 for any other environments and MID servers

My script includes some logic to auto-detect the folder, and detect if the jars are synced, otherwise it just restarts the service. The script also includes logic to clear the recycle bin, since the file can still be found even if in the recycle bin. If you are not using the D drive, you will need to slightly update the two lines to whichever drive you are using.

Also a word of caution, just deleting the log4j jar files without replacing will break the MID server service from starting all together. We can only hope that ServiceNow properly patches this soon.

Node Switcher UI Page!

If you aren’t familiar, when you log into ServiceNow, you are assigned a node dynamically, to serve all your transactions. There many be many situations where you may want to switch to a different node. There isn’t any functionality available to the general public for this (though I know you exist hop2node!)

I developed my own node switching tool as an alternative to Chrome Extensions, since many companies have security restrictions for those. This page instead acts as a native tool within ServiceNow!

A number of you might be wondering how I was able to get this to actually work…. Or even if you aren’t I’m here to explain anyways!

Step 1 - Figuring out how to get the node IP address cookie value for all nodes. For this I had two big hints:
This little tool on the ServiceNow Share: Generate Node BigIP - Switch Between ServiceNow Nodes

https://developer.servicenow.com/connect.do#!/share/contents/4214057_generate_node_bigip_switch_between_servicenow_nodes?v=1.0&t=PRODUCT_DETAILS

This gave me the biggest hint, that part of nodes name on typical deployments, includes the last numbers for the IP address of that node. That saves so much time from a lookup perspective, since you just need to get the ballpark initial parts of the IP address first, since the nodes should be in the same data center.

The next part, which is the even harder part, most tools make use of querying stats.do to get the node IP address. However, that page is pretty long, parsing it isn’t as reliable, and most security advise is to lock down that page. I got a tip from Ahmed Hmeid from ServiceNow Gems to use SOAP against InstanceInfo.do. This is the same way the MID servers get the instance details. Basically just have to spoof a MID server!

Step 2 - Figuring out what the user’s current node is. This part was also harder than I expected. The value of the node stored in the cookie is an HTTP only flag cookie, which means it can’t be read client side at all. However, there are two server side workarounds!

var request = GlideTransaction.get().getRequest();
result.user.node_cookie = GlideCookieMan.getCookieValue(request.getCookies(), 'BIGipServerpool_' + this.instanceName);

result.user.node_name = (GlideServlet.getSystemID() + '').split(':')[1]; //get the second half of the node name

Step 3 - Mechanism for switching the node. Since it’s a special cookie, you can’t just use any normal client side function to change it. I found out though after a bit of digging, that Processors have the ability to write cookies! There is an undocumented function called g_response.addCookie which can set and override even HTTP only cookies.

var cookie = new Packages.javax.servlet.http.Cookie('BIGipServerpool_' + instanceName, node_id);
cookie.setPath("/");
g_response.addCookie(cookie);

All together the flow looks like this: UI Page Pre-Load > Script Include > SOAP > UI Page > Processor > UI Page. I’ve also added some other data enrichment in the script include to grab node metrics as well.

Closing Thoughts

I hope to one day package this up and post it on the ServiceNow share. Just a couple more things I have to get cleared up first (like getting it to work with other node naming conventions, simplifying the MID server user requirement, etc.). Developing this tool was quite the ride and challenge, but I’m happy with the result!