This session will explore Group Policy enhancements in Windows Server 2008 R2 and Windows 7. We will show you how Administrative template improvements make it easier to configure and Group Policy preference improvements to configure defaults for non-Group Policy-aware Windows components. Then we will discuss Starter GPO improvements and scripting Group Policy Objects using Windows PowerShell Group Policy cmdlets. Sign up for the webcast HERE.
Presenter: John Baker, Senior IT Pro Evangelist, Microsoft Corporation
Product(s): Windows Server 2008,Windows Server 2008 R2.
Start Date: Tuesday, July 14, 2009 11:00 AM Pacific Time (US & Canada)
Get-WMIObject is one of the most used cmdlets in PowerShell and many of us system administrators use it on a daily basis to perform our day to day tasks. Often we need to get values of CIM_DATETIME properties from instances of a class. An example would be the Win32_OperatingSystem class (truncated property list):
PS > $os = Get-WMIObject Win32_OperatingSystem
PS > $os | Format-List *
(...)
Debug : False
Description :
Distributed : False
EncryptionLevel : 256
ForegroundApplicationBoost : 2
InstallDate : 20090506145635.000000+180
LargeSystemCache :
LastBootUpTime : 20090610153830.359599+180
LocalDateTime : 20090614140846.358000+180
Locale : 040d
Manufacturer : Microsoft Corporation
(...)
The lines in yelloe shows the CIM_DATETIME properties of the class. As you can see they are a bit cryptic to read. We can convert these properties to .NET objects by using two 'built-in' methods:
PS > $os | Get-Member con*
TypeName: System.Management.ManagementObject#root\cimv2\Win32_OperatingSystem
Name MemberType Definition
---- ---------- ----------
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime ScriptMethod System.Object ConvertToDateTime();
ScriptMethods are not part of the original WMI class, they are custom methods added by the PowerShell team to Types.ps1xml file. The about_Types.ps1xml page explains how Types.ps1xml files let you extend the Microsoft .NET Framework types of the objects that are used in Windows PowerShell (You can also look at this post). Here's a screenshot of the relevant part of the file:
We can use these methods to convert WMI dates to .NET DatetTime dates and vice versa with ConvertToDateTime and ConvertFromDateTime:
PS > $os.InstallDate
20090506145635.000000+180
# Convert to .NET [DateTime]
PS > $os.ConvertToDateTime($os.InstallDate)
Wednesday, May 06, 2009 2:56:35 PM
# convert back to DMTF date
PS > $os.ConvertFromDateTime('Wednesday, May 06, 2009 2:56:35 PM')
20090506145635.000000+180
# convert the current time to DMTF datetime
PS > $os.ConvertFromDateTime([DateTime]::Now)
20090614154854.144569+180
Instead of converting WMI CIM_DATETIME properties one by one we can use the ConvertFrom-DMTFDate utility filter. A filter is a type of function that runs on each object in the pipeline, it resembles a function with all its statements in a Process block.
filter ConvertFrom-DMTFDate{
# Create 'offline' PSObject so we can
# convert the properties values
$pso = $_ | Select-Object *
# Get all CIM_DATETIME properties
$props = $_.psbase.properties | where {$_.type -eq "DateTime" -AND $_.value}
# Converts a given DMTF datetime to [DateTime].
# The returned DateTime will be in the current
# time zone of the system.
$dmtf = [System.Management.ManagementDateTimeConverter]
if($props)
{
# convert CIM_DATETIME properties to .NET DateTime
# objects and write them object back to the pipeline
foreach($p in $props){
$pso.($p.name) = $dmtf::ToDateTime($p.value)
}
$pso
}
else
{
# write original object back to pipeline
$_
}
}
Now we can pipe to the filter and convert all WMI dates at once.
PS > Get-WMIObject Win32_OperatingSystem | ConvertFrom-DMTFDate | Format-List *
(...)
Debug : False
Description :
Distributed : False
EncryptionLevel : 256
ForegroundApplicationBoost : 2
InstallDate : 5/6/2009 2:56:35 PM
LargeSystemCache :
LastBootUpTime : 6/10/2009 3:38:30 PM
LocalDateTime : 6/14/2009 3:02:45 PM
Locale : 040d
Manufacturer : Microsoft Corporation
(...)
Much more easier to read, isn't it? We can also pipe the result to another cmdlet, such as Where-Object and filter the objects by the DateTime values using any PowerShell comparison operators.
Windows Live Writer (WLW) comes with a really cool feature: AutoLink glossary. When you create links in your blog posts you can select the Automatically link to this text check box when you insert the link.

