Jump to content

Active Directory UDF (II)


water
 Share

Recommended Posts

The latest available AD UDF can be found here: https://www.autoitscript.com/forum/files/file/355-ad-active-directory-udf/

The version you run can be found by running _AD_VersionInfo.au3 or by checking line 9 ("UDF Version ...:") in the UDF code.

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

This test version should display the array of DCs two times (1st all DCs, then the list of DCs for the specified site). Further error information should get written to the SciTE console.

#AutoIt3Wrapper_AU3Check_Parameters= -d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#AutoIt3Wrapper_AU3Check_Stop_OnWarning=Y
#include <AD.au3>

; Open Connection to the Active Directory
_AD_Open()
If @error Then Exit MsgBox(16, "Active Directory Example Skript", "Function _AD_Open encountered a problem. @error = " & @error & ", @extended = " & @extended)

Global $iLLDate = _AD_GetLastLoginDateEX(default, "NFRZ")
If @error Then Exit MsgBox(16, "Error", "User: @error=" & @error & ", @extended=" & @extended)
MsgBox(64, "Active Directory Functions - Example 1", "Last Login Date for User '" & @UserName & "'" & @CRLF & $iLLDate)

; Close Connection to the Active Directory
_AD_Close()

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_GetLastLoginDate
; Description ...: Returns the lastlogin information for user and computer accounts from all DCs using the SamAccountName.
; Syntax.........: _AD_GetLastLoginDate([$sObject = @Username[, $sSite = ""[, $aDCList = ""]]])
; Parameters ....: $sObject - Optional: SamAccountName of a user or computer account to get the last login date (default = @Username).
;                  $sSite   - Optional: Only query DCs that belong to this site(s) (default = all sites).
;                  +This can be a single site or a list of sites separated by commas
;                  $aDCList - Optional: one-based two dimensional array of Domain Controllers as returned by function _AD_ListDomainControllers (default = "")
; Return values .: Success - Last login date returned as YYYYMMDDHHMMSS. @extended is set to the total number of Domain Controllers.
;                  +@error could be > 0 and contains the number of DCs that could not be reached or returns no data
;                  Failure - 0, sets @error to:
;                  |1 - $sObject could not be found. @extended = 0
;                  |2 - $sObject has never logged in to the domain. @extended = 0
;                  |3 - $aDCList has to be an array or blank
;                  |4 - $aDCList has to be a 2-dimensional array
;                  Warning - Last login date returned as YYYYMMDDHHMMSS (see Success), sets @error and @extended to:
;                  |x - Number of DCs which could not be reached. Result is returned from all available DCs. @extended is set to the total number of Domain Controllers
; Author ........: Jonathan Clelland
; Modified.......: water, Stephane
; Remarks .......: If it takes (too) long to get a result either some DCs are down or you have too many DCs in your AD.
;                  +Case one: Please check @error and @extended as described above
;                  +Case two: Specify parameter $sSite to reduce the number of DCs to query and/or retrieve the list of DCs yourself and pass the array as parameter 3
; Related .......:
; Link ..........: http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx
; Example .......: Yes
; ===============================================================================================================================
Func _AD_GetLastLoginDateEX($sObject = @UserName, $sSite = "", $aDCList = "")

    If $sObject = Default Then $sObject = @UserName
    If $sSite = Default Then $sSite = ""
    If $aDCList = Default Then $aDCList = ""
    If _AD_ObjectExists($sObject) = 0 Then Return SetError(1, 0, 0)
    If Not IsArray($aDCList) And $aDCList <> "" Then Return SetError(3, 0, 0)
    If IsArray($aDCList) And UBound($aDCList, 0) <> 2 Then Return SetError(4, 0, 0)
    If $aDCList = "" Then $aDCList = _AD_ListDomainControllers()
