backup_ast 1.0 - Easy Asterisk config file backups

As an Asterisk administrator, I'm working with config files all the time. Any work involving the phone system involves modifying a configuration file and then reloading that part of Asterisk. Before making changes, it's important to make a backup copy of the file just in case. I got tired of always typing cp /etc/asterisk/filename.conf /etc/asterisk/backup/filename.conf.201205092008 so I wrote a script that will ease in backing up either a configuration file, all of them, or a group of them, such as DAHDI.

You can find the script here:
http://pastebin.com/x9BiPmvG

Once you download the script, I recommend putting it somewhere in /usr/local/bin/, making it executable, and then running it with the -h flag to see some usage examples.

Please feel free to post with any questions. The script doesn't do much error checking as it doesn't make any changes to any files. It just checks that the backup directories are indeed available. I tried really hard to catch every possible case, but if you think of one I missed, please feel free to share and I'll quite possibly add it.

Posted
 

Asterisk 1.8 queue_log to MySQL

Information about how to do this has been posted elsewhere on the web, but most of it is significantly outdated. Moving forward with our Asterisk upgrade project we decided that we'd like to see not only CDR data written to MySQL but also the Asterisk queue_log. For those of you unfamiliar with the queue_log (this post is probably meaningless if that's you), it is the logfile in which Asterisk stores call data about calls that enter queues. It's located at /var/log/asterisk/queue_log

First things first: You need a MySQL database to use, and you need the asterisk-addons and asterisk-addons-mysql packages installed. If you use CentOS or RHEL you can use "yum install asterisk-addons asterisk-addons-mysql" to install the packages, assuming you've configured the Digium yum repos.

Once you've got the addons installed, the next thing you'll want to do is create the database table to store the asterisk queue_log data. There are two separate table structures you can choose from. The first defaults to writing the extra data associated with a queue call to one field in the database. Personally, I thought doing it that way was stupid. If you have up to five fields of data, why store it in one field per database entry? Split it up. Thankfully, someone else thought of that too and there's an undocumented option you can use to do it. More on that later. Assuming you want to use the cleaner, separated data form, this was my table structure:

USE asterisk;

CREATE TABLE queue_log (
  id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  time char(26) default NULL,
  callid varchar(32) NOT NULL default '',
  queuename varchar(32) NOT NULL default '',
  agent varchar(32) NOT NULL default '',
  event varchar(32) NOT NULL default '',
  data1 varchar(100) NOT NULL default '',
  data2 varchar(100) NOT NULL default '',
  data3 varchar(100) NOT NULL default '',
  data4 varchar(100) NOT NULL default '',
  data5 varchar(100) NOT NULL default '',
  PRIMARY KEY (`id`)
);

Once you have the table created, the next steps involve changes to the Asterisk server.

In /etc/asterisk/res_config_mysql.conf, change the [general] context to point to the database. Mine looks like this:

[general]
dbhost = 10.10.10.10
dbname = asterisk
dbuser = asteriskserver
dbpass = supersecretpwd
dbport = 3306
requirements=warn

In /etc/asterisk/logger.conf, change queue_log_to_file = no to yes. This will write the queue_log to the file in /var/log/asterisk regardless of any other destinations. Directly below that line, add queue_adaptive_realtime = yes. The queue_adaptive_realtime option is undocumented in the file but it is what splits the data into multiple fields before writing to the database.

Finally, in /etc/asterisk/extconfig.conf uncomment out queue_log => mysql,general.

After all those changes are made, restart asterisk with "core restart now". Once restarted, if you type "reload", you should see the following on the console:

