January 2009 - Posts
Windows PowerShell Integrated Scripting Environment (ISE) comes with a graphical help file (chm) which contains complete help for PowerShell as well as help for using ISE. The help file is located under C:\Windows\Help\Mui\<LCID>.
To invoke help, press F1:
ISE’s help is also context-sensitive in terms of cmdlet names. If you press F1 while your mouse cursor is positioned inside a cmdlet name, help is displayed for the corresponding cmdlet:
Note: Context sensitive help doesn’t work for aliases, more on this below.
You can also disable local help and force ISE to get help directly from Technet:
$psISE.Options.LocalHelp = $false
Now, verify that the cursor is positioned accordingly and press F1, help is coming in from the internet:
ISE support two types of help: Local and Online, both implemented in two variables: $psLocalHelp and $psOnlineHelp
PS > $psLocalHelp
Key Value
--- -----
Add-Computer WindowsPowerShellHelp.chm::/html/093f660c-b8d5-43cf-aa0c-54e5e54e76f9.htm
Add-Content WindowsPowerShellHelp.chm::/html/0c836a1b-f389-4e9a-9325-0f415686d194.htm
Add-History WindowsPowerShellHelp.chm::/html/9c7c19cd-56e8-4fb2-b476-3adc589f7a97.htm
Add-Member WindowsPowerShellHelp.chm::/html/568588f6-4fed-47e5-819f-2cd326b71ed4.htm
Add-PsSnapin WindowsPowerShellHelp.chm::/html/153a2236-80bd-4f12-9852-411471f92441.htm
(...)
PS > $psOnlineHelp
Key Value
--- -----
Add-Computer http://go.microsoft.com/fwlink/?LinkID=135194
Add-Content http://go.microsoft.com/fwlink/?LinkID=113278
Add-History http://go.microsoft.com/fwlink/?LinkID=113279
Add-Member http://go.microsoft.com/fwlink/?LinkID=113280
Add-PsSnapin http://go.microsoft.com/fwlink/?LinkID=113281
(...)
Both variables are generic types (System.Management.Automation.Host.ObservableDictionary`2), similar to Hash Tables they have Key/Value pair members, each of which contains a cmdlet name and a pointer to the help page location.
I wanted to mimic the way ISE’s help works when you press F1 and allow an alias to be expanded to cmdlet name. With these functions the cursor position doesn’t have to be inside the name, it can be on either side as well as inside a name/alias, allowing you to get help for one letter long aliases. To use the functions, execute the code in ISE or include them in your ISE profile (you can also download them from the ‘Attachment’ section at the end of this post).
function Get-LocalHelp{
# check if local help is disabled
if(!$psIse.Options.LocalHelp)
{
throw 'Local help is disabled. To enable Local help execute:'+"`n"+
'PS > $psISE.Options.LocalHelp=$true'
}
# get the caret position and current line
$col = $psIse.CurrentOpenedFile.Editor.CaretColumn
$line = $psIse.CurrentOpenedFile.Editor.CaretLine
# tokenize the active editor script
$content = $psIse.CurrentOpenedFile.Editor.Text
$tokens = [System.Management.Automation.PsParser]::Tokenize($content,[ref]$null)
#
$cmd = $tokens |where {$_.StartLine -eq $line `
-AND $_.StartColumn -le $col -AND $_.EndColumn -ge $col }
if($cmd)
{
if($psLocalHelp.ContainsKey($cmd.content))
{
hh.exe$psLocalHelpitem($cmd.content)
return
}
$alias = (Get-Alias |where {$_.Name -eq $cmd.content}).Definition
if ($alias)
{
hh.exe $psLocalHelp.item($alias)
}
}
}
function Get-OnlineHelp{
# online help is displayed in default browser
$col = $psIse.CurrentOpenedFile.Editor.CaretColumn
$line = $psIse.CurrentOpenedFile.Editor.CaretLine
$content = $psIse.CurrentOpenedFile.Editor.Text
$tokens = [System.Management.Automation.PsParser]::Tokenize($content,[ref]$null)
$cmd = $tokens | where {$_.StartLine -eq $line `
-AND $_.StartColumn -le $col -AND $_.EndColumn -ge $col }
if($cmd)
{
if($psOnlineHelp.ContainsKey($cmd.content))
{
[Diagnostics.Process]::Start($psOnlineHelp.item($cmd.content))
return
}
$alias = (Get-Alias | where {$_.Name -eq $cmd.content}).Definition
if ($alias)
{
[Diagnostics.Process]::Start($psOnlineHelp.item($alias))
}
}
}
# register shortcut keys
$null = $psIse.customMenu.subMenus.add("Get-PSLocalHelp",{Get-LocalHelp},"CTRL+F1")
$null = $psIse.customMenu.subMenus.add("Get-PSOnlineHelp",{Get-OnlineHelp},"CTRL+F2")
Code is color coded using
PowerGUI. Comments, Suggestions, Improvements are most welcome.
In previous versions of PowerShell if you wanted to discover the static members of a type you had to do:
PS > [IO.File] | Get-Member –Static
TypeName: System.IO.File
Name MemberType
---- ----------
AppendAllText Method
AppendText Method
Copy Method
Create Method
CreateText Method
(...)
In CTP3 there’s no need to do that anymore, start with:
PS > [IO.File]::
Now press the TAB key and watch the magic (keep hitting TAB to cycle through all members).
This function makes a screenshot of ISE. It sends the ALT-PRINTSCREEN keystroke to capture the active window into memory and opens MSPaint.exe so you can paste the capture into, it also registers CTRL+1 as a shortcut key.
Paste the code into ISE and run it:
- function Capture-ISEScreen
- {
- [System.Windows.Forms.SendKeys]::SendWait("%{PRTSC}")
-
- }
-
-
- $null = $psIse.customMenu.subMenus.add("Capture-ISEScreen",{Capture-ISEScreen},"CTRL+1")
The “Custom” menu updates and now shows the function name and shortcut key. Now simply press CTRL+1 to capture the editor window.

