«

»

Sep 09

The ExchUcUtil Script (and Why You May Never Need to Run It Again!)

Introduction

In 100% of all documentation, it is clearly stated that in order to connect Microsoft Lync with Exchange Unified Messaging (UM) you need to run the ExchUCUtil.ps1 script. This article will detail what this script does and how you can configure your environment so that you will never have to run this script again. Yes it’s possible and it’s pretty straightforward!

There is a brief TechNet article about the ExchUcUtil script that can be found here.

According to this (more in-depth) TechNet article, the ExchUcUtil script only does three things:

  1. Grants Lync Server permission to read Exchange UM Active Directory components, specifically, the SIP URI dial plan.
  2. Creates a UM IP gateway for each Lync Server pool or for each server running Lync Server Standard Edition that hosts users who will be enabled for Enterprise Voice.
  3. Create an Exchange UM hunt group for each UM IP gateway. The hunt group pilot identifier will be the name of the dial plan associated with the corresponding UM IP gateway. The hunt group must specify the UM SIP dial plan used with the UM IP gateway.

As a slight aside, if you look at the two linked TechNet articles you’ll note that the first article says the ExchUcUtil script only does two things while the second article lists three. Even when you find the Microsoft documentation on ExchUcUtil it is inconsistent.

Script Organization

The first step in figuring out how this PowerShell script is put together is to break it down into manageable chunks.

The script has four basic sections. At the top of the script are a bunch of constants. These aren’t anything we should worry about too much other than keeping note of them when breaking down the script.

ucutil1

The second section of the script is a collection of various functions. This is where all of the work happens and these functions will get broken down throughout this article.

Toward the bottom of the script we find the third section. It is a one line command that simply says:

ucutil2

Without this command nothing happens. All it does is call the RunScript function which will be broken down shortly.

The final section of the script is the signed certificate. This is put in so that you can be confident that the script you are running actually came from Microsoft and that nothing within the script has changed.

ucutil3 


Breaking Down the Script

As mentioned above, nothing happens until the RunScript command fires. If you pay close attention you’ll notice that this command is the only command in the entire script that is not a function, a comment, or a variable (constant) declaration. As such, this is the command that sends the script on its way.

The first concrete thing the script does is to enumerate the RTC Pools. It does this by launching a separate PowerShell script called get-ucpool.ps1.

At a high level, get-ucpool.ps1 does the following:

  1. Find a Global Catalog Server and connect to it.
  2. Find the RTCUniversalServerAdmins and RTCComponentUniversalServices groups.
  3. Enumerate all UC pools
  4. Verify that all pools are at least version “0x30000” (or 12288 decimal)
  5. Return the list of pools back to ExchUCUtil.

The next step in the script is to get existing permissions. It does this via the GetPermissions function. This function verifies that the RTCUniversalServerAdmins group and the RTCComponentUniversalServices group already have access to Exchange. The first thing it does is to grab a copy of the Exchange configuration.

ucutil4

Next it calls another function (GetObjectPermissions) and runs the get-adpermissions cmdlet against the groupname sent to it from the GetPermissions Function.

ucutil5

Once those permissions are gathered we are back to the RunScript function. The next step is to get a list of all of the UM IP Gateways. It does this by calling the GetUMIPGateways function.

GetUMIPGateways is a simple function that lists all defined UM IP Gateways by running the Get-UMIPGateway cmdlet.

ucutil6

 

Once this function completes we are returned to the RunScript function. The next step is to gather all defined SIP dial plans. This is a rare instance where a separate function is not called. Instead the Get-UmDialPlan cmdlet is called directly and the results are stored in the $dialplans variable.

ucutil7

 

Once all of this data is collected the script now turns to setting permissions and creating objects. The first step is to verify that RTCUniversalServerAdmins and RTCComponentUniversalServices groups have proper permissions on Exchange. If it is not correct, the script runs the ConfigurePermissions function.

This function is fairly straightforward. It provides “ListChildren” rights with no inheritance on the Exchange Organization container.

ucutil8

 

It then provides “ListChildren” and “ReadProperty” rights (with full inheritance) to the UM Dial Plans, AutoAttendant, and Server containers.

ucutil9

 

It does this by calling the SetObjectPermissions function. This is a small function that basically just runs the Add-Permission cmdlet.

ucutil10

 

Once the permissions have been applied to AD and Exchange the script then creates the UM IP Gateways by running the ConfigureGateways function. This function takes all of the pools, gateways, and dial plans and creates a new UM IP Gateway for each pool.

ucutil11

 

