On Windows PowerShell and other admin-related topics

Use Windows PowerShell to get antivirus product information

Windows Security Center has been available in Windows client operating systems since Windows XP SP2. This is a useful feature for monitoring the overall for security status for the system, including antivirus, antimalware and firewall protection. In situations no monitoring software like System Center Operations Manager is in place to monitor the security health on client computers, one option is to use Windows Management Instrumentation. There is a WMI namespace called root\SecurityCenter2 which exposes information from the Windows Security Center, like what antivirus product is installed on the system.

I`ve created PowerShell function to query computers for information on what antivirus is installed as well as the current status for antivirus definitions and real-time protection:

function Get-AntiVirusProduct {
param (
[parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)

$AntiVirusProduct = Get-WmiObject -Namespace root\SecurityCenter2 -Class AntiVirusProduct  -ComputerName $computername

#Switch to determine the status of antivirus definitions and real-time protection.
#The values in this switch-statement are retrieved from the following website:

switch ($AntiVirusProduct.productState) {
"262144" {$defstatus = "Up to date" ;$rtstatus = "Disabled"
"262160" {$defstatus = "Out of date" ;$rtstatus = "Disabled"
"266240" {$defstatus = "Up to date" ;$rtstatus = "Enabled"
"266256" {$defstatus = "Out of date" ;$rtstatus = "Enabled"
"393216" {$defstatus = "Up to date" ;$rtstatus = "Disabled"
"393232" {$defstatus = "Out of date" ;$rtstatus = "Disabled"
"393488" {$defstatus = "Out of date" ;$rtstatus = "Disabled"
"397312" {$defstatus = "Up to date" ;$rtstatus = "Enabled"
"397328" {$defstatus = "Out of date" ;$rtstatus = "Enabled"
"397584" {$defstatus = "Out of date" ;$rtstatus = "Enabled"}
default {$defstatus = "Unknown" ;$rtstatus = "Unknown"

#Create hash-table for each computer
$ht = @{}
$ht.Computername = 
.Name = $AntiVirusProduct.displayName
$ht.ProductExecutable = $AntiVirusProduct.pathToSignedProductExe
$ht.‘Definition Status’ = 
.‘Real-time Protection Status’ = $rtstatus

#Create a new object for each computer
New-Object -TypeName PSObject -Property $ht



Sample output:


The root\SecurityCenter2 namespace isn`t documented on MSDN, so it`s hard to find information on the properties and methods we find in the different classes in the namespace.

The productstate property of the AntiVirusProduct class is exposed as a integer value, which needs to be converted to a hexadecimal value. Then the different bytes in the value contains information in regards to definition updates and real-time protection. More information on this is available here. I haven`t found a complete reference to all possible values, the best I could find is available here.

The above function outputs Windows PowerShell objects, so it`s possible to filter the output i.e. based on the “Definition Status” property.  The computername parameter also supports value from pipeline to make it easy to get the computers to query from i.e. Active Directory without using a foreach construct. A few examples:

#Get antivirus product information for all computers in the specified OU/container
Import-Module ActiveDirectory
Get-ADComputer -SearchBase "CN=Computers,DC=contoso,DC=local" -Filter * | Select-Object -ExpandProperty name | Get-AntiVirusProduct

#Filter using Where-Object to get all computers where the Definition State is not "Up to date"
Get-AntiVirusProduct -computer (Get-Content computers.txt) | Where-Object {$_.‘Definition Status’ -notlike ‘Up to date’}


The root\SecurityCenter2 namespace is available on Windows Vista SP1 and above. Windows Security Center is not available on server operatingsystems, meaning that the root\SecurityCenter2 namespace also isn`t available. In Windows XP SP2 the namespace is called root\SecurityCenter, but the properties are not the same as in root\SecurityCenter2. It`s possible to get the function work on Windows XP, but you would need to customize it to match the properties available in the root\SecurityCenter namespace.

I would encourage you to add error handling before using this function in a production environment, i.e. adding a test to check if the remote computer is available and allowing RPC-communication. If you would like to explore the other classes in the root\SecurityCenter2 namespace for working with firewall and antispyware products, you can start by exploring the available classes like this: Get-WmiObject -Namespace root\SecurityCenter2 -List

June 12, 2011 Posted by | Desktop management, Scripting, Windows 7, Windows PowerShell, Windows Vista | , | Leave a comment

Export and import WLAN profiles

Network Shell (Netsh) is a command-line utility that makes it possible to work with various server roles and operating system components in Windows, and have been available since Windows 2000. It`s commonly used to change network interface information such as IP-addresses, as well as for resetting the TCP/IP stack. For a complete overview of the capabilities of netsh, have a look at the Netsh Command Reference on Microsoft TechNet.

Starting with Windows Vista/Windows Server 2008, netsh provides commands for Wireless Local Area Networks (WLAN). This makes it possible to import and export WLAN profiles, which can be useful when re-installing your computer or maybe when deploying corporate computers where WPA Enterprise is not used.

In combination with Windows PowerShell it`s easy to import and export WLAN profiles using netsh. I`ve provided a script containing two PowerShell functions:

  • Export-WLAN
  • Import-WLAN

Click on the thumbnails to see help info for the functions:

image image

The script is available here.

Note that Windows Vista/7 has a concept of all-user and per-user WLAN profiles:


All-user profiles is the default, and the functions are not customized to work with per-user functions.

January 23, 2011 Posted by | Desktop management, Windows 7, Windows PowerShell, Windows Vista | | Leave a comment

Export BitLocker-information using Windows PowerShell


Active Directory can be used to store both Windows BitLocker Drive Encryption recovery information and Trusted Platform Module (TPM) owner information.

On the Microsoft Windows Support site, the following information are provided:

Storage of BitLocker Recovery Information in Active Directory

BitLocker recovery information is stored in a child object of a computer object in Active Directory. That is, the computer object is the container for the BitLocker recovery object.

More than one BitLocker recovery object can exist for each computer object, because there can be more than one recovery password associated with a BitLocker-enabled volume.

Each BitLocker recovery object on a BitLocker-enabled volume has a unique name and contains a globally unique identifier (GUID) for the recovery password.

The name of the BitLocker recovery object is limited to 64 characters because of Active Directory constraints. This name incorporates the recovery password GUID as well as date and time information. The form is:

<Object Creation Date and Time><Recovery Password GUID>

For example:


The Active Directory common name (cn) for the BitLocker recovery object is ms-FVE-RecoveryInformation and includes attributes such as ms-FVE-RecoveryPassword and ms-FVE-RecoveryGuid.

Storage of TPM Recovery Information in Active Directory

There is only one TPM owner password per computer; therefore the hash of the TPM owner password is stored as an attribute of the computer object in Active Directory. It is stored in Unicode. The attribute has the common name (cn) of ms-TPM-OwnerInformation.

Active Directory Requirements

In order to store BitLocker and TPM information in Active Directory, all domain controllers must run Windows Server 2003 with Service Pack 1 or later. Schema extensions will also need to be installed on servers running Windows Server 2003.


To see if a computer has stored any BitLocker Recovery information in Active Directory, you must install the BitLocker Recovery Password Viewer and check the BitLocker Recovery tab on the computer object to see if a Recovery Password are present:


Doing this for every computer manually isn`t an option in a domain environment. To ease this task I`ve written a PowerShell-script, available here, that will generate a CSV-file containing all Windows Vista and Windows 7 computer objects in the domain. The CSV-file will contain the following information:

  • Computername
  • OperatingSystem
  • HasBitlockerRecoveryKey
  • HasTPM-OwnerInformation

I haven`t found a way to retrieve ms-FVE-RecoveryInformation objects or msTPM-OwnerInformation information on computer objects using Microsoft`s PowerShell-module for Active Directory. Because of that I`ve leveraged Quest`s free PowerShell Commands for Active Directory.

To retrieve correct information, you must run the script with a user that has been granted the following permission: Read-permission on msFVE-RecoveryInformation objects and Read-permissions on msTPM-OwnerInformation on computer-objects (e.g. Domain Admins).

When the CSV-file is generated, you can use the “Text to columns”-feature in Microsoft Office Excel and save the document as an Excel spreadsheet. Then you can apply filters to sort on e.g. HasBitlockerRecoveryKey or HasTPM-OwnerInformation.

If you`re using the BitLocker feature on other operatingsystems than Windows Vista or Windows 7, i.e. Windows Server 2008 or Windows Server 2008 R2, you may customize the filtering in the computers-variable.


BitLocker resources on Microsoft TechNet

BitLocker Drive Encryption

BitLocker Drive Encryption Overview

Backing Up BitLocker and TPM Recovery Information to Active Directory

October 24, 2010 Posted by | BitLocker, Scripting, Windows 7, Windows PowerShell, Windows Vista | | 13 Comments

Enable and configure Windows PowerShell Remoting using Group Policy

As you may know, Windows PowerShell 2.0 introduced a new remoting feature, allowing for remote management of computers.

While this feature can be enabled manually (or scripted) with the PowerShell 2.0 cmdlet Enable-PSRemoting, I would recommend using Group Policy whenever possible. This guide will show you how this can be accomplished for Windows Vista, Windows Server 2008 and above. For Windows XP and Windows Server 2003, running Enable-PSRemoting in a PowerShell startup script would be the best approach.

Windows PowerShell 2.0 and WinRM 2.0 shipped with Windows 7 and Windows Server 2008 R2. To take advantage of Windows PowerShell Remoting, both of these are required on the downlevel operating systems Windows XP, Windows Server 2003, Windows Vista and Windows Server 2008. Both Windows PowerShell 2.0 and WinRM 2.0 are available for download here, as part of the Windows Management Framework (Windows PowerShell 2.0, WinRM 2.0, and BITS 4.0). To deploy this update to downlevel operating systems I would recommend to use WSUS, which are described in detail in this blog post by Kurt Roggen.

Group Policy Configuration

Open the Group Policy Management Console from a domain-joined Windows 7 or Windows Server 2008 R2 computer.

Create or use an existing Group Policy Object, open it, and navigate to Computer Configuration->Policies->Administrative templates->Windows Components

Here you will find the available Group Policy settings for Windows PowerShell, WinRM and Windows Remote Shell:


To enable PowerShell Remoting, the only setting we need to configure are found under “WinRM Service”, named “Allow automatic configuration of listeners”:


Enable this policy, and configure the IPv4 and IPv6 addresses to listen on. To configure WinRM to listen on all addresses, simply use *.

In addition, the WinRM service are by default not started on Windows client operating systems. To configure the WinRM service to start automatically, navigate to Computer Configuration\Policies\Windows Settings\Security Settings\System Services\Windows Remote Management, doubleclick on Windows Remote Management and configure the service startup mode to “Automatic”:

No other settings need to be configured, however, I`ve provided screenshots of the other settings so you can see what`s available:





There is one more thing to configure though; the Windows Firewall.

You need to create a new Inbound Rule under Computer Configuration->Policies->Windows Settings->Windows Firewall with Advanced Security->Windows Firewall with Advanced Security->Inbound Rules:


The WinRM port numbers are predefined as “Windows Remote Management”:


With WinRM 2.0, the default http listener port changed from TCP 80 to TCP 5985. The old port number are a part of the predefined scope for compatibility reasons, and may be excluded if you don`t have any legacy WinRM 1.1 listeners.



When the rule are created, you may choose to make further restrictions, i.e. to only allow the IP addresses of your management subnet, or perhaps some specific user groups:


Now that the firewall rule are configured, we are done with the minimal configuration to enable PowerShell Remoting using Group Policy.


On a computer affected by the newly configured Group Policy Object, run gpupdate and see if the settings were applied:


As you can see, the listener indicates “Source*”GPO”, meaning it was configured from a Group Policy Object.

When the GPO have been applied to all the affected computers you are ready to test the configuration.

Here is a sample usage of PowerShell Remoting combined with the Active Directory-module for Windows PowerShell:


The example are saving all computer objects in the Domain Controller Organization Unit in a variable. Then, a foreach-loop are invoking a scriptblock, returning the status of the Netlogon-service on all of the Domain Controllers.


We`ve now had a look on how to enable and configure PowerShell Remoting using Group Policy.
There are an incredible number of opportunities opening up with the new Remoting feature in Windows PowerShell 2.0. For a complete walkthrough on how you can use this new feature, I would like to recommend the excellent Administrator’s Guide to Windows PowerShell Remoting written by Dr. Tobias Weltner, Aleksandar Nikolic and Richard Giles.

March 4, 2010 Posted by | Active Directory management, Deployment, Group Policy, Scripting, Windows 7, Windows PowerShell, Windows Server 2003 R2, Windows Server 2008, Windows Server 2008 R2, Windows Vista, Windows XP | , , | 19 Comments

Single Sign-On to Remote Desktop Services


Single sign-on is an authentication method that allows users with a domain account to log on once to a client computer by using a password, and then gain access to remote servers without being asked for their credentials again. See more details here for Windows Server 2008 and here for Windows Server 2008 R2.

On the client-side SSO are currently available for Windows XP with SP3, Windows Vista and Windows 7.


Configure SSO on the server-side

To configure SSO on the server-side (Windows Server 2008 Terminal Services or Windows Server 2008 R2 Remote Desktop Services), set the option “Security layer” to either “Negotiate” or “SSL (TLS 1.0)”:


Best practice would be to configure this in a common GPO for all Remote Desktop Services servers in the domain:


This setting resides under Computer Configuration->Policies->Administrative templates->Windows Components->Terminal Services->Terminal Server->Security.


Configure SSO on the client-side

Using a common GPO would also be the best practice to deploy the client settings needed for SSO to work.
The “Allow Delegating Default Credentials” resides under Computer Configuration->Policies->System->Credentials Delegation:



Enable “Allow Delegating Default Credentials”, press the “Show”-button and either specify the domain pre-fixed with * to allow delegation to all servers in the domain, or specify specific servers:


Next, create a RDP-file and deploy this file to the client computers.
Before deploying the file, open it in a text editor, e.g. Notepad, and add the following line: enablecredsspsupport:i:1
This will enable SSO for the RDP-file.

I would also recommend to sign the RDP-file with a Code Signing certificate. This can be accomplished using the utility rdpsign.exe:


Sample signing:


When a RDP-file are signed, the following will be added to the bottom of the file:


For Windows Vista and Windows 7 clients, the configuration would now be completed when the RDP-file are deployed.


For Windows XP clients the following would be necessary in addition to the steps above:
-Service Pack 3 needs to be installed
-At least version 6.0 of the Remote Desktop Client
-Turn on the CredSSP Security Provider

The steps to turn on the CredSSP Security Provider are described in this kb-article.

I would recommend deploying these registry settings using Group Policy Preferences:


Also the RDP-file may be deployed in the same way:


I`ve covered the usage of Group Policy Preferences in a previous post.

Also, SSO can be combined with Remote Desktop Services Web Access. The Remote Desktop Services Team has posted an excellent post describing how to set up SSO in RDS Web Access.

December 25, 2009 Posted by | Group Policy, Remote Desktop Services, Terminal Services, Windows 7, Windows Server 2008, Windows Server 2008 R2, Windows Vista, Windows XP | , , , , , | 2 Comments

Troubleshooting Group Policy made easier

In Windows Vista/Server 2008 and newer operation systems from Microsoft the userenv.log file which was logging Group Policy processing information in Windows 2000/XP are replaced by a new event log named Group Policy. You can find it in the Event Viewer when you browse to Applications and Services Logs/Microsoft/Windows/GroupPolicy.


The event categories found in the Group Policy event log:


This really makes Group Policy troubleshooting much easier!

In addition to checking out the Group Policy event log on the client, I would also recommend the use of the Group Policy Modeling (simulating what is supposed to happen) and Group Policy Results (connecting to the client to see what did happen) wizards when troubleshooting Group Policy:


March 25, 2009 Posted by | Group Policy, Windows 7, Windows Server 2008, Windows Vista | , | Leave a comment