Invoke Best Practices Analyzer on remote servers using PowerShell

Best Practices Analyzer (BPA) is a management tool integrated in Windows Server 2008 R2 used to scan server roles according to Microsoft best practice guidelines.

Included in the initial release for Windows Server 2008 R2 are the following BPA models:

  • Active Directory Domain Services
  • Active Directory Certificate Services
  • Domain Name System (DNS) Server
  • Remote Desktop Services
  • Web Server (IIS)

Since then several new BPA models are released and available both as separate downloads as well as through Windows Update:

At the time of this writing, a BPA model for 12 of 17 server roles in Windows Server 2008 R2 are available.
The 5 that are not available are:

  • Active Directory Federation Services (ADFS)
  • Active Directory Lightweight Directory Services (AD LDS)
  • Fax Server
  • Print and Document Services
  • Windows Deployment Services

In Server Manager, a BPA summary are available for each installed server role that an BPA Model exists for:


When looking at the properties for an item in BPA you get more information as well as a link to Microsoft TechNet where more information are available for the specific subject:


BPA are built as a PowerShell module, meaning that a PowerShell cmdlet (Invoke-BPAModel) are run in the background when you scan a server role from Server Manager:


This is a great feature to examine if your server roles are configured according to Microsofts best practices, however, if you got many servers it will take some time to log on to each server and scan each server role. In addition you dont get any centralized reporting this way.

Since BPA are based upon Windows PowerShell its possible to solve this using the BPA PowerShell module and PowerShell remoting:



Ive created a sample script to accomplish this, named Invoke-BPAModeling, with the following functionality:

  • Invoke BPA for all available server roles on specified remote servers
  • E-mail reporting
  • File reporting to CSV and HTML

You need to customize the initial variables on the top of the script. You can enable/disable reporting using these variables, as well as specify which servers to work against, SMTP server for e-mail reporting and paths to CSV/HTML reports.
By default, only items with a severity of “Error” and “Warning” are reported. You can change this to also include “Informational” severities by configuring IncludeAllSeverities to true.
On the server running the script from, the Active Directory module for PowerShell must be installed if you want to retrieve computer names from Active Directory. In the sample,  the script are configured to retrieve all computer accounts listed with Windows Server 2008 R2 as operating system.
You might choose alternate methods, like importing the computer names from a csv-file.
I would recommend that you approve the new BPA models mentioned at the beginning of this blog post in WSUS prior to running the script.
The script requires that PowerShell remoting are enabled and configured on the remote servers. Also note that there is a known issue with the BPA module; When the PowerShell execution policy are set to any other than “Undefined” or “Unrestricted” , an error occurs. I`ll update this blog-post as soon as a fix are provided from Microsoft.

When the script executes, it displays the progress based upon the total number of computers running against:


Sample e-mail report containing both CSV and HTML reports as attachment:


Sample HTML-report:


Sample CSV-report converted to an Excel spreadsheet:


Feel free to customize the script for your needs, as well as suggest improvements.


Best Practices Analyzer on Microsoft TechNet

Automate Active Directory Migration Tool using Windows PowerShell

Active Directory Migration Tool (ADMT) provides the ability to restructure Active Directory domain structures. It allows you to migrate users, groups and computers between domains, both intra-forest and inter-forest. Features includes password migration, SID migration and security translation among several others.
ADMT was recently released in version 3.2, adding support for Windows Server 2008 R2 and Managed Service Accounts. You can find the download here, and the ADMT migration guide here.

ADMT provides three options on how to use it, where the first and maybe most used is the GUI:


Its wizard driven and pretty straightforward to use.
The second option is the admt.exe command line utility:


In my opinion this is a pretty good example on how inconsistent various command line tools are compared to PowerShell. Although ADMT is a great tool, hopefully the next version will be rebuilt based on PowerShell.

The third option is scripting. There is a COM-object called ADMT.Migration, and there is a sample VB-script (templatescript.vbs) in the ADMT installation directory (by default C:WindowsADMT). This sample script is a good place to start to explore how the COM-object works.

Based on this Ive written a sample PowerShell script, Invoke-ADMTUserMigration, to migrate user accounts and passwords using Windows PowerShell. This script uses the “ADMTDomain” option, which means that all users from the source OU will be migrated to the target OU. To see other available options, see the ADMT documentation and the sample VBScript. Migrating other objects, like groups and computers, the same way should be pretty easy when comparing Invoke-ADMTUserMigration to templatescript.vbs.

Note that since ADMT is a 32-bit application the script must be run from an x86 instance of Windows PowerShell. It also requires elevated privileges (Run as Administrator). Trying to run it in an x64-bit PowerShell instance or without elevated privileges will result in the following error:
New-Object : Retrieving the COM class factory for component with CLSID {285029CC-5048-4D90-8B38-22D304F513DC} failed du
e to the following error: 80040154.

Before trying to run the script I would recommend that you read the ADMT migration guide and ensures that migration works as expected by running a few test migrations from the GUI.

When this is done, I also would recommend to split the migration in batches as recommended in the migration guide. A maximum of 100 objects at a time might be appropriate. Before moving on to the next batch, check the migration logs (by default in C:WindowsADMTLogs) to see that everything went OK before proceeding.

To take this a step further, Ive created a function, Migrate-ADMTUser, that migrates a single user object. This would allow you to easily do things like this:
Get-ADUser -Filter {Company -like "Oslo"} | Migrate-ADMTUser

This example combines the Active Directory module for PowerShell with ADMT, allowing us to more fine grained control on what objects to migrate.
Note that both the sample script and sample function I
ve created is meant as a guidance on how to use PowerShell to automate ADMT. The optimal way as I see it would be creating an ADMT PowerShell module with functions for migrate other objects like computers and groups in addition to users and passwords.


ADMT 3.2: Common Installation Issues

ADMT Guide: Migrating and Restructuring Active Directory Domains (TechNet-version)