<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Josh Nerius]]></title><description><![CDATA[Tinkerer, Technologist, Gamer, Geek, Chicagoan. Recently a Sr. Principal Product Manager for Platform Integrations @ ServiceNow. This is my blog. On occasion, I write about things. ]]></description><link>https://joshneri.us/</link><image><url>https://joshneri.us/favicon.png</url><title>Josh Nerius</title><link>https://joshneri.us/</link></image><generator>Ghost 4.48</generator><lastBuildDate>Mon, 31 Mar 2025 00:00:03 GMT</lastBuildDate><atom:link href="https://joshneri.us/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[I finally read "Deep Work"]]></title><description><![CDATA[<p><strong><a href="https://www.calnewport.com/books/deep-work/">Deep Work: Rules for Focused Success in a Distracted World</a></strong> (Cal Newport, 2016) has been sitting on my bookshelf for a couple years now. I first learned about the book from a HN thread a few years back, and was immediately intrigued. It sounded like a useful exploration of staying</p>]]></description><link>https://joshneri.us/i-just-finished-reading-deep-work/</link><guid isPermaLink="false">5f4ec402053b5d5e467d3f97</guid><category><![CDATA[Reading List]]></category><dc:creator><![CDATA[Josh Nerius]]></dc:creator><pubDate>Tue, 01 Sep 2020 23:20:43 GMT</pubDate><content:encoded><![CDATA[<p><strong><a href="https://www.calnewport.com/books/deep-work/">Deep Work: Rules for Focused Success in a Distracted World</a></strong> (Cal Newport, 2016) has been sitting on my bookshelf for a couple years now. I first learned about the book from a HN thread a few years back, and was immediately intrigued. It sounded like a useful exploration of staying focused (it&apos;s so much more). But like many of the books sitting on that bookshelf, it sat there, untouched, waiting for me to pick it up...</p><p>During a recent work break, I finally picked it up and started to read. And read. And read. I couldn&apos;t put it down. Everything Cal writes resonated so deeply, <strong><em>I found myself astounded</em></strong> by the book. </p><p>Quoting <a href="https://news.ycombinator.com/item?id=17164033">this comment</a> from user <a href="https://news.ycombinator.com/user?id=jonathanfoster">jonathanfoster</a> on an HN thread about Deep Work: </p><blockquote>I recently read this book and I can&apos;t recommend it enough. It&apos;s not just a productivity fluff piece about the importance of focus. He brings an academic rigor to the debate and backs up his claims with legitimate evidence. Best of all, the book is not just theory, it&apos;s 100% actionable.<br><br>I used Newport&apos;s recommendations to reclaim 4+ solid hours of deep focus and it&apos;s had a tremendous impact on my productivity and general quality of life.</blockquote><p>And I couldn&apos;t agree more. I ask of you: <br><br>a) If it&apos;s on <strong><em>your</em></strong> shelf, pick it up and read it...ASAP<br>b) If it&apos;s not on your shelf, buy it and read it...ASAP</p><p>Don&apos;t wait. I wish I hadn&apos;t.</p><p>Instead of trying to distill the book into this post, here are several other blogs and discussion threads about the topic that cover the content at a high level. If you find these interesting, <strong>read the book</strong>. </p><ul><li><a href="https://doist.com/blog/deep-work/">The Complete Guide to Deep Work</a> (<a href="https://news.ycombinator.com/item?id=19939010">HN discussion</a>) </li><li><a href="https://azeria-labs.com/the-importance-of-deep-work-the-30-hour-method-for-learning-a-new-skill/">The Importance of Deep Work and the 30-Hour Method for Learning a New Skill</a> (<a href="https://news.ycombinator.com/item?id=17163251">HN discussion</a>)</li><li><a href="https://blog.nuclino.com/slack-is-not-where-deep-work-happens">Slack Is Not Where &apos;Deep Work&apos; Happens</a> (<a href="https://news.ycombinator.com/item?id=19643298">HN discussion</a>)</li></ul>]]></content:encoded></item><item><title><![CDATA[Saving RESTMessageV2 Responses as Attachments in ServiceNow]]></title><description><![CDATA[Need to retrieve something using RESTMessageV2, save that thing as an attachment, and get the sys_id so you can do something with the newly generated attachment? ]]></description><link>https://joshneri.us/saving-restmessagev2-responses-as-attachments-in-servicenow/</link><guid isPermaLink="false">5f4eb87c053b5d5e467d3f3e</guid><category><![CDATA[ServiceNow]]></category><dc:creator><![CDATA[Josh Nerius]]></dc:creator><pubDate>Wed, 22 Jun 2016 13:49:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><strong>Applies to</strong>: Geneva, Helsinki and beyond.</p>
<p>Have you ever needed to:</p>
<ol>
<li>Retrieve something using RESTMessageV2</li>
<li>Save that thing as an attachment on a record</li>
<li>Do something with the newly generated attachment?</li>
</ol>
<p>This recently came up as a question over in the <a href="http://bit.ly/28NbZdE">sndevs slack channel</a>, and I realized that I knew how to accomplish #1 and #2, but didn&apos;t know how to actually identify the attachment to achieve #3 without some ugly hacks. But as it turns out, there&apos;s a <strong>right</strong> way to do this.</p>
<h4 id="firstsomecode">First, some code</h4>
<p>Here&apos;s a quick refresher on steps 1 and 2: retrieving and saving an attachment.</p>
<pre><code class="language-javascript">// This is where we&apos;ll save the attachment
var tablename   = &apos;incident&apos;;
var recordSysId = &apos;8d6353eac0a8016400d8a125ca14fc1f&apos;;
var filename    = &apos;snlogo.png&apos;;

