Foreach looping question

This topic contains 9 replies, has 5 voices, and was last updated by  Raymond Slieff 3 years, 8 months ago.

  • Author
  • #19922

    Jdominioni .


    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.


  • #19928

    Ondrej Zilinec

    Little tinny mistake 🙂

    Here is fixed script:

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

    You are welcomed 😉

  • #19931

    Jdominioni .

    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.


    • #19940

      Ondrej Zilinec

      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

    Jdominioni .

    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 is still new to me. Thank you for bearing with me. 🙂


  • #19954

    Istvan Szarka

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

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


    (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

    Adam Bertram

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


    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

    Jdominioni .


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


    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

    Adam Bertram

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

  • #20164

    Raymond Slieff

    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.