Cash Talks - BS Walks RSS 2.0
# Wednesday, 16 January 2008

Today I went in search of a PowerShell script to calculate the size of a directory.  I was amazed to find very little.  Even worse, I was disappointed in what I found.  Here’s an example:


Cleaned up a little it looks like:


function Get-DirectorySize


      param ($path = {(Get-Location).Path})


      $size = Get-ChildItem $path -recurse -force `

            | ? { $_.GetType() -like 'System.IO.DirectoryInfo'} `

            | % {$_.GetFiles() } `

            | Measure-Object -Property Length -Sum `

            | Measure-Object -Property Sum -Sum 


      $size2 = (Get-item $path).GetFiles() `

            | Measure-Object -Property Length -Sum 


      [System.Math]::Round(($size.Sum + $size2.Sum) /  (1024 * 1024)).ToString() + "MB"



Returning a String is ridiculous.  If you are going to all the trouble of using Measure-Object you might as well get a rich output.


function Get-DirectorySize


      param ($path = {(Get-Location).Path})


      Get-ChildItem $path -recurse -force `

            | ? { $_.GetType() -like 'System.IO.FileInfo'} `

            | Measure-Object -Property Length -Sum -Average -Minimum -Maximum`



This is cleaner and has more interesting output providing an aggregated object with Sum, Average, Minimum and Maximum properties.  However, the biggest problem is that is extremely SLOW.  Try to use this on a directory with thousands of small files.  Even worse, try to use it on a network path with thousands of small files!


This approach tries to leverage all the cool PowerShell piping and CmdLets.  I prefer these to the old school VBScript and COM object approaches.  However, sometimes old school beats new school. 


function Get-DirectorySize


      param ($path = {(Get-Location).Path})


      if (! $GLOBAL:_FileSystemObject)


            $GLOBAL:_FileSystemObject = New-Object -comobject "Scripting.FileSystemObject"





The old FileSystemObject is hard to beat for this kind of job.  In this example, I assure I don’t have to make more than one FileSystemObject. 


function Get-DirectorySize




            if (! $GLOBAL:_FileSystemObject)


                  $GLOBAL:_FileSystemObject = New-Object -comobject "Scripting.FileSystemObject"


            $accumulation = 0




            if ($_ -eq $null)


                  $_ = (Get-Location).Path



            if ($_ -is [System.IO.DirectoryInfo])


                  $_ = $_.FullName



            $accumulation += ($GLOBAL:_FileSystemObject.GetFolder($_)).Size








This final example is Pipeline friendly and marshals a DirectoryInfo parameter.  This function is very flexible and should be as fast as you are going to get. 


NOTE:  $accumulation accumulates multiple directories in the pipeline, not individual file sizes.


Related Post: Analyze Hard Drive Extensions with PowerShell

Wednesday, 16 January 2008 14:17:35 (GMT Standard Time, UTC+00:00)  #    Comments [1420] -
# Wednesday, 12 December 2007

I haven’t posted anything in a while but it’s not because I’ve been idle.  I’ve been doing a massive amount of PowerShell and will be blogging some real cools stuff in the coming weeks.


For now, I’m offering a little tidbit I wrote yesterday for reading a file into a binary byte array.  It was necessary for Publishing RDL files in Sequel Server Reporting Services – more on that later too.