Doing so will turn the link text you inserted (Text to be displayed) to an auto link. From now on every time you write ‘PowerShell’ in your posts it will create a link as you type! You can edit AutoLinks in the program Tools menu:

Behind the scenes WLW save the links in XML file (linkglossary.xml). The file is located under: %APPDATA%\Windows Live Writer\LinkGlossary and its content looks like:
<?xml version="1.0" encoding="utf-8"?>
<glossary>
<entry>
<text>PowerShell</text>
<url>http://www.microsoft.com/powershell</url>
<title>
</title>
<rel>
</rel>
<openInNewWindow>False</openInNewWindow>
</entry>
</glossary>
Often when I write blog posts I want to link cmdlet names to their online help pages thus providing the reader with the most updated help. Luckily, PowerShell V2 (CTP3) maintains the cmdlets online URLs inside the local help files. With the following command we can get all cmdlet names and their corresponding URL:
PS > Get-Help -Category cmdlet | where {$_.PSSnapIn -like "microsoft*"} | `
select name,@{n="URL";e={@($_.relatedLinks.nvigationLink)[0].uri}}
Name URL
---- ---
Get-WinEvent http://go.microsoft.com/fwlink/?LinkID=138336
Get-Counter http://go.microsoft.com/fwlink/?LinkID=138335
Import-Counter http://go.microsoft.com/fwlink/?LinkID=138338
Export-Counter http://go.microsoft.com/fwlink/?LinkID=138337
Disable-WSManCredSSP http://go.microsoft.com/fwlink/?LinkId=141438
Enable-WSManCredSSP http://go.microsoft.com/fwlink/?LinkId=141442
(...)
As you can see the output is a collection of objects, each object has two properties: Name and URL. Instead of creating the AutoLinks manually we can use the following advanced function. Set-WLWAutoLink defines three parameters. The first two: Name and URL has parameter attributes that accepts pipeline objects by property name (ValueFromPipelineByPropertyName=$true), the parameter binder will bind the objects from the above command to the parameters of the advanced function. The third parameter is a switch parameter to control if the AutoLink should open in a new window.
Set-WLWAutoLink creates new XML ‘entry’ nodes structure for non-existent cmdlets or update the URL of one if it already exists.
#requires -version 2
function Set-WLWAutoLink{
param(
[Parameter(
Position=0,Mandatory=$true,ValueFromPipelineByPropertyName=$true
)] [String]$Name,
[Parameter(
Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$true
)] [String]$URL,
[Parameter()][switch]$OpenInNewWindow
)
begin
{
$Glossary = "$env:APPDATA\Windows Live Writer\LinkGlossary\linkglossary.xml"
if(!(test-path $Glossary))
{
throw "linkglossary.xml cannot be found"
}
else
{
$xml = [xml](Get-Content $Glossary)
$nodeNames = "text","url","title","rel","openInNewWindow"
}
}
process
{
try{
$node = $xml.glossary.entry | where {$_.text -eq $name}
if($node)
{
Write-Verbose "Updating '$name' node."
$node.url = [string]$_.url
}
else
{
Write-Verbose "Creating '$name' node."
$entry = $xml.CreateElement("entry")
$nodeNames | foreach { $null = $entry.AppendChild($xml.CreateElement($_))}
$el = $xml.documentElement.AppendChild($entry)
$el.text=$Name
$el.url=$URL
$el.openInNewWindow = "$openInNewWindow"
}
}
catch
{
Write-Error $_
Continue
}
}
end
{
try
{
$xml.save($Glossary)
}
catch
{
throw
}
}
}
# Usage Example
Get-Help -Category cmdlet | where {$_.PSSnapIn -like "microsoft*"} | `
select name,@{n="URL";e={@($_.relatedLinks.navigationLink)[0].uri}} | Set-WLWAutoLink -verbose
Once the command has finished, restart WLW and check the Auto Linking section in the Tools menu. You’ll see the new AutoLinks for the cmdlets. Now start to type a new post with some PowerShell cmdlet names and watch the names turn into links on the fly.

The Scripting Guys have launched a new forum dedicated to the 2009 Summer Scripting Games. Event 1's information will be released on Monday, June 8, but you are invited to start conversations before then.