none
Beschreibung von AD-Gruppen kann nicht gelesen werden RRS feed

  • Frage

  • Hallo zusammen,

    ich habe ein Script geschrieben um alle Member (inkl. Beschreibung) einer lokalen Gruppe auszulesen. Die Beschreibung kommt auch einwandfrei mit bei Domain Accounts und Domain Groups, aber leider nur, wenn diese Universal sind. Die beiden entscheidenden Code-Schnipsel sind..

    $Group = [ADSI]"WinNT://$Computer/$LocalGroupName"
    $Members = @($Group.Invoke("Members"))
    $MemberName = $Member.GetType().InvokeMember("Name","GetProperty",$null,$Member,$null)
    $MemberType = $Member.GetType().InvokeMember("Class","GetProperty",$null,$Member,$null)
    $MemberDescription = $Member.GetType().InvokeMember("Description","GetProperty",$null,$Member,$null)
    $MemberPath = $Member.GetType().InvokeMember("ADSPath","GetProperty",$null,$Member,$null)
    

    Bei Domain Local Groups habe ich nun das Problem, dass die Beschreibung mit folgendem Fehler nicht ausgelesen werden kann:

    Exception calling "InvokeMember" with "5" argument(s): "The group name could not be found.
    "
    At line:108 char:33
    +                                 $MemberDescription = $Member.GetType().InvokeMem ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : COMException

    Alle anderen Eigenschaften (Name, Class, ADSPath) funktionieren. Stelle ich die Gruppe auf Universal um, funktioniert auch die Abfrage der Beschreibung sofort, ebenso wie bei Benutzern.

    Habt ihr dafür eine eine Erklärung und noch besser eine Lösung?

    Gruß,
    Michael

    Dienstag, 28. Oktober 2014 13:46

Antworten

  • Der WinNT: Provider ist ein Uhrgestein aus Windows NT Zeiten.
    Dieser unterstützt nur Sachen die auch schon unter Windows NT vorhanden waren.
    Die Universellen Gruppen sind das einzige was Windows NT und das Moderne AD gemeinsam haben.

    Um das moderne Active Directory abzufragen musst du den LDAP: Provider benutzen!

    Siehe Erklärung hier: WinNT vs. LDAP
    http://www.rlmueller.net/WinNT_LDAP.htm

    ungefähr so:

    $Group = [ADSI]"WinNT:////$Computer/$LocalGroupName"
    $Members = @($Group.Invoke("Members"))
    ForEach($Member in $Members) {
      
      $ADSPath = $Member.GetType().InvokeMember("ADSPath","GetProperty",$null,$Member,$null)
      $Name = $Member.GetType().InvokeMember("Name","GetProperty",$null,$Member,$null)
    
    
      # Abfragen ob es ein lokaler oder ein Member aus der Domäne ist
      If(-Not ($ADSPath -Like "*$($env:COMPUTERNAME)*")) {
        # Domänen Member!
        # LDAP Provider benutzen
        
        $AdsiSearcher = [AdsiSearcher]''   
        $AdsiSearcher.Filter = "(sAMAccountName=$Name)"
        $SearchResult = $AdsiSearcher.FindOne()
            
        $MemberName = $SearchResult.Properties.name
        $MemberDescription= $SearchResult.Properties.description
    
      } Else {
        # Lokaler Member!
    
        $MemberName = $Name
        $MemberDescription = $Member.GetType().InvokeMember("Description","GetProperty",$null,$Member,$null)
    
      }
    
      $MemberName
      $MemberDescription
    }



    PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
    auf der deutschsprachigen PowerShell Community

    Mein 21 Teiliger PowerShell Video Grundlehrgang
    Deutsche PowerShell Videos auf Youtube
    Folge mir auf:
    Twitter | Facebook | Google+

    • Bearbeitet Peter Kriegel Dienstag, 28. Oktober 2014 16:00
    • Als Antwort markiert mhedv Mittwoch, 29. Oktober 2014 09:08
    Dienstag, 28. Oktober 2014 14:58

Alle Antworten

  • Der WinNT: Provider ist ein Uhrgestein aus Windows NT Zeiten.
    Dieser unterstützt nur Sachen die auch schon unter Windows NT vorhanden waren.
    Die Universellen Gruppen sind das einzige was Windows NT und das Moderne AD gemeinsam haben.

    Um das moderne Active Directory abzufragen musst du den LDAP: Provider benutzen!

    Siehe Erklärung hier: WinNT vs. LDAP
    http://www.rlmueller.net/WinNT_LDAP.htm

    ungefähr so:

    $Group = [ADSI]"WinNT:////$Computer/$LocalGroupName"
    $Members = @($Group.Invoke("Members"))
    ForEach($Member in $Members) {
      
      $ADSPath = $Member.GetType().InvokeMember("ADSPath","GetProperty",$null,$Member,$null)
      $Name = $Member.GetType().InvokeMember("Name","GetProperty",$null,$Member,$null)
    
    
      # Abfragen ob es ein lokaler oder ein Member aus der Domäne ist
      If(-Not ($ADSPath -Like "*$($env:COMPUTERNAME)*")) {
        # Domänen Member!
        # LDAP Provider benutzen
        
        $AdsiSearcher = [AdsiSearcher]''   
        $AdsiSearcher.Filter = "(sAMAccountName=$Name)"
        $SearchResult = $AdsiSearcher.FindOne()
            
        $MemberName = $SearchResult.Properties.name
        $MemberDescription= $SearchResult.Properties.description
    
      } Else {
        # Lokaler Member!
    
        $MemberName = $Name
        $MemberDescription = $Member.GetType().InvokeMember("Description","GetProperty",$null,$Member,$null)
    
      }
    
      $MemberName
      $MemberDescription
    }



    PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
    auf der deutschsprachigen PowerShell Community

    Mein 21 Teiliger PowerShell Video Grundlehrgang
    Deutsche PowerShell Videos auf Youtube
    Folge mir auf:
    Twitter | Facebook | Google+

    • Bearbeitet Peter Kriegel Dienstag, 28. Oktober 2014 16:00
    • Als Antwort markiert mhedv Mittwoch, 29. Oktober 2014 09:08
    Dienstag, 28. Oktober 2014 14:58
  • Hallo Peter,

    vielen Dank für die Hilfe und die gute Erklärung, jetzt funktioniert die Abfrage wie sie soll! :)

    Gruß,
    Michael

    Mittwoch, 29. Oktober 2014 08:59
  • Hallo Michael !

    War mit meiner Antwort noch nicht zufrieden, weil in dem Beispiel mit dem [AdsiSearcher] nicht berücksichtigt wird, das man auch verschiedenen Domänen abfragen kann.

    Allgemein wird für den Umgang mit Lokalen Gruppen empfohlen NICHT den WinNT: Provider zu benutzen, weil der keine Active Directory Pfade unterstützt und es schwer ist, sauber an die Domänen Informationen eines Members zu kommen.

    Besser ist es WMI (CIM) für Lokale Gruppen zu benutzen.
    Ich habe meine eigen Funktion nochmal überarbeitet. Bitte nutze diese!

    Function Get-WMILocalGroupMembers {
    <#
    .Synopsis
       Function to get all members of a local group with WMI
    
    .DESCRIPTION
       Function to get all members of a local group with WMI
       To get all User members recursive use the -recurse switchparameter
       If you provide the -Computername Parameter the members of a local group on that system are retrieved
    
    .PARAMETER Name
        Name of the group to retrieve the members.
        The Name of the locale Administrators group is the default (The group name is retrived by SID of S-1-5-32-544)
    	
    .PARAMETER Domain
    	The Domain of the group
    	The default domain is the local Computer
    	
    .PARAMETER Recursive
    	Specifies to get all User members (non containers) in the hierarchy of a group. No container members (of type group) are returned!
    	
    .PARAMETER ComputerName
      Specifies the target computer for the management operation.
      The value can be a fully qualified domain name, a NetBIOS name, or an IP address.
      To specify the local computer, use the local computer name, use localhost, or use a dot (.) .
      This parameter does not rely on Windows PowerShell remoting, which uses WS-Management.
    	You can use the ComputerName parameter of Get-WmiObject even if your computer is not configured to run WS-Management remote commands.
    	To specify the local computer, such as in a list of computer names, use "localhost", the local computer name, or a dot (.).
    	The local computername is the default.
    		
    .EXAMPLE
    	Get-WMILocalGroupMembers
    	
    	Retrieves all members from the locale system and the locale Administrator group
    	
    .EXAMPLE
    	Get-WMILocalGroupMembers -Name -ComputerName 'Server1'
    	
    	Retrieves all members from the remote system 'Server1' and the locale Administrator group	
    	
    .EXAMPLE
    	Get-WMILocalGroupMembers -Name 'Remote Desktop Users'
    	
    	Retrieves all members from the locale system and the locale group with Name 'Remote Desktop Users'.
    	
    .EXAMPLE
    	Get-WMILocalGroupMembers -Name 'Remote Desktop Users' -Recurse
    	
    	Retrieves all User members recursive from the locale system and the locale group with Name 'Remote Desktop Users'.
    	
    .EXAMPLE
    	Get-WMILocalGroupMembers -Name -ComputerName 'Server1' -Name 'Remote Desktop Users'
    	
    	Retrieves all members from the remote system 'Server1' and the group with Name 'Remote Desktop Users' which is  a local group on 'Server1'.
    
    .EXAMPLE
    	Get-WMILocalGroupMembers -Name 'DomainAdmins' -Domain 'Avalon'
    	
    	Retrieves all members from the the group with Name 'DomainAdmins' from the Domain 'Avalon' (Avalon\DomainAdmins)
    	The local system is used to retrieve the members.	
    	
    .EXAMPLE
    	Get-WMILocalGroupMembers -ComputerName 'Server1' -Name 'DomainAdmins' -Domain 'Avalon'
    	
    	Retrieves all members from the the group with Name 'DomainAdmins' from the Domain 'Avalon' (Avalon\DomainAdmins)
    	The remote system 'Server1' is used to retrieve the members.
    	
    .EXAMPLE
    	$Group = Get-WmiObject -Query "Select * From Win32_Group Where LocalAccount = TRUE And SID = 'S-1-5-32-544'"
    	Get-WMILocalGroupMembers -Win32Group $Group
    	
      Retrieves all members from the given WMI Win32_Group from the locale system.
    
    .EXAMPLE
      Get-WmiObject -Query 'Select * From Win32_Group Where LocalAccount = TRUE' | Get-WMILocalGroupMembers
    
      Retrieves all local Groups of the currens System and retrieves all members from this groups.
    
    .INPUTS
        None
        You cannot pipe input to Get-WMILocalGroupMembers.
    
    .OUTPUTS
       PSObject with following NoteProperties:
         ParentName
          The name of the group which the member is member of
    
         ParentDomain
          The domain of the group which the member is member of
    
         Name
          The name of the groupmember
    
         Domain
          The domain of the groupmember
    
         SID
          The SID of the groupmember
    
         FullName
          The FullName of the groupmember in Active Directory also knowen as Displayname
          This is filled on Users only
    
         Type
          The Type of the groupmember
          Valid typevalues are 'User' or 'Group'
    
         Description
          The value out of the description field from the member
         ComputerName
    
    .NOTES
       Author: Peter Kriegel
       Initial Version: 1.0.0 04.February.2014
       Current Version 1.1.0 29.Oktober.2014
         Added begin{} and process{} blocks
         Added Pipeline Support for the -Win32Group Parameter
    #>
    
    	[CmdletBinding(DefaultParametersetname='DomainAndName')]
    	param(
    		[Parameter(
          ParametersetName='Win32Group',
          ValueFromPipeline = $true
        )]
    		[ValidateNotNullOrEmpty()]
    		$Win32Group,
    		[Parameter(
          ParametersetName='DomainAndName'
        )]
    		[String]$Name,
    		[Parameter(ParametersetName='DomainAndName')]
    		[ValidateNotNullOrEmpty()]
    		[String]$Domain = $env:ComputerName,
    		[ValidateNotNullOrEmpty()]
    		[String[]]$ComputerName = @($env:ComputerName),
    		[Switch]$Recursive
    	)
    	
      begin {
    	  Function Intern {	
    		  param(
    			  [String]$Name,
    			  [String]$Domain,
    			  [String]$ComputerName,
    			  [Switch]$Recursive
    		  )
    		
    		  # Get all members from the given Localgroup from the given ComputerName
    		  Get-WmiObject -computername $ComputerName -query "Select * From win32_groupuser Where GroupComponent=""Win32_Group.Domain='$Domain',Name='$Name'"""  | 
            ForEach-Object {
    		    
    		      # detect Type of Account
    			  If($_.PartComponent -Like '*Win32_UserAccount*' ) {
    				  $Type = 'User'
    			  } ElseIf ($_.PartComponent -Like '*Win32_Group*') {
    				  $Type = 'Group'
    				  If($Recursive) {
    				
    					  If ($PreventCircularReference -notcontains $_.PartComponent) {
    						  $PreventCircularReference += $PreventCircularReference
    						  $Group = ([WMI]($_.PartComponent))
    						  Intern -Name $Group.Name -Domain $Group.Domain -ComputerName $ComputerName -Recurse
    						  Return
    					  } Else {
    						  Return
    					  }
    				  }
    			  }
    			
    			  # Convert the PartComponent to an vital WMI object
    			  $Result = [WMI]($_.PartComponent) | Select-Object ParentName,ParentDomain,Name,Domain,SID,FullName,Type,Description,ComputerName
    			
    			  $Result.ParentName = $Name
            $Result.ParentDomain = $Domain
            $Result.ComputerName = $ComputerName
    			  $Result.Type = $Type
    			
    			  $Result
    		  } # end of ForEach-Object
    	  } #end of Function Intern
    
        # create the 'static' variable for the internal Function to prevent circular references
    	  New-Variable -Name PreventCircularReference -Value @() -Option 'AllScope'
    
      } # end of begin block
    
      process {
    	
        # test Parameters
    	  If($Win32Group -or ($PsCmdlet.ParameterSetName -eq 'Win32Group')) {
    		  If($Win32Group.__CLASS -notlike '*Win32_Group*') {
    			  $exception = New-Object System.ArgumentException 'Parametervalue is not a type of WMI/CIM class Win32_Group','Win32Group'
    	      $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception,'Win32Group','InvalidArgument',$null
            $PsCmdlet.WriteError($errorRecord)
            Return
    		  }
    		
    		  # Translate group to Name and Domain
    		  $Name = $Win32Group.Name
    		  $Domain = $Win32Group.Domain
    	  }
    	
    	  # set default for groupname
    	  If([String]::IsNullOrEmpty($Name)) {
          # For internationalization support we get the Name of the Administrators Group by SID
          $Name = (Get-WmiObject -ComputerName $ComputerName -Query "Select * From Win32_Group Where LocalAccount = TRUE And SID = 'S-1-5-32-544'").Name 
        }
    
    	  # call internal Function to do the work
    	  Intern -Name $Name -Domain $Domain -ComputerName $ComputerName -Recursive:$Recursive
      } # end of process block
    
    }

    Schau dir dort die Beispiele an!


    PowerShell Artikel, Buchtipps und kostenlose PowerShell Tutorials + E-Books
    auf der deutschsprachigen PowerShell Community

    Mein 21 Teiliger PowerShell Video Grundlehrgang
    Deutsche PowerShell Videos auf Youtube
    Folge mir auf:
    Twitter | Facebook | Google+

    Mittwoch, 29. Oktober 2014 09:28