Automating Manual munki Imports with autopkg – Part 2: Autodesk Maya

In a previous post, I discussed how I created a .munki recipe for importing macOS installers into a munki_repo with the necessary settings to complete an erase and install.

In this second part, my focus is on Autodesk Maya, which has long been a challenge for admins. As an education institution, we have a standalone license, so while this post does not address network licensing it may still prove helpful.

TL;DR – you can create a .munki recipe that imports a DMG with an app inside but which ultimately removes the normally created installs array and instead creates an artificial package receipts array!

See more info past the jump.

Licensed Silent Install

Before dealing with the recipe (originally I had created the recipe first), I wanted to deal with the challenge of how to actually get a successful licensed deployment. Autodesk does have a number of articles for how to do this silently, however I was initially very unsuccessful. For reference, these are those articles:

If you have dealt with Maya deployments in the past where every year is different, the 2020 version follows this trend. However, Autodesk added a deployment_maya.xml template apparently in an effort to make things easier (oh, the irony). This template is located in Install Maya 2020.app/Contents/Helper/manifest/deployment_maya.xml. From what I gathered from the instructions, below is the final deployment file I created (where XXX-ABCDEFGH would be your unique license). For testing purposes, I only tried installing Maya and simply commented out the not applicable license settings.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Deployment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Identity>
        <Name>Autodesk Maya 2020</Name>
        <UPI2>{4DFC17CC-DE75-47D8-867C-BF8962267737}</UPI2>
        <Platforms>
            <Platform architecture="x64" minVersion="10.11" name="Mac" />
        </Platforms>
        <Languages>
            <Language langId="en-US" />
        </Languages>
    </Identity>
    <Configuration>
        </Configuration>
    <Eula src="https://www.autodesk.com/eula">
        <Status>Accept</Status>
    </Eula>
    <LoggingSettings>
        <Logging>true</Logging>
        <Path>/Library/Logs</Path>
        <Name>autodesk_maya_2020_deployment.log</Name>
    </LoggingSettings>
    <Applications>
        <!-- CORE MAYA APP -->
        <Application>
            <Name>Maya</Name>
            <UPI2>{19988503-984D-46F1-8222-6C76C135AD41}</UPI2>
            <Manifest>manifest/app.maya.xml</Manifest>
            <Core>true</Core>
            <Install>true</Install>
            <LicenseSetting>
                <Name>MayaStandaloneLicense</Name>
                <SerialNumber>XXX-ABCDEFGH</SerialNumber>
                <ProductKey>657L1</ProductKey>
                <ProductVersion>2020.0.0.F</ProductVersion>
                <ConfigFile>MayaConfig.pit</ConfigFile>
            </LicenseSetting>
        </Application>
        <!-- PLUGINS -->
        <Application>
            <Name>MtoA</Name>
            <UPI2>{2F46F1A9-6506-45B7-94FC-CB88773A9A48}</UPI2>
            <Manifest>manifest/app.mtoa.xml</Manifest>
            <Core>false</Core>
            <Install>false</Install>
        </Application>
        <Application>
            <Name>Bifrost</Name>
            <UPI2>{3221ED25-1A12-4076-96BE-1E30428FF6C3}</UPI2>
            <Manifest>manifest/app.bifrost.xml</Manifest>
            <Core>false</Core>
            <Install>false</Install>
        </Application>
        <Application>
            <Name>Substance</Name>
            <UPI2>{10F85F13-FF62-4A64-BD02-919CCB0B9A52}</UPI2>
            <Manifest>manifest/app.substance.xml</Manifest>
            <Core>false</Core>
            <Install>false</Install>
        </Application>
        <Application>
            <Name>Rokoko</Name>
            <UPI2>{7B6A9A0D-8603-441C-B25C-CD9636CE1A23}</UPI2>
            <Manifest>manifest/app.rokoko.xml</Manifest>
            <Core>false</Core>
            <Install>false</Install>
        </Application>
    </Applications>
    <LicenseSettings>
        <!-- <LicenseSetting>
            <Name>MayaDistributedNetworkLicense</Name>
            <NetworkLicense>
                <Distributed>
                    <Server>Server1</Server>
                    <Server>Server2</Server>
                </Distributed>
            </NetworkLicense>
        </LicenseSetting>
        <LicenseSetting>
            <Name>MayaNetworkLicense</Name>
            <NetworkLicense>
                <Single>
                    <Server>Server1</Server>
                </Single>
            </NetworkLicense>
        </LicenseSetting>
        <LicenseSetting>
            <Name>MayaRedundantNetworkLicense</Name>
            <NetworkLicense>
                <Redundant>
                    <Server>Server1</Server>
                    <Server>Server2</Server>
                    <Server>Server3</Server>
                </Redundant>
            </NetworkLicense>
        </LicenseSetting> -->
        <LicenseSetting>
            <Name>MayaStandaloneLicense</Name>
			<SerialNumber>XXX-ABCDEFGH</SerialNumber>
			<ProductKey>657L1</ProductKey>
			<ProductVersion>2020.0.0.F</ProductVersion>
			<ConfigFile>MayaConfig.pit</ConfigFile>
        </LicenseSetting>
        <!-- <LicenseSetting>
            <Name>MayaUserLicense</Name>
            <UserLicense />
        </LicenseSetting> -->
    </LicenseSettings>
