Learn about Windows PowerShell
Summary: Guest blogger, Matt Graeber, completes his three-part series about interacting with the Windows API.
Microsoft Scripting Guy, Ed Wilson, is here. Matt Graeber is back with us today to finish up his three-part series. Read the previous parts to catch up for today’s post:
In the last two posts, I described two methods of interacting with the Windows API. In this post, I’ll introduce the last and final method: reflection.
Reflection gives a programmer the ability to perform type introspection on code. The most common form of type introspection you would perform in Windows PowerShell would be using the Get-Member cmdlet, which enables you to discover the methods and properties of an object. In the last post, we also used reflection to find a non-public method that implemented the kernel32.dll CopyFile function. In this post, we will be using reflection to generate code dynamically. This concept is known as metaprogramming.
To define a dynamic method that will call the CopyFile method in kernel32.dll, the following steps are needed:
As you can see, this is not a trivial process. This process involves performing tasks that Add-Type and the C# compiler would typically take care of on your behalf.
So you may be asking now, “Why the heck would I want to go through all this trouble just to call a function?” The reason I typically do this is twofold:
To see all of this in action, I wrote another implementation of the Copy-RawItem function that uses reflection. The complete text of this function is available in the Script Center Repository: Copy-RawItem (Reflection Version).
Copy-RawItem – Reflection Version:
Copies a file from one location to another including files contained within DeviceObject paths.
Specifies the path to the file to copy.
Specifies the path to the location where the item is to be copied.
Do not copy the file if it already exists in the specified destination.
None or an object representing the copied item.
Copy-RawItem '\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy2\Windows\System32\config\SAM' 'C:\temp\SAM'
[Parameter(Mandatory = $True, Position = 0)]
[Parameter(Mandatory = $True, Position = 1)]
# Create a new dynamic assembly. An assembly (typically a dll file) is the container for modules
$DynAssembly = New-Object System.Reflection.AssemblyName('Win32Lib')
# Define the assembly and tell is to remain in memory only (via [Reflection.Emit.AssemblyBuilderAccess]::Run)
$AssemblyBuilder = [AppDomain]::CurrentDomain.DefineDynamicAssembly($DynAssembly, [Reflection.Emit.AssemblyBuilderAccess]::Run)
# Define a new dynamic module. A module is the container for types (a.k.a. classes)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('Win32Lib', $False)
# Define a new type (class). This class will contain our method - CopyFile
# I'm naming it 'Kernel32' so that you will be able to call CopyFile like this:
# [Kernel32]::CopyFile(src, dst, FailIfExists)
$TypeBuilder = $ModuleBuilder.DefineType('Kernel32', 'Public, Class')
# Define the CopyFile method. This method is a special type of method called a P/Invoke method.
# A P/Invoke method is an unmanaged exported function from a module - like kernel32.dll
$PInvokeMethod = $TypeBuilder.DefineMethod(
[Reflection.MethodAttributes] 'Public, Static',
[Type] @([String], [String], [Bool]))
# Set the equivalent of: [DllImport(
# SetLastError = true,
# PreserveSig = true,
# CallingConvention = CallingConvention.WinApi,
# CharSet = CharSet.Unicode)]
# Note: DefinePInvokeMethod cannot be used if SetLastError needs to be set
$DllImportConstructor = [Runtime.InteropServices.DllImportAttribute].GetConstructor(@([String]))
$FieldArray = [Reflection.FieldInfo] @(
$FieldValueArray = [Object] @(
$SetLastErrorCustomAttribute = New-Object Reflection.Emit.CustomAttributeBuilder(
# Make our method accesible to PowerShell
$Kernel32 = $TypeBuilder.CreateType()
# Perform the copy
$CopyResult = $Kernel32::CopyFile($Path, $Destination, ([Bool] $PSBoundParameters['FailIfExists']))
if ($CopyResult -eq $False)
# An error occured. Display the Win32 error set by CopyFile
throw ( New-Object ComponentModel.Win32Exception )
Write-Output (Get-ChildItem $Destination)
Here is Copy-RawItem in action with descriptive errors that are displayed:
This wraps up my series about using Windows PowerShell to interact with the Windows API. As you can see, this process can be as simple or as complicated as you want it to be. Which method you choose will ultimately be determined by your unique execution requirements. However in most cases, using Add-Type to compile C# code will suffice.
For more resources about reflection, search the MSDN documentation for the System.Reflection and System.Reflection.Emit namespaces. Also, check out some of the awesome work by Windows PowerShell MVPs Oisin Grehan and Adam Driscoll. These guys are experts on metaprogramming and reflection, among other things.
The full script is available in the Script Center Repository: Copy-RawItem (Reflection Version).
Thank you, Matt, for sharing your time and knowledge.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
<p>Will this work with PS version 1.0 and 2.0? Though they are a little too old. PS 1.0 seems to be in grave, yet I wanted to check it with you that in case we have brought it back to life in our organization should this work?</p>
<p>Thank you so much for your time and efforts. Really appreciate this and do keep up the great work.</p>