编辑:Get-ADGroupMember问题。见截图。 我不属于该域名,但我可以执行其他查询,例如Get-ADGroup
我被指派从域中的所有计算机获取所有本地管理(和嵌套)信息。我修改了一个我发现获得嵌套组成员身份的PowerShell脚本(使用adsi)。我有很多电脑(23,000),我让它继续运行......
如果我对其中一台计算机(或所有计算机)运行我的脚本,它就可以了!所以,我猜测它可能是输出太多了吗?
我如何调试此错误? 此错误的含义是什么?
脚本输出到屏幕的一切。我将它导出到csv文件。我不确定为什么句柄“无效”。我在互联网上做过研究,我找到了this,但不确定我是否应该把它们搞得一团糟......
请帮忙。
为清楚起见,这是我的剧本:
# List local group members on the local or a remote computer
Function Get-LocalGroup
{
[Cmdletbinding()]
Param(
[Parameter(ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
[String[]]$Computers = $env:COMPUTERNAME,
[parameter()]
[string]$Group = "Administrators",
[parameter()]
[int]$Depth = ([int]::MaxValue),
[parameter()]
[switch]$allcomputers
)
function WriteError-ToFile ($stream,$comp,$error)
{
$comp = [string] $comp
$error = [string] $error
$comp = $comp -replace '`t|`n|`r|"',''
$error = [string] $er -replace '`t|`n|`r|"',''
$er = $comp,$error -join ','
$stream.WriteLine($er)
}
function Report-Member ($computer,[bool]$online=$true,$name,$domain,$parentGroup,$isGroup,$depth)
{
$member = New-Object PSObject
$member | Add-Member -MemberType NoteProperty -Name "Computer" -Value $computer
$member | Add-Member -MemberType NoteProperty -Name "Online" -Value $online
$member | Add-Member -MemberType NoteProperty -Name "Name" -Value $name
$member | Add-Member -MemberType NoteProperty -Name "Domain" -Value $domain
$member | Add-Member -MemberType NoteProperty -Name "ParentGroup" -Value $parentGroup
$member | Add-Member -MemberType NoteProperty -Name "isGroup" -Value $isGroup
$member | Add-Member -MemberType NoteProperty -Name "Type" -Value $type
$member | Add-Member -MemberType NoteProperty -Name "Depth" -Value $depth
return $member
}
Function Get-DomainGroupMember
{
[cmdletbinding()]
Param (
[parameter()]
$DomainGroup,
[parameter()]
[string]$NTName,
[parameter()]
[string]$blnNT,
[parameter()]
$Domain_and_Group
# [parameter()]
# $Domain
)
Try
{
# if the group is in first level (from local) retrieve group.
# if the group is from other domain, then also need to translate
If ($blnNT -eq $True)
{
# Convert NetBIOS domain name of group to Distinguished Name.
$objNT.InvokeMember("Set", "InvokeMethod", $Null, $objTrans, (3,"$Domain_and_Group")) | Out-Null
$DN = $objNT.InvokeMember("Get", "InvokeMethod", $Null, $objTrans, 1)
$ADGroup = [ADSI]"LDAP://$DN"
}
Else
{
$DN = $DomainGroup.distinguishedName
$ADGroup = $DomainGroup
}
$Counter++
$newblnNT = $false
# for each member of the group:
ForEach ($MemberDN In $ADGroup.Member)
{
# get the member with ADSI
$MemberGroup = [ADSI]("LDAP://{0}" -f ($MemberDN -replace '/','\/'))
# set fresh variables for each iteration.
# retrieve also the domain, we may need to change it to the original one
$SAM = $MemberGroup.Name[0]
$oldDomain = $Domain
$translated = $false
$found = $false
# if the string Name of the acccountlooks like an SID, it means that
# is a foreign user external forest. try to get the user or group account
if ($SAM -like "S-*-*-*")
{
# Write-Host $MemberDN
# try to translate to get Domain\SamAccountName
try
{
$objSID = New-Object System.Security.Principal.SecurityIdentifier ($SAM)
$objUser = ($objSID.Translate( [System.Security.Principal.NTAccount])).Value
$tmp = ([string] $objUser).split('\')
$SAM = $tmp[1]
$Domain = $tmp[0]
$translated = $true
}
catch
{
Write-Warning "Cannot translate foreign object $SAM - including SID in report with isGroup False"
$Domain = $oldDomain
WriteError-ToFile $stream $Computer "$SAM not translated"
}
if($translated)
{
# it is translated, try to get the boject in the specified domain
# $objUser = ([string] $objUser).replace('\','/')
# Write-Host $SAM $Domain $MemberGroup.class
#Get-ADGroup $SAM -server $Domain
# $objNT.InvokeMember("Set", "InvokeMethod", $Null, $objTrans, (3,$objUser)) | Out-Null
# $DN = $objNT.InvokeMember("Get", "InvokeMethod", $Null, $objTrans, 1)
try
{ # $DN = $objNT.InvokeMember("Get", "InvokeMethod", $Null, $objTrans, 1)
$obj = Get-ADObject -Filter {SamAccountName -eq $SAM} -server $Domain -Properties SamAccountName
if ($obj)
{
$SAM = $obj.SamAccountName
$isGroup = ($obj.ObjectClass -eq "group")
# Write-Host $obj.DistinguishedName $obj.Name $obj.ObjectClass
# Write-Host "`n"
$found = $true
# tengo la info, no necesita ser tranlated verdad?? si tengo q translate
#$newblnNT = $true
}
else
{
Write-Warning "Cannot Found foreign object $SAM in Domain $Domain - including it in report with isGroup False"
$Domain = $oldDomain
#$found = $true
WriteError-ToFile $stream $Computer "$SAM not found in $Domain"
}
}
catch
{
Write-Warning "Cannot Found foreign object $SAM in Domain $Domain - Error contacting the domain. Including it in report with isGroup False"
$Domain = $oldDomain
}
} # end if translated
}
# not an SID - just get the SamAccountName
else
{
$SAM=$MemberGroup.SamAccountName[0]
}
# not found - verify if the member is a group
if (-not $found){$isGroup = ($MemberGroup.Class -eq "group") }
# report the user to the screen (stdout)
Report-Member -computer $Computer -online $true -name $SAM -domain $Domain -parentGroup $NTName `
-isGroup $isGroup -type 'Domain' -depth $Counter
# Check if this member is a group.
if ($isGroup)
{
$GroupwithDomain = $Domain + "\" + $SAM
If ($Counter -lt $Depth)
{
If ($Groups[$SAM] -notcontains $GroupwithDomain)
{
Write-Verbose ("{0}: Getting domain group members" -f $SAM)
$Groups[$SAM] += ,$GroupwithDomain
# Enumerate members of domain group.
if (-not $found)
{
Get-DomainGroupMember $MemberGroup $SAM $newblnNT $GroupwithDomain
}
# Sid case, SAM of resolved Sid needs translation
else
{
Get-DomainGroupMember $obj $SAM $true $GroupwithDomain
}
}
}
}
# it does not matter if it is a user or group account -
# set the domain to the oldDomain so that you can correctly verify accounts
$Domain = $oldDomain
} # end for
} # end try
Catch
{
Write-Warning("Error getting domain group {0}" -f $_.Exception.Message)
}
}
Function Get-LocalGroupMember
{
[cmdletbinding()]
Param (
[parameter()]
[System.DirectoryServices.DirectoryEntry]$LocalGroup
)
# Invoke the Members method and convert to an array of member objects.
$Members= @($LocalGroup.psbase.Invoke("Members"))
# Add counter depth
$Counter++
ForEach ($Member In $Members)
{
Try
{
# get Ads Path
$Path = $Member.GetType().InvokeMember("ADsPath", 'GetProperty', $Null, $Member, $Null)
# Retrieve user name and domain
$tmp = $Path.split('/',[StringSplitOptions]::RemoveEmptyEntries)
$Name = $tmp[-1]
$Domain = $tmp[-2]
# Check if this member is a group.
$isGroup = ($Member.GetType().InvokeMember("Class", 'GetProperty', $Null, $Member, $Null) -eq "group")
# verify if the user is domain or local
If ($domain -eq $Computer) { $Type = 'Local'}
# The account is NT Authority local account - pseudo groups.
# psuedo groups do not have "members", so say that is not a group.
elseif($domain -eq 'NT AUTHORITY')
{
$Type = 'Local'
$isGroup = $false
}
# then the format means that is a domain account
Else {$Type = 'Domain'}
# report the user with information
Report-Member -computer $Computer -online $true -name $Name -domain $Domain -parentGroup ($LocalGroup.Name[0]) `
-isGroup $isGroup -type $Type -depth $Counter
if($domain -eq 'NT AUTHORITY') {$Type = 'Local'}
If ($isGroup)
{
# Check if this group is local or domain.
Write-Verbose ("Checking if Counter: {0} is less than Depth: {1}" -f $Counter, $Depth)
If ($Counter -lt $Depth)
{
If ($Type -eq 'Local')
{
# Verify that there are no circular groups
# because this verifies the same machine, only add Local to the hash
If ($Groups[$Name] -notcontains 'Local')
{
Write-Verbose ("{0}: Getting local group members" -f $Name)
$Groups[$Name] += ,'Local'
# Enumerate members of local group.
Get-LocalGroupMember $Member
}
Else
{
Write-Verbose ("{0}: Circular group, skip" -f $Name)
}
}
Else
{ # Verify that there are no circular groups
# build string to retrieve account from correct domain
$DomainwithGroup = $Domain + '\' + $Name
If ($Groups[$Name] -notcontains $DomainwithGroup)
{
Write-Verbose ("{0}: Getting domain group members" -f $Name)
$Groups[$Name] += ,$DomainwithGroup
# Enumerate members of domain group.
Get-DomainGroupMember $Member $Name $True $DomainwithGroup
}
Else
{
Write-Verbose ("{0}: Circular Domain group, skip" -f $Name)
}
}
}
Else
{
Write-Warning("Max depth reached: {0}" -f $Depth)
}
}
}
Catch
{
Write-Warning(("Error getting local group {0}. Savinf to error file" -f $_.Exception.Message))
WriteError-ToFile $stream $Computer $_.Exception.Message
}
}
}
Write-Verbose "on begin"
# Retrieve Distinguished Name of current domain.
$Domain = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$Root = $Domain.GetDirectoryEntry()
$Base = ($Root.distinguishedName)
# Use the NameTranslate object.
$global:objTrans = New-Object -comObject "NameTranslate"
$global:objNT = $objTrans.GetType()
# Initialize NameTranslate by locating the Global Catalog.
$objNT.InvokeMember("Init", "InvokeMethod", $Null, $objTrans, (3, $Null)) | Out-Null
$objNT.InvokeMember("Set", "InvokeMethod", $Null, $objTrans, (1, "$Base")) | Out-Null
$date = (Get-Date).ToString("MMM_dd_yyyy_hh-mm-sstt")
$output_file = [string]$pwd + "\" + $date + "_errorFinal.csv"
$stream = [System.IO.StreamWriter] $output_file
$headers = "Computer,Error"
$stream.WriteLine($headers)
Import-Module ActiveDirectory
if ($allcomputers)
{
$Computers = Get-ADComputer -Filter '*' | select -expand Name
Write-Host "Retrieved all computers from the domain. Total:" $Computers.Length
}
$count = 0
foreach ($Computer in $Computers)
{
$count++
try
{
if (-not (Test-Connection -ComputerName $Computer -BufferSize 16 -Count 1 -Quiet -ErrorAction Stop))
{
Write-Host "$count - $Computer is offline. Proceeding with next computer" -ForegroundColor "red"
Report-Member -computer $Computer -online $false
continue
}
}
catch
{
Write-Warning "Cannot ping $Computer, saving to error file"
WriteError-ToFile $stream $Computer "Cannot ping"
continue
}
Write-Host "$count - Working on $Computer" -ForegroundColor "green"
try
{
if([ADSI]::Exists("WinNT://$Computer/$Group,group"))
{
$adsi_group = [ADSI]("WinNT://$Computer/$Group,group")
$Counter = 0
$global:Groups = @{}
$Groups[$Group] += ,'Local'
$Domain = "MLIDDOMAIN1"
Get-LocalGroupMember $adsi_group
}
else
{
Write-Warning "Local group $Group doesn't exist on computer $Computer. `n Saving to error file"
WriteError-ToFile $stream $Computer "$Group group not found"
}
}
catch
{
$er = ([string] $_.Exception.Message).replace("`n","")
Write-Warning ("{0} `n Saving to error to file" -f $er)
#$er = $er.split(':')[-1]
WriteError-ToFile $stream $Computer $er
}
}
$stream.close()
}
Get-LocalGroup -Group Administrators -allComputers | Export-CSV "admin.csv"