formats

Fumbling through Windows Server 2012 Virtual Desktop Infrastructure (VDI)

Published on 23/04/2013, by in Scripting, Windows.

I’m deploying a small VDI infrastructure for my employer. Being used to Citrix XenDesktop, the Windows 2012 implementation is, how to put it, “lightweight”.

The team has done a tremendous job of exposing the various config tasks in Server Manager. Tasks such as changing SSL certs across multiple hosts or deploying new VDI collections use remoting and PowerShell workflows to an impressive degree. It all seems almost too easy. Which is just what it is when you get stuck. Microsoft has completely forgotten to write good documentation for its VDI implementation. All you’ll find on Technet is some “test lab guides” (that are more often than not wrong of simply missing important steps) and a “troubleshooting” guide. I mean, come on. The best I’ve found so far is the built-in help for the RemoteDesktop PowerShell module. Simply nowhere near good enough for serious use.

Anyways. Apart from a few glaring bugs, the solution works fairly well. User Profile Disks are nice, and it’s even possible to specify what parts of the profile to keep at logoff, and what to discard.

The bugs I’ve found:

1. When creating a new Collection (of VDI VMs), I’m not able to choose the Template VM (or “Gold VM”) from the list. It simply isn’t there. Using PowerShell to create the Collection, it all works as advertised

2. If you’re customizing the VMs with an unattend.xml file, I’ve read that you need to remove the first line in the unattend file, or else the deployment will fail.

3. The “Auto save delay” setting on the collection, which specifies how long the VM should be kept running after user logoff before reverting, doesn’t always work. I have no idea why.

As for the PowerShell support, it’s in line with the rest of Windows Server 2012 – just great. It lets you script every single thing you’re able to do in the UI. Some of the CmdLets take an insane number of parameters, but that’s just how it is. Lots to do. In case you need it, I’ve included my own script for deploying a new Collection of 3 VMs. The “Template VM” needs to be a sysprepped VM, in powered off mode. I’ve tried to explain the various parameters as best I could, since official documentation is so lacking at the moment.

$CollectionName = "Timpex VDI" #Name of the VDI Collection
$TemplateName = "Timpex_VDI_Template" #The VM to be used as a template. Needs to be sysprepped and shut down
$TemplateHostServer = "TP-HV01.timpex.net" #The Hyper-V Server where the template exists
$Allocation = @{"TP-HV01.timpex.net"=3} #The hosts and number of VMs to create. Here I'm creating only one, on host TP-HV01
$usergroups = "TIMPEXNET\domain users" #The AD Group with access to the Collection
$ConnectionBroker = "tp-app13.timpex.net" #The Connection Broker computer
$UnattendFilePath = "\\tp-app13\c$\RDVirtualDesktopTemplate\Timpex-vdi-template-unattend.xml" #Path of the unattend file (Be sure to remove the first line (<!--?xml version="1.0" encoding="utf-8"?-->) in this file.
$LocalStoragePath = "D:\Hyper-V Data\VDI" #Where (on the hyper-v host) the VMs should be placed
$NamePrefix = "TPVDI" #The computername prefix of VMs. A number will be added to this prefix when VMs are generated
$UserProfileDiskPath = "\\tp-fil01.timpex.net\uvhd" #Path of User Profile disks
$machineOU = "OU=VDI VMs,OU=Workstations,DC=timpex,DC=net" #OU where machine accounts for VMs are to be placed. The connection broker computer needs write access to this OU.

#Do it
New-RDVirtualDesktopCollection -CollectionName $CollectionName -PooledManaged -VirtualDesktopTemplateName $TemplateName -VirtualDesktopTemplateHostServer $TemplateHostServer -VirtualDesktopAllocation $Allocation -StorageType LocalStorage -Description "PowerShell created Virtual Desktop Pool" -UserGroups $usergroups -ConnectionBroker $ConnectionBroker -VirtualDesktopNamePrefix $NamePrefix -VirtualDesktopPasswordAge 31 -UserProfileDiskPath $UserProfileDiskPath -MaxUserProfileDiskSizeGB 10 -OU $MachineOU -LocalStoragePath $LocalStoragePath -Verbose -CustomSysprepUnattendFilePath $UnattendFilePath

