/build/static/layout/Breadcrumb_cap_w.png

REMOVE DISABLE USERS From AD Groups

hello all

I am struggling to find a decent way to do this. We have a lot of users who are disabled but are still a member of all of their pre-disable groups. This is causing a few issues such as distribution list failures, difficulty enumerating ACL's etc.

Does anyone know of an easy way to bulk remove groups from users that are disabled?  For ease, they all exist in one container. then export to a csv file all the users group that go disabled, anybody already using such powershell script will be willing to share.

any help would be greatly appreciated.

thanks

alex 

0 Comments   [ + ] Show comments

Answers (2)

Posted by: anonymous_9363 9 years ago
Red Belt
0

I don't have a PS script but I do have a QAD VBScript. It shouldn't be beyond the wit of Man to convert. It looks for computer and user accounts but that behaviour is easy to change by editing the filter applied in the query:

Users only

strCommandText    = strCommandText & "&(objectCategory=User)(samAccountType=805306368)" 
strCommandText    = strCommandText & "(userAccountControl:1.2.840.113556.1.4.803:=2)"

Machines only

strCommandText    = strCommandText & "&(objectCategory=Computer)(samAccountType=805306369)" 
strCommandText    = strCommandText & "(userAccountControl:1.2.840.113556.1.4.803:=2)"

'On Error Resume Next
Dim strYear
Dim strMonth
Dim strDay
Dim strDate

Const ADS_SCOPE_SUBTREE   = 2
Const ADS_PROPERTY_UPDATE   = 2
Const ADS_PROPERTY_APPEND   = 3
Const ADS_PROPERTY_DELETE   = 4
Const ADS_PAGE_SIZE   = 100
Const ADS_TIMEOUT   = 30

Const adUseClientBatch    = 3    '// Obsolete, same as adUseClient
Const adUseNone    = 1    '// Obsolete, no cursor service
Const adUseServer    = 2    '// Default, use the cursor supplied by provider or database
Const adUseClient    = 3    '// Use client-side cursor supplied by the local cursor library
Const adOpenStatic    = 3    '// Use static cursor

Dim strExcludeOUlist
Dim dtmTestDate

 '//------------------------------------------------------------------------------------------------------------//
 '// Force use of CScript
 '//------------------------------------------------------------------------------------------------------------//
 Call ForceCScriptExecution(True)

dtmTestDate     = #16/03/2012#  '// This is the date against which we're going to test.
        '// It needs to be in US format so 6/1/2011 is 1st June 2011

dtmTestDate     = DateAdd("d", -90, Date())

strExcludeOUList   = "Exchange"  '// Exclude any account with an OU which includes this text

Set objShell = CreateObject("Wscript.Shell")
lngBiasKey = objShell.RegRead("HKLM\System\CurrentControlSet\Control\TimeZoneInformation\ActiveTimeBias")
If (UCase(TypeName(lngBiasKey)) = "LONG") Then
 lngBias    = lngBiasKey
ElseIf (UCase(TypeName(lngBiasKey)) = "VARIANT()") Then
 lngBias = 0
 For intIndex = 0 To UBound(lngBiasKey)
  lngBias   = lngBias + (lngBiasKey(intIndex) * 256^intIndex)
 Next
End If
Set objShell     = Nothing

Set objRootDSE     = GetObject("LDAP://RootDSE")
strDNSDomain     = objRootDSE.Get("DefaultNamingContext")


Set objConnection    = CreateObject("ADODB.Connection")
Set objCommand     = CreateObject("ADODB.Command")
objConnection.Provider    = "ADsDSOObject"
objConnection.CursorLocation   = adUseClient

objConnection.Open "Active Directory Provider"
Set objCommand.ActiveConnection  = objConnection

With objCommand
 .Properties("SearchScope")  = ADS_SCOPE_SUBTREE
 .Properties("Page Size")  = ADS_PAGE_SIZE
 .Properties("Timeout")   = ADS_TIMEOUT
 .Properties("Cache Results")  = False
End With

strCommandText    = ""
strCommandText    = strCommandText & "<LDAP://" & strDNSDomain & ">"
strCommandText    = strCommandText & ";"
strCommandText    = strCommandText & "("

strCommandText    = strCommandText & "|(samAccountType=805306368)(samAccountType=805306369)"
strCommandText    = strCommandText & "(userAccountControl:1.2.840.113556.1.4.803:=2)"

 '// Include any user who DOES NOT have an Exchange account defined
 'strCommandText    = strCommandText & "(!homeMDB=*)"

 '// Include any user who has an Exchange account defined
 'strCommandText    = strCommandText & "(homeMDB=*)"

strCommandText    = strCommandText & ")"
strCommandText    = strCommandText & ";distinguishedName,sAMAccountName,Name,lastLogonTimeStamp;Subtree" 

'// Comma-delimited list of attribute values to retrieve
strAttributes     = "distinguishedName,lastLogonTimeStamp"

objCommand.CommandText    = strCommandText
Set objRecordSet    = objCommand.Execute

