Invoke Win32 API via PowerShell

.NET provides pretty good support to for calling Win32 APIs and there’s a free Visual Studio Add-In from redgate available which helps your dealing with the Win32 API: http://www.red-gate.com/products/dotnet-development/pinvoke/

vsaddin2

But what to do if you want to call Win32 APIs or your own .NET functionality in PowerShell?

As always there is more than one way: You can write your .NET code in Visual Studio, compile it to a class library and make it available in PowerShell using Reflection:

[System.Reflection.Assembly]::LoadFrom("path\to\your.dll")

Another – cool – way is to compile your code directly to the memory without generating a dll in the file system and consume it form within PowerShell!

The following code sample shows how to accomplish this by creating a compiler function, embed C# source code as a string, compile the code and invoke the C# function in PowerShell:

##################################################################
# Compiler
##################################################################
function Compile-Csharp ([string] $code, $FrameworkVersion="v4.0.30319")
{
 $provider = New-Object Microsoft.CSharp.CSharpCodeProvider
 $framework = [System.IO.Path]::Combine($env:windir, "Microsoft.NET\Framework\$FrameWorkVersion")
 $references = New-Object System.Collections.ArrayList
 $references.AddRange( @("${framework}\System.dll","${framework}\System.Core.dll"))
 $parameters = New-Object System.CodeDom.Compiler.CompilerParameters
 $parameters.GenerateInMemory = $true
 $parameters.GenerateExecutable = $false
 $parameters.ReferencedAssemblies.AddRange($references)
 $result = $provider.CompileAssemblyFromSource($parameters, $code)
 if ($result.Errors.Count)
 {
 $codeLines = $code.Split("`n");
 foreach ($ce in $result.Errors)
 {
 write-host "Error: $($codeLines[$($ce.Line - 1)])"
 $ce | out-default
 }
 Throw "Compilation of C# code failed"
 }
}

##################################################################
# C# Code
##################################################################
$code = @'
using System;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace CompileTest
{
 public class Sound
 {
 [DllImport("User32.dll", SetLastError = true)]
 static extern Boolean MessageBeep(UInt32 beepType);

 public static void Beep(BeepTypes type)
 {
 if (!MessageBeep((UInt32)type))
 {
 Int32 err = Marshal.GetLastWin32Error();
 throw new Win32Exception(err);
 }
 }
 }

public enum BeepTypes
 {
 Simple = -1,
 Ok = 0x00000000,
 IconHand = 0x00000010,
 IconQuestion = 0x00000020,
 IconExclamation = 0x00000030,
 IconAsterisk = 0x00000040
 }
}
'@

##################################################################
# Compile the code and access the .NET object within PowerShell
##################################################################
Compile-Csharp $code
[CompileTest.Sound]::Beep([CompileTest.BeepTypes]::IconAsterisk)

If you want to use other references than “System” in your C# code, make sure to introduce them to the compiler by adding the dll to the $references ArrayList. Also make sure to pass the appropriate framework version to the Compile-Csharp function. A list of available framework versions and the System*.dlls can be found here: C:\Windows\Microsoft.NET\Framework or C:\Windows\Microsoft.NET\Framework64

Over all this is a quite simple and very cool way to provide .NET functionality within PowerShell. Happy coding!

By the way: Make sure your speakers are turned on when running this example since it leads to a beep sound on your machine :-)

This entry was posted in powerJobs, PowerShell, Visual Studio. Bookmark the permalink.

1 Response to Invoke Win32 API via PowerShell

  1. Hi,
    to compile the code in memory you can also use the Add-Type cmdlet.
    Add-type -TypeDefinition $code

    Tested, and worked.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s