Creating Shared Calendars on Exchange 2010

imageWith 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:

1
New-SharedCalendar.ps1 -Name "Test Calendar" -Owners steve,lisa -Editors isabelle,peter -Reviewers liz,drew

And using the full set of options:

1
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

The full script follows, along with a download link for a zip file containing the script and user documentation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
<#
    .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

18 thoughts on “Creating Shared Calendars on Exchange 2010

  1. I tried using this, but the user I set as the owner cannot add the shared calendar, it tells her she does not have permissions and asks if she wants to send a calendar sharing request. Can you tell me what I may have done wrong?

    • Hiya, it’s not dead – I post regularly but on older posts like this one I don’t always have time to comment and usually notice this when I log in.

  2. I like the LDAP method to remove the user if they exist in the object’s attribute since Exchange has a habit of poor clean up. Exchange 2010’s Add-MailboxPermission cmdlet now has an automapping parameter that can be added to line 184 to improve it:

    $Mailbox | Add-MailboxPermission -User $Owner -AccessRights FullAccess -DomainController $DomainController -AutoMapping $false

  3. Pingback: Sims.Net Staff Timetables Export to Outlook

  4. Ok, i am completely new to this and i tried to run the script but i am stuck.
    When i have to enter the owners i put in for instance my SAM account name, then i hit enter and the script closes.

    What am i doing wrong?

    Regards,
    Rico

  5. Great script here.
    Do you know if it’s possible to share a shared calendar to Office.com when no user logs in as the user (such as the case of your above listed shared calendars)?

  6. Thanks for the script, but would appreciate some help as it is throwing errors.
    This is the error
    Setting Shared Calendar Mailbox Owner, Department and Description
    Exception calling “SetInfo” with “0” argument(s): “Access is denied.

    At C:\New-SharedCalendar\New-SharedCalendar.ps1:168 char:18
    + $LDAPUser.SetInfo <<<.\new-sharedcalendar.ps1 -name “Test Calendar2” -Owners scadmin,paulH,andys -editors peterg,mattj

    Being new to PowerShell I am at a loss!!

    Rgds
    Paul

  7. Steve, is there a way to automatically add a shared calendar to a user’s list of calendars in Outlook? I’ve seen your article about automatically adding an entire shared mailbox with 2010 SP1, and I would like to do something like that for just a calendar, not an entire mailbox.

    • I would like to do the same thing, auto-map a shared calendar… But, I too can only find the auto-map a mailbox.

      -Marshall

  8. Is there a possibility to add a security group to the owners variable? If i have 32 people that need to be owners, it becomes an issue having to type in every single users samaccount.

  9. This is great but was wondering if there was a way to edit/change it to do Room resouces instead of shared. Also is there a way to add a password so it is auto enabled? Thanks.

  10. Script is great, this was something i was looking for a long time and i have this finally from you now. Thanks Steve.

    I have another question; is it possible for me to automatically sync the calendar items of a mailbox to a sharepoint calendar (shared), If yes, can you help me get a hint on that.

    Thanks,
    Sai Prasad

  11. Pingback: Shared Calenders

  12. Pingback: Tweets that mention Creating Shared Calendars on Exchange 2010 -- Topsy.com

Comments are closed.