Search code examples
powershellbit-manipulationbitwise-operatorsbit

Powershell Hex, Int and Bit flag checking


I am trying to process a flag from the MECM command Get-CMTaskSequenceDeployment called 'AdvertFlags'.

The information from Microsoft in relation to this value is HERE

The value returned is designated as : Data type: UInt32

In the table of flags, the one I need to check is listed as :

Hexadecimal (Bit) Description
0x00000020 (5) IMMEDIATE. Announce the advertisement to the user immediately.

As part of my Powershell script I am trying to ascertain if this flag is set.

I can see by converting it to Binary that a particular bit gets set.

When the settings is enabled:

DRIVE:\> [convert]::ToString((Get-CMTaskSequenceDeployment -AdvertisementID ABC20723).AdvertFlags, 2) 
100110010000000000100000

When the setting is disabled:

DRIVE:\> [convert]::ToString((Get-CMTaskSequenceDeployment -AdvertisementID ABC20723).AdvertFlags, 2) 
100110010000000000000000

The 6th bit is changed. Great! So far though, I've been unable to find a way to check if this bit is set. I suspected something in the bitwise operators (-band -bor etc) would help me here but I've been unable to get it to work.

Any bitwise operation I try returns an error:

"System.UInt64". Error: "Value was either too large or too small for a UInt64."

I mean, I can compare the string literally, but other options may be changed at any point.

Any help greatly appreciated.

EDIT: Just as an example of the error I am seeing, I can see that the bit that is set is '32' and from my limited understanding I should be able to:

PS:\> '100110010000000000100000' -band '32'
Cannot convert value "100110010000000000100000" to type "System.UInt64". Error: "Value was either too large or too small for a UInt64."
At line:1 char:1
+ '100110010000000000100000' -band '32'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvalidCastIConvertible

But I just always return an error


Solution

  • To test bit6 in

    $AdvertFlags = (Get-CMTaskSequenceDeployment -AdvertisementID ABC20723).AdvertFlags
    

    Should simply be:

    if ($AdvertFlags -band 32) { 'bit6 is set' } else { 'bit6 is not set' }
    

    I do not have access to a deployment environment with Get-CMTaskSequenceDeployment cmdlet, nevertheless to confirm what I am stating:

    $AdvertFlags = [Convert]::ToUInt32("100110010000000000100000", 2)
    $AdvertFlags
    10027040
    if ($AdvertFlags -band 32) { 'bit6 is set' } else { 'bit6 is not set' }
    bit6 is set
    
    $AdvertFlags = [Convert]::ToUInt32("100110010000000000000000", 2)
    $AdvertFlags
    10027008
    if ($AdvertFlags -band 32) { 'bit6 is set' } else { 'bit6 is not set' }
    bit6 is not set
    

    Your self-answer using [bigint]'100110010000000000100000' -band "32" to test for bit6 is merely a coincident that it returns the expected value:

    10027035..10027045 |ForEach-Object {
        $Binary = [convert]::ToString($_, 2)
        [pscustomobject]@{
            Binary = $Binary
            bAnd   = $_ -bAnd 32
            Bigint = [bigint]$Binary -band "32"
        }
    }
    

    Yields:

    Binary                   bAnd Bigint
    ------                   ---- ------
    100110010000000000011011    0      0
    100110010000000000011100    0      0
    100110010000000000011101    0      0
    100110010000000000011110    0     32 # ← incorrect
    100110010000000000011111    0     32 # ← incorrect
    100110010000000000100000   32     32
    100110010000000000100001   32     32
    100110010000000000100010   32     32
    100110010000000000100011   32     32
    100110010000000000100100   32      0 # ← incorrect
    100110010000000000100101   32      0 # ← incorrect
    

    enumerations as flags

    But PowerShell has an even nicer way to test them by name:

    [Flags()] enum AdvertFlags {
        IMMEDIATE                         = 0x00000020 # Announce the advertisement to the user immediately.
        ONSYSTEMSTARTUP                   = 0x00000100 # Announce the advertisement to the user on system startup.
        ONUSERLOGON                       = 0x00000200 # Announce the advertisement to the user on logon.
        ONUSERLOGOFF                      = 0x00000400 # Announce the advertisement to the user on logoff.
        OPTIONALPREDOWNLOAD               = 0x00001000 # If the selected architecture and language matches that of the client, the package content will be downloaded in advance
        WINDOWS_CE                        = 0x00008000 # The advertisement is for a device client.
        ENABLE_PEER_CACHING               = 0x00010000 # This information applies to System Center 2012 Configuration Manager SP1 or later, and System Center 2012 R2 Configuration Manager or later.
        DONOT_FALLBACK                    = 0x00020000 # Do not fall back to unprotected distribution points.
        ENABLE_TS_FROM_CD_AND_PXE         = 0x00040000 # The task sequence is available to removable media and the pre-boot execution environment (PXE) service point.
        APTSINTRANETONLY                  = 0x00080000 #
        OVERRIDE_SERVICE_WINDOWS          = 0x00100000 # Override maintenance windows in announcing the advertisement to the user.
        REBOOT_OUTSIDE_OF_SERVICE_WINDOWS = 0x00200000 # Reboot outside of maintenance windows.
        WAKE_ON_LAN_ENABLED               = 0x00400000 # Announce the advertisement to the user with Wake On LAN enabled.
        SHOW_PROGRESS                     = 0x00800000 # Announce the advertisement to the user showing task sequence progress.
        NO_DISPLAY                        = 0x02000000 # The user should not run programs independently of the assignment.
        ONSLOWNET                         = 0x04000000 # Assignments are mandatory over a slow network connection.
        TARGETTOWINPE                     = 0x10000000 # Target this deployment to WinPE only.
        HIDDENINWINPE                     = 0x20000000 # Target this deployment to WinPE only but hide in WinPE. It can only be used by TS variable SMSTSPreferredAdvertID.
    }
    
    # $AdvertFlags = [AdvertFlags](Get-CMTaskSequenceDeployment -AdvertisementID ABC20723).AdvertFlags
    $AdvertFlags = [AdvertFlags][Convert]::ToUInt32("100110010000000000100000", 2)
    # or: $AdvertFlags = [AdvertFlags]('IMMEDIATE', 'ENABLE_PEER_CACHING', 'APTSINTRANETONLY', 'OVERRIDE_SERVICE_WINDOWS', 'SHOW_PROGRESS')
    $AdvertFlags
    IMMEDIATE, ENABLE_PEER_CACHING, APTSINTRANETONLY, OVERRIDE_SERVICE_WINDOWS, SHOW_PROGRESS
    $AdvertFlags -bAnd [AdvertFlags]'IMMEDIATE'
    IMMEDIATE