Powershell, PInvoke and GetLastError



我正试图通过PInvoke从Powershell使用GetFileSecurity。调用本身可以工作,但System.Runtime.InteropServices.Marshal.GetLastWin32Error和GetLastError(我导入用于测试)都返回了错误的错误代码。PInvoke签名中的SetLastError = true似乎根本没有任何效果,因为在启动新的Powershell实例后第一次运行脚本时,两者都返回203(ERROR_ENVVAR_NOT_FOUND),但如果我再次调用同一个脚本,两者都会返回0。

作为一个快速测试,我启动了一个等效的C程序,GetLastError在那里返回期望的值(122==ERROR_INSUFFIENT_BUFFER)。

请注意,我是Powershell和.NET的新手,所以请原谅任何明显的失礼行为。

$signature = @'
[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetFileSecurity(
  string lpFileName,
  int RequestedInformation,
  byte [] pSecurityDescriptor,
  uint nLength,
  out int lpnLengthNeeded
);
[DllImport("Kernel32.dll")]
public static extern uint GetLastError();
'@
$enum = @'
namespace Win32 {
  public enum SECURITY_INFORMATION : uint
  {
    OWNER_SECURITY_INFORMATION        = 0x00000001,
    GROUP_SECURITY_INFORMATION        = 0x00000002,
    DACL_SECURITY_INFORMATION         = 0x00000004,
    SACL_SECURITY_INFORMATION         = 0x00000008,
    UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000,
    UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000,
    PROTECTED_SACL_SECURITY_INFORMATION   = 0x40000000,
    PROTECTED_DACL_SECURITY_INFORMATION   = 0x80000000
  }
}
'@

Add-Type -TypeDefinition $enum
Add-Type -MemberDefinition $signature -Name API -Namespace Win32
$len = 0
$sec = New-Object byte[] 0
$info = new-object Win32.SECURITY_INFORMATION
$info = [Win32.SECURITY_INFORMATION]::OWNER_SECURITY_INFORMATION -bor
        [Win32.SECURITY_INFORMATION]::GROUP_SECURITY_INFORMATION -bor
        [Win32.SECURITY_INFORMATION]::DACL_SECURITY_INFORMATION
[Win32.API]::GetFileSecurity("c:temp", $info, $sec, $sec.Length, [ref] $len)
[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
[Win32.API]::GetLastError()

我会创建一个包装器C#类,该类进行GetFileSecurity调用,然后得到错误。PowerShell在GetFileSecurity()pinvoke调用和GetLastWin32Error()pinvoke调用之间对Win32 API的任何调用都可能正在重置Win32错误号。

您可以将其保留在PowerShell中,只要您阻止PowerShell将GetFileSecurity()的结果直接写入控制台即可。正如Keith Hill所说,对GetLastWin32Error()的调用必须在对GetFileSecurity()的调用之后立即,其间没有控制台写入或其他Win32 API调用。

您可以通过将呼叫转换为void:来使其静音

[void]([Win32.API]::GetFileSecurity("c:temp", $info, $sec, $sec.Length, [ref] $len))
[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()

或者,您可以将其结果保存到一个变量中,然后打印:

$result = [Win32.API]::GetFileSecurity("c:temp", $info, $sec, $sec.Length, [ref] $len)
[System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
Write-Output $result

相关内容

  • 没有找到相关文章

最新更新