#Configure stuff
$RDColl = Get-RDVirtualDesktopCollection $CollectionName
$RDCOll | Set-RDVirtualDesktopCollectionConfiguration -ClientDeviceRedirectionOptions Clipboard,Drive,AudioVideoPlayBack -RedirectAllMonitors $false -SaveDelayMinutes 5

Also, here’s the unattend file I’m referencing. Notice that you don’t need to specify domain join details or computername, as these will be dynamically injected into the unattend file as the vms are deployed (mind you, I’m deploying x86-based VMs at the moment, so if you want to use x64-based VMs you need to use the corresponding x64 components in the unattend file).

<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="specialize">
<component name="Microsoft-Windows-International-Core" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="<a href="http://schemas.microsoft.com/WMIConfig/2002/State">http://schemas.microsoft.com/WMIConfig/2002/State</a>" xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>">
<InputLocale>0414:00000414</InputLocale>
<SystemLocale>nb-NO</SystemLocale>
<UILanguage>nb-NO</UILanguage>
<UserLocale>nb-NO</UserLocale>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="<a href="http://schemas.microsoft.com/WMIConfig/2002/State">http://schemas.microsoft.com/WMIConfig/2002/State</a>" xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>">
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<NetworkLocation>Work</NetworkLocation>
<ProtectYourPC>3</ProtectYourPC>
<SkipMachineOOBE>true</SkipMachineOOBE>
<SkipUserOOBE>true</SkipUserOOBE>
</OOBE>
<UserAccounts>
<AdministratorPassword>
<Value>WouldntYouLike2Know</Value>
<PlainText>false</PlainText>
</AdministratorPassword>
</UserAccounts>
<WindowsFeatures>
<ShowMediaCenter>false</ShowMediaCenter>
<ShowWindowsMail>false</ShowWindowsMail>
<ShowWindowsMediaPlayer>false</ShowWindowsMediaPlayer>
</WindowsFeatures>
</component>
<component name="Microsoft-Windows-International-Core" processorArchitecture="x86" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="<a href="http://schemas.microsoft.com/WMIConfig/2002/State">http://schemas.microsoft.com/WMIConfig/2002/State</a>" xmlns:xsi="<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>">
<SystemLocale>nb-NO</SystemLocale>
<UILanguage>nb-NO</UILanguage>
<UserLocale>nb-NO</UserLocale>
<InputLocale>0414:00000414</InputLocale>
</component>
</settings>
<cpi:offlineImage cpi:source="catalog://tp-fil01/pc-deployment/operating systems/win7sp1x64no_office2013_patched20130417/win7sp1x64no_office2013_patched20130417_dep07ddrive.clg" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>

formats

Bits and bobs from my PowerShell profile #1: Get-specialfolder

Published on 14/04/2013, by in Scripting.

I thought I’d share a few bits and pieces from my PowerShell profile that I’ve gathered over the years. Most of it is not fancy at all, but might be useful to you still.

The PowerShell profile is a script file that gets executed everytime you start the PowerShell shell. It’s where you put your own aliases and special commands and other stuff that make your day just a little bit easier. The location of the Profile script is stored in a variable itself, $Profile. To see if you have one, you can simply type:

test-path $Profile

If you want to create one, it’s easiest done by typing

new-item -itemtype file -path $profile

And you’re off!

Anyways, to the subject. I try and keep a fairly organized folder structure for all my scripts and modules, which now counts upwards of 2000(!) files. In my documents folder, I have a scripts folder, and inside it I have a folder for each language I work with. The two I work with the most are PowerShell and SQL Server scripts.

2013-04-14 23_07_23-Powershell

Inside my PowerShell folder, I have subdivided my scripts into the following:
-3rd-party scripts: Modules and scripts I download from the masters, like the WMI Explorer script which I honestly could not live without.
-Normaldev: scripts I’m working on. Anything from rough outlines and ideas to working scripts
-Moduledev: Scripts I’ve built into PowerShell modules (more mature than the ones in my “normaldev” folder)
-Utilities: Small scripts that are usually referenced by my Profile

This works for me. It gives me a fairly organized way of working with stuff from inception through finishing a module and releasing it onto servers or GitHub if it’s part of a more formal product.

This all means that whenever I fire up PowerShell, chances are good that I want to quickly navigate to that PowerShell scripts folder. Here’s a few lines of code I’ve put in my profile to make that as easy as possible:

function get-SpecialFolder { 
  param([System.Environment+SpecialFolder]$Alias) 
  [Environment]::GetFolderPath([System.Environment+SpecialFolder]$alias) 
}

$DocsFolder  = get-SpecialFolder MyDocuments
$PowerShellScriptsFolder = "$DocsFolder\Scripts\Powershell"

function GoTo-PowershellFolder
	{
		Set-Location "$DocsFolder\Scripts\Powershell"
	}
	
function GoTo-DocsFolder
	{
		Set-Location $docsfolder
	}

New-Alias -Name gtd -Value GoTo-DocsFolder
New-Alias -Name gtp -Value GoTo-PowershellFolder

Since the path to my documents folder varies from computer to computer, I’m using Windows built-in “SpecialFolder” functions go get to my documents path. From there, I can construct variables for my “Documents” path, and thereby my “PowerShell” path (which is in Documents\Scripts\PowerShell).

So, with some easy-to-remember aliases I can fire up PowerShell, and simply write

gtp

and I’m where I need to be.

Happy profiling!

formats

Windows Server 2012 NIC Teaming and Netgear Prosafe switches

Published on 13/04/2013, by in Windows.

I’m used to working with medium-sized datacenters where walls are filled with server blades and SANs and stuff I do not understand. My new job – not so much. On my first visit to the “server room” I found a pair of HP ML 350 G3 (!) servers gathering dust in a corner.

In order to support a more advanced CI process and virtualize the few production systems we have, I invested in a HP DL 380G8 server and new switches all around. We’re now on gigabit links all the way out to each workstation, and floors are connected to each other with a 2Gb link. For switches, I bought 3 Netgear GSM7224V2 switches. For our use, these work wonders at a fraction of the price of Cisco units.

Using Windows Server 2012 on the new HP server, we’re using all 4 NICs on the server in a so-called “converged fabric”.

Anyway, what I was gonna tell you anyway in this post, is that Windows Server NIC teaming in LACP mode works nicely with Netgear LAGs (Link Aggregation Groups). Simply define a LAG on the NetGear switch and add the switchports connected to your converged fabric. On the Windows Server, define a NIC Team using LACP/Address Hash, and witness a nice increase in network speed:

2013-04-13 11_02_00-TP-HV01 - Remote Desktop Connection Manager v2.2 2013-04-13 11_04_33-TP-HV01 - Remote Desktop Connection Manager v2.2

BTW; Read this blog post for more details on nic teaming.

formats

How to set up Azure Recovery Services Backup

Published on 09/04/2013, by in Windows.

I’ve been looking everywhere for correct documentation on how to set up the certificate for Azure Recovery Services backup, the artist formerly known as Windows Azure Backup.

There is a document here outlining how to generate a self-signed certificate, but it doesn not work – the produced certifice will not be accepted by Azure when you try and upload it to the portal. Among other things, the doc states that the certificate expiry date can not be more than 3 years into the future, a fact the how-to does not consider.

Anyway, here’s my “how to create a certificate for Azure Recovery Services Backup”:

1. Download the makecert tool from the Technet gallery, if you don’t already have it installed. If you’re running visual studio 2012, you can find it using the Visual Studio prompt on your start menu, uh screen.

2. Run the following command to generate the cert (all on one line). You MUST run this as admin:

makecert.exe -pe -n “CN=Azure-Recovery” -EKU “1.3.6.1.5.5.7.3.2″ -SR localmachine -SS my -R -len 2048 -m 36 Azure-Recovery.cer

3. Start MMC, add the Certificates snapin and open your computer store (not user or service)

4. Under Certificates–>Personal–>Certificates, find your newly created certificate. The expiration date should be exactly 3 years into the future

