toasterking Posted October 11, 2017 Share Posted October 11, 2017 (edited) There does not seem to be a function in the UDF to delete objects that have children (leaf nodes). We have a security product in our organization that inserts child objects into computer containers, which makes it impossible to delete the computers from Active Directory using the _AD_DeleteObject function in this UDF, which calls the "Delete" method. To make this work, you have to call the "DeleteObject" method, which seems to use different semantics. I implemented it here: expandcollapse popup; #FUNCTION# ==================================================================================================================== ; Name...........: _AD_DeleteObjectWithChildren ; Description ...: Deletes the specified object. Works on objects with children (leaf nodes) and without children. ; Syntax.........: _AD_DeleteObject($sObject) ; Parameters ....: $sObject - Object (user, group, computer etc.) to delete (FQDN or sAMAccountName) ; Return values .: Success - 1 ; Failure - 0, sets @error to: ; |1 - $sObject does not exist ; |x - Error returned by Delete function (Missing permission etc.) ; Author ........: toasterking (partially based on _AD_DeleteObject() by Jonathan Clelland; modified by water) ; Modified.......: ; Remarks .......: ; Related .......: _AD_DeleteObject, _AD_RenameObject, _AD_MoveObject ; Link ..........: https://msdn.microsoft.com/en-us/library/aa705994(v=vs.85).aspx ; Example .......: No ; =============================================================================================================================== Func _AD_DeleteObjectWithChildren($sObject) If Not _AD_ObjectExists($sObject) Then Return SetError(1, 0, 0) If StringMid($sObject, 3, 1) <> "=" Then $sObject = _AD_SamAccountNameToFQDN($sObject) ; sAMAccountName provided Local $oAdBind = $__oAD_OpenDS.OpenDSObject("LDAP://" & $sObject, $sADAdminUser, $sADAdminPassword, $__bAD_BindFlags) If @error Or Not IsObj($__oAD_Bind) Then ; login error occurred - get extended information Local $iError = @error Local $sHive = "HKLM" If @OSArch = "IA64" Or @OSArch = "X64" Then $sHive = "HKLM64" Local $sOSVersion = RegRead($sHive & "\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "CurrentVersion") $sOSVersion = StringSplit($sOSVersion, ".") If Int($sOSVersion[1]) >= 6 Then ; Delivers detailed error information for Windows Vista and later if debugging is activated Local $aErrors = _AD_GetLastADSIError() If $aErrors[4] <> 0 Then If $__iAD_Debug = 1 Then ConsoleWrite("_AD_Open: " & _ArrayToString($aErrors, @CRLF, 1) & @CRLF) If $__iAD_Debug = 2 Then MsgBox(64, "Active Directory Functions - Debug Info - _AD_Open", _ArrayToString($aErrors, @CRLF, 1)) If $__iAD_Debug = 3 Then FileWrite($__sAD_DebugFile, @YEAR & "." & @MON & "." & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC & " " & @CRLF & _ "-------------------" & @CRLF & "_AD_Open: " & _ArrayToString($aErrors, @CRLF, 1) & @CRLF & _ "========================================================" & @CRLF) Return SetError(Dec($aErrors[4]), 0, 0) EndIf Return SetError(8, $iError, 0) Else Return SetError(8, $iError, 0) EndIf EndIf Local $vResult = $oAdBind.DeleteObject(0) ;This actually does the magic of deleting an object that has children. Method takes a single parameter and only 0 is valid. If @error Then Return SetError(@error,666,0) Return 1 EndFunc Edit: And by "implemented", I mean I found code that Jonathan Clelland and water wrote and monkeyed it until it worked for me, as I'm standing on the shoulders of giants here. Edited October 11, 2017 by toasterking Clarifying my unworthiness Link to comment Share on other sites More sharing options...
water Posted October 12, 2017 Author Share Posted October 12, 2017 (edited) Thanks for this function I'm thinking about to extend the UDF with a function to delete objects plus leaf nodes and OUs including all contained objects/leafs/subOUs. This function will be based upon your function plus the ideas I found here: http://www.selfadsi.org/delete.htm What do you (and others) think? Is such a function needed? If yes, is anyone willing to test on a test system? I'm an ordinary user so only have read access to our AD Please click the "Like this" button in the lower right corner of this post. So I know how many of you would like to see this function implemented. Edited October 12, 2017 by water argumentum, nikink and AdamUL 3 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 Link to comment Share on other sites More sharing options...
toasterking Posted October 12, 2017 Share Posted October 12, 2017 Personally, the function I posted is all I have needed beyond the many already included with your UDF. But what you suggested might be useful to others. Unfortunately, the only Active Directory installation I have access to at the moment is my employer's production system, which I cannot use for testing. I first started down the path of enumerating every child object and deleting it, then deleting the parent, but found that some objects are more difficult to enumerate and reference, and I probably just didn't know enough about what I was doing. I couldn't get the DeleteObject method working at first, but it got a lot easier once I figured out how to bind directly to the object I wanted to delete using the right credentials. Thank you for continuing to maintain this UDF. It has really helped us out! Link to comment Share on other sites More sharing options...
water Posted October 13, 2017 Author Share Posted October 13, 2017 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 Link to comment Share on other sites More sharing options...
water Posted October 16, 2017 Author Share Posted October 16, 2017 (edited) _AD_DeleteSubtree: Allows to delete an object and all children of the object as described in post #101 delete an OU including all objects and child OUs. delete all objects in an OU and all child OUs but leave the OUs intact. Means the tree remains unchanged but all contained objects get deleted (clears the tree) The example does not delete any objects. It just writes a tree of processed objects to the SciTE console and adds a prefix whether the object will be deleted or remains unchanged. To make it run modify line #9 marked with "<=== MODIFY". What do you think? Is anyone able to test the function on a test system? So that a bug does not cause any harm? Spoiler expandcollapse popup#include <AD.au3> Global $sBlank = " " ; 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) ; Delete Subtree Global $sReturn = _AD_DeleteSubtree("OU=XX,DC=XX,DC=XX") ; <=== MODIFY If @error Then Exit MsgBox(16, "Active Directory Example Skript", "Function _AD_DeleteSubtree encountered a problem. @error = " & @error & ", @extended = " & @extended & ", return value = " & $sReturn) ; Close Connection to the Active Directory _AD_Close() Exit ; #FUNCTION# ==================================================================================================================== ; Name...........: _AD_DeleteSubtree ; Description ...: Deletes the specified object including all leafs of this object. ; Syntax.........: _AD_DeleteSubtree($sObject[, $iFlag = 0]) ; Parameters ....: $sObject - Object (user, group, computer, OU etc.) to delete (FQDN or sAMAccountName) ; $iFlag - [optional] Specifies how to process leaf objects. Can be: ; | 0 - Delete the object, all containedOUs and objects ; | 1 - Only delete contained objects. The object and all contained OUs remain active. Means: The subtree will be cleared. ; Return values .: Success - 1 ; Failure - The distinguishedName of the object raising the error, sets @error to: ; |1 - $sObject does not exist ; |2 - Error returned by DeleteObject method for an object (Missing permission etc.). @extended holds the COM error code. ; |3 - Error returned by DeleteObject method for an OU (Missing permission etc.). @extended holds the COM error code. ; Author ........: water ; Modified.......: ; Remarks .......: ; Related .......: _AD_RenameObject, _AD_MoveObject, _AD_DeleteObject ; Link ..........: ; Example .......: Yes ; =============================================================================================================================== Func _AD_DeleteSubtree($sObject, $iFlag = 0, $iRecursion = 0) ; Only check the object provided by the user (performance reasons). Values: 0 = first call by user, 1 = recursive call If $iRecursion = 0 Then If Not _AD_ObjectExists($sObject) Then Return SetError(1, 0, $sObject) If StringMid($sObject, 3, 1) <> "=" Then $sObject = _AD_SamAccountNameToFQDN($sObject) ; sAMAccountName provided EndIf Local $oObject = __AD_ObjGet("LDAP://" & $sAD_HostServer & "/" & $sObject) Local $sClass = $oObject.Class If $sClass = "organizationalUnit" Then If $iFlag = 1 Then ConsoleWrite("REMAINS: " & StringLeft($sBlank, $iRecursion * 2) & $sObject & @CRLF) Else ConsoleWrite("DELETED: " & StringLeft($sBlank, $iRecursion * 2) & $sObject & @CRLF) EndIf For $oChild In $oObject _AD_DeleteSubtree($oChild.distinguishedName, $iFlag, $iRecursion + 1) If @error Then Return SetError(@error, @extended, $sObject) Next If $iFlag <> 1 Then ; OUs will not get deleted when $iFlag = 1 (clear subtree) ;~ TESTING: $oObject.DeleteObject(0) If @error Then Return SetError(3, @error, $sObject) EndIf Else ConsoleWrite("DELETED: " & StringLeft($sBlank, $iRecursion * 2) & $sObject & @CRLF) ; Objects will always be deleted ;~ TESTING: $oObject.DeleteObject(0) If @error Then Return SetError(2, @error, $sObject) EndIf Return 1 EndFunc ;==>_AD_DeleteSubtree Edited October 16, 2017 by water toasterking 1 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 Link to comment Share on other sites More sharing options...
mr84 Posted January 15, 2018 Share Posted January 15, 2018 Hi, im just wondering why this will not work? If it has a mail it returns the mail adress, but if its empty, it just writes ERROR in console: $oObject.Get($sAttribute) $oObject^ ERROR Here is the code: #include <AD.au3> _AD_Open() $ADmail = _AD_GetObjectAttribute(@username, "mail") ConsoleWrite($ADmail) _AD_Close() If $ADmail == "" Then MsgBox(64, "Warning", "Mail attribute is missing") Link to comment Share on other sites More sharing options...
water Posted January 15, 2018 Author Share Posted January 15, 2018 Which version of AutoIt do you run? Which version of the AD UDF do you run? 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 Link to comment Share on other sites More sharing options...
mr84 Posted January 16, 2018 Share Posted January 16, 2018 19 hours ago, water said: Which version of AutoIt do you run? Which version of the AD UDF do you run? SciTE Version 3.7.3 I tought i was on the latest AD UDF, but now i updated to 1.4.8.0 and its working. Thank you. Link to comment Share on other sites More sharing options...
water Posted January 16, 2018 Author Share Posted January 16, 2018 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 Link to comment Share on other sites More sharing options...
Ivo Posted February 1, 2018 Share Posted February 1, 2018 (edited) Hi Water I am using your ad.au3 a lot and it works fantastic. Today I got an error when I read the object properties from an AD user. error message: Array variable has incorrect number of subscripts or subscript dimension range exceeded. For $vPropertyValue In $oPropertyEntry.Values $iPropertyRecord = $iPropertyRecord + 1 $aObjectProperties[$iPropertyRecord][0] = $sPropertyName This peace of code is locate in your ad.au3 file. Function: Func _AD_GetObjectProperties($vObject = @UserName, $sProperties = "", $bSort = True) Local $aObjectProperties[1000][2], $oObject It works fine after increasing the array declaration to: Local $aObjectProperties[2000][2]. Br. Ivo Edited February 1, 2018 by Ivo Ivo Link to comment Share on other sites More sharing options...
water Posted February 1, 2018 Author Share Posted February 1, 2018 So there is an object with > 1000 properties. Seems that I need to brush up the function for a variable number of properties 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 Link to comment Share on other sites More sharing options...
water Posted February 2, 2018 Author Share Posted February 2, 2018 Next release will hold up to 10000 properties. That was the simplest solution 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 Link to comment Share on other sites More sharing options...
DFWITGuy Posted February 4, 2018 Share Posted February 4, 2018 (edited) I apologize if this has been addressed before and I've searched the forum for _AD_GetObjectAttribute and _AD_GetObjectProperties but I'm coming up with nothing. If i run Get-ADUser theuser -Properties * | Select * in PowerShell, I get a full list of all properties for the user "theuser", including custom properties like OtherName . If I run _AD_GetObjectProperties for that same user, I do not see the custom property OtherName listed. As such, I get errors or empty results when trying to use _AD_GetObjectAttribute or _AD_GetObjectProperties to return the data stored in OtherName. Is there something I'm missing as far as a setting to have _AD_GetObjectAttribute and _AD_GetObjectProperties return info on custom properties in AD? Thanks. ETA - Solved my own problem. User error! The properties that I thought were custom seem to be duplicates of existing properties. When I made a change to what I'm calling the master property, the secondary property changed as well. Edited February 6, 2018 by DFWITGuy Link to comment Share on other sites More sharing options...
water Posted February 4, 2018 Author Share Posted February 4, 2018 Never had to cope with custom properties before. Can you make sure that a LDAP query returns the custom properties? Something like: dsquery * -Filter "(&(objectCategory=person)(objectClass=User)(cn=theuser))" -Attr YourCustomProperty 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 Link to comment Share on other sites More sharing options...
DFWITGuy Posted February 4, 2018 Share Posted February 4, 2018 (edited) Thank you for asking, water. I'm getting expected results from the OtherName property when I run the following: dsquery * "user's distinguished name" -scope base -attr sAMAccountName OtherName sAMAccountName shows JDoe and OtherName shows Jane as expected. Ran dsquery * "user's distinguished name" -attr * to see what all is displayed and OtherName appears in the list. ETA - Solved my own problem. User error! Edited February 6, 2018 by DFWITGuy pasted wrong word Link to comment Share on other sites More sharing options...
DonChunior Posted February 5, 2018 Share Posted February 5, 2018 By using the function _AD_GetObjectProperties I can get the email address, if I know the username. But is it somehow possible to get the username, if I know the email address? Link to comment Share on other sites More sharing options...
water Posted February 5, 2018 Author Share Posted February 5, 2018 Sure. Use _AD_GetObjectsInOU. DonChunior 1 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 Link to comment Share on other sites More sharing options...
DonChunior Posted February 5, 2018 Share Posted February 5, 2018 15 minutes ago, water said: Sure. Use _AD_GetObjectsInOU. Thanks a lot for the tip! _AD_GetObjectsInOU("", "(mail=EmailAddressToSearchFor)") did the job. Link to comment Share on other sites More sharing options...
water Posted February 5, 2018 Author Share Posted February 5, 2018 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 Link to comment Share on other sites More sharing options...
water Posted February 5, 2018 Author Share Posted February 5, 2018 "mail" is the address to use when sending mails. "proxyaddresses" gives additional information about SMTP and X400 addresses. 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 Link to comment Share on other sites More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now