With objRecordSet
 .MoveFirst

 .Sort     = "Name asc"

 WScript.Echo "Total number: " & .RecordCount
 
 Do Until .EOF
  '// Retrieve attribute values for the user
  'strDN = .Fields("distinguishedName").Value

  '// Convert Integer8 value to date/time in current time zone
  On Error Resume Next

  dtmLastLogonDate = ConvertInteger8ToDate(.Fields("lastLogonTimeStamp").Value, lngBias)
  strName   = .Fields("Name").Value
  strsAMAccountName = .Fields("sAMAccountName").Value
  strdistinguishedName = .Fields("distinguishedName").Value
  
  '// The date needs to be in US format
  'If (dtmLastLogonDate < #4/1/2011#) Then
  If (dtmLastLogonDate < dtmTestDate) Then
   'Wscript.Echo strName
   'Wscript.Echo strsAMAccountName
   
   If InStr(strdistinguishedName, strExcludeOUList) = 0 Then
    'Wscript.Echo strsAMAccountName & "," & strdistinguishedName & ", Last logged on: " & dtmLastLogonDate
    'Wscript.Echo strsAMAccountName & "," & strdistinguishedName & "," & dtmLastLogonDate
    '// For display/data sorting purposes, we want this date in UK format
    strYear  = Year(dtmLastLogonDate)
    strMonth = Month(dtmLastLogonDate)
    strDay  = Day(dtmLastLogonDate)
    
    strDate  = strDay & "/" & strMonth & "/" & strYear
    Wscript.Echo strsAMAccountName & "|" & strdistinguishedName & "|" & strDate
   End If
  Else
   'Wscript.Echo strDN & ";" & dtmLastLogonDate
  End If

     .MoveNext
 Loop
End With

Function ConvertInteger8ToDate(ByVal objDate, ByVal lngBias)
 '// Function to convert Integer8 (64-bit) value to a date,
 '// adjusted for local time zone bias

 Dim lngAdjust
 Dim lngDate
 Dim lngHigh
 Dim lngLow

 lngAdjust    = lngBias
 lngHigh    = objDate.HighPart
 lngLow     = objDate.LowPart

 '// Account for bug in IADslargeInteger property methods
 If (lngLow < 0) Then
  lngHigh   = lngHigh + 1
 End If

 If (lngHigh = 0) And (lngLow = 0) Then
  lngAdjust   = 0
 End If

 lngDate    = #1/1/1601# + (((lngHigh * (2 ^ 32)) + lngLow) / 600000000 - lngAdjust) / 1440

 ConvertInteger8ToDate  = CDate(lngDate)
   
End Function

Sub ForceCScriptExecution(ByVal blnQuoteArguments)
 Dim objShellRun
 Dim strArgument
 Dim strArguments
 Dim strCmdLine
 Dim intIndex

 '// If running in CScript, do nothing
 If UCase(Right(WScript.FullName, 11)) = "CSCRIPT.EXE" Then
  Exit Sub
 End If

 If WScript.Arguments.Count > 0 Then
  strArguments  = ""
 
  For intIndex = 0 To (WScript.Arguments.Count - 1)
   If Len(strArguments) = 0 Then
    strArguments = WScript.Arguments(intIndex)
   Else
    strArguments = strArguments & " " & WScript.Arguments(intIndex)
   End If
  Next

  If blnQuoteArguments Then
   strArguments = Chr(34) & strArguments & Chr(34)
  End If
 End If

 '// If running in WScript, execute the script using CScript
 '// and then quit this script
 If UCase(Right(WScript.FullName, 11)) = "WSCRIPT.EXE" Then
  Set objShellRun   = CreateObject("WScript.Shell")
  'objShellRun.Run "CSCRIPT.EXE """ & WScript.ScriptFullName & """", 1, False
  
  strCmdLine   = "CSCRIPT.EXE "

  If InStr(WScript.ScriptFullName, " ") > 0 Then
   strCmdLine  = strCmdLine & Chr(34)
  End If
  
  strCmdLine   = strCmdLine & WScript.ScriptFullName

  If InStr(WScript.ScriptFullName, " ") > 0 Then
   strCmdLine  = strCmdLine & Chr(34)
  End If
  
  If Len(strArguments) > 0 Then
   strCmdLine  = strCmdLine & " "
   strCmdLine  = strCmdLine & strArguments
  End If
    
  objShellRun.Run strCmdLine, 1, False
  
  Set objShellRun   = Nothing
  WScript.Quit
 End If

 '// If script engine is anything else, quit with an error
 WScript.Echo "Unknown scripting engine."
 WScript.Quit
End Sub


Posted by: anonymous_9363 9 years ago
Red Belt
0

Finding group memberships is harder because you need to take account of nested memberships. Check out Mr Mueller's excellent VBSes. I have his code in scripts I use but it's surrounded by my "fluff" and would be hard to use straight out of the box, as it were.

EDIT:
Is there some reason that the scripts that one can find from Googling are of no use?!?

 
This website uses cookies. By continuing to use this site and/or clicking the "Accept" button you are providing consent Quest Software and its affiliates do NOT sell the Personal Data you provide to us either when you register on our websites or when you do business with us. For more information about our Privacy Policy and our data protection efforts, please visit GDPR-HQ