// Let&apos;s download the ServiceNow Logo
var logoUrl = &apos;https://instance.service-now.com/images/logos/logo_service-now.png&apos;;
var request = new sn_ws.RESTMessageV2();
request.setHttpMethod(&apos;get&apos;);
request.setEndpoint(logoUrl);

// Configure the request to save the response as an attachment
request.saveResponseBodyAsAttachment(tablename, recordSysId, filename);

// When we execute the request, the attachment will automatically be
// saved to the record we specified
var response = request.execute();
var httpResponseStatus = response.getStatusCode();
var httpResponseContentType = response.getHeader(&apos;Content-Type&apos;);
gs.debug(&quot;http response status_code: &quot; + httpResponseStatus);
gs.debug(&quot;http response content-type: &quot; + httpResponseContentType);
</code></pre>
<h4 id="nowwhat">Now what?</h4>
<p>If all you&apos;re concerned about is saving the attachment data to a record, you&apos;re done. No further actions are necessary. But what if you want to do something <strong>else</strong> with the attachment you just generated? Copy it somewhere, process its contents, etc?</p>
<p>The call to <a href="http://bit.ly/28Naj3D"><code>saveResponseBodyAsAttachment()</code></a> returns void, so we can&apos;t get a reference to the attachment from there. We could do something super ugly like go query the sys_attachment table and find the latest attachment associated with our target record, but this is far from ideal and prone to bugs.</p>
<p>I was happy to learn that there&apos;s a  <strong>correct</strong> way to do this.</p>
<h4 id="usinggetresponseattachmentsysid">Using getResponseAttachmentSysid()</h4>
<p>The <a href="http://bit.ly/28OCHYt"><code>response</code></a> object returned by <a href="http://bit.ly/28Naj3D"><code>request.execute()</code></a> provides a method called <a href="http://bit.ly/28PmalB"><code>getResponseAttachmentSysid()</code></a>. As the method name suggests, this returns the sys_id of the attachment generated by the REST call.</p>
<p>To use this, we simply call the method after executing the request. We can append the following lines of code to the earlier example:</p>
<pre><code class="language-javascript">// Get the sys_id of the newly created attachment
var newAttachmentSysId = response.getResponseAttachmentSysid();