asterisk*CLI> reload
  == Parsing '/etc/asterisk/extconfig.conf':   == Found
  == Binding queue_log to mysql/general/queue_log
  == Parsing '/etc/asterisk/logger.conf':   == Found
       > Found column 'id' of type 'int(10) unsigned'
       > Found column 'time' of type 'char(26)'
       > Found column 'callid' of type 'varchar(32)'
       > Found column 'queuename' of type 'varchar(32)'
       > Found column 'agent' of type 'varchar(32)'
       > Found column 'event' of type 'varchar(32)'
       > Found column 'data1' of type 'varchar(100)'
       > Found column 'data2' of type 'varchar(100)'
       > Found column 'data3' of type 'varchar(100)'
       > Found column 'data4' of type 'varchar(100)'
       > Found column 'data5' of type 'varchar(100)'
 Asterisk Queue Logger restarted

If things seem to go awry, check the /var/log/asterisk/messages file for clues. Typically you will see the errors below unless you're also using the res_config_mysql.conf file to define parameters for the Asterisk RealTime Architecture. 

[Mar 27 16:45:26] WARNING[3575] res_config_mysql.c: MySQL RealTime: No database user found, using 'asterisk' as default.
[Mar 27 16:45:26] WARNING[3575] res_config_mysql.c: MySQL RealTime: No database password found, using 'asterisk' as default.
[Mar 27 16:45:26] WARNING[3575] res_config_mysql.c: MySQL RealTime: No database host found, using localhost via socket.
[Mar 27 16:45:26] WARNING[3575] res_config_mysql.c: MySQL RealTime: No database name found, using 'asterisk' as default.
[Mar 27 16:45:26] WARNING[3575] res_config_mysql.c: MySQL RealTime: No database port found, using 3306 as default.
[Mar 27 16:45:26] WARNING[3575] res_config_mysql.c: MySQL RealTime: No database socket found (and unable to detect a suitable path).

Selecting from the database should show output similar to this:
Queue_log_mysql
That's it! Hopefully this was useful. Feel free to post any questions or comments.
Posted
 

Lion Server Profile Manager: First Day Experiences

Today I finally had the time to begin experimenting with Profile Manager built into Mac OS X Lion Server. Apple's documentation is extremely poor to say the least, so that has forced me to make some assumptions based solely on discoveries of my own throughout the day. If any of them are wrong, please leave a comment and let me know otherwise.

Here's what I found.

Setup

The setup process for Profile Manager and the MDM server bundled into it is extremely easy.

  1. Ensure proper DNS and then setup the server to be an Open Directory Master. 
  2. Create a new self-signed certificate and use that to generate a CSR for a real CA. We use Entrust here at RMU. 
  3. Submit your CSR, get a real, valid, SSL certificate and then replace the self-signed cert with the one signed by your CA of choice. 
  4. Install any intermediate certificates and then select the new cert to be the primary one for the server. 
  5. Click the "Edit" button next to "Device Management" on the Profile Manager pane of Server.app and go through the steps, one of which being the process of acquiring an Apple Push Notification Sevice (APNS) certificate. 
  6. Check the box for "Sign configuration profiles" and use the self-signed OD CA Code Signing Certificate, or purchase a real code-signing certificate from a CA (not really necessary). 
  7. If you want to change the name of the global settings for everyone profile, do that.
  8. Turn on Profile Manager.

Initial "Oooh Ahh" factor

After Profile Manager lets you know it's fully ready for use, you can access it as an admin at https://server.example.com/profilemanager

After logging in, you're presented with an "oh wow this is pretty" website. But imemdiately after the "wow" factor wears off is when you're left hoping for more detailed documentation. Similarly to Workgroup Manager, it's clear that you can assign profiles at the User, Group, Computer, or Computer Group level. Clicking around the various groups and users shows it's not very difficult to build different profiles for respectively different groups. However, there's no documentation on levels of precidence nor on how conflicting settings will interact. Initial testing by Arek Dreyer shows that Device profiles tend to take precedince over User or User Group profiles. Also gone is the concept of "Always", "Often", "Once", and "Never". Things applied through the use of Profiles essentially are always at the "Always" level of persistency. 

