Posts Tagged ‘PowerShell’

I used to use C# to write small tools to automate some of my development tasks. Lately, I find myself writing more and more PowerShell scripts. For certain daily tasks, it is much more productive to write PowerShell scripts than C#. (PowerShell is built on top of .NET, making the entire .NET framework available for you to use. Sometimes, I use PowerShell to explore how to use a .NET class, or a 3rd party API.)

The following script, makefile.ps1, shows how to find all .cpp files in nested folders and create a make file. The script, taking one parameter to specify the folder where the .cpp files to be found, can be invoked something as follows.

PS D:\MyProjects>.\makefile.ps1 .\Project1

The script first defines two functions: doFile and doFolder. The doFile function gets the full name of the file, changes its extension to ‘o’ from ‘cpp’, gets the relative file path, which is then appended to the StringBuilder object.

The doFolder function goes to the given folder, finds all .cpp files in that folder, and for each of them, invokes the doFile function. It then finds out all sub-folders, and invokes the doFolder function for each of them recursively. The {$_.Mode -match “d”} script block is to check if a given child item is a directory.

When the script is executed, it first goes to the folder if it is specified. It then gets the current location and assigns it to $currFolder, creates and instances of StringBuilder and invokes the doFolder function by passing in $currFolder and the StringBuilder object. It then appends other necessary information to the StringBuilder object, and finally writes the string to a file.

$currFolder = $null

function doFile($file, $sb)
    $fileName = $file.FullName
    $fileName = [System.IO.Path]::ChangeExtension($fileName, "o")

    [void] $sb.Append("`t")
    $fileName = $fileName.SubString($currFolder.Length + 1)
    [void] $sb.Append($fileName)
    [void] $sb.Append(" \`n")

function doFolder($folder, $sb)
    write-host "Processing folder: ""$folder""..."

    cd $folder

    # Invoke doFile for each .cpp file.
    get-childitem *.cpp | foreach-object { doFile $_ $sb }

    # Invoke doFolder recursively for each sub-folder
    get-childitem * | where-object {$_.PSIsContainer} | foreach-object { doFolder $_ $sb }

    cd ..

if ($args -ne $null -and $args[0] -ne $null)
    cd $args[0]

$currFolder = get-location
$currFolder = $currFolder.Path

$contentBuilder = new-object System.Text.StringBuilder
[void] $contentBuilder.Append("OUTFILES =")

doFolder $currFolder $contentBuilder

[void] $contentBuilder.Remove($contentBuilder.Length - 2, 1)
[void] $contentBuilder.Append("`nall: `$(OUTFILES)`n")
[void] $contentBuilder.Append("`nclean:`n")
[void] $contentBuilder.Append("`tcmd.exe /c del /s /q *.o`n")
[void] $contentBuilder.Append("`n%.o: %.cpp`n")
[void] $contentBuilder.Append("`gcc -o $@ $<`n")

cd $currFolder
set-content -encoding ascii makefile $contentBuilder.ToString()

You may ask: “Why do we need all those [void] type castings in the script?” Yes, they are there to discard the output of the statement. Otherwise you will have something like the following in the output.

Capacity                MaxCapacity                    Length
--------                -----------                    ------
      16                 2147483647                         1
      16                 2147483647                         2
      16                 2147483647                         3

For details, please read this blog entry, http://keithhill.spaces.live.com/Blog/cns!5A8D2641E0963A97!811.entry

PowerShell provides many built-in cmdlets that can be pipelined together, allowing you to write compact scripts. Using C#, you programming rhythm is edit-compile-run. With PowerShell, you just type and run, making you more productive. And the powerful reflection service provided by PowerShell, such as Get-Member, makes it a good tool for learning .NET.

Read Full Post »