Monthly Archives: February 2012

PowerShell and Executables


I don’t normally do posts like this, but I just created a Technet Wiki on PowerShell and executables. The only reason I created it there and didn’t do the post myself is that I think there is a lack of info on the topic and a community driven page might be of great help here. So, if you can, please populate it with more info!

http://social.technet.microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx

 

PowerShell: Getting Started with Win32 API


Blog on Request!

Someone asked me to delve in to Win32 API use in PowerShell. Personally I don’t feel that I’m the best person to explain this, but I’ve done it a few times now so I think I have a decent handle on it.

Let me just start off by saying Win32 API should be your last choice (ok, second to last, I hate COM). You should do a very through search of the .NET framework before jumping in to the Win32 API pool.

Once you’ve exhausted all other options and have ended up in the Win32 world, what do you do? I’m not going to go over how to find the right WIN32 API for the task because if you are at this point, you’ve probably already found the API and just want to know how to use it.

First off load up the MSDN doc for it and the PInvoke.net doc. Usually googling the API will land you on those two pages pretty quickly.

Now for an example lets take a look at an API I’ve recently been playing with, GetSystemFileCache (pinvoke)

The Signature that MSDN gives us looks like this.

BOOL WINAPI GetSystemFileCacheSize(   __out  PSIZE_T lpMinimumFileCacheSize,   __out  PSIZE_T lpMaximumFileCacheSize,   __out  PDWORD lpFlags );

Which is the signature you’d use if you were coding in C++.  Since there is no direct way to use this in PowerShell we’re going to embed this in C# code and then consume that code in PowerShell. In many cases I’ll write the C# console app first and then apply that to my PowerShell script. This is what I did with my NetStat script, which was fairly complex. In this case we’re just calling a simple method to pull the current Cache limits.

Lets take a look at this Signature. The first thing shown is BOOL, which is the return type which the docs show is any nonzero number for success. Easy enough. bool is the same in C++ as it is in C#.

Next is WINAPI which is just a tag to show its a win32 api, this can just be removed.

After this is our method name, GetSystemFileCacheSize, easy enough.

Now this is where it gets a little tricky because we often times need to convert C++ types to something C# knows.

We see we have 3 arguments here, all 3 of which are prefixed with __out, which means they are output variables (If you don’t know how to program that well it’s basically passing a reference to a variable to return multiple things). So anytime you see __out, that means the variable needs to be passed in as a reference. We’ll get to that in a moment. Next is the type that the variable needs to be. Two of which are whats called PSIZE_T and one is a PDWORD. In both cases these are prefixed with a P, which indicates Pointer (pointer, reference, __out – all the same thing) so really the type is SIZE_T and DWORD.

How do we know what SIZE_T and DWORD are in C#? Google is really your best option here, or hopefully PInvoke.net has a signature you can use. In this case PInvoke does have it, but lets pretend it doesn’t. When we google ‘C# dword’ we get some good results that let us know this is an unsigned Int (UInt32). Another clue we have is that in the MSDN docs it tells us that it’s a flag and it can have a value of 0x1 or 0x4, both of which fit in to an int just fine. So, which do we use? It doesn’t matter, provided all possible return types can fit in.

Next is that Size_T, again googling ‘C# SIZE_T’ gives us some good info as does PInvoke, but lets just google SIZE_T.

Doing so provides a great data type reference.

We can see that PSIZE_T is in there but it just says it’s a pointer to SIZE_T which we already knew.

“The maximum number of bytes to which a pointer can point. Use for a count that must span the full range of a pointer.

This type is declared in BaseTsd.h as follows:

typedef ULONG_PTR SIZE_T;