// Do something useful with it
var grAttach = new GlideRecord(&apos;sys_attachment&apos;);
if (grAttach.get(newAttachmentSysId)) {
  // Note: we&apos;re using the scoped version of GlideSysAttachment 
  // for this example. 
  var gsa = new GlideSysAttachment()
  var content = gsa.getContent(grAttach); 
  // Now we have the data...the rest is up to you
}
</code></pre>
<p>You can view/download the complete script <a href="https://gist.github.com/jnerius/d2f28b845a64fa7e1d296c79f877a8c2">here</a>. This can be executed from <strong>Scripts - Background</strong>, just remember to update the instance URL and target table/record.</p>
<p>Happy attaching!</p>
<p><a href="https://community.servicenow.com/community/develop/blog/2016/06/22/saving-restmessagev2-responses-as-attachments">View and discuss this article on the ServiceNow Community</a>.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Migrating to Ghost]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I can never seem to make up my mind about blogging platforms. I&apos;ve used WordPress, tried static site generators like Pelican and Jekyll, tried GitHub pages for awhile, and most recently have been using svbtle.</p>
<p>Each of these has come along with pros/cons, but I&apos;ve</p>]]></description><link>https://joshneri.us/migrating-to-ghost/</link><guid isPermaLink="false">5f4eb87c053b5d5e467d3f33</guid><category><![CDATA[meta]]></category><dc:creator><![CDATA[Josh Nerius]]></dc:creator><pubDate>Wed, 13 Apr 2016 01:25:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I can never seem to make up my mind about blogging platforms. I&apos;ve used WordPress, tried static site generators like Pelican and Jekyll, tried GitHub pages for awhile, and most recently have been using svbtle.</p>
<p>Each of these has come along with pros/cons, but I&apos;ve never quite settled in or felt at home (to be fair, the fact that I rarely post anything is probably more to blame).</p>
<p>Now it&apos;s time to give <a href="https://ghost.org/">Ghost</a> a try. Thanks to <a href="https://www.digitalocean.com/">DigitalOcean&apos;s</a> lovely one-click app functionality, this took about 10 minutes to configure...this bodes well considering the amount of time I&apos;ve spent in the past tweaking/hacking/fighting with the flavor of the week.</p>
<p>Let&apos;s see if this one sticks...</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[New ServiceNow REST API Docs!]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>The ServiceNow <a href="https://developer.servicenow.com">Developer Portal</a> now has a new section for <a href="https://developer.servicenow.com/app.do#!/rest_api_doc?v=geneva">REST API Documentation</a>!</p>
<p>This is a great new resource if you&apos;re building apps using ServiceNow&apos;s REST APIs, and you&apos;ll find usable examples including cURL and Python snippets. Check it out!</p>
<ul>
<li><a href="https://developer.servicenow.com">ServiceNow Developer Portal</a></li>
<li><a href="https://developer.servicenow.com/app.do#!/rest_api_doc?v=geneva">ServiceNow</a></li></ul>]]></description><link>https://joshneri.us/new-servicenow-rest-api-docs/</link><guid isPermaLink="false">5f4eb87c053b5d5e467d3f38</guid><category><![CDATA[ServiceNow]]></category><dc:creator><![CDATA[Josh Nerius]]></dc:creator><pubDate>Wed, 16 Mar 2016 02:01:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>The ServiceNow <a href="https://developer.servicenow.com">Developer Portal</a> now has a new section for <a href="https://developer.servicenow.com/app.do#!/rest_api_doc?v=geneva">REST API Documentation</a>!</p>
<p>This is a great new resource if you&apos;re building apps using ServiceNow&apos;s REST APIs, and you&apos;ll find usable examples including cURL and Python snippets. Check it out!</p>
<ul>
<li><a href="https://developer.servicenow.com">ServiceNow Developer Portal</a></li>
<li><a href="https://developer.servicenow.com/app.do#!/rest_api_doc?v=geneva">ServiceNow REST API Documentation</a></li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Multiple email addresses for your ServiceNow instance]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>Ever wish you had multiple inboxes available to your ServiceNow instance? If you find yourself needing to build out an inbound email integration, and if you find that it&apos;s often challenging uniquely identifying which messages are meant for what, this might help you out.</p>
<h2 id="subaddressingtotherescue"><a href="https://en.wikipedia.org/wiki/Email_address#Sub-addressing">Sub-addressing</a> to the rescue.</h2>]]></description><link>https://joshneri.us/simulating-multiple-email-addresses-in-your-servicenow-instance/</link><guid isPermaLink="false">5f4eb87c053b5d5e467d3f37</guid><category><![CDATA[ServiceNow]]></category><dc:creator><![CDATA[Josh Nerius]]></dc:creator><pubDate>Wed, 21 Oct 2015 01:41:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>Ever wish you had multiple inboxes available to your ServiceNow instance? If you find yourself needing to build out an inbound email integration, and if you find that it&apos;s often challenging uniquely identifying which messages are meant for what, this might help you out.</p>
<h2 id="subaddressingtotherescue"><a href="https://en.wikipedia.org/wiki/Email_address#Sub-addressing">Sub-addressing</a> to the rescue.</h2>
<p>Sub-addressing allows us to add <strong>extra</strong> information to the destination email address without changing where that email will be delivered. For example, say my ServiceNow instance email address is <a href="mailto:joshnow@service-now.com">joshnow@service-now.com</a>. Using sub-addressing, I can add information after the instance name by adding a +, followed by that extra information.</p>
<p><strong>Example</strong>: <a href="mailto:joshnow+pri1@service-now.com">joshnow+pri1@service-now.com</a>.</p>
<p>Using this example, everything after the + is ignored for delivery purposes. The message is still delivered to <a href="mailto:joshnow@service-now.com">joshnow@service-now.com</a>. The powerful thing is that the extra value is preserved in the email received by the instance.</p>
<h2 id="howcanweusethistoouradvantage">How can we use this to our advantage?</h2>
<p>Say we want all emails from &quot;System A&quot; to use one inbound email action. Perhaps System A is a monitoring tool and should be processed in a particular way. If every email comes <strong>from</strong> one address, we can just set up a condition that looks for that address. But what if these emails will come from two addresses? Or 100 addresses? The condition becomes unmanageably complex.</p>
<p>In this scenario, we need some way to consistently &quot;tag&quot; emails so we can easily identify them using a condition in our desired Inbound Action.</p>
<p>You might ask: why not just add a value to the subject, or body of the email and check for that value using a condition? This may work in some scenarios, but we may not always have control over the contents of the email or the subject line.</p>
<h2 id="wedocontrolthetoaddress">We <strong>do</strong> control the &apos;to&apos; address</h2>
<p>Continuing to use &quot;System A&quot; as our example, we send all emails to an address such as &quot;<a href="mailto:joshnow+SystemA@service-now.com">joshnow+SystemA@service-now.com</a>&quot;. In our inbound action, we now have the ability to inspect the &quot;to&quot; address of the received email. We can then use this in a condition such as: <code>email.to.indexOf(&quot;+SystemA&quot;) &gt;= 0</code>.</p>
<h2 id="onegotcha">One &apos;Gotcha&apos;</h2>
<p>If we are tightly controlling which action fires based on a sub-address, it&apos;s highly likely we do <strong>not</strong> want other, &quot;catch-all&quot; inbound actions to also fire.</p>
<p>To fix this, add <code>event.state=&quot;stop_processing&quot;;</code> at the end of the Inbound Action script, and make sure the action will run <strong>before</strong> other, less tightly conditioned actions. This bit of code tells the email engine to stop processing when this action is finished.</p>
<h2 id="inconclusion">In conclusion</h2>
<p>Sub-addressing effectively allows us to use an unlimited number of unique addresses when sending emails to our instances, and can greatly simplify conditional processing on those emails. I&apos;ll leave you with a few additional scenarios where this may come in handy.</p>
<ul>
<li>Use +pri1, +pri2, etc. to control the priority of incidents opened via email</li>
<li>Use +inc, +chg, +prb, etc. to control the <strong>type</strong> of record created</li>
<li>Use +user_id (+jnerius), etc. to tie emails from a generic address to a specific source user</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Using HandBrake CLI on a Mac to convert video from a Hubsan H107D to 720x480]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>I&apos;ve been playing with a <a href="http://www.amazon.com/Hubsan-H107D-FPV-Mini-Quadcopter/dp/B00GSNWB5K/ref=sr_1_1?ie=UTF8&amp;qid=1429404325&amp;sr=8-1&amp;keywords=hubsan+h107d">Hubsan H107D</a> quadcopter lately. If you happen to own one of these, you&apos;ve probably discovered by now that the video written to the MicroSD card is not very usable without some conversion. It is stored as a 720x240 AVI by default,</p>]]></description><link>https://joshneri.us/converting-video-from-a-hubsan-h107d-using-handbrake-cli/</link><guid isPermaLink="false">5f4eb87c053b5d5e467d3f36</guid><category><![CDATA[Hobby]]></category><category><![CDATA[howto]]></category><category><![CDATA[Miscellaneous]]></category><dc:creator><![CDATA[Josh Nerius]]></dc:creator><pubDate>Sat, 18 Apr 2015 18:37:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>I&apos;ve been playing with a <a href="http://www.amazon.com/Hubsan-H107D-FPV-Mini-Quadcopter/dp/B00GSNWB5K/ref=sr_1_1?ie=UTF8&amp;qid=1429404325&amp;sr=8-1&amp;keywords=hubsan+h107d">Hubsan H107D</a> quadcopter lately. If you happen to own one of these, you&apos;ve probably discovered by now that the video written to the MicroSD card is not very usable without some conversion. It is stored as a 720x240 AVI by default, and appears rather...squashed. To top this off, VLC complains about a missing/broken AVI index.</p>
<p>The following HandBrakeCLI command will convert the video to an MP4 and correct the aspect ratio.</p>
<pre><code>HandBrakeCLI -i 001.AVI -o 001.mp4 -e x264 -q 22 -w 720 -l 480
</code></pre>
<h2 id="ifhandbrakecliisnotinstalled">If HandBrakeCLI is not installed</h2>
<p>Install it using <a href="http://brew.sh">Homebrew</a>.</p>
<pre><code>brew install Caskroom/cask/handbrakecli
</code></pre>
<h2 id="convertinganentirefolder">Converting an entire folder</h2>
<p>If you&apos;d rather convert an entire folder of video files, use something like this:</p>
<pre><code>#!/bin/bash

