Google
 

Sunday, September 7, 2008

ITWorx Education webinars

You are invited to attend ITWorx Education webinars on Catalyst™ MLG Provisioning Suite and ExamExpert™
Click links below !!

Friday, September 5, 2008

Calling PowerShell Commands from C# code

Windows PowerShell is a solution to what the windows platform lacked, a really powerful shell !! But it does not stop at this point. Calling PowerShell commands (Cmdlets) from .net code, using the return values can add real power to you application.

In this post, I'll explian how to gain this power in a simple C# application to recursively search the file system and getting the results. The same technique can be used in many other scenarios.

Before starting to code:
First you need to install Windows PowerShell for your windows version. So you need to check How to Get Windows PowerShell 1.0

Next, add a reference to System.Management.Automation.dll to the application, It can be found under C:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\v1.0 in case of windows XP installation.

After adding this using statement, you'll be ready to code:
using System.Management.Automation;

Starting simple : Getting a list of files and folders recursively:
There are many ways to integrate with PowerShell, here, I'll use a relatively simple way which is the RunspaceInvoke class.

first, let's examine this command in PowerShell:
dir C:\WINDOWS -Recurse
Executing this command in PowerShell will get all files and folders under C:\windows recursively. By the way, dir is an alias to the command Get-ChildItem, not a command itself.

This code creates a RunspaceInvoke instance and invokes dir:

System.Collections.ObjectModel.Collection<psobject> result = null;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "D:\\Codes\\C#\\PSDir" + " -recurse");
}

Note that the Invoke method returns a generic collection of PSObjects. We'll use this collection to retrieve the results. This is one of the real powerful features of PowerShell, it talks objects not text as the old command line commands.

But what can we get from the Collection of PSObjects? PSObject class contains the ImmediateBaseObject property that contains the actual object returned by the command. In the case of dir, we expect that this command will return objects of types: System.IO.DirectoryInfo and System.IO.FileInfo. We'll see later how can we discover this. But for now, lets get the results:

foreach (PSObject item in result)
{
if (item.ImmediateBaseObject is System.IO.DirectoryInfo)
{
System.IO.DirectoryInfo info = item.ImmediateBaseObject as System.IO.DirectoryInfo;
Console.WriteLine("Directory:" + info.FullName);
}
else if (item.ImmediateBaseObject is System.IO.FileInfo)
{
System.IO.FileInfo info = item.ImmediateBaseObject as System.IO.FileInfo;
Console.WriteLine("File:" + info.FullName);
}
}

As you see in the above code, I check the type of the result and display the appropriate value based on it. The result will be something like this:




A more useful example: Searching the file system:
You can use dir to search for all files of a specific type under a specific path using the filter parameter. This is a complete code listing:

System.Collections.ObjectModel.Collection result = null;
using (RunspaceInvoke invoke = new RunspaceInvoke())
{
result = invoke.Invoke("dir " + "D:\\Codes\\C#\\PSDir" + " -recurse -Filter *.exe");
}

foreach (PSObject item in result)
{
if (item.ImmediateBaseObject is System.IO.DirectoryInfo)
{
System.IO.DirectoryInfo info = item.ImmediateBaseObject as System.IO.DirectoryInfo;
Console.WriteLine("Directory:" + info.FullName);
}
else if (item.ImmediateBaseObject is System.IO.FileInfo)
{
System.IO.FileInfo info = item.ImmediateBaseObject as System.IO.FileInfo;
Console.WriteLine("File:" + info.FullName);
}
}

Console.ReadKey();

Exploring PowerShell commands results:
In the above code, I expect the result to be .net types System.IO.DirectoryInfo and System.IO.FileInfo. But how could one detect the type?
PowerShell is very discoverable. for example, executing these statements in PowerShell lets us know the return type (Note that results depend on your file system):
$result = dir c:\
$result[0].GetType().Name

this returns:
DirectoryInfo
Trying another index like 9:
$result[9].GetType().Name
returns:
FileInfo

In this post, we made use of PowerShell commands and manipulated their results. In another post, I'll explain how to check for errors that may occur when running PowerShell commands and how to handle them.