Use the Add-Type Cmdlet that Calls the Windows API Function
The Add-Type cmdlet adds a specified .NET class to a PowerShell session. This topic demonstrates how to use this cmdlet to access the CopyFile function declared in the kernel32.dll library.
Basic Implementation
Consider the script that calls the CopyFile function:
$MethodDefinition = @'
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
public static extern bool CopyFile(string lpExistingFileName, string lpNewFileName, bool bFailIfExists);
'@
$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name 'Kernel32' -Namespace 'Win32' -PassThru
$Kernel32::CopyFile("$($Env:SystemRoot)\System32\calc.exe", "$($Env:USERPROFILE)\Desktop\calc.exe", $False)
This script does the following:
-
The
$MethodDefinitionvariable contains the ะก# method definition that matches the C++ signature ofCopyFile.Expand to see the details
C++ signatureBOOL CopyFile( [in] LPCTSTR lpExistingFileName, [in] LPCTSTR lpNewFileName, [in] BOOL bFailIfExists );C# definition[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] public static extern bool CopyFile( string lpExistingFileName, string lpNewFileName, bool bFailIfExists );The DllImport attribute indicates that the
CopyFilemethod is exposed by the kernel32.dll library as a static entry point.Note the correct translation of C++ parameter types to corresponding .NET types:
C/C++ Type .NET Type BOOL bool LPCTSTR string -
The
Add-Typecmdlet creates theKernel32class containing theCopyFilemethod defined at the previous step. -
The last line of code calls the
Kernel32::CopyFilemethod to copy the calc.exe file from Windows\System32 folder to the desktop.
Further Improvements
- It may be inconvenient to edit C# code as a string inside the PowerShell script. You can save the C# code to a separate file (e.g., CopyFile.cs) and get the file content using the Get-Content cmdlet.
- You can declare the
Copy-RawItemcommandlet in a custom PowerShell module file — to make your code reusable. - You can implement error handling — throw an exception when
CopyFilefails.
The code below demonstrates the CopyRawItem.psm1 module implementation, with the above improvements:
function Copy-RawItem {
[CmdletBinding()]
[OutputType([System.IO.FileSystemInfo])]
Param (
[Parameter(Mandatory = $True, Position = 0)]
[ValidateNotNullOrEmpty()]
[String]
$Path,
[Parameter(Mandatory = $True, Position = 1)]
[ValidateNotNullOrEmpty()]
[String]
$Destination,
[Switch]
$FailIfExists
)
$MethodDefinition = Get-Content -Path .\CopyFile.cs
$Kernel32 = Add-Type -MemberDefinition $MethodDefinition -Name 'Kernel32' -Namespace 'Win32' -PassThru
$CopyResult = $Kernel32::CopyFile($Path, $Destination, ([Bool] $PSBoundParameters['FailIfExists']))
if ($CopyResult -eq $False) {
throw New-Object ComponentModel.Win32Exception(
[System.Runtime.InteropServices.Marshal]::GetLastWin32Error())
}
else {
Write-Output (Get-ChildItem $Destination)
}
}
You can import this module and call Copy-RawItem from your script as follows:
Import-Module ./CopyRawItem.psm1
Copy-RawItem \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SAM C:\temp\SAM -FailIfExists
Here, the security account manager database file is copied from the volume shadow copy to a temporary folder (which is impossible when using standard Copy-Item cmdlet). If you run Copy-RawItem twice, you will see the “file exists” error:

If you specify an incorrect path, the “system cannot find the path specified” error is displayed.
Tip
If you receive the “Access is denied” error when accessing the shadow copy, run your PowerShell session as administrator.
Note
You can get the complete code demonstrated here at GitHub: powershell-winapi-tutorial/examples/add-type.