Войти

Показать полную графическую версию : objUser.AccountDisabled - не разберусь с этим атрибутом


AlexWhite
20-03-2022, 12:49
Всем добрый день!

По наследству в организации, где работаю досталась настройка создания пользователей в AD (ws2019) из 1С через скрипт. Скрипт помещен в "Планировщик заданий" на DC и стартует каждые 30 мин.
Сам знакомлюсь с vbs только одну неделю) Насколько я разобрался, логика скрипта такая: скрипт парсит некий xml от вэб-сервера 1С на предмет поиска поля "Login" учетки и поступает следующими способами:
1. Если в xml есть логин учетки, которой нет в AD, то создает ее в OU=Users
2. Если в xml нет логина учетки, которая есть в AD, то отключает ее, в каком бы OU она не находилась при условии, что эта учетка не находится в группе безопасности "dontoff".
3. Если в xml нет логина учетки, которая есть в AD, то игнорирует ее, в каком бы OU она не находилась при условии, что эта учетка находится в группе безопасности "dontoff".
Работа скрипта логируется в "Журнале Приложений Windows DC". Если я не ошибаюсь, то сам скрипт "затыкается" в самом низу в блоке

objUser.AccountDisabled = True
Const ADS_UF_SCRIPT = &H1
Const ADS_UF_ACCOUNTDISABLE = &H2
Const ADS_UF_HOMEDIR_REQUIRED = &H8
Const ADS_UF_LOCKOUT = &H10
Const ADS_UF_PASSWD_NOTREQD = &H20
Const ADS_UF_PASSWD_CANT_CHANGE = &H40
Const ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = &H80
Const ADS_UF_TEMP_DUPLICATE_ACCOUNT = &H100
Const ADS_UF_NORMAL_ACCOUNT = &H200
Const ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = &H800
Const ADS_UF_WORKSTATION_TRUST_ACCOUNT = &H1000
Const ADS_UF_SERVER_TRUST_ACCOUNT = &H2000
Const ADS_UF_DONT_EXPIRE_PASSWD = &H10000
Const ADS_UF_MNS_LOGON_ACCOUNT = &H20000
Const ADS_UF_SMARTCARD_REQUIRED = &H40000
Const ADS_UF_TRUSTED_FOR_DELEGATION = &H80000
Const ADS_UF_NOT_DELEGATED = &H100000
Const ADS_UF_USE_DES_KEY_ONLY = &H200000
Const ADS_UF_DONT_REQUIRE_PREAUTH = &H400000
Const ADS_UF_PASSWORD_EXPIRED = &H800000
Const ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = &H1000000

Sub recursive(objUnit, objDict)
itemExists = False
For Each objMember in objUnit
If InStr(1, objMember.objectCategory, "CN=Person", vbTextCompare) > 0 Then
itemExists = objDict.Exists(objMember.sAMAccountName)
If itemExists = False Then
objDict.Add objMember.sAMAccountName, objMember.distinguishedName
End If
Else
recursive objMember, objDict
End If
Next
End Sub

On Error Resume Next

Set objShell = CreateObject("WScript.Shell")
objShell.LogEvent 0, "Script started"

Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.CompareMode = vbTextCompare

' Bind to the rootDSE object.
Set objRootDSE = GetObject("LDAP://rootDSE")
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error getting rootDSE: " & Err.Number & " - " & Err.Description
WScript.Quit
End If

' Bind to the root container in the domain.
Set objUsers = GetObject("LDAP://" & objRootDSE.Get("defaultNamingContext"))
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error getting root container: " & Err.Number & " - " & Err.Description
WScript.Quit
End If

recursive objUsers, objDictionary





Set xmlHttp = CreateObject("MSXML2.ServerXMLHTTP")
xmlHttp.SetOption(2) = (xmlHttp.GetOption(2) - SXH_SERVER_CERT_IGNORE_ALL_SERVER_ERRORS)
xmlHttp.Open "GET", "https://1c.contora.ru/Person", False, "login", "password"
xmlHttp.send ("")

If Not xmlHttp.status = 200 Then
objShell.LogEvent 1, "Error receiving xml: " & xmlHttp.status & " - " & xmlHttp.statusText
WScrit.Quit
End If





Set xmlParser = CreateObject("MSXML2.DOMDocument")
xmlParser.async = False
xmlParser.loadXML(xmlHttp.responseText)
Set xmlHttp = Nothing

If xmlParser.parseError.errorCode Then
objShell.LogEvent 1, "Error parsing xml: " & xmlParser.parseError.errorCode & " - " & xmlParser.parseError.reason
WScript.Quit
End If





' Bind to the Users folder in the domain.
Set objUsers = GetObject("LDAP://CN=Users," & objRootDSE.Get("defaultNamingContext"))
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error getting Users container: " & Err.Number & " - " & Err.Description
WScript.Quit
End If

Set nodes = xmlParser.getElementsByTagName("Person")
For Each node In nodes
Do

strLogin = Trim(node.getAttribute("Login"))
If IsNull(strLogin) Or Len(strLogin) = 0 Then
Exit Do
End If

Set objUser = Nothing
If objDictionary.Exists(strLogin) Then
Set objUser = GetObject("LDAP://" & objDictionary(strLogin))
objDictionary.Remove(strLogin)
End If

strFullName = Trim(node.getAttribute("FullName"))
If IsNull(strFullName) Or Len(strFullName) = 0 Then
Exit Do
End If

IsNewUser = False

If objUser Is Nothing Then
Err.Clear
Set objUser = objUsers.Create("user", "CN=" & strFullName)
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error creating user" & strLogin & ": " & Err.Number & " - " & Err.Description
Exit Do
End If
IsNewUser = True
Else
objShell.LogEvent 0, "Found user " & strLogin
End If

strFirstName = Trim(node.getAttribute("FirstName"))
If IsNull(strFirstName) Then
strFirstName = ""
End If

strMiddleName = Trim(node.getAttribute("MiddleName"))
If IsNull(strMiddleName) Then
strMiddleName = ""
End If

strLastName = Trim(node.getAttribute("LastName"))
If IsNull(strLastName) Then
strLastName = ""
End If

Err.Clear
objUser.sAMAccountName = strLogin
objUser.displayName = strFullName
objUser.givenName = strFirstName
objUser.initials = Left(strMiddleName, 1)
objUser.sn = strLastName
objUser.userPrincipalName = strLogin & "@contora.ru"

objUser.SetInfo
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error commiting user " & strLogin & ": " & Err.Number & " - " & Err.Description
Exit Do
End If

If Not IsNewUser Then
Exit Do
End If

objShell.LogEvent 1, "Setting password for user " & strLogin
Err.Clear
objUser.SetPassword "Qq12345"
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error setting password for user " & strLogin & ": " & Err.Number & " - " & Err.Description
Exit Do
End If

Err.Clear
objUser.pwdLastSet = 0
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error setting pwdLastSet for user " & strLogin & ": " & Err.Number & " - " & Err.Description
Exit Do
End If

Err.Clear
userActCtrl = objUser.Get("userAccountControl")
userActCtrl = userActCtrl And Not (ADS_UF_ACCOUNTDISABLE + ADS_UF_PASSWD_NOTREQD + ADS_UF_DONT_EXPIRE_PASSWD)
objUser.userAccountControl = userActCtrl
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error setting userAccountControlfor user " & strLogin & ": " & Err.Number & " - " & Err.Description
Exit Do
End If

Err.Clear
objUser.SetInfo
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error second commiting user " & strLogin & ": " & Err.Number & " - " & Err.Description
Exit Do
End If

Loop While False
Next
Set xmlParser = Nothing





Err.Clear
Set objDontOff = GetObject("LDAP://CN=dontoff,CN=Users," & objRootDSE.Get("defaultNamingContext"))
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error getting dontoff container: " & Err.Number & " - " & Err.Description
WScript.Quit
End If

For Each objMember In objDontOff.members
If objDictionary.Exists(objMember.sAMAccountName) Then
objDictionary.Remove(objMember.sAMAccountName)
End If
Next





For Each strLogin In objDictionary
Do

Set objUser = Nothing
Set objUser = GetObject("LDAP://" & objDictionary(strLogin))

If IsNull(objUser) Or objUser Is Nothing Then
Exit Do
ElseIf InStr(1, objUser.memberOf, "CN=dontoff,CN=Users", vbTextCompare) > 0 Then
Exit Do
End If

Err.Clear
objUser.AccountDisabled = True
objUser.SetInfo
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error disabling user " & strLogin & ": " & Err.Number & " - " & Err.Description
Exit Do
Else
objShell.LogEvent 0, "Disabled user " & strLogin
End If

Loop While False
Next





objShell.LogEvent 0, "Script finished"

