Java Version in Inventory Items

295 views
Skip to first unread message

Josh Potter

unread,
Mar 13, 2013, 11:40:53 AM3/13/13
to munki-w...@googlegroups.com
With the recent Java snafu's lately, I wanted to incorporate a machine's Java version into the Application Inventory list. I wanted to share what I came up with incase someone had any better ideas or sees any potential issues.

I created a python script and placed it in /usr/local/munki/munkilib/
I then call that script from the munki postflight script. I place the call right before it does the checksums of the ApplicationInventory.plist file.

Here's what the script looks like
#!/usr/bin/python


import FoundationPlist


#Java Info.plist contains the information we want to add to the app inventory
infoPath
= r"/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Info.plist"
#The plist of App Inventory that we start by reading and then adding the Java info into.
invPath
= r"/Library/Managed Installs/ApplicationInventory.plist"

#Read in the Java info.plist
info
= FoundationPlist.readPlist(infoPath)


#Grab what we want and create a new dict
java
= {}
java
['CFBundlenName'] = info.get('CFBundleName')
java
['version'] = info.get('CFBundleVersion')
java
['path'] = infoPath
java
['name'] = info.get('CFBundleShortVersionString')


#Read in the App Inventory plist
appinv
= FoundationPlist.readPlist(invPath)


#Add the new java dict to the App Inventory dict
appinv
.append(java.copy())


#Overwrite the new ApplicationInventory.plist
FoundationPlist.writePlist(appinv, invPath)


One thing I need to do is check if the file even exists before going any further....

Gregory Neagle

unread,
Mar 13, 2013, 11:42:50 AM3/13/13
to munki-w...@googlegroups.com
This is pretty clever. It could probably be extended to grab the version info for the Flash Player plugin as well...

-Greg

--
You received this message because you are subscribed to the Google Groups "MunkiWebAdmin" group.
To unsubscribe from this group and stop receiving emails from it, send an email to munki-web-adm...@googlegroups.com.
Visit this group at http://groups.google.com/group/munki-web-admin?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Joe Wollard

unread,
Mar 13, 2013, 11:45:49 AM3/13/13
to munki-w...@googlegroups.com
On Wed, Mar 13, 2013 at 11:42 AM, Gregory Neagle <gregn...@mac.com> wrote:
This is pretty clever. It could probably be extended to grab the version info for the Flash Player plugin as well...

I'd be interested in the Silverlight and a few other 3rd party plugins as well. So, it could be modified to loop over all *.plugin bundles in /Library/Internet Plug-Ins/ just to make sure everything is reported. Good work, Josh!



--
Joe Wollard

Josh Potter

unread,
Mar 13, 2013, 12:14:17 PM3/13/13
to munki-w...@googlegroups.com
I plan on making it loop through /var/db/reciepts to look for any packages that I am pushing through munki so I can also see those in the inventory list. I didn't even think about the other plug-ins but it would definitely be nice to have those in there as well. I will post what I am come up with.

Gregory Neagle

unread,
Mar 13, 2013, 12:19:35 PM3/13/13
to munki-w...@googlegroups.com
On Mar 13, 2013, at 9:14 AM, Josh Potter <pott...@gmail.com> wrote:

I plan on making it loop through /var/db/reciepts

This would be a fragile approach, as the data in /var/db/receipts is an implementation detail and could change in future OS X releases.

Better to work with the output of `pkgutil`.

-Greg

to look for any packages that I am pushing through munki so I can also see those in the inventory list. I didn't even think about the other plug-ins but it would definitely be nice to have those in there as well. I will post what I am come up with.

Adam Reed

unread,
Mar 13, 2013, 4:56:37 PM3/13/13
to munki-w...@googlegroups.com
Hi,

Here is a script I've been running to do the Internet Plugins. It uses the same idea that Josh had, and adds the data to the Application Inventory plist before submitting it to MWA. It doesn't actually capture Java but does get Flash, Silverlight, et al. I have a second script that adds munki's version, and the OS version to the app inventory as well, as I found it easier to search for that info when it was in the Inventory. If people are interested let me know and I'll share that as well.

----

#!/usr/bin/python
# encoding: utf-8

# Adds Internet Plug-Ins to the Application Inventory data that is reported
# to MunkiWebAdmin. It is a basic copy of the code from munkicommon.py that
# creates the application data.

import sys
import os
import plistlib
import LaunchServices
from Foundation import NSDate, NSMetadataQuery, NSPredicate, NSRunLoop

sys.path.append('/usr/local/munki')
from munkilib import munkicommon

# Change the following as needed
managed_installs_dir = "/Library/Managed Installs"

def findPluginsInDirs(dirlist):
    """Do spotlight search for type plug-in within list of directories 
    provided. Returns a list of paths to plug-ins these appear to always 
    be some form of unicode string.
    """
    applist = []
    query = NSMetadataQuery.alloc().init()
    query.setPredicate_(NSPredicate.predicateWithFormat_(
                                    '(kMDItemKind = "Plug-in")'))
    query.setSearchScopes_(dirlist)
    query.startQuery()
    # Spotlight isGathering phase - this is the initial search. After the
    # isGathering phase Spotlight keeps running returning live results from
    # filesystem changes, we are not interested in that phase.
    # Run for 0.3 seconds then check if isGathering has completed.
    runtime = 0
    maxruntime = 20
    while query.isGathering() and runtime <= maxruntime:
        runtime += 0.3
        NSRunLoop.currentRunLoop().runUntilDate_(
                                   NSDate.dateWithTimeIntervalSinceNow_(0.3))
    query.stopQuery()

    if runtime >= maxruntime:
        display_warning('Spotlight search for Internet Plug-ins terminated '
              'due to excessive time. Possible causes: Spotlight indexing is '
              'turned off for a volume; Spotlight is reindexing a volume.')

    for item in query.results():
        p = item.valueForAttribute_('kMDItemPath')
        if p and not munkicommon.isExcludedFilesystem(p) and "Internet Plug-Ins" in p:
            applist.append(p)

    return applist

def getSpotlightInstalledInternetPlugins():
    """Get paths of currently installed Internet Plug-ins per Spotlight.
    Return value is list of paths.
    Excludes most non-boot volumes.
    In future may include local r/w volumes.
    """
    dirlist = []
    applist = []

    for f in munkicommon.listdir(u'/'):
        p = os.path.join(u'/', f)
        if os.path.isdir(p) and not os.path.islink(p) \
                            and not munkicommon.isExcludedFilesystem(p):
            dirlist.append(p)

    applist.extend(findPluginsInDirs(dirlist))
    return applist

def main():

    app_data_plist = os.path.join(managed_installs_dir, \
        "ApplicationInventory.plist")
    if os.path.exists(app_data_plist):
        app_data = plistlib.readPlist(app_data_plist)
    else:
        print '        Application Inventory not found.'
        sys.exit(0)

    applist = set(getSpotlightInstalledInternetPlugins())
    for pathname in applist:
        iteminfo = {}
        iteminfo['name'] = os.path.splitext(os.path.basename(pathname))[0]
        iteminfo['path'] = pathname
        plistpath = os.path.join(pathname, 'Contents', 'Info.plist')
        if os.path.exists(plistpath):
            try:
                plist = plistlib.readPlist(plistpath)
                iteminfo['bundleid'] = plist.get('CFBundleIdentifier','')
                iteminfo['version'] = munkicommon.getExtendedVersion(pathname)
                app_data.append(iteminfo)
            except Exception:
                pass

    try:
        plistlib.writePlist(app_data, app_data_plist)
    except FoundationPlist.NSPropertyListSerializationException, err:
        print '        Unable to update inventory report: %s' % err

    print '        Internet Plug-Ins added to Application Inventory Data'
   
if __name__ == '__main__':
        main()

Josh Potter

unread,
Mar 15, 2013, 9:23:41 AM3/15/13
to munki-w...@googlegroups.com
Thanks for sharing Adam. It's helpful to see a different approach. I look forward to working this into my MWA setup...

Josh Potter

unread,
Mar 26, 2013, 9:18:26 AM3/26/13
to munki-w...@googlegroups.com
Updated to loop over the /Library/Internet Plug-ins/ directory and grab what it can. There are some files/bundles that FoundationPlist.readPlist can't handle, hence the try/exception.

#!/usr/bin/python

import FoundationPlist
import os

#The plist of App Inventory that we start by reaading and then adding the Java info to.

invPath
= r"/Library/Managed Installs/ApplicationInventory.plist"

#Path where the browser plug-ins are located
plugins
= r"/Library/Internet Plug-Ins/"

#Create a list of the plugins
directoryListing
= os.listdir(plugins)


#Read in the App Inventory plist
appinv
= FoundationPlist.readPlist(invPath)

#Iterate through each plugin and grab the info
for x in directoryListing:

   
#Some plugins will not have the necessary files for the FoundationPlist.readPlist call. We skip over
   
#those plugins with the try/exception.
   
try:

        path
= os.path.join(plugins,x,'Contents/Info.plist')

       
#Get the info from the plugin
        info
= FoundationPlist.readPlist(path)


       
#Grab what we want and create a new dict

        plugin
= {}
        plugin
['CFBundlenName'] = info.get('CFBundleName','N/A')
        plugin
['version'] = info.get('CFBundleVersion','N/A')
        plugin
['path'] = path
        plugin
['name'] = os.path.splitext(os.path.basename(pathname))[0]

       
#Add the new dict to the App Inventory dict
        appinv
.append(plugin.copy())

   
except Exception:
       
pass

#Overwrite the new ApplicationInventory.plist
FoundationPlist.writePlist(appinv, test_invPath)


Joe Wollard

unread,
Mar 26, 2013, 4:13:34 PM3/26/13
to munki-w...@googlegroups.com
Good stuff, Josh!

First, a question for the list: do people want this to become a standard part of MunkiWebAdmin?

Next, I think there were a few leftovers in your copy/paste from testing that caused some errors in my test environment. Here's the same script with the modifications that made it functional for me:

from munkilib import FoundationPlist
import os

invPath = r"/Library/Managed Installs/ApplicationInventory.plist"
plugins = r"/Library/Internet Plug-Ins/"
directoryListing = os.listdir(plugins)
appinv = FoundationPlist.readPlist(invPath)

print "Adding %i plugins" % len(directoryListing)

for x in directoryListing:
    try:
        path = os.path.join(plugins, x, 'Contents/Info.plist')
        info = FoundationPlist.readPlist(path)
        plugin = {}
        plugin['CFBundlenName'] = info.get('CFBundleName','N/A')
        plugin['version'] = info.get('CFBundleVersion','N/A')
        plugin['path'] = path
        plugin['name'] = info.get('CFBundleName', os.path.splitext(os.path.basename(x))[0])
        appinv.append(plugin.copy())
    except Exception, message:
        pass

FoundationPlist.writePlist(appinv, invPath)


--
You received this message because you are subscribed to the Google Groups "MunkiWebAdmin" group.
To unsubscribe from this group and stop receiving emails from it, send an email to munki-web-adm...@googlegroups.com.
Visit this group at http://groups.google.com/group/munki-web-admin?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Joe Wollard

Joe Wollard

unread,
Mar 26, 2013, 4:26:55 PM3/26/13
to munki-w...@googlegroups.com
Just noticed a few more...

#!/usr/bin/python

from munkilib import FoundationPlist
import os

invPath = r"/Library/Managed Installs/ApplicationInventory.plist"
plugins = r"/Library/Internet Plug-Ins/"
directoryListing = os.listdir(plugins)
appinv = FoundationPlist.readPlist(invPath)

print "Adding %i plugins" % len(directoryListing)

for x in directoryListing:
    path = os.path.join(plugins, x, 'Contents/Info.plist')
    try:
        info = FoundationPlist.readPlist(path)
        plugin = {}
        plugin['CFBundleName'] = info.get('CFBundleName','N/A')
        plugin['bundleid'] = info.get('CFBundleIdentifier', 'N/A')
        plugin['version'] = info.get('CFBundleVersion','N/A')
        plugin['path'] = os.path.join(plugins, x)
        plugin['name'] = info.get('CFBundleName', os.path.splitext(os.path.basename(x))[0])
        appinv.append(plugin.copy())
    except Exception, message:
        pass

FoundationPlist.writePlist(appinv, invPath)
--
Joe Wollard

Ken Elliott

unread,
Mar 26, 2013, 11:44:07 PM3/26/13
to munki-w...@googlegroups.com, munk...@googlegroups.com
Hi,

First, a question for the list: do people want this to become a standard part of MunkiWebAdmin?
Rather than MunkiWebAdmin, I'd prefer it to be a part of Munki.
I haven't started to use MunkiWebAdmin yet, and continue to use MunkiReports.
If the Application Inventory was updated at source it would be available to all, without having to repeat code.

I've succeeded in creating an InternetPlugin.plist in bash, but have been unable to merge with the ApplicationInventroy.plist 
(My code skill is limited to bash scripts, not python, sorry.)

Thanks to all,
Ken

Michael Haberman

unread,
Mar 27, 2013, 12:59:47 PM3/27/13
to munki-w...@googlegroups.com
Hi all,

First, a question for the list: do people want this to become a standard part of MunkiWebAdmin?
Personally I would love to see this integrated into MWA!  Would make it much easier for me and my coworkers to track the version of java we have running on staff and student machines and to see which if any need to be updated.

BinkleyBloom

unread,
Apr 20, 2013, 6:37:42 AM4/20/13
to munki-w...@googlegroups.com
I may be little late with the reply, but I too would love to see this added to MWA. Wished for this many times when searching Inventory Items.

nbalonso

unread,
Apr 23, 2013, 4:55:18 AM4/23/13
to munki-w...@googlegroups.com
I'd also prefer this to be included into Munki rather than directly MWA. As Munki does the app inventory I think it makes more sense.

I see that Joe Wollards's branch already has some code for this. Any chance this gets merged into 0.9.0?

Noel

Joe Wollard

unread,
Apr 23, 2013, 9:13:15 AM4/23/13
to munki-w...@googlegroups.com
Thanks, Noel. If you look at the comments in https://code.google.com/p/munki/issues/detail?id=239#c4, you'll see that there is still a little bit of debating to do here. When Greg and I discussed this, it became a little clearer that adding these kinds of things into Munki sort of dilutes the original intent of Munki's app inventory collection. At the same time, it makes more sense for Munki to be the authority on this data so tools other than MWA could take advantage of it, but where to store this info if not in the app inventory proper?

One thought that just occurred to me is we could modify my branch slightly such that the plugin inventory gets written to a separate plist. This would keep things clean for Munki while still providing the data for tools like MWA. Of course we'd then need to modify the preflight/postflight scripts for MWA to combine those plists before generating a hash and ultimately sending it off to the MWA database, but that shouldn't be prohibitive.


--
You received this message because you are subscribed to the Google Groups "MunkiWebAdmin" group.
To unsubscribe from this group and stop receiving emails from it, send an email to munki-web-adm...@googlegroups.com.
Visit this group at http://groups.google.com/group/munki-web-admin?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Joe Wollard

Gregory Neagle

unread,
Apr 23, 2013, 9:57:38 AM4/23/13
to munki-w...@googlegroups.com
My thought it actually: if we are going to go to the effort of extending inventory past _application_ inventory, then we should do it in a way that allows the admin to add arbitrary things to the inventory, not just "Internet Plug-ins" (which is arbitrary in and of itself).

We should design a mechanism that allows the admin to define additional scripts to collect "inventory" information on whatever the admin desires:

FileVault 2 status
Fonts
Internet Plugins
Photoshop add-ons

The application inventory mechanism was originally designed for my own use to track installs of licensed commercial applications. Very few (no?) internet plugins are pay-for commercial; but many fonts and Photoshop add-ons are commercially licensed. In my environment, it would be much more important to know about extra installations of licensed fonts than the versions of Internet plugins. Other orgs may have different needs.

-Greg

Joe Wollard

unread,
Apr 23, 2013, 10:13:47 AM4/23/13
to munki-w...@googlegroups.com
So maybe something akin to a 'plugin' approach to Munki's inventory collection process then? For example, I could modify my branch to look for and execute scripts in /usr/local/munki/inventory-scripts/* and expect a plist on stdout, which could then get concatenated to the dictionary in memory before it's written to disk. If we did something like that, admins could easily add or remove items from their inventory by simply adding or removing the appropriate script (e.g. 'collect-installed-fonts.sh', 'collect-installed-internet-plug-ins.py', etc.).

...of course it would make the code a little cleaner on both sides if we require those scripts to be python so we could just import them and get the dictionary structure(s) without messing with pipes.

A.E. van Bochoven

unread,
Apr 23, 2013, 10:51:01 AM4/23/13
to munki-w...@googlegroups.com
I already took a shot at this for munkireport-php, I started a rewrite of the engine that allows upload of arbitrary items during pre or postinstall. Its written in python and I think it could be incorporated in mwa.

http://code.google.com/p/munkireport-php/source/browse/?name=rewrite

It's based around is reportcommon.py which should be placed in the munkilib folder. 

-Arjen

Marnin Goldberg

unread,
Apr 23, 2013, 7:06:26 PM4/23/13
to munki-w...@googlegroups.com



On Apr 23, 2013, at 5:16 PM, Josh Tackitt <tack...@reed.edu> wrote:

> Just found this thread while searching for ways to report the FileVault2 status.
>
> I think extending the inventory, specifically so it can include the status of FileVault 2 would be of great value.
>

This is a good idea. Among other enhancements, I've extended the postflight and my Munkireport-php server to accept the results of Rich's FileVault 2 status check script. Works nicely.

The script:
https://github.com/rtrouton/rtrouton_scripts/blob/master/rtrouton_scripts/filevault_2_encryption_check/regular_script/filevault_2_status_check.sh


Marnin

Jeremy Finke

unread,
Jan 17, 2014, 4:08:54 PM1/17/14
to munki-w...@googlegroups.com, goldb...@mail.montclair.edu
I know that this is an old thread.  Just wondering if there was an official direction taken on integrating this into munki or mwa or are people still using homegrown solutions and extending postflight themselves?

Thanks!
Reply all
Reply to author
Forward
0 new messages