
Welcome PowerShell User! This recipe is just one of the hundreds of useful resources contained in the PowerShell Cookbook.
If you own the book already, login here to get free, online, searchable access to the entire book's content.
If not, the Windows PowerShell Cookbook is available at Amazon, or any of your other favourite book retailers. If you want to see what the PowerShell Cookbook has to offer, enjoy this free 90 page e-book sample: "The Windows PowerShell Interactive Shell".
You want to work with binary data in a file.
There are two main techniques when working with binary data in a file. The first is to read the file using the Byte encoding, so that PowerShell doesn’t treat the content as text. The second is to use the BitConverter class to translate these bytes back and forth into numbers that you more commonly care about.
Example 9-2 displays the “characteristics” of a Windows executable. The beginning section of any executable (a .dll, .exe, or any of several others) starts with a binary section known as the Portable Executable (PE) header—which contains a Common Object File Format (COFF) header. Part of this header includes characteristics about that file, such as whether the file is a DLL.
For more information about the PE header format, see the PE header format specification.
################################################################################## Get-Characteristics#### From PowerShell Cookbook (O'Reilly)## by Lee Holmes (http://www.leeholmes.com/guide)################################################################################<#.SYNOPSISGet the file characteristics of a file in the PE Executable File Format..EXAMPLEPS > Get-Characteristics $env:WINDIR\notepad.exeIMAGE_FILE_LOCAL_SYMS_STRIPPEDIMAGE_FILE_RELOCS_STRIPPEDIMAGE_FILE_EXECUTABLE_IMAGEIMAGE_FILE_32BIT_MACHINEIMAGE_FILE_LINE_NUMS_STRIPPED#>param(## The path to the file to check[Parameter(Mandatory=$true)][string]$Path)Set-StrictMode-Version3## Define the characteristics used in the PE file header.## Taken from:## http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx$characteristics=@{}$characteristics["IMAGE_FILE_RELOCS_STRIPPED"]=0x0001$characteristics["IMAGE_FILE_EXECUTABLE_IMAGE"]=0x0002$characteristics["IMAGE_FILE_LINE_NUMS_STRIPPED"]=0x0004$characteristics["IMAGE_FILE_LOCAL_SYMS_STRIPPED"]=0x0008$characteristics["IMAGE_FILE_AGGRESSIVE_WS_TRIM"]=0x0010$characteristics["IMAGE_FILE_LARGE_ADDRESS_AWARE"]=0x0020$characteristics["RESERVED"]=0x0040$characteristics["IMAGE_FILE_BYTES_REVERSED_LO"]=0x0080$characteristics["IMAGE_FILE_32BIT_MACHINE"]=0x0100$characteristics["IMAGE_FILE_DEBUG_STRIPPED"]=0x0200$characteristics["IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP"]=0x0400$characteristics["IMAGE_FILE_NET_RUN_FROM_SWAP"]=0x0800$characteristics["IMAGE_FILE_SYSTEM"]=0x1000$characteristics["IMAGE_FILE_DLL"]=0x2000$characteristics["IMAGE_FILE_UP_SYSTEM_ONLY"]=0x4000$characteristics["IMAGE_FILE_BYTES_REVERSED_HI"]=0x8000## Get the content of the file, as an array of bytes$fileBytes=Get-Content$path-ReadCount0-AsByteStream## The offset of the signature in the file is stored at location 0x3c.$signatureOffset=[BitConverter]::ToUint32($fileBytes,0x3c)## Ensure it is a PE file$signature=[char[]]$fileBytes[$signatureOffset..($signatureOffset+3)]if(($signature-join'')-ne"PE`0`0"){throw"This file does not conform to the PE specification."}## The location of the COFF header is 4 bytes into the signature$coffHeader=$signatureOffset+4## The characteristics data are 18 bytes into the COFF header. The## BitConverter class manages the conversion of the 4 bytes into an integer.$characteristicsData=[BitConverter]::ToInt32($fileBytes,$coffHeader+18)## Go through each of the characteristics. If the data from the file has that## flag set, then output that characteristic.foreach($keyin$characteristics.Keys){$flag=$characteristics[$key]if(($characteristicsData-band$flag)-eq$flag){$key}}
For most files, this technique is the easiest way to work with binary data. If you actually modify the binary data, then you will also want to use the Byte encoding when you send it back to disk:
$fileBytes|Set-Contentmodified.exe-AsByteStream
For extremely large files, though, it may be unacceptably slow to load the entire file into memory when you work with it. If you begin to run against this limit, the solution is to use file management classes from the .NET Framework. These classes include BinaryReader, StreamReader, and others. For more information about working with classes from the .NET Framework, see Recipe 3.8. For more information about running scripts, see Recipe 1.2.
Recipe 1.2, “Run Programs, Scripts, and Existing Tools”
Recipe 3.8, “Work with .NET Objects”