</Deployment>

Despite using this file however, every attempt to install our standalone license per Autodesk instructions resulted in either immediate failure or a successful install without our standalone license being registered. The only difference between these two results was the use or absence of -i deploy in the command.

Immediate failure:

sudo /path/to/Install\ Maya\ 2020.app/Contents/Helper/Setup.app/Contents/MacOS/Setup -i deploy --silent --deployment /path/to/custom/deployment_maya.xml

Successful install w/o license on first launch:

sudo /path/to/Install\ Maya\ 2020.app/Contents/Helper/Setup.app/Contents/MacOS/Setup --silent --deployment /path/to/custom/deployment_maya.xml

In previous Maya deployments, I had relied on this Jamfnation thread for insight on what other admins had tried and which worked. A post in this thread referred to a new 2020 thread, but the method listed there involved installing each of the contained packages manually instead of calling the Setup binary and having Maya deal with what needed to be installed and in the correct order. Personally, I’m not a proponent of that method but the post proved helpful as the example included a reference to the AdskLicensingInstHelper command line tool. After reading the help information for this binary, I learned that this tool does in fact allow you to add, change, and remove Autodesk licensing information.

I’ve included the binary and register argument usage below for reference.

AdskLicensingInstHelper usage:

"/Library/Application Support/Autodesk/AdskLicensing/Current/helper/AdskLicensingInstHelper" --help
NAME:
   AdskLicensingInstHelper - Manage products registration with Autodesk Licensing

USAGE:
   AdskLicensingInstHelper [global options] command [command options] [arguments...]

VERSION:
   2.2.1.156

COMMANDS:
     register    Register product with the licensing components. Requires admin rights
     deregister  Deregister product from the licensing components. Requires admin rights
     list        List all products registered with licensing components
     change      Change registered product
                 
                 
     help, h     Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --help, -h     show help
   --version, -v  print the version

AdskLicensingInstHelper register usage:

"/Library/Application Support/Autodesk/AdskLicensing/Current/helper/AdskLicensingInstHelper" register --help
NAME:
   AdskLicensingInstHelper register - Register product with the licensing components. Requires admin rights

USAGE:
   AdskLicensingInstHelper register [command options] 
   Legend:
     [R] - required
     [O] - optional

