Steve Goodman's Exchange Blog
3Feb/112

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:

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

And using the full set of options:

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:

<#
    .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

15Dec/102

Outlook 2007 update for personal archive and automatic mailbox mapping released

image

Update: You'll see Ben Schorr (MVP) has commented that this update is causing problems for some users. A description of the problem is here.

Update 2: Having rolled this update to a large number of users and seen no issues in a corporate environment, it seems issues with this update are limited to Outlook when it's using non-Exchange connectors. This is confirmed on the MSDN Outlook blog.

Update 3: The Exchange Team have officially annouch the support via this patch over on the Exchange Team Blog.

Just having downloaded the update myself, I was preparing to do a short write-up about the new features that have landed in Outlook 2007 overnight – namely support for personal archives and auto-mapping of shared folders.

However, Michel de Rooij has just posted an article on EighTwoOne giving a quick overview of what the new features do and don’t provide…

Outlook 2007 hotfix for Exchange 2010 Personal Archive support

It’s worth adding that the Outlook 2007 update is available via both Microsoft Update and Windows Server Update Services as KB2412171 so be prepared for it to land on your users’ desktops…

image

image

9Nov/1010

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:

clip_image002

On the iOS device, you can then click the webcal: link in the email, which will allow you to subscribe to the Calendar:

clip_image003

Simple!

16Feb/105

Scripted Shared Mailbox Creation on Exchange 2007/2010

I thought I’d share one of the scripts we use for automating creation of Shared Mailboxes within our organisation. One of the more laborious parts of creating shared mailboxes after creation of the actual Mailbox, is setting the manager, department, and granting a (possibly long) list of users permissions and send-as rights.

This script is a simple Powershell script that takes some of the pain out of the process. The assumption is that you want to achieve the following:

  • Create a shared mailbox with a common alias, email address and username, checking input values before attempting to create the mailbox.
  • You would like to specify the Department at creation and use the Department AD attribute to generate Address Lists
  • You would like to attach a user as Manager for the Shared Mailbox so it is clear who manages it

You can use the script with Parameters – e.g:

.\New-SharedMailbox.ps1 -Department "Human Resources" -Alias hr_test -DisplayName "HR Test" -Manager managerusername -Usernames "username1,username2"

–Department is the text to use for the department attribute
–Alias is the Email Alias & Username
–DisplayName is the friendly textual name shown to users and recipients
–Manager is the username, UPN or email address of the Manager (who will have full access + send as rights along with being set as Manager)
–Usernames is a comma separated list of usernames of people who should also have full access and send-as rights.

Or - if that isn’t your thing, then you can just run the script without any options, and it will prompt you as you go along for the parameters. If you are using the Department attribute for Address List generation, you can hit enter when prompted for the department to get a list of in-use departments. As you go along values will be checked, to ensure the Alias and Display Name aren’t in use by Mailboxes or Mail Users and that the Manager and Usernames are attached to valid Mailboxes.

Before you get started with script it does need a little setup.

The setup is fairly straightforward, though. Open the script in a text editor, and change the values for $DomainController, $OU, $UPNDomain and $MailboxDatabase to values appropriate for your organisation. It goes without saying you should test this out on something not connected to your production environment. I won’t take any responsibility for any damage you do with this!

I’ve obviously taken some stuff out that is specific to our organisation (for example, we have a switch statement to determine the mailbox database and exchange server; and also generate Unix information) and if this almost does what you want let me know and I’ll be happy to help you customise it.

Download New-SharedMailbox.ps1