/\/\o\/\/ PowerShelled

This blog has moved to http://ThePowerShellGuy.com Greetings /\/\o\/\/
$AtomFeed = ("Atom.xml")
$PreviousItems = (" Moving to ThePowerShellGuy.com "," PowerShell Code formatting test for my new Blog "," PowerShell Code formatting test for my new Blog "," PowerShell Community Extensions V1.0 "," PowerShell : Access remote eventlogs "," Windows PowerShell Scripting Sweepstakes! "," PowerShell : making Custum Enums "," TechNet Webcast: An Overview of Windows PowerShell "," "Windows PowerShell: TFM" goes "Gold" "," PowerShell : Advanced renaming of files "," ")

Tuesday, January 31, 2006


about_Switch Documentation

Jeff Jones, just provided the "Missing" Switch documentation
(See also Last Post Switch -regEx )

An interesting option is the -File switch.

gr /\/\o\/\/
Tags :

as I can not Link to the Attachement in the NG I will post the Text here as reference.


Using a switch to handle multiple if statements.


You use an If statement to make a decision in a script or program.
Essentially it says; “If this condition exists, do this action.
Otherwise do that action.” You can perform that operation as many
times as you want but if you have a long list of conditions, an If
statement quickly gets unwieldy. With a long list of conditions you
can combine them in a switch statement. As in all branching
statements, braces ({}) are required to enclose script blocks.

A switch statement is, in effect, a series of If statements. It matches
the expression with each of the conditions case by case. If a match
is found, the action associated with that condition is performed. The
switch statement, very basically, takes this form:

MSH> $a = 3
MSH> switch ($a) {
1 {"It’s one"}
2 {"It’s two"}
3 {"It’s three"}
4 {"It’s four"}
It’s three

This simple example takes a value and compares it with each condition
in the list. The action just echoes a string from the match. But you
could face a problem if you check all of the conditions.
For example:

MSH> $day = "day5"
MSH> switch ($day){
day1 {"They call it stormy Monday"; break}
day2 {"Tuesday's just as bad"; break}
day3 {"Wednesday's worse"; break}
day4 {"Thursday's oh so sad"; break}
day5 {"The eagle flies on Friday"; break}
day6 {"Saturday I go out to play"; break}
day7 {"Sunday I go out to play"; break}
day5 {"Wait, too many days."; break}

The eagle flies on Friday

There are 2 day5 conditions in the list. But the break at the end of
each condition tells the switch to stop looking further and do the
action it finds. If the break statements were not there, then both
day5 actions would take place.

If the value to switch against is an array, then each element in the
array will be evaluated in order, starting at element 0. At least
one element must be present that meets at least one condition or
an error will result. If there is more than one default clause, an
error will result.

The complete switch syntax is as follows:

switch [-regex-wildcard-exact][-casesensitive] ( pipeline )
switch [-regex-wildcard-exact][-casesensitive] -file filename
followed by
"string"numbervariable{ expression } { statementlist }
default { statementlist }

By default, if no options are used, switch behaves as if a case
insensitive exact match is in effect. If "pipeline" results in an
array, each element of the array shall be evaluated in ascending offset
order (starting at 0).

At least one conditional element must be present in the switch
codeblock and only one default clause may be present. If more than
one default clause is present, a ParseException shall be thrown.

Switch has the following options:

-regex Indicates that the match clause, if a string, is
treated as a regex string. Use of this parameter
disables -wildcard and -exact. If not a string,
this option is ignored.

-wildcard Indicates that the match clause, if a string, is
treated as a wildcard string. Use of this
parameter disables -regex and -exact. If not a
string, this option is ignored.

-exact Indicates that the match clause, if a string, must
match exactly. Use of this parameter disables
-wildcard and -regex.. If not a string,
this option is ignored.

-casesensitive Modify the match clause, if a string, to be case
sensitive. If not a string, this is ignored.

-file Take input from a file (or representative) rather
than statement. If multiple -file parameters are
used, the last one is be used. Each line of the
file is read and passed through the switch block.

Multiple uses of -regex, -wildcard or -exact are allowed, however only
the last parameter used governs the behavior.

The keyword "break" indicates that no more processing shall occur and
the switch statement shall exit.

The keyword "continue" indicates that no processing shall continue
against the current token and the next token in the conditional will
be evaluated. If no tokens are available, the switch statement will

The “{ expression }” block may be a code block that will be evaluated
at the time of the comparison. The object under scrutiny is bound to
the automatic variable "$_" and is available during the evaluation of
the expression. A comparison is considered a match if the expression
evaluations to "true". This expression is evaluated in a new scope.

The “default” keyword within the switch statement indicates that if
no matches are found, the code block that follows the keyword shall
be evaluated. Program flow shall not be allowed from stanza to
stanza (e.g., the closing “}” in the compound-list is an explicit
"break". )

If multiple matches are found, each match shall result in the
expression being executed. To avoid this, the break or continue
keywords may be used to halt further comparisons.

For information about break, enter the following command
at the MSH command prompt:

help about_break

For information about continue, enter the following
command at the MSH command prompt:

help about_continue

For information about the if conditional, enter the following
command at the MSH command prompt:

help about_if

For information about script blocks, enter the following command at
the MSH command prompt:

help about_Script_block


Switch -regEx

The Switch statement has an handy option -Regex to use a Regular expresion in it.

the About_Switch help seems missing in Beta 3 but, there is some info in the About_break Help about it.

when you type :

Help about_Break

Part of the Help contains this Example :

In this example, $var is created and initialized to a string value of
"word2". The switch statement uses regex (a regular expression .NET
class) to match the variable value first with the term "word2". Because
the variable value and the first test in the switch statement match,
the first code block in the switch statement runs. When MSH reaches the
first break statement, the switch statement exits. If the four break
statements were removed from the example, then all four conditions
would be met. Thus, this example uses the break statement to display
results when the most specific condition is met.

 $var = "word2"
 switch -regex ($var)
         write-host "Exact" $_

         write-host "Match on the prefix" $_

         write-host "Match on at least the first letter" $_

         write-host "No match" $_

This was wat I was looking for in the Dir example in Last post, Hence I came up with the work-around with scriptblocks and -Match.

I found this by using the following command :

MSH>ls $MSHHOME\*.txt | match-string "switch"
about_break.help.txt:5:    A statement for immediately exiting foreachforwhiledo, or switch
about_break.help.txt:10:    or do loop or in a switch statement, ends the code block. In the case
about_break.help.txt:12:    In the case of the switch statement, the break statement causes a code
about_break.help.txt:13:    block inside of a switch statement to exit and thus the entire switch
about_break.help.txt:69:    A switch statement is not a looping construct, but the break statement
about_break.help.txt:71:    met. For example, the following switch statement uses break statements
about_break.help.txt:75:        switch -regex ($var)
about_break.help.txt:103:    "word2". The switch statement uses regex (a regular expression .NET
about_break.help.txt:105:    the variable value and the first test in the switch statement match,
about_break.help.txt:106:    the first code block in the switch statement runs. When MSH reaches the
about_break.help.txt:107:    first break statement, the switch statement exits. If the four break
about_break.help.txt:119:    For information about the switch statement, enter the following
about_break.help.txt:122:        help about_switch
about_if.help.txt:35:    elseif statements within it, consider using a switch statement instead.
about_if.help.txt:87:    For information about the switch statement, enter the following command
about_if.help.txt:90:        help about_switch
about_Reserved_words.help.txt:20:    foreach     while        if           switch

I did find it this way before in Beta 2 but could not find it yesterday.


gr /\/\o\/\/
Tags :

posted by /\/\o\/\/

Monday, January 30, 2006


Dir, Dir and more Dir in MSH

Dir Replacement for MSH, with Attribute support, like dir in CMD does.

so now you can do things like this :

dir -ar
dir -ard
dir -ah -force

and if you take a good look.

and even one more as the CMD one does ;-)

you should remove the alias DIR first, like this :

del alias:dir

(you still will have LS or GCI, I would not replace GCI but you could also pick LS to replace)

for more info en tips about getting a directorylist from Monad see this thread :
get-childitem and file attributes...

that made me write this script, maybe I will add some more parameters later,
or autoadd -Force if H or S is found, and combine it with the colored Dir replacement elswhere on my blog)

