Friday, December 30, 2011

Running PowerShell from C# with a hint of dynamic

This is an adaptation of my post Running JavaScript from C# with a hint of dynamic using PowerShell.

Here is a sample using the default api, to execute a powershell code snippet and then access a global variable defined in the PowerShell world from C#.
var script = @" $i1 = 123 ";            
var ps = PowerShell.Create();
ps.AddScript(script);
ps.Invoke();            

int i1 = (int)ps.Runspace.SessionStateProxy.GetVariable("i1");

Assert.AreEqual(123, i1);
What bother me the most is the line 6. Here is the same code using the library DynamicCsToPowerShell.
var script = @" $i1 = 123 ";

var dpsc = DynamicPowerShellContext.Create().Run(script);

int i1 = dpsc.i1;

Assert.AreEqual(123, i1);
Now compare line 6 from code snippet 1 and line 5 of code snippet 2. The goal of the library DynamicCsToPowerShell is to provide this kind of syntax.

Loading A Configuration File Defined With PowerShell
Here is a script that implements a .NET hashtable in PowerShell. This can be viewed as a simple configuration file.
# An Hashtable in PowerShell
$Dic = @{

    a = 1
    b = 2
    c = 3
}
Here is how to load, access and use the hashtable.
[TestMethod]
public void Dictionary_IntLoadFromFile() {
            
    var ps1ConfigFile = @"..\IntDictionary.ps1";
    var dpsc          = DynamicPowerShellContext.Create();
    dpsc.LoadFile(ps1ConfigFile).Run();

    Assert.AreEqual(3, dpsc.Dic.Count);

    Assert.AreEqual(1, dpsc.Dic["a"]);
    Assert.AreEqual(2, dpsc.Dic["b"]);
    Assert.AreEqual(3, dpsc.Dic["c"]);

    Assert.AreEqual(6, dpsc.Dic["a"] + dpsc.Dic["b"] + dpsc.Dic["c"]);
}
First accessing the hashtable's elements is direct. But we can also execute operations on the elements without having to cast to the right type as shown in line 14.
Obviously we are in the world of Dynamic Languages, so if you have a type mismatch, this will give a run time error.

DynamicCsToPowerShell wraps Array and Hashtable from the PowerShell world into a special object that allow this syntax. Array nested in Hashtable or Hashtable nested in array are supported.

At this point I did not find any out of the box syntax, to support this clean syntax, like it is possible with IronPython. Talking with Doug Finke who is a PowerShell specialist, he mentioned that with PowerShell v 3 we should be able to do it.

Advanced Configuration File With PowerShell
The ideas behind using a dynamic language to implement a configuration file are:
  1. Using anything but XML
  2. Having an IDE that will understand JSON, JavaScript, IronPython or PowerShell
  3. Executing code when the config file is loaded.
Here I have the same PowerShell hashtable, but the value of the key c is set by the execution of the function F1(), when the script is executed.
function F1([int] $i1, [int] $i2) {             

 return $i1 + $i2;
}
$Dic = @{

 a = 1  
 b = 2 
 c = (F1 2 1)
}

Conclusion

When writing highly customizable application using this technique opens the door to more possibilities with less effort as the dynamic language provides the environment to formalize the customization. We can build our own DSL in the dynamic language.

I do not find PowerShell as elegant as IronPython or JavaScript, but we can obtain the same result.

The source code is on github at DynamicCsToPowerShell.

2 comments: