Powershell - 调用非托管函数 CreateProfile 崩溃 Powershell.exe

Powershell - calling unmanaged Function CreateProfile crashes Powershell.exe

使用 pinvoke -- createprofile 调用一段非托管代码时。 Powershell.exe 进程在调用非托管代码中的方法后崩溃。配置文件创建成功。

为什么会这样?我的代码如下:

    function CreateProfile
    {
        param([String]$UserSid, [String]$UserName,  [system.uint32]$ProfilePath)
        Add-Type -TypeDefinition '
            using System;
            using System.Runtime.InteropServices;
            public static class PInvoke {
                [DllImport("userenv.dll", SetLastError = true, CharSet = CharSet.Auto)]
                public static extern int CreateProfile( [MarshalAs(UnmanagedType.LPWStr)] String pszUserSid, [MarshalAs(UnmanagedType.LPWStr)] String pszUserName, [Out][MarshalAs(UnmanagedType.LPWStr)] System.Text.StringBuilder pszProfilePath, uint cchProfilePath);
            }
        '
       $pszProfilePath = new-object -typename System.Text.StringBuilder
    [int]$results = [PInvoke]::CreateProfile($UserSid, $UserName, $pszProfilePath, $ProfilePath)
    }
$stringbuff = new-object system.text.stringbuilder(260)
[system.uint32]$a =$stringbuff.capacity
$sid = ((get-aduser -id 'brtestlocaluser').sid.value)
CreateProfile -usersid $sid -username 'brtestlocaluser' -ProfilePath $a

终于想通了。以另一种方式调用它似乎可以解决此问题。

function Register-NativeMethod
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
        [string]$dll,

        # Param2 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=1)]
        [string]
        $methodSignature
    )

    $script:nativeMethods += [PSCustomObject]@{ Dll = $dll; Signature = $methodSignature; }
}
function Add-NativeMethods
{
    [CmdletBinding()]
    [Alias()]
    [OutputType([int])]
    Param($typeName = 'NativeMethods')

    $nativeMethodsCode = $script:nativeMethods | ForEach-Object { "
        [DllImport(`"$($_.Dll)`")]
        public static extern $($_.Signature);
    " }

    Add-Type @"
        using System;
        using System.Text;
        using System.Runtime.InteropServices;
        public static class $typeName {
            $nativeMethodsCode
        }
"@
}
function New-ProfileFromSID {

[CmdletBinding()]
[Alias()]
[OutputType([int])]
Param
(
    # Param1 help description
    [Parameter(Mandatory=$true,
               ValueFromPipelineByPropertyName=$true,
               Position=0)]
    [string]$UserName,
    [string]$domain = ''
)
$methodname = 'UserEnvCP2'
$script:nativeMethods = @();

if (-not ([System.Management.Automation.PSTypeName]$methodname).Type)
{
    Register-NativeMethod "userenv.dll" "int CreateProfile([MarshalAs(UnmanagedType.LPWStr)] string pszUserSid,`
     [MarshalAs(UnmanagedType.LPWStr)] string pszUserName,`
     [Out][MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszProfilePath, uint cchProfilePath)";

    Add-NativeMethods -typeName $methodname;
}

$sb = new-object System.Text.StringBuilder(260);
$pathLen = $sb.Capacity;

Write-Verbose "Creating user profile for $Username";
#$SID= ((get-aduser -id $UserName -ErrorAction Stop).sid.value)
if($domain)
{
    $objUser = New-Object System.Security.Principal.NTAccount($domain, $UserName)
    $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
    $SID = $strSID.Value
}
else 
{
   $objUser = New-Object System.Security.Principal.NTAccount($UserName)
   $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
   $SID = $strSID.Value
}
Write-Verbose "$UserName SID: $SID"
try
{
   $result = [UserEnvCP2]::CreateProfile($SID, $Username, $sb, $pathLen) 
   if($result -eq '-2147024713')
   {
       $status = "$userName already exists"
       write-verbose "$username Creation Result: $result"
    }
    elseif($result -eq '-2147024809')
    {
        $status = "$username Not Found"
        write-verbose "$username creation result: $result"
    }
   elseif($result -eq 0)
   {
       $status = "$username Profile has been created"
       write-verbose "$username Creation Result: $result"
   }
   else
   {
      $status = "$UserName unknown return result: $result"
   }
}
catch
{
    Write-Error $_.Exception.Message;
    break;
}
$status
}