Active Directory ( AD ) – Get User’s Password Expiration Date ( Using VBScript )

 

Background

Ever so often my Active Directory Account expiration date sneaks up on me.

And, I will like to proactively know ahead of time.

 

Code

Looked for code and here is one I found from here and there on Net.

VBScript


OPTION EXPLICIT


REM ***********************************************************

REM Referenced Work: 

'	REM Binding to Active Directory objects with the LDAP provider
'	REm http://www.rlmueller.net/LDAP_Binding.htm

'	REM Get the Distinguished Name for an Active Directory Object
'	REM https://gallery.technet.microsoft.com/scriptcenter/1a7111e3-3c15-4e29-ac3b-84d3ac46bd4c

'	REM How to find the Active Directory Path
'	REM https://leonelson.com/2010/09/08/how-to-find-the-active-directory-path/     

'	REM Power ASP VBscript Constants
'	REM http://powerasp.net/content/new/vbscript-constants.asp

'	REM VBScript Quit
'	REM https://ss64.com/vb/quit.html

REM ***********************************************************

REM on error resume next



Function distinguish(strObject, strType) 

    REM Get the Distinguished Name for an Active Directory Object
    REM https://gallery.technet.microsoft.com/scriptcenter/1a7111e3-3c15-4e29-ac3b-84d3ac46bd4c
    
    Dim objRootDSE
    Dim strDNSDomain
    Dim objConnection
    Dim objCommand
    Dim objRecordSet
    
    Select case strType 
        Case lcase("computer") 
            strobject = strobject & "$" 
        Case lcase("user") 
            'Good 
        Case lcase("group") 
            'Good 
        Case else 
            Wscript.Echo "Their is an error in the script" 
    End Select 
    
    ' Determine DNS domain name (this could be hard coded). 
    Set objRootDSE = getObject("LDAP://RootDSE") 
    strDNSDomain = objRootDSE.get("defaultNamingContext") 
     
    Const ADS_SCOPE_SUBTREE = 2 
     
    Set objConnection = createObject("ADODB.Connection") 
    Set objCommand = createObject("ADODB.Command") 
    objConnection.Provider = "ADsDSOObject" 
    objConnection.Open "Active Directory Provider" 
     
    Set objCOmmand.ActiveConnection = objConnection 
    objCommand.CommandText = _ 
    "Select distinguishedname, Name, Location from 'LDAP://" & strDNSDomain & _ 
    "' Where objectClass='" & strType & "' and samaccountname='" & strObject & "'" 
    objCommand.Properties("Page Size") = 1000 
    objCommand.Properties("Searchscope") = ADS_SCOPE_SUBTREE  
    Set objRecordSet = objCommand.execute 
    objRecordSet.MoveFirst 
     
    Do Until objRecordSet.EOF 
       distinguish = objRecordSet.Fields("distinguishedname") 
       objRecordSet.MoveNext 
    Loop 
    
End Function    

Function Integer8Date(ByVal objDate, ByVal lngBias)

    ' Function to convert Integer8 (64-bit) value to a date, adjusted for
    ' local time zone bias.
    Dim lngAdjust, lngDate, lngHigh, lngLow
    lngAdjust = lngBias
    lngHigh = objDate.HighPart
    lngLow = objdate.LowPart
    ' Account for error in IADsLargeInteger property methods.
    If (lngLow < 0) Then
        lngHigh = lngHigh + 1
    End If
    If (lngHigh = 0) And (lngLow = 0) Then
        lngAdjust = 0
    End If
    lngDate = #1/1/1601# + (((lngHigh * (2 ^ 32)) _
        + lngLow) / 600000000 - lngAdjust) / 1440
    ' Trap error if lngDate is ridiculously huge.
    On Error Resume Next
    Integer8Date = CDate(lngDate)
    If (Err.Number <> 0) Then
        On Error GoTo 0
        Integer8Date = #1/1/1601#
    End If
    On Error GoTo 0
    
End Function


Function ADPasswordAge

	'========================================
	' First, get the domain policy.
	'========================================

    REM http://www.rlmueller.net/Programs/PwdLastSet.txt

    Dim objRootDSE
    Dim strDNSDomain
    Dim objDomain
    Dim objMaxPwdAge
    
    Dim lngHighAge
    Dim lngLowAge
    Dim sngMaxPwdAge
    
    REM http://www.rlmueller.net/Programs/PwdExpires.txt
    ' Determine domain maximum password age policy in days.
    Set objRootDSE = GetObject("LDAP://RootDSE")
    
    strDNSDomain = objRootDSE.Get("DefaultNamingContext")
    
    Set objDomain = GetObject("LDAP://" & strDNSDomain)
    Set objMaxPwdAge = objDomain.MaxPwdAge
    
    ' Account for bug in IADslargeInteger property methods.
    lngHighAge = objMaxPwdAge.HighPart
    lngLowAge = objMaxPwdAge.LowPart
    If (lngLowAge < 0) Then
        lngHighAge = lngHighAge + 1
    End If
    
    ' Convert from 100-nanosecond intervals into days.
    sngMaxPwdAge = -((lngHighAge * 2^32) _
                    + lngLowAge)/(600000000 * 1440)

                    
    ADPasswordAge = sngMaxPwdAge
    
End Function


Function localTimeBiasFromRegistry()


	' Retrieve user password information.
	' The pwdLastSet attribute should always have a value assigned,
	' but other Integer8 attributes representing dates could be "Null".
	' http://www.rlmueller.net/Programs/PwdLastSet.txt

    dim lngBias
    
    ' Obtain local time zone bias from machine registry.
    ' This bias changes with Daylight Savings Time.
    Dim objShell
    Dim lngBiasKey
    Dim k
	
	Const REGISTRY_KEY_ActiveTimeBias = "HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias"
	
    Set objShell = CreateObject("Wscript.Shell")
    
	lngBiasKey = objShell.RegRead( REGISTRY_KEY_ActiveTimeBias)
	
    If (UCase(TypeName(lngBiasKey)) = "LONG") Then
        lngBias = lngBiasKey
    ElseIf (UCase(TypeName(lngBiasKey)) = "VARIANT()") Then
        lngBias = 0
        For k = 0 To UBound(lngBiasKey)
            lngBias = lngBias + (lngBiasKey(k) * 256^k)
        Next
    End If  
    
    localTimeBiasFromRegistry = lngBias

end function


function getUsername()

	Dim strUserName

	set objNetwork = CreateObject("WScript.Network")

		strUserName = objNetwork.UserName
		
	set objNetwork = Nothing

	getUsername = strUserName

end function


Dim objUser
Dim maxPwdAge
Dim numDays

Dim strDomainDN
Dim strOrganizationUnit
Dim strRelativeDistinguishedNameofContainer
Dim strDistinguishedNameSuffix
Dim strDistinguishedName
Dim strUser
Dim objNetwork
Dim strUserName
Dim strUserDN

Dim strLog

dim objDatePwdLastSet
dim dtmPwdLastSet
dim lngBias

Dim sngMaxPwdAge

Dim dtPasswordExpiry  

Dim strLDAP

Const PROTOCOL_IDENTIFIER_LDAP  = "LDAP://"   

strUserName = getUsername()

strDistinguishedName = distinguish(strUserName, "user")                         

strUserDN = PROTOCOL_IDENTIFIER_LDAP & strDistinguishedName
              
strLog = "strUserDN :- " + strUserDN

WScript.Echo strLog


strLDAP = strUserDN

Set objUser = GetObject(strUserDN)

if (objUser is Nothing) Then

    strLog = "GetObject failed on " & strLDAP
                    
    WScript.Echo strLog 

    strLog = "Err.Number is " _
                    & CSTR(Err.Number) _
                    & " & " _
                    & "Error Description is " & Err.Description _
                    & vbCr                      
                    
                    
    WScript.Echo strLog

    WScript.Quit 

end if

lngBias = localTimeBiasFromRegistry

If (TypeName(objUser.pwdLastSet) = "Object") Then

    Set objDatePwdLastSet = objUser.pwdLastSet
    
    dtmPwdLastSet = Integer8Date(objDatePwdLastSet, lngBias)
    
Else

    dtmPwdLastSet = #1/1/1601#
    
End If

strLog = "dtPwdLastSet :- " & CSTR(dtmPwdLastSet)

WScript.Echo strLog

sngMaxPwdAge = ADPasswordAge()

strLog = "sngMaxPwdAge :- " & CSTR(sngMaxPwdAge)
    
WScript.Echo strLog

dtPasswordExpiry = DateAdd("d",sngMaxPwdAge,dtmPwdLastSet) 

strLog = "dtPasswordExpiry " & CSTR(dtPasswordExpiry)
    
WScript.Echo strLog

'========================================
' Clean up.
'========================================
Set objUser = Nothing

Set maxPwdAge = Nothing


Invoke


cscript passwordExpirationDate.vbs

Output

Output – Image #1

Output – Image #2

 

GitHub

DanielAdeniji/ActiveDirectoryGetAccountPasswordExpirationDate
Link

Dedicated

Dedicated To …

  1. Richard Mueller ( Microsoft MVP )
  2. Devin H.
    • Get the Distinguished Name for an Active Directory Object
      Link

Active Directory – Change User’s Password – Resolution

 

Preface

In a previous post, I spoke of a SMK ( Shaking My Head ) moment I was having.

I couldn’t change a password assigned to a newly created Service Account.

The post is here.

 

 

Problem Identification

Thankfully, I have friends in high places or at least friends who are not so dim.

As Ron was leaving for the day, I said to him you gonna hate me for bothering you.

But, what is with my inability to change my password.

He said it is a Group Policy thing.

I said I checked the Group Policy (GP) and I did not see that.

 

Group Policy Report

Code

Using gpresult we can generate Group Policy Reports.

Generate HTML Output

Script


set "_user=LAB\sbc"
If not exist "d:\temp" md "d:\temp"
gpresult /USER %_user% /F /H d:\temp\grResultUser.html

 

Output

accountandpasswordpolicies

Generate Textual Output

Script


set "_user=LAB\svcSQL"

gpresult /V /USER %_user% | more

Output

rsop-minimumpasswordage

Explanation

Underneath \Policies\Windows Settings \ Account Policies / Password Policy

There  goes a Winning GPO stating “Minimum password age” is 5 days.

 

Conclusion

I still did not get it, and so Ron had to explain it.

A password has to be at least 5 days old, prior to anyone having the ability to change it.

The password was only created yesterday and so I have to a wait a few more days.

 

MSFT’s Recommendation

Cristian Dobre

Link

cristiandobre

 

Confirm Our Last Password Date

Let us confirm our last password date

Code – Credit

As always, I can not write this code.

Stealing this time from Homework

The specific post is titled “How to get the last password change for a user in Active Directory” and it is credited to Alessandro Tani.

It is available here.

Code


Import-Module ActiveDirectory

$ADUser="svcDBHRDB"

$formatDate="yyyy-MM-dd HH:mm"
$now=Get-Date -format $formatDate

"Current Date & TIme is {0}" -f $now

Get-ADuser $ADUser -properties PasswordLastSet | Format-List

 

Output

getaduseroutput-20161201-0838am

Errors

Error – Import-Module : The specified module ‘ActiveDirectory’ was not loaded because no valid module file was found in any module directory.

Please read this QA:

Import-Module : The specified module ‘activedirectory’ was not loaded because no valid module file was found in any module directory
Link

 

References

  1. Security Policy Settings Reference > Account Policies > Password Policy > Minimum password age
    Link
  2. Alessandro Tani
    • How to get the last password change for a user in Active Directory
      Link
  3. Nirmal Sharma
    • When was the Last Password Changed for a User Account in Active Directory
      Link

 

Active Directory – Disabling User’s Ability to Change His\Her Password – Through Group Policy

Background

Let us disable the user’s ability to Change his/her own password.

 

Installation

Let us download and install Group Policy

MS Windows 2003

Download

Unfortunately, we are on MS Windows 2003.

And, so we will download that OS Specific install binary.

The Microsoft Group Policy Management Console (GPMC) with Service Pack 1 (SP1) unifies management of Group Policy across the enterprise. The GPMC consists of a MMC snap-in and a set of programmable interfaces for managing Group Policy.
File :- gpmc.msi
Dated :- 2012-08-12
Link

 

Installed

Installed the download msi file.

 

Usage

Once installed, access Group Policy Management via “Administrative Tools” \ “Group Policy Management”.

Add Group Policy

Outline Steps

Copying “How To Prevent Users from Changing a Password Except When Required in Windows Server 2003” ( Here ) verbatim, here is the instruction:

  1. Click Start, point to Administrative Tools, and then click Active Directory Users and Computers.
  2. Right-click the domain or organizational unit for which you want to implement the new password change policy, and then click Properties.
  3. Click the Group Policy tab.
  4. Click the Group Policy object (GPO) that you want to work with, and then click Edit. If there are no existing policies listed in the Group Policy Object Links list, click New to create a new policy, type a name for the new policy, and then click Edit.
  5. Expand the GPO, expand User Configuration, expand Administrative Templates, and then expand System.
  6. Click Ctrl+Alt+Del Options.
  7. In the right pane, double-click Remove Change Password.
  8. Click Enabled, and then click OK.
  9. Quit the Group Policy Object Editor snap-in, click OK, and then quit the Active Directory Users and Computers snap-in.
  10. Click Start, and then click Run.
  11. Type cmd in the Open box, and then click OK.
  12. At the command prompt, type the following line, and then press ENTER:
    • gpupdate /target:user /force

Screen Shots

 

Initiate New GPO

Here we walk to Forest \ Domains \ < Domain Name > \ <ou>

In our case Forest \ Domains \ < Domain Name > \ Services.

We right clicked on our OU, Services, and chose “Create and Link a GPO Here…”.

 

initiatemenu-20161130-0204pm

New GPO

Upon clicking New GPO, here is the screen that allows us name a new GPO.

newgpo

 

Group Policy Object

Group Policy Object – Settings

Here is our Group Policy Settings when first created.

settings-20161130-0101pm

 

Group Policy Object – Edit Settings

Once the Group Policy is created, let us go in and customize it for our setting.

Choose the create Group Policy Object ( GPO ), right click it and from the drop down menu click the Edit button.

 

Group Policy Object – Edit Settings – “Initial

Here is the original screen…

grouppolicy-ctrlaltdel-options-initial

 

 

Group Policy Object – Edit Settings – “Amending Changes

Please choose “Remove Change Password”, and double-click on it

grouppolicy-ctrlaltdel-options-inprocess-removechangepassword

 

Group Policy Object – Edit Settings – “Remove Change Password – Enabled

Here is what things look like once we effect “Remove Change Password”.

grouppolicy-ctrlaltdel-options

 

 

Enable Group Policy

gpupdate /force

gpupdate-force

Group Policy Review

Let us review the Group Policy in place

Script

MS Windows 2003

Code


set "_username=LABDOMAIN\svcDB"

gpresult /USER %_username% /V

 

Output

gpresult-20161130-0242pm

Explanation

We see that for our Group Policy, “Group Policy Object – User Password”,  the key Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableChangePassword is enabled.

MS Windows 2012

On MS Window 2012 and likely OS Versions between Win 2003 and Windows 2012 ( 2008 & 2008/R2), we can output the result to an HTML or XML file.

That is accomplished through the /H or /Z options respectively.

The /F option states to force an overwrite of an existing output file.

Code


set "_user=LAB\svcDB"
If not exist "d:\temp" md "d:\temp"
gpresult /USER %_user% /F /H d:\temp\grResultUser.html

Test GP

Let us connect as our Service Account and see what happens when use CTRL-ALT-DEL or CTRL-ALT-End ( when connected over Remote Desktop )

 

deskop-changepassworddisabled

We see that “Change Password” is disabled.

 

Summary

What we have shown here is the ability to revoke the current user’s ability to change his\her password via CTRL-ALT-DEL.

It does not constrain that ability through Script, Active Users & Computer, etc.

 

References

  1. How To Prevent Users from Changing a Password Except When Required in Windows Server 2003
    Link
  2. Rob Dunn – How to delegate password reset permissions for your IT staff ( SpiceWorks )
    Link
  3. Redspin – Viewing GPO’s on the Commandline
    Link

Active Directory – Change User’s Password – Erroring

 

Preface

This is a difficult post as it does not demonstrate a remedying process.

It merely demonstrates a stumbling block, we ran into as we tried to change an Active Directory Service Account’s password.

BTW, a couple of choices for changing an AD’s Account password are documented here.

 

Changing AD User Password : Attempting

UI

Active Directory Users & Managers

Reset Password

resetpassword

 

Reset Password – Access is Denied

accessisdenied

 

Console

dsmod

Tried to change password using dsmod

Batch File


@echo off

Rem Change a domain account’s password from the command line	
Rem https://itnsomnia.wordpress.com/2008/04/08/change-a-domain-accounts-password-from-the-command-line/

set "_SAMAccountName=SQLSvc"
set "_ADPassword=antelopeWASBEFOREME#"

echo ADUser
dsquery user -samid %_SAMAccountName%

dsquery user -samid %_SAMAccountName%  | dsmod user  -mustchpwd no -pwd %_ADPassword%

Echo ERRORLEVEL is %ERRORLEVEL%



Output


ADUser
"CN=MSSQLsql,OU=ServiceAccounts,OU=LAB,DC=AD"
dsmod failed:CN=MSSQLsql,OU=ServiceAccounts,OU=LAB,DC=AD:Access is denied.:Set password failed
type dsmod /? for help.
ERRORLEVEL is -2147467259
>

 

 

Diagnostic

Active Directory Users And Computers

User’s Properties

Per-using Active Directory Users and Computer, here is the AD Account’s setting:

accountproperties-account

 

Explanation

  1. User must change password at next logon
    • Set
      • Good
  2. User cannot change change password
    • Not Set
      • Good
  3. Password never expires
    • Set
      • Good

Conclusion

From a simple User Property review, nothing should stop this Service Account from changing its own password.

In a follow-up post, will review whether restrictions have been set at the Organization (ou) level.

 

Active Directory – Change User’s Password

 

Background

Requested a few Service Accounts so that we can run a few SQL Server Instances using them.

I need to change the password to something a lot tighter.

Got a nice one from Norton Identity Safe; which is here.

 

Change Password

We can change using UI.

 

UI

UI – Self Change

Logged on to the system from console or through Remote Desktop.

If through remote desktop, access Change Password using CTRL/ALT/End

rdc-menu

 

changeapassword-brused-up

 

Console

Tool – dsmod

dsmod – Change User using User Distinguished name


rem John Howard -MSFT
Rem Sample scripts for dsadd, dsmodify, dsget, dsquery, dsmod, dsmove
Rem https://blogs.technet.microsoft.com/jhoward/2005/01/27/sample-scripts-for-dsadd-dsmodify-dsget-dsquery-dsmod-dsmove/

set "_UserDN=CN=svcLABMSSQL,CN=Users,DC=LAB,DC=org"
set "_ADPassword=Hello2819$"

dsmod user "%_UserDN%" -pwd %_ADPassword%


dsmod – Change User using SAMAccountName


Rem Change a domain account’s password from the command line	
Rem https://itnsomnia.wordpress.com/2008/04/08/change-a-domain-accounts-password-from-the-command-line/

set "_SAMAccountName=svcLABMSSQL"
set "_ADPassword=Hello2819$"

echo ADUser
dsquery user -samid %_SAMAccountName%

dsquery user -samid %_SAMAccountName%  | dsmod user  -mustchpwd no -pwd %_ADPassword%



 

dsmod – Error

If Error Occurs, please ouput out ERRORLEVEL.

Here are some common ones.

 

ErrorLevel Error Description Possible Source Links
 -2147467259 ADO_UNSPECIFIED This number doesn’t indicate a specific reason for this error but will always occur if there are problems in ADO requests, e.g. you forgot to pass the search scope (Subtree, OneLevel etc.) within your request string. This error can occur even without using ADO when you have a type mismatch while writing an object attribute (for example if you use the ADSI method Put to fill an integer or string attribute in a floating point number). In this case you better convert the value into a string first.  ADSI Self ADSI
 

 

 

 

References

  1. Microsoft
    • Reset a User Password
      Link
  2. Mitch Tulloch, author of Windows Server Hacks
    • Windows Server Hacks: Resetting User Passwords
      Link
  3. John Howard
    • Sample scripts for dsadd, dsmodify, dsget, dsquery, dsmod, dsmove
      Link
  4. John Savill
    • How can I change a domain user’s password from the command line in Windows Server 2003?
      Link
  5. itnsomnia
    • Change a domain account’s password from the command line
      Link

“Active Directory Users & Computers” on MS Windows 7

Background

Really missing “Active Directory Users and Computers” on my MS Windows box.

 

Download

Downloaded Remote Server Administration Tools for Windows 7 with Service Pack 1 (SP1) from here.

 

Installed

Installed Windows6.1-KB958830-x64-RefreshPkg.msu as my box is 64 bit.

 

Scripts

Documentation

As opted not to use GUI, needs to know the arguments to pass to the DISM installer.

Remote Server Administrative Tools roles

Link

       addsroles

List Features & Status

Script


dism /online /get-features /Format:Table | find "RemoteServerAdministrationTools-Roles"

 

Output

features-remoteserveradministrationtools-roles-ad

 

Enable Features & Status

Script


dism /online /enable-feature /featurename:RemoteServerAdministrationTools

dism /online /enable-feature /featurename:RemoteServerAdministrationTools-Roles

dism /online /enable-feature /featurename:RemoteServerAdministrationTools-Roles-AD

dism /online /enable-feature /featurename:RemoteServerAdministrationTools-Roles-AD-DS

dism /online /enable-feature /featurename:RemoteServerAdministrationTools-Roles-AD-DS-SnapIns

Output

enablefeature-20161021-0214pm

 

Usage

Access MMC

Launch through Window’s Start Menu

Administrative Tools \ Active Directory Users and Computers

startmenu

Use Functionality

Find Users, Contacts, and Groups

ad-findusers

References

  1. What Are the Remote Server Administration Tools?
    Link