DEST_EXT=mp4
HANDBRAKE_CLI=HandBrakeCLI

for FILE in `ls $1`
do
    filename=$(basename $FILE)
    extension=${filename##*.}
    filename=${filename%.*}

    $HANDBRAKE_CLI -i $1/$FILE -o $1/$filename.$DEST_EXT -e x264 -q 22 -r 30 -w 720 -l 480
done
</code></pre>
<p>And then...</p>
<pre><code>./convert_video.sh ~/My/Directory
</code></pre>
<h2 id="nexttime">Next Time...</h2>
<p>My next goal is to find an easy way to stitch these together so the entire flight is contained in one video.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[Server-side "hasRoleExactly" in ServiceNow]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p>ServiceNow provides the convenient <code>gs.hasRole(role)</code> method for checking to see if the current user has the specified role(s). This works great if you&apos;re only worried about securing something against non-admins, but it will <strong>always</strong> return <em>true</em> if the current user is an admin.</p>
<p>There are</p>]]></description><link>https://joshneri.us/serverside-hasroleexactly-in-servicenow/</link><guid isPermaLink="false">5f4eb87c053b5d5e467d3f35</guid><category><![CDATA[ServiceNow]]></category><dc:creator><![CDATA[Josh Nerius]]></dc:creator><pubDate>Wed, 04 Mar 2015 02:36:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p>ServiceNow provides the convenient <code>gs.hasRole(role)</code> method for checking to see if the current user has the specified role(s). This works great if you&apos;re only worried about securing something against non-admins, but it will <strong>always</strong> return <em>true</em> if the current user is an admin.</p>
<p>There are times when this just won&apos;t work. A common use case is securing a method in a script include that might take an action only if the user has the necessary role. If our code does something like: return sensitive data about a user from a web service, we might want to prevent admins from automatically getting this access.</p>
<p>There is a <strong>client-side</strong> method called <code>g_user.hasRoleExactly(role)</code>, and this does pretty much what it sounds like: it only returns true if the user actually has the role in question. But this won&apos;t help us in our server-side code.</p>
<p>This can be solved by creating our own &quot;hasRoleExactly&quot; method.</p>
<pre><code>function hasRoleExactly(role) {
    var au = new ArrayUtil();
    var roles = gs.getSession().getRoles() + &apos;&apos;; 
    var roleArray = roles.split(&quot;,&quot;); 
    var isAuthorized = au.contains(roleArray, role); 
    return isAuthorized; 
}
</code></pre>
<p>This currently won&apos;t work if you pass in an array of roles, but it could be easily adapted to support this.</p>
<p>Also note that this doesn&apos;t prevent an admin from just impersonating another user that has the necessary role, and an admin will be able to find other ways around this as well (just comment out the hasRoleExactly check!). However, a check like this ensures a <strong>deliberate</strong> action must be taken by an admin to circumvent the security check.</p>
<!--kg-card-end: markdown-->]]></content:encoded></item><item><title><![CDATA[A better way to find ServiceNow images]]></title><description><![CDATA[<!--kg-card-begin: markdown--><p><strong>Once upon a time</strong>, it was easy to find the image you wanted in the ServiceNow image picker. Perhaps it wasn&#x2019;t pretty, but the filename was visible next to each image, making it easy to Cmd-F / Ctrl-F and locate the item you wanted. Since the Calgary release, file</p>]]></description><link>https://joshneri.us/a-better-way-to-find-servicenow-images/</link><guid isPermaLink="false">5f4eb87c053b5d5e467d3f34</guid><category><![CDATA[ServiceNow]]></category><dc:creator><![CDATA[Josh Nerius]]></dc:creator><pubDate>Mon, 24 Mar 2014 17:00:00 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: markdown--><p><strong>Once upon a time</strong>, it was easy to find the image you wanted in the ServiceNow image picker. Perhaps it wasn&#x2019;t pretty, but the filename was visible next to each image, making it easy to Cmd-F / Ctrl-F and locate the item you wanted. Since the Calgary release, file names are no longer included in the image picker view.</p>
<p><a href="http://img.svbtle.com/0kftahfxtiotvg.png"><img src="https://d23f6h5jpj26xu.cloudfront.net/0kftahfxtiotvg_small.png" alt="image_picker_images.png" loading="lazy"></a></p>
<p>The new styling is arguably more visually appealing at first glance, and certainly takes up less space, but the removal of file names has one serious side effect: it&#x2019;s now almost impossible to find the image you want. As I&apos;m sure you&apos;re well aware, 3 rows is just the beginning. I can&#x2019;t tell you how many times I&#x2019;ve repeatedly scanned the list, skimming past the item I was looking for before finally laying eyes on the right image.</p>
<h1 id="asolution">A solution</h1>
<p><a href="https://addons.mozilla.org/en-US/firefox/addon/greasemonkey/">Greasemonkey (Firefox)</a> / <a href="https://chrome.google.com/webstore/detail/tampermonkey/dhdgffkkebhmkfjojejmpbldmpobfkfo?hl=en">Tampermonkey (Chrome)</a> to the rescue. If you&#x2019;re not familiar with these plugins and what they do, they allow you to write scripts that are executed by the browser when certain pages load. For our purposes, we want a script to execute every time the image picker is loaded that will give us some fancy new options. (For more general information about Greasemonkey and user scripts, go read about them here).</p>
<p>To make everything about the Image Picker better, we need to add a user script to our extension of choice consisting of a few lines of JavaScript:</p>
<pre><code>// ==UserScript==
// @name Better ServiceNow Image Picker
// @namespace https://joshneri.us/
// @version 0.1
// @description A better way to find ServiceNow images
// @match https://*.service-now.com/image_picker.do*
// @copyright 2014+, Josh Nerius
// @require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// ==/UserScript==
$(window).load(function(){ 
    $(&quot;tr.tool_banner &gt; td&quot;)
        .append(&quot;&lt;input type=&apos;button&apos; value=&apos;Show Names&apos;&gt;&quot;)
        .click(function() {
            var frame = $(&quot;#ibrowse&quot;); 
            frame.contents().find(&quot;div &gt; a&quot;).each(function() {
                var name = $(&quot;img&quot;, this).attr(&quot;src&quot;).split(&quot;/&quot;).pop(); 
                $(this).append(&quot; &quot; + name); 
            }
        ); 
    }); 
});
</code></pre>
<p>This will give us a <strong>Show Names</strong> button when we open the image picker:<br>
<a href="http://img.svbtle.com/ziu5oeo1rtucbq.png"><img src="https://d23f6h5jpj26xu.cloudfront.net/ziu5oeo1rtucbq_small.png" alt="show_names_button.png" loading="lazy"></a></p>
<p><strong>Click the button</strong>, and the magic happens. Cmd/Ctrl-F away!<br>
<a href="http://img.svbtle.com/nu8muaryqyuq.png"><img src="https://d23f6h5jpj26xu.cloudfront.net/nu8muaryqyuq_small.png" alt="now_with_names.png" loading="lazy"></a></p>
<h1 id="installingit">Installing it</h1>
<p>If you don&#x2019;t have the Greasemonkey (Firefox) or Tampermonkey (Chrome) extension in your browser, install one of them first.</p>
<p>You can then do one of two things:</p>
<ul>
<li><a href="http://userscripts.org/scripts/show/435352">Go to the userscripts.org script I published here</a> and click &#x201C;Install&#x201D;.</li>
<li>Manually create a new user script in your extension of choice and paste in the code I provided above.</li>
</ul>
<h1 id="morestuff">More stuff</h1>
<p>The beauty of this solution is that it does not involve customization of any ServiceNow code, and will be available in whatever instance you log in to.</p>
<h1 id="caveats">Caveats</h1>
<ul>
<li>If you click Show Names more than once, it will keep appending the name repeatedly. I didn&#x2019;t feel it was worth spending the time to prevent this.</li>
<li>jQuery is loaded as part of the user script (see the @require statement). This only occurs on the image picker page however.</li>
<li>I wrote this in about 20 minutes, and didn&#x2019;t really do a lot of testing, so use it at your own risk (not that there&apos;s much harm this can do).</li>
</ul>
<!--kg-card-end: markdown-->]]></content:encoded></item></channel></rss>