获取域组时出错:句柄无效 - PowerShell

时间:2016-04-25 19:03:35

标签: .net powershell active-directory

编辑:Get-ADGroupMember问题。见截图。 我不属于该域名,但我可以执行其他查询,例如Get-ADGroup enter image description here

我被指派从域中的所有计算机获取所有本地管理(和嵌套)信息。我修改了一个我发现获得嵌套组成员身份的PowerShell脚本(使用adsi)。我有很多电脑(23,000),我让它继续运行......

问题是现在我收到以下错误: Handle is invalid problem

如果我对其中一台计算机(或所有计算机)运行我的脚本,它就可以了!所以,我猜测它可能是输出太多了吗?

我如何调试此错误? 此错误的含义是什么?

脚本输出到屏幕的一切。我将它导出到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"

0 个答案:

没有答案