Active Directory – Decoding UserAccountControl Attribute Values

In Active Directory, When we open properties of an user account, click the Account tab, and then either check or uncheck boxes in the Account options dialog box, numerical values are assigned to the UserAccountControl attribute. This UserAccountControl attribute determines the state of an account in the AD domain: active or locked, Password change at the next logon is enabled or not, if users can change their passwords and other options.

UserAccountControl Attribute in AD

To view user accounts,

  1. Click Start –> Programs
  2. Open Administrative Tools
  3. Click Active Directory Users and Computers
    • Or run dsa.msc from run window
  4. Search for a user and right-click and select Properties
  5. Click on Account tab

The Account Options section has the following options,

  • User must change password at next logon
  • User cannot change password
  • Password never expires
  • Store password using reversible encryption
  • Account is disabled
  • Smart card is required for interactive logon
  • Account is sensitive and cannot be delegated
  • User Kerberos DES encryption types for this account
  • This account supports Kerberos AES 128 bit encryption
  • This account supports Kerberos AES 256 bit encryption
  • Do not require Kerberos preauthentication

Each of these user account options is 1 (True) or 0 (False) and are not stored as separate AD attributes, instead the UserAccountControl attribute is used. The flags are cumulative. The total value of all options are stored in the value of UserAccountControl attribute.

To determine the current value of the attribute,

Using PowerShell,

$user = Read-Host "Enter user's logon"
Get-ADuser $user -properties * | Select name, UserAccountControl | ft

Using dsa.msc,

  1. dsa.msc from Run window
  2. Search for a user and right-click and select Properties
  3. Click on Attribute Editor tab
    • If you are missing this tab, Click View in the Active Directory Users and Computers window and select Advanced Features

In this example, the value of the attribute is 0x200 (decimal value is 512).

The following table lists possible flags that can be assigned to an account. Each flag corresponds to a certain UserAccountControl bit, and UserAccountControl value equals the sum of all flags.

UserAccountControl FlagHexadecimal ValueDecimal Value
SCRIPT0x00011
ACCOUNTDISABLE0x00022
HOMEDIR_REQUIRED0x00088
LOCKOUT0x001016
PASSWD_NOTREQD0x002032
PASSWD_CANT_CHANGE0x004064
ENCRYPTED_TEXT_PWD_ALLOWED0x0080128
TEMP_DUPLICATE_ACCOUNT0x0100256
NORMAL_ACCOUNT0x0200512
INTERDOMAIN_TRUST_ACCOUNT0x08002048
WORKSTATION_TRUST_ACCOUNT0x10004096
SERVER_TRUST_ACCOUNT0x20008192
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
PARTIAL_SECRETS_ACCOUNT0x0400000067108864

The userAccountControl value is calculated as,

NORMAL_ACCOUNT (512) + ACCOUNTDISABLE (2) = 514

NORMAL_ACCOUNT (512) + DONT_EXPIRE_PASSWORD (65536) + ACCOUNTDISABLE (2) = 66050

To list all active users,

Get-ADUser -Properties * -ldapFilter "(useraccountcontrol=512)" | Select UserPrincipalName,userAccountControl | ft

To list all disabled user accounts,

Get-ADUser -Properties * -ldapFilter "(useraccountcontrol=514)" | Select UserPrincipalName,userAccountControl | ft

To list accounts with a non-expiring password,

Get-ADUser -Properties * -ldapFilter "(useraccountcontrol=66048)" | Select UserPrincipalName,userAccountControl | ft

Here are the default UserAccountControl values for the certain objects:

  • Typical user: 0x200 (512)
  • Domain controller: 0x82000 (532480)
  • Workstation/server: 0x1000 (4096)

Decode UserAccountControl Values

To fully decode UserAccountControl bit field we can use this PowerShell script,

Add-Type -TypeDefinition @'
[System.Flags]
public enum UserAccountControl{
	SCRIPT = 1,
	ACCOUNTDISABLE = 2,
	BIT_02 =  4,
	HOMEDIR_REQUIRED = 8,
	LOCKEDOUT = 16,
	PASSWD_NOTREQD = 32,
	PASSWD_CANT_CHANGE = 64,
	ENCRYPTED_TEXT_PWD_ALLOWED = 128,
	TEMP_DUPLICATE_ACCOUNT = 256,
	NORMAL_ACCOUNT = 512,
	BIT_10 = 1024,
	INTERDOMAIN_TRUST_ACCOUNT = 2048,
	WORKSTATION_TRUST_ACCOUNT = 4096,
	SERVER_TRUST_ACCOUNT = 8192,
	BIT_14 = 16384,
	BIT_15 = 32768,
	DONT_EXPIRE_PASSWORD = 65536,
	MNS_LOGON_ACCOUNT = 131072,
	SMARTCARD_REQUIRED = 262144,
	TRUSTED_FOR_DELEGATION = 524288,
	NOT_DELEGATED = 1048576,
	USE_DES_KEY_ONLY = 2097152,
	DONT_REQ_PREAUTH = 4194304,
	PASSWORD_EXPIRED = 8388608,
	TRUSTED_TO_AUTH_FOR_DELEGATION = 16777216,
	PARTIAL_SECRETS_ACCOUNT = 67108864
}
'@

