Packaging NetExtender for Munki

Disclaimer

The following tutorial is based on and works for NetExtender version 7.5.774 for Mac. Your mileage may vary for other versions.

Why does NetExtender need a Munki-fied "update"?

The actual NetExtender application doesn't need anything special for Munki. You can do a regular munkiimport on the .dmg file, and it'll go in just fine and install to users' /Applications folders, as you'd expect any application to.

Likely your organization has some organization-specific parameters you want users to put in, though, and perhaps your own certificate to mark as trusted. One way to go about that is to offer written instructions to your users (type in this URL with this port number, etc.)

You can have the user do this, or you can create an "update" package for NetExtender that will make it so the user has to enter only her username and password.

Overview of NetExtender's configuration files

NetExtender creates several hidden files and folders in a user's directory when she launches up the program:

/Users/username/.netextender has the config preferences for the user

/Users/username/.netExtenderCerts has a folder inside it called PUB_CERT that stores site certificates.

/Users/username/.netExtender.log contains a log for the application. We don't need to worry too much about this file.

Overall procedure for creating "update" package

If you want to create an "update" package, this is how you can do it. First, install NetExtender on a computer and actually VPN in (you may have to be off site or tethered to a hotspot or phone). This will create the files and folders mentioned above.

Once you have the files created, open up the .netextender file with a text editor. You may have to show hidden files in Finder first. Under [profiles], you should see a line with your organization's information and your username and password, delimited by a | symbol (vertical slash). Replace both the username and password information with a single space. There may be a second line with a hashed password—go ahead and delete that line entirely. It should look something like:

[profiles]
blahblahblahconnectioninformation| | |blahblahmoreinformation
It's important to keep the spaces in place of the username and password. Otherwise, this file won't work.

In that same file, under [trustedcerts], you'll see a line for your organization's certificate. Make a note of that line (or copy it to your clipboard or another text file for future reference).

Also go into /Users/username/.netExtenderCerts/PUB_CERT to find your ca-bundle.crt file. You'll need this later.

Create a package (if you're a novice at it like I am, you can use Packages to create the .pkg file using a graphical user interface). For the payload, you want to put .netextender (for visibility's sake, I renamed mine to be netextender and then used the script to put the dot back in front of the name... you can keep it with the dot in front, as long as you modify the script accordingly) and ca-bundle.crt in /Users/Shared, at least the way this script is written. You can modify the script and put the payload elsewhere.

Then, open up a real text editor like TextWrangler or nano (don't use TextEdit), and paste in and modify it as you see fit and save it as PutInConfigs.sh (or whatever you want to call it, really, as long as you can find it later).

#!/bin/bash

# Change to /Users directory
cd /Users

# Loop through existing users
for p in *; do

# Check it's not a user we don't care about
if [[ $p != "adminuseraccount" && $p != "Shared" ]]; then

# See if the user already has a netextender config file
if [ -f /Users/$p/.netextender ]; then

# Append the trusted cert
sed -i .bak 's/\[trustedcerts\]/\[trustedcerts\]\'$'\nblahblahblahalltheinformationfromyourorganizationscertfile/' /Users/$p/.netextender

else
# Copy netextender to user's folder
cp /Users/Shared/netextender /Users/$p/.netextender

# Change ownership to user
chown $p /Users/$p/.netextender

fi

# Make directories for the certificate
mkdir -p /Users/$p/.netExtenderCerts/PUB_CERT

# Copy certificate to the certificates folder
cp /Users/Shared/ca-bundle.crt /Users/$p/.netExtenderCerts/PUB_CERT/

# Change ownership to user
chown -R $p /Users/$p/.netExtenderCerts

# End if
fi

# End loop
done;

# Delete source files
rm /Users/Shared/netextender
rm /Users/Shared/ca-bundle.crt
Be sure to substitute in your actual certificate information for the sed command and also to substitute in any other accounts you don't want modified. See the italicized parts of the script for what you should be looking out for.

Then, using Packages, make this a post-install script (so it'll run after delivering the payload of the two files).

Script Logic

The script loops through all the user accounts (except the ones specified) and then delivers the appropriate files for each user. This is a bit of roundabout hack, so maybe someone can point me in the direction of how to copy only to the logged-in user even though the script itself is running as root. Our use case is one primary user on a laptop, so if it were possible to install it to the currently-logged-in user, that'd be great. Specifying to avoid the other admin accounts seems to be fine, though.

The script will see if an existing .netextender config file already exists. If the config file already exists, the script will take the information about the trusted certs and just insert it into the existing file. If the .nextender file doesn't already exist, the new one will be copied in.

Then it will also make directories (if they don't already exist) needed for the trusted cert(s) and then copy the .crt bundle in.

Finally, it will delete the files-to-be-copied, because they've already been copied.

Importing into Munki

Once you have built your .pkg, use munkiimport to import it into Munki and then mark this "update" package as an update for your actual NetExtender imported .dmg package.

P.S. I use "update" in quotation marks, because it's not strictly an update. It's not like going from 7.5.774 to 7.5.775 or from 7.5 to 7.6. It's only an "update" in the sense that Munki needs to know to install this any time someone installs NetExtender.

LEGO Mindstorms stuck on splash screen

For the odd computer here and there I've had LEGO Mindstorms get stuck on the splash screen (we're talking 10-15 minutes or more). A bit of trouble, but I've found going to /Library/Internet Plug-Ins and deleting the Silverlight.plugin, then reinstalling both Silverlight and LEGO Mindstorms seems to fix it.

Packaging Starry Night College for Munki

The following tutorial is just a more step-by-step version of Multiple guest users on one PC - How to register Starry Night, and with Munki in mind.

starrynightmunki01
Find the Starry Night app in your /Applications folder, right-click it, and select Show Package Contents.

starrynightmunki02
Then, go to Contents > Resources > Sky Data > Resources and find the p.ssd file.

starrynightmunki03
Open up the p.ssd file with a text editor. I'd highly recommend a custom text editor like TextWrangler instead of Mac OS X's built-in TextEdit.

starrynightmunki04
At the bottom of the text file, paste in the following two lines:

<SN_VALUE name="LicenseeName" value="Username">
<SN_VALUE name="LicenseNumber" value="Registration Number">
and replace Username with your actual licensed username and Registration Number with your actual licensed registration number.

Then save and close the file.

starrynightmunki05
Go ahead and do a munkiimport on the Starry Night app. The developer is Simulation Curriculum Corp.

Opening .wps Files without using WordPerfect

Very rarely, you may get a .wps (WordPerfect) file as an attachment instead of a .pdf, .docx, or .pages file. You can ask the sender to re-send it in another format, or you can pay WordPerfect US$220 to install WordPerfect to open one attachment... or you can try to open the .wps file.

Won't work in Google Drive

openingwordperfectfiles01
Google Drive won't open .wps files or convert them to Google Doc files.

Won't work in Microsoft Word

openingwordperfectfiles02
Opening it with Word by right-clicking the file and selecting Word doesn't work.

openingwordperfectfiles03
And selecting the file from within Word also doesn't work...

openingwordperfectfiles04
... you'll get some options to try to interpret the file or get some readable text out of it, but it'll mainly turn out gobbledygook.

Won't work in Page

openingwordperfectfiles05
Pages won't open .wps files.

It does work in LibreOffice!!!

openingwordperfectfiles06
Here's the solution: if you don't want to discard the attachment or have the sender re-send in another format, open the .wps file in LibreOffice. The formatting may not be exactly the same as in WordPerfect, but it will be pretty close.

And the best part is that LibreOffice is cross-platform (it works on Mac, Windows, and Linux).

Creating a Symantec Endpoint Protection package for Munki

Thanks to Erik from the Munki Dev group for the tip.

If you have a newer version of Symantec Endpoint Protection (SEP) that comes as an .app with a separate Additional Resources folder, here is how you can get a Munki-friendly package out of it.

munkisep01
Go ahead and launch up the installer .app file.

munkisep02
Click Continue when prompted.

munkisep03
Don't proceed any further with the installation. Instead, click on the Tool menu and select Create remote deployment package.

munkisep04
Give the package a name and save it to wherever you can find it later.

munkisep05
Then, click OK when you're done and quit out of the installer.

You should then be able to use munkiimport to import the new .pkg file into your Munki repository.

If you're upgrading from an older version of SEP, you may have to adjust what Munki is looking for (otherwise, it will see the com.remote.deploy receipt with version 0 and think the newest version is already installed).

An installs array works well for this (here's an example based on

makepkginfo -f /Applications/Symantec\ Solutions/Symantec\ Endpoint\ Protection.app
output):
<key>installs</key>
<array>
<dict>
<key>CFBundleIdentifier</key>
<string>com.symantec.sep.mainapp</string>
<key>CFBundleName</key>
<string>Symantec Endpoint Protection</string>
<key>CFBundleShortVersionString</key>
<string>14.0.2415.0200</string>
<key>CFBundleVersion</key>
<string>12</string>
<key>minosversion</key>
<string>10.6</string>
<key>path</key>
<string>/Applications/Symantec Solutions/Symantec Endpoint Protection.app</string>
<key>type</key>
<string>application</string>
<key>version_comparison_key</key>
<string>CFBundleShortVersionString</string>
</dict>
</array>

Restoring a deleted recovery partition on a Mac

Update

This is only one method to restore the missing recovery partition. Check out Recreating a deleted recovery partition on a Mac for another method.

The Missing Recovery Partition Problem

I don't actually know how a recovery partition gets deleted, but I've come across a few Macs with the partition deleted, and I've been looking for a way to restore them, because if you don't have the recovery partition and you want to boot into recovery mode (holding down Cmd-R at startup), you'll have to boot into Internet Recovery Mode (which will involve you connecting to a wireless network and downloading a temporary recovery).

Outdated Solution

Apparently, for Mac OS X Lion and Mountain Lion, Apple had this program called Recovery Disk Assistant that let you install a recovery partition (on an external drive, but presumably you could do it on an internal one, too). I also found an article from April, 2015 talking about Recovery Disk Assistant and OS X Lion. The one comment on the article says This may be a dumb question, but I have a slow internet. Can I do this with Yosemite? No reply there. It would be great to have solution that works for Yosemite.

Less-than-ideal Solution

I found an article called Pro tip: Restore the recovery partition in OS X 10.10 Yosemite that advises either reinstalling OS X (not ideal) or restoring using Carbon Copy Cloner. I tried to follow the instructions to restore using Carbon Copy Cloner, but I couldn't find a Recovery HD button to click.

Working Solution

I finally figured out a solution on my own (with lots of help from Apple Boot Partition and Enable Disk Utility's Debug Menu).

The gist of it is you clone an existing recovery partition and then change it to an Apple Boot partition. Details to follow.

What you'll need:

  • One Mac missing a recovery partition (of course—that's why you're here, right?). I'll refer to this Mac as Mac #1.
  • At least one other Mac that already has a working recovery partition on it. I'll refer to this Mac as Mac #2.
  • A Thunderbolt cable to connect the two Macs.

Boot into Mac #2, log in as an admin user, and then paste into Terminal.app the following command so you'll be able to see the debug menu in Disk Utility:

defaults write com.apple.DiskUtility DUDebugMenuEnabled 1
restorerecoverypartition00
When you launch up Disk Utility afterwards, you should see a new menu called Debug. From that menu, select Show every partition. You should now be able to see hidden partitions (including one called Recovery HD).

Boot Mac #1 into target disk mode and then attach it to Mac #2 using a Thunderbolt cable. You should see Mac #1's partitions show up in Mac #2's Disk Utility.

restorerecoverypartition01
Click on Mac #1's hard drive (not the partitions underneath), select the Partition tab, and click the plus sign (+) to add a new partition. You won't be able to drag the partition size to be very small (I think the smallest you can make the new partition by mouse-dragging is about 6 GB), but if you type in a value (e.g., .65—or anything less than 1), it'll automatically bump the value up to 1.07 GB. That should be fine, since the normal recovery partition is 650 MB, which isn't that far off from 1.07 GB. If you want to make the partition even smaller, you can explore disk management from the command line.

restorerecoverypartition02
You'll be asked if you really want to repartition. You backed up your data on Mac #1 already, right? Or the data isn't that important to you? Either way, repartitioning is usually fine, but there is a small risk you could lose data. Act accordingly.

restorerecoverypartition03
Once you have repartitioned Mac #1, click on Recovery HD for Mac #2 and select the Restore tab. Drag Macintosh HD 2 (the newly-created small partition) to Destination, and then click Restore.

restorerecoverypartition04
Click Erase, when prompted.

restorerecoverypartition05
When it's done, we still have one more important step to undertake. You'll see, if you click on the old Recovery HD, that its Partition Type is Apple Boot Partition.

restorerecoverypartition06
And the new Recovery HD's Format is Mac OS Extended (Journaled). If you leave it that way, holding down Cmd-R at startup will still go to Internet Recovery Mode instead of regular Recovery Mode (and manually selecting the new partition by holding down the Option key at startup will just lead you to a do-not-enter symbol).

restorerecoverypartition07
Close out Disk Utility and launch up the Terminal. Enter the command

diskutil list
to list out the partitions and drives.

Identify the partition to fix. It should be TYPE Apple_HFS and NAME Recovery HD. In this case, it's /dev/disk2s3, but be sure to look at how it's displayed in your setup (the numbers may be different from this example).

Unmount the partition (substitute your numbers for #, where appropriate):

diskutil unmountDisk /dev/disk#s#
Then put in a command like the following (substituting in your actual disk numbers) to change the partition type:
sudo asr adjust -target /dev/disk#s# -settype Apple_Boot

restorerecoverypartition08
If you launch up Disk Utility now, you should see that the Recovery HD on Mac #1 is type Apple Boot Partition, and recovery mode should now work on that Mac.

Running a post-uninstall script for a Munki package

Much as I love editing text files and entering commands into Terminal.app, I do also appreciate a good GUI frontend. Apart from munkiimport, I mainly manage Munki using MunkiAdmin, as I referenced in Absolute beginner’s guide to setting up Munki (not monkey).

Of course, I got a bit too comfortable with the GUI frontend, and I put in incorrectly a post-uninstall script for a package and got back this error message: Error executing script postuninstall_script: [Errno 8] Exec format error.

After I actually read the Munki wiki page on Pre And Postinstall Scripts, I realized my mistake—I'd put in only the command I wanted without giving the environment for that command.

munkiadminpostuninstallscript
Turns out (which makes sense in hindsight) I had to put in

#!/bin/bash
before putting the actual command to run after the uninstall.

In case anyone else who's GUI-dependent (and who also hasn't read the wiki carefully) runs into this issue, that's the solution—put in the environment you're using (Is it bash, shell, python, etc.?), and not just the command itself.

Configure Mac Remote Management from the Terminal

On a Mac, if you want to remotely manage the client machine using ARD (Apple Remote Desktop), you can go to System Preferences > Sharing > Remote Management.

What if you want to configure a user to remotely manage the machine but you have only SSH access (or you want to run a script instead of going through the GUI)?

A command like this will help:

sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Resources/kickstart -configure -users username -access -on -privs -all -restart -agent
Just sub in the actual username for username.

More details at Apple Remote Desktop: Configuring remotely via command line (kickstart).

Using MySQL with MunkiReport

By default, MunkiReport uses its own embedded sqlite database, which apparently isn't as robust as MySQL (the sqlite website has more information on sqlite's appropriate uses and limitations). If you are extremely unfamiliar with MySQL databases, you may want to just stick with the default sqlite database until you are. I have a basic tutorial on how to set up MunkiReport with some sensible and relatively easy defaults.

I won't go step by step with how to configure MySQL, because there are a lot of intricacies and when you move off the default sqlite to MySQL, you'll likely have your own preferences for how you want to implement it.

That said, the following facts may help you if you are familiar with MySQL but aren't as familiar with MunkiReport:

  • This guide is handy for getting MySQL in general set up on macOS 10.12 (Sierra).
  • You do have to manually create a MySQL user and MySQL database (MunkiReport will create the tables).
  • Everything you need to configure MySQL is in the MunkiReport config.php file you copied from the original config_default.php. Simply uncomment the lines for MySQL and comment out the lines for sqlite.
  • Assuming you are installing the MySQL database to the same server as MunkiReport, all the values should be good, except you may want to change the dbname (default is munkireport), the pdo_user (default munki), and the pdo_pass (default munki) to whatever the database, username, and password is for your MySQL database.
  • You do actually have to still create the password hashes and usernames for MunkiReport admins and put them into the config.php file***. There is no user or user authentication table in the MySQL database.
  • Even though you've copied and customized the config.php, deleting the original config_default.php file will break MunkiReport. Leave that file alone.
  • While you can migrate your sqlite data to MySQL, there probably isn't a need. Once your Munki clients check in on their own, the database will pretty much re-create itself.

*** Another alternative is to use LDAP or Active Directory authentication. You can find more details about that in the comments of the config_default.php file.

Restoring a Mac partition to its full size

Usually, when you add a new partition to a Mac using Disk Utility, you can then just (minus sign) delete the new partition and Disk Utility will automatically expand your first partition to take up the free space.

Occasionally, Macs will act weird and not fill up the free space and, more importantly, not let you manually drag the old partition to fill up the free space. You're just stuck with unusable free space.

There is a relatively simple solution that involves only a couple of terminal commands. (Thanks to the Restore Macintosh HD to its original partition configuration thread on Stack Exchange for the tip.)

Boot up into recovery mode (Cmd-R at startup). If you want to be extra safe, use Disk Utility to back up your first partition in case something goes wrong.

Go to Utilities > Terminal.

Enter in this command:

diskutil cs list
and get the Logical Volume UUID of your partition-to-expand.

Then run

diskutil cs resizeStack XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX 0g
where XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX is the UUID in question.

expandpartition01
You should see the progress of your partition expanding.

expandpartition02
Then you'll see it verifying the volume.

That's it. Your partition should now be fully expanded.