Skip to content

Instantly share code, notes, and snippets.

@Bill-Stewart
Created July 7, 2025 17:08
Show Gist options
  • Save Bill-Stewart/40baae695a13ff6324d8e1946ff9c862 to your computer and use it in GitHub Desktop.
Save Bill-Stewart/40baae695a13ff6324d8e1946ff9c862 to your computer and use it in GitHub Desktop.
#requires -version 3
<#
.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 0 through 18446744073709551615 (hexadecimal FFFFFFFFFFFFFFF); that is, the value can be a maximum of 64 bits in length. A Negative value will be converted and/or truncated to a 32-bit signed value.
.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
* A list of the bits set in the value (in hex and decimal)
Hexadecimal values are output in byte pairs.
.EXAMPLE
PS C:\> Get-Flags -2147483642
Dec: 2147483654 (signed: -2147483642)
Hex: 8000 0006
BitPosition-Hex BitPosition-Dec
--------------- ---------------
8000 0000 2147483648
0000 0004 4
0000 0002 2
The output shows that the negative value -2147483642 is 2147483654 as an unsigned 32-bit decimal value, or 80000006 in hexadecimal. This value has bits set in the following positions: 80000000 (decimal 2147483648), 4, and 2.
#>
[CmdletBinding()]
param(
[Parameter(Position = 0,Mandatory)]
[String]
$Value
)
# Outputs a string as a 64-bit unsigned value; negative value will be
# output/truncated as a 32-bit unsigned value
function ConvertTo-Unsigned {
param(
[String]
$value
)
if ( $value.IndexOf(".") -eq -1 ) {
$value = $value.Trim()
if ( $value[0] -eq "-" ) {
try {
[BitConverter]::ToUInt32([BitConverter]::GetBytes($value -as [Int32]),0)
}
catch {
}
}
else {
$value -as [UInt64]
}
}
}
# Outputs a 32-bit unsigned value as signed
function ConvertTo-Signed {
param(
[UInt32]
$value
)
try {
[BitConverter]::ToInt32([BitConverter]::GetBytes($value),0)
}
catch {
}
}
# Outputs unsigned integer as hex string with specifed width in nibbles and
# spaces between byte pairs
function Get-HexString {
param(
[UInt64]
$value,
[Int]
[ValidateSet(8,16)]
$nibbles = 8
)
("{0:X$nibbles}" -f $value) -replace '....(?!$)','$0 '
}
$uInt = ConvertTo-Unsigned $Value
if ( $null -eq $uInt ) {
Write-Error "Unable to convert '$Value' to an unsigned integer." -Category InvalidArgument
return
}
# Is value 64-bit (16 nibbles) or 16-bit (8 nibbles)?
$nibbles = if ( $uInt -gt [UInt32]::MaxValue ) { 16 } else { 8 }
# Most-significant bit position for 32-bit value = 2^31
$highBit32 = [BitConverter]::ToUInt32([BitConverter]::GetBytes(0x80000000),0)
# 32-bit value is signed if it's not 2^31 and sign bit is set
$signed = ($nibbles -eq 8) -and ($uInt -ne $highBit32) -and (($uInt -band $highBit32) -ne 0)
# Build and output header to host
$header = "Dec: $uInt"
if ( $signed ) { $header += " (signed: {0})" -f (ConvertTo-Signed $uInt) }
$header += "`nHex: {0}" -f (Get-HexString $uInt $nibbles)
Write-Host $header
# Most-significant bit position for 64-bit value = 2^63
$highBit64 = [BitConverter]::ToUInt64([BitConverter]::GetBytes(0x8000000000000000),0)
# Output each set bit position, starting at 2^63
for ( [UInt64] $i = $highBit64; $i -gt 0; $i /= 2 ) {
if ( ($uInt -band $i) -ne 0 ) {
[PSCustomObject] @{
"BitPosition-Hex" = Get-HexString $i $nibbles
"BitPosition-Dec" = $i
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment