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

Backing up Group Policy Objects using Windows PowerShell

A best practice in domain environments are backing up the Group Policy Objects regularly. Even though a GPO may be restored by restoring a system state backup from a domain controller to an alternate location, and then copy the contents from the deleted GPO to a new GPO to restore the settings, this may be a hazzle since it`s not pretty straightforward. It also requires you to restart the domain controller affected in Directory Services Restore Mode.
PowerShell MVP Don Jones has written a good article on this topic, available here.

For those of you who may not want to do GPO restore the hard way, or buy a commercial third party product, I would encourage you to schedule regular GPO backups using the Windows PowerShell Group Policy-module available in Windows Server 2008 R2, as well as RSAT in Windows 7.
To accomplish this, I`ve written a small script which backs up all modified GPO`s in the specified timespan. I would generally recommend to have the script run once a day, thereby setting the timespan-variable to the last 24 hours. The script are called Backup-ModifiedGPOs.ps1, and available from here.

All Group Policy Objects modified in the specified timespan are backup up to the specified backup path.
Also, an HTML-report are created for each GPO-backup, with the unique backup GUID as part of the filename. This way you can easily see what settings each backup contains.

When restoring a GPO, you must first note the GUID of the backup you want to restore. Then you can restore the GPO by using the Restore-GPO cmdlet in the Group Policy-module. Sample usage:


Administrators who feels more comfortable working with the GUI, may use the Group Policy Management Console to do the restore.

The following procedure from the Group Policy Planning and Deployment Guide on Microsoft TechNet describes how to accomplish the restore operation from the GUI:

To view the list of GPO backups

  1. In the GPMC console tree, expand the forest or domain that contains the GPOs that you want to back up.
  2. Right-click Group Policy Objects, and the click Manage Backups.
  3. In the Manage Backups dialog box, enter the path to the location where you stored the GPO backups that you want to view. Alternatively, you can click Browse, locate the folder that contains the GPO backups, and then click OK.
  4. To specify that only the most recent version of the GPOs be displayed in the Backed up GPOs list, select the Show only the latest version of each GPO check box. Click Close.

Using the GPMC to restore GPOs

You can also restore GPOs. This operation restores a backed-up GPO to the same domain from which it was backed up. You cannot restore a GPO from a backup into a domain that is different from the GPO’s original domain.

To restore a previous version of an existing GPO

  1. In the GPMC console tree, expand Group Policy Objects in the forest or domain that contains the GPOs that you want to restore.
  2. Right-click the GPO that you want to restore to a previous version, and then click Restore from Backup.
  3. When the Restore Group Policy Object Wizard opens, follow the instructions in the wizard, and then click Finish.
  4. After the restore operation completes, a summary will state whether the restore succeeded. Click OK.

To restore a deleted GPO

  1. In the GPMC console tree, expand the forest or domain that contains the GPO that you want to restore.
  2. Right-click Group Policy Objects, and then click Manage Backups.
  3. In the Manage Backups dialog box, click Browse, and then locate the file that contains your backed-up GPOs.
  4. In the Backed up GPOs list, click the GPO that you want to restore, and then click Restore.
  5. When you are prompted to confirm the restore operation, click OK.
  6. After the restore operation completes, a summary will state whether the restore succeeded. Click OK. Click Close.

Important: Since Group Policy links are stored on the Organizational Unit objects in Active Directory, this information are not backup up and also not restore. However, the HTML backup-reports contains this information, so you may manually re-link the GPO to the correct OU(s).

Also note that WMI filters and IPSec policies are not backed up by the backup feature in the Group Policy Management Console. For more information on how to manage these items, see the before mentioned Group Policy Planning and Deployment Guide.


June 15, 2010 Posted by | Active Directory management, Group Policy, Scripting, Windows 7, Windows PowerShell, Windows Server 2008 R2 | 12 Comments

Dynamic Remote Desktop Connection Manager connection list

Microsoft recently released a free tool for managing multiple remote desktop connections called “Remote Desktop Connection Manager”.

A sample screenshot:


There are several nice features, such as “Connect group” which lets you connect to all servers in a group at once:


On the “Group Properties” you may set common settings for all connections in the group, like logon credentials:


Further, there are group properties for RDS Gateway (formerly TS Gateway), display settings, local resources and so on.

There are several applications for remote desktop connections on the market, and some of them got these settings as a per server setting. It`s nice to be able to group servers and configure common settings.

Dynamically creating the connection list

When you work in larger environments with hundreds, maybe thousands of servers, setting up each connection manually isn`t an option.

Since Remote Desktop Connection Manager stores the config-files in xml-files, it`s rather easy to create dynamic config-files for a domain using Windows PowerShell. I`ve created a script to accomplish this, called New-RDCManFile.ps1, available from here. It uses Microsoft`s PowerShell-module for Active Directory, which is available in Windows Server 2008 R2 and RSAT for Windows 7.

The script does the following:
Creates a template xml-file
Inserts the logged on user`s domain name in the file properties
Inserts the logged on user`s domain name in the group properties
Inserts the logged on user`s username in the logoncredentials section
Inserts the logged on user`s domain name in the logoncredentials section
Retrieves all computer objects from Active Directory with the word “server” in the operatingsystem property
Adds each computer object as a server object
Saves the XML-file to %userprofile%\domain-name.rdg

When done you can open the rdg-file in Remote Desktop Connection Manager. I would recommend you to insert your password in the Group Properties to avoid being asked for credentials for each connection.

Feel free to customize the script to your needs, in example by editing the XML-template to edit the Group Properties. Another customization might be creating a group for each server OU for enhanced overview in larger environments.

If you would rather use Quest`s PowerShell Commands for Active Directory (which works on downlevel operatingsystems like Windows XP and Windows Server 2003), or any other way to retrieve the server names, you may customize this on line 110.

You might also want to schedule the script to run on a regular basis, saving the file to a central location. This way the IT personnel will always have access to the latest version with the most recent servers added.

If you got any further ideas or comments, please let me know in the comments section below.

June 2, 2010 Posted by | Active Directory management, Remote Desktop Services, Remote Management, RSAT, Scripting, Windows 7, Windows PowerShell, Windows Server 2008 R2 | 19 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

Pin and unpin applications from the taskbar and Start-menu using Windows PowerShell

I`ve created a PowerShell module for working with pinned applications in Windows 7 and Windows Server 2008 R2. The module are created based on a script created by Ragnar Harper and Kristian Svantorp.

The module are available here, on the TechNet Script Center Gallery.

Installation and usage

Modules in Windows PowerShell can be “installed” in two ways:

1) Save the module as a psm1-file, and store it in a folder with the same name as the psm1-file. Copy this folder, using i.e. xcopy or Copy-Item, to a desired PowerShell module-folder (see available module paths using $env:PSModulePath)

2) Import the module by calling the psm1-file directly.

The first option are preferred for production use.

Next, import the module using Import-Module:

(Option 1)

(Option 2)

The module consist of one function as shown here:


The help text are available with Get-Help:


For example usage, add –Examples to the Get-Help cmdlet:


Basic error checking for valid parameters are included:


The Set-PinnedApplication function supports the en-us and nb-no locales as-is, but you can easily add support for more locales.

Feel free to let me know in the comment section below if you got any feedback.

Update, 06.08.2010: A new version of the module are now published at the original link on the TechNet Script Center Gallery. In the new version, there are full MUI support, after an update by Johan Akerstrom.

February 26, 2010 Posted by | Desktop management, Windows 7, Windows PowerShell, Windows Server 2008 R2 | | 18 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