Once the UM IP Gateways are created it removes all of your Hunt Groups….

ucutil12

…And creates new ones… ucutil13

Once it has done this work, control returns to the RunScript function which then outputs the results.

ucutil15

 

While it may feel a little unsettling that the script is removing hunt groups and creating new ones, this script does seem to work pretty flawlessly. I have run it numerous times in several environments and it works perfectly every time. Every Lync admin and Microsoft support representative has it ingrained in his or her head that this script MUST BE RUN in order to hook up Lync and Exchange Unified Messaging.

But what if you have a complicated network that spans continents, that has hundreds of Lync Pools, Lync servers, and Exchange UM servers in various Exchange Organizations? What if you have a network that has firewalls restricting connectivity between offices or countries? What happens then if you run this script?

No script can be designed for every single network that exists and in the case of this script it has to make the assumption that all pools can talk to all gateways. But this is not always the case. So what to do?


Configure your network to never have to run ExchUCUtil ever again!

Microsoft support and Lync Administrators don’t like this option because they have been trained to run ExchUCUtil and their experience has proven that this script works and, when necessary, fixes all kinds of issues. However, if you’ve read this far, you should have realized that the script doesn’t do any voodoo magic. It sets permissions and it creates UM IP Gateways and Hunt Groups. There is no reason you can’t do this yourself. So, let’s go through the steps necessary to do this yourself.

First, let’s check out the permissions created by the script. Remember that it adds Read permissions to certain Exchange objects for the RTCuniversalAdmins group and the RTCComponentUniversalAdmins group.

Here is the output of the first time the ExchUcUtil script was run on the flinchbot.com domain. It is edited to only show the security-related output.

[PS] C:Program FilesMicrosoftExchange ServerV15Scripts>.ExchUCUtil.ps1

Using Global Catalog: GC://DC=flinchbot,DC=com

Configuring permissions for flinchbot.comRTCUniversalServerAdmins …

First Organization: The appropriate permissions haven’t been granted for the Office Communications Servers and Administrators to be able to read the UM dial plan and auto attendants container objects in Active Directory. The correct permissions are being added to the container objects.

UM DialPlan Container: The appropriate permissions haven’t been granted for the Office Communications Servers and Administrators to be able to read the UM dial plan and auto attendants container objects in Active Directory. The correct permissions are being added to the container objects.

UM AutoAttendant Container: The appropriate permissions haven’t been granted for the Office Communications Servers and Administrators to be able to read the UM dial plan and auto attendants container objects in Active Directory. The correct permissions are being added to the container objects.

Administrative Groups: The appropriate permissions haven’t been granted for the Office Communications Servers and Administrators to be able to read the UM dial plan and auto attendants container objects in Active Directory. The correct permissions are being added to the container objects.

Configuring permissions for flinchbot.comRTCComponentUniversalServices …

First Organization: The appropriate permissions haven’t been granted for the Office Communications Servers and Administrators to be able to read the UM dial plan and auto attendants container objects in Active Directory. The correct permissions are being added to the container objects.

UM DialPlan Container: The appropriate permissions haven’t been granted for the Office Communications Servers and Administrators to be able to read the UM dial plan and auto attendants container objects in Active Directory. The correct permissions are being added to the container objects.

UM AutoAttendant Container: The appropriate permissions haven’t been granted for the Office Communications Servers and Administrators to be able to read the UM dial plan and auto attendants container objects in Active Directory. The correct permissions are being added to the container objects.

Administrative Groups: The appropriate permissions haven’t been granted for the Office Communications Servers and Administrators to be able to read the UM dial plan and auto attendants container objects in Active Directory. The correct permissions are being added to the container objects.

Permissions for group flinchbot.comRTCUniversalServerAdmins

ObjectName AccessRights Configured

———- ———— ———-

First Organization ListChildren True

UM DialPlan Container ListChildren, ReadProperty True

UM AutoAttendant Container ListChildren, ReadProperty True

Administrative Groups ListChildren, ReadProperty True

Permissions for group flinchbot.comRTCComponentUniversalServices

ObjectName AccessRights Configured

———- ———— ———-

First Organization ListChildren True

UM DialPlan Container ListChildren, ReadProperty True

UM AutoAttendant Container ListChildren, ReadProperty True

Administrative Groups ListChildren, ReadProperty True

The ADSI Edit utility can be used to view the specific settings that were created by this script. Begin by starting the ADSI Edit utility and connecting to the Configuration Naming Context.

ucutil16

 

Next drill down to the following path:

CN=First Organization,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=flinchbot,DC=com

Note that you may have a different Exchange Organization name. In this example “First Organization” is the name of the Exchange 2013 Organization in the flinchbot.com domain.

Right click on your Exchange Organization name and select Properties. From the window that pops up, click on the Security tab. If you scroll down you should see the two Lync groups have been added:

ucutil17

 

Close this window and return to the main ADSI Edit window. Scroll down until you get to the CN=UM* containers. Earlier in the article it was shown that security is added to the following UM objects: UM Dial Plans and AutoAttendant.

We see two of these objects here.

Right click on CN=UM AutoAttendant Container and select Properties. Next, select the Security Tab and scroll down the list.

You should see two groups listed: RTCComponentUniveralServices and RTCUniversalServerAdmins

ucutil18

 

You should see the same for the CN=UM DialPlan container.

ucutil19

In either container, you can see specifically which permissions have been assigned to those groups. Earlier in this article it was detailed that the following permissions were set by the script: “ListChildren” and “ReadProperty”. We can see this reflected here.

ucutil20

If you go back over the script, you’ll see that the script verifies if these rights are granted. If they are, it doesn’t change anything. As such, if you have run the script once, haven’t added a new Exchange Organization with UM Servers, and don’t touch these permissions, this part of the script is redundant. If you create a new Exchange Organization, you can manually add the permissions listed in this article or run the ExchUCUtil script to have it done for you. In general, this is the innocuous part of the script.

The real problems in large and/or complex environments is when the script starts removing Hunt Groups and adding UM IP Gateways. If you are in a rigidly defined environment where users are assigned to specific UM Servers and they cannot access other UM Servers (e.g. due to firewalls) then you may not want to run the ExchUcUtil script. ExchUCUtil is oblivious to your network layer and will start adding UM objects that it thinks all users should be able to access. Yet when the Lync client is told to access a gateway it cannot get to, Lync will potentially start failing to forward calls to Exchange UM. To exacerbate this issue, either the Lync client or Exchange UM does not have very robust failover capabilities – at least where the Lync 2010 client is concerned. (On the production environment that is the true source for this article, we all want to stay employed and will not run ExchUcUtil just to see if the 2013 family of Microsoft software is more robust. Sure we could run it, but then we need to reset Exchange UM in about 20 different countries and start submitting our resumee’s to find new employment).


Impact on Exchange

Here is what happens in Exchange when the ExchUcUtil script is run. In the test environment, this article was followed to assure that the minimum requirements for the script are met.

The first step is to create a UM Dial Plan. This was done using PowerShell. In order to make these steps repeatable, PowerShell will be used for all of these steps.

To create a UM dialplan you use the New-UMDialPlan cmdlet. Here is the command used in the lab and below that is the output of running this command.

New-UMDialplan -name “UMDialPlan” -UriType “SipName” -VoipSecurity Secured -NumberOfDigitsInExtension 4 -CountryOrRegionCode 1

ucutil21

Notice that the UMIPGateway field is empty.

Also note that this command creates a corresponding UM Mailbox Policy:

ucutil22

At this point, the ExchUCUtil script can be run. Below is the relevant output from the script relating to the Exchange UM piece:

ucutil24

Running the Get-UMDialPlan command now shows that there are entries in the UM IP Gateway field.

ucutil25

 

Formatting this for better output of the UM IP Gateways shows the following:

ucutil26

 

The two UM IP Gateways listed refer to the two Lync pools in this lab. One is a Standard Edition Pool (lycn2013se) and one is an Enterprise Edition pool (lyncpool).

In most cases, this configuration is completely fine and the ExchUcUtil script did its job just fine. However, as mentioned above, there are large and/or complex networks where adding all available pools to a new UM Dial Plan is not at all desirable. So how does one work around this? How can one end up having the same basic result without running the script?

The Exchange lab can be reset by removing the UM IP Gateways created by the ExchUCUtil script. By running the Remove-UMIPGateway command you can remove the gateways automatically created and assigned to the UM Dial Plan.

ucutil27

 

Running the Get-UMDialPlan verifies that there is still only one dial plan and that there are no assigned UM IP Gateways.

ucutil28

 

So instead of having the ExchUcUtil creating these automatically, this can be done manually with the following set of commands.

First, assign the UM dial plan to a specific server. That is done via the following:

Set-UMServer -Identity Exchange13.flinchbot.com -DialPlans @{add=”UMDialPlan”}

According to TechNet, the –DialPlans parameter does the following:

The DialPlans parameter specifies all the dial plans for which this server will handle UM calls. If no dial plans are defined, the Unified Messaging server won’t handle UM calls.

The next step is to create a new UM IP Gateway. This is done via the following:

New-UMIPGateway -Name Lyncpool_UMIPGateway -Address lyncpool.flinchbot.com

This cmdlet is very straightforward. The first parameter is the name of the UM IP Gateway object within Exchange. ExchUCUtil automatically chose the names “lyncpool” and “lync2013se”. In this example, the name “lyncpool_UMIPGateway” was chosen. It’s a bit longer but is a more descriptive name (another advantage of not using ExchUcUtil!).

Next you need to create a UM Hunt Group. A Hunt Group is a simple object that connects a UM IP Gateway with a UM Dial Plan.

New-UMHuntGroup -Name Lyncpool_HuntGroup -UMIPGateway Lyncpool_UMIPGateway -UMDialPlan “UMDialPlan” -PilotIdentifier “UMDialPlan”

This is also a straightforward command. The first parameter (-Name) is the name of the hunt group. The next parameter is the name of the UM IP Gateway we want to link with the UM Dial Plan.

The PilotIdentifier parameter can be confusing when manually configuring a UM dial plan. If you read the TechNet article on New-UmHuntGroup, it has this to say about the PilotIdentifier parameter:

The PilotIdentifier parameter specifies the number string used to uniquely identify the pilot access number for the specified IP gateway. This number must match the subscriber access number configured in the UM dial plan.

So what does this mean for Lync, especially if we do not want (or need) a Subscriber Access number? If you keep searching, you will find this TechNet article.

Create an Exchange UM hunt group for each UM IP gateway. The hunt group pilot identifier will be the name of the dial plan associated with the corresponding UM IP gateway. The hunt group must specify the UM SIP dial plan used with the UM IP gateway.

So for the PilotIdentifier, use the name of your dial plan. In the examples in this article, that would be “UMDialPlan”.

And that’s it. This may seem like more work than just launching ExchUCUtil but it really isn’t. For one, it goes a lot faster (in large environments) since you aren’t waiting for the ExchUCUtil script to enumerate all of your pools and then go about removing hunt groups, creating UM IP Gateways, and adding back the UM Hunt Groups.

If you are in an environment where the Exchange administrators are separate from the Lync administrators, the following is a very concise and understandable set of cmdlets for the Exchange Admins to run:

New-UMDialPlan -name “UMDialPlan” -UriType “SipName” -VoipSecurity Secured -NumberOfDigitsInExtension 4 -CountryOrRegionCode 1

Set-UMServer -Identity Exchange13.flinchbot.com -DialPlans @{add=”UMDialPlan”}

New-UMIPGateway -Name Lyncpool_UMIPGateway -Address lyncpool.flinchbot.com

New-UMHuntGroup -Name Lyncpool_HuntGroup -UMIPGateway Lyncpool_UMIPGateway -UMDialPlan “UMDialPlan”

This also is easier to document in your change management tracking than the following:

New-UMDialPlan -name “UMDialPlan” -UriType “SipName” -VoipSecurity Secured -NumberOfDigitsInExtension 4 -CountryOrRegionCode 1

Navigate to Exchange Install directory and then the scripts folder.

Run ExchUcUtil.ps1

Magic happens


Summary

In the overwhelming majority of networks, you can and should continue to run the ExchUcUtil.ps1 script and go on about life just fine. However, there are scenarios where you may not want to run it, be it due to firewalls blocking access between some Lync Servers and some Exchange Servers or simply because you want to have better control of the naming of your Gateways within Exchange UM.

In order to set up your configuration successfully without running the ExchUcUtil script, be sure that you have your security settings set up correctly. This is probably the easiest part to mess up or to forget to do if you add a new Exchange Organization with the UM role installed (or adding the UM role to an existing Organization). But once you have your security properly configured, the rest of the script simply automates step which you can do manually.

 

 

BTW – I do not get all of the credit of figuring this out and making it work in our produciton environment. Quite the contrary. So credit is due to those who chose to remain anonymous.

10 comments

2 pings

