Tuesday, February 27, 2007

Leo Vildosola's Code Snippet Plugin - Test post

The following code is just stuff laying around and is used only to test the plugin.  DOn't assume any of it is working as much cam from my junk folder where I park snippets that I may be using for other projects.  My intentions are to just see how well code embeds in teh blog and how the highlighting behaves.  To that end I chose large and possibly broken code to see what would happen.  It appears that the formatter behaves well.   Thankyou again Leo Vildosola.


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'>
    <b:include data='blog' name='all-head-content'/>
Blogger Template Style
Name:     Minima
Designer: Douglas Bowman
URL:      www.stopdesign.com
Date:     26 Feb 2004
Updated by: Blogger Team
----------------------------------------------- */

/* Variable definitions
   <Variable name="bgcolor" description="Page Background Color"
             type="color" default="#fff" value="#ffffef">
   <Variable name="textcolor" description="Text Color"
             type="color" default="#333" value="#333333">
   <Variable name="linkcolor" description="Link Color"
             type="color" default="#58a" value="#5588aa">
   <Variable name="pagetitlecolor" description="Blog Title Color"
             type="color" default="#666" value="#666666">
   <Variable name="descriptioncolor" description="Blog Description Color"
             type="color" default="#999" value="#999999">
   <Variable name="titlecolor" description="Post Title Color"
             type="color" default="#c60" value="#cc6600">
   <Variable name="bordercolor" description="Border Color"
             type="color" default="#ccc" value="#cccccc">
   <Variable name="sidebarcolor" description="Sidebar Title Color"
             type="color" default="#999" value="#999999">
   <Variable name="sidebartextcolor" description="Sidebar Text Color"
             type="color" default="#666" value="#666666">
   <Variable name="visitedlinkcolor" description="Visited Link Color"
             type="color" default="#999" value="#999999">
   <Variable name="bodyfont" description="Text Font"
             type="font" default="normal normal 100% Georgia, Serif" value="normal normal 100% Georgia, Serif">
   <Variable name="headerfont" description="Sidebar Title Font"
             default="normal normal 78% 'Trebuchet MS',Trebuchet,Arial,Verdana,Sans-serif" value="normal normal 78% 'Trebuchet MS',Trebuchet,Arial,Verdana,Sans-serif">
   <Variable name="pagetitlefont" description="Blog Title Font"
             default="normal normal 200% Georgia, Serif" value="normal normal 200% Georgia, Serif">
   <Variable name="descriptionfont" description="Blog Description Font"
             default="normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif" value="normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif">
   <Variable name="postfooterfont" description="Post Footer Font"
             default="normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif" value="normal normal 78% 'Trebuchet MS', Trebuchet, Arial, Verdana, Sans-serif">

/* Use this with templates/template-twocol.html */

body {
  font:x-small Georgia Serif;
  font-size/* */:/**/small;
  font-size: /**/small;
  text-align: center;
a:link {
a:visited {
a:hover {
a img {

/* Header

#header-wrapper {
  margin:0 auto 10px;
  border:1px solid $bordercolor;

#header { 
  margin: 5px;
  border: 1px solid $bordercolor;
  text-align: center;

#header h1 {
  margin:5px 5px 0;
  padding:15px 20px .25em;
  font: $pagetitlefont;

#header a {

#header a:hover {

#header .description {
  margin:0 5px 5px;
  padding:0 20px 15px;
  line-height: 1.4em;
  font: $descriptionfont;
  color: $descriptioncolor;

/* Outer-Wrapper
----------------------------------------------- */
#outer-wrapper {
  width: 880px;
  margin:0 auto;
  font: $bodyfont;

#main-wrapper {
  width: 600px;
  float: left;
 /* word-wrap: break-word;*/ /* fix for long text breaking sidebar float in IE */
 overflow: hidden;   /* fix for long non-text content breaking IE sidebar float */

#sidebar-wrapper {
  width: 220px;
  float: right;
  word-wrap: break-word; /* fix for long text breaking sidebar float in IE */
  overflow: hidden;      /* fix for long non-text content breaking IE sidebar float */

/* Headings
----------------------------------------------- */

h2 {
  margin:1.5em 0 .75em;
  line-height: 1.4em;

/* Posts
h2.date-header {
  margin:1.5em 0 .5em;

.post {
  margin:.5em 0 1.5em;
  border-bottom:1px dotted $bordercolor;
.post h3 {
  margin:.25em 0 0;
  padding:0 0 4px;

.post h3 a, .post h3 a:visited, .post h3 strong {

.post h3 strong, .post h3 a:hover {

.post p {
  margin:0 0 .75em;

.post-footer {
  margin: .75em 0;
  font: $postfooterfont;
  line-height: 1.4em;

.comment-link {
.post img {
  border:1px solid $bordercolor;
.post blockquote {
  margin:1em 20px;
.post blockquote p {
  margin:.75em 0;

/* Comments
----------------------------------------------- */
#comments h4 {
  margin:1em 0;
  font-weight: bold;
  line-height: 1.4em;
  color: $sidebarcolor;

#comments-block {
  margin:1em 0 1.5em;
#comments-block .comment-author {
  margin:.5em 0;
#comments-block .comment-body {
  margin:.25em 0 0;
#comments-block .comment-footer {
  margin:-.25em 0 2em;
  line-height: 1.4em;
#comments-block .comment-body p {
  margin:0 0 .75em;
.deleted-comment {

#blog-pager-newer-link {
  float: left;
#blog-pager-older-link {
  float: right;

#blog-pager { 
  text-align: center;

.feed-links {
  clear: both;
  line-height: 2.5em;

/* Sidebar Content
----------------------------------------------- */
.sidebar { 
  color: $sidebartextcolor;
  line-height: 1.5em;

.sidebar ul {
  margin:0 0 0;
  padding:0 0 0;
.sidebar li {
  padding:0 0 .25em 15px;

.sidebar .widget, .main .widget { 
  border-bottom:1px dotted $bordercolor;
  margin:0 0 1.5em;
  padding:0 0 1.5em;

.main .Blog { 
  border-bottom-width: 0;

/* Profile 
----------------------------------------------- */
.profile-img { 
  float: left;
  margin: 0 5px 5px 0;
  padding: 4px;
  border: 1px solid $bordercolor;

.profile-data {
  font: $postfooterfont;
  color: $sidebarcolor;
  font-weight: bold;
  line-height: 1.6em;

.profile-datablock { 
  margin:.5em 0 .5em;

.profile-textblock { 
  margin: 0.5em 0;
  line-height: 1.6em;

.profile-link { 
  font: $postfooterfont;
  text-transform: uppercase;
  letter-spacing: .1em;

/* Footer
----------------------------------------------- */
#footer {
  margin:0 auto;
  line-height: 1.6em;
  text-align: center;

/** Page structure tweaks for layout editor wireframe */
body#layout #header { 
  margin-left: 0px;
  margin-right: 0px;

  <div id='outer-wrapper'><div id='wrap2'>

    <!-- skip links for text browsers -->
    <span id='skiplinks' style='display:none;'>
      <a href='#main'>skip to main </a> |
      <a href='#sidebar'>skip to sidebar</a>

    <div id='header-wrapper'>
      <b:section class='header' id='header' maxwidgets='1' showaddelement='no'>
<b:widget id='Header1' locked='true' title='tech-comments (Header)' type='Header'/>
    <div id='content-wrapper'>

      <div id='main-wrapper'>
        <b:section class='main' id='main' showaddelement='no'>
<b:widget id='Blog1' locked='true' title='Blog Posts' type='Blog'/>

      <div id='sidebar-wrapper'>
        <b:section class='sidebar' id='sidebar' preferred='yes'>
<b:widget id='LinkList2' locked='false' title='Feeds' type='LinkList'/>
<b:widget id='Profile1' locked='false' title='About Me' type='Profile'/>
<b:widget id='LinkList1' locked='false' title='Links' type='LinkList'/>
<b:widget id='BlogArchive1' locked='false' title='Blog Archive' type='BlogArchive'/>

      <!-- spacer for skins that want sidebar and main to be the same height-->
      <div class='clear'>&#160;</div>

    </div> <!-- end content-wrapper -->

    <div id='footer-wrapper'>
      <b:section class='footer' id='footer'/>

  </div></div> <!-- end outer-wrapper -->



$x|foreach {Get-Acl

 $_.Fullname $_|add-member -membertype noteproperty -name Owner3 -value $owner }

function Add-Owner( $obj){
     $owner=(Get-Acl $obj.Fullname).Owner
     $obj|add-member -membertype noteproperty -name Owner -value $owner

$files=dir c:\ -filter *.zip -recurse
$files | foreach {add-owner( $_) }
$files | select-object -property fullname,extension,length,LastWriteTime,owner|export-csv d:\files.txt -notype

# AdOwnerToFile.ps1
#  Cut and paste to PS.  Change the "DIR" filter and path as needed.
# function is separated out for re-use
function Add-Owner( $obj){
     $owner=(Get-Acl $obj.Fullname).Owner
     $obj|add-member -membertype noteproperty -name Owner -value $owner
# get a filtered list of files
$files=dir c:\ -filter *.zip -recurse
# add the owner as a "note" property on each file
$files | foreach {add-owner( $_) }
# use select-object to select fields and field order to send to Export-Csv
$files | select-object -property  fullname,extension,length,LastWriteTime,owner|export-csv d:\files.txt -notype


using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
using System.Management.Automation;
using System.Collections;

namespace DSS.PowerShell
    [Cmdlet(VerbsDiagnostic.Ping, "Computer", SupportsShouldProcess = true)]
    public class PingComputerCmd : PSCmdlet

        #region Properties

        private string[] _Name = {"localhost"};
        private Boolean _All = false;
        private int _Output = 0;
        [Parameter(Position = 0,
          Mandatory = false,
          ValueFromPipelineByPropertyName = true,
          HelpMessage = "Help Text")]
        public string[] Name
               return _Name;
                _Name = value;        

        [Parameter(Position = 1, Mandatory = false, ValueFromPipelineByPropertyName = false, HelpMessage = "Return all objects")]
            public bool All
                    return false;
                    _All = value;

        [Parameter(Position = 2, Mandatory = false, ValueFromPipelineByPropertyName = false, HelpMessage = "Return all objects")]
        public int Output
                return 0;
                _Output = value;
        protected override void ProcessRecord()
                if (_Name.Length == 1)  // see if it's a filename
                    if (System.IO.File.Exists(_Name[0]))
                        _Name = System.IO.File.ReadAllLines(_Name[0]);
                foreach (string ThisName in _Name)
                    WriteDebug("Attempting to ping " + ThisName);
                    SelectQuery Query = new SelectQuery("SELECT StatusCode FROM Win32_PingStatus WHERE Address = '" + ThisName + "'");
                    ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Query);
                   foreach (ManagementObject result in Searcher.Get())
                            string statusCode = result.GetPropertyValue("StatusCode").ToString();
                            if (statusCode == "0")
                                WriteDebug("Successful ping of " + ThisName);
                                if ( _Output == 0 ) WriteObject("Good:" + ThisName);
                                else WriteObject(ThisName);
                        catch (Exception)
                            if (_All)
                                WriteObject("Exc:" + ThisName );

Leo Vildosola's Code Snippet plugin for Windows Live Writer

Leo has posted his new version of the code snippet plugin on Live Gallery here.

He has blogged it here.

My previos post uses his plugin for code formatting.  It is very easy to use.  The new version looks even better. 

Keep up the good effort Leo.

Thursday, February 22, 2007

Getting DIVs to work in IE6 and IE7 and Other Browsers

Here is a DIV style that will work in IE6 and IE7.  It contains the text or included contents and correctly displays scrollbars if needed. (Higlighting done with Scott Dunn's Code Formatter)

<div style="width: 95%; overflow: hidden; border-right: thin solid; border-top: thin solid; border-left: thin solid; border-bottom:thin solid;" > </div>

The border settings are optional but good to use while understanding the behavior of the style.

The key seems to be using a local style on the div.  Using an included style block doesn't work because blogger clears all styles before displaying a new div.  It can probably be done but I haven't yet managed to find the correct mechanism.

overflow can be set to hidden or auto if scrollbars are needed.  WOrd break adjustments can be applied locally and seem to get out from under styles imposed by the blogger template.

I highly recommend that IE6 any style patches in the template be removed in favor of free-flowing the blog sections.  If you need correct containment in an inserted element or div just apply a local style to the object.  be sure to a a width: 100%; to the style. THe presence of this style bit seems t force teh div to behave.

Steve Dunn's Code Formatter  uses a containing DIV with the width pre-set so it behaves correctly once the template patches have been removed.  Steve uses the ActiPro ASP.NET DLLs to generate DHTML into the WLW blog editor.

Steves code provides support for the following languages:

  • Batch File
  • C#
  • CSS
  • HTML
  • INIFile
  • Java
  • JScript
  • Perl
  • PHP
  • Python
  • SQL
  • VB.NET
  • VBScript
  • XML

 Code highlighting produced by Actipro CodeHighlighter (freeware)

Test of Code Snippet WLWPI

Code Snippet Editor after Resetting blog to NOT convert line feeds.

using System;
using System.IO;

namespace HtmlAgilityPack.Samples
    class Html2Xml
        static void Main(string[] args)

        static void Test()
            HtmlToText htt = new HtmlToText();
            string s = htt.Convert(@"..\..\mshome.htm");
            StreamWriter sw = new StreamWriter("mshome.txt");

I have tested this on spaces.live.com and it fails in exactly the same way.

Tuesday, February 20, 2007

Copy Code To Clipboard

This text will be copied onto the clipboard when you click the button below. Try it! It will also retain the indentation and add proper end-of-line sequences.


Dim objWMIService
Dim colFiles
Dim oFile
Dim iReturn, sReturn

strComputer = "."
Set objWMIService = GetObject("winmgmts:\\"& strComputer & "\root\cimv2")
Set colFiles = objWMIService.ExecQuery("Select * from CIM_DataFile where Extension = 'cpy'")

For Each oFile in colFiles
	wscript.Echo "OLDNAME:" & oFile.Name
	sNewName = oFile.Path & oFile.FileName & ".log"
	wscript.Echo "NEWNAME:" & sNewName
	iReturn = oFile.rename( sNewName )
	If Return <> 0 Then
		Select Case iReturn
			Case0 : sReturn = "Success" 
			Case2 : sReturn = "Access denied"
			Case8 : sReturn = "Unspecified failure"
			Case9 : sReturn = "Invalid object"
			Case 10 : sReturn = "Object already exists"
			Case 11 : sReturn = "File system not NTFS"
			Case 12 : sReturn = "Platform not Windows NT or Windows 2000"
			Case 13 : sReturn = "Drive not the same"
			Case 14 : sReturn = "Directory not empty"
			Case 15 : sReturn = "Sharing violation"
			Case 16 : sReturn = "Invalid start file"
			Case 17 : sReturn = "Privilege not held" 
			Case 21 : sReturn = "Invalid parameter"
		End Select
	MsgBox sReturn & ">>>>" & oFile.Name
	End If


Saturday, February 10, 2007

HTA Sampler at ScriptingAnswers.com

HTA sampler demonstrting how to use:

  • Modal dialogs
  • Modeless dialogs
  • Per-line output formatting to an HTA form for displaying diagnostic messages
  • Use of "Popup" info boxes that display and disappear automatically.( like tooltips but better and dynamic)
  • Use of "callback" functions to communincate beween dialogs and an HTA.
  • Storing of XML data inside an HTA for later use.
  • Saving of teh partial contents as HTML by directly copying the comntents of controls to a file.  Useful for displaying and then saving reports without the need to reformat.
  • Numerous other small but useful DHTML techniques.

HTA as ZIP file with Readme: HTA%20Sampler.zip at www.ScriptingAnswers.com/Scriptvault.asp

HTA Sampler source in a syntax highlighted we page:  HTASamplerSource (Viewable as web page if browser set to dsiplay based on content.  If it doesn't display as syntax highlighted then download and remove "TXT" extension and open in browser.  Highlighting is all done with HTML styles and will display correctly in all browsers.

Thank you to Steve Dunn's Windows Live Writer Code Formatter Plugin

Thank you to -  Actipro CodeHighlighter

del.icio.us tags: , , , , ,

Wednesday, February 07, 2007

Designing A CmdLet (Part IId - Test Code)

I am posting a new zip of the test code here with some additions to the "Computer" object. ( Link to full project source at end of blog article)   [NOTE: this code is not "production" quality yet.  I have not guarded against every possible exception and have not tested to guaratee the code won't "hang".  The code DOESN NOT change anything in the system or in PowerShell and has not caused any issues after many executions.  I amproviding it for you to experiment with and, hopefully, provide some feedback.

I have added OSInfo as a collection of OS information about all things informational to the operating system. ( How's that for a sentence?  Never give a programmer a pen and paper!)

With this version of the DLL you can:

PS>$computer=get-computer localhost                       
Name        IsPingable OSInfo            Services                           
----        ---------- ------            --------                           
localhost   True       \\OMEGA\root\c... {Alerter, ALG, AppMgmt, aspnet_... 

SystemDirectory : C:\WINDOWS\system32
Organization    : Designed Systems & Services
BuildNumber     : 2600              
RegisteredUser  : James Vierra                  
SerialNumber    : 55274-006-6247011-22174                              
Version         : 5.1.2600                                    


We can expand on OSInfo like this:  ( please excuse the line wraps.)


   TypeName: System.Management.ManagementObject#root\cimv2\Win32_OperatingSystem

Name                                      MemberType   Definition
----                                      ----------   ----------
Reboot                                    Method       System.Management.ManagementBaseObject Reboot()
SetDateTime                               Method       System.Management.ManagementBaseObject SetDateTime(System.String LocalDateTime)
Shutdown                                  Method       System.Management.ManagementBaseObject Shutdown()
Win32Shutdown                             Method       System.Management.ManagementBaseObject Win32Shutdown(System.Int32 Flags, System.I...
BootDevice                                Property     System.String BootDevice {get;set;}
BuildNumber                               Property     System.String BuildNumber {get;set;}
BuildType                                 Property     System.String BuildType {get;set;}
Caption                                   Property     System.String Caption {get;set;}
CodeSet                                   Property     System.String CodeSet {get;set;}
CountryCode                               Property     System.String CountryCode {get;set;}
CreationClassName                         Property     System.String CreationClassName {get;set;}
CSCreationClassName                       Property     System.String CSCreationClassName {get;set;}
CSDVersion                                Property     System.String CSDVersion {get;set;}
CSName                                    Property     System.String CSName {get;set;}
CurrentTimeZone                           Property     System.Int16 CurrentTimeZone {get;set;}
DataExecutionPrevention_32BitApplications Property     System.Boolean DataExecutionPrevention_32BitApplications {get;set;}
DataExecutionPrevention_Available         Property     System.Boolean DataExecutionPrevention_Available {get;set;}
DataExecutionPrevention_Drivers           Property     System.Boolean DataExecutionPrevention_Drivers {get;set;}
DataExecutionPrevention_SupportPolicy     Property     System.Byte DataExecutionPrevention_SupportPolicy {get;set;}
Debug                                     Property     System.Boolean Debug {get;set;}
Description                               Property     System.String Description {get;set;}
Distributed                               Property     System.Boolean Distributed {get;set;}
EncryptionLevel                           Property     System.UInt32 EncryptionLevel {get;set;}
ForegroundApplicationBoost                Property     System.Byte ForegroundApplicationBoost {get;set;}
FreePhysicalMemory                        Property     System.UInt64 FreePhysicalMemory {get;set;}
FreeSpaceInPagingFiles                    Property     System.UInt64 FreeSpaceInPagingFiles {get;set;}
FreeVirtualMemory                         Property     System.UInt64 FreeVirtualMemory {get;set;}
InstallDate                               Property     System.String InstallDate {get;set;}
LargeSystemCache                          Property     System.UInt32 LargeSystemCache {get;set;}
LastBootUpTime                            Property     System.String LastBootUpTime {get;set;}
LocalDateTime                             Property     System.String LocalDateTime {get;set;}
Locale                                    Property     System.String Locale {get;set;}
Manufacturer                              Property     System.String Manufacturer {get;set;}
MaxNumberOfProcesses                      Property     System.UInt32 MaxNumberOfProcesses {get;set;}
MaxProcessMemorySize                      Property     System.UInt64 MaxProcessMemorySize {get;set;}
Name                                      Property     System.String Name {get;set;}
NumberOfLicensedUsers                     Property     System.UInt32 NumberOfLicensedUsers {get;set;}
NumberOfProcesses                         Property     System.UInt32 NumberOfProcesses {get;set;}
NumberOfUsers                             Property     System.UInt32 NumberOfUsers {get;set;}
Organization                              Property     System.String Organization {get;set;}
OSLanguage                                Property     System.UInt32 OSLanguage {get;set;}
OSProductSuite                            Property     System.UInt32 OSProductSuite {get;set;}

As you can see there is plenty of good info here.  Very usable and also very usable for testing.

Load the DLL and explores the following:

  • $computer=Get-Computer localhost
  • $computer.OsInfo | gm
  • $computer.Services
  • $computer.Services["Browser"].State      #or start/stop and other methods

Download project: HERE.

There are dozens of useful methods and properties in a pipeline-able object that can be used to format reports with the Select-Object CmdLet and the Export-CliXML or ConverTo-Html and Export-CSV formatter CmdLets.


Tuesday, February 06, 2007

PowerShell CmdLet Parameters (Part IV)

After getting some experience with ParameterSet implementation I can now provide some basic explanation of how they might be used.

ParameterSets - A Simple Explanation

 I start the CmdLet code out by adding the optional DefaultParameterSetName attribute to the declaration of the CmdLet Class and set it to the name of the set that I want to use as a default.  The name DefaultSet seems appropriate.

<Cmdlet(VerbsCommon.Get, "Computer", _ SupportsShouldProcess:=True, _ DefaultParameterSetName:="DefaultSet")> _ Public Class Get_Computer : Inherits PSCmdlet

I then define the members of my DefaultSet.  Currently there is only one named parameter.

<Parameter( _ Position:=0, _ ParameterSetName:="DefaultSet", _ Mandatory:=True)> _ Public Property Name() As String() End Property

 I can then add other parameter set names to the CmdLet.  I have three more here each with one parameter.  Any time I add one of these switches to the CmdLet invocation I will force that ParametSet's rules to be applied.  If there are other parameters that are mandatory then they will be checked for by the runtime.  Checking will exclude looking for parameters that exist in other sets and only look at the unnamed parameters and the one belonging to the detected named set.

<Parameter( _ ParameterSetName:="FileSet", _ ValueFromPipeline:=True)> _ Public Property File() As System.IO.FileInfo End Property <Parameter( _ ParameterSetName:="DomainSet", _ Mandatory:=False)> _ Public Property Domain() As SwitchParameter End Property <Parameter( _ ParameterSetName:="OUSet", _ Mandatory:=True)> _ Public Property OU() As String End Property

The following is a parameter that has not been given an association with a "named" ParameterSet.  It will be available to all parameter sets. 

<Parameter( _ Mandatory:=False)> _ Public Property Filter() As SwitchParameter End Property

 In my ProcessRecord method I can check to see which parameter set has been validated and take a custom action.

Protected Overrides Sub ProcessRecord() Select Case ParameterSetName Case Is = "DefaultSet" Case Is = "FirstSet" Case Is = "DomainSet" Case Is = "OUSet" Case Is = "FileSet" End Select End Sub

 I use a WriteVerbose statement in the BeginProcessing section to help diagnose parameter set detection during code building.   The output from this statement will be visible if I add the global CmdLet switch "-verbose" to the CmdLet invocation. ( Get-Computer -verbose)

Protected Overrides Sub BeginProcessing() MyBase.BeginProcessing() WriteVerbose(ParameterSetName) End Sub


  1. Unnamed parameters belong to all parameter sets.
  2. A parameter can belong to more than one named parameter set.

More on parameter sets later.


Technorati tags: PowerShell CmdLet Development,

PowerShell: Designing a CmdLet (Part IIc - the switches)

Debugging with PowerShell

The test code sample has some other "default" and built in features that I want to point out.  These items need to be considered during the design phase as they will have an impact on how the CmdLet is coded.

The Debug Switch ( -debug )

The "debug" switch is built into PowerShell and is applied to code in every CmdLet.  The code elements (or methods) that are affected are:  WriteVerbose, WriteDebug, WriteError and WriteWarning.  Each of these is affected in different ways determined by the following.

  1. The verbose switch
  2. The debug switch
  3. $DebugPreferences
  4. $VerbosePreferences
  5. $ReportErrorShowSource
  6. $ReportErrorShowStackTrace
  7. $ReportErrorShowExceptionClass
  8. $ReportErrorShowInnerException
  9. $WarningPreference
  10. $ConfirmPreference

The test code uses "WriteVerbose" to add information about the execution of the command.  Adding the "-verbose" switch to the CmdLet or changing the $VerbosePreference variable will allow this output to be displayed.  The "-debug" switch has an affect on the output also.

My initial use of WriteVerbose is to allow the operator to see which computers are being skipped when the "-filter" switch has been defined.  This can be useful for documenting what machines have not been contacted.  This will probably change to a more complex filter that can handle multiple conditions along with the ability to define a log file or log variable.  For now I am just testing different approaches to the layout and design of the CmdLet.

The Verbose Switch ( -verbose )

As above this switch allows output from the WriteVerbose method.  I have sued it only for trace like info and outputting the failed pings.  Currently it also outputs the value of the Parameter set chosen by PowerShell because of the selected switches or the input variable type.(edit1)

PS>get-computer -file d:\computers.txt -verbose
Services                                       Name    IsPingable 
--------                                       ----    ---------- 
{Alerter, ALG, AppMgmt, aspnet_state...}       omega   True 
                                               test1   False 
{Alerter, ALG, AppMgmt, aspnet_state...}       omega   True 
                                               test2   False 
{Alerter, ALG, AppMgmt, aspnet_state...}       omega   True 


Above shows that the "FileSet"  parameterset was chosen for processing.  With this set the "ping" verbose messages are purposely surpressed. 

If we choose to add the-filter switch then we get more info:

PS>get-computer -file d:\computers.txt -verbose -filter
VERBOSE: FileSetVERBOSE: Successful ping omega
VERBOSE: Unable to ping test1
VERBOSE: Successful ping omega VERBOSE: Unable to ping test2
VERBOSE: Successful ping omega


By factoring this and other environmentall controllable behaviors we can optimize the flexibility and efficiency of the CmdLet and it's coding.


Windows PowerShell : PowerShell Tip: How to “shift” arrays…

Bruce Payette blogs the following... 

Link to Windows PowerShell : PowerShell Tip: How to “shift” arrays…

I haven't paid much attention to "mulitple assignment" in PoSH but this is a great example of what it can buy for us.  In the past in other languages we could initialize variables easily:

a, b, c,d = 0

name, rank, serial = "empty"


In PoSH:


$name,$rank,$serial = "empty","hello","world"



$x,$y,$z=$a   # will distribute the values back into individual variables

$m,$n=$a will put the first element in to $m and the remainder in $n

Read Bruce's blog to see how this plays out with arrays. It's quite useful and very cool.

Sunday, February 04, 2007

PowerShell: Designing a CmdLet (Part IIb - the code)

Download Test Code

If you need assistance in compiling and testing the CmdLet code see Don Jones' Make-A-CmdLet blog.

I have included the Get-Computer.vb source file and the generated DLL "PSSExtensionsVB.DLL" to the zip file.  You can load the DLL by following these instructions:

$dllpath=<path to saved dll> C:\Windows\Microsoft.NET\Framework\v2.0.50727\installutil $dllpath add-pssnapin PSSExtensionsVB

Now try the following commands:


Get-Computer localhost

Get-computer comp1,comp2,comp3

Get-Computer -file c:\computers.txt

dir c:\computers.txt | Get_Computer.txt

$hosts = "host1",host2", "host3"

$hosts | Get-Computer

Any input object or collection where the object "name" property is a computer can feed this CmdLet.

Try the following:

PS>$mycomputer = Get-Computer localhost                                                                                                     
VERBOSE: DefaultSet                                                                                                                         
Services                                  Name         IsPingable 
--------                                  ----         ---------- 
{Alerter, ALG, AppMgmt, aspnet_state...}  localhost    True 
Key                   Value                                                                 
---                   -----                                                                 
Alerter               \\OMEGA\root\cimv2:Win32_Service.Name="Alerter" 
ALG                   \\OMEGA\root\cimv2:Win32_Service.Name="ALG"
AppMgmt               \\OMEGA\root\cimv2:Win32_Service.Name="AppMgmt" 
aspnet_state          \\OMEGA\root\cimv2:Win32_Service.Name="aspnet_state"
AudioSrv              \\OMEGA\root\cimv2:Win32_Service.Name="AudioSrv" 
BITS                  \\OMEGA\root\cimv2:Win32_Servic="BITS"
Browser               \\OMEGA\root\cimv2:Win32_Service.Name="Browser"


Use GM to explore the properties of $mycomputer.

Look at the code and see how little code is needed to create this much functionality.  NET coupled with PowerShell is very powerful and flexible.

In the next installment I will explore more of the options available for creating powerful CmdLet's that help to simplify administration.  Along the way I will add some more interesting abilities to the "Computer" object for fun and to help test the growing CmdLet design.  Remember, we are only at the design stage.  After we have tested all of the elements and chosen the final configuration we still have to complete the design.  After the design is complete we will begin the final stage of code generation and testing.

Saturday, February 03, 2007

HooRah! for PowerShell CmdLets

I had to blog this.  PowerShell is so neat that it drives me into a frenzy.

I was adding the capability of taking input from a file.  I decided that any good system would be smart enough to recognize a file name in a commandline so I named the parameter  "File" and defined it as a "System.IO.FileInfo" type.

Here is what PowerShell does for us with a little help from NET classes.  Remember that I am only receiving a FileInfo type into my property.

PS> get-computer -file d:\computers.txt               
Services                                   Name     IsPingable 
--------                                   ----     ---------- 
{Alerter, ALG, AppMgmt, aspnet_state...}   omega    True 
                                           test1    False 
{Alerter, ALG, AppMgmt, aspnet_state...}   test2    True 

As you can see above sending a file name on the commandline is automatically detected as a file and loads the FleInfo into the CmdLet.  All I have to do in code is to open the Fileinfo called _file with a _file.OpenText() into a streamreader and begin reading the lines out of the file.

This also works like the following:

PS>dir d:\computers.txt|get-computer
VERBOSE: DefaultSet                                                                                                                         
Services                                       Name    IsPingable 
--------                                       ----    ---------- 
{Alerter, ALG, AppMgmt, aspnet_state...}       omega   True 
                                               test1   False 
{Alerter, ALG, AppMgmt, aspnet_state...}       omega   True 
                                               test2   False 
{Alerter, ALG, AppMgmt, aspnet_state...}       omega   True 

As you can see it also takes a FileInfo from the pipeline and, with the exact same three or four lines of code, it gets the file contents and runs the CmdLet.

This is exactly the way I have always seen code as working.  In the past I always trid to design code systems that leveraged the context.  NET does this extremely well.  Declaritive systems are much easier to work with because they usually exhibit behaviors like above.  Of course it does become necessary to think around this or some very weird behaviors can result.  This is not hard with NET languages since the NET classes and the CLR have anticipated this need and provide numerous mechanism to guard against eratic code behavior starting with very good strong typing.

Just for Fun and Info - The CmdLet code

The Parameter

<Parameter( _ ParameterSetName:="FileSet", _ ValueFromPipeline:=True)> _ Public Property File() As System.IO.FileInfo Get Return _File End Get Set(ByVal value As System.IO.FileInfo) _File = value End Set End Property

The Code


Case Is = "FileSet" Dim f As StreamReader = _File.OpenText() Dim line As String While Not f.EndOfStream line = f.ReadLine() GetComputer(line) End While f.Close() End Select

Doesn't matter if the name of FIleInfo comes from the pipeline or the commandline.   It treats them all the same.

I can also enter the command as : "d:\computers.txt"|get-computer

The string will be recognized by PS, I believe, as a file name and avoind the need for a dir command.

The following also works:

get-computer host1

get-computer host1,host2,host3



Get-Computer alone raises a prompt for the user to enter one or more names.  All of this done by adjusting the Parameter Attributes and the CmdLet Property types. ( Al little attention to PropertySets also helped)

Almost all "declaritive" with an extremely small amount of code.

PowerShell: Designing a CmdLet (Part II)

Well, now that the dust has settled this week I can get back to my CmdLet fun.

Over the week I did have some time to think about where this is all going.  It dawned on me that the CmdLet design should not include anything about the design of the returned object.  This wasn't evident to me at first and I was fretting about how to write that part up and still keep things simple.  It's easy now - don't include it'

The objects(s) returned by a CmdLet are NOT part of the CmdLet even if the CmdLet generates them.  They are objects that the CmdLet finds, selects or generates.  After the CmdLet completes it's execution they exist independently.

Here is my first take at what this CmdLet should look like.

CmdLet Name: Get-Computer
Parameters Name NetBIOS name, DNS name or array of string names
IPAddress Address in dot notation for input from pipeline
Domain Switch parameter that extracts all computer names from the default domain
OU aDSPath to OU containing computer objects
File FileInfo object or string pathname of file with list of computer names
Verbose [switch]Causes display of extra information for testing and debugging
Filter [switch]Causes only pingable computers to be returned
Simple [switch]Causes only names to be returned instead of Computer objects
Returns Object Returns a Computer object or a collection of Computer objects.  Can also return a list of pingable computer names
- - -

The "Computer" object is a basic and simple test object.  I have given it some of the elements that I will need to test it in a pipeline.  After the CmdLet is functioning correctly I will go back to the computer object and add a world of functionality to it.

Computer Object

Properties: Name, IPAddress, DNSAddress, OS, OSVersion, IsPingable, Services, [Future-Products, Accounts, ADInfo, ConsoleUser, TSUsers]

Methods: StartService, RestartService, StopService, Install,UnInstall, Shutdown, Restart, GPUpdate, [others not yet selected]

The initial test version only has Services available but this is enough for testing.

Test Code

I will post the test code here tomorrow after I have found a place to park it for download - blogspot doesn't allow uploading of files or images.)

Steve Dunn's Code Formatter

Steve just released the latest version for his excellent code formatter Plug-In for Windows Live Writer here.

Let's take it for a test spin...

 C# Code (no long lines)

using System; using System.Collections.Generic; using System.Text; using System.Management; using System.Management.Automation; using System.Collections; namespace DSS.PowerShell { [Cmdlet(VerbsDiagnostic.Ping, "Computer", SupportsShouldProcess = true)] public class PingComputerCmd : PSCmdlet { #region Properties private string[] _Name = {"localhost"}; private Boolean _All = false; private int _Output = 0; [Parameter(Position = 0, Mandatory = false, ValueFromPipelineByPropertyName = true, HelpMessage = "Help Text")] [ValidateNotNullOrEmpty] public string[] Name { get { return _Name; } set{ _Name = value; } }

 VB.NET Code (long lines)

 Word wrap still forced on but background colors and other elements work well. (Excuse the ugly blue).   I tried to manually remedy this to see why the scroll bars won't come on.  Something in the style for the DIV is in conflict.  My CSS is not the best so I am not able to pick it out.  It's possible that a div embedded in a div wil not inherit the "auto" style correctly.

Public Function Ping() As String Try Dim Query As SelectQuery Query = New SelectQuery("SELECT StatusCode FROM Win32_PingStatus WHERE Address = '" & Me.Name & "'") Dim Searcher As ManagementObjectSearcher Searcher = New ManagementObjectSearcher(Query) Dim result As ManagementObject For Each result In Searcher.Get If Not IsNothing(result.GetPropertyValue("StatusCode")) Then Dim x = result.GetPropertyValue("StatusCode") If result.GetPropertyValue("StatusCode") = 0 Then _Pingable = True Return "Pinged:" & Me.Name End If Else _Pingable = False End If Next Catch ex As Exception End Try Return "no hope" End Function

Here is DIV HTML as generated.

<div class="wlWriterEditableSmartContent" id="57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:1716bf5a-05d7-4f1a-9918-9ded3cc355da" contenteditable="false" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; width: 749px; padding-top: 0px">

Here is a DIV with scroll:

This is a very long line of continuing text a very very very long line that never ends anywhere

The above line wraps in WLW Web Layout mode but doesn't in Preview mode.  This is probably due to inheritance from the blog template.  There is a way in CSS to specify that a style blocks inheritance.  If I can find this I will experiment with it. 

By the way.  This was not the behavior of teh templates on the old blogspot blog site.  The newer templates are imposing more forced style rules somewhere.  Some of these may be unblockable.  I don't know yet.

 In any case this version of the formatter is much more flexible than the previous version.  Keep up the excellent work Steve.


After some testing with ode Formatter I have determined that the word wrap/scrollbar issue is being caused by settings in teh BlogSpot blog templates.  There is an entry in "main wrapper" that looks like this:

#main-wrapper { width: 600px; float: left; word-wrap: break-word; /* fix for long text breaking sidebar float in IE */ overflow: hidden; /* fix for long non-text content breaking IE sidebar float */ }

The comments indicate a patch for IE6.  Removing this patch seems to allow the scrollbars to display correctly.   ( I have not done this permanently on this blog yet so it still doesn't display the scroll bars.)

If Steve can find a way to block the inheritance of this style rule then his code will work under nearly all blog templates.  It it can't be done for some reason tehn I will alter this template so his code works correctly.

Testing with IE6 instead of IE7 shows that making template changes does break IE6.  Changes will not allow IE6 to display scrollbars.

There has to be a way to do this in all browsers.