Use the PowerShell Best Practices Module to Configure Servers

Doctor Scripto

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using the Windows PowerShell Best Practices module to audit configuration of servers.

Microsoft Scripting Guy, Ed Wilson, is here. Well, tonight is the Charlotte Windows PowerShell user group. We are doing a mini version of the Scripting Games, and so if you are in the area, you should check it out. It is a great learning experience to see how four or five different people approach the same problem.

Exploring the Best Practices module

Today, I decided to play around with the Best Practices module on my domain controller running Windows Server 2012. To find the available cmdlets, I used the Get-Command cmdlet to look at the Best Practices module, as shown here.

PS C:\> Get-Command -Module bestpractices


CommandType     Name                                               ModuleName

———–     —-                                               ———-

Cmdlet          Get-BpaModel                                       BestPractices

Cmdlet          Get-BpaResult                                      BestPractices

Cmdlet          Invoke-BpaModel                                  BestPractices

Cmdlet          Set-BpaResult                                      BestPractices

First find the available best practice models

The first thing to do is to check for available best practice models. I do this by using the Get-BPAModel cmdlet and by not supplying anything else. This returns everything from everything as shown here.

PS C:\> Get-BpaModel

Id                     : Microsoft/Windows/ADRMS

Company                : Microsoft Corporation

Name                   : RightsManagementServices

Version                : 1.0

LastScanTime           : Never

LastScanTimeUtcOffset  :

SubModels              :

Parameters             :

ModelType              : SingleMachine

SupportedConfiguration :


Id                     : Microsoft/Windows/CertificateServices

Company                : Microsoft Corporation

Name                   : CertificateServices

Version                : 1.0

LastScanTime           : Never

LastScanTimeUtcOffset  :

SubModels              :

Parameters             :

ModelType              : SingleMachine

SupportedConfiguration : Win8


For me, a better output is to look at the ID and the LastScanTime. This is because invoking the BPAModel requires the ID and because I want to know when the last time (if ever) the Best Practices Analyzer (BPA) model ran. Here is the command and the associated results.

PS C:\> Get-BpaModel | select id, lastscantime

Id                                         LastScanTime

—                                         ————

Microsoft/Windows/ADRMS                    Never

Microsoft/Windows/CertificateServices      Never

Microsoft/Windows/DHCPServer               Never

Microsoft/Windows/DirectoryServices        11/18/2012 11:57:12 AM

Microsoft/Windows/DNSServer                Never

Microsoft/Windows/FileServices             Never

Microsoft/Windows/Hyper-V                  Never

Microsoft/Windows/LightweightDirectoryS… Never

Microsoft/Windows/NPAS                     Never

Microsoft/Windows/RemoteAccessServer       Never

Microsoft/Windows/TerminalServices         Never

Microsoft/Windows/UpdateServices           Never

Microsoft/Windows/VolumeActivation         Never

Microsoft/Windows/WebServer                Never

To focus in on one specific best practices model, use the ID from the above output. I use the Clipboard to avoid a lot of typing. As shown here, the Invoke-BPAModel cmdlet does not appear to like wild cards.

PS C:\> Invoke-BpaModel -Id *dir*

Invoke-BpaModel: There has been a Best Practice Analyzer error for Model Id ‘*dir*’. The Model is not installed.

At line:1 char:1

+ Invoke-BpaModel -Id *dir*

+ ~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : ResourceUnavailable: (:) [Invoke-BpaModel], CommandLetException

    + FullyQualifiedErrorId : ModelNotFound,Microsoft.BestPractices.Cmdlets.RunScan Command


So, I use the Clipboard to paste the real ID name of the Directory Services BPA model to the Invoke-BPAModel cmdlet. This command is shown here along with the associated output from the command.

PS C:\> Invoke-BpaModel -Id Microsoft/Windows/DirectoryServices

ModelId           : Microsoft/Windows/DirectoryServices

SubModelId        :

Success           : True

ScanTime          : 11/18/2012 12:28:33 PM

ScanTimeUtcOffset : -05:00:00

Detail            : {DC1, DC1}

Retrieving results from the best practices analyzer

To retrieve results after running the Invoke-BPAModel cmdlet, use the Get-BPAResults cmdlet. The command is shown here.

Get-BpaResult -Id Microsoft/Windows/DirectoryServices

The output is extensive and, when unfiltered, goes on for page after page. This is because the cmdlet presents lots of information about each check. The results of the command and the first two checks are shown here.

Image of command output

Well, I might not be an expert on the Best Practices Analyzer, but dude, I certainly know Windows PowerShell. So, I can fix this output easily. To do this, I first pipe the results to the Group-object and sort by the count. This way, I can get the “executive overview” and see the number of runs, hits, and errors.

PS C:\> Get-BpaResult -Id Microsoft/Windows/DirectoryServices | group severity -NoEle

ment | sort count


Count Name

—– —-

    1 Error

    8 Warning

   34 Information

Hey, that is not too bad at all. I guess I will look at the Error first. I filter it out by using the WhereObject cmdlet. Because I am using Windows Server 2012, I have access to Windows PowerShell 3.0 and, therefore, to the new Where-Object syntax. Here is the command I use.

Get-BpaResult -Id Microsoft/Windows/DirectoryServices | where severity -eq error

Even the output from this one error is extensive. It appears (just a bit cut off) in the following figure.

Image of command output

After looking over the output, I decide I am only interested in the Title, Impact, and Resolution properties. The cleaned up output is shown here.

Image of command output

From my previous command, where I grouped the results by severity, I saw there were eight warnings. I now want to examine them. I use the up arrow, and change error to warning, as shown here.

Get-BpaResult -Id Microsoft/Windows/DirectoryServices | where severity -eq warning | fl title, impact, Resolution

It might also be interesting to see the results by category. The following command shows that most of my results are configuration-related.

PS C:\> Get-BpaResult -Id Microsoft/Windows/DirectoryServices | group category -NoElement

Count Name

—– —-

   42 Configuration

    1 Operation

If I am curious as to which report is related to operations, I use the following command.

Get-BpaResult -Id Microsoft/Windows/DirectoryServices | where category -eq ‘operation’

To get a general overview of the warnings I have, I use the following command.

Get-BpaResult -Id Microsoft/Windows/DirectoryServices | where severity -eq warning | fl title

The command and resulting list of warnings are shown in the following image.

Image of command output

OK, it seems that a lot of the warnings are because I do not have a backup. How about if I filter out the “backup noise” and see what is left. Here is the command I use.

PS C:\> Get-BpaResult -Id Microsoft/Windows/DirectoryServices | ? { $_.title -notmatch ‘backed up’ -AND $_.severity -eq ‘warning’} | select title



All domains should have at least two domain controllers for redundancy

All OUs in this domain should be protected from accidental deletion

The domain controller dc1.nwtraders.msft should comply with the recommended best …

 There is more stuff related to the BPA module, and you can even download updated and additional BPA models. That is about it for now. Join me tomorrow when I will talk about more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


Discussion is closed.

Feedback usabilla icon