de-DEen-GB
 
rss

Just can't get enough of IT

This blog is about mostly anything in IT. But the primary focuses are Microsoft Technologies like Exchange, Office 365, Azure and Cloud Security.

Problem

I came across an interesting issue when setting up a new Exchange 2013 server in an Exchange organization having the cmdlet extension agent enabled.

As mentioned in my last post Exchange setup checks for the existence of the ScriptingAgentConfig.xml file when agent extenstion is enabled in the Exchange organization. It turned out that this ist not only true when you install an Exchange update using /mode:update, but as well when installing a new Exchange server using /mode:install.

The following error occurs when Exchange Management Tools are provisioned.

Configuring Microsoft Exchange Server

    Preparing Setup                                                               COMPLETED
    Stopping Services                                                             COMPLETED
    Copying Exchange Files                                                        COMPLETED
    Language Files                                                                COMPLETED
    Restoring Services                                                            COMPLETED
    Language Configuration                                                        COMPLETED
    Exchange Management Tools                                                     FAILED
     The following error was generated when "$error.Clear();
          Set-WERRegistryMarkers;
        " was run: "Microsoft.Exchange.Provisioning.ProvisioningBrokerException: Provisioning layer
initialization failed: '"Scripting Agent initialization failed: "File is not found: 'C:\Program File
s\Microsoft\Exchange Server\V15\Bin\CmdletExtensionAgents\ScriptingAgentConfig.xml'.""' ---> Microso
ft.Exchange.Provisioning.ProvisioningException: "Scripting Agent initialization failed: "File is not
 found: 'C:\Program Files\Microsoft\Exchange Server\V15\Bin\CmdletExtensionAgents\ScriptingAgentConf
ig.xml'."" ---> System.IO.FileNotFoundException: "File is not found: 'C:\Program Files\Microsoft\Exc
hange Server\V15\Bin\CmdletExtensionAgents\ScriptingAgentConfig.xml'."
   at Microsoft.Exchange.ProvisioningAgent.ScriptingAgentConfiguration.Initialize(String xmlConfigPa
th)
   at Microsoft.Exchange.ProvisioningAgent.ScriptingAgentConfiguration..ctor(String xmlConfigPath)
   --- End of inner exception stack trace ---
   at Microsoft.Exchange.ProvisioningAgent.ScriptingAgentConfiguration..ctor(String xmlConfigPath)
   at Microsoft.Exchange.ProvisioningAgent.ScriptingAgentClassFactory.get_Configuration()
   at Microsoft.Exchange.ProvisioningAgent.ScriptingAgentClassFactory.GetSupportedCmdlets()
   at Microsoft.Exchange.Provisioning.ProvisioningBroker.BuildHandlerLookupTable(CmdletExtensionAgen
t[] enabledAgents, Exception& ex)
   --- End of inner exception stack trace ---
   at Microsoft.Exchange.Provisioning.ProvisioningLayer.GetProvisioningHandlersImpl(Task task)
   at Microsoft.Exchange.Provisioning.ProvisioningLayer.GetProvisioningHandlers(Task task)
   at Microsoft.Exchange.Configuration.Tasks.Task.<BeginProcessing>b__4()
   at Microsoft.Exchange.Configuration.Tasks.Task.InvokeNonRetryableFunc(Action func, Boolean termin
atePipelineIfFailed)".

As expected a fresh Exchange install contains the sample file only. The following screenshot shows the Exchange Management Shell and the releated folder in the background.

Enabled cmdlet extension agent breaks Exchange setup

 

Solution

The only solution currently known to me is to disable the cmdlet extension agent until the setup of the new Exchange server has finished.

Disable-CmdletExtensionAgent "Scripting Agent"

Having the cmdlet extension agent disabled the setup finishes without any issues. Don't forget to copy the cmdlet extension Xml file to the newly built server and to enable the cmdlet extension agent again.

Enable-CmdletExtensionAgent "Scripting Agent"

 

Links

 


You need assistance with your Exchange Server setup? You have questions about your Exchange Server infrastructure and going hybrid? You are interested in what Exchange Server 2016 has to offer for your environment?

Contact me at thomas@mcsmemail.de
Follow at https://twitter.com/stensitzki

 

Read More »

When you've enabled the Exchange scripting agent extension agents, it is required to copy the configuration file to each Exchange server. Paul Cunningham's script helps you to achive this goal pretty easily.

But if you have installed the Exchange 2013 Management Tools on additonal servers, these servers are not fetched using the Get-ExchangeServer cmdlet. But when you install a Cumulative Update the existence of the extension agent config file is checked. And this even on a server having only the Exchange Management Tools installed.

Therefore the following PowerShell code provides an easy and simple way to add additonal server having the Exchange 2013+ Management Tools installed (aka Admin Servers, Monitoring Servers, Job Servers, etc.). The script uses a filter to select Exchange 2013 servers only, as the script has been extended in an environment having still active Exchange 2007 servers.

The following PowerShell snippet displays only the changes, which need to be added to Paul's original script starting row 68.

# Original PowerShell code
# $exchangeservers = Get-ExchangeServer

# Select all Exchange 2013 servers only, restrict properties to Name and AdminDisplayName
$exchangeservers = Get-ExchangeServer | ?{$_.AdminDisplayVersion -like "Version 15.0*"} | Select Name, AdminDisplayVersion