с ошибкой в "Журнале Приложений Windows DC"
Error disabling user : -2147463155 - Свойства службы каталогов не могут быть найдены в кэше.
Собственно и вопрос) В скрипте есть строка 236: objUser.AccountDisabled = True, которая как-то должна отсылаться на атрибуты пользователя, чья учетка проверяется на предмет отключена она или нет. Понимаю, что наверно вопрос больше по AD, но тем не менее, правильно ли задан данный атрибут при условии, что строка 242: objShell.LogEvent 0, "Disabled user " в "Журнале Приложений Windows DC" логируется правильно как
Disabled user Ivanov
Те проблема в каком-то пользователе, где останавливается скрипт с ошибкой или это неверный параметр AccountDisabled, которого в явном виде нет в атрибутах пользователя?

Спасибо заранее!

Sham
20-03-2022, 14:22
strLogin пустой что-ли (должен быть в тексте ошибки перед двоеточием)? Может быть надо проверять, что не пустой в начале итерации по objDictionary?

AlexWhite
20-03-2022, 15:01
strLogin пустой что-ли (должен быть в тексте ошибки перед двоеточием)?

Да, пустой. Нет логина на котором останавливается скрипт.

Может быть надо проверять, что не пустой в начале итерации по objDictionary?

Учетку же нельзя создать без логина.

Sham
20-03-2022, 18:05
Ключ в словаре objDictionary это атрибут sAMAccountName. Словарь заполняется в recursive(), где objDict.Add. Этот атрибут sAMAccountName видимо где-то пустой. Можно добавить "objDictionary(strLogin)" в строку лога, чтобы понять, какая строка запроса LDAP://... приводит к ошибке. Это где objShell.LogEvent 1, "Error disabling user " & strLogin &.... ну как-нибудь .... & "LDAP://" & objDictionary(strLogin) (& - конкатенация строк).

AlexWhite
20-03-2022, 20:06
ну как-нибудь .... & "LDAP://" & objDictionary(strLogin) (& - конкатенация строк).

спасибо большое за совет, теперь вижу "проблемное место". Последний блок поправил и получилось так.

Err.Clear
objUser.AccountDisabled = True
objUser.SetInfo
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error disabling user " & "LDAP://" & objDictionary(strLogin) & strLogin & ": " & Err.Number & " - " & Err.Description
Exit Do
Else
objShell.LogEvent 0, "Disabled user " & strLogin
End If


Error disabling user LDAP://CN=Склад,OU=Завод,OU=Контора,DC=ad,DC=contora,DC=ru: -2147463155 - Свойства службы каталогов не могут быть найдены в кэше.

Склад - это оказался контакт, у которого нет логина. Поэтому и была ошибка.

Sham, не подскажите как сделать так, чтобы скрипт игнорировал контакты?

Sham
21-03-2022, 03:09
Сейчас добавляется в словарь по наличию подстроки "CN=Person" в objMember.objectCategory. Видимо, можно попробовать добавить дополнительную проверку к itemExists = False ещё and objMember.objectClass = "user". Проверить не могу.

AlexWhite
26-03-2022, 21:42
Сейчас добавляется в словарь по наличию подстроки "CN=Person" в objMember.objectCategory. Видимо, можно попробовать добавить дополнительную проверку к itemExists = False ещё and objMember.objectClass = "user". Проверить не могу. »

Сделал, получилось так

Sub recursive(objUnit, objDict)
itemExists = False
For Each objMember in objUnit
If InStr(1, objMember.objectCategory, "CN=Person", vbTextCompare) > 0 Then
itemExists = objDict.Exists(objMember.sAMAccountName)
If itemExists = False and objMember.objectClass = "user" Then
objDict.Add objMember.sAMAccountName, objMember.distinguishedName
End If
Else
recursive objMember, objDict
End If
Next
End Sub

Получаю ошибку

Error getting Users container: 13 - Несоответствие типа

Наверно надо что-то еще тут менять

' Bind to the Users folder in the domain.
Set objUsers = GetObject("LDAP://CN=Users," & objRootDSE.Get("defaultNamingContext"))
If (Err.Number <> 0) Then
objShell.LogEvent 1, "Error getting Users container: " & Err.Number & " - " & Err.Description
WScript.Quit
End If

или я неправильно добавил условие and objMember.objectClass = "user"

Sham
28-03-2022, 01:30
Error getting Users container: 13 - Несоответствие типа »
это видимо Err.Number не 0 остался после "несоответствия типа", и там неверная строка ошибки получается. Какой тип в objectClass?

я бы вывел в консоль, что добавляется в словарь (там где objDict.Add), к примеру: WScript.Echo objMember.sAMAccountName, objMember.distinguishedName, objMember.objectClass
там видны будут критерии. Может и другие атрибуты есть помимо objectClass.

кстати, ошибкаWScrit.Quit » WScript




© OSzone.net 2001-2012