Thursday, 14 May 2026

Disable the Accounts, Move the account to UnSync OU.

             $users = Get-Content C:\Temp\kumar\admaccount1.txt


            $targetou = "OU=Unmanaged Users,DC=Test,DC=com"


                        foreach ($usr in $users){


                        $userdn = Get-Aduser $usr -Properties * | Select-Object -ExpandProperty DistinguishedName


                            if ($usr){


                                Disable-ADAccount $usr


                            if ($usr) {


                            Move-ADObject -Identity $userdn -TargetPath $targetou


                                }


                                }


                                }

Adding Guest Accounts into Azure AD Groups

 We manage several enterprise Azure AD applications that grant access to both internal users and external guest accounts. Frequently, we receive bulk requests to add guest accounts into Azure AD groups. To streamline this process and reduce manual effort, we developed a script that automates the addition of guest accounts to the required groups.




#[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;

# Connect to Azure AD

#Connect-AzureAD


# Import users from CSV

$Users = get-content "C:\temp\kumar\users.txt"


# Specify the group

$Group = Get-AzureADGroup -ObjectId abcdef-xyx-123


# Add each user to the group

foreach ($User in $Users) {

    $userObjectId = (Get-AzureADUser -Filter "Mail eq '$User'").ObjectID

    if ($userObjectId -ne $null) {

        Add-AzureADGroupMember -ObjectId $Group.ObjectId -RefObjectId $userObjectId -ErrorAction SilentlyContinue

        Write-Host "WIP $User"

    }

}


#$userObjectId = (Get-AzureADUser -Filter "Mail eq 'abc@xyz.com'").ObjectID

Custom Password Generator

 The below script would help you to generate passwords randomly, instead of using public sites, you can generate the password by yourself. 


$Password = New-Object -TypeName PSObject

$Password | Add-Member -MemberType ScriptProperty -Name "Password" -Value { ("123456789!@#$%&0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz".tochararray() | sort {Get-Random})[0..15] -join '' }

$Password #| Out-GridView

Suspicious Active Directory Account Disable

 Recently, our security team detected suspicious activity involving approximately 200 accounts. They immediately engaged me to disable these accounts and requested that comments be added during the disable process to ensure the service desk team does not inadvertently re-enable them. To meet this requirement, we developed a lightweight script that automated the account disable action while inserting the necessary comments for tracking and control.


$listofuser = Get-content C:\Temp\user.txt


#$Comment = "Account disabled on 05-Dec-2025 by Admin IncNumber"


foreach ($usr in $listofuser) {


    # Disable the account

    Get-Aduser -Filter {UserPrincipalName -eq $usr} | Disable-ADAccount


    # Update the description field

  Get-Aduser -Filter {UserPrincipalName -eq $usr} | Set-ADUser -Description $Comment

   # Get-Aduser -Filter {UserPrincipalName -eq $usr} -Properties Description |Select-Object Name,UserPrincipalName,Enabled,Description | Export-Csv C:\Temp\report.csv -NoTypeInformation -Encoding UTF8 -Append

  #  Write-Host "Account Disabled for the user $usr | $comment" -ForegroundColor Green



}


Privilege Account MFA Method Report:-

 Our security team requested an assessment to identify privileged accounts and verify their MFA status. To address this requirement, we began developing a script that retrieves all _ADM accounts along with the details of their configured MFA methods.



# [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12;


#Connect-MgGraph -Scopes "Directory.Read.All","UserAuthenticationMethod.Read.All"


$searchBase = "OU=Privileged,OU=Managed Users,DC=TEST,DC=com"


$listofusers = Get-ADUser -SearchBase $searchBase -Filter {samaccountname -like "*_adm"} -Properties * | Select-Object -ExpandProperty UserPrincipalName


foreach ($usr in $listofusers){



# Get all users and check their authentication methods

$results = Get-MgUser -UserId $usr | ForEach-Object {

    $methods = Get-MgUserAuthenticationMethod -UserId $_.Id

    [PSCustomObject]@{

        DisplayName = $_.DisplayName

        UserPrincipalName = $_.UserPrincipalName

        MFAEnabled = ($methods | Where-Object {$_.AdditionalProperties['@odata.type'] -like "*microsoft.graph.microsoftAuthenticatorAuthenticationMethod*"}).Count -gt 0

    }# Export to CSV

$results | Export-Csv -Path "C:\Temp\kumar\MFAStatus.csv" -NoTypeInformation -Append

}

}


Active Directory Privilege Account expire match User Regular Account:-

 We recently encountered a surge of incidents where numerous administrator accounts were found to be expired, leading to a flood of support tickets. Upon investigation with several users, we discovered that the Identity Access Management (IAM) team had identified approximately 1,500 user accounts that had expired and subsequently renewed them due to organizational changes. However, this renewal process inadvertently caused the associated _ADM accounts to also expire.


Unfortunately, when the IAM team extended the user accounts, they only updated the regular accounts and overlooked the privileged (_ADM) accounts. As a result, the AD team was later requested to align the expiration dates of the 1,500 user accounts with their corresponding _ADM accounts. To resolve this, we developed a script that synchronized and updated the expiration dates of the privileged accounts to match those of the regular accounts.

$listofusers = Get-content C:\Temp\user.txt


foreach ($usr in $listofusers) {


$date = Get-aduser $usr -Properties AccountExpirationDate | Select-Object -ExpandProperty AccountExpirationDate

$ConvertADm2Normal= Get-ADUser $usr | Select-Object -ExpandProperty SamAccountName

$newName = $ConvertADm2Normal + "_Adm"


Get-ADUser -Identity $newName | Set-ADAccountExpiration -DateTime:$date -Server test.com


#Get-ADUser $newName -Properties AccountExpirationDate | Select-Object Name,AccountExpirationDate



}


Wednesday, 13 May 2026

Last Login Report both On Prem and Azure

We often receive request for collecting Last login report both on prem and Azure AD sign in login, we have build the script to collect this. 
Sharing interesting tiny script that make your life more easier :) 
# Verify your machine having proper firewall rules in place. 
# Test-NetConnection login.microsoftonline.com -Port 443
# Test-NetConnection autologon.microsoftazuread-sso.com -Port 443

# Enable Tls12 protocol
# [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Verify Microsoft Site
# Invoke-WebRequest -Uri "https://login.microsoftonline.com" -UseBasicParsing

# This report need some Microsoft Graph Command, hence we are installing the modules. 

# Install-Module Microsoft.Graph -Scope AllUsers -Force
# Install-Module Microsoft.Graph -Scope AllUsers -Force -AllowClobber

# Connect Microsoft Graph by using your Azure AD credentials. 

# Connect-MgGraph -Scopes "User.Read.All","Directory.Read.All"

# $Cred = Get-Credential

$listofusers = Get-content C:\temp\kumar\azuread1.txt

$Properties = @("Id","DisplayName","UserPrincipalName","SignInActivity")

foreach ($usr in $listofusers){
#$Users = Get-MgUser -All -Property $Properties | Select-Object -First 100

    $Users1 = get-aduser -filter {UserPrincipalName -eq $usr} -Properties * -Server Server1.test.com -Credential $Cred | Select-Object SamAccountName,LastLogonDate
    $Users = Get-MgUser -Filter "userPrincipalName eq '$usr'" -Property $Properties

    $Users | Select-Object DisplayName, UserPrincipalName, @{Name="LastLoginDate";Expression={$_.SignInActivity.LastSignInDateTime}}

         # Merge into one object
        $Combined = [PSCustomObject]@{
            AzureDisplayName       = $Users.DisplayName
            AzureUserPrincipalName = $Users.UserPrincipalName
            AzureLastLoginDate     = $Users.SignInActivity.LastSignInDateTime
            OnPremSamAccountName   = $Users1.SamAccountName
            OnPremLastLogonDate    = $Users1.LastLogonDate
        }

        # Output or export
        $Combined | Export-Csv "AzureAD_LastLogin.csv" -NoTypeInformation -Append


}

Saturday, 18 January 2025

Domain Controller Jumped Time future Dates

 

 


Synopsis

            We recently had an issue with one of AD server, the server time jumping previous dates. After couple of hours the server returning with original time and it is following domain time hierarchy. So, the time drift is not consistent with forest PDC. Initially we had an issue with one server later it triggered such issues multiples domain controllers.

            Time drift that causes on domain controller, that lead potential issues to business few service below for reference.

Authentication and authorization,

Domain controller replication will break

Group Managed Service account must reconfigure.

 

 

Investigation

        We started analysis how / who initiating this time jump on domain controllers. we checked the below factors,

Ø                      Is there any network connection issue between PDC to Domain Controller, both have logically disconnected each other, we assumed possible network glitches but upon checking within same site and same subnet another domain controller we don’t see any time drift from PDC. hence network or fireall not a concern. 

Ø                  Verified once server back to original time are they taking time from PDC or local CMOS. Luckily the server taking time from PDC, not from local CMOS.

Ø                  The very first server we observed this issue, domain controller installed with physical server, the HP product team they documented the list of products affected this bug and they provided solution to follow.

The below link that will help you to check if your physical box falls under this category.

 

https://support.hpe.com/hpesc/public/docDisplay?docId=emr_na-c04557232

            We have checked our product version is not impacted and observed this issue also affecting Virtual domain controllers too. Hence hardware bug not an issue to us.

 

We finally give up with all basic troubleshooting and opened support case to Microsoft team,

Microsoft team captured the w32 debug logs and found some interesting issue about STS (secure time seeding) that causing this issue.

To collect debug logs we must run the below command with Administrator cmd.

Command to enable w32time debug logs:

w32tm /debug /enable /file:%SystemRoot%\temp\W32Time.log /size:10485760 /entries:0-1003 (we need to restart the time service in order for logs to be collected)

Commands to stop and start the time service:

net stop w32time - to stop the time service

net start w32time – to start the time service

 

Solution: -

        The issue is not consistent also we won’t be able to reproduce the issue to capture the logs, it took some time to capture it. Finally, we had an enough logs that prove it caused secure time seeding, hence Microsoft recommend turning off this STS feature.

Before implementing we captured what present registry value on each domain controller (Our domain controller hosted on windows server 2019) and found this feature is turned on all domain controllers.

Registry value

Registry Key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config

Value Name: UtilizeSslTimeData

Value Type: REG_DWORD

Value: 1 = enabled (default), 0 = Disabled

We implemented this registry disable though below group policy option to push all Domain Controller.

Group Policy and the corresponding registry to disable STS(reboot required):

Setting:

Sub Setting:

  • UtilizeSslTimeData

Explain Text

  • This parameter controls whether W32time will use time data computed from SSL traffic on the machine as an additional input for correcting the local clock.

ADMX File:

  • W32Time.admx file.

Reboot Requirements

  • Reboot required.

 

Note: Changes on the registry value requires reboot. Hence plan your implementation accordingly.

 

Reference Notes:

The below reference article that explains more about how this STS feature that causing this issue and why Microsoft made this feature default as turned on state.

My favorite articles are here.

Ø  https://arstechnica.com/security/2023/08/windows-feature-that-resets-system-clocks-based-on-random-data-is-wreaking-havoc/

Ø  https://techcommunity.microsoft.com/blog/askds/secure-time-seeding-on-dcs-a-note-from-the-field/4238810

 

 

 

 

 

 

 

 

 

 

Saturday, 23 November 2024

Eventlog Report with powershell

Account Lockout Eventlog Search on AD server 


 We usually face challange to pull account lockout source on domain controller security eventlog, although we have nice friendly gui view in event logs, sometime that wont help us to analyze account lockout source. One of my user had account lockout issue every One Minute once.by using native powershell method i found this below query to identify the source of account lockout.

# Specify the log name and a filter for Event ID (if needed)

$LogName = "Security"

$EventID = 4771 # Example Event ID

# Retrieve and extract specific information (e.g., Client Address)

