TLS / SSL cipher strength change

One of my customers asked me today what is the configuration of their send connectors, because they need to establish new boundary encryption between them and business partner. One of the settings was to check connectors what ciphers does it use.

I havent seen that setting before on Exchange side, so I start googling a bit and after few dead ends I have found this article: http://social.technet.microsoft.com/Forums/en-US/exchangesvrgeneral/thread/5830c533-38eb-4d88-92fe-6e1a02d7bac4

Thanks to JShan99 here it is.

Cipher is the combination of hash and encryption algorithm which can be used and is compatible on all ends of communication channel. Ciphers are used to protect data and communication against unauthorised access, so strength of cipher is the most important. Ciphers can be set via group policy by the following settings. The first cipher in the list should be the strongest one and then the list should fall beck to less stronger ones and so on to lowest, however standard cipher set by default in Windows Server 2008 R2 is not the strongest one.

Default Settings

open: gpedit.msc -> Computer Settings -> Administrative templates -> Network -> SSL Configuration Settings ->SSL Cipher Suite Order and you will see Not Configured and default list of ciphers in order from 1st to last to try.

 before

Change settings

  • Click Enabled radio button and on the left side fill in the correct order of ciphers from strongest or most preferred to use to weak ones or less preferred.

after

  • Apply settings
  • Reboot computer

Settings can be managed via GPO.

