Exchange PrepareAD

#MsExchange

If you can remember back when you built you Exchange environment, you ran setup /PrepareAD and you may or not have noticed this message:

Setup will prepare the organization for Exchange 2013 by using 'Setup /PrepareAD'. No Exchange 2010 server roles have been detected in this topology. After this operation, you will not be able to install any Exchange 2010 servers.
For more information, visit: http://technet.microsoft.com/library(EXCHG.150)/ms.exch.setupreadiness.NoE14ServerWarning.aspx

Now if you forgot about this, your are screwed. In this case I would not be able to install any Exchange 2010 in the future.

Wouldn’t it be nice if Microsoft made you press any key or something, so if you have a DOH! moment you can fix things?!

Parsing Message Headers using Powershell

#MsExchange #Powershell

So sometimes I want or need to look at the message headers of an email to work out where it comes from.  You can use something like http://mxtoolbox.com/public/tools/emailheaders.aspx to do that, but I thought, you must be able to so this with Windows Powershell.  Guess what you can ;-)

Meet Parse-EmailHeaders.ps1.  Now I cheated a little by using Sapien Powershell Studio to build the GUI as I couldn’t be bothered to manually create the GUI in notepad ;-)

So fireup powershell and run the script.

Parse-EmailHeader(1)

Essentially, in outlook get the message header of an email and paste it in to the GUI box and click on the Parse Button.

Parse-EmailHeader(2)

In the shell you will see what it’s up to.

PS C:\PS> .\Parse-EmailHeader.ps1
Looking for C:\PS\Parse-EmailHeader_KnownIPs.csv
 - Found
 --  60  Found
Discovering IP Geo Information
 + / +
[fe80::4100:46ba:3a5c:54ce] + / + [fe80::b42c:7f9:e0ef:23d%10]
10.11.123.10 + / + 10.11.250.20
91.206.176.84 + / + 10.47.216.189
2a01:111:f400:7e04::177 + / + 2a01:111:e400:8814::26
10.242.16.26 + / + 10.242.136.153
213.199.154.78 + / + 10.174.65.75
2a01:111:f400:7e00::105 + / + 2a01:111:e400:1000::18
10.242.64.18 + / + 10.242.68.20
unknown unknown GB GB GB unknown unknown GB unknown unknown
http://maps.googleapis.com/maps/api/staticmap?size=800x800&sensor=false&path=color:0xff0000ff|weight:5|UB40SL|E149YY&mar
kers=size:mid%7Ccolor:red%7CUB40SL%7CE149YY
Looking for C:\PS\Parse-EmailHeader_KnownIPs.csv
 - Found
 --  60  Found
Discovering IP Geo Information
 + / +
 + / + 10.180.165.174
 + / + 10.114.67.131
 + / + 10.152.6.199
 + / + mail-la0-f45.google.com
relay146.msgfocus.com. [86.54.102.146] + / + mx.google.com
209.85.215.45 + / + 10.47.216.92
2a01:111:f400:7e04::108 + / + 2a01:111:e400:9414::19
10.141.8.147 + / + 10.242.141.17
unknown unknown unknown unknown unknown unknown unknown CL unknown unknown
http://maps.googleapis.com/maps/api/staticmap?size=800x800&sensor=false&path=color:0xff0000ff|weight:5|UB40SL|E149YY&mar
kers=size:mid%7Ccolor:red%7CUB40SL%7CE149YY
Looking for C:\PS\Parse-EmailHeader_KnownIPs.csv
 - Found
 --  60  Found
Discovering IP Geo Information
 + / +

http://maps.googleapis.com/maps/api/staticmap?size=800x800&sensor=false&path=color:0xff0000ff|weight:5|UB40SL|E149YY&mar
kers=size:mid%7Ccolor:red%7CUB40SL%7CE149YY
PS C:\PS> .\Parse-EmailHeader.ps1
Looking for C:\PS\Parse-EmailHeader_KnownIPs.csv
 - Found
 --  60  Found
Discovering IP Geo Information
 + / +
[10.0.0.189:8127] helo=HOME-?? + / + Momo-dev:3.5.1.0
unknown unknown UA
http://maps.googleapis.com/maps/api/staticmap?size=800x800&sensor=false&path=color:0xff0000ff|weight:5|UB40SL|E149YY&mar
kers=size:mid%7Ccolor:red%7CUB40SL%7CE149YY

The end result is a saved file called Parse-EmailHeaders.html which will automagically open once the parsing is complete.

Parse-EmailHeader(3)

Now, as an added bonus, if a file called Parse-EmailHeaders_KnownIPs.csv exists, it will use it to populate Country and City of IP’s you know about.

IP,Country,City
2a01:111:e400:8000::28,Microsoft EOP (NL),Amsterdam
10.242.80.27,Microsoft EOP (NL),Amsterdam
10.242.77.156,Microsoft EOP (NL),Amsterdam
10.16.249.240,Microsoft EOP (IE),Dublin

Why have this?  Well I put all my known Exchange Hub and Edge servers in, with the Datacentre location so I can see the path it took.  Create the csv file in the same folder as the .ps1 and chop and change as you wish.

Hope you like

Parse-EmailHeader.ps1 (zip)

Add Excluded Applications to Windows Error Reporting

#Powershell

The place I am working at is using an app called Exclaimer to put signatures on email.  It drives me mad, and it creating mini dumps when it crashes.  Found a server if 10GB of min dump.

Check it out, open control panel and then in the search box type Problem Reports. Then select View all problem reports from the list.  So you can clear them from here, but I wanted to stop them being generated for Exclaimer.

So from Problem reports, click action Centre in the address bar and under maintenance there is setting.  Then at the bottom of Problem Reporting Setting is the option to exclude from reporting.  As you would expect this is just a registry hack, but you have to know what service is running the application you want to exclude.  So check the service and then you can adapt this:

#Start Control Panel and search for "Problem Reporting"
#http://support.microsoft.com/kb/163846
#NT AUTHORITY\LOCAL SERVICE S-1-5-19 
#NT AUTHORITY\NETWORK SERVICE S-1-5-20

#http://blogs.microsoft.co.il/scriptfanatic/2010/05/16/quicktip-additional-powershell-registry-drives/
$null           = New-PSDrive -Name HKU -PSProvider Registry -Root Registry::HKEY_USERS
$path           = "HKCU:\Software\Microsoft\Windows\Windows Error Reporting\ExcludedApplications"
$LocalService   = "HKU:\S-1-5-19\Software\Microsoft\Windows\Windows Error Reporting\ExcludedApplications"
$NetworkService = "HKU:\S-1-5-20\Software\Microsoft\Windows\Windows Error Reporting\ExcludedApplications"

if (-not (Test-Path -Path $path)){$null = New-Item -Path $path}
if (-not (Test-Path -Path $LocalService)){$null = New-Item -Path $LocalService}
if (-not (Test-Path -Path $NetworkService)){$null = New-Item -Path $NetworkService}

$apps  = @()
$apps += "Exclaimer.PolicyProcessingEngine.RemoteDeploymentService.exe"
$apps += "Exclaimer.PolicyProcessingEngine.ConfigurationService.exe"
$apps += "Exclaimer.PolicyProcessingEngine.RemoteDeploymentService.exe"
$apps += "Exclaimer.Connectors.MailRules.ExchangeUpdateService.exe"

ForEach($app in $apps){
  Write-Host $app
  Set-ItemProperty -Path $path           -Name $App -Value 1 -Type DWord
  Set-ItemProperty -Path $LocalService   -Name $App -Value 1 -Type DWord
  Set-ItemProperty -Path $NetworkService -Name $App -Value 1 -Type DWord
}

Using powershell to add local intranet setting in IE

#Powershell

This has been bugging me for a while.  When testing OWA on an Exchange Server, integrated website tests fail as the domain the server is in, is not in the trust intranet setting for IE.

Thanks to Bing, found some code and adapted it ;-)