OPTIONS:
   --prod_key key, --pk key             [R] key of the product to register (e.g. "001K1")
   --prod_ver version, --pv version     [R] version of the product to register (e.g. "2019.0.0.F")
   --config_file path, --cf path        [R] product's PIT config file path
   --eula_locale value, --el value      [R] EULA locale (e.g. "US")
   --feature_id key, --fi key           [O] alternate key of the product to register (e.g. "ACD", for license method USER only)
   --lic_method value, --lm value       [O] Selected license method during install. Should be one of (case insensitive): USER, STANDALONE, NETWORK
   --lic_server_type value, --lt value  [O] network license server type. Should be one of (case insensitive): SINGLE, REDUNDANT, DISTRIBUTED
   --lic_servers value, --ls value      [O] list of comma separated network license server addresses. For example: @127.0.0.1,@192.168.1.1,@9.0.9.0
   --serial_number value, --sn value    [O] serial number to register the product with (default 000-00000000)
   --sel_prod_key key, --sk key         [O] selected key for products installed as a bundle or suite (e.g. "784K1")
   --no_user_license, --nu              [O] set if this product does not want to support user licensing

With this information, I was able to successfully run the installation as well as activate our standalone license (I copied the Maya install app to /private/tmp):

sudo /private/tmp/Install\ Maya\ 2020.app/Contents/Helper/Setup.app/Contents/MacOS/Setup --silent && sudo "/Library/Application Support/Autodesk/AdskLicensing/Current/helper/AdskLicensingInstHelper" register --pk 657L1 --pv 2020.0.0.F --cf /private/tmp/Install\ Maya\ 2020.app/Contents/Helper/MayaConfig.pit --el US --lm STANDALONE --sn ${your_serial}

After confirming this, I had the core of my postinstall script to do the actual installing and licensing. The template below includes the autopkg variables I use in my recipe, but you could replace these if you wanted to use for your own purposes:

#!/bin/bash

# Install path variables
INSTALLERPATH="%DESTINATION_PATH%/Install Maya 2020.app"
CONFIG="${INSTALLERPATH}/Contents/Helper/MayaConfig.pit"
KEY="%MAYA_KEY%"
LICENSE_EXE="/Library/Application Support/Autodesk/AdskLicensing/Current/helper/AdskLicensingInstHelper"
LICENSE_TYPE="%MAYA_LICENSE_TYPE%"
LOCALE="%MAYA_LOCALE%"
SERIAL="%MAYA_SERIAL%"
SETUP="${INSTALLERPATH}/Contents/Helper/Setup.app/Contents/MacOS/Setup"
VERSION="%MAYA_VERSION%"

# Exit & error if installer doesn't exist
if [ ! -d "$INSTALLERPATH" ]; then
    /bin/echo "${INSTALLERPATH} does not exist. Exiting ..."
    exit 1
fi

# Run Maya 2020 installer
"$SETUP" --silent

# Verify AdskLicensingInstHelper exists
if [ -f "$LICENSE_EXE" ]; then
    # Register Maya 2020
    "$LICENSE_EXE" register --pk "$KEY" --pv "%MAYA_VERSION%" --cf "$CONFIG" --el "$LOCALE" --lm "$LICENSE_TYPE" --sn "$SERIAL"
else
    /bin/echo "${LICENSE_EXE} does not exist. Exiting ..."
    exit 1
fi

If you happen to have a license type other than standalone, refer to the AdskLicensingInstHelper register usage info to determine how to add your applicable license, replacing the license command in the above script template (take especial note of the required options).

UPDATE: 08/03/20 If you happen to use Mudbox, please see the comments at the bottom for an updated postinstall_script to get licensing working.

Import Recipe

With the necessary commands to achieve a licensed install, the next step was to create the munki autopkg recipe. My initial recipe can be found here (don’t use it because the listed posinstall_script was from the 2019 version).

The problem with this first recipe attempt was that it was based on the app version accurately reflecting the version and the minor/patch version. However, as of the latest Maya release (2020.2) and the original release, this is not the case, as both the app’s CFBundleVersion and CFBundleShortVersionString have a version of 2020. This meant that if you had attempted to import the software into munki that it would indicate you have an existing item with the same version, and even if forcibly imported it it would never update an existing Maya 2020 installation since the app version would be the same.

