Sunday, November 25, 2007

Back From a Long Vacation

After not posting for quite some time I felt that I should provide a little information on what has happened in case there may be one or more brae individuals who might be monitoring this all but dead blog.

Six months ago I was diagnosed with Lyme disease.  I have apparently had it for more than six years and was becoming progressively more debilitated.  Over those years I was hospitalized repeatedly but told that there was nothing wrong.  After my heart stopped a couple of times I still didn't have a diagnosis.

On each hospitalization I told the doctors that I was certain that I had an infection and I listed all of the symptoms.  They insist6ed I was imagining these things or that I might have a psych problem.  One doctor insisted that my symptoms were symptoms of heroin withdrawal and required that I be tested for drugs.   When the test came back negative he said there was nothing wrong with me and sent me home.

One smart doctor looked at me six months ago and said "I think you have Lyme disease".    I have been on antibiotics now for six months and am just starting to feel more normal.  For many months I could barely stand up.  This disease is one where the cure can be more devastating than the disease when you have had it for as long as I have. I hope I continue to regain my normal unlimited energy level although I don't expect to be "normal" for many more months.  At least I can sit at the keyboard for more than five minutes without nearly passing out.

For the next couple of months I will be playing catch-up wit the technology and forums. Hopefully, I will soon return to blogging on a more regular basis.

Here is a useful starting point or anyone interested in information on Lyme disease.  This is a very useful site to refer your doctor to.  Most doctors are very limited in their knowledge this disease.  older information about Lyme was incorrect and has downplayed it's seriousness.   The most difficult thing about diagnosing Lye is that it can mimic many other diseases and is very hard to get a reliable laboratory test.  Most test that are negative for Lyme are incorrect which is most often the case when the disease has been in the system for a long time.

Thursday, May 24, 2007

Script With Class in VBScript

Someone asked me to help with a script and to also give some assistance in how best to use VBScript to accomplish tasks simply and quickly.  I took the opportunity to inject a "Class" that I use frequently to send formatted output to a log file.  This seems to have caused no end of confusion for the poor soul whose burden I was trying to lighten.

The use of classes in VBScript appears to be not well understood.  Consider the following:  You use an object to retrieve WMI information.

Set objWMI = GetObject("winmgmts:...)

The "objWMI" object is an instance of a "Class".  You access it's properties and methods using the "dot" notation: objWMI.Name.

A VBScript Class looks like the following:


1 Class CMyClass 2 3 Sub Class_Initialize 4 End Sub 5 6 Sub Class_Terminate 7 End Sub 8 9 End Class

The "Subs" re called on the creation of an instance and when an instance is destroyed.

Set objMyClass = new CMyclass

The class methods are called like any other object.  If CMyClass had a "Write" method we would call it like this: objMyClass.Write "Hello World!"

Why is this any different or better than using a plain old "Sub".  Bear with me a bit and I will show you some neat stuff and then maybe, some magic.


   1:  Class CLogFile
   3:      Dim fso 'FSO object
   4:      Dim ofile ' FIle object
   5:      Dim sFileName ' saves the pre built filename
   6:      Dim bLocal ' ' Setinstance to use WScript.Echo instaed of file
   8:      Sub Class_Initialize() ' this happens for every instance
  10:          sFileName = sLogPath & "\" _        
  11:              & Right("0" & Month(Date),2) & "-" _        
  12:              & Right("0" & Day(Date),2) & "-"  _        
  13:              & Right(Year(Date),2) & "-"  _        
  14:              & DatePart("h", Now) & DatePart("n", Now) & ".txt"
  15:              Set fso = CreateObject("Scripting.FileSystemObject")        
  17:      End Sub
  19:      Sub Open( sLogPath ) 'Call at begiing of script     
  21:          if sLogPath = "" Then             
  22:              bLocal = True      ' Echo don't use file       
  23:          Else  'open/create file     
  24:              Set ofile = fso.OpenTextFile(sFileName , 8,True)        
  25:              Write "Log file being opened"             
  26:          End If
  29:      End Sub
  31:      Sub Write( sMessage )  
  33:          If Not bLocal Then              
  34:              ofile.WriteLine "[" & Now & "] " & sMessage          
  35:          Else              
  36:              WScript.Echo "[" & Now & "] " & sMessage          
  37:          End If    
  39:      End Sub        
  41:      Sub Close  ' call at end of script to timestamp the log closing.
  42:          Write "Log file being closed"
  43:          ofile.Close
  44:          ' clean up for good practice
  45:          Set ofile = Nothing
  46:      End Sub  
  48:  End Class

This is the bombshell I dropped on my friend.  It looks foreboding but in a bit you will see what it buys us.

1.  Encapsulation:

All variables required for the functionality of the included code are embedded in the class.  This makes it convenient to copy and paste as it doesn't need external feeding.  No more global FileSystemObject.  It's hidden inside the class

2.  Abstraction:

The functionality is totally hidden.  It just does what we want without having to think about how it's done.

3.  Portability

4.  Reusable Code:

Code can be used over and over to perform the same function without the need for redesign.

In the case of this LogFIle class the output format can be changed easily without changing any of the calling code.  This code uses a specific format for the file name which it generates.  This can be easily altered.  A method can easily be added to handle switching between formats for different uses.  The log lines contain a time stamp which can be easily turned on or off.

The actually version of this that I use is somewhat more complex as the "Write" method takes an array of values and the "Open" method takes a formatter spec.  The class can switch between text, CSV, HTML and XML outputs.  This allows the same code to be used over and over even in the same script.  Each "Set obj = new Class" can open a different output file with a different format.  This object can even output to the command line.  The Class I use outputs to either the command line StdOut or the StdErr or both.  I have a "Write" "WriteEx" and a "WriteError" method that are used to control where the output goes and how it is both tagged and formatted.

 Study the above code and you will see how it accomplishes numerous effects with very few lines of code. 

 Later I might publish my more sophisticated Log class. 

Saturday, March 03, 2007

ActiPro Syntax Highlighter - (updated)

The ActiPro Syntax Highlighter with PowerShell script.  Highlighting is correct.  Module was added to ActiPro by ActiPro support in a very short time showing that the ActiPro Editor is very flexible.  This code was highlighted and copied to HTML using the ActiPro SyntaxEditor.  The new semantic definition was added by simply adding a "dynamic" language definition and then opening the script file.  I saved the file as HTML and pasted it into WLW to get a test of the HTML conversion.  I also added a DIV to force the containment of the lines.

AcriPro Website

ActiPro has done an excellent job on this product suite.

(Thank you Keith Hill for the use of your CmdLet code for use as a test case.  It was the largest and most complex script I could find when I went looking)

# ---------------------------------------------------------------------
# Author:    Keith Hill
# Desc:      CMDLET to pretty print XML.
# Usage:     This file contains a function-based CMDLET.  In order to use
#            it, you must dot source the file into your shell e.g.:
#            PoSH> . c:\bin\format-xml.ps1
# Date:      08/09/2006
# ---------------------------------------------------------------------
function Format-Xml {
    begin {
        function PrettyPrintXmlString([string]$xml) {
            $tr = new-object System.IO.StringReader($xml)
            $settings = new-object System.Xml.XmlReaderSettings
            $settings.CloseInput = $true
            $settings.IgnoreWhitespace = $true
            $reader = [System.Xml.XmlReader]::Create($tr, $settings)
            $sw = new-object System.IO.StringWriter
            $settings = new-object System.Xml.XmlWriterSettings
            $settings.CloseOutput = $true
            $settings.Indent = $true
            $writer = [System.Xml.XmlWriter]::Create($sw, $settings)
            while (!$reader.EOF) {
                $writer.WriteNode($reader, $false)
            $result = $sw.ToString()
        function PrettyPrintXmlFile($path) {
            $rpath = resolve-path $path
            $contents = gc $rpath
            $contents = [string]::join([environment]::newline, $contents)
            PrettyPrintXmlString $contents
        function Usage() {
            "    Format-Xml -Path <pathToXmlFile>"
            "    Formats the XML into a nicely indented form (ie pretty printed)."
            "    Outputs one <string> object for each XML file."
            "    -Path <string[]>"
            "        Specifies path to one or more XML files to format with indentation."
            "        Pipeline input is bound to this parameter."
            "    Format-Xml -Path foo.xml"
            "    Format-Xml foo.xml"
            "    gci *.xml | Format-Xml"  
            "    [xml]`"<doc>...</doc>`" | Format-Xml"
        if (($args[0] -eq "-?") -or ($args[0] -eq "-help")) {
    process {
        if ($_) {
          if ($_ -is [xml]) {
            PrettyPrintXmlString $_.get_OuterXml()
          elseif ($_ -is [IO.FileInfo]) {
            PrettyPrintXmlFile $_.FullName
          elseif ($_ -is [string]) {
            if (test-path -type Leaf $_) {
                PrettyPrintXmlFile $_
            else {
                PrettyPrintXmlString $_
          else {
            throw "Pipeline input type must be one of: [xml], [string] or [IO.FileInfo]"
    end {
        if ($Path) {
          foreach ($aPath in $Path) {
            PrettyPrintXmlFile $aPath



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" "">
<html xmlns='' xmlns:b='' xmlns:data='' xmlns:expr=''>
    <b:include data='blog' name='all-head-content'/>
Blogger Template Style
Name:     Minima
Designer: Douglas Bowman
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
 */ {
  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 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

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: at

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