Things that should be documented

  1. By default, everyone is in the "Everyone" group. The "Everyone" group has the option checked to allow members of the group to "Enable Remote Management" under "Portal Access." This means that by default, everyone can enroll their devices into Profile Manager; probably not what you want to have enabled. It also means that trying to turn off the ability to enroll devices is greyed out at the user level. Disabling the option at the group level then of course unlocks the ability to set it per-user.
  2. Only admins can see Enrollment profiles when logged in to the user portal.
  3. You cannot pre-associate a user with a device. Therefore profiles configured for devices and device groups will never show as available for download in the user portal. Only user and user group profiles will show.
  4. Along with number 3, if you set a profile's distribution type to "Manual Download," it will only show in the list in the user portal if it is a user or user group profile, not a device or device group profile.
  5. Along with number 3 and 4, if a device or device group profile distribution method is set to "Manual Download", the only way to get access to these is to download them as an admin through the admin portal and distribute them via some other means. They will never be shown in the user portal.
  6. There is currently no way to lock trust profiles or device management profiles. Only configuration profiles. This means an admin user can easily remove their device from device management.
  7. Why anyone would ever need more than two, a "Restricted" and and an "Unrestricted", enrollment profiles. The only option for enrollment profiles is whether or not the computer is required to be in the devices list prior to enrolling. Maybe I'm not understanding these properly, but here at RMU I imagine I'd only ever use a Restricted Enrollment Profile? Perhaps I'd want more if I want a more granular view of the "Usage" of the particular enrollment profile?

Bugs I found

  1. My trust profile didn't immediately show in the user portal as available for download. In Server.app, even though it was already selected, I had to select the code-signing OD CA self-signed certificate again and profile manager rewrote the settings.  It then became available for download. This happens after every restart of the Profile Manager service.
  2. My trust profile is named "Trust profile for" but is missing the domain or name of the server. Running "sudo serveradmin settings devicemgr:server_organization = fqdn.example.com has no effect.
  3. Using Firefox 7 with the admin web interface presented some problems. Active tasks wouldn't change to completed unless I reloaded manually. Safari also had some issues with this, but less often.
  4. When manually importing a plist to the "Custom Settings" section of a profile, you're unable to delete more than one key out of that plist at a time. Pressing shift or command to select multiple items does not work. For example, if you import the Safari plist but only need the HomePage key, you'll be there for quite awhile clicking "delete" on the unneeded keys. As a workaround, write a plist to your desktop with the same name only containing the keys you need. Then upload that.
  5. There is no way to resize the columns in the "Activity" panes in the admin portal. There is a lot of available screen space but the web app keeps the columns super tiny.

Overall first day experiences

A lot of bugs. A lot of confusion. Shit poor documentation. The best third-party resource I currently know of is Arek Dreyer's presentation at MacSysAdmin 2011. Listen to his presentation; it has a lot of good sidenotes.

Remote wipe and remote lock are both cool. Note that remote lock immediately reboots the machine; there is no prompt and no opportunity to save.

If this is the tool that Apple wants us to use to replace MCX and Workgroup Manager, it's got a long way to go. MCX is well understood and has extremely detailed documentation. We sys admins don't just want to know how to do something, we want to know WHY it works the way it does and what to do when it doesn't. This was my favorite line from the Apple Profile Manager documentation:

To send the URL of the Profile Manager server to a user so they can log in and download the configuration profiles you assigned to them, click the arrow next to Visit User Portal, then copy the URL from the browser window that opens.

Thank you, Apple, for that extremely helpful lesson on copying and pasting. I could have never figured that out by myself!

I'll leave off with this. Profile Manager's logging isn't so bad. But often it says this:

Oct 19 16:19:54 server.example.com ProfileManager[13678] <Info>: Processing MagicController#do_magic (for ip.ad.dr.ess at 2011-10-19 16:19:54) [POST]

Do Magic through the MagicController, huh? I'd really like to know what that is.

