{"id":1588,"date":"2025-02-07T11:29:46","date_gmt":"2025-02-07T16:29:46","guid":{"rendered":"https:\/\/www.brunerd.com\/blog\/?p=1588"},"modified":"2025-02-15T03:07:40","modified_gmt":"2025-02-15T08:07:40","slug":"psa-its-jamf-inventory-time-do-you-know-where-your-macs-are","status":"publish","type":"post","link":"https:\/\/www.brunerd.com\/blog\/2025\/02\/07\/psa-its-jamf-inventory-time-do-you-know-where-your-macs-are\/","title":{"rendered":"PSA: It&#8217;s Jamf Inventory Time, Do You Know Where Your Macs Are?"},"content":{"rendered":"\n<p>Or rather should I say, &#8220;Do you know <em>when<\/em> they are&#8221;? Tell me, Mac Admins, has this ever happened to you: You need to figure out when a computer last submitted inventory to Jamf. Seems easy, right? Just use the built-in Last Inventory criteria, right? Well, if you use the API to update computer records then the <em>moment<\/em> you do, <em>that<\/em> becomes the <em>new<\/em> Last Inventory date. The <em>actual<\/em> time when a Mac last sent it&#8217;s inventory is lost and can now only be loosely <em>correlated<\/em> with Last Check-In. Not ideal\u2122<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Does anyone really know what time it is?<\/h3>\n\n\n\n<p>Adding <a href=\"https:\/\/github.com\/brunerd\/macAdminTools\/blob\/main\/Jamf\/EAs\/zLast%20Inventory%20(Actual).sh\" data-type=\"link\" data-id=\"https:\/\/github.com\/brunerd\/macAdminTools\/blob\/main\/Jamf\/EAs\/zLast%20Inventory%20(Actual).sh\" target=\"_blank\" rel=\"noreferrer noopener\">zLast Inventory (Actual)<\/a> creates a safe harbor for the <em>actual<\/em> date of an inventory submission. It won&#8217;t change no matter how many API writes you make to the computer record. Just create a new extension attribute in your Jamf with an input type of <strong>Script<\/strong> and a data type of <strong>Date<\/strong>. Leave it in the <strong>General<\/strong> category, so it&#8217;s nearer to the built-in Last Inventory field in the UI. You might also want to add it as a default column in your <strong>Computer Inventory Display<\/strong> preferences and\/or use it in Advanced Searches and reports where more <strong>reality<\/strong> is desired.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Additional Uses for finding victim&#8217;s of &#8220;Unknown Error&#8221;<\/h3>\n\n\n\n<p>With <a href=\"https:\/\/github.com\/brunerd\/macAdminTools\/blob\/main\/Jamf\/EAs\/zLast%20Inventory%20(Actual).sh\" data-type=\"link\" data-id=\"https:\/\/github.com\/brunerd\/macAdminTools\/blob\/main\/Jamf\/EAs\/zLast%20Inventory%20(Actual).sh\" target=\"_blank\" rel=\"noreferrer noopener\">zLast Inventory (Actual)<\/a> you may also be able to find Macs that are quietly failing to submit inventory. I came across a few Macs with a cryptic <code>\"Unknown Error\"<\/code> message a few months ago. When <code>jamf recon<\/code> runs it <em>fails<\/em> to upload the inventory which is bad enough but more insidiously the <strong>Last Inventory<\/strong> date in Jamf is <em>updated anyway<\/em>! The fix seemed to require removing both the Jamf framework on the endpoint <em>and<\/em> deleting the computer record in Jamf before re-enrolling. If you know what this is let me know! Anyway here it is, all two lines all gussied up with lots of comments.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The extension attribute <\/h2>\n\n\n\n<pre class=\"wp-block-code language-bash\"><code>#!\/bin\/bash\n# zLast Inventory (Actual) -  Copyright (c) 2025 Joel Bruner (https:\/\/github.com\/brunerd\/macAdminTools\/tree\/main\/Jamf\/EAs) Licensed under the MIT License\n# A Jamf Pro Extension Attribute to report the _actual time_ of a successful inventory submission\n# This is to address two issues with the built-in Last Inventory:\n#  1) This date stamp is not affected by API writes to the computer record\n#  2) Detect \"Unknown Error\" inventory submission failures if date does not match built-in Last Inventory date (excluding API writes in History)\n\n# Notes:\n# The \"z\" at the beginning of this EA's name is to ensure it is runs last and is closest to built-in Last Inventory datestamp\n# The Jamf EA date type does not consider time zone offsets so we must normalize the time to UTC (-u) for the most consistent behavior\n# When viewing an EA date in a Report, Inventory Display, or Computer Record it will not be localized according to Preferences as built-in dates are\n\n#MySQL DATETIME format with time normalized to UTC (YYYY-MM-DD HH:MM:SS)\nDATE_NORMALIZED=$(date -u +\"%F %T\")\n\necho \"&lt;result&gt;${DATE_NORMALIZED}&lt;\/result&gt;\"<\/code><\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><a href=\"https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-89.png\"><img loading=\"lazy\" decoding=\"async\" width=\"444\" height=\"54\" src=\"https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-89.png\" alt=\"\" class=\"wp-image-1606\" srcset=\"https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-89.png 444w, https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-89-300x36.png 300w\" sizes=\"auto, (max-width: 444px) 100vw, 444px\" \/><\/a><figcaption class=\"wp-element-caption\">It looks only <em>slightly<\/em> better in the UI&#8230;<\/figcaption><\/figure>\n<\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><a href=\"https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-88.png\"><img loading=\"lazy\" decoding=\"async\" width=\"858\" height=\"146\" src=\"https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-88.png\" alt=\"\" class=\"wp-image-1605\" style=\"width:471px;height:auto\" srcset=\"https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-88.png 858w, https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-88-300x51.png 300w, https:\/\/www.brunerd.com\/blog\/wp-content\/uploads\/image-88-768x131.png 768w\" sizes=\"auto, (max-width: 858px) 100vw, 858px\" \/><\/a><figcaption class=\"wp-element-caption\">Note: EA dates are not localized according to your UI prefs, unlike like built-in dates.<\/figcaption><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\">Ideas in Waiting<\/h2>\n\n\n\n<p>Apparently, my &#8220;maximizer&#8221; self can&#8217;t just write a dang two-line script without <em>also<\/em> thinking of all the &#8220;<a href=\"https:\/\/ideas.jamf.com\" target=\"_blank\" rel=\"noreferrer noopener\">Jamf Ideas<\/a>&#8221; that either need to be created and or upvoted in relation this. I encourage you to take a look at these and vote them up too.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>&#8220;<a href=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-16064\" data-type=\"link\" data-id=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-16064\" target=\"_blank\" rel=\"noreferrer noopener\">Inventory Time becomes incorrect with API (JN-I-16064)<\/a>&#8221; &#8211; The &#8220;raison d&#8217;\u00eatre&#8221; of this blog post, it shouldn&#8217;t be called Last Inventory if API writes are going to affect it also. This feature request dates back to May 22, 2014 (and I&#8217;m sure there are FRs that pre-date that!) It&#8217;s status is &#8220;Future Consideration&#8221;: At almost 11 years later, the future is here now Jamf!<\/li>\n\n\n\n<li>&#8220;<a href=\"https:\/\/ideas.jamf.com\/ideas\/JPRO-I-1068\" data-type=\"link\" data-id=\"https:\/\/ideas.jamf.com\/ideas\/JPRO-I-1068\" target=\"_blank\" rel=\"noreferrer noopener\">Localize Extension Attribute dates in the UI according to Account Preferences (JPRO-I-1068)<\/a>&#8221; &#8211; As you can see above, the dates from Extension Attributes are not localized like the &#8220;built-in&#8221; dates of Last Update and Last Inventory. Why not?<\/li>\n\n\n\n<li>&#8220;<a href=\"https:\/\/ideas.jamf.com\/ideas\/JPRO-I-1078\">Expanded parsing of date and time formats in extension attribute(JPRO-I-1078)<\/a>&#8221; &#8211; Jamf hitched it&#8217;s wagon to MySQL&#8217;s <code>DATETIME<\/code> format <code>YYYY-MM-DD HH:MM:SS<\/code> which was introduced in 1999 and has no provisions for time zone. In 2025 this seems somewhat rudimentary. Jamf could expand what&#8217;s accepted for <code>date<\/code> types to accommodate more date time representations or at <em>least<\/em> in the short term document the fact <em>you<\/em> need normalize all times to UTC before sending.<\/li>\n\n\n\n<li>&#8220;<a href=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-22451\" target=\"_blank\" rel=\"noreferrer noopener\">Ability to customize order of display fields in Reports (JN-I-22451)<\/a>&#8221; &#8211; Another &#8220;oldie but goody&#8221; from Jan 22, 2014 (Happy belated 11th Birthday!) it has 575 votes and has to be one of the most requested features that&#8217;s still under &#8220;Future Consideration&#8221; (again, the future is <em>now<\/em> Jamf). If we have to <em>make<\/em> an extension attribute to get some truth for Last Inventory can we at least have it show up somewhere we&#8217;d like? This request has many siblings, some that should be merged <a href=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-27291\">here<\/a>, <a href=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-24509\">here<\/a>, <a href=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-24661\">here<\/a>, <a href=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-24294\">here<\/a> and ones that were merged <a href=\"https:\/\/ideas.jamf.com\/ideas\/JPRO-I-1063\">here<\/a> and <a href=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-26729\">here<\/a>.<\/li>\n\n\n\n<li>Oh yeah, almost forgot, you cannot &#8220;<a href=\"https:\/\/ideas.jamf.com\/ideas\/JN-I-22827\" target=\"_blank\" rel=\"noreferrer noopener\">Retain Display items when Cloning Saved Advanced Search (JN-I-22827)<\/a>&#8220;<s> I thought I was going crazy after I&#8217;d made a series of reports by cloning, only to find the &#8220;clones&#8221; had only copied the <strong>search criteria<\/strong> but <em>not<\/em> the all those <strong>Display<\/strong> items I&#8217;d spent time checking off &#8211; that I had to do again and again.<\/s> [Edit: I might have misremembered and you have to uncheck the default Display items you <em>don&#8217;t<\/em> want re-enabled in your &#8220;clone&#8221; so this still holds true]  Aye, what kinda &#8220;clone&#8221; is <em>that<\/em>?! It&#8217;s not! This &#8220;idea&#8221; is labeled <code>Not likely to implement<\/code> but hey, you can <em>still<\/em> leave your angsty comments in memoriam like me, vote it up, and pour outta 40. \ud83e\udea6\ud83c\udf7b [ Edit: Yes, these are &#8220;first world&#8221; nerd problems, I know. Blame it on the bad early 2025 vibes.]<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Where was I? Oh right, the thing&#8230;<\/h2>\n\n\n\n<p>In closing, add <a href=\"https:\/\/github.com\/brunerd\/macAdminTools\/blob\/main\/Jamf\/EAs\/zLast%20Inventory%20(Actual).sh\" data-type=\"link\" data-id=\"https:\/\/github.com\/brunerd\/macAdminTools\/blob\/main\/Jamf\/EAs\/zLast%20Inventory%20(Actual).sh\" target=\"_blank\" rel=\"noreferrer noopener\">zLast Inventory (Actual)<\/a> as an extension attribute to your Jamf. You never know when you might need a bit of reality for Last Inventory in your Jamf reports and searches.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Or rather should I say, &#8220;Do you know when they are&#8221;? Tell me, Mac Admins, has this ever happened to you: You need to figure out when a computer last submitted inventory to Jamf. Seems easy, right? Just use the built-in Last Inventory criteria, right? Well, if you use the API to update computer records [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[19,46,12],"tags":[20,47,22,24],"class_list":["post-1588","post","type-post","status-publish","format-standard","hentry","category-bash","category-jamf","category-scripting","tag-bash","tag-jamf","tag-scripting","tag-shell"],"_links":{"self":[{"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/posts\/1588","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/comments?post=1588"}],"version-history":[{"count":18,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/posts\/1588\/revisions"}],"predecessor-version":[{"id":1644,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/posts\/1588\/revisions\/1644"}],"wp:attachment":[{"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/media?parent=1588"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/categories?post=1588"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.brunerd.com\/blog\/wp-json\/wp\/v2\/tags?post=1588"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}