5. Right-click the cert, choose “All tasks”–>Export

6. Choose “No, don’t export the private key”

7. Format should be the first in the list, DER encoded binary X.509

8. Export to a file name of your liking

9. The produced certificate is the one you’re gonna upload to Azure Recovery Services. I actually had to try twice to get the certificate accepted.

formats

SQL Reporting Services (SSRS) PowerShell Module

Published on 06/04/2013, by in Scripting.

I’ve been working with SSRS lately to try and help our reporting dev come up with a automated deployment solution. Microsoft’s implementation of a scripting solution (rsscripter) is pretty much a joke. I have no intention of re-living those dark years of vbscript just to publish a report to a reporting services instance.

So, we came up with the idea that we’ll just use PowerShell against the reporting services webservices instead. Much better. One thing to notice: When you upload a report using the webservice, SSRS is not smart enough to link the reports datasets/datasources, even if you already have these published in SSRS. So much of the code in the module is about relinking reports and datasets after they’ve been uploaded.

I’m not getting piping from Get-SSRSItem to Remove-SSRSItem to work, so that’s work in progress. Otherwise everything seems to be working nicely. Also, since our standard reports only have one datasource, I haven’t built functionality for uploading datasources, only reports and datasets.

Some of the code comes from Randy Paulo’s excellent blog, which is well worth adding to your rss reader.

So, consider this work in progress. I hope you’ll find it useful

Downlad link:
http://hindenes.com/powershell/SQLReporting.psm1

formats

Creating Azure VM into an affinity Group using PowerShell

Published on 05/04/2013, by in Scripting.
There's a lot of examples on Azure VM Creation using PowerShell out there, but I couldn't 
find one for deploying a vm from the "Image Gallery" into an Affinity Group.
For example, if you've set up a VM Network and want to place the VM inside that network, 
you need to use Affinity Groups. Here's the script I'm using. 
All the parameters(variables, really) are required.
#Params to fill in
$VMName = "TimTest208"
$InstanceSize = "Small"
$ImageLabel = "Windows Server 2012 Datacenter, March 2013"
$VMPassword = "pass@word1"
$VMNetName = "TIM-VMNET-NE-01"
$VMSubnetName = "TIM-VMNET-NE01-SN01"

#Begin Script
$StorageAccount = (Get-AzureStorageAccount).Label
Get-AzureSubscription | Set-AzureSubscription -CurrentStorageAccount $StorageAccount
Get-AzureSubscription | Select-AzureSubscription

$AG = (Get-AzureAffinityGroup).Name
New-Azureservice -AffinityGroup $AG -ServiceName "$VMName" #This will be the service Public DNS Name created by azure
#This sometimes takes a few secs, wait-looping
    $FirstLoop = $true
    Do
        {
            if (!$FirstLoop)
                {
                    Start-Sleep -Milliseconds 500
                }
            $Cloudservice = Get-azureService | where {$_.Label -eq $VMName}
        }
    Until ($CLoudService)
$CLoudServiceName = $CLoudService.Label
$ImageName = (Get-AzureVMImage | where {$_.Label -eq $ImageLabel}).ImageName

$VM = New-AzureVMConfig -Name $VMName -InstanceSize $instanceSize -ImageName $ImageName
$VM | Add-AzureProvisioningConfig -Windows -Password $VMPassword
$VM | set-azuresubnet -SubnetNames $VMSubnetName
New-AzureVM -ServiceName "$CLoudServiceName" -VMs $VM -VNetName $vmnetname

#Uncomment the next line if you want to enable RDP on the VM's public IP
$VM | Add-AzureEndpoint -Protocol tcp -LocalPort 3389 -Name "RDP in"
$VM | Start-AzureVM
formats

Switching from Android to Microsoft

Published on 06/03/2013, by in Everyday, Windows.

New job, new devices. I decided to take the plunge and replace my Android-based smartphone and tablet with brand spanking new toys with a Windows key at the bottom.

And no – this isn’t going to be one of those 14-page rewievs of the Lumia 920, there’s already enough of those out there. I simply wanted to touch on the good and the bad when switching from Android to Windows.

