Archive

Archive for May, 2010

Using Cmdlet Extension Agents to Cause Automatic Events to Occur in Exchange 2010 – Life Just Got Simpler!

May 29th, 2010 6 comments

In previous posts, I’ve shown how to automate some tasks like automatically sending a ‘welcome’ email to all new user accounts, automatically applying Messaging Records Management policies to new users, and other functions. This helps perform normally routine tasks, as well as providing for a level of interaction with the users that isn’t as readily available manually. It also helps reduce errors and maintain consistency.

The problem with these methods is that they rely on scheduled tasks. So, every four hours, send a message to the new users. That’s all fine and dandy when the account is provisioned for a user starting tomorrow or next week. But if the HR person is standing at your desk saying “the person is starting NOW”, there’s a gap. Additionally, as the environment gets bigger and bigger, the queries to find new users can take more time and more system resources. There must be a better way, and there IS!

A nearly undocumented Exchange 2010 feature called the cmdlet extension agents helps perform tasks automatically based on other commands running. Other Exchange notables have talked about some of the features, including Administrator Audit Logging. There are also cmdlet extension agents for OAB Resource Management, Provisioning Policy, Mailbox Resources Management, RUS, and even a Query Base DN agent. These can be seen by using the Get-CmdletExtensionAgent cmdlet. Today, we’ll focus on the Scripting Agent.

Picture this: a new user mailbox is created from ANY method that calls the new-mailbox cmdlet. This could be Exchange Management Console, Exchange Management Shell, or even some custom provisioning application. As soon as that cmdlet succeeds, the server immediately fires another event – say, sending the ‘welcome’ email. Or disabling POP3 and IMAP on the mailbox; or assigning an Exchange ActiveSync or retention policy. Very cool. But it gets even cooler when you realize that you can also trigger events BEFORE the cmdlet actually does much. Imagine, everytime the remove-mailbox cmdlet is run, an export-mailbox cmdlet is triggered and dumps the mailbox to .pst! It’s possible! Here’s how we can do thngs:

Open Notepad and paste the following:

<?xml version="1.0" encoding="utf-8" ?>
<Configuration version="1.0">
 <Feature Name="MailboxProvisioning" Cmdlets="new-mailbox">
  <ApiCall Name="OnComplete">
   if($succeeded)    {
    $newmailbox = $provisioningHandler.UserSpecifiedParameters["Name"]
    set-casmailbox $newmailbox -ImapEnabled $false
   }
  </ApiCall>
 </Feature>
</Configuration>

Save the file as ScriptingAgentConfig.xml in the \bin\CmdletExtensionAgents folder, which, by default is C:\Program Files\Microsoft\Exchange Server\V14\Bin\CmdletExtensionAgents

Let’s break down how this works. In our code, the highlighted sections are where we need to focus, Notice this line: <Feature Name=”MailboxProvisioning” Cmdlets=”new-mailbox”>. The “cmdlets” parameter dictates what cmdlets will fire our custom event. In this case, whenever new-mailbox is executed. We can define multiple cmdlets here, separating them with a comma.The very next line, <ApiCall Name=”OnComplete”> defines when during the new-mailbox process our custom event will fire. Here, it’s OnComplete, or after the new-mailbox command finishes. We can also use “validate”, to trigger an event after Exchange determines new-mailbox is a valid command and has all of the info it needs. “validate” is where we could export a mailbox during remove-mailbox, as it occurs after validation, but before the mailbox is actually removed.

For the sake of keeping things simple here, we’ll disable IMAP on a new mailbox as an example. In order to disable the IMAP feature, we normally run the set-casmailbox cmdlet (or use EMC, which just calls set-casmailbox), which requires a mailbox name. So, we use $newmailbox = $provisioningHandler.UserSpecifiedParameters[“Name”] to assign the mailbox name used in the new-mailbox cmdlet to a variable, $newmailbox. After that, we simply run set-casmailbox $newmailbox -ImapEnabled $false like we would from EMS or a .ps1 script. That’s it!

Before we try out our new found feature, we need to enable the Cmdlet Extension Agent. Open an Exchange Management Shell window and use the following command:

Enable-CmdletExtensionAgent "Scripting Agent"

Now – using either EMS or EMC, create a new mailbox. Once it’s created, look at the Mailbox Features tab of the mailbox, and you’ll see that IMAP is disabled:

You can certainly perform multiple actions, if you’d like, by simply specifying each command on a new line. If you’d like to take complex actions after new-mailbox (or any cmdlet), you can also call an external script by placing the path and script name in the .xml file.

$newmailbox = $provisioningHandler.UserSpecifiedParameters["Name"]
c:\myscript.ps1 -name $newmailbox

Keep in mind that you can’t do things like write-host or dump other outputs to the console screen. If you’d like to look at some other samples, look at the ScriptingAgentConfig.sample file in the \CmdletExtensionAgents folder in Notepad.

As you can see, the possibilities here are endless. We can automate many tasks, and, with the power of PowerShell, perform many actions not available in the Exchange Management Console.

Caveats: If you have more than one server running Exchange 2010, you’ll need to enable the extension agent on each, and create the .xml file.

Script: Add-Cmdlets2Dictionary.ps1 – Adding PowerShell and Exchange Cmdlets to the Office Dictionary

May 12th, 2010 1 comment

I write a LOT of things that include technical terms, including email, book chapters, and client documentation. Of course, being the good soldier that I am, I try to spell and grammar check things so that the communications don’t make me look like a blabbering idiot.

The problem is that I’m constantly adding terms to the dictionary as I come across them. This include a ton of PowerShell, and usually, Exchange specific cmdlets. When I switched to a new workstation a week ago, I figured it was time to make life earlier. I mentioned online that there had to be a way to easily take a full list of PowerShell cmdlets and functions and dump them into the dictionary. Fellow Exchange MVP Michael B. Smith said it should be easy in PowerShell, and could be done in a single line of code. So we started to collaborate via Facebook (of all places!) on a solution. Michael posted the solution at Simplifying Life for Exchange Authors. I recommend you read his post for a way to do this painlessly. Thanks to Michael for indulging me.

After we came up with working code, it dawned on my that not everyone has remote PowerShell sessions into Exchange servers from their workstations. So I figured I’d make life a little easier, and compiled some various pieces together into a script. The script below will get a list of all Exchange servers in the same AD site as your workstation, randomly pick one, and establish a remote PowerShell session to it. Once established, it will dump all PowerShell functions and cmdlets to the Office dictionary. Copy the following code into Notepad on your workstation:

function Get-ExchangeServerInSite {
    $ADSite = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]
    $siteDN = $ADSite::GetComputerSite().GetDirectoryEntry().distinguishedName
    $configNC=([ADSI]"LDAP://RootDse").configurationNamingContext
    $search = new-object DirectoryServices.DirectorySearcher([ADSI]"LDAP://$configNC")
    $objectClass = "objectClass=msExchExchangeServer"
    $version = "versionNumber>=1937801568"
    $site = "msExchServerSite=$siteDN"
    $search.Filter = "(&($objectClass)($version)($site))"
    $search.PageSize=1000
    [void] $search.PropertiesToLoad.Add("name")
    [void] $search.PropertiesToLoad.Add("msexchcurrentserverroles")
    [void] $search.PropertiesToLoad.Add("networkaddress")
    $search.FindAll() | %{
        New-Object PSObject -Property @{
            Name = $_.Properties.name[0]
            FQDN = $_.Properties.networkaddress |
                %{if ($_ -match "ncacn_ip_tcp") {$_.split(":")[1]}}
            Roles = $_.Properties.msexchcurrentserverroles[0]
        }
    }
}

#add all servers in the local site to an array
$servers = New-Object System.Collections.ArrayList
Get-ExchangeServerInSite | %{ [void]$servers.Add(($_.fqdn)) }

#select a random server from the current site
if($servers.count -gt 1) {
    $random = Get-Random -Minimum 0 -Maximum $servers.count
    $fqdn = $servers[$random]
}
else {
    $fqdn = $servers[0]
}

#create the session
$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "http://$fqdn/PowerShell/" -Authentication Kerberos
#import the session
Import-PSSession $session
$dicFile = (Get-Content Env:AppData) + "\Microsoft\UProof\CUSTOM.DIC"
Get-Command -module $global:importresults | Where-Object {$_.CommandType -eq "cmdlet" -or $_.CommandType -eq "function" -and $_.Name -notmatch ":"} | select-Object Name | Out-file -append $dicfile
#kill the session
Remove-PSSession $session