Update: Exchange 2013 is not supported on servers running FIPS (algoritnms for hashing and signing supported by US Federated Information Oricessing Standard: http://support.microsoft.com/?kbid=811833)

Print server – enable auditing and log gathering script – Event ID: 307

I was asked by my friend to install print server to his environment (Windows Server 2008 R2 SP1), enable auditing of print jobs and create report on weekly basis.

  • To install print server there is very nice video: on youtube
  • After printers are installed and deployed we should enable audit of PrinterService event. logs. On the print server Open Server Manager -> Diagnostics -> Event Logs -> Applications and services Logs -> Microsoft -> Windows -> PrintService

server_manager

  • Expand PrintService event. logs -> Right click Operational
  • Make sure Disable Log is present (Otherwise click Enable Log)

Log Enabled

  • Print test pages
  • Run the following script and it will go through event. logs, collect event. ID 307 for last 168 hours and gather you CSV file with the most important info about printed documents (What, where, when and by whom was printed)
$dat = get-date
$name="$($dat.day)_$($dat.month)_$($dat.year)"
start-transcript c:\scripts\printaudit_logs\log_$name.log
#print audit script
$pserv = "PrintServerName"
$AuFileRaw = "c:\scripts\printaudit_logs\Audit.csv"
$AuFileLRD = "c:\scripts\printaudit_logs\last_run.csv"
################################# Test mode - uncomment
$dat | Out-File $AuFileLRD 
############################################################################################################################################
#read_event_log daily from current
$a = Get-WinEvent -ProviderName "Microsoft-Windows-PrintService" -ComputerName $pserv |  where {(($_.id -eq 307) -and ($_.timecreated -ge $dat.addhours(-168)))} | select Message,TimeCreated

#read event from file
#$a = Get-WinEvent -Path 'C:\Scripts\PrintAudit_logs\system log.evtx' |  where {(($_.id -eq 307))} | | select Message,TimeCreated

$lr = "DocName;user;IP;Printer;IP Port;size;pages;Date"
$lr  | Out-File $AuFileLRD -Append
foreach ($rec in $a) {
$r = $rec.message -replace " owned by ",";"
$r = $r -replace " was printed on ",";"
$r = $r -replace " on ",";"
$r = $r -replace " through port ",";"
$r = $r -replace "  Size in bytes: ",";"
$r = $r -replace ". Pages printed: ",";"
$r = $r -replace ". No user action is required.",""
$r
$out = "$($r);$($rec.timecreated)"
#saving to raw file
$out | Out-File $AuFileRaw -Append
$out | Out-File $AuFileLRD -Append
}

#saving to raw file
#generate reports
#sending mail
Stop-Transcript

Update: I made new version of the script gathering print reports for selected period. It is also faster, because I have added additional conditions to not include empty lines in reports. Here is the new version. Blue lines are subject to change to alter period, logs placement and print server name:

#Version 1.1
$dat = get-date
$name="$($dat.day)_$($dat.month)_$($dat.year)"
start-transcript c:\scripts\printaudit_logs\log_$name.log
#print audit script
$pserv = "OPHQMS01"
$AuFileRaw = "c:\scripts\printaudit_logs\Audit.csv"
$AuFileLRD = "c:\scripts\printaudit_logs\last_run.csv"
$AuFileRep = "c:\scripts\printaudit_logs\Audit_$name.html"
$smtpserver = "smtp.domain.local"
$adminrecip = "zbynek.salon@salonovi.cz"
$month = $dat.addmonths(-1) | select month
################################# Test mode - uncomment
#$dat | Out-File $AuFileLRD 
############################################################################################################################################
#read_event_log daily from current
$b = @()
$a = Get-WinEvent -ProviderName "Microsoft-Windows-PrintService" -ComputerName $pserv | select id,Message,TimeCreated
#$a = Get-WinEvent -Path 'C:\scripts12013-082013.evtx' | select id,Message,TimeCreated
foreach ($line in $a){
$b += $line |  where {(($line.id -eq 307) -and ($line.timecreated.month -eq $month.month))} | select Message,TimeCreated
}

#read event from file
$lastm = "_$($dat.addmonths(-1).month)_$($dat.year)"
#creating folder structure
Remove-Item -Recurse -Force "c:\scripts\printaudit_logs\stats$($lastm)"
new-item -ItemType Directory -path "c:\scripts\printaudit_logs\stats$($lastm)" -erroraction SilentlyContinue
new-item -ItemType Directory -path "c:\scripts\printaudit_logs\stats$($lastm)\uzivatelske" -erroraction SilentlyContinue
new-item -ItemType Directory -path "c:\scripts\printaudit_logs\stats$($lastm)\tiskarny" -erroraction SilentlyContinue

$lr = "Dokument;Uživatel;IP;Tiskárna;IPPort;Velikost;Stran;Datum"
$lr  | Out-File $AuFileLRD
$lr  | Out-File $AuFileRaw
foreach ($rec in $b) {
if ( $rec.message -notlike $null) {
	$r = $rec.message -replace " owned by ",";"
	$r = $r -replace " was printed on ",";"
	$r = $r -replace " on ",";"
	$r = $r -replace " through port ",";"
	$r = $r -replace "  Size in bytes: ",";"
	$r = $r -replace ". Pages printed: ",";"
	$r = $r -replace ". No user action is required.",""
	$out = "$($r);$($rec.timecreated)"
#saving to raw file
	$out | Out-File $AuFileRaw -Append
	$out | Out-File $AuFileLRD -Append
	}
}

#saving to raw file

#generate reports
$Rep = Import-Csv $AuFileLRD -Delimiter ";"
$psum = @()
$usum = @()
$printers = $rep | group tiskárna | select name
$users = $rep | group uživatel | select name

# user stats
foreach ($us in $users){
$uout = "c:\scripts\printaudit_logs\stats$($lastm)\uzivatelske\$($us.name)$($lastm).csv"
$x = @(); $x +=$Rep | where {$_.uživatel -like "$($us.name)"}
$usum += $x | group uživatel,tiskárna,stran | select name,count
$x | select * -excludeproperty uživatel,ip,velikost,ipport |  Export-Csv $uout -Encoding unicode -Delimiter ";"
}
# printer stats
foreach ($pr in $printers){
$prout = "c:\scripts\printaudit_logs\stats$($lastm)\tiskarny\$($pr.name)$($lastm).csv"
$x = @(); $x +=$Rep | where {$_.tiskárna -like "$($pr.name)"}
$psum += $x | group tiskárna,stran | select name,count
$x | select * -excludeproperty tiskárna,ip,velikost,ipport | Export-Csv $prout -Encoding unicode -Delimiter ";"
}
$psum =  $rep | group tiskárna | sort count -Descending | select name,count
$usum =  $rep | group uživatel,tiskárna | sort count -Descending | select name,count
#sending mail
$body = "Zdravím,

Statistiky za měsíc $($lastm) naleznete v \\ophqms01\printaudit_logs .

S pozdravem
Admin" send-mailmessage -From zbynek.salon@domain.local -To $adminrecip -Subject "Print audit" -Body $body -BodyAsHtml -Encoding ([System.Text.Encoding]::unicode) -smtpserver $smtpserver Stop-Transcript

How to connect to shared / additional mailbox via POP3 (Exchange 2010/2013)

This article is analogical to my previous article for IMAP. http://exkb.wordpress.com/2013/01/10/how-to-connect-to-shared-additional-mailbox-via-imap-exchange-20102013/

Test via Telnet:

  • Prerequisite here is to have Plain text login set on Exchange servers (POP3). Use the following commands to set plaintext login. POP3 services must be restarted before change takes effect.
Set-POPSettings -Server <SERVERNAME> -LoginType PlaintextLogin
Get-Service *pop* | Restart-Service
  • type the following command into the command line. I use Windows Server 2008 R2 and there is no Telnet client feature installed by default, so if you dont have it, please install it via Server manager MMC.
telnet <name of your pop3 server> pop3 (where pop3 is key word of protocol used by telnet client)
  • You will get OK answer from your setver if everything is OK
user SALONOVI\Anatolij.Stokurev\Shared.Mailbox1 (According to POP3 protocol you have to insert valid username / password combination to logon to mailbox)
PASS Minus30* (Enter password)
LIST (list messages from the mailbox)
RETR 1 (retrieve first message from the list)
QUIT (End session)
  • Result is in the following Picture

result

Test via Outlook

  • Add POP3 connection to your existing profile or create new profile (File -> Account Settings -> New -> Manual Configuration -> POP/IMAP)
  • Open Settings
  • Change settings according the Picture:

outlook settings

  • Our admin user doesnt have e-mail address. Fill in e-mail address of the shared account instead
  • Into the username use the same syntax as before “DOMAIN\USER\MAILBOXALIAS”
  • In More settings TAB use working configuration of your SMTP server
  • Hit NEXT and you will get the test window. After test is OK you are ready touse new profile with POP3 connected to shared mailbox

Problems with certificate renewal Exchange 2010 / Exchange 2013 coexistence, Failed to enable constraints

Scenario:

I have a LAB, with Exchange 2010 / Exchange 2013 in coexitence:

  • 1 Exchange 2010 CHM
  • 2 DAG servers with FrontEnd and Backend roles and HAProxy load balancer

I have selected renew Exchange Certificate from EMC and got certificate request. Requested certificatee renewal on Startcom Certification authority -> Completed pending request

Problem:

When I was trying to renew certificate for SMTP / TLS, I started to get error message on the Picture.

Error

It was not possible to do anything with certificates in EMC, because list was empty.

Solution:

  • Run EMS
  • List certificates
Get-ExchangeCertificate | Select Status,Thumbprint,Notafter,Services | ft -Autosize
  • In the list you will see pending requests

List of certificates

  • Complete pending request
Import-ExchangeCertificate -FileData ([Byte[]]$(Get-Content -Path Z:Z_DOKUMENTYSALONOVI.CZSMTP_certifikat_renewal_2013_2.cer -Encoding byte -ReadCount 0))
completed pending request
  • Check certificate if it is valid
Get-ExchangeCertificate <Thumbprint> |fl ; Thumprint from previous command
  • Assign services to certificate (Requires confirmation to overwrite existing SMTP certificate)
Get-ExchangeCertificate <Thumbprint> | Enable-ExchangeCertificate -Services SMTP
Assigning Services
  • Once CSR is completed an all certificates are in place, it is possible to access  certificates in EMC again.

After

How to connect to shared / additional mailbox via IMAP (Exchange 2010/2013)

I was solving the issue for one of our customers. They have application, which needs to log on to mailbox via IMAP, but administrator user doesn´t have mailbox. Here is the solution:

  • Administrator user “Anatolij.Stokurev” doesn´t have a mailbox
  • Anatolij.Stokurev needs to access mailbox “Shared.mailbox1”
  • Syntax to log on to additional / shared mailbox via IMAP is to use: DOMAIN\USERNAME\MAILBOXALIAS in username field and password in your application,
  • NOTE: get-credential command doesn´t accept syntax from point above (double in username) so you shoud enter credentials directly

Example:

  • I have created shared mailbox in Exchange 2013 and user in AD

shared creation1

I granted full access to user, who doesnt have mailbox Anatolij.Stokurev by command

Add-MailboxPermission Shared.Mailbox1 -user Anatolij.Stokurev -AccessRights FullAccess

permissions1

Note: You cannot add permissions for user without mailbox in EAC / ECP. Powershell is the only option here.

Test via Telnet:

  • Prerequisite here is to have Plain text login set on Exchange servers (IMAP). Use the following commands to set plaintext login. IMAP services must be restarted before change takes effect.
Set-IMAPSettings -Server <SERVERNAME> -LoginType PlaintextLogin
Get-Service *ima* | Restart-Service
  • type the following command into the command line. I use Windows Server 2008 R2 and there is no Telnet client feature installed by default, so if you dont have it, please install it via Server manager MMC.
telnet <name of your imap server> imap (where imap is key word of protocol used by telnet client)
  • You will get OK answer from your setver if everything is OK
a1 LOGIN SALONOVI\Anatolij.Stokurev\Shared.Mailbox1 Minus30*  (According to IMAP protocol you have to insert valid username / password combination to logon to mailbox)
a2 LIST "" "*" (list folders from the mailbox)
a5 LOGOUT (End session)
  • Result is in the following Picture

result

Test via Outlook

  • Add IMAP connection to your existing profile or create new profile (File -> Account Settings -> New -> Manual Configuration -> POP/IMAP)
  • Open Settings
  • Change settings according the Picture:

outlook settings

  • Our admin user doesnt have e-mail address. Fill in e-mail address of the shared account instead
  • Into the username use the same syntax as before “DOMAIN\USER\MAILBOXALIAS”
  • In More settings TAB use working configuration of your SMTP server
  • Hit NEXT and you will get the test window. After test is OK you are ready touse new profile with IMAP connected to shared mailbox

Tips for good articles and tools

Here is articles list. I like those, need those and don´t have time to look for them again and again.

Active Sync features comparison:

http://en.wikipedia.org/wiki/Comparison_of_Exchange_ActiveSync_Clients

Free e-mail checking tools:

http://centralops.net/co/

http://mxtoolbox.com/

RBAC manager

http://rbac.codeplex.com/

My friend’s Exchange-related blog!!!!

http://ficility.net

SPN records check (Service Principal Name) – Exchange 2010 / Exchange 2013

There is a lots of articles about enabling Kerberos authentication for Exchange 2010 CAS servers, but not much about what SPN (Service Principal Names) list. It is kind of easy to determine list of SPNs for particular servers. SPN records are similar in Exchange 2010 and Exchange 2013. Here is the procedure

  • Open command line or Powershell under elevated permissions
  • Type the following command
setspn -Q */*EX10* >> d:spn_records.txt 

Explanation

  • setspn.exe – name of utility, which can set SPN records or list their status
  • -Q -switch to query mode (listing existing SPN records)
  • */ wildcard of SPN name
  • /*EX10* -names of the servers with wildcards
  • >> d:spn_records.txt – direct output to file with append feature

Results

Result for Exchange CAS/HUB

CN=SRVEX10CH1,OU=Exchange,OU=Servers,DC=subdomain,DC=domain,DC=local
 POP3/SRVEX10CH1.subdomain.domain.local
 POP3/SRVEX10CH1
 POP/SRVEX10CH1.subdomain.domain.local
 POP/SRVEX10CH1
 IMAP4/SRVEX10CH1.subdomain.domain.local
 IMAP4/SRVEX10CH1
 IMAP/SRVEX10CH1.subdomain.domain.local
 IMAP/SRVEX10CH1
 SMTP/SRVEX10CH1
 SMTP/SRVEX10CH1.subdomain.domain.local
 SmtpSvc/SRVEX10CH1
 SmtpSvc/SRVEX10CH1.subdomain.domain.local
 exchangeRFR/SRVEX10CH1
 exchangeRFR/SRVEX10CH1.subdomain.domain.local
 exchangeAB/SRVEX10CH1
 exchangeAB/SRVEX10CH1.subdomain.domain.local
 ExchangeMDB/SRVEX10CH1
 ExchangeMDB/SRVEX10CH1.subdomain.domain.local
 WSMAN/SRVEX10CH1
 WSMAN/SRVEX10CH1.subdomain.domain.local
 TERMSRV/SRVEX10CH1.subdomain.domain.local
 TERMSRV/SRVEX10CH1
 RestrictedKrbHost/SRVEX10CH1
 HOST/SRVEX10CH1
 RestrictedKrbHost/SRVEX10CH1.subdomain.domain.local
 HOST/SRVEX10CH1.subdomain.domain.local

Result for Exchange UM server

CN=SRVEX10UM1,OU=Exchange,OU=Servers,DC=subdomain,DC=domain,DC=local
 SmtpSvc/SRVEX10UM1.subdomain.domain.local
 SmtpSvc/SRVEX10UM1
 WSMAN/SRVEX10UM1
 WSMAN/SRVEX10UM1.subdomain.domain.local
 TERMSRV/SRVEX10UM1
 TERMSRV/SRVEX10UM1.subdomain.domain.local
 RestrictedKrbHost/SRVEX10UM1
 HOST/SRVEX10UM1
 RestrictedKrbHost/SRVEX10UM1.subdomain.domain.local
 HOST/SRVEX10UM1.subdomain.domain.local

Result for Exchange PF/Mailbox server

CN=SRVEX10PF1,OU=Exchange,OU=Servers,DC=subdomain,DC=domain,DC=local
 MSSRVrverClusterMgmtAPI/SRVEX10PF1
 MSSRVrverClusterMgmtAPI/SRVEX10PF1.subdomain.domain.local
 SMTP/SRVEX10PF1
 SMTP/SRVEX10PF1.subdomain.domain.local
 SMTPSVC/SRVEX10PF1
 SMTPSVC/SRVEX10PF1.subdomain.domain.local
 exchangeMDB/SRVEX10PF1.subdomain.domain.local
 exchangeMDB/SRVEX10PF1
 WSMAN/SRVEX10PF1
 WSMAN/SRVEX10PF1.subdomain.domain.local
 TERMSRV/SRVEX10PF1.subdomain.domain.local
 TERMSRV/SRVEX10PF1
 RestrictedKrbHost/SRVEX10PF1
 HOST/SRVEX10PF1
 RestrictedKrbHost/SRVEX10PF1.subdomain.domain.local
 HOST/SRVEX10PF1.subdomain.domain.local

Result for DAG

CN=EX10DAG,OU=Exchange,OU=Servers,DC=subdomain,DC=domain,DC=local
 MSServerCluster/EX10DAG.subdomain.domain.local
 MSServerCluster/EX10DAG
 MSServerClusterMgmtAPI/EX10DAG.subdomain.domain.local
 MSServerClusterMgmtAPI/EX10DAG
 MSClusterVirtualServer/EX10DAG.subdomain.domain.local
 MSClusterVirtualServer/EX10DAG
 HOST/EX10DAG.subdomain.domain.local
 HOST/EX10DAG

Mailbox quotas change based on Custom Attribute

  • Exchange 2010 / 2013 can be designed so, that multiple mailbox tiers can be placed within one database. In this case there is not easy way how to control mailbox limits for bigger companies. I wrote the script, which can help managing limits based on single value in Custom attribute 12.

How it works

  • Change custom attribute 12 for maiblox users to value Tier1, Tier2 ….Tier5
  • Plan to run the script on daily basis via task manager
  • Script will change the limits to correct values and check if the limits are still OK for existing mailboxes
  • If limits have changed for some reason. Script will set correct ones
  • For non existing value or deviated one: for example “Tier 1” the default tier will be set

What do you need to customize

  • Where to put report file (line 9)
  • Define tiers (Number for size, Unit for multiplier MB,GB etc)
  • You can specify unlimited value as well, unit value then is empty “”

Work left for service desk

  • Add tier info to CustomAttribute12 or leave it empty for default tier assignment
  • change CustomAttribute12 value once mailbox user requests change of mailbox limits

Script

 # Author: zbynek.salon@salonovi.cz
 # Version 3.0
 # Purpose: 1/ Changing limits based on tier value inside CustomAttribute12
 #
 #######################################################################################################################################################
 # Date and report definitions
 $dat = get-date | select day,month,year
 $date = "$($dat.day)_$($dat.month)_$($dat.year)"
 $file = "d:report_$date.txt"
 $report = "started at $($date) - Task 1/ Changing limits based on tier value inside CustomAttribute12"
 $report | out-file "$($file)" -width 2000000 -Append
 #######################################################################################################################################################
 # Tier definition W-Warning, S-ProhibitSend, R-ProhibitSendReceive, WU-Warning Unit, SU-Send Unit, RU-Receive Unit, TI - TierInfo
 $t = [PSCustomObject]@{
 T1 =[PSCustomObject]@{
 W="950"
 S="1024"
 R="1250"
 WU="MB"
 SU="MB"
 RU="MB"
 TI="Limit 1024MB"
 }
 T2 = [PSCustomObject]@{
 W="450"
 S="500"
 R="650"
 WU="MB"
 SU="MB"
 RU="MB"
 TI="Limit 500MB"
 }
 T3 = [PSCustomObject]@{
 W="130"
 S="150"
 R="200"
 WU="MB"
 SU="MB"
 RU="MB"
 TI="Limit 150MB"
 }
 T4 = [PSCustomObject]@{
 W="8192"
 S="10240"
 R="unlimited"
 WU="MB"
 SU="MB"
 RU=""
 TI="Business demand 8GB"
 }
 T5 = [PSCustomObject]@{
 W="2048"
 S="2548"
 R="3072"
 WU="MB"
 SU="MB"
 RU="MB"
 TI="Temporarily increased - for cleanup 2,5GB"
 }
 }
 #######################################################################################################################################################
 # Function
 function Limit ($mb,$ti,$rep){
 $res=0
 if ($mb.issuewarningquota.isunlimited -eq $true)
 {
 if ("unlimited" -ne $ti.w){$res=1}
 }
 else{
 if ($mb.issuewarningquota.value.toMB() -ne $ti.w){$res=1}
 }
 if ($mb.prohibitsendquota.isunlimited -eq $true)
 {
 if ("unlimited" -ne $ti.s){$res=1}
 }
 else{
 if ($mb.prohibitsendquota.value.toMB() -ne $ti.s){$res=1}
 }
 if ($mb.prohibitsendreceivequota.isunlimited -eq $true)
 {
 if ("unlimited" -ne $ti.r){$res=1}
 }
 else{
 if ($mb.prohibitsendreceivequota.value.toMB() -ne $ti.r){$res=1}
 }
 if ($res -eq 1){
 Write-Host "$($ti.TI)"
 $report = "$($mb.alias);$($mb.ExchangeGuid);$($mb.customattribute12);$($mb.issuewarningquota);$($mb.prohibitsendquota);$($mb.prohibitsendreceivequota);Will be set to correct limits"
 $report | out-file "$($rep)" -width 2000000 -Append
 set-mailbox "$($mb.exchangeguid)" -usedatabasequotadefaults $false -Prohibitsendquota "$($ti.s)$($ti.SU)" -prohibitsendreceivequota "$($ti.r)$($ti.RU)" -issuewarningquota "$($ti.w)$($ti.WU)"
 }
 else{
 Write-Host "$($ti.TI)"
 $report = "$($mb.alias);$($mb.ExchangeGuid);$($mb.customattribute12);$($mb.issuewarningquota);$($mb.prohibitsendquota);$($mb.prohibitsendreceivequota);Mailbox OK"
 $report | out-file "$($rep)" -width 2000000 -Append
 }
 }
########################################################################################################################################
 # Main program
 $a = $null
 $a = @()
 $a += get-mailbox -resultsize unlimited | select *quota*,customattribute12,alias,Exchangeguid
 foreach ($line in $a){
 if ($line.exchangeguid -ne $null){
 $tier=$null
 switch ($line.customattribute12) {
 "Tier1"{
 $tier = $t.t1
 Limit $line $tier $file
 }
 "Tier2"{
 $tier = $t.t2
 Limit $line $tier $file
 }
 "Tier3"{
 $tier = $t.t3
 Limit $line $tier $file
 }
 "Tier4"{
 $tier = $t.t4
 Limit $line $tier $file
 }
 "Tier5"{
 $tier = $t.t5
 Limit $line $tier $file
 }
 "$null"{
 $tier = $t.t3
 Limit $line $tier $file
 }
 default{
 $tier = $t.t3
 Limit $line $tier $file
 }
 }
 }
 }

Uninstallation of incorrectly installed package / RU

Sometimes it happens, that it is not possible to install some updates for example interim update for Exchange (RU), because previous installation was stuck.
The normal way of installing RU works like this:

1. Disable Forefront if installed (FSCUTILITY /DISABLE) – nice article for example here: http://www.urtech.ca/2012/03/solved-how-to-disable-forefront-for-exchange-without-killing-exchange/
2. Run installation of new RU (This will automatically uninstall prevous RU and install new one)
3. Reboot the server
4. Enable Forefront if installed (FSCUTILITY /ENABLE)

In our case the previous try recorded errors in event log:Event ID 1603 or Event ID 2771.
Both errors mean, that there was a problem uninstalling previous version of RU.

We have tried to:

1. uninstall RU manually but without success:
a/ selected your favorite way to uninstall RU (whether to use Control Panel -> Programs and features -> Select view installed updates -> Locate and uninstall needed package or using command line msiexec.exe /x <packagename.msp>
b/ Reboot the server

2. Install previous RU again
No success, the package cannot be applied to the version of the product that is installed on this computer (In normal words the update is already installed)

3. Install new RU

4. Cause 1)
Installation of previous RU went incorrect and package is in half installed state
we have tried to repair installation of the package by executing msiexec.exe /fa <path and name of RU package.msp>, but we have got the same errors (Event ID 1602)

5. Cause 2)
Previous RU package have been removed incorrectly and registry entries of this package are still visible in Programs and features TAB.
This was our case. We have done uninstallation of previous RU update for Exchange 2010 SP2, however record that RU is installed was still present in registry database of installed packages.
Database is located in the following registry key:

[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionUninstall]

and each particular subkey means one installed package. It is in most cases presented as package GUID. If you click on some subkey you will see the similar result as shown in the picture. The important stuff is package name and uninstallation string.
We copied uninstallation string and run it in elevated command prompt but it failed again.

Image

We made sure that previous RU was really uninstalled by checking Exchange version in Powershell, however record was still in the key mentioned above. We have exported the particular registry key and deleted it. After that we were able to install the same RU again and continue.