{"id":3336,"date":"2013-06-25T00:01:00","date_gmt":"2013-06-25T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2013\/06\/25\/use-powershell-to-interact-with-the-windows-api-part-1\/"},"modified":"2013-06-25T00:01:00","modified_gmt":"2013-06-25T00:01:00","slug":"use-powershell-to-interact-with-the-windows-api-part-1","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-interact-with-the-windows-api-part-1\/","title":{"rendered":"Use PowerShell to Interact with the Windows API: Part 1"},"content":{"rendered":"<p><span style=\"font-size: 12px\"><strong>Summary<\/strong>: Guest blogger, Matt Graeber, discusses how&nbsp;to use Windows PowerShell to interact with Windows API functions in Part 1 of a three-part series.<\/span><\/p>\n<p><span style=\"font-size: 12px\">Microsoft Scripting Guy, Ed Wilson, is here. Guest blogger, Matt Graeber, is back. Matt first joined us as a guest yesterday with his post <\/span><a style=\"font-size: 12px\" href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2013\/06\/24\/use-powershell-and-regular-expressions-to-search-binary-data.aspx\" target=\"_blank\">Use PowerShell and Regular Expressions to Search Binary Data<\/a><span style=\"font-size: 12px\">.<\/span><span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>Welcome back, Matt&hellip;<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>I often finding myself needing to use Windows PowerShell to interact with Windows API functions to accomplish a low-level task. For those who are not familiar with the Windows API, basically, it refers to the functionality that is exposed by your built-in system DLLs. For example, kernel32.dll exposes hundreds of functions that can be used by developers for interacting with the operating system.<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>In Windows PowerShell, there are three ways to interact with Windows API functions:<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<ol>\n<li>Use the <strong>Add-Type<\/strong> cmdlet to compile C# code. This is the officially documented method.<\/li>\n<li>Get a reference to a private type in the .NET Framework that calls the method.<\/li>\n<li>Use reflection to dynamically define a method that calls the Windows API function.<\/li>\n<\/ol>\n<h2>Background to using Add-Type<\/h2>\n<p>In the examples that follow, I use the <strong>CopyFile<\/strong> function in kernel32.dll as the function that Windows PowerShell will interact with. Now, you may have just asked the question, &ldquo;Why would I want to call <strong>CopyFile<\/strong> when Windows PowerShell already has the <strong>Copy-Item<\/strong> cmdlet?&rdquo;<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>That&rsquo;s a very good question, indeed. As it turns out though, there are certain file paths that the Windows PowerShell file provider doesn&rsquo;t know how to handle. In particular, it doesn&rsquo;t know how to interpret special device object paths, such as: \\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy2\\Windows\\System32\\calc.exe. These are the kinds of paths that you need to deal with when you interact with files that are backed up by the Volume Shadow Copy Service. For example, running the following command lists the device object paths of each volume shadow copy:<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p style=\"padding-left: 30px\"># Run this from an administrative prompt<\/p>\n<p style=\"padding-left: 30px\">Get-WmiObject Win32_ShadowCopy | Select-Object DeviceObject<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>Before diving into using Windows PowerShell to call <strong>CopyFile<\/strong>, it is helpful to have some background on C\/C++ types vs. .NET types.<span style=\"font-size: 12px\">&nbsp;<\/span><span style=\"font-size: 12px\">According to MSDN documentation (see <\/span><a style=\"font-size: 12px\" href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/aa363851(v=vs.85).aspx\" target=\"_blank\">CopyFile function<\/a><span style=\"font-size: 12px\">), <\/span><strong style=\"font-size: 12px\">CopyFile<\/strong><span style=\"font-size: 12px\"> has the following function definition:<\/span><span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4621.hsg-6-25-13-1.png\"><img decoding=\"async\" title=\"Image of code\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4621.hsg-6-25-13-1.png\" alt=\"Image of code\" \/><\/a><\/p>\n<p>So <strong>CopyFile<\/strong> has a return type of BOOL and three parameters&mdash;two &lsquo;T&rsquo; strings and a bool. The key to interacting with Win API functions is knowing how to convert these C\/C++ types to the equivalent .NET type. Fortunately, there is a site dedicated to this cause: <a href=\"http:\/\/www.pinvoke.net\/\" target=\"_blank\">PINVOKE.NET<\/a> , which provides a treasure trove of the type of information you need to perform this task. It is worth a bookmark in your favorites.<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>If you search for <strong>CopyFile<\/strong> on PINVOKE.NET, you will find the following C# definition:<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p style=\"padding-left: 30px\">[DllImport(&#8220;kernel32.dll&#8221;, CharSet = CharSet.Unicode)]<br \/> static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);<\/p>\n<p><span style=\"font-size: 12px\">You can now see the translation of C\/C++ types to .NET types:<\/span><\/p>\n<p style=\"padding-left: 30px\">BOOL -&gt; bool<\/p>\n<p style=\"padding-left: 30px\">LPCTSTR -&gt; string<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>Now, you should have the background needed to start using Windows PowerShell to interact with the <strong>CopyFile<\/strong> function. Let&rsquo;s jump into our first method of interaction, <strong>Add-Type<\/strong>.<strong><\/strong><\/p>\n<h2>Using Add-Type to call the CopyItem<em> <\/em>function<\/h2>\n<p>The <strong>Add-Type<\/strong> cmdlet is used to define .NET types that will be made available to your Windows PowerShell session. What&rsquo;s really cool about it is that it can compile C# code on the fly. If you view the Help for <strong>Add-Type<\/strong>, you&rsquo;ll find some good examples of how to call Windows API functions.<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>As an example, the following code allows me to call the <strong>CopyItem<\/strong> function within Windows PowerShell:<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p style=\"padding-left: 30px\">$MethodDefinition = @&#8217;<\/p>\n<p style=\"padding-left: 30px\">[DllImport(&#8220;kernel32.dll&#8221;, CharSet = CharSet.Unicode)]<\/p>\n<p style=\"padding-left: 30px\">public static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);<\/p>\n<p style=\"padding-left: 30px\">&#8216;@<\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: 12px\">$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name &#8216;Kernel32&#8217; -Namespace &#8216;Win32&#8217; -PassThru<\/span><\/p>\n<p style=\"padding-left: 30px\"><span style=\"font-size: 12px\"># You may now call the CopyFile function<\/span><\/p>\n<p style=\"padding-left: 30px\"># Copy calc.exe to the user&#8217;s desktop<\/p>\n<p style=\"padding-left: 30px\">$Kernel32::CopyFile(&#8220;$($Env:SystemRoot)\\System32\\calc.exe&#8221;, &#8220;$($Env:USERPROFILE)\\Desktop\\calc.exe&#8221;, $False)<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>The <strong>$MethodDefinition<\/strong> variable simply contains the C# definition that I took from PINVOKE.NET with one minor modification: I defined the <strong>CopyFile<\/strong> method to be public. Methods that are added with <strong>Add-Type<\/strong> must be public to easily interact with them in Windows PowerShell.<span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n<p>I then call <strong>Add-Type<\/strong> and provide the C# source code, a type name, and a namespace. By specifying the type name and namespace, after calling <strong>Add-Type<\/strong> you can reference the new type in WindowsPowerShell with `[Win32.Kernel32]`.<\/p>\n<p><span style=\"font-size: 12px\">Lastly, by default, <\/span><strong style=\"font-size: 12px\">Add-Type<\/strong><span style=\"font-size: 12px\"> doesn&rsquo;t output the type definition that it creates. The <\/span><strong style=\"font-size: 12px\">-PassThru<\/strong><span style=\"font-size: 12px\"> parameter tells it to output the type definition.<\/span><\/p>\n<p>After calling <strong>Add-Type<\/strong>, you can finally call <strong>CopyFile<\/strong> directly within Windows PowerShell. The previous example simply copies calc.exe to the user&rsquo;s desktop. It&rsquo;s worth noting the two colons that follow the <strong>$Kernel32<\/strong> variable. These indicate that you are calling a static .NET method. All static methods are called this way in Windows PowerShell.<\/p>\n<p>To wrap things up, I wrote the <strong>Copy-RawItem<\/strong> function that wraps the <strong>CopyFile<\/strong> function nicely. The full script is also available in the Script Center Repository: <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Copy-RawItem-Add-Type-39741f8c\" target=\"_blank\">Copy-RawItem (Add-Type Version)<\/a>.<\/p>\n<p style=\"padding-left: 30px\"><strong>Copy-RawItem Function<\/strong>:<\/p>\n<p style=\"padding-left: 30px\">function Copy-RawItem<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">&lt;#<\/p>\n<p style=\"padding-left: 30px\">.SYNOPSIS<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Copies a file from one location to another including files contained within DeviceObject paths.<\/p>\n<p style=\"padding-left: 30px\">.PARAMETER Path<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Specifies the path to the file to copy.<\/p>\n<p style=\"padding-left: 30px\">.PARAMETER Destination<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Specifies the path to the location where the item is to be copied.<\/p>\n<p style=\"padding-left: 30px\">.PARAMETER FailIfExists<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Do not copy the file if it already exists in the specified destination.<\/p>\n<p style=\"padding-left: 30px\">.OUTPUTS<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; None or an object representing the copied item.<\/p>\n<p style=\"padding-left: 30px\">.EXAMPLE<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Copy-RawItem &#8216;\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy2\\Windows\\System32\\config\\SAM&#8217; &#8216;C:\\temp\\SAM&#8217;<\/p>\n<p style=\"padding-left: 30px\">#&gt;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; [CmdletBinding()]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; [OutputType([System.IO.FileSystemInfo])]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; Param (<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(Mandatory = $True, Position = 0)]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ValidateNotNullOrEmpty()]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [String]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Path,<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Parameter(Mandatory = $True, Position = 1)]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [ValidateNotNullOrEmpty()]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [String]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $Destination,<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; [Switch]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $FailIfExists<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; )<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $MethodDefinition = @&#8217;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; [DllImport(&#8220;kernel32.dll&#8221;, CharSet = CharSet.Unicode, SetLastError = true)]<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; public static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);<\/p>\n<p style=\"padding-left: 30px\">&#8216;@<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name &#8216;Kernel32&#8217; -Namespace &#8216;Win32&#8217; -PassThru<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; # Perform the copy<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; $CopyResult = $Kernel32::CopyFile($Path, $Destination, ([Bool] $PSBoundParameters[&#8216;FailIfExists&#8217;]))<\/p>\n<p style=\"padding-left: 30px\">&nbsp;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; if ($CopyResult -eq $False)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # An error occured. Display the Win32 error set by CopyFile<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; throw ( New-Object ComponentModel.Win32Exception )<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; else<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; {<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Write-Output (Get-ChildItem $Destination)<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; }<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p>The following image illustrates using the <strong>Copy-RawItem<\/strong> function.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6087.hsg-6-25-13-2.png\"><img decoding=\"async\" title=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6087.hsg-6-25-13-2.png\" alt=\"Image of command output\" \/><\/a><\/p>\n<p>The only code in the <strong>Copy-RawItem<\/strong> that warrants explanation is the last few lines where error checking occurs. The MSDN documentation states that if <strong>CopyFile<\/strong> returns FALSE, an error occurred. In C\/C++, you would determine the cause for the error by calling <strong>GetLastError<\/strong>. In Windows PowerShell, you can channel the error by throwing a ComponentModel.Win32Exception object. This is what allows you to pry out the error from a Win API function without calling <strong>GetLastError<\/strong>.<\/p>\n<p>~Matt<\/p>\n<p>Thank you, Matt. Join us tomorrow when Matt will continue this series.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><strong>Ed Wilson, Microsoft Scripting Guy<\/strong><span style=\"font-size: 12px\">&nbsp;<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Guest blogger, Matt Graeber, discusses how&nbsp;to use Windows PowerShell to interact with Windows API functions in Part 1 of a three-part series. Microsoft Scripting Guy, Ed Wilson, is here. Guest blogger, Matt Graeber, is back. Matt first joined us as a guest yesterday with his post Use PowerShell and Regular Expressions to Search Binary [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[56,431,3,63,45],"class_list":["post-3336","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-guest-blogger","tag-matt-graeber","tag-scripting-guy","tag-security","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Guest blogger, Matt Graeber, discusses how&nbsp;to use Windows PowerShell to interact with Windows API functions in Part 1 of a three-part series. Microsoft Scripting Guy, Ed Wilson, is here. Guest blogger, Matt Graeber, is back. Matt first joined us as a guest yesterday with his post Use PowerShell and Regular Expressions to Search Binary [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3336","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=3336"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/3336\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=3336"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=3336"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=3336"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}