So, after living in relative harmony with my Samsung S3 (which I used a lot) and my Android-based ASUS Transformer TF101 tablet (which I didn’t use that much), I’ve switched to a Windows Phone 8-based Nokia Lumia 920, and a Windows RT-powered ASUS Vivotab RT tablet.

Before I’m going any further, it’s worth pointing out that both my Samsuns S3 and my ASUS TF101 were loaded with custom ROMs to get that nice “android” feeling – I can’t believe how much crap the vendors put on top of a very good OS (Android ICS, that is). Kind of reminds me of bying a Toshiba laptop, if you know what I mean…

I chose the Lumia 920 simply because I think it’s a nice-looking phone. The ASUS tablet might be a tougher sell – why not the Surface RT? As it turns out, the ASUS Vivotab is the only Windows RT-powered tablet with a sim card slot for sale in Norway. Also, when trying the Surface RT I didn’t like the way it “felt”, especially in upright mode. My wrists actually got tired from holding the thing when reading a Kindle book. The ASUS unit feels light, has the same guts as the Surface RT and is always connected as long as I’m within 3G coverage. Nuff said.

Switching from Android to Windows Phone 8

IMG_1966

I don’t consider myself a heavy mobile phone user. Corporate email, some Facebook and a lot of Google Reader reading when waiting for someone/the bus or just killing time.

Powering up the Lumia 920 I went. “Damn. This is weird. I just have kept my S3″. However, after a few days of use, I really like the flow of the OS. The “people hub” works as prescribed and all in all it’s an effective little thing.

My android phone would constantly skip to the next song or whatever when I was out walking or moving about, because the android (so-called) lock screen is far from a lock screen – you can basically operate the entire phone without unlocking it. Not so with the Lumia 920. When the phone is locked, it’s locked. Basic volume controls and play/pause are all you get. My songs have stopped skipping on me, and I’m thankful for it.

As far as apps go - you know the story. Still some are missing. For the life of me I can’t unerstand why a good podcast manager is so hard to come by, but hopefully that will come with time. The updated twitter client works well, Microsoft’s facebook app is good enough, and all the email/calendar stuff works wonders.

Do not, however, expect to do any reading on the device after bedtime. The device does not have a rotation lock, which must be by far the biggest missing feature in Windows Phone 8. Apps rotate here and there, and sometimes they rotate midway in the app. Try and search up and install an app from the Marketplace and you’ll know what I mean. The fact that such a a beatiful screen is rendered useless after bedtime is simply beyond me.

with the exception of the lacking screen rotate, the Luma 920 is a very nice phone. After 2 days of use, I really fell in love with it. I’m putting my S3 in a drawer as we speek.

The ASUS vivotab RT

IMG_1967

I have been using Windows 8 since the betas, but I have to admit: although I love the core OS, I’m not so sold on Microsoft trying to “tabletize” my work laptops. I’ve been running various start-screen replacements such as stardock and pokki to try and get back some of the lost “Windows 7 feel” of the OS. On a tablet device though, the platform just shines. My iPad-using friends are jeleaus of the beuatiful and elegant os and the rich interaction it offers. On the tablet form-factor, I’m all in.

My only gripe was the fact that I couldn’t get gmail setup as an activesync account on my ASUS. Google is killing off their activesync support, but I’ve been under the impression that it would still work until around June 2013 or whatever. Which means that I’ll be switching my domain to outlook.com as soon as the butt-ugly hotmail-style calendar gets a facelift. In the meantime, I can live with IMAP-based gmail.

One thing worth mentioning: Windows RT doesn’t come into its own until you start using Windows 8 on your main computer, and link your local user account to a Microsoft account. The background syncing Windows 8 and RT is doing with skydrive is just terrific. Recently visited websites, saved passwords, WLAN keys - it’s a small thing but it works so effortlessly it almost feels like magic.

IE 10 on the Windows RT is by far the best browser I’ve tried on any tablet. I find it a lot smoother than Google Chrome on Android ICS, but it may not be a fair comparison since my android tablet suffers from a lot slower hardware than the ASUS Vivotab does. The fact that Flash content is only available on “approved sites” is just plain stupid.