Which can be used like this to decode the bits,

If you want to display all flags that are set in UAC,

Get-AdUser -Filter * -Properties UserAccountControl | select name, @{n='UAC';e={[UserAccountControl]$_.UserAccountControl}}

This script can also be used to determine UserAccountControl value for specific AD accounts,

$user = Read-Host "Enter user's logon"
Get-ADuser $user -properties * | select name,UserPrincipalName, @{n='UAC';e={[UserAccountControl]$_.UserAccountControl}}

Update UserAccoutControl Attribute in AD using PowerShell

To change UserAccountControl attribute in AD using PowerShell, we can use Set-ADUser, Set-ADComputer and Set-ADAccountControl cmdlets,

$user = Read-Host "Enter user's logon"
Set-ADAccountControl -Identity $user –CannotChangePassword:$true -PasswordNeverExpires:$true

or

$user = Read-Host "Enter user's logon"
Set-ADUser -Identity $user –CannotChangePassword:$true -PasswordNeverExpires:$true

Set a specified computer to be trusted for delegation,

$Computer = Read-Host "Enter computer or server name"
Set-ADAccountControl -Identity $Computer -TrustedForDelegation $True

or

$Computer = Read-Host "Enter computer or server name"
Set-ADComputer -Identity $Computer -TrustedForDelegation $True

The user account attribute can also be updated using the Set-ADUser cmdlet. In this below example, I’m enabling user account,

$user = Read-Host "Enter user's logon"
Set-ADUser $user -Replace @{UserAccountControl = 512}

Hope this post helped you get a better understanding of the UserAccountControl attribute.

Thank you for stopping by ✌

PowerShell – Generate and email list of new users created in AD – Updated

If you don’t have an AD user provisioning tool implemented in your environment, I’m sure most of your user provisioning and de-provisioning is done using PowerShell scripts which helps in reducing the amount of time consumed in this process.

You probably are bombarded with requests from various departments in your organization to provide them with a list of new users who were created for various reasons.

This script can be automated by securely storing the credentials and running a scheduled task that runs on a specific day. Don’t store your admin or any credentials in any of your scripts.

You can use ConvertFrom-SecureString command to get an encrypted standard string and ConvertTo-SecureString to simply reverse the process by importing the data from your file and then create a PSCredential object.

(Get-Credential).Password | ConvertFrom-SecureString | Out-File "C:\Temp\Password.txt"

$User = "AdminUser@acme.com"
$File = "C:\Temp\Password.txt"
$MyCredential=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $File | ConvertTo-SecureString)

In this above method, the point of converting password to a SecureString and storing it in a file is to keep it out of plain text in PS scripts so that it’s not as easily discovered. This can be easily decrypted and not recommended.

You can use the Microsoft.PowerShell.SecretManagement and Microsoft.PowerShell.SecretStore PS modules which I’ve covered in a later post.

​$Days = -7
$Maxdate = (Get-Date).addDays($Days) 
$CurrentWeekNumber = Get-Date -UFormat %V

$dateformat = "dddd MM/dd/yyyy"
$subjDate = Get-Date $Maxdate -Format $dateformat

$NewUsers = Get-ADUser -filter { whencreated -ge $Maxdate} -Properties EmailAddress, co, Description | Select-Object -Property GivenName, SurName, DisplayName, Description, co, EmailAddress # Gathering recent New AD Users

if ($NewUsers) # If there are more than one new user created in last $Days, prepare to send a mail
    {
    $MailBody = $NewUsers | ConvertTo-Html -Fragment
    
            $MailParams = @{Body       = $mailBody | Out-String
                            BodyAsHtml = $true
                            From       = "AD-Admin@acme.com"
                            To         = "jsmith@acme.com" # separate with comma for multiple users. "jdoe@acme.com", "jroe@acme.com"
                            SmtpServer = "smtp.acme.com"
                            Subject    = "New users for the week : $CurrentWeekNumber | Week Starting - $subjDate"
                            Encoding   = "UTF8"
                            Priority   = "Normal" # Accepted values: Normal, High, Low
                            #Port      = xxxx #If not 25
                            Credential = $(Get-Credential)
                            }
    Send-MailMessage @MailParams
    }

