Welcome › Forums › General PowerShell Q&A › Nested ForEach Loops
- This topic has 5 replies, 3 voices, and was last updated 3 months, 1 week ago by
Participant.
-
AuthorPosts
-
-
October 14, 2020 at 12:32 pm #263325
Using Powershell to pull data from eDirectory, the data I’m trying to grab looks like:
cn primary secondary 123joe ABCD 5678 123joe ABCD 8998 123joe ABCD 1648 123janis DEFG null 123janis GHEX null Where a user ID might have one or more primary values, and zero or more secondary values.
The code I’m working with allows me to entirely grab a user like 123joe in three rows with all three of his secondary identifiers, but this code won’t grab 123janis at all, who has no secondary identifiers. I’d like to fix the query to pull all IDs, including the ones with no secondary identifiers.
PowerShell123456789101112131415161718192021222324252627282930313233$eDirPath = 'LDAP://0.0.0.0'$eDirUser = 'userID'$eDirPWD = 'password'$eDirAuthType = 'None'#Establish eDirectory Connection and Enumerate$Root = New-Object System.DirectoryServices.DirectoryEntry -argumentlist $eDirPath,$eDirUser,$eDirPWD,$eDirAuthType$Query = New-Object System.DirectoryServices.DirectorySearcher$Query.SearchRoot = $Root$Query.Filter = "(cn=123*)"$SearchResults = $Query.FindAll()$ldapIDs = @()ForEach ($Result in $SearchResults) `{$CCGroupALL = [PSCustomObject]$Result.PropertiesForEach ($Item in $CCGroupALL){$primary = $Item.primary$secondary = $Item.secondaryForEach ($cn in $Item.cn){ForEach ($primary in $Item.primary){ForEach ($secondary in $Item.secondary){$ldapIDs += "$cn,$primary,$secondary"}}$CSVoutput = "cn,primary,secondary" , $ldapIDs}}}$CSVoutput | Out-File C:\ldapFile.csv -
October 14, 2020 at 3:19 pm #263376
This will never output data if there are no secondary items because of the ForEach logic on line 23. If $Item.secondary is null then the ForEach will operate 0 times, resulting in line 25 being skipped because that loop doesn’t do anything and therefore producing no data for $CSVoutput on line 28.
Separating the primary and secondary foreach loops should solve the problem:
PowerShell123456789101112131415161718192021222324252627282930313233343536373839404142$eDirPath = 'LDAP://0.0.0.0'$eDirUser = 'userID'$eDirPWD = 'password'$eDirAuthType = 'None'#Establish eDirectory Connection and Enumerate$Root = New-Object System.DirectoryServices.DirectoryEntry -argumentlist $eDirPath,$eDirUser,$eDirPWD,$eDirAuthType$Query = New-Object System.DirectoryServices.DirectorySearcher$Query.SearchRoot = $Root$Query.Filter = "(cn=123*)"$SearchResults = $Query.FindAll()$ldapIDs = @()ForEach ($Result in $SearchResults) {$CCGroupALL = [PSCustomObject]$Result.PropertiesForEach ($Item in $CCGroupALL) {$primary = $Item.primary$secondary = $Item.secondaryForEach ($cn in $Item.cn) {$ldapIDs += "$cn" #store the cn valueForEach ($primary in $Item.primary) {$ldapIDS += "$primary" #store the primary value} #ForEach $primaryForEach ($secondary in $Item.secondary) {$ldapIDs += "$secondary" #store the secondary value} #ForEach $secondary} #ForEach $cn$CSVoutput = "cn,primary,secondary", $ldapIDs #store values in CSVoutput} #ForEach $Item} #ForEach $Result$CSVoutput | Out-File C:\ldapFile.csv(untested)
Of course, this isn’t the best methodology.
-
October 14, 2020 at 4:28 pm #263397
What exactly are you trying to end up with?
-
October 14, 2020 at 5:04 pm #263403
Trying to end up with three columns in a csv like:
cn primary secondary 123joe ABCD 5678 123joe ABCD 8998 123joe ABCD 1648 123janis DEFG 123janis GHEX Basically, for each user ID, grab all the primary values, and if there are any secondary values grab those too.
But if the user ID doesn’t have a secondary value like 123janis, then just grab the user ID and primary value(s).
I tried grokkit’s code and it looks like all the data is being dropped into the first column.
-
October 14, 2020 at 6:22 pm #263415
Getting closer…
The following code uses If and ElseIf to run a separate query based on whether Item.secondary is null or not null.
When I use the Write-Host output, it looks correct on screen, but the CSV file ends up with all the data sitting in row 2 of the file, like:
cn primary secondary 123joe,ABCD,5678,123joe,ABCD,8998,123joe,ABCD,1648,123janis,DEFG,123janis,GHEX Any ideas how to get the $CSVOutput formatted correctly?
PowerShell12345678910111213141516171819202122232425262728293031ForEach ($Result in $SearchResults) `{$CCGroupALL = [PSCustomObject]$Result.PropertiesForEach ($Item in $CCGroupALL){$primary = $Item.primary$secondary = $Item.secondaryForEach ($cn in $Item.cn){If ($null -ne $Item.secondary){ForEach ($primary in $Item.primary){ForEach ($secondary in $Item.secondary){#Write-Host "$cn",",","$primary",",","$secondary"$ldapIDs += "$cn,$primary,$secondary"}}}ElseIf ($null -eq $Item.secondary){ForEach ($primary in $Item.primary){#Write-Host "$cn",",","$primary",",","$secondary"$ldapIDs += "$cn,$primary,$secondary"}}}$CSVoutput = "cn,primary,secondary" , $ldapIDs}}$CSVoutput | Out-File C:\ldapFile.csv -
October 15, 2020 at 2:19 pm #263651
Solved. A working version of the full script is pasted below. Made a modification based on this article (no longer using +=).
This version includes grabbing two additional columns from eDirectory: firstname $fn and lastname $ln.
PowerShell12345678910111213141516171819202122232425262728293031323334353637383940414243$eDirPath = 'LDAP://0.0.0.0'$eDirUser = 'userID'$eDirPWD = 'password'$eDirAuthType = 'None'#Establish eDirectory Connection and Enumerate$Root = New-Object System.DirectoryServices.DirectoryEntry -argumentlist $eDirPath,$eDirUser,$eDirPWD,$eDirAuthType$Query = New-Object System.DirectoryServices.DirectorySearcher$Query.SearchRoot = $Root$Query.Filter = "(cn=123*)"$SearchResults = $Query.FindAll()$ldapIDs = New-Object System.Collections.Generic.List[System.String]ForEach ($Result in $SearchResults) `{$CCGroupALL = [PSCustomObject]$Result.PropertiesForEach ($Item in $CCGroupALL){$fn = $Item.givenname$ln = $Item.sn$primary = $Item.primary$secondary = $Item.secondaryForEach ($cn in $Item.cn){If ($null -ne $Item.secondary) # use this loop if secondary is not null{ForEach ($primary in $Item.primary){ForEach ($secondary in $Item.secondary){$ldapIDs.Add("$cn,$fn,$ln,$primary,$secondary")}}}ElseIf ($null -eq $Item.secondary) # otherwise use this loop if secondary is null{ForEach ($primary in $Item.primary){$ldapIDs.Add("$cn,$fn,$ln,$primary,$secondary")}}}$CSVoutput = "cn,fn,ln,primary,secondary" , $ldapIDs #create the CSVOutput with header row}}$CSVoutput | Out-File C:\Ldap.csvNote: if you want to test in your environment, input your eDirectory ldap path, userID, and password. Also the “primary” and “secondary” attributes probably don’t exist in your eDirectory environment, so you’ll want to modify these accordingly. Also the $Query.Filter above will only grab user IDs beginning with “123” so modify accordingly.
Your $eDirPath might look something like: ‘LDAP://your IP address/o=something/ou=somethingElse’
Whereas your $eDirUser credentials might look something like: ‘cn=yourID,ou=something,o=somethingElse’
-
-
AuthorPosts
- The topic ‘Nested ForEach Loops’ is closed to new replies.