Friends in cupertino...

Profile Manager | Editing a custom imported plist | Deleting Multiple Keys
rdar://problem/10317006

Profile Manager | Activity Panes | Unable to resize/wrongly sized columns
rdar://problem/10317034

Profile Manager | Trust profile unavailable for download after service restart
rdar://problem/10317052

Profile Manager | Trust profile missing organization name
rdar://problem/10317107

Profile Manager | Add ability to lock trust and enrollment profiles
rdar://problem/10317143

Profile Manager | Updates to documentation
rdar://problem/10317170

 

Posted
 

Using The Luggage with Apps that have spaces in their names

Recently when trying to build a package using The Luggage, I noticed that it would choke on apps that had spaces in their names. Doing some searching, I discovered that making it work is as simple as adding a custom stanza to the makefile for each app/file that has a space. The package I was making was a custom installer for RMU's new VMware View remote access system. It included Microsoft's "Remote Desktop Connection", VMware's "VMware View Client", a postflight scipt to write the "view.rmu.edu" entry to a preference file, and a custom welcome message and background for the installer.

Here's my makefile:

include /usr/local/share/luggage/luggage.make

TITLE=RMU_VMware_View
REVERSE_DOMAIN=edu.rmu
PAYLOAD=unbz2-application-Remote_Desktop_Connection.app \
        unbz2-application-VMware_View_Client.app \
        pack-script-postflight \
        pack-resource-Welcome.rtf \
        pack-resource-background.gif
PACKAGE_VERSION=1

unbz2-application-Remote_Desktop_Connection.app: Remote_Desktop_Connection.app.tar.bz2 l_Applications
        @SUDO ${TAR} xjf Remote_Desktop_Connection.app.tar.bz2 -C ${WORK_D}/Applications
        @SUDO chown -R root:admin "${WORK_D}/Applications/Remote Desktop Connection.app"

unbz2-application-VMware_View_Client.app: VMware_View_Client.app.tar.bz2 l_Applications
        @SUDO ${TAR} xjf VMware_View_Client.app.tar.bz2 -C ${WORK_D}/Applications
        @SUDO chown -R root:admin "${WORK_D}/Applications/VMware View Client.app"

Notice that instead of the usual "unbz2-applications-XXXX.app" I used "unbz2-application-xxxx.app" and included those stanzas in the Makefile itself. Note the quotes around the names in the chown lines. The pack-xxx stanzas came from the included luggage.make file; it's not necessary to reproduce these in your makefile, so long as the files don't include spaces in their names.

Hope this helps someone!

Posted
 

Setting Asterisk 1.8 Caller ID from Legacy PBX Systems

Unfortunately we still have numbers registered to our old Nortel PBX. After many trials, we have been unsuccesful at passing the caller ID name from the Nortel PBX to our Asterisk systems.  We implemented the following solution/workaround into the [stdexten] subroutine.

After
exten => _X.,n,Set(LOCAL(mbx)="${ext}"$["${cntx}" ? "@${cntx}" :: ""])
but before
exten => _X.,n,Dial(${dev},20)                  ; Ring the interface, 20 seconds maximum
we added this line:

exten => _X.,n,Set(CALLERID(name)=${IF(${DB_EXISTS(cidname/${CALLERID(num)})}?${DB(cidname/${CALLERID(num)})}:${CALLERID(name)})})

That line checks to see if there is an Asterisk database entry for the caller ID number in the database family "cidname". We've loaded all of our Nortel users' names and extensions into astdb. If there is an entry in the databse, that line overrides whatever is in sip.conf or whatever, if anything, is coming over the wire.

Here's an example. Let's say I have a phone registered at extension 1000 with the caller ID line set to "Mike Boylan" <1000> in sip.conf. If I do the following, the caller ID will be changed when I dial (to any number that uses stdexten) to "Legacy PBX CID".