Hope this script was useful is generating weekly reports of newly created AD users.

Thank you for stopping by. ✌

Active Directory – Update user’s co and countryCode attributes using PowerShell

I recently faced an issue where users are provisioned to AD using an user system/tool that applies the Country value to the user while creating the account but it doesn’t have the ability to update the countryCode and co attributes. And I had few thousand users with no value set in the co and countryCode attributes.

In this post, I’ll cover the details on how came up with a workaround for this issue.

The AD attributes we are dealing with here are,

  • c (Country-Name): ISO-3166 2-digit string value
  • countryCode (Country-Code): ISO-3166 Integer value
  • co (Text-Country): Open string value

When we pick a country name from the drop-down in the Active Directory users and computers GUI, the c, co and countryCode attributes are automatically assigned.

With PowerShell, we can use the Set-ADUser to assign the c attribute to the user,

$user = Read-Host "Enter user's logon"
Set-ADUser -Identity $user -Country US

In this method, no values are assigned to the co and countryCode attributes automatically like how it happened while updating in the GUI. Below are the screenshots of the user properties after running the above cmdlet.

We can use this method to assign all three values for the user,

$user = Read-Host "Enter user's logon"
Set-ADUser -identity $user -Replace @{c="CN";co="United States";countryCode="840"}

In my scenario, the users provisioned by the tool already had the c attribute value set. I exported all users from the AD domain, determined the countries and then used the below script to update the co and countryCode attributes.

$users = Get-ADUser -LDAPFilter '(!userAccountControl:1.2.840.113556.1.4.803:=2)' -Properties * | Select cn, sAMAccountName, userPrincipalName, c

foreach ($User in $Users){
        if($user.c -eq 'AU') {
            Set-ADuser $user.sAMAccountName -Replace @{co="Australia";countrycode="36"}
        }
        elseif ($user.c -eq 'US') {
	        Set-ADuser $user.sAMAccountName -Replace @{co="United States";countrycode="840"}
        }
        elseif ($user.c -eq 'GB') {
	        Set-ADuser $user.sAMAccountName -Replace @{co="United Kingdom";countrycode="826"}
        }
        elseif ($user.c -eq 'CA') {
	    Set-ADuser $user.sAMAccountName -Replace @{co="Canada";countrycode="124"}
        }
        else {
            Write-Host $user.cn does not contain Country value
    }
}

This table at the end of this post provides all countries in the AD address tab Country/region drop-down list. You can use this to update the above script according to your needs. I also made this script to be run as a scheduled task to run once a week to update the new users created throughout the week. Not a perfect solution but replacing the user provisioning tool wasn’t an option in my case, hence I stuck with this method.

Hope this post helped you in better understanding the c, co and countryCode attributes in AD and an easier method to update it.

Thank you for stopping by ✌

