Win, VM, Linux, Scripting – ramblings of a SysAdmin
MS Exchange 2007
Restoring mailboxes in Exchange 2007 (part 1)
Jul 15th
Lately I’ve been doing a number of mailbox restore procedures on Exchange 2007, so I thought it would be a good idea to make my own posts about it (yes it involves scripting), because things are not always as straightforward as MS or TechNet say it is. This is going to be a multi-part post: Create the RSG and mount the DB to be restored, Restore mailbox(es), Remove the restored DB and RSG. Before you think about it I’m going to answer it for you:
Q: But why don’t we use the nice GUI Tool from Exchange Management Console (Extra.exe) and do it from there, “we don’t need no scripting”?
A: My experience tells me the scripted method is safer and works “as expected” unlike the GUI, which says it did something, when it didn’t (I’ve spent days trying to figure out why a RSG Database won’t actually dismount when the GUI said: “Completed Successfully”.
OK, let’s get on with it. All that I am about to explain requires Exchange Administrator privileges on the Exchange servers.
We will be creating a Recovery Storage Group, this is the first step in the restore process. To create the RSG you need following:
- Adequate disk-space to restore the mailbox database, locally on the Exchange Server where the DB was residing
- Exchange Management Shell running as Administrator (especially on CCR clusters)
- No other Recovery Storage Group already created on that server with an existing RSG database (you can only have 1 RSG with 1 DB in the RSG). It is best to remove any previous RSG completely then recreate it for your needs.
- Specific information like which DB to link to the RSG and the list of mailboxes to restore.
Creating a Recovery Storage Group can be as easy as this:
New-StorageGroup -Server <MBX Role Server Name> -Name <StorageGroup Name> -LogFolderPath <Logs Folder> -SystemFolderPath <SystemFiles Path> -Recovery -Verbose
The command is very similar to creating a new SG, except for the -Recovery switch, designating it as a Recovery Storage Group. I added the -Verbose switch so you can see what is going on behind the scenes.
New-MailboxDatabase -MailboxDatabaseToRecover <Mailbox Name> -StorageGroup <Recovery Storage Group Name> -EdbFilePath <path to store edb file> -Verbose
Here it is just as easy as creating a new mailbox database, only you are creating it in the recovery storage group you created with the previous command. The key thing to remember here is that the value of the “MailboxDatabaseToRecoverParameter” must be the exact same name of the mailboxDB of which you want to recover from. If the name is different you will not be able to run any restore commands, because it will not be able to find any mailboxes when it searches the recovered database.
A working script for creating the RSG
Below I’m sharing with you a working snippet that should help in creating a recovery storage group and DB. In short here is what the code does:
Using a given UserPrincipalName…
- Attempts to retrieve the mailbox for the UPN (it is a “forest friendly” coding for retrieving the mailbox). If it fails it quits
- Checks if a folder structure for placing, logs, system files and the edb file exists (I used a location called d:, use a variable if you like).
- If folders already exist, it will quit, otherwise it will create a folder with the MDB name, and logs and edb subfolders,
- Next it checks if a Recovery Storage Group already exists, unless you cancel the script it will continue to use this RSG, with the given details. Otherwise it will create a RSG on its own.
- It will then create a mailbox database where you / your backup admin will restore your exchange backup.
$MBX_UPN = Read-Host
$Filter = "UserPrincipalName -like '$MBX_UPN'"
$SourceMBX = get-mailbox -IgnoreDefaultScope -Filter $Filter
If ($SourceMBX -eq $null) {
Write-Host -foregroundcolor Red "No Mailbox for $MBX_ID found`nScript will Quit"
exit }
Write-Host -ForegroundColor Green "Source Mailbox is`n $SourceMBX"
$LinkedMDB = Get-MailboxDatabase -Identity $SourceMBX.Database
Write-Host -ForegroundColor Green "Ok, Database ($($LinkedMDB.StorageGroup.Name)) is grabbed, now creating RSG Folders and RSG`nPress Enter to continue or Ctrl+C to Cancel"
Read-Host
#Checking if the RSG folders already exist, if not attempt to create them
If ((Test-Path "d:\$($LinkedMDB.StorageGroup.Name)")) {
Write-Host -ForegroundColor Red "Folder already exists. Please remove d:\$($LinkedMDB.StorageGroup.Name) before running this script again.`nScript will quit"
exit
}
$SysPath = New-Item -Type Directory -Path d: -Name $LinkedMDB.StorageGroup.Name | Get-Item
If ((Test-path $SysPath)) {
$DBPath = New-Item -Type Directory -Path $SysPath -Name DB | Get-Item
$LogsPath = New-Item -Type Directory -Path $SysPath -Name Logs | Get-Item
}
#If folders were created successfully we can continue
If ((Test-path $SysPath) -and (Test-path $DBPath) -and (Test-path $LogsPath)) {
#Checking if RSG already exists
$RSG_check = Get-StorageGroup -Server $LinkedMDB.ServerName | where {$_.Recovery -like "True"}
If ($RSG_check -ne $null) {
Write-Host -ForegroundColor Magenta "A RSG was found on $($RSG_check.ServerName). Here are RSG Details:"
$RSG_Check | select-object Name,Identity,Recovery,LogFolderPath,SystemFolderPath | fl
Write-Host -ForegroundColor Magenta "To use this RSG Press Enter, to cancel Press Ctrl+C"
Read-Host
}
Else {
Write-Host -ForegroundColor Green "Now creating Recovery Storage Group..."
New-StorageGroup -Server $LinkedMDB.Server -Name "Recovery Storage Group" -LogFolderPath $LogsPath.FullName -SystemFolderPath $SysPath.FullName -Recovery -Verbose
}
Write-Host -ForegroundColor Green "OK! No RSG found. Now creating RSG Database..."
New-MailboxDatabase -MailboxDatabaseToRecover $LinkedMDB.AdminDisplayName -StorageGroup "$($LinkedMDB.ServerName)\Recovery Storage Group" -EdbFilePath "$($DBPath.FullName)\$($LinkedMDB.Name).edb" -Verbose
}
Else {
Write-Host -ForegroundColor Red "Could not Create folder or folder structure in d:\$($LinkedMDB.StorageGroup.Name). Check messages above for errors! Script will quit."
exit
}
This is about it with creating a Recovery Storage Group, it is actually not difficult, just remember to name the MDB inside the RSG with the same name as the source MDB (this was also required on Exchange 2003, as far as I know). Also you cannot have more than one RSG per Maibox Server, it is best to remove any RSG you have after you are finished recovering data. Next post we will discuss how to restore data from a MDB and how to remove the RSG.
As always I value your feedback and hope you found this post useful.
Change Notification “From” Email Address in FSE
Mar 28th
After a recent deployment of FSE (Forefront Server for Exchange) on an Exchange CMS, I sat back and just watched Forefront notifications come in. Initially they were delivered in my Outlook junk email folder, but I quickly figured it out and added the “domain” Forefront was sending from. This was all ok for me, a sysadmin, but then it hit me: Users whose attachments get blocked also get this notification and it probably ends up in the junk folder aswell. First I thought, ok, let’s push a list of accepted domains down to the clients, but then it dawned on me that there had to be a way to change the “from” address in Forefront. As an added bonus I wanted to find a way to change it on any Server Role (mailbox, hub, cas, edge). Thankfully the Forefront Server for Exchange User Guide provides the answer (goes to show RTFM sometimes goes a long way).
How to Change the From Address
This From Address is written down in a registry key of the Server where FSE is installed.
- Open the Registry Editor and browse to the corresponding key depending on the OS version you have:
For 32-bit:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Forefront Server Security\ Notifications\FromAddress
For 64-bit:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Forefront Server Security\Notifications\FromAddress - Change the default value to the sender name you would like. I chose a name that also identifies the server where the notification is sent from. You can use any alphanumeric characters, just keep in mind that illegal characters are replaced with “_”.
- Now Microsoft says to Restart/Recycle the Exchange and FSE services for this change to become active, please read the notes below regarding this:
Notes: Restarting/Recycling Services looks like quite a simple task however, I do have some hints on that:
- If using a CMS (Clustered Mailbox Server) you just have to recycle FSE on the ACTIVE node, FSE is not actively running the PASSIVE node. Exchange services don’t need to be restarted for this change to take effect – (this is my personal observation)
- Recycling FSE on servers running Microsoft Exchange Transport Service (Transport, Edge Roles) will also recycle the Microsoft Exchange Transport service (Transport Service has a dependency on FSE) – so plan for downtime.
- There is a “bug” in Forefront: after the change and restarting services (not sure what is the cause, didn’t play around to find out) Forefront sends out 3 failed update notifications (1 per engine), for deprecated scan engines it has (AhnLab, Sophos, CAvet) even though none of those engines are enabled/configured to get updates. I spent almost 2 hours scouring the Internet for a reason why this happened. Best just to ignore it, save yourself some brain-cells.
- If changing the registry key by hand via remote registry you will not see the wow6432Node because regedit already connected you to that key.
Disclaimer: As you know changing the registry is “bad juju” if you don’t know what you are doing you can break things, so handle these operations with care.
This is probably the first post in a series related to Forefront Security for Exchange, I hope they prove useful.
Get Forwarding Email Address of Forwarded Mailboxes
Jan 23rd
This second article, let’s start by talking a little about the “-Filter” parameter, used in most Exch Shell cmd-lets that I’ve found myself abusing of these past days. I have supporting role in an Exchange 2007 Migration Project, and we were tasked with “cleaning up” what is left of the Legacy Exchange Servers in terms of mailboxes. The Domain structure contains multiple forests, one of which has quite a few child domains. In “everything is a possibility” domain structures say you may be required to
Task #1 - Get a list of all legacy mailboxes that have forwarding addresses enabled or that DO NOT have a forwarding address at all.
and then
Task #2 – Based on the list from 1, create a report with forwarded email address and the forwarding address.
Task #1 – Is done via this one liner
$LegacyFWList = get-mailbox -ResultSize unlimited -RecipientTypeDetails LegacyMailbox -IgnoreDefaultScope -Filter {(ForwardingAddress -like '*')} | select-object ForwardingAddress,WindowsEmailAddress,RealFWAddress
Code Breakdown:
get-mailbox -ResultSize unlimited -RecipientTypeDetails LegacyMailbox -IgnoreDefaultScope -Filter {(ForwardingAddress -like '*')} -ResultSize unlimited
- By default the cmdlet returns only the first 1000 results. I used unlimited but it also accepts a number as input
- get-mailbox cmdlet extracts only “LegacyMailbox” objects – this means mailboxes on servers pre Exchange 2007.
- IgnoreDefaultScope performs a forest-wide search. Without this only legacy MBX’s on exchange servers in the forest root domain would have been returned.
- Using this does have some limitations to it, check the help for what those are.
- Biggest limitation is that -Identity must now be the a valid DN of the object.
- I did not want to extract all DN’s in the forest and pipe them to the cmdlet, I looked for an alternative to this.
I discovered the –Filter parameter. It allows you to apply filters to the search on more Object Properties, much better than –Identity which we cannot use because of the -IgnoreDefaultScope.
A great thing about it is that it can be used without any limitations with IgnoreDefaultScope. Full details about how to use –Filter Parameter and what properties of AD objects are filterable can be found here and here. Back to our task, you can see what we did.
-Filter {(ForwardingAddress -like '*')}
We looked for any objects that contained any value in the “ForwardingAddress” Property of the returned object
But say you want the opposite of this “get all legacy mailboxes that have no forwarding address”…if would stand to reason that this should work:
-Filter {(ForwardingAddress -notlike '*')}
You are out of luck, it returns the entire list of legacy recipients. I went through a few filters until I found this:
-Filter {(ForwardingAddress -ne $null)}
or
-Filter {(ForwardingAddress -ne*')}
I have to say that it was a surprise when I stumbled upon this, as it doesn’t really make sense. TechNet articles say -like, and I assume also -notlike accept wildcards, while -eq does not, you can also assume -ne does not. Well -ne does take wildcards, which I particularly do not mind in this case. I’m not sure if this is a bug, a feature, or just a flaw in my logic somehow and it’s working because it is supposed to.
Moving on…
select-object ForwardingAddress,WindowsEmailAddress,RealFWAddress
- I can save you running a “| get-member” on what the get-mailbox returned previously and tell you that only “ForwardingAddress,WindowsEmailAddress” are properties returned by get-mailbox.
- “RealFWAddress” is something I made up. Why? Well unless you know already ForwardingAddress is not an address actually, it is a collection of properties for the recipient where emails are forwarded, the list contains DN, ObjectGUID, CN and others, not an actual email address.
- RealFWAddress is a blank property, attached to the $LegacyFWList object, as a placeholder for when we do script a way to get that email address…which is now! read on
Task #2 – Create a list of forwarded addresses and forwarding addresses.
Now we come to the second part of my post, the “get-recipient” cmdlet. Since there is no way for us to know to what object are the emails forwarded to [it could be a DL, a contact, a mailbox, another legacy user] we have to make our search as broad as possible. If you try to run get-mailbox on a contact object you will get nothing obviously. We are using foreach-object to go through the entire list. ForwardingAddress is actually the CN of the object. We pass the DN of the Property to a cmdlet that will return a primary email address, if any.
This following code will accomplish just that:
$LegacyFWList | foreach-object {
$ForwardingDN = $_.ForwardingAddress.DistinguishedName
$Filter = "DistinguishedName -like '$ForwardingDN'"
$_.RealFWAddress = get-recipient -Filter $Filter -IgnoreDefaultScope | select-object PrimarySmtpAddress}
$LegacyFWList | export-csv "c:\Change\This\Path.csv"
Code Breakdown:
$ForwardingDN = $_.ForwardingAddress.DistinguishedName $Filter = "DistinguishedName -like '$ForwardingDN'"
- I used these 2 variables in the code, $DistinguishedName and $Filter, trying to write a one liner resulted in somehow “deformed” filter command that get-recipient would not understand.
$_.RealFWAddress = get-recipient -Filter $Filter -IgnoreDefaultScope | select-object PrimarySmtpAddress
- Lastly, RealFWAddress property I introduced above gets populated with PrimarySmtpAddress value.
$LegacyFWList | export-csv "c:\Change\This\Path.csv"
- In the end all that’s left is export the $LegacyFWList variable to CSV and process however you wish, or just store it in xml / pass it on to another part of a script.
I have to admit the last part of the code is less ideal. Why? Well, the export does not output a clean forwarding email address. I have tried various ways to fix it, but in the end I concluded that it took me 30 minutes of trying to get a nicer export, and 15 seconds to fix it after importing the csv in excel.
UPDATE 1: 26.01.2010 – added proper way to filter people with no forwarding address
UPDATE 1: 21.02.2010 – added syntax highlighting and small rewrites
Exchange 2007 Management Shell – Basics, Tips and Tricks
Jan 11th
This first post i’d like to talk a little about Exchange 2007′s Management Shell. If you are already working with Exchange 2007, you must know by now that there has been a shift in how administration and management tasks are done. Microsoft introduced the Management Shell of Exchange as a Powershell Extension, and a lot of the GUI tasks are now done from the command line.
Powershell is Microsoft’s new (or maybe not so new, let’s just say latest , it has been with use for some years) extensible command shell interface. It is built on .NET Framework, so it may look more like a shell aimed at the programming savvy, but I think people that have really basic programming skills can handle it after some getting used to.
How to get it? Well assuming you have an Exchange 2007 server in your organization, you have it by default on the Exchange Servers. You can and should use the shell on the Exchange Servers [running scripts closest to the "managed entities" is always best IMO, you avoid adding additional Points of Failure] but you can also download the Exchange Management Tools for Exchange 2007 and install them on your own workstation, or a workstation you designate for management.
Ok, so now you have the tools installed. Unless you already found the link to the Exchange Management Shell on your start menu, you can start the tools by typing this in the run box.
%windir%\system32\windowspowershell\v1.0\powershell.exe -PSConsoleFile "%ProgramFiles%\Microsoft\Exchange Server\bin\exshell.psc1" -noexit -command ". '%ProgramFiles%\Microsoft\Exchange Server\bin\Exchange.ps1'"
You can probably use this in some scripted NT batch files, if you like. You will find some good information on Google about introductions to powershell, I won’t bore you with them. I’m going to assume you have the shell, have done some really light reading on the topic.
Here are some quick fixes for Powershell’s quirks though. You must have stumbled upon this at least once.
Ever ran an extended help command like the one below?
get-help Get-MailBox -full
Lots of lines scrolling, you couldn’t read a thing. It’s like one of those days you wish you were either in The Matrix or Startrek, so you can read the damn command-let help slowly or be an Android…or you could have not skipped the RTFM part of powershell, but if you’re like me, you did.
Worst part about this is that the powershell.exe line buffer is the same as the buffer of cmd.exe, so if the help is big enough, scrolling back up won’t give you a change to read all of the help.
How to Fix it? – Not to worry old NT batch and Powershell have the answer
Tip #1 – Using Powershell - For this I should have done the obvious, meaning taking a closer look at the output of:
get-help get-help (yes you can get-help on get-help)
There’s a little line that says there’s also the option of running, help [command] instead of get-help. You you try:
help get-mailbox -full
You get the equivalent of the /p switch on the NT batch, now that’s help for non Android people
Tip #2 – Oldschool, using NT batch you can redirect the output of help to a text file and read it at your leisure.
get-help Get-mailbox-full > c:\get-mailbox.help notepad C:\get-mailbox.help
Which one is better?
Powershell method is quicker because you don’t have to notepad the text file and search for it there. However you cannot use the same method for cmd-let output [or may I have not figured out how, yet], basically reading the output of a cmd-let page by page.
For that you still have to do use the general method, in NT Batch redirect the output to a file and read that later on, like this for example:
get-excommand | select-object Type,Name | ft > c:\ex-command.help
notepad C:\ex-command.help
This should help anyone struggling with learning the Exchange shell syntax for referencing all of the cmd-let switches available.
Happy Scripting, hope this first post was not so bad.