# Add additional servers as needed

$manualServers = @()
# Copy and modify as needed
$manualServers += (New-Object PSObject -Property @{Name="EXSRV2010";AdminDisplayVersion="Version 14"})
$manualServers += (New-Object PSObject -Property @{Name="EXSRV2013-01";AdminDisplayVersion="Version 15"})
$manualServers += (New-Object PSObject -Property @{Name="EXSRV2013-02";AdminDisplayVersion="Version 15"})

# Combine arrays
$exchangeservers = $exchangeservers + $manualServers

# End Modification

$report = @()

[string]$date = Get-Date -F yyyyMMdd-HHmmss

Enjoy extending the Exchange PowerShell cmdlets.

Links

Questions? Just leave a comment.

Read More »

There are three different ways to configure new Exchange user mailboxes after these have been created.

  • The classic manual administrator approach (keeps your job safe, but is it fun?)
  • The workflow based approach using some kind of IDM workflow solution (keeps the IDM consultant's job safe)
  • The scripting agent approach by extending the Exchange cmdlets (keeps your job safe, is fun, keeps you in control and get's you more free time)

The Exchange cmdlet extension is controlled by a scripting agent configuration file and a organizational setting to enable/disable the scripting agent.

Preparation

A scripting agent configuration file sample (ScriptingAgentConfig.xml.sample) is located in

  • $exinstall\Bin\CmdletExtensionAgents

The sample needs to be renamed to ScriptingAgentConfig.xml, to be picked up the PowerShell engine.

As always, a slight reminder: Test any modification in a test environment first, before you use the extension in a production environment.

After succesfull testing and deployment, you need to enable the scripting agent using

Enable-CmdletExtensionAgent "Scripting Agent"

Example

Even thought that you can extend mostly any Exchange cmdlet, this example covers the extension of the New-Mailbox and Enable-Mailbox cmdlets in a multi domain and multi AD site environment.

This extension disables the following CAS mailbox settings, after a new mailbox has been created:

  • ActiveSync
  • IMAP4
  • POP3
  • MAPI over HTTP

What does the example do?

  • Extension is named MailboxProvisioning and handles the cmdlets New-Mailbox and Enable-Mailbox
  • Is called on trigger OnComplete
    • The extension code is called after the original cmdlet has finished
  • Code is executed, if the original cmdlet was successfully finished
  • Code is executed, if the mailbox created is not an archive
  • A slight delay of 10 seconds ensures that domain controller activities have been finished
    • Can be adjusted or even removed, depending on your environment
  • Try to fetch at least on of three user parameters to identify the user mailbox
    • Checking for Identity, Name, Alias
  • Fetch a list of all domain controllers in the current AD site where the Exchange server is located
  • Iterate through the list of domain controllers and try to fetch the new CAS mailbox
    • If fetched, remember the domain controller's FQDN
  • Change the CAS mailbox settings as needed and use the remembered domain controller as DC to write to

 

<?xml version="1.0" encoding="utf-8" ?>
  <Configuration version="1.0">
	<Feature Name="MailboxProvisioning" Cmdlets="New-Mailbox,Enable-Mailbox">
		<ApiCall Name="OnComplete">
			If ($succeeded) {
				if (!($provisioningHandler.UserSpecifiedParameters.Archive -eq $true)) {
					# delay execution for 10 seconds, adjust as needed
					Start-Sleep -s 10
					
					# validate parameters to use a not null parameter
					if ($provisioningHandler.UserSpecifiedParameters["Identity"] -ne $null) {
						$user = $provisioningHandler.UserSpecifiedParameters["Identity"].ToString()
					}
					elseif ($provisioningHandler.UserSpecifiedParameters["Name"] -ne $null) {
						$user = $provisioningHandler.UserSpecifiedParameters["Name"].ToString()
					}
					else {
						$user = $provisioningHandler.UserSpecifiedParameters["Alias"].ToString()
					}
						
					# view entire forest in a multi domain environment
					Set-AdServerSettings -ViewEntireForest:$true
					
					# fetch domain controllers in AD site}
					$server = Get-ExchangeServer $env:computername
					$DCs = Get-DomainController | ?{$_.adsite -eq $server.site}
					
					$CasMailbox = $null
					foreach($d in $DCs) {
						while($CasMailbox -eq $null) {
							# find a valid domain controller having the updated user object
							$CasMailbox = Get-CASMailbox $user -DomainController $d.dnshostname -ErrorAction SilentlyContinue
							# fetch DCs FQDN
							$WriteDC = $d.DnsHostName
							break
						}
					}
					
					try {
						# set CAS features as needed
						Set-CasMailbox $user -ActiveSyncEnabled:$false -ImapEnabled:$false -PopEnabled:$false -MapiHttpEnabled:$false -DomainController $WriteDC -ErrorAction SilentlyContinue
					}
					catch {}
				}
			}
		</ApiCall>
	</Feature>
</Configuration>

Notes

After adding the PowerShell code to the ScriptingAgentConfig.xml file, the file needs to be distributed across all Exchange servers. For distribution of the scripting agent configuration file I personally recommend Paul Cunningham's PowerShell script.

Be aware of the fact, that the scripting agent Xml is being validated using a strict schema validation. The scripting agent Xml is case sensitive, as noted here.

Links

Read More »