I also got the keyboard dock for my ASUS. I love the fact that it’s adjustable. The Surface RT kickstand is nice in theory, but the angle must have been decided by a midget (or by a designer with a weird sense of humor). I could barely see the screen when I put the Surface in kickstand-mode, so the adjustability of the ASUS dock is refreshing.

To be honest, I don’t really need a tablet. I always bring one of my laptops with me when travelling anyway. Its just nice to be able to watch a movie and do some light typing without firing up the big guns. For working while flying economy, the ASUS really shines. I love the OneNote MX app especially, and have also found a Google Reader client to my taste.

Unlike the Windows Phone 8, the Windows RT acually does have a orientation lock. It does not work globally, so excpect a few apps to pop the wrong way while in bed trying to use the tablet in portrait mode. The Kindle app seems to “respect” the orientation lock though, so you’re able to read your Danielle Steel novel.

The ecosystem

I while back, I wrote a blog post on trying to stay in sync on my android devices. I’ve been living in relative peace with all my devices. I chose to use SugarSync for file syncing a long time ago, and I have not looked back. Why Dropbox is more popular than SugarSync baffles me, since I find the latter so much better. Anyhow, Microsoft kind of takes it for granted that SkyDrive is the way to sync files. Although “syncing” is not the right word, “access” would be better. Windows Phone 8 will automatically send your captured photos to SkyDrive, and both Windows Phone 8 and Windows RT has built-in apps for accessing files and photos in Skydrive. There’s nothing wrong with SkyDrive, but it’s still lacking some features I need. SugarSync is working on an app for Windows Phone 8, hopefully that lets me send my photos to my SugarSync folders instead of SkyDrive.

If there’s one thing I miss on these two mobile platforms, it’s not being unable to upload pictures of my dinner to Instagram (Lasagna, by the way). It’s the fact that there is an app missing from both platforms, and that’s a good podcast manager. Preferably one that syncs my subscriptions from one device to the other. I would be willing to pay for that.

Apart from that, I’m extremely happy with both my devices, and very excited about what’s to come. The future is Blue!

formats

New job!

Published on 06/02/2013, by in Everyday.

Darn, it’s been quiet here lately!

I have switched jobs. The last one just didn’t fit me well – there was simply too much me and my employer didn’t agree on. It’s like that sometimes, and sometimes you just have to face facts and move on.

So, I decided to try something new. After over 10 years in the world of Windows Server, Active Directory, Citrix, Exchange and PowerShell (the last couple of years), I’m now working at Timpex, a Norwegian ISV focusing on systems for the logistics and transport industry. My job here? Well, we don’t quite know yet. I will be focusing on the deployment process first, and then take it from there. I’ve been wanting to get better aquainted with wix for a long time, so that’s what I’m doing right now. I’m learning about dev stuff like MSBuild and github and rake and SSDT and what not.

It feels good to learn something completely new again, I don’t think I’ve done that since I started working with PowerShell 5 years ago.

Needless to say, this change will probably affect the topics I write about on this blog a bit. I won’t be working with Exchange 2010 or System Center on a day-to-day basis anymore. I’ll still use PowerShell a lot, so there should still be some scripting content here. Apart from that, I’m exited to discover what’s ahead!

Tags:
formats

The big Exchange Mailbox move

Published on 09/12/2012, by in Everyday, Scripting, Windows.

One of the first things I did when starting at my current employer this summer was to take a look at their hosted Exchange. I wasn’t impressed. There are too many reasons to mention here that things were as they were at that time, but that isn’t the point in this context. The point is that we decided to completely rebuild the entire thing. Easier said than done when there’s around 6500 mailboxes and lord knows how much data running. This was actually a problem – things weren’t tagged in a manner that made it easy to figure out how much disk space was spent on database replicas and how much was used on primary data. It was basically a mess.

The thing with medium to large environments, whatever they are, is to stress naming conventions (you might call them naming standards, that’s okay too). 10 years ago, naming standards were mostly for “cleanliness”. Now, as we mostly operate large environments using PowerShell, good naming conventions makes the whole scripting task a heck of a lot easier – even enjoyable at times!

