by

Get Full Control over your Exchange remote PowerShell session

[Another great post from Shay Levy - original available here]

PowerShell 2.0 supports two kinds of remote configurations: fan-in and fan-out. When we execute a command against a bunch of servers we use fan-out (one to many). Fan-in is used when multiple users are connecting to a remote server (many to one). Exchange server implements a fan-in configuration via a virtual directory on the Exchange server’s IIS. We can connect to the virtual directory (http connection) and manage our Exchange server remotely, without having to install the Exchange Management Tools locally on our admin station.

We can create a remote session (using the currently logged on credentials) with the New-PSSession cmdlet.

If you need to connect with alternate credentials, add the –Credential parameter:

PS > $uri = 'http://dc1.homelab.com/PowerShell'
PS > $session = New-PSSession -ConfigurationName Microsoft.Exchange `
               -ConnectionUri $uri -Authentication Kerberos

The session is created and we can import the commands from the remote session into our local session and use them as if they were installed locally (aka, implicit remoting).

PS> Import-PSSession –Session $session

When the session finished importing, all commands from the remote session are available in our local session. In the background a module is created that contains all remote commands. Let’s try one command:

PS > Get-MailboxDatabase

Name                           Server   Recovery  ReplicationType
----                           ------   --------  ---------------
Mailbox Database 0311695863    DC1      False     None

Now let’s try to get the database size:

PS > $db = Get-MailboxDatabase -Identity 'Mailbox Database 0311695863' -Status
PS > $db.DatabaseSize
152.1 MB (159,449,088 bytes)

We get back the size of the database in MB and in bytes. Exchange supports several methods to format the size of an object (mailbox/database) through a series of methods: ToBytes(), ToKB(), ToMB() etc. Let’s try to format the size of the database and get the value in bytes:

PS > $db.DatabaseSize.ToBytes()
Method invocation failed because [System.String] doesn't contain a method named 'ToBytes'.
At line:1 char:25
+ $db.DatabaseSize.ToBytes <<<< ()
    + CategoryInfo          : InvalidOperation: (ToBytes:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

We get an error that the DatabaseSize property doesn’t contain the ToBytes method. We can also see that DatabaseSize is a String. This is the expected behavior in a remoting session. When a source computer sends a script to a remote computer, the code is serialized first (converted to XML), when it gets to the destination machine it’s converted back (deserialized) and executed. The result is serialized again and sent back to the source computer. It is important to understand that when the source computer gets the final result, it convert it back to objects but the objects are “dehydrated”, and contains a bunch of Note properties and one method – ToString (some “primitive” types, like Int, can be deserialized better than others). As a consequence, if we want to execute methods on the “real” object we need to do that on the remote end. When we want to get hold of the object itself (and it’s members) we invoke the command on the remote end with the Invoke-Command

cmdlet:

 
PS > $identity = 'Mailbox Database 0311695863'
PS > $sb = {(Get-MailboxDatabase -Status –Identity $identity).DatabaseSize.ToBytes()}
PS > Invoke-Command -Session $session -ScriptBlock $sb

Method calls are not allowed in restricted language mode or a Data section.
    + CategoryInfo          : ParserError: (ToGB:Token) [], ParseException
    + FullyQualifiedErrorId : MethodCallNotSupportedInDataSection

Another error! We cannot run methods in restricted language mode. What does this mean? The Exchange configuration is locked down (restricted session). By default, only administrators can connect to the end point, but they are restricted as well!

A few words on LanguageMode. There are three possible values: NoLanguage, RestrictedLanguage, and FullLanguage. In FullLanguage you can do whatever you want. In NoLanguage mode only commands that are using the Runspace APIs are allowed, and in RestrictedLanguage mode commands that contain scripts that need to be evaluated are not allowed.

This was a bit disappointing. If the server admin cannot have full access to the remote session then who can? I’m not sure why the Exchange team decided to lock the environment. The notion of connecting to any remote server and managing it without having to install local tools is not fulfilled here.

I started to look for a way to bypass that limitation and it appears that I was looking in the wrong direction! Hats off to my friend, MVP Aleksandar Nikolic, for a great tip! We can change the language mode by opening the web.config file in the PowerShell virtual directory:

 

 

 

 

 

 

I changed the value to FullLanguage, saved the file, recycled the MSExchangePowerShellAppPool application pool and re-created a remote session:

PS > $uri = 'http://dc1.homelab.com/PowerShell'
PS > $session = New-PSSession -ConfigurationName Microsoft.Exchange `
-ConnectionUri $uri -Authentication Kerberos
PS > $identity = 'Mailbox Database 0311695863'
PS > $sb = {(Get-MailboxDatabase -Status –Identity $identity).DatabaseSize.ToBytes()}
PS > Invoke-Command -Session $session -ScriptBlock $sb
159449088

And it worked, we can invoke methods in the remote session without having to parse strings. The final step was to create a separate environment, for admins only, one that doesn’t change the original configuration made by the Exchange team. I reverted back the value in the web.config file and wrote the following script to automate the process. Log on to your Exchange server, open PowerShell (not EMS) and run it (comments inline):

# load the IIS module
Import-Module WebAdministration

# get the path to the exchange server installation directory
# and create a new folder for the exadmin application
$path = ‘HKLM:SOFTWAREMicrosoftExchangeServerv14Setup’
$exbin = Join-Path (Get-ItemProperty $path).MsiInstallPath ClientAccess
$folder = New-Item -Path $exbinexadmin -ItemType Directory -Force

# copy the web.config file to the new directory, load it (as xml) and
# change the language mode (from RestrictedLanguage) to FullLanguage
Copy-Item $exbinPowerShellweb.config $folder.FullName -Force
[xml]$wconfig = Get-Content $exbinexadminweb.config
$wconfig.configuration.appSettings.add.value = 'FullLanguage'
$wconfig.Save("$exbinexadminweb.config")

# Create a new IIS application pool, and start it
$pool = New-WebAppPool -Name exadmin

# Configure the exadmin app pool to run under the LocalSystem account (0)
Set-ItemProperty IIS:AppPoolsexadmin -Name ProcessModel -Value @{identityType=0}

# start app pool
Start-WebAppPool -Name exadmin

# Create a new IIS Web Application.
$application = New-WebApplication -Name exadmin -Site 'Default Web Site' `
-PhysicalPath "$exbinexadmin" -ApplicationPool $pool.name

#Set the application SSL settings to accept client certificates (if they are provided)
Set-WebConfigurationProperty -Filter //security/access –Name SslFlags `
-Value SslNegotiateCert -PSPath IIS: -Location 'Default Web Site/exadmin'

# create new end point configuration and allow administrators to remotely run commands
# a dialog is shown with the local administrators group selected, and we can add
# users/groups we want to have access to the end point
#Get-PSSessionConfiguration exadmin | Unregister-PSSessionConfiguration -Force
Register-PSSessionConfiguration -Name exadmin -Force
Set-PSSessionConfiguration -Name exadmin -ShowSecurityDescriptorUI -Force

# testing the new environment, uncomment and change database identity
# create a fan-in session (notice we are connecting to exadmin) and try to
# invoke the ToBytes method – it works
#$sb = { (Get-MailboxDatabase -Status -Identity 'Mailbox Database 0311695863').DatabaseSize.ToBytes() }
#$uri = ‘http://dc1.homelab.com/exadmin’
#$session = New-PSSession -ConfigurationName Microsoft.Exchange –ConnectionUri $uri
#Invoke-Command $session –ScriptBlock $sb

Now you can connect from any computer that has PowerShell 2.0 installed to your Exchange server and gain full access. I hope this has been helpful, here’s some related resources you may find useful as well:

How objects are sent to and from remote sessions
Configuring PowerShell for Remoting – Part 1
Configuring PowerShell for Remoting – Part 2 (Fan-In)
Administrator’s Guide to Windows PowerShell Remoting
Layman’s Guide to PowerShell 2.0 remoting
Deep Dive video: Constrained PowerShell Endpoints – Aleksandar Nikolic
Book: Microsoft Exchange 2010 PowerShell Cookbook – Mike Pfeiffer

by

Exchange – Removing Illegal Alias Characters using PowerShell

[I came across this great article by Shay Levy and found it very useful so I thought I would share it. The original article can be found here]

If you’re in a mixed-mode environment with both Exchange 2003 and Exchange 2007/2010 you may have noticed this message when using the Get-* cmdlets in the Exchange Management Shell:

WARNING: The object domain.com/Users/UserName has been corrupted, and it’s in an inconsistent state. The following validation errors happened:
WARNING: Property expression “xx xxx” isn’t valid. Valid values are: Strings formed with characters from A to Z (uppercase or lowercase), digits from 0 to 9, !, #, $, %, &, ‘, *, +, -, /, =, ?, ^, _, `, {, |, } or ~. One or more periods may be embedded in an alias, but each period should be preceded and followed by at least one of the other characters. Unicode characters from U+00A1 to U+00FF are also valid in an alias, but they will be mapped to a best-fit US-ASCII string in the e-mail address, which is generated from such an alias.

Or one of the following:

WARNING: Object <distinguished name of the recipient> has been corrupted and it is in an inconsistent state. The following validation errors have been encountered:
WARNING: <alias of the recipient> is not valid for Alias.

These messages (there are others as well) appears when you try to manage a recipient with spaces (or any other invalid character) in its alias using the Exchange management tools. For example, in Exchange Server 2003, you could create recipients with spaces in aliases. Exchange Server 2007/2010 does not allow recipients to have spaces in their aliases. The biggest problem with invalid aliases – you will not be able to move a mailbox to an Exchange 2007/2010 server. To mitigate this I’ve written the following function.

Note: In Exchange 2010, the mailbox’s alias is generated based on the Name property. Invalid characters in the name will be replaced with a question mark (?) when the alias is generated.

function Test-ExchangeAlias
{
    param(
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [ValidateLength(1,64)]
        [string]$Alias,

        [switch]$RemoveIllegalCharacters
    )

    begin
    {
        $IllegalCharacters = 0..34+40..41+44,46+58..60+62+64+91..93+127..160
    }

    process
    {
        if($RemoveIllegalCharacters)
        {
            foreach($c in $IllegalCharacters)
            {
                $escaped = [regex]::Escape([char]$c)

                if($Alias -match $escaped)
                {
                    Write-Verbose "illegal character code detected: '$c'"
                    $Alias = $Alias -replace $escaped
                }
            }

            $Alias
        }
        else
        {
            for($c=0; $c -lt $Alias.Length; $c++)
            {
                $code = [int][char]$Alias[$c]
                Write-Verbose "Testing current Alias character code: $code"

                if($IllegalCharacters -contains $code)
                {
                    Write-Verbose "Character code: $code is an invalid alias character."
                    $false
                    return
                }
            }

            $true
        }
    }
}

The function supports two parameters, Alias and RemoveIllegalCharacters. In the Begin block we assign a series of numbers to a variable, $IllegalCharacters, using the range operator along with the plus operator (+) to combine a range with a list of elements in an array. These numbers represents the character codes an alias cannot contain.

In the Process block we check if the RemoveIllegalCharacters parameter has been specified. If it was specified, all invalid characters are removed and a fixed alias is returned. Otherwise the function just tests if the alias is valid and returns $true/$false respectively. Invalid characters are removed using the Replace operator. Since we don’t know if each invalid character is a regular expression meta character we use the Escape method to convert it so that the regular expression engine will interpret any metacharacters that it may contain as character literals.

With the following command you can fix all invalid aliases on all mailbox objects:

 
Get-Mailbox –ResultSize Unlimited | Where-Object {-not (Test-ExchangeAlias -Alias $_.Alias)} | Foreach-Object {
     $NewAlias = Test-ExchangeAlias -Alias $_.Alias -RemoveIllegalCharacters
     $_ | Set-Mailbox –Alias $NewAlias
}

When running the above you’ll get the ‘inconsistent state’ error for each invalid alias mailbox object but if you issue the command again you’ll see that the error has gone and the Aliases have been fixed.

by

Released: Update Rollup 1 for Exchange Server 2010 SP1

Microsoft today release Update Rollup 1 for Exchange Server 2010 SP1 after the Exchange CXP team released it last week.

This update includes new fixes for the following server roles:

  • Client Access
  • Mailbox
  • Edge Server
  • Hub Transport

The following three major fixes were called to our attention by the Exchange CXP team:-

  • 2028967 Event ID 3022 is logged and you still cannot replicate a public folder from one Exchange Server 2010 server to another
  • 2251610 The email address of a user is updated unexpectedly after you run the Update-Recipient cmdlet on an Exchange Server 2010 server
  • 978292 An IMAP4 client cannot send an email message that has a large attachment in a mixed Exchange Server 2010 and Exchange Server 2003 environment

Fix 98359 addresses an issue with redirected mail that will solve a large number of the people who I speak to’s problems…

  • 983549 Exchange Server 2010 removes the sender’s email address from the recipient list in a redirected email message

For a list of changes that are included in this update rollup, see KB2407028.

Note Microsoft Update does not detect Update rollups on Exchange Server 2010 Mailbox servers that are part of a database availability group (DAG).

You may want to deploy Update Rollup 1 for Exchange Server 2010 SP1 to multiple computers that are running Exchange Server 2010 SP1. Or, you may want to deploy Update Rollup 1 for Exchange Server 2010 SP1 to Mailbox servers that are part of a database availability group (DAG). The update rollup is also available from the Microsoft Download Center.

The following file is available for download from the Microsoft Download Center: Exchange2010-KB2407028-EN-x64 package