如何獲取特定用戶組內(nèi)的無效賬戶?
有時(shí)候,IT管理員可能會(huì)想清除某些服務(wù)器/計(jì)算機(jī)內(nèi)置管理員組里面的一些已失效的用戶,這些用戶可能曾經(jīng)被加入管理員組,但是由于離職或是其他原因,賬號(hào)已從AD注銷,而在這些用戶組內(nèi),他們的SID信息卻得以保留,就像是這樣:

像圖中的最后兩個(gè)用戶,S-1-5-21-1004336348-1220945662-1801674531-10174 和 6866,就是由于信息從AD獲取不到,而顯示為SID的。如何批量從服務(wù)器抓這樣的SID用戶出來呢?我們可以使用 PowerShell 腳本。
以下就是一個(gè)代碼示例,我將其做成了一個(gè)函數(shù) QueryNonExistentUsers, 大家可以用在很多實(shí)際的工作之中,而且稍加修改,可以完成多種多樣的任務(wù):
1 #Query Non-existent Users PowerShell Script Function by Eric Sheh 2 #Version 1.2 Build 20120626 3 4 Function QueryNonExistentUsers 5 { 6 Param 7 ( 8 [Parameter(Mandatory=$true,Position=0)][String]$Server, 9 [Parameter(Mandatory=$true,Position=1)][String]$UserGroup, 10 [Parameter(Mandatory=$false,Position=2)][Bool]$CountInstead = $False 11 # Example: QueryNonExistentUsers "hostname" "Administrators" $True OR QueryNonExistentUsers -Server "hostname" -UserGroup "Administrators" -CountInstead $True 12 # OR QueryNonExistentUsers "hostname" "Administrators" OR QueryNonExistentUsers -Server "hostname" -UserGroup "Administrators" 13 ) 14 Begin 15 { 16 $members=@() 17 } 18 Process 19 { 20 [adsi]$computer = "WinNT://" + $Server 21 $group = $computer.psbase.children | ?{$_.psbase.schemaclassname -eq 'group'} | ?{$_.Path -match $UserGroup} 22 23 foreach ($user in $group.Members()) 24 { 25 $usr_obj = New-Object PSObject 26 $usr_obj | Add-Member -MemberType NoteProperty -Name 'aDSPath' -Value $user.GetType().InvokeMember('aDSPath', 'GetProperty', $null, $user, $null) 27 $usr_obj | Add-Member -MemberType NoteProperty -Name 'Name' -Value $user.GetType().InvokeMember('Name', 'GetProperty', $null, $user, $null) 28 $path = $usr_obj.aDSPath.split('/') 29 30 if ($path.Count -eq 4) 31 { 32 $usr_obj | Add-Member -MemberType NoteProperty -Name 'Domain' -Value $path[2] 33 } 34 elseif ($path.Count -eq 5) 35 { 36 $usr_obj | Add-Member -MemberType NoteProperty -Name 'Domain' -Value $path[3] 37 } 38 else 39 { 40 $usr_obj | Add-Member -MemberType NoteProperty -Name 'Domain' -Value 'Unknown' 41 } 42 $members += $usr_obj 43 } 44 45 $members = @($members | Sort-Object -Property Domain, Name) 46 $members = $members | Where-Object {$_.Domain -eq "Unknown"} 47 } 48 End 49 { 50 If ($CountInstead) 51 { 52 return $members.count 53 } 54 else 55 { 56 return $members 57 } 58 } 59 }
我們可以寫兩行code來調(diào)用這個(gè)函數(shù)進(jìn)行測(cè)試(例如連接到 TestServer,查詢其上的內(nèi)建 Administrators 組里面有沒有無效用戶):
1 #Test: 2 $Result = QueryNonExistentUsers "TestServer" "Administrators" 3 Write-Output $Result
可以看見執(zhí)行結(jié)果與上面的第一張 UI 查詢結(jié)果圖是一致的:

最后我解釋一下幾個(gè)要點(diǎn):
1. 使用 ADSI 比使用 WMI 的運(yùn)行效率高;
2. 使用 ADSI 時(shí),操作本地對(duì)象用"WinNT://",而操作AD對(duì)象,請(qǐng)使用"LDAP://";
3. 獲得代碼中定義的 $user 對(duì)象后,為何要用"/"符號(hào)分段呢?有時(shí)怎么確定 Domain 的呢?其實(shí)是利用了 Members 對(duì)象里 aDSPath 屬性值的一些特性的:
例如對(duì)于本地用戶,aDSPath 的值是這樣:
即"WinNT://DomainName/HostName/LocalUserName"的形式,所以依"/"拆分后,形成了一個(gè)一維數(shù)組,共有5個(gè)元素,其中第二元素為空。因此要取第四個(gè)元素"HostName"作為該賬戶的"域"(因?yàn)檫@是個(gè)本地賬戶)。
而對(duì)于域賬戶,aDSPath 的值是這樣的:
即"WinNT://DomainName/DomainUserName"的形式。因此拆分后形成一維數(shù)組只有四個(gè)元素,因此要取第三個(gè)元素作為該賬戶的域名稱。
而對(duì)于已失效的用戶,結(jié)果是這樣的:
所以我們?nèi)藶樘幚硭?Domain 值為"Unknown"并寫入結(jié)果中。
對(duì)了,這個(gè)函數(shù)的參數(shù)和使用方法在以上的代碼中其實(shí)已有說明,這里再單獨(dú)列舉一下:
QueryNonExistentUsers "hostname" "groupname" $true/$false
第一個(gè)參數(shù) hostname 自然是你要查詢的那臺(tái)機(jī)器的名稱了,第二個(gè)參數(shù)是你要查詢的用戶組,而第三個(gè)參數(shù)可以省略,默認(rèn)是為 $false 的,返回具體的組內(nèi)全部用戶,而如果你指定為 $true, 那么返回的只是一個(gè)計(jì)數(shù)值。例如上面的例子中,如果執(zhí)行"$Result = QueryNonExistentUsers "TestServer" "Administrators" $true",那么返回結(jié)果是數(shù)字2.
如果您要得到返回的完整組內(nèi)用戶列表,請(qǐng)將代碼中的"$members = $members | Where-Object {$_.Domain -eq "Unknown"}"去掉(在第46行),這里有這一句就是為了在結(jié)果中篩出失效賬戶。
佘華煜 (Eric Sheh),微軟 MVP,致力于為微軟 Windows 和 Office 用戶及 IT 專業(yè)人士提供更好的幫助與支持。 關(guān)注我的 新浪微博,加入 我要做電腦達(dá)人 微群,收聽每日 Office 效率提升秘籍~

浙公網(wǎng)安備 33010602011771號(hào)