Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
niark
Frequent Visitor

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.

pbi.JPG

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 !

1 ACCEPTED SOLUTION
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 🙂

View solution in original post

14 REPLIES 14
phillip_from_oz
Frequent Visitor

I’m trying to do bitwise operation on the userAccountControl field of Active Directory(AD) user table.

 

I’ve successfully loaded the AD user table.

 

I’m using this article:

https://community.powerbi.com/t5/Desktop/AD-useraccountcontrol-integer-conversion/td-p/437105

but having trouble doing this step:

phillip_from_oz_0-1642525467121.png

 

 

This is where I’m at:

phillip_from_oz_1-1642525467135.png

 

 

But the “Insert Step After” is blanked out.

 

Please how do I fix this?

 

 

KenSkinner
Frequent Visitor

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

v-yulgu-msft
Employee
Employee

Hi @niark,

 

Please provide more details about source data in Power BI and the result table you want to achieve.

How to Get Your Question Answered Quickly

 

regards,

Yuliana Gu

Community Support Team _ Yuliana Gu
If this post helps, then please consider Accept it as the solution to help the other members find it more quickly.

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  - Thanks for the solution. I have time understanding the M code but followed all most steps. I'm still not sure how you got table UAC_Flags? Does the code you provided generates it or got it from somewhere else?

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 🙂

I really like this, but I ams struggling on this. After I create the new blank query and paste the code above. It doesnt give me the option to right click in applied steps. It want's me to enter Parameters. Do you have any screenshots or anything that can help me with this? I would really appreciate it. 

Anonymous
Not applicable

Hi,

Just wanted to thank you for the solution you provided to the other person. After much headscratching I worked out how to use your solution. All I have to say is you must be really smart 🙂 I wonder if the Power BI people will integrate your idea in to Power BI AD interface so it can translate the Microsoft hex codes in to human readable format.

Ciao

Anonymous
Not applicable

@niark Thanks for following through with the solution. I'm having trouble implementing the last step of your solution within PowerBI. I have the data and columsn in powerBI, but how are you invoking the PS script you developed? Any guidance would be appreciated. 

Hi @Anonymous ,

 

the code has to be used as a function.

 

please follow these steps :

go to "edit queries"

create a new blank query

open the advanced editor

paste the code as is

name the query as you want (ei:fnConvertUAC)

in the "applied step" pane add a new step (right click) and paste the content of the formula : #"Invoked Custom Function1" = Table.AddColumn(<Previous Step>, <Name of the column to create>, each fnConvertUAC([userAccountControl], UACRef, "decimal", "|"))

where

[userAccountControl] = the column where the data are

UACRef = the table having the references (headers are "flag" "hexadecimal" "decimal") in my previous post

"decimal" = the column to use to compare (as userAccountControl is an [int] the decimal column should be used)

"|" = the separator you want

 

Hope it's clearer.

 

and sorry for the delay, the email sent by the forum was under my spams...

 

Regards

 

 

 

Hi,

I am getting the below error when I invoke the function.

Function:

= Table.AddColumn(user, "UAC", each fnConvertUAC([userAccountControl], UAC_Flags, "decimal", "|"))

 

Error:

Expression.Error: The column 'decimal' of the table wasn't found.
Details:
decimal

Hi bagurudeen,

« decimal » is the name of the column containing the values. Power query is a case sentive language be careful with such mistakes.

Regards

Thank you very much for your quick response.

 

Now when I run the function, its creating an empty column. 

 

User table:

displayNameuserAccountControl

User166082
User2514
User366048
User4512
User5

66080

 

Applied steps

= Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCi1OLTJU0lEyMzOwMFKK1YGIGAFFTA1N4HxjiAoTC7iICVgFQocp1AwDpdhYAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [displayName = _t, userAccountControl = _t])

 

= Table.TransformColumnTypes(Source,{{"userAccountControl", Int64.Type}})

 

UAC_Flags table:

FlagHexDec

SCRIPT0x00011
ACCOUNTDISABLE0x00022
RESERVED0x00044
HOMEDIR_REQUIRED0x00088
LOCKOUT0x001016
PASSWD_NOTREQD0x002032
PASSWD_CANT_CHANGE0x004064
ENCRYPTED_TEXT_PWD_ALLOWED0x0080128
TEMP_DUPLICATE_ACCOUNT0x0100256
NORMAL_ACCOUNT0x0200512
RESERVED null
INTERDOMAIN_TRUST_ACCOUNT0x08002048
WORKSTATION_TRUST_ACCOUNT0x10004096
SERVER_TRUST_ACCOUNT0x20008192
RESERVED null
RESERVED null
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
RESERVED null
PARTIAL_SECRETS_ACCOUNT0x0400000067108864
RESERVED null
RESERVED null
RESERVED null
RESERVED null
RESERVED null

 

Applied steps:

= Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("rZPBjuMgDIZfpcp5DkBIQo8MeFrUBDLgTKeqRrzGPv4SSNqm073tIRLCP/bn3871WgXlzYjVW0X+EEJoOtDq5+1aSaXcZFGbIN97WOMsHViOewjgv0CvEZ4OPEeObgBtfPTwORl/V4h0EFnRO3Vy01qUkrlomyOjDOGso3WYXq8v2Syo2aNASYtRHaU9rGh8FrWFAKzylxFBR4RvjGN6IPvenW8sIpdkhQZhGKOext4oiRCXxouSklnJmkJnnR9kvyp2RcKypKG/bNnlb740FsFrN0hjI/op4FMKUaoQXoDOzp8CSjTuSZ7VCWlWc7IvULmef5WXFaWg+y3bbgP3+la7ZDB8j2mAMXvuvN7d6mevm6YuBIMNsXeHRPurfPa5pqQrBGGQHpX0erscfFGyllFeRpjbSQP8cD5q6OGQ7SiJxSJvGGdCLJPBVbbkzJi5fLK16QrpFCDJQjzBJTrbXx5AywT2HW3Y3YBEGUcPcsLjHTS7T/e8Jvy+ksmexS79AJntr4Voidh0hS7OOZ+6e+Auv0TXdWz5MV7u1ZjcNGkhAygPGLary2+J2o6SxMD/nei/X/78BQ==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type text) meta [Serialized.Text = true]) in type table [Flag = _t, Hex = _t, Dec = _t])

 

= Table.TransformColumnTypes(Source,{{"Flag", type text}, {"Hex", type text}, {"Dec", Int64.Type}})

 

= Table.TransformColumnTypes(#"Changed Type",{{"Dec", type number}})

 

Your code:

= (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

 

Invoked fucntion:

= Table.AddColumn(user, "UAC", each fnConvertUAC([userAccountControl], UAC_Flags, "Dec", "|"))

 

Result:

displayNameuserAccountControlUAC

User166082 
User2514 
User366048 
User4512 
User566080 

 

Dont know what I am doing wrong, appreciate you help. Thank you again.

If you are still having trouble, a small tweak to the reference table.  Make the column names (i.e. Flag, Hex, Dec) all lower case | flag hex dec - this will fix the error! 

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.