gr /\/\o\/\/
Tags :

# Dir Function replacement with attributefilter
# /\/\o\/\/ 2006
# http://mow001.blogspot.com

function dir {
  if($args.length -ne 0) { 
    $Script:NewArgs = @()
    $Script:filters = @()
    foreach ($arg in $args) {
      Switch ($arg) {
       {$_ -match '-a'} {
          if ($_ -match 'r'){$Script:filters += ' | where { $_.attributes -match "ReadOnly"}'}
          if ($_ -match 'd'){$Script:filters += ' | where { $_.attributes -match "Directory"}'}
          if ($_ -match 'h'){$Script:filters += ' | where { $_.attributes -match "Hidden"}'}
          if ($_ -match 's'){$Script:filters += ' | where { $_.attributes -match "System"}'}
          if ($_.remove(0,2) -match 'a'){$Script:filters += ' | where { $_.attributes -match "Archive"}'}
          if ($_ -match 'n'){$Script:filters += ' | where { $_.attributes -match "NotContentIndexed"}'}
       {$_ -eq '-d'} {$Script:filters += ' | where { $_.mshiscontainer}'}
       default {$Script:NewArgs += $_}
    invoke-command("gci $Script:NewArgs $Script:filters")
  } else {

posted by /\/\o\/\/

Sunday, January 29, 2006


Simple Show-Image function for Monad

This function, will show a Image as background of a Form.

this makes it a small Picture viewer,

the static method fromFile of the .NET system.drawing.image class is used to get the Image from the filename.

The script will set the Image as background of the Form and it will size the form to the Size of the picture, if you pull it wider the picture gets tiled.

Also I Implemented a new trick to fix the focus problem, if you do not set the TopMost property of the Form to $true the form shows "hidden" behind the other forms. I did this in all the form examples for this reason.

Grzegorz Niemirowski, pointed me to a way to set this back again after the form is loaded, by using Add_shown in the NG Bringing form to front

(Oops, only when I did look up the link, I see he did the same thing allready , using a Picturebox.)


Strange I had to pick this as an example, without thinking about it, but I will post anyway, for the work and the picture of my niece ;-)

thanks Grzegorz, www.grzegorz.net

gr /\/\o\/\/

# /\/\o\/\/ 2006
# mow001.blogspot.com

Function Show-image {

  $Image = [system.drawing.image]::fromfile($filename)

  $form = new system.windows.forms.form
  $form.BackgroundImage = $image;$form.text = $Filename

  $size = $Image.size;$size.width += 8;$size.Height += 30
  $form.size = $size

  $form.topmost = $true
  $Form.Add_Shown({$form.topmost = $false})

posted by /\/\o\/\/

Thursday, January 26, 2006


MSH out-zip Function

This function will add files to a "Compressed (zipped) Folder" or will make a new ZIP file if the file does not exists.

you can use the Shell.application COM Object to add files or folders to a Compressed folder, so you can also use the CopyGUI ScriptMethod from Update-TypeData (Democracy to the types) , to add files or folders to a ZIP file, as this uses this object also.

(gi test.txt).CopyGUI("c:\mow.zip")

MSH>(gi .).copygui

Script              : $name= $args[0]
                                      #$target = (read-host "Enter Target: ")
                                      $(new-object -com shell.application).NameSpace($name).CopyHere($this.fullname)
                                      trap {"Error Copying"continue }
OverloadDefinitions : {System.Object CopyGUI();}
MemberType          : ScriptMethod
TypeOfValue         : System.Object
Value               : System.Object CopyGUI();
Name                : CopyGUI
IsInstance          : False

But only if this ZIP file does already exist.

the Out-Zip function will also Create a New ZIP file (Compressed Folder) , if it does not exist.

I made it to take file or directory objects from the pipeline so you can use it like this :

# add all textfiles in Dir to Mow.zip
ls *.txt | out-zip c:\mow.zip

#add Monad directory to zipfile
cd g:\monad
gi . | outzip c:\mow.zip

(more like a filter)

the script looks like this :

# Out-Zip.msh
# creates out-Zip function
# /\/\o\/\/ 2006   
# http://mow001.blogspot.com

function out-zip {

  if (-not $path.EndsWith('.zip')) {$path += '.zip'}

  if (-not (test-path $path)) {
    set-content $path ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
  $ZipFile = (new-object -com shell.application).NameSpace($path)
  $input | foreach {$zipfile.CopyHere($_.fullname)}


gr /\/\o\/\/

Tags :

posted by /\/\o\/\/

Monday, January 23, 2006


get a Users LastLogontime and Domaincontroller from MSH

This script will check all Domaincontrollers for the lastlogontime of a user.

I started this script a while ago (see Monad(MSH) Beta 3 is getting closer ), after this (How can I determine the last time a user logged on to Active Directory? ) scripting guys article.

I wanted to do this in 4 lines from MSH, but I had some problems getting the IADsLargeInteger value (the LastLogon property is stored like one), but as I have written a Snap-in for this, (See
MSH snap-in to Translate IADsLargeInteger to Int64 ), I could now finish it.

This script is not 4 lines, first for readability, and I decided to do some timing in the script also.

the script will list the last logontime from every domaincontroller and keeps a counter running that keeps the time, as I was running this on a worldwide 200 + DC's Domain, I was interested in timing this.

the Output looks like this :

00:00 Site172DC002.Domain.mow.com Never
00:00 Site173dc002.Domain.mow.com Never
00:00 Site172dc001.Domain.mow.com Never
00:03 Site101dc000.Domain.mow.com Never
06:25 Site101dc002.Domain.mow.com 2005-12-27 13:40:45
06:25 Site101dc001.Domain.mow.com 2005-12-27 13:41:25
06:25 Site102dc000.Domain.mow.com Never
06:25 Site105dc002.Domain.mow.com Never
06:27 Site107dc001.Domain.mow.com Never
06:30 Site123dc000.Domain.mow.com Never
06:35 Site143dc001.Domain.mow.com Never
06:39 Site153dc001.Domain.mow.com Never
06:41 Site163dc001.Domain.mow.com Never
06:42 Site101dc001.Domain.mow.com Never
06:43 Site105dc001.Domain.mow.com Never
06:45 Site144dc001.Domain.mow.com Never
06:45 Site108dc002.Domain.mow.com 2006-01-23 12:10:35
06:45 Site154dc000.Domain.mow.com Never
06:46 Site113dc001.Domain.mow.com Never
06:46 Site183dc001.Domain.mow.com Never
06:46 Site133dc001.Domain.mow.com Never

Checked 231 DC's for CN=Mow08946,OU=Users,OU=MowOU,DC=Domain,DC=Mow,DC=com in 06:47 Minutes

Server Last Logon : Site108dc002.Domain.mow.com at 2006-01-23 12:10:35 

(ofcourse I scrabled this a bit, any double DC's are my mistake, not Monads ;-) )

the final script looks like this :

# Check-LastLogon.MSH  
# check all Domaincontrollers for the lastlogontime of a user 
# Uses the Get-IADsLargeInteger Snapin you can find here :
# http://mow001.blogspot.com/2006/01/msh-snap-in-to-translate.html
# /\/\o\/\/ 2006  
# http://mow001.blogspot.com 

# fill in full DN of user

$DN = "CN=Mow08946,OU=Users,OU=MowOU,DC=Domain,DC=Mow,DC=com"

# Gets UTC offset to translate lastlogon time from UTC to local
$UtcOffset = [timezone]::CurrentTimeZone.GetUtcOffset($(get-date)).hours

# Get All Domaincontrollers 

$dom = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$dcs = $dom.DomainControllers

# Add stopWatch for Timing

$sw = new-object System.Diagnostics.Stopwatch

# Find Lastlogon times 

[dateTime]$MaxLogon = "1-1-1980"
$dcs | foreach {

    # Connect to Domain Controller 

    $de = new-object System.DirectoryServices.DirectoryEntry("LDAP://$($_.name)/$DN")
    # here we do some translations to get the LargeInterger to a Local DateTime Object

    $LastLogon = "Never"
    $LastLogon = ([datetime]::FromFileTime((Get-IADsLargeInteger $de.get_Properties()["LastLogon"].Value))).AddHours($UtcOffset)

   # Display Time-running DC name and Time 

   $timeRunning = [datetime]::parse($sw.Elapsed).tostring("mm:ss")
   "$TimeRunning $($_.name) $LastLogon"

   # update $maxlogon if found date is later

   if ($maxlogon -lt $LastLogon) {$maxlogon = $LastLogon;$LastServer = $_.name}

# Stop Timing 

$timeRunning = [datetime]::parse($sw.Elapsed).tostring("mm:ss")

# Display Summary

"`nChecked $($dcs.count) DC's for $dn in $timeRunning Minutes"
"`nServer Last Logon : $LastServer at $maxlogon" 

what did you say !!, ... 5 Lines ???

Oops, I overdid the commenting since then LOL :-)

but, remember the scripting guys example only outputs the lastlogon time in the end,
if you remove the comments, timekeeping and status output there is not much left ;-)

$DN = "CN=Mow08946,OU=Users,OU=MowOU,DC=Domain,DC=Mow,DC=com"
$UtcOffset = [timezone]::CurrentTimeZone.GetUtcOffset($(get-date)).hours
$dom = [System.DirectoryServices.ActiveDirectory.Domain]::getcurrentdomain()
$dcs = $dom.DomainControllers
[dateTime]$MaxLogon = "1-1-1980";$dcs | foreach {trap{continue};$de = new-object System.DirectoryServices.DirectoryEntry("LDAP://$($_.name)/$DN")
    $LastLogon = ([datetime]::FromFileTime((Get-IADsLargeInteger $de.get_Properties()["LastLogon"].Value))).AddHours($UtcOffset)
    if ($maxlogon -lt $LastLogon) {$maxlogon = $LastLogon;$LastServer = $_.name}


gr /\/\o\/\/
Tags :

posted by /\/\o\/\/

Sunday, January 22, 2006


Some fun With Monads Add-Member, MP3 files and COM

In Monad Beta 3 there is a new command,


This command lets you add you Custom Members to an MSHObject (the wrapper MSH uses).
It works a bit like adding ScriptMethods and Properties in the Typedata (See : Update-TypeData (Democracy to the types)), but now you can do this on-the-fly.

Also it's a bit like using the Select-Object statement to make Custom Properties, I used before here : Report MP3 count and size by User from MSH , I going to use the Same Data (A list of MP3 files on a Disk) to show some Examples of Add-Member to get some more info from them as Artist, Title and add a Play Method.

First lets get the list :

$computer = "."
$drive = "G:"
$Extension = "MP3"

# get the MP3 Files

$files = get-wmiobject -computer $computer cim_datafile -filter "Drive = '$drive' AND Extension = '$Extension'"

MSH>$files | ft

     Compressed       Encrypted Size                     Hidden Name                  Readable System File    Version             Writeable
     ----------       --------- ----                     ------ ----                  -------- -----------    -------             ---------
          False           False                           False g:\monad\74q...           True                                         True
          False           False                           False g:\mp3\80-12...           True                                         True

Now we have a list of MP3 files, but I do not like the Standard Output.
For MP3 files I would like Other Properties,
like Author, that the standard output does not provide but as I know that the Shell.Application COM-object can provide this Info I can Add it with Add-Member using a scriptProperty, like this :

# Add a Script Property

$files | add-member -Type scriptProperty "Author" {
  $shell = new-object -com shell.application
  $Folder = $shell.Namespace($this.drive + $this.path)
  $file = $Folder.Items().Item($this.filename + "." + $this.extension)
  $Property = $Folder.GetDetailsOf($file,9)
  return $Property
} -force

Now I added that ScriptProperty and can do like this :

Dire Straits

Now every time I ask for the Author scriptproperty like that, the scriptMethod gets called, and gets the Author.

I would like to add some more properties, but would not like every time I check them the Script will run, So I will add some more properties but now I use a NoteProperty, that I fill only one time with the script(I add an ID too, you see why later ;-)).

# Add some More Properties, but use NoteProperties this Time

$shell = new-object -com shell.application
$i = 0 
foreach ($file in $files) {
  add-member -in $file -type noteProperty -name "ID" $i -force
  foreach ($prop in (@{Title = 10;Artist = 9;AlbumTitle = 17}).getEnumerator()) {
    $oFolder = $shell.Namespace($file.drive + $file.path)
    $oFile = $oFolder.Items().Item($file.filename + "." + $file.extension)
    $Property = $oFolder.GetDetailsOf($oFile,$script:prop.Value)
    add-member -in $file -type noteProperty -name $prop.key $Property -force
  $i += 1

Now I added some more Properties, If you do a get-member you can see that,
but We can make it even more Handy we can group our properties in a propertyset.

# Make a PropertySet from them 

$files | add-member --type PropertySet "Mp3Info" ([string[]]("ID","Title","Artist","FileType","AlbumTitle","Path")) -force

MSH>$files[50] | select mp3info

ID         : 50
Title      : Skateaway
Artist     : Dire Straits
FileType   : MP3 Format Sound
AlbumTitle : Making Movies
Path       : \mp3\dire straits\dire straits (1980) - making movies\

Nice or not ?,
but Wait we are not ready yet, We can also add ScriptMethods, so to make it even more handy, let's Add this :

# Add The Play Method

$files | add-member -Type scriptMethod "Play" {$WMP = new -com "WMPlayer.OCX";$wmp.openplayer($this.name)}

Now we can Also call the PLay() method on the MP3 file to play it in Windows Media PLayer.

# play SurfCity from the GhostTones 
($files |  where {$_.artist -eq "The Ghosttones" -and $_.Title -eq "Surf City"}).play()

Cool or not ?,
this just plays 1 file, but as you can also make playlist etc from here, for more info about using the windows MediaPlayer here :

Monad Really Does Rock

Now you can also see why I did add the ID value :

MSH>$files | where {$_.artist -like "*Brood*"} | ft mp3info

                     ID Title                   Artist                 FileType               AlbumTitle             Path
                     -- -----                   ------                 --------               ----------             ----
                    623 Never Be Clever         Herman Brood           MP3 Format Sound       Nederpop Top 100 Go... \MP3\NL\Neder....
                    647 Still Believe           Herman Brood & His ... MP3 Format Sound       Nederpop Top 100 Go... \MP3\NL\Neder....
                    666 Saturday Night          Herman Brood & His ... MP3 Format Sound       Nederpop Top 100 Go... \MP3\NL\Neder....

You can see Add-Member is a very Powerfull way to extend Objects in MSH.
And remember if you want them permanent you can also use the MSHXML files and update-typedata.

gr /\/\o\/\/
Tags :

posted by /\/\o\/\/

Saturday, January 21, 2006


MSH snap-in to Translate IADsLargeInteger to Int64

As I mentioned before ( Monad(MSH) Beta 3 is getting closer )I was looking for a way to get to LargeInteger values from AD in MSH,

I could not read the Com-Object from MSH, see also this Thread : accesing IADsLargeInteger
As I needed the Logon date from AD that is a LargeInteger Value.

I still did not find a way, but since MSH now supports snap-in's I decided to write one for it.


I't will cast the IADsLargeInteger COM-object to a Long (Int64) so we can use it from MSH, from there it's easy to get the Date,

So now I can get to the PwdLastset property like this (as I'm using Adam for testing, this accounts Logon values are not filled, that's why I use that in this example)

MSH>$de = New System.directoryservices.DirectoryEntry("LDAP://localhost:389/cn=mow,ou=mowOu,dc=mow,dc=adam")
MSH>$li = $de.get_Properties()["pwdlastset"].Value
MSH>Get-IADsLargeInteger $li
MSH>$long = Get-IADsLargeInteger $li

maandag 21 november 2005 1:11:42

Let's get to the making of the Snap-in,
I First made the Snap-in in C#, following the example in the getting started.

it looks like this :

// MSH snapin to get an IADsLargeInteger object to an Int64
// /\/\o\/\/ 2006
// http://mow001.blogspot.com

using System;
using System.ComponentModel;
using System.Management.Automation;
using System.Reflection;

namespace mow
    // This class defines the properties of a snap-in
    public class getIADsLargeInteger : MshSnapIn
        /// Creates instance of DemonSnapin class.
        public getIADsLargeInteger() : base() { }
        ///Snapin name is used for registration
        public override string Name
        { get { return "getIADsLargeInteger"; } }
        /// Gets vendor of the snap-in.
        public override string Vendor
        { get { return "MOW (http://mow001.blogspot.com)"; } }
        /// Gets description of the snap-in. 
        public override string Description
        { get { return "Gets a IADsLargeInteger"; } }
    /// Gets a IADsLargeInteger
    public class getIADsLargeIntegerCommand : Cmdlet
        [Parameter(Position = 0, Mandatory = true)]
        public object  LargeInteger
            get { return largeInt; }
            set { largeInt = value; }

        private object largeInt;

        protected override void EndProcessing()
            ActiveDs.IADsLargeInteger li = (ActiveDs.IADsLargeInteger)largeInt ;
            long lng = (long)((uint)li.LowPart +(((long)li.HighPart) << 32));

But how to get this into MSH as a working snap-in, this takes a few steps.

First save the C# code above in getIADsLargeInteger.cs, in the MSH program directory,
e.g. : "C:\Program Files\Microsoft Command Shell\v1.0"

then, It uses the ADSI typelibrary to "translate" the ADSI Com-object so We need to provide that also, it is the following DLL,


the most easy way is to get this DLL, is to start a project in VS 2005 and add the ADSI typelibrary as a reference.( Project -> Add reference -> COM)

if you then build the project the DLL is generated in the Bin directory, also you can use the commandline too tblImp for this.

Copy this DLL to the Monad Directory also.
Now we can past the following code into the MSH Console to compile the Snap-in :


$compiler = "$env:windir/Microsoft.NET/Framework/v2.0.50727/csc"
$ref = "$MSHHOME/System.Management.Automation.dll"
$ref2 = "$MSHHOME/Interop.ActiveDs.dll"
&$compiler /target:library /r:$ref /r:$ref2 getIADsLargeInteger.cs

Now a DLL is created, getIADsLargeInteger.dll

Now we need to install it first with the installutil,
and then we can add it to the MSH-shell.

# install Snap-in

set-alias installutil $env:windir\Microsoft.NET\Framework\v2.0.50727\installutil
installutil getIADsLargeInteger.dll

# Load the Snapin

add-mshsnapin getIADsLargeInteger

And now we are ready to use the Snap-in as in the Example we started with, and are able to get the Dates we need from AD.
and as this snap-in is loaded in MSH now, it will even show up in get-command :

Cmdlet Get-IADsLargeInteger Get-IADsLargeInteger [-LargeInteger] Object [-Verbose] [-D...

and Get-IA [Tab] will work also !!

I still hope there will be a way to do this from MSH, I can load the typelibrary, I do not know why the same trick does not work in MSH,
but this will get me going, and making my first Snap-in in MSH was also a nice adventure, as this was also my first C# project.

gr /\/\o\/\/
Tags :

posted by /\/\o\/\/

Friday, January 20, 2006


Commandline editing with MSH.

There is a discussion going on now, and has been before at the newsgroup about the Commandline editing posibilities in MSH,

MSH runs on the cmd.exe console(at least till V2), hence has the same capabilities and limitations, and yes they are a bit oldfasioned and limited as CMD.exe was neglected a (whole) bit (to much) in windows.

And now with the power of MSH on the Commandline, we notice that even more, the Monad team has also pointed this out as a high priority for V2 in the NG.

but still I think CMD console is not as limited as most people think.

so I will give some tricks I find handy here,

I hear a lot of complains about the Cut-and-Past handing in the Console, but I realy love it ;-)
but not in it's "standard" form, I set it in Quick-edit Mode, It's realy the first thing I do change.

The complaint is the Ctrl-C ctrl-V does not work, you need to use the mouse to choose copy or Past from the Menu.

or you can use the keyboard shortcut

Copy :
Alt-Enter -> E -> (Y or Enter)

Paste :
Alt-Enter -> E -> P

As the scrolling Example, I made a work-a-round function for in last post, MSH Scroll-host function , (I Edited it, to remove the Key-echo workaround) that's not very handy

But here there is a better solution this time , setting QuickEdit Mode :

And while I'm at it, I also set the Buffer and Window Size.
set the buffer to 9999 (ignore the warning) to keep a long history of output.

Now you can just left-click and drag to select, and just right-click to paste.

that's what I realy like, while writing a script I do this a lot to past tested lines to Notepad.

also in MSH I just paste complete scripts to the console. (that get's it in my history also)
MSH will Nicely parse them, anly look out for Tabs in the Pasted code they will be parsed as typed so this wil trigger Tab-Completion !!
this will give very strange effects, but I never use tabs in my code so it's not a problem for me, only sometimes when I past in "Strange" code from somewhere that does.

another Tip I want to mention is using the function key's and arrows.

try F7 this will give a list of the command history,

In this Image you see the List shown as you press F7 in the console.
you can use the arrows and page-up page down to walk, Enter to run the Line and Right-arrow to just copy the line to the console.

Also note that in this session, I First tested a single line of the script of last post, when it was OK I pasted it to notedpad, and Just pasted the whole script back into the MSH shell to test.

also all the variables are in the Global scope (as MSH does think I did type them) so I can chack the values or paste in parts of the code again when I changed variables)

the QuickEdit Mode makes this very Quick and because can select rectangles in MSH you can leave out the prompt.

I love this way to work.

only gotha is for example a foreach
you can not do this
$a foreach
"do something"

as when you work "interactive" (as we fake this by just pating code in) you need to provide the { on the same line

$a foreach {
"do something"

so thats why you see me do that a lot in my code, it's a bit less readable but much more handy in testing as the last example I can just past on the commandline to test.
for the first example I need to save the textfile and run the script.

then if you have to change a past of the current command you can use use delete, change the part of the line and use F1 or the right arrow to fill it on with characters of the old line, this is very handy also.

So you see,
QuickEdit needs some getting used to, but if you get the hang of it, its very easy to work with.
or even can't live without it again (I would not want to change it for Ctrl-C / crtl-V).

and there are also some handy shortcuts for editing lines in CMD
(try the other Function key's but most you can do also with the arrows)


gr /\/\o\/\/
Tags :

posted by /\/\o\/\/

MSH Scroll-host function

The only way to scroll by keyboard (without a mouse) in the command console, hence in MSH Is by using the following combination of key's

Alt-Space, E, L

this is not very handy

after I saw a post about this in the NG, I made this function scroll-host (alias S), to simplify it a bit, after you run this script

S [enter]

is enough to get into scrolling mode , Space will stop the scollingmode and jump back to the last line.

# Scroll-Host.msh 
# creates Scroll-Host Function 
# /\/\o\/\/ 2006 
# http://mow001.blogspot.com 

Function Scroll-host { 

  $Oldpos = $host.ui.rawui.CursorPosition 

  while ($true) { 

    $script:pos = $host.ui.rawui.CursorPosition 
    $key = $host.ui.rawui.ReadKey("NoEcho,IncludeKeyDown").VirtualKeyCode

    # Quit on Space Enter or Escape

    if ($key -eq 32 -or $key -eq 13 -or $key -eq 27) {
        $host.ui.rawui.CursorPosition = $oldpos;break}

    # Handle Cursor 

    switch ($key) {
      38 {$script:pos.y -=1
      40 {$script:pos.y +=1
      33 {$script:pos.y -= ($host.ui.rawui.windowsize.height -1)} 
      34 {$script:pos.y += ($host.ui.rawui.windowsize.height -1)} 

    if ($script:pos.y -lt 0) {$script:pos.y = 0
    if ($script:pos.x -lt 0) {$script:pos.x = 0
    if ($script:pos.y -gt ($host.ui.rawui.buffersize.Height - 1)) {
            $script:pos.y = ($host.ui.rawui.buffersize.Height - 1)} 
    $host.ui.rawui.CursorPosition = $script:pos 

set-alias s scroll-host

the trick part was that I could not get rid of the Key press echoed to the screen, so I remove it after, by buffering the character that was there before.

*edit* , I got a helpfull comment from "Monad Jim", so I could remove the "ugly" character removing work-around :

# Read the key and remove the output of this

$TempPos = $host.ui.rawui.CursorPosition
$re = new-object $rect $TempPos.x,$TempPos.y,1,$TempPos.y
$buffer = $host.ui.rawui.getbuffercontents($re)
$key = $host.ui.rawui.ReadKey().VirtualKeyCode


gr /\/\o\/\/
Tags :

PS. Yes, I could have used a switch statement for the keycheck, also you could add enter to quit also as in the original, it's that lazy thing again ;-).

*Edit* as I removed the echo comment I did those changes also.

posted by /\/\o\/\/

Tuesday, January 17, 2006


Series about Monad on Computerworld

On computerworld a 4 part series about Monad has started,
Hands On: Learning Monad, the scripting language for Windows Vista
it is Excerpted from the O'Reilly Media Inc. book Monad by Andy Oakley
so its a good read if you are starting with Monad and will give you an impression of the book also.


gr /\/\o\/\/

posted by /\/\o\/\/

Watching FSRM Quota and filescreen events from Monad

With Windows 2003 Server R2 comes FSRM (File Server Resource Manager),

(for more info White paper on storage management in R2, or about FSRM Step-by-Step Guide for File Server Resource Manager .)

you can send alerts with FSRM by Mail, Eventlogs and running a command.

but with FSRM you can also get the events by some new WMI Classes.


I used Get-WmiClasses from Wmi-Help Part 1 , to list them (we installed nothing more on the R2 server as FSRM)

(its easy to use this script remote by filling in the Path in the Managementscope declaration)
$MS = new-object system.management.ManagementScope(\\server\root\cimv2)

I made 2 hashTables from this script, and did compare them like this :

MSH C:\MowMSH> $ClassesR2.keys | select @{expression={$_}; name="R2"},@{expression={$classesW2k3.ContainsKey($_.tostring())}; name="2k3"} | where {$_.'2k3' -eq $false}

R2                                                                             2k3
--                                                                             ---
win32_quotalimitevent                                                        False
win32_quotathresholdevent                                                    False
win32_filescreenevent                                                        False
win32_quotaevent                                                             False

from there on it was easy, I just modified this script a bit :MSH Cluster Watcher script

now it looks like this,

# watch-QuotaEvent.msh 
# watches for WMI events
# parameters are prefilled for watching R2 FSRM events.  
# /\/\o\/\/ 2005 

'Param ($server = "server", $class = "win32_quotaevent")
Param ($server = "server", $class = "Win32_FileScreenEvent")

Function Main {
  "Watching $server, Press Any Key to Quit"
  trap {Break}

  # Make a WMI Connection to the R2 server

  $ms = new-object system.management.managementscope
  $ms.path = "\\$server\root\Cimv2"

  # Make Event Watcher

  $ew = new-object system.management.ManagementEventWatcher
  $ew.scope = $ms
  $ew.query = "SELECT * FROM $Class WITHIN 10"

  $opt = new-object System.Management.EventWatcherOptions
  $opt.Timeout = [timespan]::FromSeconds(1)
  $ew.options = $opt

  # Wait for event :

  while (!$host.ui.rawui.KeyAvailable){
    $e = $null
    $e = $ew.WaitForNextEvent()
. main

you can use the parameters, but as a good admin is lazy, I just made 2 copies and prefilled the parameters ;-)

so in 10 Minutes (test-Quota where running already) I could catch Quota and Filescreen events in MSH like this :

MSH C:\MowMSH> .\FSWatch.msh
Watching Server, Press Any Key to Quit

FileScreenFlags      : 1
FileScreenGroup      : Audio and Video Files
FileScreenPath       : F:\MowTestData
FileScreenSystemPath : \\?\Volume{3afa528a-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\MowTestData
SourceFileOwner      :
SourceFileOwnerEmail :
SourceFileOwnerSid   :
SourceFilePath       : F:\MowTestData\test.mp3
SourceIoOwner        : Domain\Mow
SourceIoOwnerEmail   : mow001@hotmail.com
SourceIoOwnerSid     : S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxx-xxxxxxx
SourceProcessId      : 4
SourceProcessImage   : System Process
TIME_CREATED         : 127819666365994053
__GENUS              : 2
__CLASS              : Win32_FileScreenEvent
__SUPERCLASS         : __ExtrinsicEvent
__DYNASTY            : __SystemClass
__RELPATH            :
__DERIVATION         : {__ExtrinsicEvent, __Event, __IndicationRelated, __SystemClass}
__SERVER             :
__NAMESPACE          :
__PATH               :


MSH C:\MowMSH> .\QuotaWatch.msh
Watching Server, Press Any Key to Quit

QuotaFlags           : 256
QuotaFree            : 191488
QuotaHighWaterMark   : 261952512
QuotaHighWaterTime   : 20060117120104.452558+060
QuotaLimit           : 262144000
QuotaOwner           :
QuotaOwnerEmail      :
QuotaOwnerSid        :
QuotaPath            : F:\MowTestData
QuotaSystemPath      : \\?\Volume{3afa528a-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\MowTestData
QuotaUsed            : 261952512
SourceFileOwner      :
SourceFileOwnerEmail :
SourceFileOwnerSid   :
SourceFilePath       : F:\MowTestData\Copy of srv03_r2_2075_usa_x86fre_adsr2.iso
SourceIoOwner        : domain\mow
SourceIoOwnerEmail   : mow001@hotmail.com
SourceIoOwnerSid     : S-1-5-21-xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxx-xxxxxxx
SourceProcessId      : 4
SourceProcessImage   : System Process
TIME_CREATED         : 127819656645306841
__GENUS              : 2
__CLASS              : Win32_QuotaLimitEvent
__SUPERCLASS         : Win32_QuotaEvent
__DYNASTY            : __SystemClass
__RELPATH            :
__DERIVATION         : {Win32_QuotaEvent, __ExtrinsicEvent, __Event, __IndicationRelated, __SystemClass}
__SERVER             :
__NAMESPACE          :
__PATH               : 

this gives the possibility do handle the events a custom way,
a very powerfull capability.

as we are testing R2 FSRM for Quota management, it is likely we need to script some policies and reports also, this is also very powerfull but there are commandlinetools for it.

main reason is we need more flexibility in mail scheduling.
(Standard 1 hour) and policy configuration.

but the scripting possibilities of FSRM look very promising for this.

gr /\/\o\/\/

Tags :

posted by /\/\o\/\/

Monday, January 16, 2006


More ACL and MSH on MSH for Fun

and the next episode in our combined series ;-)

MSH For Fun: Combination Rights, Inheritance and Propagation Settings of File System Access Rules

I have another one in the pipeline ;-)

gr /\/\o\/\/

posted by /\/\o\/\/

Sunday, January 15, 2006



Very Cool

posted by /\/\o\/\/

Monad and "Jeugd sentiment"

I did not know the Right word for "Jeugd Sentiment" in english , but it's strange how much "Old stuff" comes up while playing with Monad, and how much it made me think back.


playing with the RawUI (sprites etc. on my Atari)
Wipe the screen in MSH
Thow Dices in MSH
Atari Laptop (no MSH content)

Oneliner compititions.
GUI folder copy tool

my BBS time (RA ASCI graphics)
MSH Welcome screen (*edit* b.t.w. I was looking for a Drawing program for ASCI to draw boxes etc, I remember one from that time, but the Welcome screen was made from a Bitmap converter I find while searching for one, I did not found it Yet any recomendations ? plz leave a comment.)

my IRC time (running #dutch (nick still MRC then)
Monad IRC Bot

and I see I'm not the only one (rember aliens ?).

and yesterday, as I did see this post on Lee Holmes blog : Monad hosting, an introduction

You see the Turtle ?!?!

again I found myself thinking back,

remembers me about the "Open Dagen" (introduction days) at school, where we did some Logo Demos, to interest new students for the Computerlessons.

how longer I play with Monad, the more I remember how much I misssed a good Shell to play with.

gr /\/\o\/\/

*edit* Oops I did almost forget VIM, as I used to carry a diskette with VI.exe (or Com) with me all the time at school, after starting with it programming INFORMIX on my Stage.
I slided back into notepad, but going back to it with VIM now with MSH.

Tags :

posted by /\/\o\/\/

Monad Beta 3 Docs changes

In the beta 3 doc's only the getting started is updated,
and not that much has changed.

I did a quick check for the changes by browsing the printed copies, head-to-head

I will list the mayor changes I found :

Page 16 Added $True / $False parsing
Note the catch with -eq True !

Page 18 - Added more parsing info

Page 41 - 4 new policy variables $ReportError*

Page 43 - Changed text : Writing to Console paragraph Changed
- Added : Pipelines of data added (from winFX site ?)

Page 63 - Added reference to Add-Member in get-help

Page 71 - Added : Add-member / add-MshSnapin / Export Console
Page 73 - Added : get-MshSnapin
Page 75 - added : Remove MshSnapin

Page 82 - 83 - Added Extending the shell with MshSnapins

Page 84 - Added Appendix D - Creating a MshSnapin.

Note that this list does not pretend to be complete, I only posted it as a help for a Quickscan of the documentation changes, I did not list small changes in sentence structure etc.
I I did this by hand so I can have missed something.

gr /\/\o\/\/
Tags :

posted by /\/\o\/\/

Thursday, January 12, 2006


Get SpecialFolder Locations in Monad

I did think of this function a while ago but this did not work in Beta 2,
There used to be a bug where MSH wouldn't find nested types (note the + sign)


this Enum is used by [Environment]::GetFolderPath to get the Path of a special folder.
so with a small function like this :

function get-SpecialFolder {

you can now easy get a path to a special folder.

MSH>get_SpecialFolder history
C:\Documents and Settings\mow\Local Settings\History

if it does not exist you get a list of possibel values (by converting it in the parms section.

MSH>get_SpecialFolder foo
get_SpecialFolder : Cannot convert "foo" to "System.Environment+SpecialFolder" due to invalid enumeration values. The possible enumerationvalues are "Desktop, Programs, Personal, MyDocuments, Favorites, Startup, Recent, SendTo, StartMenu, MyMusic, DesktopDirectory, MyComputer, Templates, ApplicationData, LocalApplicationData, InternetCache, Cookies, History, CommonApplicationData, System, ProgramFiles, MyPictures, CommonProgramFiles"
.At line:1 char:18+ get_SpecialFolder <<<< foo

gr /\/\o\/\/

Tags :

posted by /\/\o\/\/

Wednesday, January 11, 2006


Filling Emty Properties in AD from MSH

As I was testing again on my ADSI LargeInterger problem, see Monad(MSH) Beta 3 is getting closer

B3 did not solve this, I did Impoort the ADSI typelibrary but I did not mentioned to do it yet.

But as I used Adam for testing (see Monad and Adam (and a preview of my to-be AD provider)

My user object kind was of empty.

I was missing a lot of properties, for example the first and lastname.
becouse you will not get them back if they are not set.

you can see in the samples below how to get those properties filled,
first I used ADSIEdit to fill Firstname (Givenname) and lastname (sn),

You can see that after a RefreshCache() in MSH, I can see the New Properties,

you can also "create" the property by filling it with invokeset()

$mow = new-object system.directoryservices.directoryentry("LDAP://localhost:389/cn=mow,ou=mowOu,dc=mow,dc=adam")


# did fill the First and Last Name with ADSIEdit


# Making the new Property



PropertyName                       Value
------------                       -----
sn                                 SurName
givenName                          Mow
objectClass                        {top, person, organizationalPer...
cn                                 mow
street                             MowDrive
distinguishedName                  CN=mow,OU=MowOu,DC=mow,DC=adam
instanceType                       4
whenCreated                        11/21/2005 12:11:42 AM
whenChanged                        1/11/2006 8:43:21 PM
displayName                        mow
uSNCreated                         System.__ComObject
uSNChanged                         System.__ComObject
name                               mow
objectGUID                         {161281039722423859...
badPwdCount                        0
badPasswordTime                    System.__ComObject
pwdLastSet                         System.__ComObject
objectSid                          {15002224157174, ...
objectCategory                     CN=Person,CN=Schema,CN=Configur...
nTSecurityDescriptor               System.__ComObject

for now I used ADSIEdit to look up the property values, but ofcourse we get get them from Monad too , by looking at the schema, more about that later.

gr /\/\o\/\/

Tags :

posted by /\/\o\/\/


October 2005   November 2005   December 2005   January 2006   February 2006   March 2006   April 2006   May 2006   June 2006   July 2006   August 2006   September 2006   October 2006   November 2006   December 2006  

$Links = ("PowerShell RC1 Docs"," PowerShell RC1 X86"," PowerShell RC1 X64"," Monad GettingStarted guide"," Monad Progamming Guide"," Monad SDK"," Monad videos on Channel 9"," MSH Community Workspace"," scripts.readify.net "," MonadSource"," www.reskit.net"," PowerShell Blog"," Under The Stairs"," computerperformance powershell Home"," proudlyserving"," MSH on wikipedia"," MSHWiki Channel 9"," Keith Hill's Blog"," Precision Computing"," PowerShell for fun"," MSH Memo (Japanese)"," monadblog")

find-blog -about "PowerShell","Monad" | out-Technorati.
find-blog -contains "","" | out-Technorati.
Web mow001.blogspot.com

This page is powered by Blogger. Isn't yours?