Skip to comment form

  1. soder

    Wow, wonderfully detailed description. There is 1 thing though, that none of these infinite-wisdom Lync MVPs could answer to me: Exchange 2007 version of the exchucutil.ps1 had a -verify commandline switch, that run the script in read-only mode. Since Exchange 2010, the switch is omitted from every documentation, even if I could find the word in the script source code. Unfrotunately, this PS script looks chinese to me, so I couldnt decipher if the -verify switch is still honored, or it will run in write-enabled mode regardless of what I try to do. Can you comment on this maybe?

  2. soder

    Wow, wonderfully detailed description. There is 1 thing though, that none of these infinite-wisdom Lync MVPs could answer to me: Exchange 2007 version of the exchucutil.ps1 had a -verify commandline switch, that run the script in read-only mode. Since Exchange 2010, the switch is omitted from every documentation, even if I could find the word in the script source code. Unfrotunately, this PS script looks chinese to me, so I couldnt decipher if the -verify switch is still honored, or it will run in write-enabled mode regardless of what I try to do. Can you comment on this maybe?

  3. soder

    Sorry, but I am really interested in your answer 🙂

  4. soder

    Sorry, but I am really interested in your answer 🙂

  5. flinchböt

    Thanks for bugging me again. Sorry I didn’t respond sooner. I kept the initial notification “unread” in e-mail, but then I moved (and hadn’t turned on my lab until today), my inbox got full and I forgot. So I looked at the script that comes with Exchange Server 2013 and yes, verify is still supported.

    The following is seen on line 10:
    param($Forest = $null,[Switch]$Verify)

    This means that it is looking for a command line parameter named Verify. Launch this with -Verify to run the script in “verify mode”. (The switch basically means that if -verify is present, set the $verify variable to $True, else set it to $false).

    However, bizareness happens a few lines down – line 21 to be exact:
    $Verify = $false;

    This sets $Verify to $false NO MATTER WHAT you set on the command line. So effectively, $Verify is disabled.

    I don’t have any idea why this is done but there is certainly a good reason. I don’t want to speculate.

    So if you want to run a verify, comment out line 21, then run exchucutil.ps1 -verify. I ran it in my lab and I got a list dumping out the permissions and not attempting to actually make changes.

    However, don’t take this as approval to edit this script in your production environment. there is *some* reason why Microsoft effectively removed the verify permissions. (Well, it could be an oversight. It probably is….)

    In short, as of at least Exchange 2013 (and maybe 2010) verify does not officially work anymore.

  6. flinchböt

    Thanks for bugging me again. Sorry I didn’t respond sooner. I kept the initial notification “unread” in e-mail, but then I moved (and hadn’t turned on my lab until today), my inbox got full and I forgot. So I looked at the script that comes with Exchange Server 2013 and yes, verify is still supported.

    The following is seen on line 10:
    param($Forest = $null,[Switch]$Verify)

    This means that it is looking for a command line parameter named Verify. Launch this with -Verify to run the script in “verify mode”. (The switch basically means that if -verify is present, set the $verify variable to $True, else set it to $false).

    However, bizareness happens a few lines down – line 21 to be exact:
    $Verify = $false;

    This sets $Verify to $false NO MATTER WHAT you set on the command line. So effectively, $Verify is disabled.

    I don’t have any idea why this is done but there is certainly a good reason. I don’t want to speculate.

    So if you want to run a verify, comment out line 21, then run exchucutil.ps1 -verify. I ran it in my lab and I got a list dumping out the permissions and not attempting to actually make changes.

    However, don’t take this as approval to edit this script in your production environment. there is *some* reason why Microsoft effectively removed the verify permissions. (Well, it could be an oversight. It probably is….)

    In short, as of at least Exchange 2013 (and maybe 2010) verify does not officially work anymore.

  7. flinchböt

    @soder – I just blew out my response into a full blog post: http://flinchbot.wordpress.com/2013/10/17/exchucutil-ps1-and-the-verify-switch/

  8. flinchböt

    @soder – I just blew out my response into a full blog post: http://flinchbot.com/index.php/2013/10/17/exchucutil-ps1-and-the-verify-switch/

  9. Cleveland

    I’m not sure where you’re getting your info, but good topic.
    I needs to spend some time learning much more or
    understanding more. Thanks for magnificent info I was looking for this info for my mission.

  10. Cleveland

    I’m not sure where you’re getting your info, but good topic.
    I needs to spend some time learning much more or
    understanding more. Thanks for magnificent info I was looking for this info for my mission.

  1. exchucutil.ps1 and the Verify Switch | Thoughts From a Böt Named Flinch

    […] I got an excellent question as a followup to my post breaking down the exchucutil.ps1 script in excruciating detail. […]

  2. exchucutil.ps1 and the Verify Switch » Thoughts From a Bot Named Flinch

    […] I got an excellent question as a followup to my post breaking down the exchucutil.ps1 script in excruciating detail. […]

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

%d bloggers like this: