Archive

Posts Tagged ‘PowerShell’

Script: AutoApplyMRMPolicy.ps1 – Automatically Applying Messaging Records Management Policies to New Users

May 18th, 2009 No comments

Description

I’ve had several client ask me lately how to set retention periods on mailboxes, and, equally important, how to make sure that all newly created mailboxes have the policy applied. Some organizations will have more than one admin who creates mailbox enabled user accounts, and leaving it up to the admins to manually set the account for a retention policy is just prone to mistakes.

I won’t go into a lot of detail talking about what MRM is and what can be done. It’s already been covered many times on other sites, including this short but informative video from the Exchange product group. This article assumes that you have a working policy already in place. What I’ll cover here is how to use PowerShell to be consistent in applying an MRM policy to all users. For the most part, we’ll “set it and forget it”.

We can use PowerShell to apply an MRM policy using the ManagedFolderMailboxPolicy parameter of the Set-Mailbox cmdlet. This script basically looks for all users who are not resource accounts, not disabled, and don’t already have a policy applied (since we don’t generally want to override that). We do that with this line:

$MBXArray = @(Get-Mailbox | Where-Object {($_.RecipientType -eq 'UserMailbox') -and ($_.UserAccountControl -notmatch 'AccountDisabled') -and ($_.ManagedFolderMailboxPolicy -eq $null)})

$MBXArray is thus a list of mailboxes that pass the query. We then cycle through the array with ForEach and apply a policy to each mailbox using Set-Mailbox, like this:

Set-Mailbox -identity $Mailbox.SAMAccountName -ManagedFolderMailboxPolicy $strPolicyName -ManagedFolderMailboxPolicyAllowed

I use the -ManagedFolderMailboxPolicyAllowed parameter to get past confirmation prompts, since we’ll run the PowerShell script has a Windows scheduled task. $strPolicyName is a variable that holds the name of the policy we’d like to apply.

That’s simple enough, really. But it’s generally a good idea to have some sort of record that a policy was applied. PowerShell gives us a couple of ways to record the event, and we’ll use both.

First, when the script first starts, we’ll write an event to the application event log noting that the script is starting. First, set some variables and create a new object with

$strWhoAmI = $MyInvocation.MyCommand.Name
$evt.Source=$strWhoAmI
$evt=new-object System.Diagnostics.EventLog("Application")
$infoevent=[System.Diagnostics.EventLogEntryType]::Information

The first line actually creates a variable, $strWhoAmI, and assigns it the name of the PowerShell script. The second line sets that same info to be the source of the event log entry we’re about to write.

We use the two lines below to set the text for the event log, and write it.

$strEventLogText = "Beginning processing."
$evt.WriteEntry($strEventLogText,$infoevent,70)

When the script is finished, we also write another event log entry to say we’re done, along with a count of how many mailboxes were processed.

Next is where we build some flexibility into the script. At the beginning of the script, we define another variable, $strLogEachUser (and set it to $false) to disable writing an event log entry for EACH user we apply a policy to. In larger environments, it’s not a good idea to have that set to $true when the script runs the first time, as it can result in a LOT of event log entries. But, after that, it might provide some valuable information. The log entry will look something like

Messaging Records Management policy ‘MyManagedFolderPolicy’ applied to Claudia Richard

The next logging option we have is to stamp the actual AD account when we apply the policy to it. We do this by using one of the Custom Attributes available on Active Directory objects. For a user account, there are 15 Custom Attributes, and they can be viewed by opening a recipient in Exchange Management Console, and clicking on the Custom Attributes button near the bottom of the General tab. We’ll use Custom Attribute 13 for this example. This is easily accomplished by using the -CustomAttribute13 parameter of the Set-Mailbox cmdlet.We assign the text we’ll use with the $strMRM variable near the top of the script:

$strMRM = "MRM policy applied by " + $strWhoAmI + " " + $strToday

This allows for the script name, policy name, and a time stamp, and looks like this:

MRM policy applied by AutoApplyMRMPolicy.ps1 05/16/2009 12:16:38

The last feature built in is a status indicator while the script is running. This probably won’t be very valuable unless you plan to only ever manually run the script. The status indicator is disabled by default, but can be enabled by changing

$strShowStatus = $false

to

$strShowStatus = $true

it’s the same status indicator you see when doing many tasks at one time, such as moving or export mailboxes.

Here’s the finished script. Save it as AutoApplyMRMPolicy.ps1 in your \scripts folder on your Exchange server. Edit the three variables under the header block to suit your needs.

###############################################################################
# AutoApplyMRMPolicy.ps1 by Pat Richard, MVP
# https://www.ucunleashed.com/85
#
# Automatically apply a Messaging Records Management policy to
# all users who are:
#        a) not resource accounts
#        b) not disabled
#        c) don't already have a policy applied
#
# This script is designed to be run as a Windows Scheduled task on an Exchange
# server.
#
# UPDATES
# =======
# v1.3 05/22/2009 Updated array per Nick's additional suggestions
# v1.2 05/19/2009 Updated array per Nick's suggestions
# v1.1 05/15/2009 Added status indicator;
#            cleaned up/added event log entries
#            added variables for enabling/disabling each
# v1.0 04/30/2009 Initial version
#
# Simply edit the settings below to fit your needs
###############################################################################

$strPolicyName = 'MyManagedFolderPolicy'
$strLogEachUser = $false
$strShowStatus = $false

############ DO NOT EDIT ANYTHING BELOW THIS LINE ############
$strToday = Get-Date
$strWhoAmI = $MyInvocation.MyCommand.Name
$strMRM = "MRM policy applied by " + $strWhoAmI + " " + $strToday
$evt=new-object System.Diagnostics.EventLog("Application")
$evt.Source=$strWhoAmI
$infoevent=[System.Diagnostics.EventLogEntryType]::Information
$strEventLogText = "Beginning processing."
$evt.WriteEntry($strEventLogText,$infoevent,70)
$MBXArray = @(Get-Mailbox | ? {($_.RecipientType -eq 'UserMailbox') -and ($_.UserAccountControl -notmatch 'AccountDisabled') -and ($_.ManagedFolderMailboxPolicy -eq $null)})

    ForEach ($Mailbox in $MBXArray) {
        $x=$x+1
        if($strShowStatus){
            Write-Progress -id 1 -activity "Applying Messaging Records Management policy '$strPolicyName'" -status $Mailbox.SAMAccountName -percentComplete (100/$MBXArray.count*$x) -CurrentOperation '' -SecondsRemaining ($MBXArray.count-$x)
        }
        Set-Mailbox -identity $Mailbox.SAMAccountName –ManagedFolderMailboxPolicy $strPolicyName -ManagedFolderMailboxPolicyAllowed -CustomAttribute13 $strMRM
        if($strLogEachUser){
            $strEventLogText = "Messaging Records Management policy '$strPolicyName' applied to "+$mailbox.DisplayName
            $evt.WriteEntry($strEventLogText,$infoevent,70)
        }
    }
############ Blank line after next line is intentional for cleaner event log entry ############
$strEventLogText = "Finished processing "+$MBXArray.count+" accounts.

For more information on Messaging Records Management, see http://technet.microsoft.com/en-us/library/bb310756.aspx."
$evt.WriteEntry($strEventLogText,$infoevent,70)

Create a scheduled task

The last piece of this is a scheduled task. This is quite easy. Go to Scheduled Tasks on the server (Control Panel–> Scheduled Tasks). Right click and choose New>Scheduled Task. Call the task what ever you like, such as AutoApplyMRMPolicy. Right click the task and choose Properties. For the RUN field, paste this:

c:\windows\system32\windowspowershell\v1.0\powershell.exe -psconsolefile "c:\Program Files\Microsoft\Exchange Server\bin\exshell.psc1" -Command "AutoApplyMRMPolicy.ps1"

but change the -psconsole parameter to point to your \bin folder. The default path is shown. For the START IN field, enter the path to your \scripts folder, such as the default:

"c:\program files\microsoft\exchange server\scripts"

Set RUN AS to an administrator account. Click the Schedule tab and configure the task to run at least once a day. Be careful to ensure that it runs outside of your backup and maintenance windows. Click Ok. That’s all there is to it.

Some things to note:

The script will apply a policy to ALL users who are not disabled, resource accounts, or already configured for a policy. If you need it to be more restrictive, alter the line that starts with “$MBXArray =”

There is no error checking in the script. If there is enough call for that, I’ll work that into the script.

Feel free to make suggestions as to how to improve the script.

