Installed macOS Updates into an Extension Attribute

joethedsa
Contributor II

Hi All,

I want to leverage the "system_profiler SPInstallHistoryDataType" command which will tell me all of the installed macOS updates. To do that I can add a pipe and grep the string "macOS". However I'm looking to get both the macOS update(s) that were installed and the Install Date when it happened into an Extension Attribute.

As an example, one of the results of the command is below:

   macOS Mojave Security Update Developer Beta 2021-001:

      Version: 10.14.6
      Source: Apple
      Install Date: 1/29/21, 9:11 AM

From the above text, I'm looking to only display what is below into the EA:

macOS Mojave Security Update Developer Beta 2021-001:
Install Date: 1/29/21, 9:11 AM

I'm not sure what what the command syntax will look like to get rid of the "middle" data from the result of the command. As you can imagine, the EA will continually update as new "macOS updates" get installed.

Thanks to anyone that can offer guidance.

13 REPLIES 13

mm2270
Legendary Contributor III

This isn't exactly the format you were looking for, but you could try something like this.

system_profiler SPInstallHistoryDataType -json | awk -F'"' '/_name|install_date/{print $2,$4}' | sed -e 's/_name /Product: /g;s/install_date /Install Date: /g'

Edit: Sorry, you said you were only looking for OS updates. Let me adjust the above to get only those. Be right back...

OK, this will filter out just the "macOS" installs:

system_profiler SPInstallHistoryDataType -json | awk -F'"' '/_name|install_version|install_date/{print $2,$4}' | grep -A3 "macOS" | sed -e 's/_name /Name: /g;s/install_version /Version: /g;s/install_date /Date: /g'

jhuls
Contributor III

Whoa...I wasn't aware of this. I might need to investigate further. This might be useful for us since common sense evades the powers that be in regards to giving everyone admin privs. It actually might be nice if that install date info was included in Jamf's inventory.

atomczynski
Valued Contributor

Interesting,
What else is needed to turn this into a EA?

mm2270
Legendary Contributor III

Here's an EA format, which should give very similar output to what @joethedsa asked for above. This can obviously be formatted in a few different ways, such as the date for example, can be in YYYY-MM-DD HH:MM:SS format, or the install date can be placed on the same line as the product name instead of the following line.

#!/bin/bash

product_names=$(system_profiler SPInstallHistoryDataType -json | awk -F'"' '/_name/{print $4}')
install_dates=($(system_profiler SPInstallHistoryDataType -json | awk -F'"' '/install_date/{print $4}'))

i=0
while read item; do
    if [[ "$item" =~ ^"macOS" ]]; then
        install_date_raw="${install_dates[$i]}"
        install_date_formatted=$(date -jf "%Y-%m-%d"T"%T"Z "$install_date_raw" +"%D %l:%M %p")
        list+=("${item}")
        list+=("Installed: ${install_date_formatted}")
    fi
    let i=$((i+1))
done < <(echo "$product_names")

echo "<result>$(printf '%s
' "${list[@]}")</result>"

Note that this should only grab items that start with 'macOS' in the beginning of their names, so I'm not sure if it will end up missing some important installation lines or not. YMMV.

etarasula
New Contributor II

I can verify that this works on Monterey 12.2.1

Brings good ol' big list of all updates ever installed. Can it be withered down to the very last one? 

sdagley
Esteemed Contributor II

Here's @mm2270 's script modified to return only the last installed update whose name starts with 'macOS'. There is also a '-' added between the update name and the installed date:

 

#!/bin/bash

product_names=$(system_profiler SPInstallHistoryDataType -json | awk -F'"' '/_name/{print $4}')
install_dates=($(system_profiler SPInstallHistoryDataType -json | awk -F'"' '/install_date/{print $4}'))

i=0
updatesFound=0
while read item; do
    if [[ "$item" =~ ^"macOS" ]]; then
    	let updatesFound=$((updatesFound+1))
        install_date_raw="${install_dates[$i]}"
        install_date_formatted=$(date -jf "%Y-%m-%d"T"%T"Z "$install_date_raw" +"%D %l:%M %p")
        list+=("${item}")
        list+=("Installed: ${install_date_formatted}")
    fi
    let i=$((i+1))
done < <(echo "$product_names")

let lastUpdateName=$((updatesFound*2-2))
let lastUpdateDate=$((updatesFound*2-1))
echo "<result>$(printf '%s' "${list[$lastUpdateName]}-${list[$lastUpdateDate]}")</result>"

 

