Anything for sysadmins!


Dell warranty information API

I've always used the SOAP API that's provided by Dell, however recently it stopped working due to a misconfiguration in the service. This triggered me to find a different solution and luckily Dell also provides a REST API that is even simpler, gives more detailed information and actually still works.

There are 3 APIs available at the moment, but I will only dig into the warranty status as that is the most useful.

Functional specification of the warranty status API:

Function Global:Get-DellAssetInformation {
    Param([String]$ServiceTag = $(Get-WmiObject -Class "Win32_Bios").SerialNumber)
    Try {
        # Possible API keys
        # 1adecee8a60444738f280aad1cd87d0e
        # d676cf6e1e0ceb8fd14e8cb69acd812d
        # 849e027f476027a394edd656eaef4842
        $APIKey = "1adecee8a60444738f280aad1cd87d0e"
        $DellURL = "$ServiceTag&apikey=$APIKey"

        $XML = New-Object System.Xml.XmlDocument
    Catch {
        Write-Host $($_.Exception.Message)

Once you run this bit of code you can use the following to get the detailed information.

To get the information for the local machine use:


To get the information for a different ServiceTag use the following:

Get-DellAssetInformation -ServiceTag AB12AB1

If you have questions or comments, please post it below!

More information:

Filed under: Powershell 6 Comments

Mailbox size overview for Exchange 2010

Once every now and then you'll want an overview of what the mailbox sizes are for your organization. You can then see who is using the most space and perhaps offer them some help archiving their mailbox. However Exchange 2010 doesn't really offer this in a organized way. This is exactly the reason why I created this one-liner. This will output to a GridView or to a CSV which you can then use to organize the data as you wish.

Get-MailboxDatabase | % { Get-MailboxStatistics -Database $_.Name | Select DisplayName, @{Name="Size (MB)";Expression={($_.TotalItemSize).Substring($a.IndexOf("(")).Replace("(","").Replace(" bytes)","").Replace(",","") / 1MB}} }

You could output it to GridView by piping it to


Get-MailboxDatabase | % { Get-MailboxStatistics -Database $_.Name | Select DisplayName, @{Name="Size (MB)";Expression={($_.TotalItemSize).Substring($a.IndexOf("(")).Replace("(","").Replace(" bytes)","").Replace(",","") / 1MB}} } | Out-GridView

Or export it to a CSV by piping it to



 Get-MailboxDatabase | % { Get-MailboxStatistics -Database $_.Name | Select DisplayName, @{Name="Size (MB)";Expression={($_.TotalItemSize).Substring($a.IndexOf("(")).Replace("(","").Replace(" bytes)","").Replace(",","") / 1MB}} } | Export-Csv C:\MailboxSizes.csv

As a result you can open the CSV in Excel, add some Conditional Formatting and Column Formating and voila! Yes, these are the actual mailbox sizes!


Scheduling the Update-SPProfilePhotoStore command

When you setup your SharePoint 2010 User Profile Service to import the user's pictures from Active Directory you will have to run the Update-SPProfilePhotoStore command. Of course you don't want to do this manually every time so you'll need to schedule it on the SharePoint servers in your farm.

The best place to schedule this is on the Central Administration server.

  1. Open the Task Scheduler and click Create Task…
  2. Enter a name and select an account with enough permissions, in my case the SharePoint Farm account and check Run whether user is logged on or not
  3. Click the Triggers tab and click New. Select a schedule that makes sense to you. I'm sticking to my User Profiles Service Synchronization task schedule.
  4. Click the Actions tab and click New.
    In the Add
    arguments box enter:

    -NonInteractive -NoProfile -Command "& {Add-PSSnapin Microsoft.SharePoint.PowerShell;Update-SPProfilePhotoStore -MySiteHostLocation https://<MysiteHostLocation> -CreateThumbnailsForImportedPhotos 1}"

  5. Click OK and enter the required password

This should start the task every hour and import the Active Directory image right into the User Profile Service which also resizes the images in 3 formats.


Mailbox Import/Export Exchange cmdlets unavailable

The <verb>-MailboxExportRequest and <verb>-MailboxImportRequest cmdlets have been introduced in Exchange 2010 SP1 to simplify the export of messages directly into a PST file from PowerShell. The previous requirement to have Outlook and some other software installed on the exporting computer have been dropped and the whole export process has been moved to the Mailbox Replication Service (MRS). A small disadvantage is that the cmdlets are not available by default as you'll first need to define the proper permission to your role group.

I can write in detail how to add these permissions, but Microsoft has done this quite well already in this technet article: Add the Mailbox Import Export Role to a Role Group

This command will get you started:

New-ManagementRoleAssignment -Name "Import Export_Enterprise Support" -SecurityGroup "Enterprise Support" -Role "Mailbox Import Export"


Unable to open PST file with mailbox import/export requests

I was trying to an export of a mailbox using the New-MailboxExportRequest CMDlet in Exchange 2010 SP1. However instead of creating a PST it gave me an error.

Unable to open PST file '\\Server\Exports\Test.pst'. Error details: Access to the path '\\ExServer1\Imports\Test1.pst' is denied.;

Microsoft.Exchange.MailboxReplicationService.RemotePermanentException: Access to the path '\\Server\Exports\Test.pst' is denied.

I was soon pointed into the right direction by a blog post by Tony Redmond. He indicated that because the Mailbox Replication Server (MRS) is running as LocalSystem it can't access a network share. By adding the Exchange Trusted Subsystem group to the share permissions you will give the LocalSystem account and therefore MRS access to the share.


Database Maintenance in Exchange 2010 – Online Defragmentation, Monitoring, Whitespace

Online Defragmentation/Monitoring

With the coming of Exchange 2010 the database maintenance has been simplified a lot. No more worries about online maintenance windows overlapping with the database backups. The reason for this is that the online defragmentation has been moved out of the mailbox database maintenance process. The online defragmentation is now running in the background all the time.

This option is enabled by default and no further settings are required. You can monitor the database defragmentation with the performance monitor by adding a couple of performance counters.

  • MSExchange Database ==> Instances \ Defragmentation tasks        Shows the background database defragmentation tasks currently executing.
  • MSExchange Database ==> Defragmentation Tasks completed/Sec    Shows the number of background database defragmentation tasks completing execution per second.
  • MSExchange Database ==> Defragmentation Tasks Discarded        Shows the background database defragmentation tasks that couldn't be registered.
  • MSExchange Database ==> Defragmentation Tasks Pending        Shows the background database defragmentation tasks currently pending.
  • MSExchange Database ==> Instances \ Defragmentation        Tasks Scheduled/Sec Shows the background database defragmentation tasks scheduled for execution per second.

The performance counters are solely to check performance and are not required to be part of the daily maintenance of the database.

It's also possible to enable extended Extensible Storage Engine (ESE) performance counters, but to enable these counters you'll have to change a setting in the registry.


If you want to track the whitespace in your Exchange 2010 database you can use the following EMC command:

Get-MailboxDatabase -Status | Select-Object Name,AvailableNewMailboxSpace

The returned amount is however only the space available in the ESE B+-tree structure.

Older versions of Exchange generate an event with ID 1221 to show the whitespace. Exchange 2010 generates a similar event only for the mail queue database with event ID 7007.

During my search for information about whitespace I came across an interesting script by Mike Pfeiffer that generates quite some useful data about the mailbox database.

 Function Get-DatabaseStatistics {
</p><p>    $Databases = Get-MailboxDatabase -Status
</p><p>    ForEach($Database in $Databases) {
</p><p>        $DBSize = $Database.DatabaseSize
</p><p>        $MBCount = (Get-Mailbox -Database $Database.Name).Count
</p><p>        $MBAvg = $DBSize.ToBytes() / $MBCount            
</p><p>        New-Object PSObject -Property @{
</p><p>            Server = $Database.Server.Name
</p><p>            DatabaseName = $Database.Name
</p><p>            LastFullBackup = $Database.LastFullBackup
</p><p>            MailboxCount = $MBCount
</p><p>            "DatabaseSize (GB)" = "{0:n2}" -f ($DBSize.ToBytes() / 1GB)
</p><p>            "AverageMailboxSize (MB)" = "{0:n2}" -f ($MBAvg / 1MB)
</p><p>            "WhiteSpace (MB)" = "{0:n2}" -f ($Database.AvailableNewMailboxSpace.ToBytes() / 1MB)
</p><p>        }
</p><p>    }

After running this script in the EMC you can execute the script by running Get-DatabaseStatistics. The output should be similar to the image below.


Creating a new list in SharePoint 2010 using PowerShell

One of the best new features of SharePoint 2010 is the ability to manage most aspects of SharePoint with PowerShell. A good example of this is creating new lists on sites.

To create a new list you'll first have to figure out how to tell SharePoint which template to use. Here's how you can show all template possibilities:

 $SPAssignment = Start-SPAssignment
</p><p>$SPWeb = Get-SPWeb http://localhost -AssignmentCollection $spAssignment
</p><p>$SPWeb.ListTemplates | Select Name, Description

You can use any of the templates returned on that site. To create a list you can use the Add() method:

 $SPTemplate = $SPWeb.ListTemplates["Custom List"]
</p><p>$SPWeb.Lists.Add("List Title","Description",$SPTemplate)

If you want to perform a different action on a list please use

$SPWeb.Lists | Get-Member

to find out what command to use.

To dispose of all the objects that have been called, just run

Stop-SPAssignment $SPAssignment


Pausing PowerShell

Ever wondered how to use the pause function of DOS in PowerShell. Look no more. Here's the script to do this:

[Powershell]Write-Host "Press any key to continue ..."

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")[/PowerShell]

More info here:


Full failover with two Exchange 2010 Servers

Every sysadmin runs into the problem at some time; switching to a newer version of Exchange. Hopefully most of you can migrate to Exchange 2010 within the forest. However sometimes it just makes more sense to setup a new forest with the new version of Exchange, SharePoint, etc. In my case it makes more sense. It takes a lot more work, but in the process I'm able to update all the servers to Windows Server 2008 R2 as well. Having all the servers on the same version of Windows saves me time on management. I'm getting side-tracked! Let's get back to Exchange and the problem at hand: DAG Failover with two Exchange 2010 Servers.

If you haven't read up on the functioning/existence of Database Availability Groups (DAG) and CAS failover of Exchange 2010, you'll probably think that it's a breeze. However that's not the case. The new failover isn't really build on a two server setup. DAG uses Windows' Failover Clustering to provide failover on the Mailbox Database level. This work really well, but comes with one huge disadvantage. Failover Clustering is not compatible with Network Load Balancing (NLB) and NLB is used for failover of the Client Access Server (CAS) role. As an alternative one could use a hardware or software load balancer that load balances TCP/IP traffic, but those don't come cheap, which doesn't really make sense for the smaller shops. But a solution is near!

The solution

After a lot of thinking, discussing and experimenting I came up with a solution. While using the standard Windows Failover Clustering for DAG I can use the Client Access Server Array (


) without NLB for failover of the CAS role. However instead of having NLB switching the active server I'll have to script which server is active. My current default answer for scripting and automation applies here: "Let's PowerShell it!".

First I tried to change the RpcClientAccessServer directly, but that didn't have the right effect. A colleague suggested to use the CAS array and just activate the CAS array IP on the active server. This made a lot of sense as NLB does something similar. So let's go through the steps!

  1. Create a CAS array
    [Powershell]New-ClientAccessArray -Fqdn "name.domain.local" -Site "AD-Site-Name"[/Powershell]
  2. Create the A record in DNS for your newly created CAS array and have it point to an available IP that can be used by both Exchange servers.
  3. Add the CAS array IP on one of the available network adapters of the active server by using the command
    [Powershell]netsh in ip add address "Adapter Name"[/Powershell]

You're not done yet! You can connect an Outlook client to a mailbox. AutoDiscover should now use the CAS array DNS as the connection point. You can check the connection point by right-clicking the Outlook taskbar icon while holding the CTRL button and selecting Connection Status.

If you don't see the right hostname in the server name field, you should check the results of the AutoDiscover. You can use the option Test E-mail AutoConfiguration in the CTRL + right-click menu of Outlook or you can use the website to test you AutoDiscover results. You can use this site to test almost any aspect of your Exchange connectivity. You should get something like the following as a result.

&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;Autodiscover xmlns=""&gt;
&lt;Response xmlns=""&gt;


&lt;Server&gt;<span style="background-color: silver;">exchange.domain.local</span>&lt;/Server&gt;
&lt;ServerDN&gt;/o=&lt;domain netbios&gt;/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration/cn=Servers/cn=<span style="background-color: silver;">exchange.domain.local</span>&lt;/ServerDN&gt;
&lt;MdbDN&gt;/o=&lt;domain netbios&gt;/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration/cn=Servers/cn=<span style="background-color: silver;">exchange.domain.local</span>/cn=Microsoft Private MDB&lt;/MdbDN&gt;


The magic script

Time to implement the PowerShell script. The script will take care of the CAS failover by activating the IP on one of the Exchange 2010 servers. The script uses ping to make sure that the other host is still reachable. I've scripted it to check if it can ping the gateway before doing a CAS failover just to make sure that it's not a network-wide issue. It will also check the database copy status (Get-DatabaseCopyStatus) to make sure that the mailbox database has also done its failover to the host running the script.

There are a couple of variables that you need to set in the script before you can run it properly. There should be enough comments in the script to figure it out, otherwise just leave a comment and I'll be sure to answer! You might also want to change the text of the e-mail that is being send in case of failover.

You can download the script here!

There are a couple of settings that you have to edit in the script to customize it for your environment and preferences. I won't go into this any further as it's quite well explained in the script itself. If you do have questions please comment on this post and I'll get back to you as soon as I can.

$Limit = "10" # Ping fails before failover attempt
$Gateway = "&lt;hostname/IP&gt;" # Gateway of this server
$Hostname = "&lt;hostname/IP&gt;" # Hostname of the other Exchange Server
$LocalHostname = "&lt;hostname/IP&gt;" # Hostname of the local Exchange server
$MailTo = "Name &lt;;" # E-mail address where the failover e-mails will be send to
$MailFrom = "Name &lt;;" # E-mail address shown in the from field
$IP = "&lt;IP&gt;" # Failover IP address that will be added to the server (IP of ClientAccessArray FQDN)

Creating the script account

Create a new domain user and add it to the View-Only Organization Management role using the Exchange Control Panel (ECP). You can access the ECP by going to https://<servername>/ecp/. This however doesn't provide it with permissions to allow remote PowerShell. You can grant the permissions by running

Set-User FailMon -RemotePowerShellEnabled $True on the Exchange Management Shell (EMS).

<img alt="" src="" />

Also add the domain user to the local administrators group to give it the appropriate permissions to run the task on the right level.
<h3>Scheduling the script</h3>
To have the task start, you can use the task scheduler. The script can be fired as much as you like, as it will only spawn one instance.

powershell.exe -command "&amp;{C:\Scripts\FailoverMon.ps1}"

Make sure that, while creating the scheduled task, you select an account with the appropriate permissions on your Exchange organization.

I've set my task to trigger (as shown) on startup with a repeat of every 10 minutes.

If you want to know more on how to schedule a PowerShell script, please check here.


When the tasks are scheduled and running on both the servers you can try a failover by shutting down the server which currently has the CAS array IP address. You should see it failover with the DAG and you should also see that the IP address is added to the other server. The client will get a notification on Outlook that the administrator made changes to the configuration and that Outlook need to restart to work properly.


Failback is still a manual process if you want to failback to the previous server. To do so, you'll have to make sure that the previous server is configured with the CAS array IP address and that the DAG indicates that it's healthy. Then it's just a matter of manually removing the CAS array IP address on the server that doesn't need it anymore. Then it'll automatically detect that it's switched servers and the above dialog is again presented to the client. You can use the following command to remove the IP address from the server.

[Powershell]netsh in ip delete address "Adapter Name"[/Powershell]

Edit: Please note that this setup is not supported by Microsoft.
If you still have questions or when it just doesn't work for you, please let me know by commenting on this post.

Update: The script is available again through this link.


Scheduling PowerShell scripts

Most of the management tasks for desktops and server systems can be done by using PowerShell. However, some of these tasks have to be scheduled on certain events or times. This isn't as straight forward as you might think because you can't just call the script directly. The way described below works for me all the time.

  1. Start Task Scheduler
  2. Select Task Scheduler Library and right-click it
  3. Select Create Task
  4. Define your security options and triggers
  5. On the Actions tab click the New button
  6. You can leave the Action as it is. In the Program/script field enter: powershell.exe
    In the Add arguments field enter: -command "&"{<full path to script }""
    In the Start in field you can enter anything you would like or leave it empty

You can test run the task by right-clicking it and selecting Run. The column Last Run Result will show the outcome.