Country (co)Code (c)Code
AfghanistanAF4
Åland IslandsAX248
AlbaniaAL8
AlgeriaDZ12
American SamoaAS16
AndorraAD20
AngolaAO24
AnguillaAI660
AntarcticaAQ10
Antigua and BarbudaAG28
ArgentinaAR32
ArmeniaAM51
ArubaAW533
AustraliaAU36
AustriaAT40
AzerbaijanAZ31
Bahamas, TheBS44
BahrainBH48
BangladeshBD50
BarbadosBB52
BelarusBY112
BelgiumBE56
BelizeBZ84
BeninBJ204
BermudaBM60
BhutanBT64
BoliviaBO68
Bonaire, Sint Eustatius and SabaBQ535
Bosnia and HerzegovinaBA70
BotswanaBW72
Bouvet IslandBV74
BrazilBR76
British Indian Ocean TerritoryIO86
British Virgin IslandsVG92
BruneiBN96
BulgariaBG100
Burkina FasoBF854
BurundiBI108
Cabo VerdeCV132
CambodiaKH116
CameroonCM120
CanadaCA124
Cayman IslandsKY136
Central African RepublicCF140
ChadTD148
ChileCL152
ChinaCN156
Christmas IslandCX162
Cocos (Keeling) IslandsCC166
ColombiaCO170
ComorosKM174
CongoCG178
Congo (DRC)CD180
Cook IslandsCK184
Costa RicaCR188
Côte d’IvoireCI384
CroatiaHR191
CubaCU192
CuraçaoCW531
CyprusCY196
Czech RepublicCZ203
DenmarkDK208
DjiboutiDJ262
DominicaDM212
Dominican RepublicDO214
EcuadorEC218
EgyptEG818
El SalvadorSV222
Equatorial GuineaGQ226
EritreaER232
EstoniaEE233
EthiopiaET231
Falkland IslandsFK238
Faroe IslandsFO234
FijiFJ242
FinlandFI246
FranceFR250
French GuianaGF254
French PolynesiaPF258
French Southern TerritoriesTF260
GabonGA266
GambiaGM270
GeorgiaGE268
GermanyDE276
GhanaGH288
GibraltarGI292
GreeceGR300
GreenlandGL304
GrenadaGD308
GuadeloupeGP312
GuamGU316
GuatemalaGT320
GuernseyGG831
GuineaGN324
Guinea-BissauGW624
GuyanaGY328
HaitiHT332
Heard and McDonald IslandsHM334
HondurasHN340
Hong Kong SARHK344
HungaryHU348
IcelandIS352
IndiaIN356
IndonesiaID360
IranIR364
IraqIQ368
IrelandIE372
Isle of ManIM833
IsraelIL376
ItalyIT380
JamaicaJM388
Jan MayenSJ744
JapanJP392
JerseyJE832
JordanJO400
KazakhstanKZ398
KenyaKE404
KiribatiKI296
KoreaKR410
KosovoXK906
KuwaitKW414
KyrgyzstanKG417
LaosLA418
LatviaLV428
LebanonLB422
LesothoLS426
LiberiaLR430
LibyaLY434
LiechtensteinLI438
LithuaniaLT440
LuxembourgLU442
Macao SARMO446
Macedonia, FYROMK807
MadagascarMG450
MalawiMW454
MalaysiaMY458
MaldivesMV462
MaliML466
MaltaMT470
Marshall IslandsMH584
MartiniqueMQ474
MauritaniaMR478
MauritiusMU480
MayotteYT175
MexicoMX484
MicronesiaFM583
MoldovaMD498
MonacoMC492
MongoliaMN496
MontenegroME499
MontserratMS500
MoroccoMA504
MozambiqueMZ508
MyanmarMM104
NamibiaNA516
NauruNR520
NepalNP524
NetherlandsNL528
New CaledoniaNC540
New ZealandNZ554
NicaraguaNI558
NigerNE562
NigeriaNG566
NiueNU570
Norfolk IslandNF574
North KoreaKP408
Northern Mariana IslandsMP580
NorwayNO578
OmanOM512
PakistanPK586
PalauPW585
Palestinian AuthorityPS275
PanamaPA591
Papua New GuineaPG598
ParaguayPY600
PeruPE604
PhilippinesPH608
Pitcairn IslandsPN612
PolandPL616
PortugalPT620
Puerto RicoPR630
QatarQA634
ReunionRE638
RomaniaRO642
RussiaRU643
RwandaRW646
Saint BarthélemyBL652
Saint Kitts and NevisKN659
Saint LuciaLC662
Saint MartinMF663
Saint Pierre and MiquelonPM666
Saint Vincent and the GrenadinesVC670
SamoaWS882
San MarinoSM674
São Tomé and PríncipeST678
Saudi ArabiaSA682
SenegalSN686
SerbiaRS688
Serbia and Montenegro (Former)CS891
SeychellesSC690
Sierra LeoneSL694
SingaporeSG702
Sint MaartenSX534
SlovakiaSK703
SloveniaSI705
Solomon IslandsSB90
SomaliaSO706
South AfricaZA710
South Georgia and the South Sandwich IslandsGS239
SpainES724
Sri LankaLK144
St Helena, Ascension and Tristan da CunhaSH654
SudanSD736
SurinameSR740
SvalbardSJ744
SwazilandSZ748
SwedenSE752
SwitzerlandCH756
SyriaSY760
TaiwanTW158
TajikistanTJ762
TanzaniaTZ834
ThailandTH764
Timor-LesteTL626
TogoTG768
TokelauTK772
TongaTO776
Trinidad and TobagoTT780
TunisiaTN788
TurkeyTR792
TurkmenistanTM795
Turks and Caicos IslandsTC796
TuvaluTV798
U.S. Minor Outlying IslandsUM581
U.S. Virgin IslandsVI850
UgandaUG800
UkraineUA804
United Arab EmiratesAE784
United KingdomGB826
United StatesUS840
UruguayUY858
UzbekistanUZ860
VanuatuVU548
Vatican CityVA336
VenezuelaVE862
VietnamVN704
Wallis and FutunaWF876
YemenYE887
ZambiaZM894
ZimbabweZW716

AzureAD/O365 – Update User’s Manager using PowerShell