Get-WinEvent -FilterHashtable @{LogName = $LogName; Id = $EventID}|where {$_.message -match "Nameoftheaccount"} | ForEach-Object {

    # Extract "Client Address" from the message

    if ($_.Message -match "Client Address:\s+(\S+)") {

        [PSCustomObject]@{

            TimeCreated    = $_.TimeCreated

            EventID        = $_.Id

            ClientAddress  = $matches[1] # Extracted IP or address

        }

    }

}

#happy learning...

Friday, 9 September 2022

PKI Expired Certificate Cleanup Script

 # Date define our Certificate Retention period.

$FileName = (Get-date).ToString("dd-MM-yyyy")

 

$Date = (Get-Date).AddDays(-375).ToShortDateString()


# Store List of Certificate which need to take action.

# Disposition Values

# 20 certificate was issued

# 21 certificate is revoked

# 30 certificate request failed

# 31 certificate request is denied


$CollectRow = certutil.exe -view -restrict "Disposition=30,notbefore<=$Date" -out Requestid csv | findstr.exe /v "Issued Request ID"


foreach($DelCert in $CollectRow) {


    Certutil -deleterow $DelCert Request

    $CALog = "$DelCert Successfully Deleted"

    $CALog | Out-File "C:\CAClearLog\$FileName + CAResult-log.txt" -Append


}

PKI Certificate Cleanup from Issuing Authority

 <# 

.Description 

    The Script will help to delete certificate which we defined in the input file.  

#>


$ExpiredCertficates = Get-Content C:\temp\row1.txt


foreach($ExpiredCertficate in $ExpiredCertficates) {


    Certutil -deleterow $ExpiredCertficate Request


    Write-Host "Deleting Certificate $ExpiredCertficate"


}


PKI Certificate Report

<# 

.Description 

    The Script will help to fetch Certificate Expiration Date as we defined. 

#>


certutil.exe -view -restrict 'disposition=20,NotAfter<=12/1/2019' -out 'RequestID,RequesterName,NotBefore,NotAfter,Disposition,Request.RequestID,Issued Email Address' csv > C:\temp\Issued_Validation.csv


Sunday, 12 September 2021

Introduce New Custom Active Directory Attribute

 

Introduce New Custom Attribute


Add Custom attribute, to store Service Account owner information.

Creating custom attribute in AD, we need schema dll need to be register first.

Once schema registered, open Schema snap-ins.


 

Select Attributes, and create attribute.

Then, the system will give a warning about schema object creation. Click OK to continue and the following screen will open:




New Attribute form look like below.


Common Name: This is the name of the object. You can only use letters, numbers, and hyphens for the common name (CN).

LDAP Display Name: When an object is referring to a script, program, or command-line utility, it needs to be called using the LDAP display name instead of the CN. When you define the CN, it will automatically create an LDAP Display Name.

Unique X500 Object ID: Each and every attribute in an AD schema has a unique object ID (OID) value. There is a script developed by Microsoft to generate these unique OID values. It can be found at https://gallery.technet.microsoft.com/scriptcenter/Generate-an-Object-4c9be66a#content.

 

It includes the following script, which will generate the OID:

#---

$Prefix="1.2.840.113556.1.8000.2554"

$GUID=[System.Guid]::NewGuid().ToString()

$Parts=@()

$Parts+=[UInt64]::Parse($guid.SubString(0,4), "AllowHexSpecifier")

$Parts+=[UInt64]::Parse($guid.SubString(4,4), "AllowHexSpecifier")

$Parts+=[UInt64]::Parse($guid.SubString(9,4),

"AllowHexSpecifier")

$Parts+=[UInt64]::Parse($guid.SubString(14,4), "AllowHexSpecifier")

$Parts+=[UInt64]::Parse($guid.SubString(19,4), "AllowHexSpecifier")

$Parts+=[UInt64]::Parse($guid.SubString(24,6), "AllowHexSpecifier")

$Parts+=[UInt64]::Parse($guid.SubString(30,6),

"AllowHexSpecifier")

$OID=[String]::Format("{0}.{1}.{2}.{3}.{4}.{5}.{6}.{7}",

$prefix,$Parts[0],$Parts[1],$Parts[2],$Parts[3],$Parts[4],

$Parts[5],$Parts[6])

$oid

#---