The good news is that the Maya_core2020.pkg contained in the Maya installer app does include both the major and minor versions in the package receipt. Using the PackageInfoVersioner Shared Processor from the Facebook autopkg repo, we can collect this and supply it in the needed places. However, this processor did not also include collecting the package id AKA the receipt. Some additional testing and a PR later, PackageInfoVersioner now collects the package id.

Given this, the ultimate question was now whether or not it was possible to import a DMG with a contained .app into munki while simultaneously overwriting the produced installs array and create an artificial munki receipts array? While there are other packages that get installed by default besides the core package (ex. licensing), for this purpose I think this is sufficient.

As it turns out, you can create an arbitrary receipts array and override the installs array, and all while using the native autopkg processors! The applicable recipe processors are listed below followed by the actual XML:

  • FlatPkgUnpacker – unpack the Maya_core2020.pkg
  • PkgPayloadUnpacker – unpack the resulting payload
  • CodeSignatureVerifier – verify the Maya 2020 app code signature is what’s expected
  • PackageInfoVersioner (Shared processor) – as mentioned previously, to get the package id and version of the unpacked package payload
  • MunkiPkginfoMerger – merge the collected package id and version into a receipts array, create an intentionally blank installs array, and use the collected package version for the munki item version
  • MunkiImporter – import the item into a munki_repo with the merged info
<dict>
    <key>Arguments</key>
    <dict>
        <key>flat_pkg_path</key>
        <string>%found_filename%/Install Maya 2020.app/Contents/Helper/Packages/Maya/Maya_core2020.pkg</string>
        <key>destination_path</key>
        <string>%RECIPE_CACHE_DIR%/unpack</string>
    </dict>
    <key>Processor</key>
    <string>FlatPkgUnpacker</string>
</dict>
<dict>
    <key>Arguments</key>
    <dict>
        <key>destination_path</key>
        <string>%RECIPE_CACHE_DIR%/%NAME%/Applications/Autodesk/maya2020</string>
        <key>pkg_payload_path</key>
        <string>%RECIPE_CACHE_DIR%/unpack/Payload</string>
    </dict>
    <key>Processor</key>
    <string>PkgPayloadUnpacker</string>
</dict>
<dict>
    <key>Arguments</key>
    <dict>
        <key>expected_authority_names</key>
        <array/>
        <key>input_path</key>
        <string>%RECIPE_CACHE_DIR%/%NAME%/Applications/Autodesk/maya2020/Maya.app</string>
        <key>requirement</key>
        <string>identifier "com.autodesk.Maya.2020" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = XXKJ396S2Y</string>
        <key>strict_verification</key>
        <true/>
    </dict>
    <key>Processor</key>
    <string>CodeSignatureVerifier</string>
</dict>
<dict>
    <key>Arguments</key>
    <dict>
        <key>package_info_path</key>
        <string>%RECIPE_CACHE_DIR%/unpack/PackageInfo</string>
    </dict>
    <key>Processor</key>
    <string>com.facebook.autopkg.shared/PackageInfoVersioner</string>
</dict>
<dict>
    <key>Comment</key>
    <string>Create a receipt based on the Maya core PKG, since this is the only place the major and minor versions are listed. Also write blank installs array to avoid undesirably having the installer app serve as an indicator of the item being installed.</string>
    <key>Arguments</key>
    <dict>
        <key>additional_pkginfo</key>
        <dict>
            <key>installs</key>
            <array/>
            <key>receipts</key>
            <array>
                <dict>
                    <key>packageid</key>
                    <string>%pkg_id%</string>
                    <key>version</key>
                    <string>%version%</string>
                </dict>
            </array>
            <key>version</key>
            <string>%version%</string>
        </dict>
    </dict>
    <key>Processor</key>
    <string>MunkiPkginfoMerger</string>
