Sorting results of a ForEach -parallel workflow statement

This topic contains 1 reply, has 2 voices, and was last updated by Profile photo of Don Jones Don Jones 1 year, 8 months ago.

  • Author
    Posts
  • #23778
    Profile photo of Mike Edwards
    Mike Edwards
    Participant

    Is it possible to sort the output of a workflow that has a Foreach -parallel statement? I've got a script that collects trusted domain names and sends them to another script via a workflow for processing. The second script gathers the domain name, IP Address of the DC's, whether the LDAP port is open on the DC and the date (among other things). When processing is completed by the second script, the output is sent to a .csv file. The script works, but I'd like to list the domain names alphabetically in the .csv file. I've tried sending the output to an array and sorting the array, but I must be missing something.

    By the way, the ForEach -parallel statement is a requirement.

    Here's the script that runs first:

    ##########C:\trustsearch.ps1############
    $filename = get-date -UFormat %b%d%Y
    Function IsolatedNameQuery{
    $startDTM = (get-date)
    $objUser = New-Object System.Security.Principal.NTAccount("junk")
    $strSID = $objUser.Translate([System.Security.Principal.SecurityIdentifier])
    $endDTM = (get-date)
    $totaltime = (($endDTM-$startDTM).TotalSeconds)
    $script:ftotaltime = "{0:N2}" -f $totaltime
    $csvheader = "Isolated Name Query Time (sec.),Domain,Run Number,IP Address,LDAP Query Elapsed Time"
    out-file -InputObject $csvheader -FilePath "c:\$filename.csv" -Encoding ascii -NoClobber
    add-content "$ftotaltime" -path "c:\$filename.csv"
    }

    IsolatedNameQuery

    #search all trusted domain objects

    Import-module activedirectory
    $ADDomainTrust = Get-ADObject -Filter {ObjectClass -eq "trustedDomain"} -Properties *

    #workflow

    workflow Get-domains
    {

    param( $trusteddomainlist)
    foreach -parallel ($trusteddomain in $trusteddomainlist)
    {
    $trust = $trusteddomain.name
    InlineScript {C:\trustsearch.ps1 $using:trust}
    }
    }

    Get-domains $ADDomainTrust

    Here's the script that does the processing and outputs the .csv file (script #2):

    #Collect information on the trusted domains
    $filename = get-date -UFormat %b%d%Y
    $port = "389"
    $trust=$args[0]
    $domainarray = @()

    foreach($domain in $trust){
    $dn = $domain.replace(".", "")
    $domainname = $domain.cn

    #Find IP addressess for all domain controllers for each trusted domain
    Foreach($Address in $domain){
    $ipconfig = [System.Net.Dns]::GetHostAddresses($domain)

    #Telnet to port 389 (LDAP port) to see if it is open on each of the IP addresses.
    Foreach ($ip in $ipconfig){

    $t = New-Object Net.Sockets.TcpClient
    # Use Try\Catch to remove exception info from console if we can't connect
    try
    {
    $t.Connect($ip,$port)
    } catch {}

    #Search external schema
    if($t.Connected)
    {

    $startDTM = (Get-Date)
    $result = (Measure-Command -Expression {Get-ADObject -Filter * -SearchBase (Get-ADRootDSE -Server $ip).SchemaNamingContext -SearchScope Subtree -Server $ip}).TotalSeconds
    $fresult = "{0:N2}" -f $result
    $domainfacts = new-object PSObject -property @{"domain" = $domain; "RunNumber" = $startDTM; "IPAddress" = $ip; "LDAPQueryTime" = $fresult}
    $domainarray += $domainfacts

    }
    else
    {

    $domainarray = new-object PSObject -property @{"domain" = $domain; "RunNumber" = $startDTM; "IPAddress" = $ip; "LDAPQueryTime" = 'Server or port not available'}
    }

    }

    $domainarray | Select domain,RunNumber,IPAddress,LDAPQueryTime | Sort-Object domain -Descending | Format-Table -HideTableHeaders

    out-file -InputObject $domainarray -FilePath "c:\$filename.csv" -Encoding ascii -Append -NoClobber

    Any assistance or ideas would be greatly appreciated.

  • #23780
    Profile photo of Don Jones
    Don Jones
    Keymaster

    This:

    $domainarray | Select domain,RunNumber,IPAddress,LDAPQueryTime | Sort-Object domain -Descending | Format-Table -HideTableHeaders
    out-file -InputObject $domainarray -FilePath "c:\$filename.csv" -Encoding ascii -Append -NoClobber
    

    I don't fully understand. It absolutely isn't producing a CSV file, though, it's producing a formatted table. Also, if I understand your code correctly, $domainarray actually only contains one object at a time, so there'd be nothing to sort. You're relying on -Append to send each individual object to the text file – which, again, is not a CSV file, because you used Format-Table.

    Also note that the commands I pasted above are two separate commands. The first one is essentially accomplishing nothing – it ends with Format-Table, which you'll never see because this runs as a workflow. The second command, beginning with Out-File, takes the original $domainarray (which has never been altered) and outs it to a file, which implicitly calls Format-Table a second time.

    If you did this:

    $domainarray | Select domain,RunNumber,IPAddress,LDAPQueryTime | Export-CSV whatever.csv -Append
    

    I'd understand that. At the end, I'd re-read and sort the entire CSV.

    Import-CSV whatever.csv | Sort Domain -Desc | Export-CSV whatever2.csv
    

    But right now you're definitely not producing a CSV file, regardless of the filename extension.

You must be logged in to reply to this topic.