DCSIMG
January 2009 - Posts - Shay Levy

Shay Levy

If you repeat it, PowerShell it!

News


btn_donate_LG

View Shay Levy's profile on LinkedIn Follow Shay Levy at Twitter Shay Levy's Facebook profile Subscribe to my FriendFeed


site statistics




January 2009 - Posts

Using Help in PowerShell ISE

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:

image

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:

image

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:

image 


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.

PowerShell CTP3 quick tip

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).

Windows PowerShell ISE screenshot capture

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: 

  1. function Capture-ISEScreen  
  2. {  
  3.     [System.Windows.Forms.SendKeys]::SendWait("%{PRTSC}")  
  4.     Start-Process mspaint  
  5. }  
  6.  
  7. # create shortcut key  
  8. $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.

capture

Active Directory Recycle Bin


image

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.

PowerGUI Quick Video Tips


Darin Pendergraft, PowerGUI’s Product Manager in a series of PowerGUI Quick Tips.

 

 

Downloading and Installing

 

Script Editor Features

 

Working with columns in the grid

 

Generating Reports

 

Setting Filters in the grid

Free eBook: Windows Server 2008 Core Administrator’s Pocket Consultant

Microsoft is celebrating its 25th anniversary and you get a free eBook thumbs_up

The book, by Mitch Tulloch with the Windows Server Core Team, is available for download here (PDF, 6.1 MB).

Server Core Quick Start Guide

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


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.

Get-WMIQualifierValue

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"
}