</dict>
<dict>
    <key>Arguments</key>
    <dict>
        <key>pkg_path</key>
        <string>%found_filename%</string>
        <key>repo_subdirectory</key>
        <string>%MUNKI_REPO_SUBDIR%</string>
    </dict>
    <key>Processor</key>
    <string>MunkiImporter</string>
</dict>

Using the Recipe

Per the instructions in the recipe description (be sure you’ve added my recipe repo – https://github.com/autopkg/apizz-recipes.git – and Facebook’s – https://github.com/facebook/Recipes-for-Autopkg.git – in order to use the required shared processor):

  1. Download a copy of Autodesk Maya 2020.
  2. Create a recipe override of the recipe.
  3. Specify a PATH where the recipe will look for a Maya 2020 DMG. If applicable, move your downloaded Maya 2020 to this location.
  4. Specify a DESTINATION_PATH which munki will copy the install app to on endpoints. This will also be inserted in the required places in the postinstall script for installation.
  5. Enter your license type in MAYA_LICENSE_TYPE. Valid options are USER, STANDALONE, and NETWORK.
  6. If applicable, update the MAYA_LOCALE. Default is ‘US’.
  7. Enter your Maya’s SERIAL to be used in the postinstall script to activate the software.
  8. Run the recipe.
  9. Profit.

Reflection & Looking Ahead

In closing, we managed to take the process of manually importing Autodesk’s Maya 2020 and working out some of the … nuances … to automate the bulk of getting this imported into a munki_repo with autopkg.

While this works for my own immediate purposes, you could take this a step further by incorporating something like the SMBMounter Shared Processor to point your autopkg instance to a shared network folder, rather than one directly on your system or one that’s already mounted.

If you have questions or comments, post ’em below!

3 comments

  1. Pingback: Automating Manual munki Imports with autopkg – Part 3: Pro Tools | apizz
  2. sonic68 · 10 Days Ago

    I use munki to deploy Mudbox which is very similar to Maya the licensing is pretty much the same. I used the licensing part of your post install script here are the settings I used for licensing Mudbox. The big difference is where Mudbox looks for the MudboxConfig.pit file, Mudbox looks in /Library/Application Support instead of in the .app directory like Maya does. Right now I am just importing the mudbox.dmg file into munki and changing the location where it copies the installer to /private/tmp then I have the following script set as a post install script in the pkginfo file. Thanks for doing all the heavy lifting it made Mudbox easier to manage this year.

    #!/bin/sh

    # Install path variables
    CONFIG=”/Library/Application Support/Autodesk/Adlm/PIT/2020/MudboxConfig.pit”
    KEY=”498L1″
    LICENSE_EXE=”/Library/Application Support/Autodesk/AdskLicensing/Current/helper/AdskLicensingInstHelper”
    LICENSE_TYPE=”STANDALONE”
    LOCALE=”US”
    SERIAL=”xxx-xxxxxx”
    VERSION=”2020.0.0.F”

    # Install command for Mudbox
    /private/tmp/Install\ Mudbox\ 2020.app/Contents/MacOS/setup –noui –force

    # licensing Mudbox 2020
    # after running your installer do the following:

    # Verify AdskLicensingInstHelper exists
    if [ -f “$LICENSE_EXE” ]; then
    # Register Mudbox 2020
    “$LICENSE_EXE” register –pk “$KEY” –pv “$VERSION” –cf “$CONFIG” –el “$LOCALE” –lm “$LICENSE_TYPE” –sn “$SERIAL”
    else
    /bin/echo “${LICENSE_EXE} does not exist. Exiting …”
    exit 1
    fi

    # Remove the Mudbox installer
    /bin/rm -rf /private/tmp/Install\ Mudbox\ 2020.app

    Like

    • apizz · 10 Days Ago

      Thanks for this! I’m sure others will find this helpful.

      Like

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s