UPDATED 5/22/09: Cleaned up the array stuff a little per more Nick’s suggestions. Thanks, Nick!

Installation

Execution Policy: Third-party PowerShell scripts may require that the PowerShell Execution Policy be set to either AllSigned, RemoteSigned, or Unrestricted. The default is Restricted, which prevents scripts – even code signed scripts – from running. For more information about setting your Execution Policy, see Using the Set-ExecutionPolicy Cmdlet.

Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

PowerShell Script to Set All AutoDiscover Related Virtual Directories to Use a Single Domain Name

October 1st, 2008 No comments

I’ve updated the Set-AllVDirs.ps1 script that streamlines the process of setting the virtual directory paths for various web services including Offline Address Book, AutoDiscover, Unified Messaging, and Exchange Web Services. If you’re using a single name certificate in place of a Subject Alternative Name certificate, this script walks you through the process of changing each of the URLs.

See the script at The Exchange 2007 Wiki page here.

Cluster Administration from PowerShell and the Infamous Back Tick

July 18th, 2008 No comments

Of course we all know by now how powerful PowerShell is. “It slices, it dices, it makes julienne fries, whatever those are!” to quote Ron Popeil

One of the cool things with PowerShell is that you can call some external programs. While waiting for some hardware to arrive on a project, I was scripting the setup of a two node Single Copy Cluster (SCC) install of Exchange 2007. One thing you want to do with an Exchange SCC cluster in 2007 is assign dependencies for resources. Say you have a mailbox database called “First Storage Group/Mailbox Database”, and it resides on the cluster resource called “Disk S:”. Well, when the cluster starts up, it should wait for “Disk S:” to be online before trying to bring the “First Storage Group/Mailbox Database” resource online. It only makes sense, right?

Back to my project. So I’m able to script the creation of the storage groups using something like

New-StorageGroup SG1 -SystemFolderPath G:\SG1 -LogFolderPath K:\SG1

from there, I create a new database

New-MailboxDatabase -Name DB1 -StorageGroup SG1 -EdbFilePath G:\SG1

I set some configuration on the new database

get-mailbox | set-mailboxdatabase -DeletedItemRetention 14.00:00:00 -MailboxRetention 30.00:00:00 -IssueWarningQuota unlimited -ProhibitSendQuota unlimited -ProhibitSendReceiveQuota unlimited -PublicFolderDatabase "Second Storage Group\Public Folders" -RetainDeletedItemsUntilBackup:$true -MountAtStartup$true

Life is good. Now, I need to assign the cluster dependencies for the new database resource. But first, the database needs to be unmounted to assign the dependency. So, we precede the cluster command with:

get-mailboxdatabase | dismount-database

Then we can do the dependencies. From a command prompt,

Cluster cluster1 res "SG1/DB1 (MbxCluster1)" /AddDep:"Disk S:"

would work beautifully. It would assign the “Disk S:” cluster resource as a dependency for the new database. But PowerShell wouldn’t accept that syntax, telling me

“Too many command line parameters have been specified for this operation…”

Seems PowerShell doesn’t like the special characters there, and they need to be escaped with a back tick (on an English keyboard, that’s the key to the left of the “1”). After some noodling around, and the help of Ross and Scott, this seems to work:

Cluster cluster1 res ` "SG2`/DB3 `(MbxCluster1`) `" `/adddep: `"Disk S: `"

Not the cleanest of lines, but I’m able to keep everything within a single PowerShell script. Normally, I would have given up and just manually done the dependency configuration, except that this project will involve dozens of databases, and, like many engineers, I’m lazy. Plus, I should know this limitation for the future, as it streamlines the setup of the cluster.

We can now mount the databases with

get-mailboxdatabase | mount-database

I use those broad commands to essentially handle all of the databases, since the script sets them all up at the same time.

Note: I know, we should not have databases with no quota limits on them. But this is a GroupWise to Exchange 2007 migration. So I leave them unlimited till the migration is complete (to avoid migration problems), and then I’ll clamp them down for safety.

As you can see, we can essentially setup all of the SGs and DBs, and assign the cluster config all from within PowerShell. If you’re looking for a great book on PowerShell for Exchange 2007, check out Professional Windows PowerShell for Exchange Server 2007 Service Pack 1 @ Amazon.com. It’s an easy read, but quite informative.