Foreach looping question

This topic contains 9 replies, has 5 voices, and was last updated by Profile photo of Raymond Slieff Raymond Slieff 2 years, 1 month ago.

  • Author
    Posts
  • #19922
    Profile photo of Jdominioni .
    Jdominioni .
    Participant

    Hello,

    So, first time poster here, so I'm sure I'll screw up the formatting. 🙂 I looked around, but didn't find anything here that seemed to match my situation, but I certainly could have missed it.

    I'm trying to cobble together a simple script to query a list of computers for a particular Event ID. I have sections of this working, and I'm a little lost as to why this isn't working correctly.

    I can get my list of domain controllers, no problem:

    $computername = get-adgroupmember "Domain Controllers" | select name

    I can get a filtered event log if I put an actual computer name into the statement:

    get-eventlog -logname "Directory Service" -ComputerName DC1 | ?{$_.eventid -eq "1864"} | select MachineName,EventID,TimeGenerated

    I can have the script get a list of each DC and echo it back to me:

    $computername = get-adgroupmember "Domain Controllers" |select name
    foreach ($computer in $computername) {$computer}
    

    And it spits the list back out at me, so I know the loop is iterating as I expect.

    So why does this not work?:

    $computername = getadgroupmember "Domain Controllers" |select name
    foreach ($computer in $computername)
    {
    get-eventlog -logname "Directory Service" -ComputerName $computer | ?{$_.eventid -eq "1864"} | select MachineName,EventID,TimeGenerated
    }
    

    -ComputerName wants a string. I'm not sure if I'm passing a string or an object down the pipeline, honestly. I tried adding "out-string" after the "select name." I've tried dumping the list to a file and using

    $computername = get-content "C:\folder\computername.txt"
    

    And have verified the txt file contains the proper output. I tried removing the "name" and dash line from the top of the text file. And the "get-content" method works the same when put into the "foreach" proof loop.

    But, when trying to loop this, I get:

    get-eventlog : The network path was not found.
    At C:\eventid\1864-3.ps1:4 char:10
    +          get-eventlog -logname "Directory Service" -ComputerName $computer | ?{$ ...
    +          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [Get-EventLog], IOException
        + FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.GetEventLogCommand
    

    This has to be something small and stupid I'm missing.... any help is greatly appreciated.

    Jason

  • #19928
    Profile photo of Ondrej Zilinec
    Ondrej Zilinec
    Participant

    Little tinny mistake 🙂

    Here is fixed script:

    $computername = getadgroupmember "Domain Controllers" 
    foreach ($computer in $computername)
    {
          get-eventlog -logname "Directory Service" -ComputerName $computer.name | ?{$_.eventid -eq "1864"} | select MachineName,EventID,TimeGenerated
    }
    

    You are welcomed 😉

  • #19931
    Profile photo of Jdominioni .
    Jdominioni .
    Participant

    You are awesome. Now that the underlying mistake is corrected, I can expand on this to create some flexibility.

    I SO appreciate the help. I'm still getting used to how to use the properties of objects.

    Jason

    • #19940
      Profile photo of Ondrej Zilinec
      Ondrej Zilinec
      Participant

      I was thinking about your approach and I guess you wanted do it this way:

      $computername = (get-adgroupmember "Domain Controllers").Name
      foreach ($computer in $computername)
      {
          get-eventlog -logname "Directory Service" -ComputerName $computer | ?{$_.eventid -eq "1864"} | select MachineName,EventID,TimeGenerated
      }
      
  • #19941
    Profile photo of Jdominioni .
    Jdominioni .
    Participant

    First, I appreciate you coming back to this with another approach. The first one did work for what I needed it to do, but this second method helps clarify some of the ideas of powershell.

    I come from doing a lot of Linux work where everything is text, so this idea of object.property is still new to me. Thank you for bearing with me. 🙂

    Jason

  • #19954
    Profile photo of Istvan Szarka
    Istvan Szarka
    Participant

    Just some extra info that helped me a lot when I first learned this:

    get-adgroupmember "Domain Controllers" | select -ExpandProperty name

    and

    (get-adgroupmember "Domain Controllers").Name

    do the same thing. Both extracts or expands the name property and make it a string object.
    Most or maybe all of the time when we mean text, PowerShell actually means a string object.

    You can always check the object type by piping the cmdlet into "Get-Member" ot "gm":

    Get-Service winrm | select name | gm
    # returns the object TypeName: Selected.System.ServiceProcess.ServiceController
    # if you want to pipe it into another cmdlet whose property accepts string, it will break, because the selected property is a ServiceController object, not a String
    
    Get-Service winrm | select -ExpandProperty name | gm
    (Get-Service winrm).Name | gm
    # returnes the object TypeName: System.String
    
  • #19975
    Profile photo of Adam Bertram
    Adam Bertram
    Participant

    I wouldn't depend on using the Domain Controllers group to be a sure-fire way to get them. I'd use this:

    (Get-AdDomain).ReplicaDirectoryServers

    Also, I tend to never use Get-EventLog. It's pretty slow. Get-WinEvent is much faster and you have more filtering capabilities. Try something like this:

    $DomainControllers = [Get-AdDomain].ReplicaDirectoryServers
    foreach [$Dc in $DomainControllers] {
        Get-WinEvent -Computername $Dc -FilterHashTable @{'LogName' = 'Directory Service'; 'Id' = '1864'} | Select-Object MachineName,Id,TimeCreated
    }

    That should be much more reliable and quicker.

  • #20005
    Profile photo of Jdominioni .
    Jdominioni .
    Participant

    Istvan,

    Thank you for those additional methods. As a noob I'm still trying to figure out what advantages or disadvantages each method has.

    Adam,

    Thank you for this suggestion; I will be trying it later today. I'm scanning ~150 domain controllers, many across slow WAN connections, and my first pass at this took like 9 hours.... Also, I see your point on the DC group.

  • #20012
    Profile photo of Adam Bertram
    Adam Bertram
    Participant

    For 150 DCs, Get-WinEvent is the way to go, for sure.

  • #20164
    Profile photo of Raymond Slieff
    Raymond Slieff
    Participant

    Sorry for being late to the party, but if you were using the AD Module, for gathering domain controllers this should also work.

    (pre)(Get-ADDomainController -Filter *).Name(/pre)

    And I believe all the options for this discussed so far are domain specific not forest wide just for some awareness on that.

You must be logged in to reply to this topic.