Organizational hierarchy is vital to run everyday activities smoothly in any enterprise. With Azure AD, user’s manager information can be updated easily and this information can be used in other features like Teams and apps that require workflow.

In this post, I’ll go over steps on how to update manager information for a specific user, for a list of users based on information from a csv file and to determine users’ manager information

Make sure you are connected to Azure AD,

$credential = Get-Credential
Connect-AzureAD -credential $credential

To update manager information for a specific user:

$user = Read-Host "Enter user's email address to update Manager information"
$Manager = Read-Host "Enter Manager's email address"
Set-AzureADUserManager -ObjectId (Get-AzureADUser -SearchString $User).Objectid -RefObjectId (Get-AzureADUser -SearchString $Manager).Objectid

To bulk update users’ manager information from a CSV file:

Note: csv file has UserEmail,ManagerEmail as column headers

$list = Import-csv "C:\tmp\SetManager\UsersManagers.csv"
Foreach($entry in $list) {
        $User = $entry.UserEmail
        $Manager = $entry.ManagerEmail
        $UserObj = Get-AzureADUser -SearchString $User
        $ManagerObj = Get-AzureADUser -SearchString $Manager

        Write-Host Updating $UserObj.DisplayName with $ManagerObj.DisplayName as manager -ForegroundColor Yellow

        Set-AzureADUserManager -ObjectId $UserObj.Objectid -RefObjectId $ManagerObj.Objectid

        Write-Host "Update Complete." -ForegroundColor Green

}

To determine a user’s manager:

$user = Read-Host "Enter user's email address to determine Manager information"
(Get-AzureADUserManager -ObjectId (Get-AzureADUser -SearchString $User).Objectid).DisplayName

To determine all users’ manager information in the Azure AD tenant:

$Users = Get-AzureADUser -All $true

ForEach($User in $Users) {

    $Manager = Get-AzureADUserManager -ObjectId $User.Objectid
    If ($Manager) {
    Write-Host $User.DisplayName manager is $Manager.DisplayName -ForegroundColor Green}
    Else {
    Write-Host "No Manager information found" for $User.DisplayName -ForegroundColor Red}
}

Thank you for stopping by. ✌

PowerShell – Determine all file extensions and count to files by extensions in a folder

Managing file shares can be daunting task some times and when you are trying to make sure the data doesn’t walk out of these shares, other control mechanism usually come into place and along with that comes questions to administrators. One such question I got asked recently was, can you tell me all the file types in this share and how many files there are?

If you come across this situation, you can use the below lines to get an easy overview of the filetypes and the count of files. The input can also be in the UNC format(Ex: \\Server2\Share)

$path = Read-Host "Enter folder path to analyze file extensions"
Get-ChildItem -Path $path -Recurse -File | Group-Object Extension | Sort-Object count -desc | ft -AutoSize

I also put together this below script that will generate two csv files as output. One with a overview of file extensions and count of files and the second with the files’ path on where it is stored in the share.

$path = Read-Host "Enter folder path to analyze file extensions"
$dir = Split-Path -Path $path -Leaf

# create a folder named 'Report' in the script path to store the csv files generated
$ReportFolder = ".\Report"
if (Test-Path $ReportFolder){
    Write-Host "Report folder already exists" -ForegroundColor Green
}
else
{
    New-Item $ReportFolder -ItemType Directory
    Write-Host "Report Folder Created successfully" -ForegroundColor Red
}

#variable to store file name for log file extensions and count. Create top two columns = Extension and File Count
$ft = “.\Report\Folder report for ” + $dir + "$((Get-Date).ToString("MMddyyyy_HHmmss"))" + “.csv”
“Extension`tFile Count” | Out-File -FilePath $ft

#variable to store file name for file name to log file list by extension
$fl = “.\Report\File extension report for ” + $dir + "$((Get-Date).ToString("MMddyyyy_HHmmss"))" +“.csv”

#Analyse path for file type extension
$dirext = Get-ChildItem -Path $path -Recurse -File | Group-Object Extension | Sort-Object count -desc

foreach($ext in $dirext)
{
$ext.Name + “`t” + $ext.Count | Out-File -FilePath $ft -Append

“File Report on file Extensions`:  ” + $($ext.Name) + ” [Count`: ” + $ext.Count + “]” | Out-File -FilePath $fl -Append
$ext.Group.FullName | Out-File -FilePath $fl -Append
“`n`r” | Out-File -FilePath $fl -Append
}
Write-Host "Reports generated successfully" -ForegroundColor Green

Hope this post helped you in digging into what’s in your file shares when it comes to file types.😉😁

Thank you for stopping by. ✌