asterisk7*CLI> database put cidname 1000 "Legacy PBX CID"
Updated database successfully

asterisk7*CLI> database show cidname
/cidname/1000                                     : Legacy PBX CID 

You can see in the console that when I dial, the CID Name was changed:

asterisk7*CLI>
  == Using UDPTL CoS mark 5
  == Using SIP RTP CoS mark 5
    -- Executing [4805@rmuld:1] Gosub("SIP/1000-00000085", "4805,stdexten(SIP/4805)") in new stack
    -- Executing [4805@rmuld:50000] NoOp("SIP/1000-00000085", "Start stdexten") in new stack
    -- Executing [4805@rmuld:50001] Set("SIP/1000-00000085", "LOCAL(ext)=4805") in new stack
    -- Executing [4805@rmuld:50002] Set("SIP/1000-00000085", "LOCAL(dev)=SIP/4805") in new stack
    -- Executing [4805@rmuld:50003] Set("SIP/1000-00000085", "LOCAL(cntx)=") in new stack
    -- Executing [4805@rmuld:50004] Set("SIP/1000-00000085", "LOCAL(mbx)="4805"""") in new stack
    -- Executing [4805@rmuld:50005] Set("SIP/1000-00000085", "CALLERID(name)=Legacy PBX CID") in new stack
    -- Executing [4805@rmuld:50006] Dial("SIP/1000-00000085", "SIP/4805,20") in new stack
  == Using UDPTL CoS mark 5
  == Using SIP RTP CoS mark 5
    -- Called SIP/4805
    -- SIP/4805-00000086 is ringing
  == Spawn extension (rmuld, 4805, 50006) exited non-zero on 'SIP/1000-00000085'

If you can get your legacy PBX systems to send Caller ID information, including the name, to Asterisk, great. But if you're like us and struggle to do so, this is a very reasonable workaround. Your users will never know, nor do they care, how the CID information is being set.

Posted
 

Inception Style Installation of CS 5.5 Master Collection

Adobe Application Manager Enterprise Edition is a great tool for sys admins that need to manage Creative Suite installations. It allows sys admins to disable EULA and registration reminders, kill off Adobe Air, turn off updates, etc. The only problem with the tool is that the packages it produces, although technically native Apple PKGs, really are not. There's no feedback given during install time as the package is essentially just a massive script copying files. The other problem is that AAMEE packages are extremely slow to install. Using Munki for my images this year, I noticed the initial bootstrapping of a machine was taking upwards of an hour to complete, with more than a half an hour of that time dedicated to the Creative Suite installation. I wanted to fix that.

Problem: Installing Creative Suite (CS) 5.5, all of the additional content, and all of the current CS 5.5 updates was taking, cumulatively, 31 minutes. That was accounting for more than half of the bootstrapping time of a new machine being configured with Munki.

What I did: I launched Composer on a machine that was freshly imaged. I pointed Munki to a manifest file that only included the Creative Suite installation (including the extra content and updates) and allowed it to do its thing. For 31 minutes or so. After Creative Suite was finished installing, I created a package in Composer based on what was installed.

Essentially, I made a Composer package of a Munki installation of an AAMEE generated Creative Suite Package. Inception much?

The results: The Composer built package, which includes the entire Creative Suite, all of the extra content, and all of the updates takes only 13 minutes to install using Munki. That's almost 60% faster than having Munki install the AAMEE packages.

Was the extra time spent repackaging the Munki installation of an AAMEE generated Creative Suite Package worth it? Absolutely. It will significantly cut the time required to bootstrap a new machine.

EDIT: Everyone should also read the comment below by Greg Neagle. Fortunately what he describes does not affect my environment at Robert Morris, but it may very well affect yours. 

Posted
 

Snow Leopard Static Mapper - Version 1.0

In response to a thread on the Mac OS X Server mailing list, I took it upon myself to write a small application that can assist Mac OS X Server administrators in creating static DHCP mappings to be imported into Server Admin.

 

This application was written to be a Snow Leopard compatible replacement for Scott Finney's "Leopard Static Map Importer". The functionality is the same with the only difference being the exported plist is able to be imported into a Snow Leopard server. The code base is my own. Scott had nothing to do with this project nor does this imply any endorsement from Scott as a replacement for his application.

 

Screen_shot_2011-07-03_at_5

 

The application is lightweight and was written in AppleScript Objective-C.

Version 1.0 can be downloaded here:

http://mboylan.me/2X1r0U2o2d1y2w0w102Z

 

Please read the included Read Me file for more information and for how to contact me to report bugs.

 

Feedback is heavily welcomed. If this helps you, please let me know!

 

If you came here from the mailing lists... the build I posted to the lists was actually static "Mappper" with three P's! An extra feature! It works the same, but if the extra P annoys you, download the new build above.

 

Posted
 

Installing Universal Type Client 3.0 with Munki

Edit the file Universal\ Type\ Client\ 3.0.mpkg/Contents/Packages/universalTypeClient.pkg/Contents/Resources/postflight

Change it to look like this:

#!/bin/bash

#set the permissions on the application bundle
sudo chmod -R 775 "$2/Universal Type Client.app"

#set the ownership of the application bundle
sudo chown -R "root:admin" "$2/Universal Type Client.app"

#create UTC directory...
if [ ! -d "/Library/Extensis" ]; then
        sudo mkdir "/Library/Extensis"        
fi

sudo chmod -R 777  "/Library/Extensis"

#create UTC directory...
if [ ! -d "/Library/Extensis/UTC" ]; then
        sudo mkdir "/Library/Extensis/UTC"        
fi

sudo chmod -R 777  "/Library/Extensis/UTC"

#copy the corecli app to the /usr/bin directory and change the permissions on it to: 755
#Doing this instead of adding it to the PackageMaker project because editing the project can cause "bad" stuff like the "relocatable bundle" issue.
if [ -e "$2/Universal Type Client.app/Contents/Resources/corecli" ]; then
        if [ -e "/usr/bin/corecli" ]; then
                sudo ditto --rsrc "$2/Universal Type Client.app/Contents/Resources/corecli" "/usr/bin/corecli"
                sudo chmod 755 "/usr/bin/corecli"
        fi
fi

Same thing as before. Just removing all the code that makes assumptions that shouldn't be made.

Posted
 

Simplifying Frequently Changing IVR Menus in Asterisk 1.8

Many organizations use IVR menus in their phone systems. Certainly we've all heard something like "Thank you for calling Robert Morris University. Please press...". One inherent problem with these menus is that they're generally not easy to maintain -- especially the ones that change frequently. The people that have "control" over these menus generally are able to record new files, but the replacement of the sound files is often a manual process.

Using astdb (or any other database engine asterisk can talk to), the process of managing frequently changing sound files can be simplified.

Using some code snippets I found on the web, along with some of my own brain power, I've put together this early working version of a simple IVR menu changing application. Essentially how it works is each sound file in the menus are assigned an ID and passcode. Every user who can record new sound files also is given a username and password in the "ariusers" context in Voicemail.conf. After authenticating as an allowed user, they then must enter the ID and password of the sound file they'd like to change. When recording is finished, the user is able to listen back at the new sound file, accept it, or rerecord it. After that, they're prompted whether or not they'd like to change another file. If not, the system says thank you and hangs up. On hangup it moves the temp audio file into the right place with the right name that is already referenced in the dialplan.

You'll want to insert two kinds of values into the Asterisk database. Auth values and name values. Example:

asterisk -r -x 'database put recname 64101 isc_64101_thankyou'; sleep 1;
asterisk -r -x 'database put recauth 64101 1234'; sleep 1;

Once your values are inserted and matched to sound files, here's the dialplan code to make this work. Any questions or comments, please post them.

[globals]
; Must be writable by the user running the asterisk process... usually "asterisk"
CUSTOM_RECORDINGS=/var/lib/asterisk/sounds/en/custom

; Somewhere in the dialplan
exten => 5000,1,Gosub(RecordPrompt,${EXTEN},1)

; The special subroutine that makes this all work
[RecordPrompt]
; Handles extension changes over time
exten => _[A-Za-z0-9].,1,NoOp()

; Can this user even use this feature?
same => n,Read(UserID,custom/welcome-user-id);
same => n,VMAuthenticate(${UserID}@ariusers,s);

; Get which message they want to change
same => n(getmessage),Read(MessageID,custom/enter-message-id,5,,,1)
same => n,Read(MessagePWD,custom/enter-message-pwd,4)
same => n,Set(ValidMessagePWD=${DB(recauth/${MessageID})})
same => n,GotoIf($['${MessagePWD}' = '${ValidMessagePWD}']?prerec)
same => n,Playback(option-is-invalid)
same => n,Goto(getmessage)

; This will be our filename
same => n(prerec),Set(RecordedFilename=${DB(recname/${MessageID})})
same => n,Set(RandomNumber=${RAND()})

; Record the prompt
same => n(record),Playback(custom/say-message)
same => n,Wait(1)
same => n,Record(${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav)

; Ask how we want to handle the recording
same => n(handle_recording),Read(ActionItem,vm-review,1)

; Verify we got values we expect
same => n,GotoIf($['${ActionItem}' = '1' | '${ActionItem}' = '2' | '${ActionItem}' = '3']?valid_action)
same => n,Playback(option-is-invalid)
same => n,Goto(handle_recording)

same => n(valid_action),NoOp()
; Handle the recording
; 1 accept, 2 review, 3 re-record
same => n,GotoIf($['${ActionItem}' = '1']?accept) ; keep this recording
same => n,GotoIf($['${ActionItem}' = '3']?record)   ; re-record it

; If we get here they pressed 2
same => n,Playback(${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber})
same => n,Goto(handle_recording)

; Recording accepted, move from tmp to permanent
same => n(accept),Verbose(2,Recording accepted!)
same => n,System(mv ${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav ${GLOBAL(CUSTOM_RECORDINGS)}/${RecordedFilename}.wav)
same => n,Playback(custom/message-updated)

; Do they want to rerecord another message?
same => n(recordanother),Read(RecordAnother,custom/record-another,1)
same => n,GotoIf($['${RecordAnother}' = '1']?getmessage)
same => n,Playback(option-is-invalid)
same => n,Goto(recordanother)

; On hangup remove the tmp file
exten => h,1,Verbose(2,Cleanup the file)
same => n,System(rm -f ${GLOBAL(CUSTOM_RECORDINGS)}/temporaryRecording-${RandomNumber}.wav)
Posted
 

Installing Extensis Universal Type Client 2.1 with Munki

The postflight script for the UTC Preference Pane references environment variables not present when using Munki.

If you're planning to use the UTC installer with Munki, you'll need to modify the postflight script inside the following folder:

Universal\ Type\ Client\ 2.1.mpkg/Contents/Packages/utcoreprefpane.pkg/Contents/Resources

Here's my replacement:

--------------------
#!/bin/bash
#set proper permissions on the prefpane
sudo chmod -R 555 "/Library/PreferencePanes/utcore-prefpane.prefPane"

#This USED to set something in the /L/P domain to the user who installed it first.
#We're using root:admin as that's how things in the /L/P domain should normally be set
#set ownership of the prefpane

sudo chown -R root:admin "/Library/PreferencePanes/utcore-prefpane.prefPane"
---------------------

Notice the removals of the environment variables at the top as well as the addition of the login item at the end of the script. You'll need to add the UTC Helper App as a login item for your users some other way. I recommend using MCX. 

Posted