Windows Server 2008 R2 has a new COOL feature: Recycle Bin. Once you turn it on (one way action!) you can restore deleted objects and all their attributes are also restored, there is no longer a need to rejoin a deleted computer account or rebuild a deleted user account groups membership.
The feature has no GUI and the only way to implement it is by using PowerShell which is included by default as part of the Windows Server 2008 operating system.
Click the image to watch the video.
Microsoft is celebrating its 25th anniversary and you get a free eBook 
The book, by Mitch Tulloch with the Windows Server Core Team, is available for download here (PDF, 6.1 MB).
In this “Concentrated Guide” (4MB) Don Jones walks you through the steps you need to install, configure and promote a Windows Server 2008 Server Core domain controller.
PowerGUI 1.6 has been released and is available for Download. The new version is PowerShell v2 CTP3 compatible and includes some new improvements as well as bug fixes. You can read more on Dmitry's blog or go straight to the WIKI page for the full product coverage, help, video tutorials and more.
When you create WQL queries for Get-WMIObject you sometimes need to know some property values in advance. A good example is when you want to query the event logs for a specific EventType, you cant do:
PS > Get-WmiObject -class Win32_NTLogEvent -filter "EventType='error'"
Get-WmiObject : Invalid query
It yields an error because EventType expects a numeric value:
PS > Get-WmiObject -class Win32_NTLogEvent -filter "EventType=
1"
So, how do you know which values to use? One way is to find them on MSDN. That was my main method, but not anymore. With Get-WMIQualifierValue you will get the value names and their corresponding numeric values for all class properties that support the 'Values' and 'ValueMap' qualifiers.
In a nutshell, a value map is an array linked to a property with the Value and ValueMap qualifiers, kind of a hash table key/value pair if you will. Get-WMIQualifierValue is also compatible with all versions of PowerShell.
function Get-WMIQualifierValue($Class){
if($PSVersionTable)
{ #PowerShell v2 detected
$wmi = gwmi meta_class -filter "__Class = '$class'" -amended
}
else
{ #PowerShell v1 detected
$wmi=[wmiclass]$class
$wmi.psbase.options.useAmendedQualifiers=$true
}
foreach ($p in $wmi.psbase.properties)
{
$names = $p.qualifiers | foreach {$_.name}
if($names -contains "values" -AND $names -contains "valuemap")
{
$pLen = "-"* ($p.name.length)
write-host ("`n$pLen`n"+$p.name+"`n$pLen") -fore yellow
$value=$p.qualifiers["Values"].value
$meaning=$p.qualifiers["ValueMap"].value
$map = $value | select Value,@{n="Meaning";e={$_}}
1..$map.length | foreach { $map[$_-1].value=$meaning[$_-1] }
$map | ft -a
}
}
}
Here is a sample output for the Win32_NTLogEvent WMI class:
PS > Get-WMIQualifierValue -class Win32_NTLogEvent
---------
EventType
---------
Value Meaning
----- -------
1 error
2 warning
3 information
4 security audit success
5 security audit failure
----
Type
----
Value Meaning
----- -------
1 error
2 warning
4 information
8 audit success
16 audit failure
Another example would be to ping a computer, from the (truncated) output you can see that a value of 0 for StatusCode means success (the remote computer is online)
PS > Get-WMIQualifierValue -class Win32_PingStatus
----------
StatusCode
----------
Value Meaning
----- -------
0 Success
11001 Buffer Too Small
11002 Destination Net Unreachable
11003 Destination Host Unreachable
11004 Destination Protocol Unreachable
11005 Destination Port Unreachable
11006 No Resources
11007 Bad Option
11008 Hardware Error
11009 Packet Too Big
11010 Request Timed Out
11011 Bad Request
11012 Bad Route
11013 TimeToLive Expired Transit
11014 TimeToLive Expired Reassembly
11015 Parameter Problem
11016 Source Quench
11017 Option Too Big
11018 Bad Destination
11032 Negotiating IPSEC
11050 General Failure
Armed with this knowledge you can construct the following WMI ping check:
$ping = gwmi win32_pingstatus -filter "address='comp1'"
if($ping.StatusCode -eq 0)
{
write-host "comp1 is online"
}
else
{
write-host "comp1 is not available"
}