Forum Discussion

niark's avatar
niark
Frequent Visitor
8 years ago
Solved

AD useraccountcontrol integer conversion

Hi all,

I used to use a simple PS code to translate an AD useraccountcontrol attribute value into a human readable format :

 

Function Translate-UAC {

Param ([int]$UAC)

$PropertyFlags = @(
	"SCRIPT", "ACCOUNTDISABLE", "RESERVED", "HOMEDIR_REQUIRED", "LOCKOUT", "PASSWD_NOTREQD", "PASSWD_CANT_CHANGE", "ENCRYPTED_TEXT_PWD_ALLOWED", "TEMP_DUPLICATE_ACCOUNT", "NORMAL_ACCOUNT", "RESERVED", "INTERDOMAIN_TRUST_ACCOUNT", "WORKSTATION_TRUST_ACCOUNT", "SERVER_TRUST_ACCOUNT", "RESERVED", "RESERVED", "DONT_EXPIRE_PASSWORD", "MNS_LOGON_ACCOUNT", "SMARTCARD_REQUIRED", "TRUSTED_FOR_DELEGATION", "NOT_DELEGATED", "USE_DES_KEY_ONLY", "DONT_REQ_PREAUTH", "PASSWORD_EXPIRED", "TRUSTED_TO_AUTH_FOR_DELEGATION", "RESERVED", "PARTIAL_SECRETS_ACCOUNT" "RESERVED" "RESERVED" "RESERVED" "RESERVED" "RESERVED"
)
#One property per line (commented because I use the second one)
#1..($PropertyFlags.Length) | Where-Object {$UAC -bAnd [math]::Pow(2,$_)} | ForEach-Object {$PropertyFlags[$_]} 

#One line for all properties (suits my script better)
$Attributes = ""
1..($PropertyFlags.Length) | ? {$UAC -bAnd [math]::Pow(2,$_)} | % {
If ($Attributes.Length -EQ 0) {$Attributes = $PropertyFlags[$_]}
Else {$Attributes = $Attributes + " | " + $PropertyFlags[$_]}
} Return $Attributes } Translate-UAC -UAC 66080

this function returns : PASSWD_NOTREQD | NORMAL_ACCOUNT | DONT_EXPIRE_PASSWORD

 

 

what I did in PBI, is to create a new table with all values (PASSWD_NOTREQD...)  and an index column starting by 1.

the question is, from a useraccountcontrol value in another table (AD_Table) how can I filter the value from TABLE1 if the calculation of the bitwise is 'true' and from that take the 'human readable value' and concatenate them into one cell...

 

here manual result :

userAccountControl  Column1

66082ACCOUNTDISABLE | PASSWD_NOTREQD | NORMAL_ACCOUNT | DONT_EXPIRE_PASSWORD
514ACCOUNTDISABLE | NORMAL_ACCOUNT
66048NORMAL_ACCOUNT | DONT_EXPIRE_PASSWORD
512NORMAL_ACCOUNT
66080PASSWD_NOTREQD | NORMAL_ACCOUNT | DONT_EXPIRE_PASSWORD

 

Thanks for your help !

  • Here is the solution :

    // input is the cell with the decimal value ei:512
    // tableref is the table referencing the decimal values with the 'human readable' ones
    // columnref is the column name of tableref where decimal values are
    // delimiter is the character to split by ei:|
    // the result is a text ei:PASSWD_NOTREQD|NORMAL_ACCOUNT|DONT_EXPIRE_PASSWORD
    // the function can be updated to return a table/list to have it expanded for example
    (input as number, tableref as table, columnref as text,delimiter as text) as text =>
    let
    	//create a list with all potential values. should be 32 for this purpose
    	values = {1..Table.RowCount(tableref)},
    	//function to have the power of a decimal value
    	fnPower = (value as number) => Number.Power(2,value),
    	//function to have the bitwise "and" value. this function compare the power value against the input ei: 8/512
    	fnBitwise = (value as number, v as number) => Number.BitwiseAnd(value,v),
    	//all values are calculated (pow2) and the bitwise and is retrieved
    	//an index column is then added to get the position of the values 
    	//the result is filtered to get records that are not 0 (0 means the bitwise comparison failed)
    	TableResult = Table.SelectRows(
                            Table.AddIndexColumn(
    			    Table.FromList(
    			        List.Transform(
    				    values,
    				    each fnBitwise(fnPower(_),input)
    				),
    				Splitter.SplitByNothing(),
    				null,
    				null,
    				ExtraValues.Error
    			    ),
    			    "Index",
    			    1,
    			    1
                            ),
    			each ([Column1] <> 0)
    		    ),
    	//the result is merged with the reference table on the referenced column. the inner join is used to filtered out not required values
    	//then the rows are merged into one cell with the positioned delimiter
    	Result = Text.Combine(
                        Table.ExpandTableColumn(
                            Table.RemoveColumns(
                                Table.NestedJoin(TableResult,{"Column1"},tableref,{columnref},columnref,JoinKind.Inner),
    			    {"Column1", "Index"}
    			),
    			columnref
    			,{"flag"}
    			,{"flag"}
    		    )[flag],
    		    delimiter
                    )
    in
    	Result

    the reference table is like this :

    flaghexadecimaldecimal

    SCRIPT0x00011
    ACCOUNTDISABLE0x00022
    RESERVED0x00044
    HOMEDIR_REQUIRED0x00088
    LOCKOUT0x001016
    PASSWD_NOTREQD0x002032
    PASSWD_CANT_CHANGE0x004064
    ENCRYPTED_TEXT_PWD_ALLOWED0x0080128
    TEMP_DUPLICATE_ACCOUNT0x0100256
    NORMAL_ACCOUNT0x0200512
    RESERVED0x04001024
    INTERDOMAIN_TRUST_ACCOUNT0x08002048
    WORKSTATION_TRUST_ACCOUNT0x10004096
    SERVER_TRUST_ACCOUNT0x20008192
    RESERVED0x400016384
    RESERVED0x800032768
    DONT_EXPIRE_PASSWORD0x1000065536
    MNS_LOGON_ACCOUNT0x20000131072
    SMARTCARD_REQUIRED0x40000262144
    TRUSTED_FOR_DELEGATION0x80000524288
    NOT_DELEGATED0x1000001048576
    USE_DES_KEY_ONLY0x2000002097152
    DONT_REQ_PREAUTH0x4000004194304
    PASSWORD_EXPIRED0x8000008388608
    TRUSTED_TO_AUTH_FOR_DELEGATION0x100000016777216
    RESERVED0x200000033554432
    PARTIAL_SECRETS_ACCOUNT0x400000067108864
    RESERVED0x8000000134217728
    RESERVED0x10000000268435456
    RESERVED0x20000000536870912
    RESERVED0x400000001073741824
    RESERVED0x800000002147483648

     

    and to use it, add a custom function column :

    #"Invoked Custom Function1" = Table.AddColumn(#"Removed Columns", "UAC", each fnConvertUAC([userAccountControl], UACRef, "decimal", "|"))

     

    Hope it will help.

     

    if someone comes with a better/quicker/less code way, don't hesitate to share :)

14 Replies

    • niark's avatar
      niark
      Frequent Visitor

      Hi,

      the sources :

      tableName = User

      content =

      displayNameuserAccountControl
      User166082
      User2514
      User366048
      User4512
      User566080

       

      tableName = UAC_Flags

      content =

      FlagHexDec
      SCRIPT0x00011
      ACCOUNTDISABLE0x00022
      RESERVED0x00044
      HOMEDIR_REQUIRED0x00088
      LOCKOUT0x001016
      PASSWD_NOTREQD0x002032
      PASSWD_CANT_CHANGE0x004064
      ENCRYPTED_TEXT_PWD_ALLOWED0x0080128
      TEMP_DUPLICATE_ACCOUNT0x0100256
      NORMAL_ACCOUNT 0x0200512
      RESERVED  
      INTERDOMAIN_TRUST_ACCOUNT 0x08002048
      WORKSTATION_TRUST_ACCOUNT0x10004096
      SERVER_TRUST_ACCOUNT 0x20008192
      RESERVED   
      RESERVED   
      DONT_EXPIRE_PASSWORD 0x1000065536
      MNS_LOGON_ACCOUNT 0x20000131072
      SMARTCARD_REQUIRED0x40000262144
      TRUSTED_FOR_DELEGATION 0x80000524288
      NOT_DELEGATED0x1000001048576
      USE_DES_KEY_ONLY 0x2000002097152
      DONT_REQ_PREAUTH0x4000004194304
      PASSWORD_EXPIRED 0x8000008388608
      TRUSTED_TO_AUTH_FOR_DELEGATION0x100000016777216
      RESERVED  
      PARTIAL_SECRETS_ACCOUNT0x0400000067108864
      RESERVED  
      RESERVED  
      RESERVED  
      RESERVED  
      RESERVED  

       

      expected result :

      displayNameuserAccountControlFlags
      User166082ACCOUNTDISABLE | PASSWD_NOTREQD | NORMAL_ACCOUNT | DONT_EXPIRE_PASSWORD
      User2514ACCOUNTDISABLE | NORMAL_ACCOUNT
      User366048NORMAL_ACCOUNT | DONT_EXPIRE_PASSWORD
      User4512NORMAL_ACCOUNT
      User566080PASSWD_NOTREQD | NORMAL_ACCOUNT | DONT_EXPIRE_PASSWORD

       

      • niark's avatar
        niark
        Frequent Visitor

        Here is the solution :

        // input is the cell with the decimal value ei:512
        // tableref is the table referencing the decimal values with the 'human readable' ones
        // columnref is the column name of tableref where decimal values are
        // delimiter is the character to split by ei:|
        // the result is a text ei:PASSWD_NOTREQD|NORMAL_ACCOUNT|DONT_EXPIRE_PASSWORD
        // the function can be updated to return a table/list to have it expanded for example
        (input as number, tableref as table, columnref as text,delimiter as text) as text =>
        let
        	//create a list with all potential values. should be 32 for this purpose
        	values = {1..Table.RowCount(tableref)},
        	//function to have the power of a decimal value
        	fnPower = (value as number) => Number.Power(2,value),
        	//function to have the bitwise "and" value. this function compare the power value against the input ei: 8/512
        	fnBitwise = (value as number, v as number) => Number.BitwiseAnd(value,v),
        	//all values are calculated (pow2) and the bitwise and is retrieved
        	//an index column is then added to get the position of the values 
        	//the result is filtered to get records that are not 0 (0 means the bitwise comparison failed)
        	TableResult = Table.SelectRows(
                                Table.AddIndexColumn(
        			    Table.FromList(
        			        List.Transform(
        				    values,
        				    each fnBitwise(fnPower(_),input)
        				),
        				Splitter.SplitByNothing(),
        				null,
        				null,
        				ExtraValues.Error
        			    ),
        			    "Index",
        			    1,
        			    1
                                ),
        			each ([Column1] <> 0)
        		    ),
        	//the result is merged with the reference table on the referenced column. the inner join is used to filtered out not required values
        	//then the rows are merged into one cell with the positioned delimiter
        	Result = Text.Combine(
                            Table.ExpandTableColumn(
                                Table.RemoveColumns(
                                    Table.NestedJoin(TableResult,{"Column1"},tableref,{columnref},columnref,JoinKind.Inner),
        			    {"Column1", "Index"}
        			),
        			columnref
        			,{"flag"}
        			,{"flag"}
        		    )[flag],
        		    delimiter
                        )
        in
        	Result

        the reference table is like this :

        flaghexadecimaldecimal

        SCRIPT0x00011
        ACCOUNTDISABLE0x00022
        RESERVED0x00044
        HOMEDIR_REQUIRED0x00088
        LOCKOUT0x001016
        PASSWD_NOTREQD0x002032
        PASSWD_CANT_CHANGE0x004064
        ENCRYPTED_TEXT_PWD_ALLOWED0x0080128
        TEMP_DUPLICATE_ACCOUNT0x0100256
        NORMAL_ACCOUNT0x0200512
        RESERVED0x04001024
        INTERDOMAIN_TRUST_ACCOUNT0x08002048
        WORKSTATION_TRUST_ACCOUNT0x10004096
        SERVER_TRUST_ACCOUNT0x20008192
        RESERVED0x400016384
        RESERVED0x800032768
        DONT_EXPIRE_PASSWORD0x1000065536
        MNS_LOGON_ACCOUNT0x20000131072
        SMARTCARD_REQUIRED0x40000262144
        TRUSTED_FOR_DELEGATION0x80000524288
        NOT_DELEGATED0x1000001048576
        USE_DES_KEY_ONLY0x2000002097152
        DONT_REQ_PREAUTH0x4000004194304
        PASSWORD_EXPIRED0x8000008388608
        TRUSTED_TO_AUTH_FOR_DELEGATION0x100000016777216
        RESERVED0x200000033554432
        PARTIAL_SECRETS_ACCOUNT0x400000067108864
        RESERVED0x8000000134217728
        RESERVED0x10000000268435456
        RESERVED0x20000000536870912
        RESERVED0x400000001073741824
        RESERVED0x800000002147483648

         

        and to use it, add a custom function column :

        #"Invoked Custom Function1" = Table.AddColumn(#"Removed Columns", "UAC", each fnConvertUAC([userAccountControl], UACRef, "decimal", "|"))

         

        Hope it will help.

         

        if someone comes with a better/quicker/less code way, don't hesitate to share :)

  • Wow - that totally works!  I've never tried working with a custom function before but you've definitely opened a cool door.  Thanks!