Creating Shared Calendars on Exchange 2010
With Public Folders slowly, painfully making their way out from Exchange, you might find a need to replace shared calendars that traditionally you would have used a public folder for. While Sharepoint is a great option, using Shared Mailboxes isn't a bad idea either.
One of the issues with creating a Shared Mailbox for a Calendar is that as well as creating the mailbox, often you'll need to add folder permissions to the Calendar for Editors, Reviewers and perhaps publish iCal and Web URLs for subscriptions. And the chances are, you probably don't want the Shared Mailbox auto-mapped to the owner's Outlook client.
To make the process a little more simple, I've written a short script that wraps up all this into a single script, allowing you to specify the initial owners (who get full access to the mailbox) and optionally an initial set of people who can edit the calendar and an initial list of calendar viewers. You can choose to publish the iCal and Web URLs (which are provided in the script output), and the manager and department fields are auto-populated from the first owner specified.
Finally, you'll also find a basic set of documentation (in word format, so you can alter to your own needs) that you can provide to the users to help them get started managing their new shared calendar.
Here's a quick example of the script's usage, in it's simplest form:
And using the full set of options:
The full script follows, along with a download link for a zip file containing the script and user documentation:
.SYNOPSIS
Creates a mailbox for use as a shared calendar
Steve Goodman
.DESCRIPTION
Creates a shared mailbox, assigns owner(s), with full access, along with editors and viewers. Restricts mail to authenticated users.
Additionally generates a HTML/iCal published URL if specified.
.PARAMETER Name
Name of the Shared Calendar. Used for the Display Name
.PARAMETER SamAccountName
Optional - Pre-Windows 2000 Login name to use when creating the mailbox. If not specified, uses defaults
.PARAMETER UserPrincipalName
Optional - User Principal Name (UPN) to use when creating the mailbox. If not specified, uses defaults
.PARAMETER Database
Optional - Mailbox Database to use
.PARAMETER OrganizationalUnit
Optional - AD Organizational Unit to use when creatng the mailbox. If not specified, uses defaults.
.PARAMETER Owners
List of the people who should be the owners of the mailbox. The first will be specified as the "manager" field, their department used, and all owners will be given "Full Access" mailbox permissions. The Auto-Mapping will be removed.
.PARAMETER Editors
Optional - List of the people who should have editor access on the Calendar
.PARAMETER Reviewers
Optional - List of the people who should have viewer access on the Calendar
.PARAMETER WebPublish
Optional - Publish the Calendar via private iCal and HTML URLs. Defaults to False. Requires Default Sharing Policy to allow Web Publishing.
.EXAMPLE
Creates a new calendar, allowing defaults:
New-SharedCalendar.ps1 -Name "Test Calendar" -Owners steve,lisa -Editors isabelle,peter -Reviewers liz,drew
.EXAMPLE
Creates a new calendar, many options set
New-SharedCalendar.ps1 -Name "Shared Calendar" -SamAccountName sharedcalendar -UserprincipalName sharedcalendar@sgdev.stevieg.org -Database DB01 -OrganizationalUnit sgdev.stevieg.org/People -Owners sgoodman,fstone -Editors epitts,csutton -Reviewers fcarson -WebPublish:$True
#>
param(
[parameter(Position=0,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Calendar Name")][string]$Name,
[parameter(Position=1,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Logon Name (SAM Account Name)")][string]$SamAccountName,
[parameter(Position=2,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Logon Name (User Principal Name)")][string]$UserPrincipalName,
[parameter(Position=3,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Mailbox Database")]$Database,
[parameter(Position=4,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Organizational Unit")][string]$OrganizationalUnit,
[parameter(Position=5,Mandatory=$true,ValueFromPipeline=$false,HelpMessage="Mailbox Owners")][array]$Owners,
[parameter(Position=6,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Calendar Editors")][array]$Editors,
[parameter(Position=7,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Calendar Reviewers")][array]$Reviewers,
[parameter(Position=8,Mandatory=$false,ValueFromPipeline=$false,HelpMessage="Publish (privately) via the web?")][bool]$WebPublish=$false
)
# Check all pre-reqs
if ((Get-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin -ErrorAction SilentlyContinue))
{
throw "Exchange 2007 Management Console Not Supported"
}
if (!(Get-Command New-Mailbox -ErrorAction SilentlyContinue))
{
throw "Please launch the Exchange 2010 Management Shell"
}
# Setup splatting hashtable
$NewSharedMailbox = @{
"Shared" = $True
"Name" = $Name
}
# Check parameters OK and add relevant parameters to splatting hashtable
$Recipient=Get-Recipient $Name -ErrorAction SilentlyContinue
if ($Recipient)
{
$Recipient
throw "Recipient $($Name) Exists (See above)"
}
if ($SamAccountName)
{
$Recipient=Get-Mailbox $SamAccountName -ErrorAction SilentlyContinue
if ($Recipient)
{
$Recipient
throw "Recipient $($SamAccountName) Exists (See above)"
}
$NewSharedMailbox.Add("SamAccountName",$SamAccountName)
}
if ($UserPrincipalName)
{
$Recipient=Get-Mailbox $UserPrincipalName -ErrorAction SilentlyContinue
if ($Recipient)
{
$Recipient
throw "Recipient $($UserPrincipalName) Exists (See above)"
}
$NewSharedMailbox.Add("UserPrincipalName",$UserPrincipalName)
}
if ($Database)
{
$MailboxDatabase=Get-MailboxDatabase $Database -ErrorAction SilentlyContinue
if (!$MailboxDatabase)
{
throw "Mailbox Database $($Database) not found"
}
$NewSharedMailbox.Add("Database",$Database)
}
if ($OrganizationalUnit)
{
$objOrganizationalUnit = Get-OrganizationalUnit $OrganizationalUnit -ErrorAction SilentlyContinue
if (!$objOrganizationalUnit)
{
throw "Organizational Unit $($OrganizationalUnit) not found"
}
$NewSharedMailbox.Add("OrganizationalUnit",$OrganizationalUnit)
}
if ($Owners.Count -eq 0)
{
throw "You must specify at least one owner"
}
foreach ($Owner in $Owners)
{
if (!(Get-Mailbox $Owner -ErrorAction SilentlyContinue))
{
throw "Owner mailbox $($Owner) not found"
}
}
if ($Editors)
{
foreach ($Editor in $Editors)
{
if (!(Get-Mailbox $Editor -ErrorAction SilentlyContinue))
{
throw "Editor mailbox $($Editor) not found"
}
}
}
if ($Reviewers)
{
foreach ($Reviewer in $Reviewers)
{
if (!(Get-Mailbox $Reviewer -ErrorAction SilentlyContinue))
{
throw "Reviewer mailbox $($Reviewer) not found"
}
}
}
# Create mailbox
Write-Host -ForegroundColor Green "Creating Shared Calendar Mailbox"
$Mailbox = New-Mailbox @NewSharedMailbox
if (!$Mailbox)
{
throw "An error occurred creating the shared calendar mailbox"
}
$DomainController = $Mailbox.OriginatingServer
$Mailbox
# Set Owner Details including Department to match the first specified Owner
Write-Host -ForegroundColor Green "Setting Shared Calendar Mailbox Owner, Department and Description"
$Mailbox | Set-User -Manager (Get-User $Owners[0]) -Department ((Get-User $Owners[0]).Department) -DomainController $DomainController
# Set Description
$LDAPUser = [ADSI]"LDAP://$($DomainController)/$($Mailbox.DistinguishedName)"
$LDAPUser.description = "Shared Calendar"
$LDAPUser.SetInfo()
$LDAPUser = [ADSI]"LDAP://$($DomainController)/$($Mailbox.DistinguishedName)"
Write-Host "Manager: $($LDAPUser.manager)"
Write-Host "Department: $($LDAPUser.department)"
Write-Host "Description: $($LDAPUser.description)"
# Set authenticated mail only
$Mailbox | Set-Mailbox -RequireSenderAuthenticationEnabled:$true
# Set Owner Permissions
Write-Host -ForegroundColor Green "Adding Shared Calendar Mailbox Owner Permissions and removing Outlook auto-mapping"
foreach ($Owner in $Owners)
{
# Add Permission
$Mailbox | Add-MailboxPermission -User $Owner -AccessRights FullAccess -DomainController $DomainController
# Remove Auto-Mailbox mapping
$LDAPUser=[ADSI]"LDAP://$($DomainController)/$($Mailbox.DistinguishedName)"
$LDAPUser.msExchDelegateListLink.Remove(((Get-Mailbox $Owner).DistinguishedName))
$LDAPUser.SetInfo()
}
if ($Editors -or $Reviewers)
{
# Wait until Mailbox is ready before adding folder permissions
Write-Host -ForegroundColor Green "Waiting until mailbox folder structure is available before adding folder permissions"
$MailboxReady=$False
while ($MailboxReady -eq $False)
{
Write-Host -NoNewline "."
$Result = Get-MailboxFolderStatistics $Mailbox -ErrorAction SilentlyContinue
if ($Result)
{
$MailboxReady = $True
}
sleep 5
}
Write-Host
}
# Set Editor Permissions
if ($Editors)
{
Write-Host -ForegroundColor Green "Adding Editor permissions to Calendar"
foreach ($Editor in $Editors)
{
Add-MailboxFolderPermission "$($Mailbox.SamAccountName):\Calendar" -User $Editor -AccessRights Editor -DomainController $DomainController
}
}
# Set Reiewer Permissions
if ($Reviewers)
{
Write-Host -ForegroundColor Green "Adding Reviewer permissions to Calendar"
foreach ($Reviewer in $Reviewers)
{
Add-MailboxFolderPermission "$($Mailbox.SamAccountName):\Calendar" -User $Reviewer -AccessRights Reviewer -DomainController $DomainController
}
}
# Publish Calendar
if ($WebPublish)
{
if (((Get-SharingPolicy | Where {$_.Default -eq $True}).Domains|Where {$_.Domain -eq "anonymous"})) {
Write-Host -ForegroundColor Green "Publishing Calendar using private URL"
Set-MailboxCalendarFolder -Identity "$($Mailbox.SamAccountName):\Calendar" -DetailLevel FullDetails -PublishDateRangeFrom OneYear -PublishDateRangeTo OneYear -PublishEnabled:$true -SearchableUrlEnabled:$false -DomainController $DomainController
$MailboxCalendarFolder = Get-MailboxCalendarFolder -Identity "$($Mailbox.SamAccountName):\Calendar" -DomainController $DomainController
Write-Host -ForegroundColor Yellow -NoNewline "Web URL: "
Write-Host $MailboxCalendarFolder.PublishedCalendarUrl
Write-Host -ForegroundColor Yellow -NoNewline "iCal URL: "
Write-Host $MailboxCalendarFolder.PublishedICalUrl
} else {
Write-Host -ForegroundColor Yellow "Skipping Web/iCal Publishing because Default Sharing Policy does not allow web publishing (to anonymous domains)"
}
}
Download the Script and User Documentation
Shared Exchange Calendars on iOS devices
Just a quick post on how to view an Exchange 2010 shared calendar/mailbox on your iPhone or iPad…
Once you’ve (or your admin has) configured Exchange to allow iCal publishing, you can then send links via email from the shared calendar mailbox itself:
On the iOS device, you can then click the webcal: link in the email, which will allow you to subscribe to the Calendar:
Simple!
Managing iCal Calendar Sharing with Exchange 2010 SP1 [Updated]
One of the new features available in Exchange 2010 SP1 that I’m excited about (and already making use of) is the ability to share calendars from Exchange either in iCalendar or HTML format.
So – why is this useful? Doesn’t Exchange 2010 already have improved Calendar sharing with the new federated sharing features available from RTM? Well, yes it does.. And this new features doesn’t replace federated sharing, however if you want to share calendars now is that the world doesn’t run Exchange 2010. Some organisations will move to it over the next year or two; but lets face facts – some enterprises out there may move to Google Apps, Zimbra or something else, so Federated Sharing isn’t going to be an option. While a workaround might be to create partner mailboxes or use third party software, it would be nice to have a solution that “just works” and enables the business to collaborate with partners easily without worrying too much about what technology each other uses. Only with open standards can this happen and with SP1 that’s now a reality.
The ability to publish calendars with anonymous viewers (and that’s an important point, which I’ll come back to) means that should the admin enable it, the user can now go in via OWA, select the calendar they wish to share and choose to publish it. They then receive a set of URLs that they can share via email. The recipient then can simply refer to the calendar via a web browser, or by using any iCalendar compliant software or web app they can subscribe to the shared Calendar.
Getting back to the anonymous part, there are two options. The end user can publish a calendar with a “public” URL that is searchable. The other option is a “restricted” URL with an obfuscated URL. Additionally, the user can restrict what will be shown for each calendar they choose to publish. On top of this, the admin can restrict via sharing policies the maximum amount of information users can publish, and sharing policies can be tied to a certain set of users. So there is some risk in enabling the facility, but by default no user’s calendars are shared, and there are a number of controls available to user and admin to pull the feature in line with the business and individual user’s requirements.
Now you know a little more about the new feature, let’s take a look at how it comes together from a user perspective, and how it’s configured by the admin.
The User Experience
If a feature is going to work well it has to be easy for a user to find and configure. Exchange 2010 SP1 doesn’t disappoint as the feature is listed in both OWA and Outlook in the same place as other calendar sharing options.
For an OWA user, they select the calendar they want to share, then choose “Share”, and the option is listed as “Publish This Calendar…”

If they’re using Outlook 2010 (beta ), the user right clicks the calendar they want to share, chooses “Share” and again, it’s listed as “Publish This Calendar…”

After clicking “Publish This Calendar…” via OWA or Outlook, the options can be chosen including the detail to show, the date range and the type of access:

After clicking “Start Publishing”, the links are generated:
The user can now either copy the links from this page, or via “Share” choose “Send Links to This Calendar…” which opens a new email with the two URLs attached.
Opening the calendar by the recipient is easy enough. For our first example, let’s have a look at Exchange’s primary competitor, Google Apps. To add the shared calendar to Google Calendar, the end user chooses “Add” then “Add by URL”.

They pop in the iCalendar URL, and it shows up in the recipients Google Calendar. You’ll see below I’m subscribing to two Exchange 2010 SP1 calendars – my personal one and my team’s:

(In my case – this is one aspect I personally like about the feature. Although I don’t use Google Calendar I do use iGoogle and it allows me to see my Exchange calendars on my homepage via the Google Calendar widget.)
Next up it’s Zimba. Add a new Calendar, choose Synchronise appointments from remote calendar, then pop in the Exchange iCalendar URL:

Again, the Calendars show perfectly:

Finally let’s not forget Outlook users; from Outlook 2007 onwards iCalendar subscriptions are supported. I’ve quickly tried this in Outlook 2010 beta – simple right click in the calendar list, choose “Add Calendar” and then select “From Internet…”
As above, after popping the iCalendar URLs in the subscriptions are created in the local Outlook client.

And, finally let’s not forget HTML sharing, which does exactly what you’d expect:

The Admin Experience
Now you’ve seen the user experience let’s take a look at what needs to be done to get it up and running in your SP1 environment. To get it all enabled we need to do the following:
- Set an ExternalURL for your organisation’s Client Access Server
- Enable Calendar Publishing on the OWA Virtual Directory
- Create or modify the sharing policy to allow anonymous sharing
Setup of the ExternalURL is pretty standard stuff so I won’t cover it here. Moving on to the Calendar Publishing OWA virtual directory feature, let’s look at what it’s made up of.
The Calendar Publishing works via a new virtual directory – “calendar”. This lives beneath the “owa” virtual directory as “/owa/calendar” and has anonymous, http access enabled (watch out ISA/TMG users). It’s enabled by default but should it need re-enabling it’s pretty straightforward using Powershell. Here’s a quick example:
Set-OWAVirtualDirectory "owa (Default Web Site)" –CalendarPublishingEnabled:$true
Next up, a sharing policy needs to be configured to allow anonymous access. You can do this via EMS or via the EMC. The EMS example below changes the Default Sharing Policy to only allow anonymous access with maximum access level of Calendar Sharing with Free/Busy plus Subject, Location and Body.
Set-SharingPolicy -Identity "Default Sharing Policy" -Domains "Anonymous:CalendarSharingFreeBusyReviewer"
Via the EMC is also pretty straightforward and particularly suitable when you need to create multiple policies or modify existing ones. Here’s a quick run through of how to create a new policy via EMC that only applies to certain users:
Open EMC and navigate to the Organizational Configuration node, then to Mailbox and select the Sharing Policies tab:

First, examine the sharing policies already present. In the above screenshot, I’ve got a single sharing policy which is disabled. As we’re adding a new policy right-click in the white space or click “New Sharing Policy…” on the actions pane. Give the policy a name and add a new “domain” called “Anonymous” and select an appropriate maximum level of access:

After you’ve added the “domain” anonymous to the policy, make sure it’s enabled, then press Next. On the next page you’ll be presented with the opportunity to add mailboxes now. You can of course add these later either via the EMC or via EMS:

Press Next, then after confirming the details, press New. After completion you’ll see a warning that lets you know calendar publishing is enabled for this policy:

Press Finish and we’re all done. You should now be able to login to the specific mailbox and following the first part of the article share the Calendar.
Conclusion
We’ve had a look at what the new feature brings both from an end-user experience and to an administrator. As we can seen it’s great for sharing calendars in an environment where open standards are important or where partners use different products. I’d like to see full WebDAV compatibility so a Linux user can plug straight in and go, but this is a great start as far as sharing is concerned.
Getting back to new shared calendar features in SP1 - I’m hoping more can be revealed over the next few weeks as there’s still a bit more in store!
And of course, you’ll be able to get your hands on this yourself early June.
A final thought – bear in mind all the features and steps described here are not necessarily final so don’t be surprised if things change over the next few months.
Steve


