Tag Archive for exchange

Microsoft Entourage, Exchange Web Services edition

This new version of Microsoft’s email client for Mac has not gotten much attention, but anyone who uses Entourage to connect to a Microsoft Exchange Server should consider installing the free upgrade. Version 13.0.0 is also known as the “Exchange Web Services” edition. At the time of writing, you need to download and install the update manually from the Microsoft Mac website. It only works with Exchange Server 2007

EWS screen shot

Microsoft has changed the technology the Entourage uses to exchange data with an Exchange Server from WebDAV to Exchange Web Services. This is as important as it sounds! You can notice the effect most clearly when synchronizing large numbers of items, such as when you migrate accounts or sync with a public folder. In my experience, the rate of data transfer has improved by many times. Beware that the upgrade does erase your local Entourage profile, so back up any Entourage data stored locally on your machine first. Any data already stored in your Exchange account will reload from there, so you don’t have to worry about that.

As with the last few versions of Entourage, the EWS edition talks to your organization’s client access server (which also hosts webmail), so Entourage works just as well off-campus and on.

Entourage 13 also synchronizes notes and to-do items, which previous versions did not.

One of our users files his mail into dozens of folders. With Entourage 12, his folders took so long to sync that the Sent Items folder would remain several days out of date, never having the chance to fully synchronize. Version 13 saved our bacon by (presumably) synchronizing more quickly and being able to keep all of his folders updated.

Incidentally, we are also using the EWS protocol in one of our home-grown web scripts to publish a calendar on our website for employee use.

Microsoft Entourage 2008, Exchange Web Services edition

Calendar request web form for MS Outlook

For a while, we have used the moderated folder and custom form features of Microsoft Outlook and Microsoft Exchange to allow users to request school vehicles for trips and other purposes. It didn’t work well. Our users view this public folder calendar through Outlook, Entourage, and Outlook Web Access. Only Outlook supports custom forms. Public folders were difficult to find. They don’t sync well with Entourage. It was a mess.

With our upgrade to Exchange 2007, we decided to move away from public folders and create buses as resources instead. At the same time, we wanted to build an easier-to-use request form for users. We wondered whether we could build a simple web script (in Perl or PHP) and send Outlook a calendar object that it could use.

It worked! Uncharacteristically, Microsoft uses an open, standard format for calendar entries. Below, I have reproduced part of a script I wrote that sends a .vcs (vcalendar) file as an attachment that our transportation coordinator may open in Outlook, review, and add to a calendar. May other potential uses for this exist.

Please do try this code and let me know any improvements you make. This is only part of our script code. It won’t work on your server as is!


use Time::Local;
use CGI qw(:standard);
use Net::SMTP;

sub write_form {

param(-name=>'action', -value=>'save_form');

$output = start_form .
p . "Please complete the following form to request a school vehicle." .
"<div style=\"border:1px solid black; padding:5px; margin:20px 0 20px 0;\"><b>Required Information</b>" .
p . "Activity: " . textfield(-name=>'activity', -size=>60) .
p . "Destination: " . textfield(-name=>'destination', -size=>60) .
p . "Depart date: " . popup_menu(-name=>'depart_month', -values=>['',@months], -labels=>\%month_labels) . ' ' . popup_menu(-name=>'depart_day', -values=>['',@mdays]) . ' ' . popup_menu(-name=>'depart_year', -values=>['',@years], -default=>$year) . ' Hour: ' . popup_menu(-name=>'depart_hour', -values=>['',@hours], -labels=>\%hours_labels) . ' Min: ' . popup_menu(-name=>'depart_min', -values=>['',@mins]) .
p . "Return date: " . popup_menu(-name=>'return_month', -values=>['', @months], -labels=>\%month_labels) . ' ' . popup_menu(-name=>'return_day', -values=>['',@mdays]) . ' ' . popup_menu(-name=>'return_year', -values=>['',@years], -default=>$year) . ' Hour: ' . popup_menu(-name=>'return_hour', -values=>['',@hours], -labels=>\%hours_labels) . ' Min: ' . popup_menu(-name=>'return_min', -values=>['',@mins]) .
p . "Driver: " . textfield(-name=>'driver', -size=>'30') .
'  ' . "Contact: " . textfield(-name=>'contact', -size=>'30') .
p . "Number of students + adults: " . textfield(-name=>'total_number', -size=>'3') .
p . "Depart from: " . checkbox_group(-name=>'depart_from', -values=>['Gym','Theater']) .
p . "Division/Department: " . textfield(-name=>'division_department', -size=>'20') . "</div>" .

"<div style=\"border:1px solid black; padding:5px; margin:20px 0 20px 0;\"><b>Optional Information</b>" .
p . "Rental vehicle types (e.g., minivan, SUV, cargo van): " . textfield(-name=>'rental_vehicle_types', -size=>'40') .
p . "Other details: " . checkbox_group(-name=>'other_details', -values=>['Cargo van','Drop off only','Pick up only','Overnight trip']) .
p . "Special requests: " . textfield(-name=>'special_requests', -size=>'60') . "</div>" .
p . submit(-name=>'submit', -value=>'Submit Request') . hidden(-name=>'action') . endform;

$template =~ s/\$body/$output/;
$template =~ s/\$title/Request Transportation/g;
print header . $template;


sub save_form {

# check for empty minute fields
if (!param('depart_min')) {param(-name=>'depart_min', -value=>'00');}
if (!param('return_min')) {param(-name=>'return_min', -value=>'00');}

# convert dates to GMT
$depart_localtime = timelocal(0,param('depart_min'),param('depart_hour'),param('depart_day'),param('depart_month'),param('depart_year'));
$return_localtime = timelocal(0,param('return_min'),param('return_hour'),param('return_day'),param('return_month'),param('return_year'));
($s,$n,$h,$d,$m,$y) = gmtime($depart_localtime); $y+=1900;
$vcs_depart_time = $y . sprintf("%02d",$m) . sprintf("%02d",$d) . 'T' . sprintf("%02d",$h) . sprintf("%02d",$n) . sprintf("%02d",$s) . 'Z';
($s,$n,$h,$d,$m,$y) = gmtime($return_localtime); $y+=1900;
$vcs_return_time = $y . sprintf("%02d",$m) . sprintf("%02d",$d) . 'T' . sprintf("%02d",$h) . sprintf("%02d",$n) . sprintf("%02d",$s) . 'Z';

# format vcs file
PRODID:-//Microsoft Corporation//Outlook MIMEDIR//EN
LOCATION:" . param('destination') . "
DESCRIPTION;ENCODING=QUOTED-PRINTABLE:Activity: " . param('activity') . "=0D=0ADestination: " . param('destination') . "=0D=0ADepart time: " . param('depart_month') . "/" . param('depart_day') . "/" . param('depart_year') . " " . param('depart_hour') . ":" . param('depart_min') . "=0D=0AReturn time: " . param('return_month') . "/" . param('return_day') . "/" . param('return_year') . " " . param('return_hour') . ":" . param('return_min') . "=0D=0ADriver: " . param('driver') . "=0D=0AContact: " . param('contact') . "=0D=0ANumber of students + adults: " . param('total_number') . "=0D=0ADepart from: " . join(", ", param('depart_from')) . "=0D=0ADivision/Department: " . param('division_department') . "=0D=0ARental vehicle types: " . join(", ", param('rental_vehicle_types')) . "=0D=0AOther details: " . join(", ", param('other_details')) . "=0D=0ASpecial requests:" . param('special_requests') . "=0D=0A
SUMMARY:" . param('activity') . "

# send mail
$smtp = Net::SMTP->new('localhost');
$smtp->datasend("To: Transportation Coordinator\n");
$smtp->datasend("From: $fullname\n");
$smtp->datasend("Subject: Transportation request\n");
$smtp->datasend("MIME-Version: 1.0\n");
$smtp->datasend("Content-Disposition: attachment; filename=\"request.vcs\"\n");
$smtp->datasend("Content-Type: application/text; name=request.vcs\n");
$smtp->datasend($vcs . "\n\n");

# return html
$output = "Thank you. The transportation coordinator will review this request and then assign it to a vehicle. Please check the transportation calendar in a day or two to confirm your reservation.<P><a href=$cgiurl>Submit another transportation request</a>";
$template =~ s/\$body/$output/;
$template =~ s/\$title/Transportation Request Sent/g;
print header . $template;


But will it include calendars?

Apple says:

Snow Leopard includes out-of-the-box support for Microsoft Exchange 2007

Does this mean just mail, or mail+calendar, or the whole package? Note that even Microsoft Entourage does not sync Notes or Tasks with Exchange Server.

On a related note, Jon Udell has built a small script (exchange2ical) to publish iCal feeds for Exchange calendars!

I wonder which approach will bear fruit most quickly.

AppleScript for laptop deployment and maintenance

Working in AppleScript again for the first time in many years, I have written a series of scripts that I hope will combine into a single application to partially automate fall laptop prep. Each fall, we collect and maintain 350 teacher and laptop students, a grossly time-consuming effort. Many configuration tasks involve opening an application and changing settings — difficult to do quickly and with consistently high accuracy. AppleScript has the ability to program changes in configuration.

As quirky as AppleScript is, it provides an ideal bridge between OS X GUI user friendliness and command-line power. Partly, this is because AppleScript can call execute shell and Perl commands, so one has the power of all three languages available. For example, the script collects the user’s password from a GUI window and then calls the shell commands cp to copy a missing driver from our file server to the local system and lpadmin to add the printers. One includes the password in the shell statement using simple text concatenation. Same for the Entourage configuration — capture the user name from AppleScript’s “name of current user” and then pass it to the Entourage configuration statement. Finally, you can package the entire thing into an executable application for use in-house or distribution to users. Way cool.

The first script turns off automatic VLAN detection for Cisco Clean Access agent, a feature that causes processor utilization to spike every few seconds, reducing battery life. The second automatically adds 20 or so SMB printers to the Macintosh using lpadmin, a useful post-restore action. A third configures Microsoft Entourage for our mail server. Next, I would like to set the user’s server shortcuts, check for proper antivirus operation, and check Acrobat Reader version.

Please note: these scripts are currently under development (they’re not yet finished) and contain Catlin Gabel-specific settings. Please use them to inform your own script-writing. They won’t work as-is on your network. Many thanks to William M. Smith for a couple key tips. His Entourage/Exchange setup script is terrific if you’re looking for that function — better generalized than what I have provided below.

-- Cisco Clean Access patch for CCAAgent
-- Disables automatic VLAN detection

do shell script "whoami"
set theUser to the result

do shell script "cp /applications/ccaagent.app/contents/resources/setting.plist \"/users/" & theUser & "/library/application support/cisco systems/ccaagent/preference.plist\""

tell application "System Events"
set the thePListPath to "/Users/" & theUser & "/Library/Application Support/Cisco Systems/CCAAgent/preference.plist"
tell application "System Events"
tell property list file thePListPath
tell contents
set previousValue to value
set value to ({|VlanDetectInterval|:"0"} & previousValue)
end tell
end tell
end tell
end tell

display alert "Auto VLAN detection turned off!"

-- Adds Catlin Gabel printers

-- get desired divisions
set theDivisions to {"LS", "MS", "US", "All"}
choose from list theDivisions with prompt "Which division?"
set theDivision to result as text

-- get user name and password
do shell script "whoami"
set theUser to the result
set thePassword to text returned of (display dialog "User's network password" default answer "" with hidden answer)

-- configure lists of printers, names, and driver file locations
-- need to add Graceland

set lsPrinterNames to {"LS 2nd grade", "LS Comp Lab B&W", "LS Library B&W - Duplexing", "LS Library Color - Duplexing", "LS Office - Duplexing", "LS Spanish", "LS French", "LS Japanese"}
set msPrinterNames to {"MS Library Color - Duplexing", "MS Mobile Blue", "MS Office", "MS Secret Garden - Duplexing", "MS Upper Hall"}
set usPrinterNames to {"US Art B&S", "US Dant 9 - Duplexing", "US Dant 12 - Duplexing", "US Dant Main - Duplexing", "US Dant 10", "US Library B&W - Duplexing", "US Comp Lab Color - Duplexing", "US Math - Duplexing", "US Modern Lang 2 - Duplexing", "US Modern Lang 5 - Duplexing", "US Office - Duplexing", "US Science Main", "US Vollum Learning Center Copier", "US Vollum Main - Duplexing"}

set lsPrinterDrivers to {"HP LaserJet 2200.gz", "HP LaserJet 4250.gz", "HP LaserJet 4000 Series.gz", "HP Color LaserJet 4650.gz", "HP LaserJet 4000 Series.gz", "HP LaserJet 4MP.gz", "HP LaserJet 4MP.gz", "HP LaserJet 1320 Series.gz"}
set msPrinterDrivers to {"HP Color LaserJet 4600.gz", "HP LaserJet 2100 Series.gz", "HP LaserJet 4100 Series.gz", "HP LaserJet 5MP.gz", "HP LaserJet 1320 Series.gz"}
set usPrinterDrivers to {"HP LaserJet P2015.gz", "HP LaserJet 2200.gz", "HP LaserJet 4350.gz", "HP LaserJet 4000 Series.gz", "HP LaserJet 4100 Series.gz", "HP Color LaserJet 4600.gz", "HP LaserJet 2300.gz", "HP LaserJet 2300.gz", "HP LaserJet 2300.gz", "HP LaserJet 4250.gz", "HP LaserJet 2100 Series.gz", "RICOH Aficio MP 161", "HP LaserJet 4100 Series.gz", "HP LaserJet 4100 Series.gz"}

-- copy Ricoh driver from installer folder to system PPD library
tell application "Finder"
open location "smb://" & theUser & ":" & thePassword & "@cgsfiles01/installers"
end tell
do shell script "cp \"/Volumes/Active/RICOH Aficio MP 161\" \"/Library/printers/PPDs/Contents/Resources/\""

-- set range of printers to install
if theDivision is equal to "ls" then
set thePrinters to lsPrinters
set thePrinterNames to lsPrinterNames
set thePrinterDrivers to lsPrinterDrivers
end if
if theDivision is equal to "ms" then
set thePrinters to msPrinters
set thePrinterNames to msPrinterNames
set thePrinterDrivers to msPrinterDrivers
end if
if theDivision is equal to "us" then
set thePrinters to usPrinters
set thePrinterNames to usPrinterNames
set thePrinterDrivers to usPrinterDrivers
end if
if theDivision is equal to "All" then
set thePrinters to lsPrinters & msPrinters & usPrinters
set thePrinterNames to lsPrinterNames & msPrinterNames & usPrinterNames
set thePrinterDrivers to lsPrinterDrivers & msPrinterDrivers & usPrinterDrivers
end if

-- loop through printers
repeat with x from 1 to the number of items in thePrinters
do shell script "/usr/sbin/lpadmin -p " & item x of thePrinters & " -E -v smb://" & theUser & ":" & thePassword & "@CATLIN/CGSPRINT01/" & item x of thePrinters & " -P \"/Library/Printers/PPDs/Contents/Resources/" & item x of thePrinterDrivers & "\" -D \"" & item x of thePrinterNames & "\" -o printer-is-shared=false"
end repeat

-- do shell script "/usr/sbin/lpadmin -p ITVLMOFC -E -v smb://" & theUser & ":" & thePassword & "@CATLIN/CGSPRINT01/ITVLMOFC -P \"/Library/Printers/PPDs/Contents/Resources/HP Laserjet 4000 Series.gz\" -D \"IT Vollum Office\" -o printer-is-shared=false"

display alert "Printers successfully added!"

-- Configure Entourage

tell application "System Events"
set theUser to name of current user
set fullName to full name of current user
end tell
set thePassword to text returned of (display dialog "User's network password" default answer "" with hidden answer)

tell application "Microsoft Entourage"

make new Exchange account with properties {name:"Catlin Gabel", Exchange server settings:{address:"https://webmail.catlin.edu/exchange", requires SSL:"true"}, Exchange ID:theUser, domain:"catlin", full name:fullName, email address:theUser & "@catlin.edu", LDAP server:"cgsdc00", search base:"ou=catlin users,dc=catlin,dc=edu", public folder server settings:{address:"https://webmail.catlin.edu/public", requires SSL:"true"}}

set enabled of schedule "Send & Receive All" to scheduled

end tell