With this in mind, we first spent a few weeks testing and tweaking and thinking, before we came up with the database design (we used the Exchange Sizing calculator to help us design the scale correctly):

Any database has a “primary” server where it lives in normal operation. This server serves the db using high-speed LUNs on our IBM V7000 SANs. A database will also have a “replica” server, where the same database lives on slower, older LUNs. This lets us re-use older SANs while also ensuring we’re as fault-tolerant as we need to be.

We also figured out a scheme of “brother/sister” server. A DB with server1 as the primary will have server2 as the secondary. So 01/02 make a pair, 03/04 make a pair and so on. This means that we always add new server capacity in pairs. We can now bring down all even- or odd-named servers at any time for maintenance without worrying about any database being taken offline, which makes maintenance window planning very easy.

For the DB naming convention, it looks like this:

As you can see, we haven’t fully completed the brother/sister scheme at this point, but that’s coming along.

We’ve also borrowed from the Microsoft HMC guide around storage mountpoints instead of drive letters. Each mountpoint is a folder named identically to the underlying VHDX file on the hypervisor, and the volume label is also eqal to the mountpoint. Each mountpoint can have one or more databases (most only 1), which means that we can read from the DB name which server, mountpoint and thereby VHDX file and thereby LUN/SAN any database resides on.

We’ve been able to build some simple scripts around this design, for example our Get-MountPointFreeSpace function, which lets us scan the volume a database is placed on and report on freespace, database whitespace and so on.

During the last 5 months we’ve slowly and steadily moved all customers from our old Exchange servers to our new. The old servers were physical, and have been refurbished as Windows Server 2012 Hyper-V hosts with just some added RAM. What used to be a not-so-well-designed Exchange system is now an extremely well-performing Hyper-V cluster hosting not only our Exchange server but also our entire system center stack, test environments and a bunch of other servers.

We also scaled our 2 physical cas servers out to 3 virtual ones. We dont need 3 CAS vms, but it gives us enough flexibility to take one of them offline at any time, also during peak hours, should we need to. We use a Citrix Netscaler load balancer in front of our CASes which does a tremendous job of load-balancing traffic across those CASes. We can actually take one server offline without the clients noticing at all.

There was also a half-finished Exchange 2003 termination project when I started, which we are finishing now. Exchange 2003 mailbox moves are a bit more challenging as the mailbox is actually down while it’s being moved, so there’s been a lot of late evening work monitoring those moves. If I had to do it again I’d spend more time automating the entire process, but we decided the volume of mailboxes on that platform was to low, and the error probability to high to fully automate it. We developed scripts that basically move mailboxes in 100GB chunks across each night, and that seems to work well enough.

So, that’s our Exchange. The devil is, as they say, in planning, naming conventions and details. And, to qute a colleague of mine: “I like our database new database names. It all looks so tidy!”

formats

Measuring Exchange 2010 Mailbox growth using PowerShell

Published on 28/11/2012, by in Everyday, Scripting.

During a recent mailstorm we needed to quickly get an idea of users with abnormal mailbox growth. The script below lets you list all users in a database, wait for a few minutes before listing them again, and then list them out based on the delta in the first and second measurement. It’s not advanced scripting by any means, but it’s a nice little tool for your Exchange admin toolbox, especially for large environments:

$firststats = Get-mailbox -database Database1 | get-mailboxstatistics
$secondstats = Get-mailbox -database Database1 | get-mailboxstatistics
foreach ($stat in $firststats)
    {
        $valueMB = $stat.TotalItemSize.Value.ToMB()
        $SecondStat = $secondstats | where {$_.DisplayName -eq $Stat.DisplayName}
        $secondvalueMB = $SecondStat.TotalItemSize.Value.ToMB()
        $diff = $secondvalueMB - $valueMB
        $stat | add-member -MemberType NoteProperty -Name DiffMB -Value $diff -force
    }
$firststats | select displayname, DiffMB | Sort-Object DiffMB