So this says it’s a ULONG (unsigned long, a long in C# is Int64, which google will help with again) It also indicates that it’s a pointer. This is where PInoke really saves us. It lets us know about an IntPtr type that is a special pointer specifically for this.

So now our new C# signature is as follows

bool GetSystemFileCacheSize(ref IntPtr lpMinimumFileCacheSize, ref IntPtr lpMaximumFileCacheSize, ref int lpFlags);

We see that it specifies ref for all the __out variables (in this case all of them, but some times they are __in) and a data type of IntPtr and int.

We’re still in the C# side of the world. we’ll need to use the System.Runtime.InteropServices (otherwise known as pinvoke). If you don’t know C# this might be a bit tricky, but we’re going to write a small C# class to contain our method and create a wrapper function around it. Not always needed but I find it makes it easier to work with.


using System;

using System.Runtime.InteropServices;

public class test1

{

[DllImport("kernel32.dll")]

public static extern bool GetSystemFileCacheSize(ref IntPtr lpMinimumFileCacheSize, ref IntPtr lpMaximumFileCacheSize, ref int lpFlags);

public struct CacheSize

{

public Int64 Min;

public Int64 Max;

public int Flags;

}

public static CacheSize GetSize()

{

IntPtr lpMin = IntPtr.Zero;

IntPtr lpMax = IntPtr.Zero;

int lpFlags = 0;

bool b = GetSystemFileCacheSize(ref lpMin, ref lpMax, ref lpFlags);

CacheSize size = new CacheSize();

size.Min = lpMin.ToInt64();

size.Max = lpMax.ToInt64();

size.Flags = lpFlags;

return size;

}

The first part of this is just adding the pinvoke namespace and the basic system namespace which helps with the IntPtr. We then create a public class. I usually start with Test1 because once you add a type to PowerShell you can’t overwrite it.

Then you’ll see the keywords [DLLImport(“kernel32.dll”)] so depending on what DLL your function is in will determin what you put in there which is followed by the signature.

Next I created a struct to help with the output to PowerShell. You’ll see how this comes in to play as we start to work with the PowerShell side of things. For now just see that it’s a simple holder for our return data. Next is our function wrapper. I’ve called it GetSize which returns my struct. You’ll also notice that it’s prefiexed with public static for both, which is important for accessing it within PowerShell.

In my function I set my min and max pointer to zero (special pointer zero) and the flags to zero. I then call the win32 api passing it the variables I created as references (pointers) and capture the return in b which if I was trying to do something for production, I’d check the return value.

I then create an object of my type CacheSize and populate it with the return values and return that to the caller.

Now that the C# is done, how do we apply this in PowerShell?

If you read my blog you’ll notice I’ve used Add-Type a few times which is a great tool for adding in types or C# code as we are doing here so we’ll just wrap this in a here-string and pass it to Add-Type like so:


Add-Type

<span style="color: #8b0000; font-family: Lucida Console; font-size: xx-small;"><span style="color: #8b0000; font-family: Lucida Console; font-size: xx-small;"><span style="color: #8b0000; font-family: Lucida Console; font-size: xx-small;">@'</span></span></span>

using System;

using System.Runtime.InteropServices;

public class test1

{

[DllImport("kernel32.dll")]

public static extern bool GetSystemFileCacheSize(ref IntPtr lpMinimumFileCacheSize, ref IntPtr lpMaximumFileCacheSize, ref int lpFlags);

public struct CacheSize

{

public Int64 Min;

public Int64 Max;

public int Flags;

}

public static CacheSize GetSize()

{

IntPtr lpMin = IntPtr.Zero;

IntPtr lpMax = IntPtr.Zero;

int lpFlags = 0;

bool b = GetSystemFileCacheSize(ref lpMin, ref lpMax, ref lpFlags);

CacheSize size = new CacheSize();

size.Min = lpMin.ToInt64();

size.Max = lpMax.ToInt64();

size.Flags = lpFlags;

return size;

}

}

'@

NOTE: Be careful of new lines in this code, the code formatter has been doing weird things to me lately.

Once you run that its imported the class in to our running environment and we can access that method like so.


$rtn = [test1]::getsize()

$rtn

$rtn | select @{n='min';e={$_.min /1mb}}, @{n='Max';e={$_.max/1gb}},flags

The return should be the same on all systems (at least what I’ve seen from tests) as 1MB min and 1024GB max. If you have a file server that’s hosting TB’s of data, you might find this to be a problem when its eaten all of your memory in system cache!

There is a way to set it with a win32 API that im working on now. I’ll be sure to post that solution when I figure it out!

I hope this has helped you understand how to use Win32 APIs a little better!