Skip to content

Instantly share code, notes, and snippets.

@Bill-Stewart
Last active July 14, 2025 20:16
Show Gist options
  • Save Bill-Stewart/e97e02d761f41a8a04a831135774a604 to your computer and use it in GitHub Desktop.
Save Bill-Stewart/e97e02d761f41a8a04a831135774a604 to your computer and use it in GitHub Desktop.
#requires -version 3
# Version history:
#
# 2025-07-14
# * Added spaces in binary string output to improve readability.
#
# 2025-07-11
# * Initial version. Replaces an older script.
<#
.SYNOPSIS
Outputs the bits that are set in a numeric value.
.DESCRIPTION
Outputs the positions of individual bits that are set in a numeric value. The value must fit in the range -2147483648 (i.e., the smallest possible signed 32-bit value) through 18446744073709551615 (i.e., the largest possible unsigned 64-bit value). A negative value is cast to a 32-bit unsigned integer.
.PARAMETER Value
Specifies the value.
.OUTPUTS
The output contains the following information:
* The value in decimal (including the signed decimal value if 32 bit)
* The value in hexadecimal
* The value in binary
* A list of the bits set in the value
Hexadecimal values are output in byte pairs.
.EXAMPLE
PS C:\> Get-BitFlags -2147483642
Dec: 2147483654 (signed: -2147483642)
Hex: 8000 0006
Bin: 10000000 00000000 00000000 00000110
Bit Hex Dec
--- --- ---
2^31 8000 0000 2147483648
2^2 0000 0004 4
2^1 0000 0002 2
The output shows that the negative value -2147483642 is 2147483654 as an unsigned 32-bit decimal value, or 80000006 in hexadecimal. In this value, bits are set in the following positions: 2^31, 2^1, and 2^1.
#>
[CmdletBinding()]
param(
[Parameter(Position = 0,Mandatory)]
[String]
$Value
)
# Outputs a string as a 64-bit unsigned integer; a negative value will be cast
# to a 32-bit unsigned integer
function ConvertTo-Unsigned {
param(
[String]
$value
)
if ( $value.IndexOf(".") -eq -1 ) {
$value = $value.Trim()
if ( $value[0] -eq "-" ) {
$int32 = $value -as [Int32]
if ( $null -ne $int32 ) {
[BitConverter]::ToUInt32([BitConverter]::GetBytes($int32),0)
}
}
else {
$value -as [UInt64]
}
}
}
# Outputs a 32-bit unsigned integer as a signed integer
function ConvertTo-Signed {
param(
[UInt32]
$value,
[Int]
$bits
)
[BitConverter]::ToInt32([BitConverter]::GetBytes($value),0)
}
# Tests whether an unsigned integer can be interpreted as 32-bit signed
function Test-Signed {
[CmdletBinding()]
param(
[Parameter(Position = 0,Mandatory)]
[UInt64]
$value
)
if ( $value -gt [UInt32]::MaxValue ) {
return $false
}
(ConvertTo-Signed $value) -lt 0
}
# Outputs the bit width for an unsigned integer "rounded up":
# * 0x100000000 or greater = 64 bits
# * 0x1000 to 0xFFFFFFFF = 32 bits
# * 0x100 to 0xFFFF = 16 bits
# * 0 to 0xFF = 8 bits
function Get-BitWidth {
[CmdletBinding()]
param(
[Parameter(Position = 0,Mandatory)]
[UInt64]
$value
)
if ( $value -gt [UInt32]::MaxValue ) { return 64 }
elseif ( $value -gt [UInt16]::MaxValue ) { return 32 }
elseif ( $value -gt [Byte]::MaxValue ) { return 16 }
else { return 8 }
}
# Outputs unsigned integer as hex string byte pairs using the specified width;
# if width not specified, output using automatic width
function ConvertTo-HexString {
param(
[UInt64]
$value,
[Int]
[ValidateSet(0,2,4,8,16)]
$width = 0
)
if ( $width -eq 0 ) {
$width = (Get-BitWidth $value) / 4
}
("{0:X$width}" -f $value) -replace '....(?!$)','$0 '
}
# Outputs unsigned integer as binary string with leading zeros with a space
# between each byte
function ConvertTo-BinaryString {
param(
[Parameter(Position = 0,Mandatory)]
[UInt64]
$value
)
# Why character array?
# * "b" string format specifier not universally available
# * [Convert]::ToString doesn't support UInt64 values
$width = Get-BitWidth $value
$chars = New-Object Char[] $width
for ( $i = $width - 1; $i -ge 0; $i-- ) {
$chars[$i] = ('0','1')[$value -band 1]
$value = $value -shr 1
}
($chars -join '') -replace '........(?!$)','$0 '
}
$uInt = ConvertTo-Unsigned $Value
if ( $null -eq $uInt ) {
Write-Error "Unable to convert '$Value' to an unsigned integer." -Category InvalidArgument
return
}
# Build and output header to host
$header = "Dec: $uInt"
if ( Test-Signed $uInt ) {
$header += " (signed: {0})" -f (ConvertTo-Signed $uInt)
}
$header += "`nHex: {0}" -f (ConvertTo-HexString $uInt)
$header += "`nBin: {0}" -f (ConvertTo-BinaryString $uInt)
Write-Host $header
# Get width of hex strings for output objects
$hexWidth = (Get-BitWidth $uInt) / 4
# Output each set bit starting at most significant bit (2^63)
$bit = 63
for ( [UInt64] $i = [UInt64] [Math]::Pow(2,$bit); $i -gt 0; $i /= 2 ) {
if ( ($uInt -band $i) -ne 0 ) {
[PSCustomObject] @{
"Bit" = "2^{0}" -f $bit
"Hex" = ConvertTo-HexString $i $hexWidth
"Dec" = $i
}
}
$bit--
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment