Johny Clelland Posted February 19, 2010 Posted February 19, 2010 Hi, I'm back again...apologies for my absence. Congratulations on your fabulous work! I'm very impressed with the conversion to UDF format that you've carried out. I could never have managed all this (there's only so many hours in the day). Have you thought about how to convert old scripts to the UDF versions? I'll have a look and see if there's any simple way of doing it. I have rather a lot of scripts that use my original 'include' file, and it would probably make sense to convert to using your UDF, but I don't fancy manually modifying 9500+ lines of code. I'll have a play with the new UDF version and see if I can't figure out a simple way of converting. I guess I'll need to consult your version history to see what changes have occurred to functions over the course of your work. I think since we last spoke I've only added one further function to my own copy. This is a way to add additional SMTP addresses to an Exchange-enabled account. I also have code for Removing/Editing these, though I haven't formalised it into ADFunctions yet. Here's my attempt at making the code compatible with your UDF format, let me know if you need anything else. expandcollapse popup; #FUNCTION# ==================================================================================================================== ; Name...........: _AD_AddEmailAddress ; Description ...: Add an additional SMTP email address to the 'Email Addresses' tab of an Exchange-enabled AD account ; Syntax.........: _AD_AddEmailAddress($sAD_User, $sAD_newemail[, $fAD_primary = False]) ; Parameters ....: $sAD_User - User account (sAMAccountName or FQDN) ; $sAD_newemail - Email address to add to the account ; $fAD_Flag - Optional: if TRUE the new email address will be set as primary address ; Return values .: Success - 1 ; Failure - 0, @error set ; |1 - $sAD_User does not exist ; |2 - Could not connect to $sAD_User ; Author ........: Jonathan Clelland ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: No ; =============================================================================================================================== Func _AD_AddEmailAddress($sAD_User, $sAD_newemail, $fAD_primary = False) If _AD_ObjectExists($sAD_User) = 0 Then Return SetError(1, 0, 0) If StringMid($sAD_User, 3, 1) <> "=" Then $sAD_User = _AD_SamAccountNameToFQDN($sAD_User) ; sAMAccountName provided Local $oAD_User = _ADObjGet("LDAP://" & $sAD_HostServer & "/" & $sAD_User) If Not IsObj($oAD_User) Then MsgBox(0, "Error!", "An error occurred attaching to the user object '" & $sAD_User & "'.") Return SetError(2, 0, 0) EndIf Local $aAD_proxyaddresses = $oAD_User.GetEx("proxyaddresses") If $fAD_primary Then For $i = 0 To UBound($aAD_proxyaddresses) - 1 If StringInStr($aAD_proxyaddresses[$i], "SMTP:", 1) Then $aAD_proxyaddresses[$i] = StringReplace($aAD_proxyaddresses[$i], "SMTP:", "smtp:", 0, 1) EndIf Next _ArrayAdd($aAD_proxyaddresses, "SMTP:" & $sAD_newemail) $oAD_User.Put("mail", $sAD_newemail) Else _ArrayAdd($aAD_proxyaddresses, "smtp:" & $sAD_newemail) EndIf $oAD_User.PutEx(2, "proxyaddresses", $aAD_proxyaddresses) $oAD_User.SetInfo If @error <> 0 Then Return SetError(@error, 0, 0) Return 1 EndFunc And here's an example of how to use it; expandcollapse popup; ***************************************************************************** ; Example 1 ; Add an email address to a user ; ***************************************************************************** #include <AD.au3> #include <ButtonConstants.au3> #include <GUIConstantsEx.au3> #include <WindowsConstants.au3> ; Open Connection to the Active Directory _AD_Open() $iReply = MsgBox(308, "Active Directory Functions - Example 1", "This script adds an email address to a user." & @CRLF & @CRLF & _ "Are you sure you want to change the Active Directory?") If $iReply <> 6 Then Exit ; Enter user account and description #Region ### START Koda GUI section ### Form= $Form1 = GUICreate("Active Directory Functions - Example 1", 514, 124) GUICtrlCreateLabel("User account (samAccountName or sAMAccountName):", 8, 10, 231, 34) GUICtrlCreateLabel("New email address:", 8, 42, 231, 17) $IUser = GUICtrlCreateInput(@UserName, 241, 8, 259, 21) $IEmail = GUICtrlCreateInput("me@mydomain.com", 241, 40, 259, 21) $BOK = GUICtrlCreateButton("Add address", 8, 72, 121, 33) $BCancel = GUICtrlCreateButton("Cancel", 428, 72, 73, 33, BitOR($GUI_SS_DEFAULT_BUTTON, $BS_DEFPUSHBUTTON)) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE, $BCancel Exit Case $BOK $sUser = GUICtrlRead($IUser) $sEmail = GUICtrlRead($IEmail) ExitLoop EndSwitch WEnd ; Change attribute $iValue = _AD_AddEmailAddress($sUser, $sEmail, True) If $iValue = 1 Then MsgBox(64, "Active Directory Functions - Example 1", "Email address for user '" & $sUser & "' successfully changed") ElseIf @error = 1 Then MsgBox(64, "Active Directory Functions - Example 1", "User '" & $sUser & "' does not exist") Else MsgBox(64, "Active Directory Functions - Example 1", "Return code '" & @error & "' from Active Directory") EndIf ; Close Connection to the Active Directory _AD_Close() Thanks again for all your hard work, as I say, the UDF version would never have been possible without you, Cheers, Johny. Hi, I think we got hit by bug #1068: Binary to Int. This was fixed in 3.3.2.0 I was always wondering why the function returned a negative value because IsMember only returns 0x0 or 0x1. I changed the code to return an absolute value so the function returns a valid result for every AutoIt version.
water Posted February 20, 2010 Author Posted February 20, 2010 Hi Johny,glad you like the UDF version I will incorporate _AD_AddEmailAddress in the next version.Have you thought about how to convert old scripts to the UDF versions?No I haven't. I have myself converted some scripts from adfunctions.au3 to AD.au3. It didn't take me long as the scripts only had a few calls to adfunctions.au3.But I think it's better to do it manually for the following reasons:You have to add _AD_Open and _AD_Close calls at the appropriate places in your scriptYou have to change the function names from _AD* to _AD_*I've removed ByRef so the way data is returned has changed (see the history for which functions are affected)Some conversion code (from SamAccountName to FQDN and vice versa) can be removed from the scripts as it will be done by the function itselfYou might have to change the error checking code. The functions now set @error so you don't have to check the result any moreHave a nice weekend My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
water Posted February 25, 2010 Author Posted February 25, 2010 Wow - 200 downloads of the UDF and (nearly) no questions. Everyone is happy with the UDF so far? My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
gcue Posted March 2, 2010 Posted March 2, 2010 yes very! great job just waiting for the connection check error =) thank you for putting so much work into it =)
water Posted March 2, 2010 Author Posted March 2, 2010 Hi gcue, just waiting for confirmation that _AD_JoinDomain (new function) and _AD_IsObjectLocked (rewritten function) work. Then I will release 0.37 My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
gcue Posted March 8, 2010 Posted March 8, 2010 thanks for the error checking! works great =) great work water
water Posted March 8, 2010 Author Posted March 8, 2010 Wow! That was fast! Glad it works. My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
water Posted March 8, 2010 Author Posted March 8, 2010 My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
Yorn Posted March 8, 2010 Posted March 8, 2010 I can echo that there are some of us that use this UDF nearly daily that can't thank you enough for the work put into it. Prior to Johnny and your work in this area I was doing most object calls manually so it's handy to have a convenient way to regularly do simple AD tasks. Thanks!
water Posted March 9, 2010 Author Posted March 9, 2010 That's the reason why I started to convert Johns adfunctions into a "real" UDF. I made some scripts based on his UDF that saved me a lot of time in my company. I received a lot of help from this forum as well. So it was only fair to return a bit of time and effort. I'm glad so many people - as shown by the download stats - like the work of John and me. My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
eternally1027 Posted March 9, 2010 Posted March 9, 2010 (edited) Water, Looks great so far. I use a combination of Clelland's UDF and another UDF which I found floating around. I use these in a Production environment for a fairly large enterprise. As such, I have stabilized all of the code which I use. It is good to see a promising new compilation. One suggestion is to combine all of the existing UDFs. For example, Clelland's v3.3 has functions that v3.35 does not. Here are a few functions which I converted from v3.3 to v3.35. They have been tested thoroughly. I have put them into the appropriate format for the UDF, I believe. expandcollapse popup; #Function#==================================================================================================================== ; Name...........: _AD_SetPasswordExpired ; Description ...: Sets user's password as expired ; Syntax.........: _AD_SetPasswordExpired($sAD_Object) ; Parameters ....: $sAD_Object - Username ; Return values .: 0 (Failed) or 1 (Worked) ; Author ........: Ethan Turk ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _AD_SetPasswordExpired($sAD_Object) If Not _AD_ObjectExists($sAD_Object) Then Return SetError(1, 0, 0) Local $sAD_Property = "sAMAccountName" If StringMid($sAD_Object, 3, 1) = "=" Then $sAD_Property = "distinguishedName"; FQDN provided Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sAD_Property & "=" & $sAD_Object & ");ADsPath;subtree" Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query) ; Retrieve the FQDN for the object Local $sAD_LDAPEntry = $oAD_RecordSet.fields(0).value Local $oAD_Object = _AD_ObjGet($sAD_LDAPEntry) ; Retrieve the COM Object for the object ;$oAD_Object.GetInfo $oAD_Object.Put ("pwdLastSet", "0") $oAD_Object.SetInfo() Local $iAD_Error = @error If $iAD_Error <> 0 Then Return SetError($iAD_Error, 0, 0) Return 1 EndFunc ; #Function#==================================================================================================================== ; Name...........: _AD_DeleteMailbox ; Description ...: Delete's Mailbox from a User ; Syntax.........: _AD_DeleteMailbox($sAD_Object) ; Parameters ....: $sAD_Object - Username ; Return values .: 0 (Failed) or 1 (Worked) ; Author ........: Ethan Turk ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _AD_DeleteMailbox($sAD_Object) If Not _AD_ObjectExists($sAD_Object) Then Return SetError(1, 0, 0) Local $sAD_Property = "sAMAccountName" If StringMid($sAD_Object, 3, 1) = "=" Then $sAD_Property = "distinguishedName"; FQDN provided Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sAD_Property & "=" & $sAD_Object & ");ADsPath;subtree" Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query) ; Retrieve the FQDN for the object Local $sAD_LDAPEntry = $oAD_RecordSet.fields(0).value Local $oAD_Object = _AD_ObjGet($sAD_LDAPEntry) ; Retrieve the COM Object for the object If $oAD_Object.HomeMDB = "" Then Return 0 $oAD_Object.DeleteMailbox $oAD_Object.SetInfo $oAD_Object = 0 Return 1 EndFunc ; #Function#==================================================================================================================== ; Name...........: _AD_MailEnableGroup ; Description ...: Enables Mail for a Group ; Syntax.........: _AD_MailEnableGroup($sAD_Object) ; Parameters ....: $sAD_Object - Username ; Return values .: 0 (Failed) or 1 (Worked) ; Author ........: Ethan Turk ; Modified.......: ; Remarks .......: ; Related .......: ; Link ..........: ; Example .......: ; =============================================================================================================================== Func _AD_MailEnableGroup($sAD_Object) If Not _AD_ObjectExists($sAD_Object) Then Return SetError(1, 0, 0) Local $sAD_Property = "sAMAccountName" If StringMid($sAD_Object, 3, 1) = "=" Then $sAD_Property = "distinguishedName"; FQDN provided Local $sAD_Query = "<LDAP://" & $sAD_HostServer & "/" & $sAD_DNSDomain & ">;(" & $sAD_Property & "=" & $sAD_Object & ");ADsPath;subtree" Local $oAD_RecordSet = $oAD_Connection.Execute($sAD_Query) ; Retrieve the FQDN for the object Local $sAD_LDAPEntry = $oAD_RecordSet.fields(0).value Local $oAD_Object = _AD_ObjGet($sAD_LDAPEntry) ; Retrieve the COM Object for the object $oAD_Object.MailEnable $oAD_Object.Put("internetEncoding",1310720) $oAD_Object.SetInfo $oAD_Object = 0 Return 1 EndFunc Edited March 9, 2010 by eternally1027
water Posted March 9, 2010 Author Posted March 9, 2010 Hi Ethan, thanks for the functions! I will incorporate them in the next version. My goal is to create a single UDF that contains all Active Directory related functions. Some of the functions contained in adfunctions.au3 are still missing (mail related). As soon as I find some spare time and understand what the functions do I will move them to the AD UDF. What functions do you think are still missing in the AD UDF (except the functions you've sent me)? My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
eternally1027 Posted March 9, 2010 Posted March 9, 2010 Water, As far as I can see, the current list is pretty much complete (at least for what I use). I just upgraded to your update and it seems that all of my existing scripts are working correctly. It looks great. I just used your API to integrate the AD UDF into SciTE. Perfect. Great work. I see this helping a lot of people. Also, thanks to Johnathan Clelland for writing this UDF in the beginning. Ethan
Fire Posted March 9, 2010 Posted March 9, 2010 Fantastic Job!Thanks very much water. [size="5"] [/size]
gcue Posted March 10, 2010 Posted March 10, 2010 (edited) i am getting a strange error (dr watson type): autoit3.exe has encountered a problem and needs to close. we are sorry for the inconvenience... happens almost everytime when i pull one specific account and a few times on others BUT if i leave the msgbox in between both queries i never get the error. so i figured i should put in a sleep in place of the msgbox to avoid the error? but that didnt work. any ideas? expandcollapse popup_AD_Open() $groups = _AD_GetUserGroups($initials) If @error Then MsgBox(0, "", "cant find user") Exit EndIf _ArraySort($groups) MsgBox(0,"","") $password_info = _AD_GetPasswordInfo($initials) If Not @error Then $password_expires = _DateTimeFormat($password_info[9], 0) EndIf $object_properties = _AD_GetObjectProperties($initials) If Not @error Then For $x = 1 To UBound($object_properties) - 1 If $object_properties[$x][0] = "givenName" Then $first_name = $object_properties[$x][1] ContinueLoop EndIf If $object_properties[$x][0] = "sn" Then $last_name = $object_properties[$x][1] ContinueLoop EndIf If $object_properties[$x][0] = "displayName" Then $display_name = $object_properties[$x][1] ContinueLoop EndIf If $object_properties[$x][0] = "company" Then $company = $object_properties[$x][1] ContinueLoop EndIf If $object_properties[$x][0] = "department" Then $department = $object_properties[$x][1] ContinueLoop EndIf If $object_properties[$x][0] = "physicalDeliveryOfficeName" Then $office = $object_properties[$x][1] ContinueLoop EndIf If $object_properties[$x][0] = "lastLogon" Then $last_logon = _DateTimeFormat($object_properties[$x][1], 0) ContinueLoop EndIf If $object_properties[$x][0] = "pwdLastSet" Then $password_last_set = _DateTimeFormat($object_properties[$x][1], 0) ContinueLoop EndIf If $object_properties[$x][0] = "accountExpires" Then If $object_properties[$x][1] = "1600/12/31 16:00:00" Then $account_expires = "Never" ContinueLoop Else $account_expires = _DateTimeFormat($object_properties[$x][1], 0) ContinueLoop EndIf EndIf Next EndIf _AD_Close() Edited March 10, 2010 by gcue
water Posted March 10, 2010 Author Posted March 10, 2010 Hi gcue, could you please run your program with#AutoIt3Wrapper_Run_Debug_Mode=yinserted at the beginning? So we might see where it aborts and if it always happens at the same instruction. My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
gcue Posted March 10, 2010 Posted March 10, 2010 (edited) bah now i cant get it to crash.. grrrr Edited March 10, 2010 by gcue
water Posted March 10, 2010 Author Posted March 10, 2010 I hope it stays that way My UDFs and Tutorials: Spoiler UDFs: Active Directory (NEW 2024-07-28 - Version 1.6.3.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 (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 Â
Recommended Posts