joethedsa
Contributor II

@mm2270, Thank you for contributing to this discussion. I put your script in an EA and it's not populating anything. I've made sure the computer(s) have done inventory updates too. The EA is setup with the following: Data Type:String and Input Type:Script. For testing purposes, I ran the script you shared locally (i.e. not in an EA) on a 10.14.6 computer and I'm thinking it doesn't know how to process the "-json" in the command because I get the generic command output of "usage" and "example" results. I'm assuming, if a script doesn't run locally that it probably won't run in an EA as well? For what it's worth when I ran the second command that you gave in your original post

system_profiler SPInstallHistoryDataType -json | awk -F'"' '/_name|install_version|install_date/{print $2,$4}' | grep -A3 "macOS" | sed -e 's/_name /Name: /g;s/install_version /Version: /g;s/install_date /Date: /g'

when I press Return it just brought me back to the prompt as if it did process something but there was no output. Any thoughts?

Hasibravo
New Contributor III

You need to echo the result.

#!/bin/bash

# Get the macOS version and installation date
macos_info=$(system_profiler SPInstallHistoryDataType -json | awk -F'"' '/_name|install_version|install_date/{print $2,$4}' | grep -A3 "macOS" | sed -e 's/_name /Name: /g;s/install_version /Version: /g;s/install_date /Date: /g')

# Print the result
echo "<result>$macos_info</result>"

JFGraphia
New Contributor II

To cross check I ran the above command without any elevated privs and it did work and returned ALL of the update install history(which I do not find personally useful but to each his own). Output posted below but truncated to only contain 2020 updates. Come on we all loved 2020...just look at BigSur......

--
Name: macOS 10.15.3 Update
Date: 2020-02-15T13:52:35Z
Name: Gatekeeper Compatibility Data
Date: 2020-02-15T14:11:13Z
--
Name: macOS Catalina 10.15.4 Update
Date: 2020-05-17T13:20:51Z
Name: MRTConfigData
Date: 2020-05-17T13:40:25Z
--
Name: macOS 10.15.6 Update
Date: 2020-07-15T20:15:13Z
Name: MRTConfigData
Date: 2020-07-15T20:37:29Z
--
Name: macOS Catalina 10.15.6 Supplemental Update
Date: 2020-08-30T14:40:09Z
Name: MRTConfigData
Date: 2020-08-30T14:56:26Z
--
Name: macOS Big Sur
Date: 2020-12-28T14:33:01Z
Version: 11.1
Name: macOS 11.1
Date: 2020-12-28T15:08:14Z
Version: 11.1
Name: MRTConfigData

mm2270
Legendary Contributor III

@joethedsa Have you tried the EA format I posted above in my second posting? I just added that to our Jamf system and it seems to be populating data for me.
But question for you. Are the Macs you're running this against all on Big Sur or are some on Catalina? I'm still on Catalina right now, and I admit I didn't test this against any Big Sur machines yet, so that might account for the issue.

I would try just running the system_profiler command with the -json flag to see what output you get. For example:

system_profiler SPInstallHistoryDataType -json

See what that produces. If you just get an error or it doesn't produce anything at all, then the -json flag would be the issue. But I can't see why that wouldn't work the same way in Big Sur as it would in previous OS releases.

JFGraphia
New Contributor II

What I posted came from 11.1

joethedsa
Contributor II

@mm2270, Ah ha, so I just ran the command locally and checked the EA in Jamf for a Catalina computer and I can see the output of both. This leads me to conclude that the "-json" option isn't compatible on OS's lower than Catalina since when I run the command and look at the EA on a Mojave system, I get nothing. Since a good majority of our computers are still on Mojave, is there an equivalent command that could be used to capture this information on both older and newer OS's?

psliequ
Contributor III

Just for fun here's how I do it and separate the attributes by Apple software vs. Third Party

Apple;

echo "<result>$(system_profiler SPInstallHistoryDataType | sed -e "s/^[ 	]*//" | grep -B 3 -A 2 "Source: Apple" | sed -e '/^[[:space:]]*$/d;/Source: Apple/d' | uniq)</result>"

Third Party;

echo "<result>$(system_profiler SPInstallHistoryDataType | sed -e "s/^[ 	]*//" | grep -B 3 -A 2 "Source: 3rd Party" | sed -e '/^[[:space:]]*$/d;/Source: 3rd Party/d' | uniq)</result>"