Syntax: This defines the storage representation for the object. You are only allowed to use a syntax defined by Microsoft. One attribute can only associate with one syntax. In the following table, I have listed a few commonly used syntaxes:

Syntax

Description

Boolean

True or false

Unicode String

A large string

Numeric String

String of digits

Integer

32-bit numeric value

Large Integer

64-bit numeric value

SID

Security identifier value

Distinguished Name

String value to uniquely identify object in AD

With all the above notes, we will fill the below form.






        As the next step, we need to add it to the user class. In order to do that, go to the Classes container, double-click on the user class,


Click on the Attributes tab. In there, by clicking the Add button, we can browse and select the newly added attribute from the list:



Now when we open a user account, we can see the new attribute. Update owner employee id info,



Now all efforts are done, let see we can retrieve from PowerShell. 



**************************Happy Learning************************ 

Saturday, 27 February 2021

How to By-pass ADFS and Azure SSO

 Summary:

            Typically, when we implement AZURE AAD and ADFS, we would expert any federated URL’s would sign automatically. This is quite expected behavior’, if any corporate users are already signed on their computer not required sign on for all remaining resource. however, if you want to disallow some users from using Seamless SSO sign in on shared kiosks. The SSO should bypass for those users. Let see how to bypass.

Add the below URLs into Internet Explorer Restricted Zone, adding this URL for set of computers can be via GPO or GPO Preference for Shared Service Computers.

https://autologon.microsoftazuread-sso.com and https://aadg.windows.net.nsatc.net

Once the URLs are present in Restricted Zone.

Run the KLIST Purge command on KIOSK Computers to refresh any new token.

Now when user attempted to access any new federated URL’s the URL, s would ask you to submit credentials.

Note: Seamless SSO Sometime not working appropriately when IE with IN Private Mode, so check the URLs in IE with Normal mode.

***********************Happy Learning*************************


 

Friday, 27 November 2020

Create Group which correspond to Server Name

 # This script create Group which correspond to Server Name. 

# Import Active Directory Module.

Import-Module ActiveDirectory

# Computer OU Container

$ParentOU="OU=Root,DC=test,DC=local"

# Locate the Group OU, in which script will create groups.

$GroupOU="OU=ServerGroup,OU=Root,DC=test,DC=local"

# The script will find computer object which is leass than specified in the customdate

$customdate=(Get-date).Adddays(-3)

$log=get-date

$ColComputers=get-adComputer -SearchBase $ParentOU -Filter {(Whencreated -ge $customdate)}

foreach ($Computer in $ColComputers)

{

$ComputerCN = (Get-ADComputer $Computer).name

# Verify the OU path before group creation process

$check = [ADSI]::Exists("LDAP://$($GroupOU)") 

if ($check -eq $True)

Try 

# Check Group Already exist in Directory Service

$GroupExists = Get-ADGroup -Identity $ComputerCN

# If Group Already exist, redirect the output to log file.

$Outmsg="Group $($ComputerCN) alread exists! Group creation skipped!$log" 

$Outmsg | Out-file -append ".\Result_Log1.txt"

}

Catch

{

# IF Group not exist in AD, create new group which is correspond to computername

$create = New-ADGroup -Name $ComputerCN -GroupScope: "Global" -Path: "$GroupOU" -SamAccountName:"$ComputerCN" -Description "Local Administrator Group for $ComputerCN"  -Server:"NATEST-DC1" 

$Outmsg= "Group $($ComputerCN) created!$log" 

$Outmsg | Out-file -append ".\Result_Log1.txt"

 

 } 

  } 

  Else 

  { 

    Write-Host "Target OU can't be found! Group creation skipped!" 

  } 

}

Thursday, 19 November 2020

Active Directory Replication Report

 # Get today's date for the report 

$today = Get-Date 

 

# Setup email parameters 

$subject = "Replication REPORT - " + $today 

$priority = "Normal" 

$smtpServer = "SMTP.Server.com" 

$emailFrom = "from@email.com" 

$emailTo = "to@email.com" 

$log = "C:\temp\ReplicationSummary.txt"

repadmin /replsum * /bysrc /bydest /sort:delta > $log

#$ReplicationStatus = "Replication REPORT - " + $today 


$Result = Get-Content C:\temp\ReplicationSummary.txt -raw


# Send the report email 

Send-MailMessage -To $emailTo -Subject $subject -Body $Result -SmtpServer $smtpServer -From $emailFrom -Priority $priority

Saturday, 20 June 2020

Update Missing Group Owner Attribute in MIM

[cmdletbinding()]           
param()
Set-ResourceManagementClient -BaseAddress “http://TEST-MIM.test.com:5725”
$MIMGroups = Get-Content C:\Temp\ADGroups.txt
foreach ($MIMGroup in $MIMGroups) {
$og = get-resource -ObjectType "Group" -AttributeName "AccountName" -AttributeValue "$MIMGroup"
$owner = $og.Owner | Select-Object -ExpandProperty value -First 1
$og.DisplayedOwner = "$owner"
Save-Resource $og
}

Microsoft Identity Manager Group Report

 # Microsoft Identity Manager Group Report

[cmdletbinding()]           
param()

# Connect MIM Identity Manager

Set-ResourceManagementClient -BaseAddress “http://Mim.test.com:5725”

# List of AD Groups from specific OU.

$MIMGroups = Get-ADGroup -Filter * -SearchBase "OU=Test-MIM,DC=Test,DC=com" -Properties * | Select-Object -ExpandProperty SamAccountName

# Check each Group Attribute one at time

foreach ($MIMGroup in $MIMGroups) {

# Check Group Attribute from Metaverse and store value into Variable

$og = get-resource -ObjectType "Group" -AttributeName "AccountName" -AttributeValue "$MIMGroup"

# Create Powershell Object and extract specific attribute from Og variable

 $obj = New-Object -Type PSObject -Property (           
  @{           
   "AccountName"  = $og.AccountName;           
   "DisplayName" = $og.DisplayName;
   "AuthoritativeDirectory" = $og.AuthoritativeDirectory;           
   "DisplayedOwner" = $og.DisplayedOwner;
   "Owner" = $og.Owner
  }           
 )

# Export values into excel
         
 $Obj |Select-Object AccountName,DisplayName,AuthoritativeDirectory,@{Name="DisplayedOwner";e={$_.DisplayedOwner -join ","}},@{Name="Owner";e={$_.Owner -join ","}} | export-csv c:\temp\AllADGroups.csv -notypeinformation -Encoding UTF8 -Append       
}

Wednesday, 22 April 2020

Check SPN Entry Contains DNS Alias

# DNS Alias Info

$DNSAlias = Get-Content C:\temp\nas.txt

# AD Server Information

$ADObjects = Get-ADComputer -Filter * -SearchBase "OU=TESTServer,DC=test,DC=local" -Property Name,ServicePrincipalName | Select-Object name,@{Name="SPN";e={$_.ServicePrincipalName -join ","}}

# Check Server SPN entry contains DNS Alias

foreach ($DNS in $DNSAlias){
foreach ($ADObj in $ADObjects){
    If ($ADObj -like "*$DNS*"){
        $log = "$DNS Object found in $ADObj" | Out-File -Append C:\temp\Result.txt
    }else{
        $Log = "$Dns Object Not Found in $ADObj" | Out-File -Append C:\temp\Result-Not.txt
    }
    }
    }

Check Active Directory Computer Object Contains DNS Alias

# DNS Alias Info

$DNSAlias = Get-Content C:\temp\dns.txt

# AD Server Information

$ADObjects = Get-Content C:\temp\nas.txt| Get-ADComputer -Property
Name,ServicePrincipalName | Select-Object name,@{Name="SPN";e={$_.ServicePrincipalName -join ","}}

# Check Server SPN entry contains DNS Alias
foreach ($DNS in $DNSAlias){
foreach ($ADObj in $ADObjects){
    If ($ADObj -like "*$DNS*"){
        $log = "$DNS Object found in $ADObj" | Out-File -Append C:\temp\Result.txt
    }else{
        $Log = "$Dns" | Out-File -Append C:\temp\Result-Not.txt
    }
    }
    }