Category Archives: C#

PowerShell: Getting the Disk Drive from a Volume or Mount Point

So this is way harder than I thought it would be.

If you take a look at the WMI class for Win32_MountPoint

You’ll notice there is a remark there that says:

There may not be any way to search from Win32_MountPoint to get to the associated Win32_DiskDrive

Which also applies to the Volume.

That sends you over to this blog post which talks about a win32 api call via DeviceIoControl and I managed to find decent info on and also this blog post here which basically gives some VB code for it.

So after taking all that in, I was able to write a simple C# snippet that you can toss in PS to query for a Volume

Add-Type -TypeDefinition @"
using System;
using Microsoft.Win32.SafeHandles;
using System.IO;
using System.Runtime.InteropServices;

public class GetDisk
 private const uint IoctlVolumeGetVolumeDiskExtents = 0x560000;

 public struct DiskExtent
 public int DiskNumber;
 public Int64 StartingOffset;
 public Int64 ExtentLength;

 public struct DiskExtents
 public int numberOfExtents;
 public DiskExtent first;

 [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
 private static extern SafeFileHandle CreateFile(
 string lpFileName,
 [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess,
 [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode,
 IntPtr lpSecurityAttributes,
 [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition,
 [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes,
 IntPtr hTemplateFile);

 [DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
 private static extern bool DeviceIoControl(
 SafeFileHandle hDevice,
 uint IoControlCode,
 [MarshalAs(UnmanagedType.AsAny)] [In] object InBuffer,
 uint nInBufferSize,
 ref DiskExtents OutBuffer,
 int nOutBufferSize,
 ref uint pBytesReturned,
 IntPtr Overlapped

 public static string GetPhysicalDriveString(string path)
 //clean path up
 path = path.TrimEnd('\\');
 if (!path.StartsWith(@"\\.\"))
 path = @"\\.\" + path;

 SafeFileHandle shwnd = CreateFile(path, FileAccess.Read, FileShare.Read | FileShare.Write, IntPtr.Zero, FileMode.Open, 0,
 if (shwnd.IsInvalid)
 Exception e = Marshal.GetExceptionForHR(Marshal.GetLastWin32Error());

 var bytesReturned = new uint();
 var de1 = new DiskExtents();
 bool result = DeviceIoControl(shwnd, IoctlVolumeGetVolumeDiskExtents, IntPtr.Zero, 0, ref de1,
 Marshal.SizeOf(de1), ref bytesReturned, IntPtr.Zero);
 return @"\\.\PhysicalDrive" + de1.first.DiskNumber;
 return null;


This will allow you to call this static method to get its Disk path, so you can do something like this.

$DeviceID = [GetDisk]::GetPhysicalDriveString('c:\')
gwmi win32_diskdrive | ? { $_.deviceid -eq $DeviceID}

Now you say, but Justin, this isnt working for a mount point path!? Which is true, but we can work around that.

We can use the Win32_MountPoint class to figure this out, or, you can use this cmdlet Get-MountPointData which basically parses the class for you. Really all you need to do is get the Volume DeviceID, which looks something like this.


So we can take that and search on it like so.


NOTE: This must be run as admin, since we’re hitting the disk subsystem (kernel)


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 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 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:


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



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:


<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



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 | 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!

List OLE/ODBC Providers with .NET

Recently I wanted to be able to list the OLE/ODBC Providers installed on a system. Not horribly hard, but also didnt have a ton of luck finding info on how to do this.


For OLE there is a .NET library that allows you to do this fairly easily. I focused in on the wrong method at first but thanks to help from BigTeddy over at the Technet Powershell forums the problem was resolved.

System.Data.OleDBEnumerator class has a GetElements method that will return a list of available providers.



Oddly enough, you would think that the System.Data.ODBC namespace would have something along those lines, but no. If it does, I cant find it. However, you can pull it from the registry fairly easily from the following location.



#32 bit drivers on a 64 bit system here

Get-ItemProperty 'HKLM:\SOFTWARE\Wow6432Node\ODBC\ODBCINST.INI\ODBC Drivers'

Create a Popup Input Box with C#

So I decided I wanted to keep the interface of my Overseer project pretty clean, but wanted to get simple input before creating certain objects. For example, a tab name when a user clicks the new tab button.

Here is a sample of what I’m talking about.

Here is the function I created to do this. You’ll need to add a using statement to your project.

using System.Drawing.Drawing2D;

public DialogResult PopupInput(Control ctrl, int border, int length, ref string output)

//handle alignment
Point ctrlpt = this.PointToScreen(ctrl.Location);
ctrlpt.Y += 24;
ctrlpt.X += 4;

TextBox input = new TextBox { Height=20, Width=length, Top= border/2,Left=border/2};
input.BorderStyle = BorderStyle.FixedSingle;
//######## SetColor to your preference
input.BackColor = Color.Azure;

Button btnok = new Button {DialogResult = System.Windows.Forms.DialogResult.OK, Top=25};
Button btncn = new Button { DialogResult = System.Windows.Forms.DialogResult.Cancel, Top = 25 };

Form frm = new Form { ControlBox = false, AcceptButton = btnok, CancelButton = btncn, StartPosition = FormStartPosition.Manual, Location = ctrlpt };
frm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
//######## SetColor to your preference
frm.BackColor = Color.Navy;

RectangleF rec = new RectangleF(0, 0, (length + border), (20 + border));
GraphicsPath GP = new GraphicsPath(); //GetRoundedRect(rec, 4.0F);
float diameter = 8.0F;
SizeF sizef = new SizeF(diameter,diameter);
RectangleF arc = new RectangleF(rec.Location, sizef);
GP.AddArc(arc, 180, 90);
arc.X = rec.Right - diameter;
GP.AddArc(arc, 270, 90);
arc.Y = rec.Bottom - diameter;
GP.AddArc(arc, 0, 90);
arc.X = rec.Left;

frm.Region = new Region(GP);
frm.Controls.AddRange(new Control[] {input,btncn,btnok});
DialogResult rst = frm.ShowDialog();
output = input.Text;
return rst;

If you’d like to make a sample app like the one above create a basic windows forms project, toss the above method in there with a button and a textbox on the form and add this code to the on click of the button.

string var="";

if (PopupInput(button1, 4, 75, ref var) == System.Windows.Forms.DialogResult.OK)
textBox1.Text = var;

NOTE: I’m not an awesome coder so any advice would be appreciated. I only post this because I wasn’t able to find something like it on the net.

EDIT: I forgot to add, as you can see by default the box aligns to the bottom of the passed in control. It would be easy to align it to another location, or to add a param that would let you pick. I wanted to keep the code as short as possible, but if anyone wants to see that, let me know.

Validate NetBIOS Domain Name to see if its in use or just test to see if its valid. Powershell/C#


Recently someone in the forums asked how they could check to see if a NetBIOS Domain Name was in use or not. Come to find out there isn’t a .NET methods for doing this that I could find but there is an API function for that. First I’ll show the C# and then I’ll show how to use it in Powershell. Creating a C# console app was how I went about figuring this out for Powershell.

First I took a look at the API which looked pretty easy to bring in to C# and then I called it within my Main() function. Here is the complete C# console code.

using System;

using System.Runtime.InteropServices;


public class NetworkUtil



    public static extern UInt32 NetValidateName(string lpServer,string lpName, string lpAccount,string lpPassword, int NameType);


    static void Main()


        UInt32 rtn = NetValidateName(null, "jrich-pc", null, null, 1);





So lets walk through this. First I only included (using) the System and InteropServices (PInvoke) and then created a class for this. I used NetworkUtil so that I could extend my class in my NetStat powershell cmdlet if I wanted (I suspect this will grow over time).

I then used the DLLImport to pull in the function from the .dll file. I’ve included the SetLastError simply because I saw it on most but its not really needed. The CharSet being set to Unicode is very important. That part threw me for a loop. The docs don’t really talk about it and the only reference is in their example. I stumbled across it when looking at another example of a similar call (

The question that should be running through your mind right about now is, how did you convert the C++ function signature to C#? The answer is simple, I guessed based on what it implied. The first time I started to play with PInvoke stuff I was surprised at how forgiving the types were. Granted this can get you in trouble, but if you know what you are expecting in return, you can go from there and tweak it.

The C++ signature is as follows.

NET_API_STATUS NetValidateName( __in LPCWSTR lpServer, __in LPCWSTR lpName, __in LPCWSTR lpAccount, __in LPCWSTR lpPassword, __in NETSETUP_NAME_TYPE NameType );


The return type is a structure of error codes that boil down to numbers, so I said hey, lets make it a INT32, I later found a negative error code so I changed it to UINT32, you almost never see negative numbers (I’ll look at that in a bit). Then we need to keep the name the same. For the param’s we’ll see most are LPCWSTR which is a string (docs tell you and the STR gives it away) so I simple made them all strings in the C# code. The last param is of type NETSETUP_NAME_TYPE which is defined in the docs to be a simple ENUM that is 0-5. At first I created the ENUM but then decided it was easy enough to just send it a number and if I needed to change it I’d reference the docs.

Then I get to testing this from my main function with a simple call.

UInt32 rtn = NetValidateName(null, "jrich-pc", null, null, 1);

Reading the docs you’ll see the inputs are pretty basic;

Server – The server to query again, null is the local machine, this should be fine for most.

Name – The name you want to query for

Username and Password – If you query a server (an AD server) you can provide creds, if you don’t it uses the current context (you)

Name Type – This is the type of query you want to preform.

The Name Type can be found on the docs page, but I’ve copied them here for simple reference. The two that seem to be of most value are 1 and 3.





The nametype is unknown. If this value is used, the NetValidateName function fails with ERROR_INVALID_PARAMETER.



Verify that the NetBIOS computer name is valid and that it is not in use.



Verify that the workgroup name is valid.



Verify that the domain name exists and that it is a domain.



Verify that the domain name is not in use.



Verify that the DNS computer name is valid.

This value is supported on Windows 2000 and later. The application must be compiled with _WIN32_WINNT >= 0x0500 to use this value.


These are pretty well documented and make good sense. As I said typically you’ll use 1 and 3 and maybe even 4 depending on how you want to code your app.


The part that was hardest was tracking down these error codes. I found the best way was to google the display names that the docs showed. Here is a table I made with the Error Codes I was able to track down.










It found what you were looking for



It wasn’t able to connect to your query server





















Found query server but RPC wasn’t available


Most of these codes are pretty obvious and should make sense once you start to test it.



Now, lets use this in powershell. Its actually pretty easy once we figure that part out.

Add-Type -TypeDefinition @"
using System;
using System.Runtime.InteropServices;

public class NetworkUtil
    public static extern UInt32 NetValidateName(string lpServer,string lpName,string lpAccount,string lpPassword,
        int NameType);

Function Test-NetBIOSName{

param([string] $Name, [int] $NameType)


Test-NetBIOSName “myserver” 1

The function I created is very basic. You could tweak the param’s to validate input and the such, but I’ll leave that up to you.

Hope this helps!