if (-not (Test-Path -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\OSIT.org.loc'))
{
    $null = New-Item -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\OSIT.org.loc'
}
Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\OSIT.org.loc' -Name http -Value 1 -Type DWord
Set-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains\OSIT.org.loc' -Name https -Value 1 -Type DWord

Fix-ResynchronizingOrInitializing.ps1

#MsExchange #Powershell

Sometimes you get databases in a DAG with an Initializing or Resynchronizing state.  The way I have found to fix this is to Suspend the database copy and then resume it.

If you have quite a few databases its a pain in the butt using the console to do this .. so I wrote this.  You have to run it on the server that has a copy in either Initializing or Resynchronizing state.

##########################################################################################
#Load the Exchange 2010 bits & bobs
#########################################################################################
$xPsCheck = Get-PSSnapin | Select Name | Where {$_.Name -Like "*Exchange*"}
If ($xPsCheck -eq $Null) {Write-Host "Loading Exchange Snapin"; Add-PsSnapin Microsoft.Exchange.Management.PowerShell.e2010}

$gmdcs = Get-MailboxDatabaseCopyStatus
ForEach($item in $gmdcs){
  $tmpstatus = $item.Status
  $tmpName   = $item.Name
  Write-Host $tmpName "["$tmpStatus"]"
  IF (($tmpStatus -eq "Resynchronizing") -OR ($tmpStatus -eq "Initializing")){
    Write-Host "- Suspending"
    suspend-MailboxDatabaseCopy -Identity $tmpName -Confirm:$False
    Write-Host "- Resuming"
    resume-MailboxDatabaseCopy -Identity $tmpName
  }
}

Exchange 2013 Command Log

#MsExchange #Powershell

One of the things I like about Exchange 2010 is the ability in the Exchange Management Console to view the command log.  So typically I would do some in the console, the get the command by clicking View and selecting View Exchange Management Shell Command Log, finding the command I just ran and using it in a script.

Well Exchange 2013 is all web based now and that feature has gone :-( but you can still get the information by using the  Search-AdminAuditLog cmdlet.

This works for both Exchange 2010 and 2013 .. enjoy

$whoai = ([System.Security.Principal.WindowsIdentity]::GetCurrent()).Name
 $saal = Search-AdminAuditLog -UserIds $whoai | Sort RunDate -Descending
 $Matrix = @()
 ForEach($Item in $saal){
 $tmpMatrix = ""|Select Caller, When, Change
 $tmpMatrix.Caller = $Item.Caller
 $tmpMatrix.When = $Item.RunDate
 $tmpMatrix.Change = $Item.CmdLetName + " "
 $tmpMatrix.Change += "'" + $item.ObjectModified + "' "
$tmpCmdletParameters = $item.CmdletParameters
 $Param = ""
 ForEach($tmpParam in $tmpCmdletParameters){
 $Param += " -" + $tmpParam.Name + " '" + $tmpParam.Value + "' "
 }
 $tmpMatrix.Change += $Param
 $Matrix += $tmpMatrix
 }
$Matrix | ft -auto -wrap

NetApp SnapManager for Exchange Reports and Powershell Brackets

#NetApp #Powershell

SME is a great tool, but it has an undocumented feature, where it doesn’t flush it’s report files.  Now these files get big and I wanted a way to zip or delete the files.

The issue is that the folder name has brackets in it [servername] and powershell treats brackets as “special”.
Try it! Open powershell, create a folder and put a file in the folder

md C:\ps\[test]

now dir it:

dir C:\ps\[test]

Nothing right, but it works with the command prompt.  It took figging ages and a fair amount of Bing time to work a way around it, it’s dead simple:

dir -LiteralPath C:\ps\[test]

Yeah baby! using -LiteralPath does the trick

Powershell Split String

#Powershell

I wanted to put a disclaimer in my profile.ps1 file, but I wanted it to look nice.  I wanted it to split at 67 characters and split whole words.

It was a painful exercise, but this works!

$message="This system is the property of Flaphead.com, and provided only for authorised used according to Flaphead.com policies. This system may be subject to monitoring for lawful purposes and to ensure compliance with Flaphead.com policies in accordance with all applicable legislation. Use of this system constitutes consent to lawful monitoring, Flaphead.com policies and all applicable legislation."

$SplitAt = 67
$Start = 0
$MessageLength = $Message.Length
$MessageArray = @()
$more = $True
While($more){
$CharsLeft = $MessageLength - $Start
$splitNow = [math]::min($SplitAt, $CharsLeft)
$chars = $Message.substring($start,$SplitNow)
if($splitNow -ne $SplitAt){$tmpLine = $Chars}ELSE{ $tmpLine = $Message.substring($start,$chars.lastindexof(" ")+1)}
$start += $tmpLine.Length
IF([string]::IsNullOrEmpty($tmpLine)){$more=$False}ELSE{ $MessageArray += $tmpLine}
$tmpLine
if($start -gt $MessageLength){$more=$False}
}