Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   objUser.AccountDisabled - не разберусь с этим атрибутом (http://forum.oszone.net/showthread.php?t=350906)

AlexWhite 20-03-2022 12:49 2982017

objUser.AccountDisabled - не разберусь с этим атрибутом
 
Всем добрый день!

По наследству в организации, где работаю досталась настройка создания пользователей в 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 2982024

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

AlexWhite 20-03-2022 15:01 2982028

Вложений: 1
Цитата:

strLogin пустой что-ли (должен быть в тексте ошибки перед двоеточием)?
Да, пустой. Нет логина на котором останавливается скрипт.

Цитата:

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

Sham 20-03-2022 18:05 2982036

Ключ в словаре 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 2982039

Цитата:

ну как-нибудь .... & "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 2982050

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

AlexWhite 26-03-2022 21:42 2982315

Цитата:

Цитата Sham
Сейчас добавляется в словарь по наличию подстроки "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 2982343

Цитата:

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

это видимо Err.Number не 0 остался после "несоответствия типа", и там неверная строка ошибки получается. Какой тип в objectClass?

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

кстати, ошибка
Цитата:

Цитата AlexWhite
WScrit.Quit »

WScript


Время: 22:05.

Время: 22:05.
© OSzone.net 2001-