function read-filebytes($fileItem={Throw "fileItem is required for read-filebytes"})


  try {

    []$stream = []::OpenRead($fileItem.fullname)

    try {

      [byte[]]$filebytes = New-Object byte[] $stream.length

      [void] $stream.Read($filebytes, 0, $stream.Length);


    } -finally {



  } -catch {

    Write-Error "Error reading file $fileItem - $_"





I’m using the TryCatchFinally Cmdlet it’s really made error management much easier.


The real trick to this script is:


  [byte[]]$filebytes = New-Object byte[] $stream.length


This pre-allocates the memory for the Stream Read method.  Not a common technique in PowerShell.



Wednesday, 12 December 2007 23:19:29 (GMT Standard Time, UTC+00:00)  #    Comments [38] -
# Saturday, 13 October 2007

Omar Al Zabir wrote a Code Project article entitled Deployment made simple using Powershell where I added the following comment. 

I've been using and extending NAnt for 4 years. It has some really nice things and I've done some amazing things with it. However, my current strategy is to leave it. - It's just converting all my existing stuff that will make it painful and slow.

We plan to use MSBuild for Build Control and PowerShell for Deployment. Currently we use NAnt for both of these things.

The worst thing about NAnt and MSBuild is it's XML. The semantics of the language are limited by XML. XSLT is powerful but painful for the same reason. Neither language supports IF, THEN, ELSE because of the constraints of XML. The most glaring problem with these languages is the lack of Parametrized control. A "Target" has expected input that must be passed by convention, no declaration control, and properties are all "Global". Even parameters used in a small snippet are Global. Hopefully you can see the ramifications of this without me spelling it out.

While NAnt and MSBuild are both extensible, it can be awkward to Extend in a way providing backwards compatibility (see comments on parameters) if you are trying to build a library of scripts. It's VERY easy to break dependent scripts.

With this said, MSBuild still has a future with us. If you want to make build processes that execute with Team Build AND when a developer presses F5, MSBuild is what will facilitate it. In short, it the best way to extend Visual Studio for the foreseeable future.

I still have a temptation to use MSBuild for deployments for this simple advantage - it's part of the Framework starting in 2.0. If a machine has 2.0+ installed, it has the core MSBuild language. This gives you flexibility of pushing scripts to a target server and executing them remotely. Nonetheless, PS is so much more powerful when it comes to working with OS components and it will become standard on the OS, it's just a matter of time before you'll be able to count on availability.

Powershell not only provides Parametrized Procedures but is embraces OO with a vengeance. It naively can work will all .Net Classes, but also ADO, WMI, and COM! You don't have to dance through hoops to get full access to these. If you need to utilize .NET objects, you don't have to write rapper Tasks like you would in NAnt and MSBuild. You may want isolate the access in scripts and Cmdlets, but it's not required.

With all that said, Powershell is "scripting". You don't get strong typing that comes from a compiled language because these things are resolved at run time. It works really hard to make sense of Types but that leaves it resolution at Run Time. Also, PowerShell has new syntax and parsing rules you'll have to learn. It won't be painless to learn and master but it has so much power it will be worth it.

Since that time, we have moved forward on this plan.  Our Deployments are all using PowerShell.  Omar's article is nice but it really only scratches the surface of what we are doing.  No wonder he can call it "Deployments made simple"!
I'm still enjoying PowerShell and learning more stuff every day.  We really have not reached a full version 1.0 of our PowerShell deployments replicating all the features used in our NAnt deployments.  But it's real close.  The major difference is we don't customize a single PowerShell script for a product Deployment.  Everything is contained in an XML Configuration file.  With NAnt, I often had a dozen custom Build files for a product.
After Version 1.0, I'll start refactoring some large chunks of code into C# libraries called from PowerShell.  Much of the reasons are in my comments above.  Application code belongs in C# where I have strong typing and can have Unit Tests with Code Coverage.  PowerShell is great at some things - piping, consistent command line interface, and portable.  It also provides the ability to hot fix some logic in a pinch.
I'll post more about the capabilities and functionality in future Blog entries.  It's really cool!
Saturday, 13 October 2007 23:49:22 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -

This morning I did a little exercise.  Because PowerShell does not have C#'s Using Statement, Class references have to be fully qualified.  This includes Enumeration Values.  IMHO, this can make calls to managed methods a bit wordy.

In order to manage this, I have at times initialized a hash table with enumeration values.  For example, to initialize the values of System.Security.Cryptography.CipherMode I would create the following.

$CipherMode = @{}
$CipherMode.OFB = [System.Security.Cryptography.CipherMode]::OFB
$CipherMode.CFB = [System.Security.Cryptography.CipherMode]::CFB
$CipherMode.CBC = [System.Security.Cryptography.CipherMode]::CBC
$CipherMode.ECB = [System.Security.Cryptography.CipherMode]::ECB
$CipherMode.CTS = [System.Security.Cryptography.CipherMode]::CTS

This allows use of $CipherMode.CBC instead of [System.Security.Cryptography.CipherMode]::CBC.  While I found this handy at times, it is arduous to initialize.  And this one only has 5 values.

I developed a couple of functions that take the drudgery out of it.  The usage is:

$CipherMode = Get-EnumValues "System.Security.Cryptography.CipherMode"

This as easily handles enumeration of 2 or 200.  Beauty!

I also made a helper function that will simply show me the enumeration names:

Get-EnumNames "System.Security.Cryptography.CipherMode"

This will return:


The Source Code is as follows:

function Get-ValidEnumClass ([string] $ClassName = ${Throw "Class Name is required"})
  $type = [System.Type]::GetType($ClassName)
  if ($type -eq $null)
    throw "Invalid Class Name or Assembly not loaded for [$ClassName]"
  if (!$type.IsEnum)
    throw "Invalid Enum Class [$ClassName]"

function Get-EnumNames ($EnumClass = ${Throw "Valid Enum Class Name or Type is required"})
  if ($EnumClass -is [string])
    $EnumClass = Get-ValidEnumClass $EnumClass

function Get-EnumValues ([string] $EnumClassName = ${Throw "Valid Enum Class Name is required"})
  $type = Get-ValidEnumClass $EnumClassName
  $enumNames = Get-EnumNames $type
  $values = @{}
($name in $enumNames)
    $values[$name] = $type::$name.GetHashCode()

Saturday, 13 October 2007 22:36:50 (GMT Daylight Time, UTC+01:00)  #    Comments [1178] -

For some reason, modern error handling was left out of PowerShell Version 1.0.  However, as both a tribute and a mockery to what is in and not in PowerShell, Adam Weigert posted the following PowerShell function in this post:

function Try
        [ScriptBlock]$Command = $(throw "The parameter -Command is required."),
        [ScriptBlock]$Catch   = { throw $_ },
        [ScriptBlock]$Finally = {}
    & {
        $local:ErrorActionPreference = "SilentlyContinue"
                & {
                    trap { throw $_ }
                throw $_
            $_ | & { &$Catch }

    & {
        trap { throw $_ }

# Example usage 

Try {
    echo " ::Do some work..."
    echo " ::Try divide by zero: $(0/0)"
} -Catch {
    echo "  ::Cannot handle the error (will rethrow): $_"
    #throw $_
} -Finally {
    echo " ::Cleanup resources..."

I did a bit of testing with nested error handling and I'm comfortable enough I'm going to start rolling it out.

Don't get me wrong, I LOVE PowerShell and for a version 1 product, it is amazingly functional and usable.  But, I usually refer to the error handing as Trap Crap.  It's not that it doesn't work... This function uses it and it works.  But keep in mind, implementing your own Try Finally Catch using Trap Crap would look very similar to the Try implementation code!  Can your read it?  I can, but it takes too many brain cells and productive minutes to do so.

Compare it to the "Example usage".  Hmmm... which do you want to use.  It has a bit of awkwardness because of the "parameter" nature of the scriptblocks.  Stick with the "} -Finally {" formatting.  You'll have to do that or use continuation marks.

Until 2.0 comes out, this'll have to do.

Saturday, 13 October 2007 06:19:40 (GMT Daylight Time, UTC+01:00)  #    Comments [10] -
# Wednesday, 10 October 2007

I created a DasBlog Content filter for creating Wikipedia links.  DasBlog Content filters are simple search and replace items.  It does stuff like replace ; -) with  <img alt="; -)" src="smilies/wink.gif">   (I inserted a space after ; so it would not get performed)  It can also do RegEx patterns as used in this example.

I created a derivative of their Google search that searches Wikipedia instead.  The Find Pattern is


RegEx patterns. 

<a href="${expr}">${expr}</a>

This allows you to type $ w(Microsoft)  and it will create Microsoft.   (I inserted a space after $ so it would not get performed)

The imbedded HTML is:

<a href=””>Microsoft</a>

Multi Word with spaces works great too.  If you want it to go to a page it must be exact and unique. 

Wednesday, 10 October 2007 19:57:55 (GMT Daylight Time, UTC+01:00)  #    Comments [17] -

PowerGUI's editor is nice and lightweight.  I wasn't crazy about the colors in the syntax highlighting.

Luckily, this can be customized.  Not with a GUI, but at least in the configuration XML - PowerShellSyntax.xml.  I replaced the Styles section with the following:

<Style Key="ReservedWordStyle" ForeColor="Blue" Bold="True" /> 
<Style Key="OperatorStyle" ForeColor="Red" />
<Style Key="OperatorWordStyle" ForeColor="Red" />
<Style Key="VariableStyle" ForeColor="Purple" /> 
<Style Key="CmdletStyle" ForeColor="Black" Bold="True" /> 
<Style Key="NetClassStaticStyle" ForeColor="teal" /> 
<Style Key="NetClassStaticMethodStyle" ForeColor="saddlebrown" /> 
<Style Key="CmdletParamStyle" Italic="True" ForeColor="Black" /> 
<Style Key="NumberStyle" ForeColor="Black" /> 
<Style Key="StringDelimiterStyle" ForeColor="Green" /> 
<Style Key="StringDefaultStyle" ForeColor="Green" Bold="True" /> 
<Style Key="CommentDelimiterStyle" ForeColor="Maroon" /> 
<Style Key="CommentDefaultStyle" ForeColor="Maroon" /> 
<Style Key="AutoVars" ForeColor="Navy" />

A Sample Render looks like:

# Some sample code

$strComputer = "."
$colItems = get-wmiobject -class "Win32_LoadOrderGroup" -namespace "root\CIMV2" `

foreach ($objItem in $colItems)
"DriverEnabled: " $objItem.DriverEnabled 
"GroupOrder: " $objItem.GroupOrder 
"Name: " $objItem.Name write-host

I'm sure I'll tweak it, but I'm already happier using the product.


Wednesday, 10 October 2007 04:41:49 (GMT Daylight Time, UTC+01:00)  #    Comments [4] -

When I first saw PowerGUI I was suspicious.  Quest is a first rate company that is very proud of their tools.  I've personally drove the purchase of their tools for Oracle Development a few years back.

Quest made a Press Release for PowerGUI.  It doesn't really commit to keeping it free.  Besides, it's still Beta.  I figured the other foot would drop when it got released.  And by foot, I mean several hundred dollars of foot.

Dimitry Sotnikov recent post announces a new download - that's still Free!  Still slightly leery, I did some searching and found his commentary Why is Quest doing free PowerShell stuff?

While I can't imagine Quest committing to keeping it free, it looks like it is for now!

Don't get me wrong, I'm not a "profit is evil" kind of guy.  But I find it difficult to keep up with the license management for my team.  A product has to be core to the job and save a magnitude more time that it costs fooling with it.  Who knows, we might get addicted to it and maybe Quest will charge a hundred dollars or less for it.

Hopeful Microsoft will make the definitive editor for PowerShell.  Hey, maybe integrate into Visual Studio!  We pay thousands of dollars per developer per year and you would think an intellisense editor for PowerShell wouldn't be too much to ask for.  (I'm hoping Bruce will slap me down again and show me where I've missed it.)

Wednesday, 10 October 2007 01:54:23 (GMT Daylight Time, UTC+01:00)  #    Comments [48] -
# Tuesday, 09 October 2007
Simple technique for deferred expansion of Powershell strings. It is useful for Template strings.
Tuesday, 09 October 2007 19:50:06 (GMT Daylight Time, UTC+01:00)  #    Comments [48] -
<2008 January>
About the author/Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2017
Cash Foley
Sign In
Total Posts: 20
This Year: 0
This Month: 0
This Week: 0
Comments: 5413
Pick a theme:
All Content © 2017, Cash Foley
DasBlog theme 'Business' created by Christoph De Baene (delarou)