Home > database >  Assigning byte array to an object in PowerShell
Assigning byte array to an object in PowerShell

Time:03-29

Looking for a way to assign byte array to an object - tried using -as operator with no luck. (Targeting PowerShell version 5.1)

$CSharpCode = @"
using System;
namespace TestStructure
{
    public struct TestStructure3
    {
       public Byte Field1;
       public Byte Field2;
       public UInt32 Field3;
       public UInt32 Field4;
    }

    public struct TestStructure2
    {
       public UInt32 Field1;
       public UInt32 Field2;
    }

    public struct TestStructure1
    {
       public UInt16 Field1;
       public UInt16 Field2;
       public TestStructure2 Field3;
       public TestStructure3 Field4;
    }
}
"@

Add-Type -TypeDefinition $CSharpCode

[byte[]]$BytesArray = 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22

$MyObject = $BytesArray -as [TestStructure.TestStructure1]
  • that last call fails, $MyObject is $null

CodePudding user response:

PowerShell doesn't natively translate between byte arrays and initialized instances of blittable types, but you can write a small utility function to take care of it like this:

function ConvertTo-Struct
{
  # Only accept struct types (sealed value types that are neither primitive nor enum)
  param(
    [Parameter(Mandatory = $true)]
    [ValidateScript({ $_.IsValueType -and $_.IsSealed -and -not($_.IsPrimitive -or $_.IsEnum) })]
    [Type]$TargetType,

    [Parameter(Mandatory = $true)]
    [byte[]]$BinaryData
  )

  # Start by calculating minimum size of the underlying memory allocation for the new struct
  $memSize = [System.Runtime.InteropServices.Marshal]::SizeOf([type]$TargetType)

  # Make sure user actually passed enough data to initialize struct
  if($memSize -gt $BinaryData.Length){
    Write-Error "Not enough binary data to create an instance of [$($TargetType.FullName)]"
    return
  }

  # now we just need some unmanaged memory in which to create our struct instance
  $memPtr = [IntPtr]::Zero
  try {
    $memPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($memSize)

    # copy byte array to allocated unmanaged memory from previous step
    [System.Runtime.InteropServices.Marshal]::Copy($BinaryData, 0, $memPtr, $memSize)

    # then marshal the new memory region as a struct and return
    return [System.Runtime.InteropServices.Marshal]::PtrToStructure($memPtr, [type]$TargetType)
  }
  finally {
    # and finally remember to clean up the allocated memory
    if($memPtr -ne [IntPtr]::Zero){
      [System.Runtime.InteropServices.Marshal]::FreeHGlobal($memPtr)
    }
  }
}

Now that we've gotten that squared away, let's put it to use:

$testStructure1 = ConvertTo-Struct -TargetType ([TestStructure.TestStructure1]) -BinaryData (1..24 -as [byte[]])
  • Related