Save it as Add-Cmdlets2Dictionary.ps1. Now, open PowerShell, navigate to where you saved the file, and execute it using .\Add-Cmdlets2Dictionary.ps1. Once it’s finished, open Word or Outlook and test it with some random cmdlets like New-Mailbox. Keep in mind that Michael’s one-liner works great if you’ve already got a remote session into an Exchange server. My script above is in case you don’t, or you want a reusable script to share with colleagues.

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.

Script: Set-Exchange2010FilterConfig.ps1 v2.0 – Cleaner Configuration of the FilterPack for Exchange Server 2010

May 10th, 2010 2 comments

Description

Late last year, I wrote Cleaner configuration of the FilterPack for Exchange Server 2010 to provide a cleaner script that handles registration of file types for the Office 2007 Filter Pack. This was because the default script would generate a bunch of exception errors when it encountered existing registration entries in the registry. This could be fairly confusing to some people. So my script just did some rudimentary checking before attempting to set the registration. Same end result, just a little cleaner.

Anyways, fast forward to last week, when Microsoft released v2.0 of the Filter Pack. The new version includes support for Office 2010 file types, as well as all of the legacy versions. The registration script didn’t need to change, since it’s based on file extensions, and there aren’t new file extensions in 2010 (like there was in 2007).

But, some people are also installing the Adobe PDF iFilter 9.0 package to enable Exchange to index PDF file attachments as well. Like the Office Filter Pack, the PDF Filter Pack requires a PowerShell script to run to register the file types. Combine that and the update to the script mentioned at Automated prerequisite installation via PowerShell for Exchange Server 2010 on Windows Server 2008 R2 – v2.0, and combining the two filter pack registration scripts just made sense.

This version allows you to register either the Office or the PDF Filter Pack, or both. If you register the PDF Filter Pack, a server reboot is required, as is running the script .\ResetSearchIndex.ps1, which is located in the \scripts folder (typically c:\Program Files\Microsoft\Exchange Server\V14\Scripts). Resetting the search index can be somewhat taxing if there is already a large amount of mail in databases on that server, so you may want to plan when to run this.

Check out the original post for more info, and get the updated script at Set-Exchange2010FilterConfig20.zip

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.

[Redirect] Automated Prerequisite Installation via PowerShell for Exchange Server 2010 on Windows Server 2008 R2 – v2.0

May 7th, 2010 No comments

Big changes in the fairly popular script at Automated prerequisite installation via PowerShell for Exchange Server 2010 on Windows Server 2008 R2. In an effort to make your job easier (as well as mine), I’ve updated it extensively. And, I’ve used better coding practices to make it more efficient.

Changes to the script include at least the following:

  1. Downloads now use BITS on the machine. If BITS isn’t installed, the script will install it to download the files, and remove it when you exit. The script also detects whether the server you’re running it on has Internet access before trying to download files.
  2. Microsoft Office 2010 Filter Packs has replaced the 1.0 file. This adds support for indexing of content in Office 2010 file attachments in addition to the previously available Office 2007 files. For more info, see Bharat Suneja’s Released: Microsoft Office 2010 Filter Packs post.
  3. Adobe PDF iFilter 9 support has been added to (only) option #11. This adds support for indexing of .pdf files. See the Exchange Product Groups Introducing Attachment Inspection in Transport Rules for more info. Option #11 is the same as #6, but with .pdf filter, and is what I use for my server builds.
  4. Better detection of a successful installation of the filter packs
  5. Added an option (#13) to disable TCP/IP v6
  6. Updated the option (#12) to download the latest Update Rollup to get UR3
  7. Added an option (#7) due to a project requirement
  8. Removed the auto rebooting of the server if a reboot was required. It now just displays a warning that a reboot is needed before installing Exchange. This allows you to inspect what the script has done, and identify any issues, as well as execute more options, like disabling TCP/IP v6, before rebooting.

With the change in the Office filter pack, as well as the addition of the .pdf filter pack, I’ll have a new version of the configuration script for those available at Cleaner configuration of the FilterPack for Exchange Server 2010 in the next couple of days.

Visit the original post at the link above for the original info and a link to the updated script.

As always, if you’d like to see an option added, or have questions or comments, please feel free to let me know.