_ArrayDisplay($aDCList, "List of all DCs") ; ~~
    Local $aSite, $sSingleDC, $bWasIn
    ; Delete all DCs not belonging to the specified site
    $aSite = StringSplit($sSite, ",", 2)
    If UBound($aSite) > 0 And $aSite[0] <> "" Then
        For $iCount1 = $aDCList[0][0] To 1 Step -1
            $bWasIn = False
            For $sSingleDC In $aSite
                If $aDCList[$iCount1][3] = $sSingleDC Then $bWasIn = True
            Next
            If Not $bWasIn Then _ArrayDelete($aDCList, $iCount1)
        Next
        $aDCList[0][0] = UBound($aDCList, 1) - 1
    EndIf
_ArrayDisplay($aDCList, "List of all DCs for the specified site") ; ~~
    ; Get LastLogin from all DCs
    Local $aResult[$aDCList[0][0] + 1]
    Local $sLDAPEntry, $oObject, $oRecordSet
    Local $iError1 = 0, $iError2 = 0
    For $iCount1 = 1 To $aDCList[0][0]
ConsoleWrite("Pinging DC " & $aDCList[$iCount1][2] & @CRLF)
        If Ping($aDCList[$iCount1][2]) = 0 Then
ConsoleWrite("  Result: @error = " & @error & @CRLF)
            $iError1 += 1
            ContinueLoop
        EndIf
ConsoleWrite("Query DC " & $aDCList[$iCount1][2] & @CRLF)
        $__oAD_Command.CommandText = "<LDAP://" & $aDCList[$iCount1][2] & "/" & $sAD_DNSDomain & ">;(sAMAccountName=" & $sObject & ");ADsPath;subtree"
        $oRecordSet = $__oAD_Command.Execute ; Retrieve the ADsPath for the object
        ; -2147352567 or 0x80020009 is returned when the service is not operational
        ;       If @error = -2147352567 Or $oRecordSet.RecordCount = 0 Then
        If @error Or $oRecordSet.RecordCount = 0 Then
ConsoleWrite($aDCList[$iCount1][2] & " returned @error=" & @error & ", @extended=" & @extended & @CRLF)
            $iError1 += 1
        Else
            $sLDAPEntry = $oRecordSet.fields(0).Value
            $oObject = __AD_ObjGet($sLDAPEntry) ; Retrieve the COM Object for the object
If @error Then ConsoleWrite("ObjGet for " & $aDCList[$iCount1][2] & " returned @error=" & @error & ", @extended=" & @extended & @CRLF)
            $aResult[$iCount1] = $oObject.LastLogin
            ; -2147352567 or 0x80020009 is returned when the attribute "LastLogin" isn't defined on this DC
            ;           If @error = -2147352567 Then $iError2 += 1
            If @error Then
ConsoleWrite("PropertyGet for " & $aDCList[$iCount1][2] & " returned @error=" & @error & ", @extended=" & @extended & @CRLF)
                $iError2 += 1
            EndIf
            $oObject.PurgePropertyList
        EndIf
    Next
    _ArraySort($aResult, 1, 1)
    ; If error count equals the number of DCs then the user has never logged in
    If $iError2 = $aDCList[0][0] Then Return SetError(2, 0, 0)
    Return SetError($iError1, $aDCList[0][0], $aResult[1])

EndFunc   ;==>_AD_GetLastLoginDateEX

 

Edited by water

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Which messages do you get on the SciTE console?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

I modified my above script so it writes to the Console every DC it pings and the error code, if any.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

  • 1 month later...

Long time reader, first time poster.  I'm struggling a bit with _AD_GetObjectOU.  If I run this code with @username, it works.  But with @computername I get error 1.  My user and computer objects are in the same OU.  I've already got working code which moves a PC to a new OU, and I'm wanting to prevent these moves for specific OUs.  I figured the easiest way would be to drop all the excluded OUs into an array and compare them to the machine's OU.  But I can't seem to get this to work for a computer object.

_AD_Open("username","password","","","",3)
   $dnTest = _AD_GetObjectOU(@ComputerName, "distinguishedName")
   msgbox(48,"Debug", "Name: " & @ComputerName & " Computer DN: " & $dnTest & " Error: " & @error)
_AD_Close()

 

 

 

Link to comment
Share on other sites

  • Moderators

@CrabChuck as shown in the example script for _AD_GetObjectOU, when dealing with computer objects you need to add $ after them. Thhis works just fine for me:

#include <AD.au3>

_AD_Open()
   $dnTest = _AD_GetObjectOU(@ComputerName & "$", "distinguishedName")
   msgbox(48,"Debug", "Name: " & @ComputerName & " Computer DN: " & $dnTest & " Error: " & @error)
_AD_Close()

 

"Profanity is the last vestige of the feeble mind. For the man who cannot express himself forcibly through intellect must do so through shock and awe" - Spencer W. Kimball

How to get your question answered on this forum!

Link to comment
Share on other sites

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

water,

thank you for your UDF and keeping it supported!

Sometimes _AD_GetPasswordInfo() produces an error in our environment. Calling $aTemp = _AD_GetObjectProperties($sObject, "MSDS-UserPasswordExpiryTimeComputed") seems to be domain controller dependent. Connected to a 2003 (R2) DC an empty array will return (@error = 0). This seems to be no real failure due to the fact that 2003 does not support this computed value (please see https://docs.microsoft.com/en-us/windows/desktop/adschema/a-msds-userpasswordexpirytimecomputed). A 2008+ (R2) DC returns as expected. As a simple workaround I use this:

If @error = 0 And UBound($aTemp, 1) > 1 Then
    $aPwdInfo[13] = $aTemp[1][1]
Else ; Required if DC version < 2008.
    $aPwdInfo[13] = $aPwdInfo[9]
EndIf

... instead of If @error = 0 Then $aPwdInfo[13] = $aTemp[1][1]. I will be pleased if this function could handle this case.

Thank you!

Link to comment
Share on other sites

This is the modified version:

; #FUNCTION# ====================================================================================================================
; Name...........: _AD_GetPasswordInfo
; Description ...: Returns password information retrieved from the domain policy and the specified user or computer account.
; Syntax.........: _AD_GetPasswordInfo([$sSamAccountName = @UserName])
; Parameters ....: $sObject - Optional: User or computer account to get password info for (default = @UserName). Format is sAMAccountName or FQDN
; Return values .: Success - Returns a one-based array with the following information:
;                  |1 - Maximum Password Age (days)
;                  |2 - Minimum Password Age (days)
;                  |3 - Enforce Password History (# of passwords remembered)
;                  |4 - Minimum Password Length
;                  |5 - Account Lockout Duration (minutes). 0 means the account has to be unlocked manually by an administrator
;                  |6 - Account Lockout Threshold (invalid logon attempts)
;                  |7 - Reset account lockout counter after (minutes)
;                  |8 - Password last changed (YYYY/MM/DD HH:MM:SS in local time of the calling user) or "1601/01/01 00:00:00" (means "Password has never been set")
;                  |9 - Password expires (YYYY/MM/DD HH:MM:SS in local time of the calling user) or empty when password has not been set before or never expires
;                  |10 - Password last changed (YYYY/MM/DD HH:MM:SS in UTC) or "1601/01/01 00:00:00" (means "Password has never been set")
;                  |11 - Password expires (YYYY/MM/DD HH:MM:SS in UTC) or empty when password has not been set before or never expires
;                  |12 - Password properties. Part of Domain Policy. A bit field to indicate complexity / storage restrictions
;                  |      1 - DOMAIN_PASSWORD_COMPLEX
;                  |      2 - DOMAIN_PASSWORD_NO_ANON_CHANGE
;                  |      4 - DOMAIN_PASSWORD_NO_CLEAR_CHANGE
;                  |      8 - DOMAIN_LOCKOUT_ADMINS
;                  |     16 - DOMAIN_PASSWORD_STORE_CLEARTEXT
;                  |     32 - DOMAIN_REFUSE_PASSWORD_CHANGE
;                  |13 - Calculated password expiration date/time. Identical with element 9 of this array.
;                  |     Returns a value even when fine grained password policy is in use; which means that most of the other elements of this array are blank or 0.
;                  |     This is a Virtual Attribute (aka "Pseudo Attribute", "Constructed Attribute" or "Back-link") where the value is calculated by the LDAP Server Implementation and is not actually part of the LDAP Entry.
;                  Failure - "", sets @error to:
;                  |1 - $sObject not found
;                  |2 - Function _AD_GetObjectProperties returned an error which is returned in @extended
;                  Warning - Returns a one-based array (see Success), sets @extended to:
;                  |1 - Password does not expire (User Access Control - UAC - is set)
;                  |2 - Password has never been set
;                  |4 - The Maximum Password Age is set to 0 in the domain. Therefore, the password does not expire
;                  |8 - The version of the accessed DC (needs to be >= 2008) does not support property MSDS-UserPasswordExpiryTimeComputed. Element 13 of the returned array is set to element 9.
;                  |The @extended value can be a combination of the above values e.g. 3 = 1 (Password does not expire) + 2 (Password has never been set)
; Author ........: water
; Modified.......:
; Remarks .......: For details about password properties please check: http://msdn.microsoft.com/en-us/library/aa375371(v=vs.85).aspx
; Related .......: _AD_IsPasswordExpired, _AD_GetPasswordExpired, _AD_GetPasswordDontExpire, _AD_SetPassword, _AD_DisablePasswordExpire, _AD_EnablePasswordExpire, _AD_EnablePasswordChange,  _AD_DisablePasswordChange
; Link ..........: http://www.autoitscript.com/forum/index.php?showtopic=86247&view=findpost&p=619073, http://windowsitpro.com/article/articleid/81412/jsi-tip-8294-how-can-i-return-the-domain-password-policy-attributes.html
; Example .......: Yes
; ===============================================================================================================================
Func _AD_GetPasswordInfo($sObject = @UserName)

    If $sObject = Default Then $sObject = @UserName
    If _AD_ObjectExists($sObject) = 0 Then Return SetError(1, 0, "")
    If StringMid($sObject, 3, 1) <> "=" Then $sObject = _AD_SamAccountNameToFQDN($sObject) ; sAMAccountName provided
    Local $iExtended = 0, $aPwdInfo[14] = [13], $oObject, $oUser, $sPwdLastChanged, $iUAC, $aTemp
    $oObject = __AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain)
    $aPwdInfo[1] = Int(__AD_Int8ToSec($oObject.Get("maxPwdAge"))) / 86400 ; Convert to Days
    $aPwdInfo[2] = __AD_Int8ToSec($oObject.Get("minPwdAge")) / 86400 ; Convert to Days
    $aPwdInfo[3] = $oObject.Get("pwdHistoryLength")
    $aPwdInfo[4] = $oObject.Get("minPwdLength")
    ; Account lockout duration: http://msdn.microsoft.com/en-us/library/ms813429.aspx
    ; http://www.autoitscript.com/forum/topic/158419-active-directory-udf-help-support-iii/page-5#entry1173322
    $aPwdInfo[5] = __AD_Int8ToSec($oObject.Get("lockoutDuration")) / 60 ; Convert to Minutes
    If $aPwdInfo[5] < 0 Or $aPwdInfo[5] > 99999 Then $aPwdInfo[5] = 0
    $aPwdInfo[6] = $oObject.Get("lockoutThreshold")
    $aPwdInfo[7] = __AD_Int8ToSec($oObject.Get("lockoutObservationWindow")) / 60 ; Convert to Minutes
    $oUser = __AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sObject)
    $sPwdLastChanged = $oUser.Get("PwdLastSet")
    $iUAC = $oUser.userAccountControl
    ; Has user account password been changed before?
    If $sPwdLastChanged.LowPart = 0 And $sPwdLastChanged.HighPart = 0 Then
        $iExtended = BitOR($iExtended, 2)
        $aPwdInfo[8] = "1601/01/01 00:00:00"
        $aPwdInfo[10] = "1601/01/01 00:00:00"
    Else
        Local $sTemp = DllStructCreate("dword low;dword high")
        DllStructSetData($sTemp, "Low", $sPwdLastChanged.LowPart)
        DllStructSetData($sTemp, "High", $sPwdLastChanged.HighPart)
        ; Have to convert to SystemTime because _Date_Time_FileTimeToStr has a bug (#1638)
        Local $sTemp2 = _Date_Time_FileTimeToSystemTime(DllStructGetPtr($sTemp))
        $aPwdInfo[10] = _Date_Time_SystemTimeToDateTimeStr($sTemp2, 1)
        ; Convert PwdlastSet from UTC to Local Time
        $sTemp2 = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sTemp2))
        $aPwdInfo[8] = _Date_Time_SystemTimeToDateTimeStr($sTemp2, 1)
        ; Is user account password set to expire?
        If BitAND($iUAC, $ADS_UF_DONT_EXPIRE_PASSWD) = $ADS_UF_DONT_EXPIRE_PASSWD Or $aPwdInfo[1] = 0 Then
            If BitAND($iUAC, $ADS_UF_DONT_EXPIRE_PASSWD) = $ADS_UF_DONT_EXPIRE_PASSWD Then $iExtended = BitOR($iExtended, 1)
            If $aPwdInfo[1] = 0 Then $iExtended = BitOR($iExtended, 4) ; The Maximum Password Age is set to 0 in the domain. Therefore, the password does not expire
        Else
            $aPwdInfo[11] = _DateAdd("d", $aPwdInfo[1], $aPwdInfo[10])
            $sTemp2 = _Date_Time_EncodeSystemTime(StringMid($aPwdInfo[11], 6, 2), StringMid($aPwdInfo[11], 9, 2), StringMid($aPwdInfo[11], 1, 4), StringMid($aPwdInfo[11], 12, 2), StringMid($aPwdInfo[11], 15, 2), StringMid($aPwdInfo[11], 18, 2))
            ; Convert PasswordExpires from UTC to Local Time
            $sTemp2 = _Date_Time_SystemTimeToTzSpecificLocalTime(DllStructGetPtr($sTemp2))
            $aPwdInfo[9] = _Date_Time_SystemTimeToDateTimeStr($sTemp2, 1)
        EndIf
    EndIf
    $aPwdInfo[12] = $oObject.Get("pwdProperties")
    $aTemp = _AD_GetObjectProperties($sObject, "MSDS-UserPasswordExpiryTimeComputed")
    If @error = 0 Then
        If UBound($aTemp, 1) > 1 Then
            $aPwdInfo[13] = $aTemp[1][1]
        Else ; Required if DC version < 2008.
            $aPwdInfo[13] = $aPwdInfo[9]
            $iExtended = BitOR($iExtended, 8)
        EndIf
    Else
        Return SetError(2, @error, "")
    EndIf
    Return SetError(0, $iExtended, $aPwdInfo)

