Home > Back-end >  Powershell Hex, Int and Bit flag checking
Powershell Hex, Int and Bit flag checking

Time:08-20

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

CodePudding user response:

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 te 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

But PowerShell has an even nicer way for enumerations as flags and test them:

[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

CodePudding user response:

As always I BELEIVE I found the answer minutes after posting (After spending a couple hours on this!).

By adjusting the type to [bigint] the comparison was able to complete and return the expected answer:

DRIVE:\> [bigint]'100110010000000000100000' -band "32"
32

So a simple:

If (([bigint]'100110010000000000100000' -band "32") -gt 0){$true}else{$false}
True

and:

If (([bigint]'100110010000000000000000' -band "32") -gt 0){$true}else{$false}
False

Solves my issue. Feel free to give any extra advice if this is not the ideal way to proceed.

I though PS would be smarted when auto defining types etc. This is targeting PS5 on Server 2012 R2 though.

  • Related