none
Удаление "Неизвестных" учетных записей с помощью сценария RRS feed

  • Вопрос

  • Всем привет!

    Прошу помочь в написании небольшого сценария по удалению "Неизвестных" профилей на RDP серверах. Интересует удаление исключительно Неизвестных" профилей.

    Даже не знаю, где начать поиск, прошу помочь.

    Спасибо.

    13 марта 2015 г. 9:17

Ответы

Все ответы

  • и в чем конкретно у вас вопрос?

    Неизвестным он считается если не может отрезолвить SID в имя. Это может происходить изза того что пользователь удален или отсутствует домен контроллер каторый сможет разрешить сид в имя.

    13 марта 2015 г. 9:53
  • https://helgeklein.com/free-tools/delprof2-user-profile-deletion-tool/
    • Предложено в качестве ответа Vector BCOModerator 13 марта 2015 г. 11:46
    • Помечено в качестве ответа KazunEditor 17 марта 2015 г. 6:04
    13 марта 2015 г. 10:45
  • Спасибо за ответы.

    Задачка немного перенеслась по срокам. Как протестирую, дам обратную связь.

    17 марта 2015 г. 6:07
  • Вариант сценария на VBS:
    Option Explicit
    
    Dim objFS, objShell, objFolder, objFile, objWShell, objWMI
    Dim strTranslator, strLogFile, strComputer, strTargetPath
    Dim objDict, objRegExp, arrTemp, intNumArgs, strKey, strTemp, i
    Dim blnIsConsole, blnRecursive, blnCreateLog, blnSilent, blnAvailable, blnHasError
    
    strComputer = "."
    blnCreateLog = True: blnSilent = True: blnAvailable = True
    Set objFS = CreateObject("Scripting.FileSystemObject")
    strTranslator = objFS.GetBaseName(WScript.FullName)
    If StrComp(strTranslator, "cscript", vbTextCompare) = 0 Then blnIsConsole = True
    If blnIsConsole Then
    	arrTemp = Array("tc", "tlp", "r", "nl", "s")
    	Set objDict = CreateObject("Scripting.Dictionary")
    	objDict.CompareMode = 1
    	For i = 0 To UBound(arrTemp)
    		objDict.Add arrTemp(i), vbNullString
    	Next
    	'--- Проверка корректности набора заданных ключей, определение значений ключей
    	Set objRegExp = CreateObject("VBScript.RegExp")
    	objRegExp.Global = True
    	objRegExp.IgnoreCase = True
    	objRegExp.Pattern = "^[-/]"
    	intNumArgs = WScript.Arguments.Count
    	Select Case intNumArgs
    		Case 0: Call View_Help: WScript.Quit 0
    		Case 1
    			strTemp = objRegExp.Replace(WScript.Arguments.Item(0), "")
    			If strTemp = "?" Then
    				Call View_Help: WScript.Quit 0
    			Else
    				If Len(strTemp) > 1 Then
    					If LCase(Left(strTemp, 4)) <> "tlp:" Then
    						Call Err_Message(1, strTemp)
    						WScript.Quit 0
    					Else
    						If Len(strTemp) > 4 Then
    							objDict.Item("tlp") = Mid(strTemp, 5)
    						Else
    							Call Err_Message(11, "tlp")
    							WScript.Quit 0
    						End If
    					End If
    				Else
    					Call Err_Message(1, Null)
    					WScript.Quit 0
    				End If
    			End If
    		Case Else
    			For Each strTemp In WScript.Arguments
    				arrTemp = Null
    				strTemp = objRegExp.Replace(strTemp, "")
    				If Len(strTemp) > 0 Then
    					If strTemp = "?" Then
    						Call Err_Message(2, strTemp)
    						WScript.Quit 0
    					Else
    						i = InStr(strTemp, ":")
    						If i > 0 Then
    							strKey = Left(strTemp, i - 1)
    							If strKey = "tlp" Or strKey = "tc" Then
    								arrTemp = Split(strTemp, strKey & ":", -1, vbTextCompare)
    								If Len(arrTemp(1)) = 0 Then
    									Call Err_Message(11, strKey)
    									WScript.Quit 0
    								End If
    							Else
    								Call Err_Message(10, strKey)
    								WScript.Quit 0
    							End If
    						Else
    							If strTemp <> "tlp" And strTemp <> "tc" Then
    								strKey = strTemp
    							Else
    								Call Err_Message(11, strTemp)
    								WScript.Quit 0
    							End If
    						End If
    						If objDict.Exists(strKey) Then
    							If Len(objDict.Item(strKey)) = 0 Then
    								If IsArray(arrTemp) Then
    									objDict.Item(strKey) = arrTemp(1)
    								Else
    									objDict.Item(strKey) = "+"
    								End If
    							Else
    								Call Err_Message(4, strKey)
    								WScript.Quit 0
    							End If
    						Else
    							Call Err_Message(3, strKey)
    							WScript.Quit 0
    						End If
    					End If
    				Else
    					Call Err_Message(3, strTemp)
    					WScript.Quit 0
    				End If
    			Next
    	End Select
    	'------
    	'--- Проверка корректности заданных значений ключей
    	For Each strTemp In objDict.Keys
    		Select Case LCase(strTemp)
    			Case "tc": If Len(objDict.Item(strTemp)) > 0 Then strComputer = objDict.Item(strTemp)
    			Case "tlp"
    				If Len(objDict.Item(strTemp)) > 0 Then
    					strTargetPath = Trim(objDict.Item(strTemp))
    					If Len(strTargetPath) >= 3 Then
    						strTargetPath = Replace(strTargetPath, "/", "\")
    						objRegExp.Pattern = "\\{2,}"
    						strTargetPath = objRegExp.Replace(strTargetPath, "\\")
    						objRegExp.Pattern = "^""|""$"
    						strTargetPath = objRegExp.Replace(strTargetPath, "")
    						objRegExp.Pattern = "^[c-z]:\\$"
    						If objRegExp.Test(Left(strTargetPath, 3)) Then
    							If Len(strTargetPath) > 3 Then
    								objRegExp.Pattern = "[<>:""\*\?\|]"
    								If objRegExp.Test(Mid(strTargetPath, 4)) Then
    									Call Err_Message(9, strTemp)
    									WScript.Quit 0
    								End If
    								objRegExp.Pattern = "\\$"
    								strTargetPath = objRegExp.Replace(strTargetPath, "")
    							End If
    							If strComputer = "." Then
    								strTemp = strTargetPath
    							Else
    								strTemp = "\\" & strComputer & "\" & Left(strTargetPath, 1) & "$" & _
    											Mid(strTargetPath, 3)
    							End If
    							If Not objFS.FolderExists(strTemp) Then
    								Call Err_Message(8, strTemp)
    								WScript.Quit 0
    							End If
    						Else
    							Call Err_Message(9, strTemp)
    							WScript.Quit 0
    						End If
    					Else
    						Call Err_Message(9, strTemp)
    						WScript.Quit 0
    					End If
    				Else
    					Call Err_Message(5, "tlp")
    					WScript.Quit 0
    				End If
    			Case "r": If Len(objDict.Item(strTemp)) > 0 Then blnRecursive = True
    			Case "nl": If Len(objDict.Item(strTemp)) > 0 Then blnCreateLog = False
    			Case "s": If Len(objDict.Item(strTemp)) = 0 Then blnSilent = False
    		End Select
    	Next
    	Set objRegExp = Nothing
    Else
    	Set objShell = CreateObject("Shell.Application")
    	Set objFolder = objShell.BrowseForFolder(0, "Выбор каталога", &h10 + &h200, &h11)
    	If objFolder Is Nothing Then
    		WScript.Quit 0
    	Else
    		strTargetPath = objFolder.Self.Path
    		If MsgBox("Выполнять рекурсивный просмотр папок?", vbYesNo + vbQuestion, "Очистка DACL") = vbYes Then
    			blnRecursive = True
    		End If
    	End If
    	Set objShell = Nothing
    End If
    If blnIsConsole And strComputer <> "." Then
    	blnAvailable = Available(strComputer)
    	strTargetPath = "\\" & strComputer & "\" & Left(strTargetPath, 1) & "$" & Mid(strTargetPath, 3)
    End If
    If blnAvailable Then
    	If blnCreateLog Then
    		strLogFile = objFS.BuildPath(objFS.GetParentFolderName(WScript.ScriptFullName), "Clear_DACL.log")
    		Set objFile = objFS.OpenTextFile(strLogFile, 2, True)
    		'objFile.WriteLine Now & vbNewLine
    	Else
    		Set objFile = Nothing
    	End If
    	On Error Resume Next
    	strTemp = objFS.GetDrive(objFS.GetDriveName(strTargetPath)).FileSystem
    	If Err.Number <> 0 Then
    		strTemp = vbNullString
    		Err.Clear
    	End If
    	If UCase(strTemp) = "NTFS" Then
    		Set objWMI = GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
    		If Err.Number = 0 Then
    			Set objFolder = objFS.GetFolder(strTargetPath)
    			If Err.Number = 0 Then
    				Call Clear_DACL(objWMI, objFolder, objFile, blnRecursive, blnIsConsole, blnSilent)
    				If Not blnSilent Then WScript.Echo "Обработка папки " & UCase(strTargetPath) & " завершена."
    			Else
    				blnHasError = True
    				Call Err_Message(7, "Ошибка "  & Err.Number & " при подключении к папке " & UCase(strTargetPath) & _
    								vbNewLine & Err.Description)
    				Err.Clear
    			End If
    		Else
    			blnHasError = True
    			Call Err_Message(7, "Ошибка " & Err.Number & " при подключении к WMI-пространству станции """ & _
    							UCase(strComputer) & """" & vbNewLine & Err.Description)
    			Err.Clear
    		End If
    		Set objWMI = Nothing
    	Else
    		If Len(strTemp) > 0 Then
    			If Not objFile Is Nothing Then
    				objFile.WriteLine "Объекты файловой системы " & UCase(strTemp) & " не имеют DACL."
    				objFile.Close
    			End If
    			If Not blnSilent Then WScript.Echo "Объекты файловой системы " & UCase(strTemp) & " не имеют DACL."
    		Else
    			blnHasError = True
    			Call Err_Message(7, "Не удалось определить тип файловой системы тома папки " & UCase(strTargetPath))
    		End If
    	End If
    	If Not objFile Is Nothing Then
    		objFile.Close
    		Set objFile = Nothing
    	End If
    	If blnCreateLog And Not blnIsConsole And Not blnHasError Then
    		Set objWShell = CreateObject("WScript.Shell")
    		objWShell.Run "notepad.exe " & strLogFile, 1
    		Set objWShell = Nothing
    	End If
    Else
    	Call Err_Message(6, strComputer & " не существует или недоступен.")
    End If
    Set objFS = Nothing
    WScript.Quit 0
    
    '======
    
    Function Clear_DACL(objWMIServ, objDir, objLog, blnRec, blnCon, blnSil)
    Dim objItem, objSecSettings, objSD, objACE, arrACE, strSID
    Dim strPath, strTemp, blnHasInherited, blnHasError, blnIsFound, intRes, i
    Const SE_DACL_PROTECTED = 4096 'Флаг-признак отключенного режима наследования управляемым каталогом
    							   'безопасности NTFS от "родителя"
    Const INHERITED_ACE = 16 'Флаг-признак того, что текущая запись DACL унаследована от "родителя"
    
    On Error Resume Next
    For Each objItem In objDir.SubFolders
    	blnHasError = False: blnIsFound = False: strSID = vbNullString
    	strPath = objItem.Path
    	If Err.Number = 0 Then
    		strTemp = strTemp & UCase(strPath) & vbNewLine
    		i = InStr(strPath, "$")
    		If i > 0 Then
    			strPath = Replace(Mid(strPath, i - 1), "$", ":")
    		End If
    		Set objSecSettings = objWMIServ.Get("Win32_LogicalFileSecuritySetting.Path='" & strPath & "'")
    		If Err.Number = 0 Then
    			If objSecSettings.GetSecurityDescriptor(objSD) = 0 Then
    				If Err.Number = 0 Then
    					intRes = 0
    					If Not IsNull(objSD.DACL) Then
    						For Each objACE In objSD.DACL
    							If IsNull(objACE.Trustee.Name) Then
    								blnIsFound = True
    								Exit For
    							End If
    						Next
    						If blnIsFound Then
    							If CBool(objSD.ControlFlags And SE_DACL_PROTECTED) Then
    								arrACE = objSD.DACL
    							Else
    								blnHasInherited = True
    								arrACE = Array()
    								i = -1
    								'--- Выборка из исходного DACL записей, не унаследованных от "родителя"
    								For Each objACE In objSD.DACL
    									If CBool(objACE.AceFlags And INHERITED_ACE) Then
    										If IsNull(objACE.Trustee.Name) Then
    											blnHasError = True
    											strTemp = strTemp & objACE.Trustee.SIDString & _
    														" -> запись унаследована от ""родителя""." & vbNewLine
    										End If
    									Else
    										i = i + 1
    										ReDim Preserve arrACE(i)
    										Set arrACE(i) = objACE
    									End If
    								Next
    								'------
    								'--- Отключение наследования настроек безопасности от "родителя"
    								objSD.ControlFlags = objSD.ControlFlags + SE_DACL_PROTECTED
    								intResult = objSecSettings.SetSecurityDescriptor(objSD)
    								'------
    							End If
    							If intRes = 0 Then
    								'--- Поиск в DACL записей, у свойства Trustee.Name которых отсутствует значение
    								For Each objACE In arrACE
    									If IsNull(objACE.Trustee.Name) Then
    										objACE.AccessMask = 0 'назначение нулевой маски для последующего автоудаления записи
    										strSID = strSID & objACE.Trustee.SIDString & " -> запись удалена." & vbNewLine
    									End If
    								Next
    								'------
    								Set objACE = Nothing
    								objSD.DACL = arrACE 'собственно изменение DACL
    								Erase arrACE
    								'--- Включение наследования настроек безопасности от "родителя",
    								'если первоначально оно было включено
    								If blnHasInherited Then
    									objSD.ControlFlags = objSD.ControlFlags - SE_DACL_PROTECTED
    								End If
    								'------
    								'--- Итоговое сохраненение изменений, внесённых в дескриптор безопасности
    								intRes = objSecSettings.SetSecurityDescriptor(objSD)
    								Select Case intRes
    									Case 0
    										strTemp = strTemp & strSID
    										If blnHasError Then
    											strTemp = strTemp & "Частично успешное завершение." & vbNewLine
    										Else
    											strTemp = strTemp & "Полностью успешное завершение." & vbNewLine
    										End If
    									Case 2: strTemp = strTemp & "Доступ запрещён." & vbNewLine
    									Case 5, 9, 1307: strTemp = strTemp & "Для выполнения операции недостаточно полномочий." & vbNewLine
    									Case 21: strTemp = strTemp & "Заданы недопустимые значения параметров." & vbNewLine
    									Case Else: strTemp = strTemp & "Неизвестная ошибка с кодом: " & intRes & vbNewLine
    								End Select
    								'------
    							Else
    								strTemp = strTemp & "Не удалось отключить наследование безопасности." & vbNewLine
    							End If
    						Else
    							strTemp = strTemp &  "Очистка DACL не требуется." & vbNewLine
    						End If
    					Else
    						strTemp = strTemp & "Список управления доступом пуст." & vbNewLine
    					End If
    				Else
    					strTemp = strTemp & "Ошибка " & Err.Number & " при выполнении метода GetSecurityDescriptor." & _
    								vbNewLine & Err.Description & vbNewLine
    					Err.Clear
    				End If
    			Else
    				strTemp = strTemp & "Не удалось прочитать дескриптор безопасности." & vbNewLine
    			End If
    		Else
    			strTemp = strTemp & "Ошибка " & Err.Number & " обращения к классу Win32_LogicalFileSecuritySetting " & _
    						"при обработке папки " & UCase(strPath) & vbNewLine
    			Err.Clear
    		End If
    	Else
    		blnHasError = True
    		strTemp = strTemp & "Ошибка " & Err.Number & " при попытке рекурсивного просмотра папки " & _
    					UCase(objDir.Path) & vbNewLine
    		Err.Clear
    	End If
    	Set objSD = Nothing
    	Set objSecSettings = Nothing
    	If Not objLog Is Nothing Then objLog.WriteLine strTemp
    	If blnCon And Not blnSil Then WScript.Echo strTemp
    	strTemp = vbNullString
    	If blnRec And Not blnHasError Then Call Clear_DACL(objWMIServ, objItem, objLog, blnRec, blnCon, blnSil)
    Next
    Set objItem = Nothing
    On Error GoTo 0
    End Function
    
    '======
    
    Function Available(strName)
    Dim objWShell, objExec, objOutStream, strTemp
    
    Set objWShell = CreateObject("WScript.Shell")
    Set objExec = objWShell.Exec("ping -n 1 -w 130 " & strName)
    Set objOutStream = objExec.StdOut
    While Not objOutStream.AtEndOfStream
    	strTemp = strTemp & Trim(objOutStream.ReadLine())
    Wend
    If InStr(1, strTemp, "TTL", vbTextCompare) > 0 Then
    	Available = True
    Else
    	Available = False
    End If
    End Function
    
    '======
    
    Function Err_Message(intNumber, strComment)
    Select Case intNumber
    	Case 1: WScript.Echo "Недопустимый ключ или набор ключей."
    	Case 2: WScript.Echo "Недопустимое сочетание ключа " & UCase(strComment) & " с другими ключами."
    	Case 3: WScript.Echo "Недопустимый ключ " & UCase(strComment)
    	Case 4: WScript.Echo "Дублирование ключа " & UCase(strComment)
    	Case 5: WScript.Echo "Ключ " & UCase(strComment) & " является обязательным."
    	Case 6: WScript.Echo "Компьютер " & UCase(strComment)
    	Case 7: WScript.Echo strComment
    	Case 8: WScript.Echo "Папка " & UCase(strComment) & " не найдена."
    	Case 9: WScript.Echo "Недопустимое значение ключа " & UCase(strComment)
    	Case 10: WScript.Echo "Ключ " & UCase(strComment) & " не требует указания значения."
    	Case 11: WScript.Echo "Ключ " & UCase(strComment) & " требует указания значения."
    	Case Else: WScript.Echo "Не классифицированная ошибка."
    End Select
    End Function
    
    '======
    
    Function View_Help()
    WScript.Echo "Сценарий предназначен для очистки DACL подпапок заданной папки" & vbNewLine & _
    			 "от не олицетворённых DACL-записей, оставшихся после удаления учётных записей" & vbNewLine & _
    			 "пользователей или групп, которым ранее соответствовали эти DACL-записи." & vbNewLine & _
    			 "Очистка выполняется без нарушения наследования настроект от ""родителя""." & vbNewLine & vbNewLine & _
    			 "Возможности сценария:" & vbNewLine & _
    			 "- обеспечение работы как в графическом, так и в консольном режимах;" & vbNewLine & _
    			 "- обеспечение работы с папками как локального, так и удалённого компьютера;" & vbNewLine & _
    			 "- поддержка рекурсивного просмотра подпапок (по умолчанию - отключена);" & vbNewLine & _
    			 "- ведение журнала работы (по умолчанию - включена);" & vbNewLine & _
    			 "- поддержка работы в ""молчаливом"" режиме (по умолчанию - отключена)." & vbNewLine & vbNewLine & _
    			 "При работе в ""молчаливом"" режиме не выводятся никакие сообщения сценария," & vbNewLine & _
    			 "кроме сообщений о ситуациях, приводящих к его аварийному завершению." & vbNewLine & _
    			 "Данный режим никак не влияет на процедуру ведения журнала." & vbNewLine & vbNewLine & _
    			 "При работе в графическом режиме функциональность сценария имеет ограничения:" & vbNewLine & _
    			 "- доступна обработка папок только на тех томах, которые подключены локально;" & vbNewLine & _
    			 "- невозможен просмотр встроенной справки;" & vbNewLine & _
    			 "- невозможно отключение процедуры ведения журнала;" & vbNewLine & _
    			 "- работа ведётся в ""молчаливом"" режиме, но после завершения работы выводится" & vbNewLine & _
    			 "  содержимое файла журнала." & vbNewLine & vbNewLine & _
    			 "Ключи командной строки:" & vbNewLine & _
    			 "?" & vbTab & vbTab & "- вывод справки; не совместим с другими ключами." & vbNewLine & _
    			 "tc:<компьютер>" & vbTab & "- (""Target Computer"") NetBIOS-имя компьютера, на локальном томе" & vbNewLine & _
    										vbTab & vbTab & "  которого размещена папка; необязательный;" & vbNewLine & _
    										vbTab & vbTab & "  по умолчанию предполагается текущий компьютер." & vbNewLine & _
    			 "tlp:<путь>" & vbTab & "- (""Target Local Path"") абсолютный локальный путь к папке;" & vbNewLine & _
    									vbTab & vbTab & "  обязательный." & vbNewLine & _
    			 "r" & vbTab & vbTab & "- (""Recursive"") рекурсивный просмотр подпапок; необязательный;" & vbNewLine & _
    								   vbTab & vbTab & "  по умолчанию не выпоняется." & vbNewLine & _
    			 "nl" & vbTab & vbTab & "- (""No Log"") отключение ведения журнала; необязательный;" & vbNewLine & _
    									vbTab & vbTab & "  по умолчанию журнал ведётся." & vbNewLine & _
    			 "s" & vbTab & vbTab & "- (""Silent"") ""молчаливый"" режим; необязательный;" & vbNewLine & _
    								   vbTab & vbTab & "  по умолчанию отключен." & vbNewLine & vbNewLine & _
    			"Ключ может иметь перед собой один из префиксов: ""-"" или ""/"". Порядок следования ключей произвольный."
    End Function


    17 марта 2015 г. 21:52
  • Всем привет!

    Написал небольшую проверку наличия профиля на сервере. Но она работает только для одной учётной записи. Правда написано коряво, но все же.

    $ListProfileForRemove = (Get-ADUser –Identity i.zhukov | foreach { $_.SamAccountName}).ToString()
    foreach ($ListUsersForRemove in $ListProfileForRemove)
    {
        $testPathGrapes = Test-Path "\\grapes\c$\Users\$ListProfileForRemove"
            If ($testPathGrapes -eq $True) {
            Write-Host "На сервере GRAPES удалены файлы профиля"
            }
            Else {
            Write-Host "На сервера GRAPES удаление файлов профиля не требуется"
            }
    }

    Как написать алогичную проверку для нескольких учетных записей пользователей заданных в переменной?


    8 апреля 2015 г. 18:03