EndFunc   ;==>_AD_GetPasswordInfo

What I changed:

  • SCRIPT BREAKING: The old function returned some warning information in @error. Now the warning info gets returned in @extended (which is more sensible). The values have changed (old: 2-4 , now: 1, 2, 4, 8). The old form could lead to wrong results.
  • New warning value added: 8 describes that the DC does not support the computed property.
  • If _AD_GetObjectProperties returns an error _AD_GetPasswordInfo returns this error and sets the return value to "".

What do you think?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Hi, thanks so much for including the Exchange create mailbox function in the UDF, it's working great. Personally, I'd rather the user not see the Powershell command prompt when creating a mailbox, and just wondering whether this can hidden, either permanently or through a parameter? I've manually changed line 4203 to @SW_HIDE for myself but just a suggestion to include in the UDF :) 

 

Link to comment
Share on other sites

Good idea :) Will add an additional parameter to the next release to set the showflag parameter.

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

This is the modified function. Show_flag is set to Default which means @SW_Hide.
What do you think?

; #FUNCTION#====================================================================================================================
; Name...........: _AD_CreateMailboxPS
; Description ...: Creates a mailbox for a user using PowerShell
; Syntax.........: _AD_CreateMailboxPS($sUser, $sURI[, $sSessionParam = Default[, $sMailboxParam = Default[, $sRunShowFlag = Default]])
; Parameters ....: $sUser         - User account (SamAccountName or FQDN) for which you want to create the mailbox
;                  $sURI          - Specifies a URI that defines the connection endpoint for the session. The URI must be fully qualified.
;                                   Example: http://YourExchangeServerNameGoesHere.CompanyName.com
;                  $sSessionParam - Optional: One or multiple additional parameters for the PowerShell "Session" command e.g. " -Authentication Kerberos"
;                  $sMailboxParam - Optional: One or multiple additional parameters for the PowerShell "Enable-Mailbox" command (see parameter $sSessionParam)
;                  $sRunShowFlag  - Optional: Sets the show-flag parameter of the Run command. Default = Default keyword
; Return values .: Success - Zero based one-dimensional array holding the StdOut messages written by PowerShell
;                  Failure - "", sets @error to:
;                  |1 - $sUser does not exist
;                  |2 - $sUser already has a mailbox
;                  |3 - $sUser is invalid (empty)
;                  |4 - $sURI is invalid (empty)
;                  |5 - Run returned an error (PowerShell could not be started). @extended is set to the @error returned by Run
;                  |6 - Writing to StdIn returned an error. @extended is set to the @error returned by StdinWrite
;                  Failure - Zero based one-dimensional array holding the StdErr messages written by PowerShell, sets error to:
;                  |7 - PowerShell has written some error messages to StdErr.
; Author ........: water
; Modified.......:
; Remarks .......: The mailbox is created using PowerShell. No additional tools need to be installed on the local mchine.
; Related .......:
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func _AD_CreateMailboxPS($sUser, $sURI, $sSessionParam = Default, $sMailboxParam = Default, $sRunShowFlag = Default)

    Local $aResult, $sProperty, $oRecordSet, $sLDAPEntry, $oUser, $iPID, $sCMD = "Powershell -Command -", $sSTDOUT = "", $sSTDERR = "", $sOutput = "", $bError = False
    If StringStripWS($sUser, $STR_STRIPALL) = "" Then Return SetError(3, 0, "")
    If StringStripWS($sURI, $STR_STRIPALL) = "" Then Return SetError(4, 0, "")
    If $sSessionParam = Default Then $sSessionParam = ""
    If $sMailboxParam = Default Then $sMailboxParam = ""
    If Not _AD_ObjectExists($sUser) Then Return SetError(1, 0, "")
    $sProperty = "sAMAccountName"
    If StringMid($sUser, 3, 1) = "=" Then $sProperty = "distinguishedName" ; FQDN provided
    $__oAD_Command.CommandText = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sProperty & "=" & $sUser & ");ADsPath;subtree"
    $oRecordSet = $__oAD_Command.Execute ; Retrieve the ADsPath for the object
    $sLDAPEntry = $oRecordSet.fields(0).Value
    $oUser = __AD_ObjGet($sLDAPEntry) ; Retrieve the COM Object for the object
    If $oUser.HomeMDB <> "" Then Return SetError(2, 0, "")
    $iPID = Run($sCMD, @SystemDir, $sRunShowFlag, $STDIN_CHILD + $STDOUT_CHILD + $STDERR_CHILD)
    If $iPID = 0 Or @error Then Return SetError(5, @error, "")
    $sCMD = "$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri " & $sURI & " " & $sSessionParam & _
            ";Import-PSSession $Session" & _
            ";Enable-Mailbox -Identity " & $sUser & " " & $sMailboxParam & _
            ";Remove-PSSession $Session"
    StdinWrite($iPID, $sCMD)
    If @error Then Return SetError(6, @error, "")
    StdinWrite($iPID)
    ; Process STDOUT
    While 1
        $sOutput = StdoutRead($iPID)
        If @error Then ExitLoop
        If $sOutput <> "" Then $sSTDOUT = $sSTDOUT & $sOutput
    WEnd
    ; Process STDERR
    While 1
        $sOutput = StderrRead($iPID)
        If @error Then ExitLoop
        If $sOutput <> "" Then $sSTDERR = $sSTDERR & $sOutput
        $bError = True
    WEnd
    If $bError Then
        $aResult = StringSplit($sSTDERR, @CRLF, $STR_ENTIRESPLIT + $STR_NOCOUNT)
        Return SetError(7, 0, $aResult)
    Else
        $aResult = StringSplit($sSTDOUT, @CRLF, $STR_ENTIRESPLIT + $STR_NOCOUNT)
        Return $aResult
    EndIf
EndFunc   ;==>_AD_CreateMailboxPS

 

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

  • 3 weeks later...

water,

thank you for V1.4.11.0 - I'm currently updating my scripts regarding _AD_GetPasswordInfo. Differently than originally thought/written, it's somehow "unhandy" to error out this function by @error = 2 if _AD_GetObjectProperties fails. It will be OK for me if it stays that way, but I think @extended += 8 reflects this issue sufficiently. My idea:

If @error = 0 And UBound($aTemp, 1) > 1 Then
    $aPwdInfo[13] = $aTemp[1][1]
Else ; Required if DC version < 2008.
    $aPwdInfo[13] = $aPwdInfo[9]
    $iExtended = BitOR($iExtended, 8)
EndIf

What do you think?

Link to comment
Share on other sites

With the current implementation I wanted to grab ALL possible situations:

  • The property has been found
  • The property has not been found
  • Another error occurred

With your solution I can only grab situation 1 and 2.
In which cases do you get @error = 2 where the cause isn't "DC version < 2008"?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

water,

I did not express myself well:

All of the @extended return codes should stay unchanged - but why should this function error out if _AD_GetObjectProperties fails? As you say yourself "In which cases do you get @error = 2 where the cause isn't "DC version < 2008"?" - so I understand that way both causes happen mostly same time and @extended = 8 currently reflects this situation well enough.

I don't really like to bother you, here's a idea of how to reflect both situations using @extended w/o erroring out by @error = 2:

$aTemp = _AD_GetObjectProperties($sObject, "MSDS-UserPasswordExpiryTimeComputed")
    If @error = 0 Then
        If UBound($aTemp, 1) > 1 Then
            $aPwdInfo[13] = $aTemp[1][1]
        Else ; Required if DC version < 2008.
            $aPwdInfo[13] = $aPwdInfo[9]
            $iExtended = BitOR($iExtended, 16)
        EndIf
    Else
        $aPwdInfo[13] = $aPwdInfo[9]
        $iExtended = BitOR($iExtended, 8)
    EndIf

Anyway you decide I'm happy with it - I just liked to let you know.

Link to comment
Share on other sites

  • 2 weeks later...

We have 3 cases the function should handle:

  1. DC >= 2008: @error = 0, @extended = 0
  2. DC < 2008: @error = 0, @extended = 8
  3. All other situations: @error = 2, @extended depends on the error that happened

You get @error = 2 in case number 2?

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...