question

AintGotNoTime-6052 avatar image
0 Votes"
AintGotNoTime-6052 asked AintGotNoTime-6052 commented

Combine multiple arrays down to one

In my script I am pulling accounts from many OU structures, and so I have an array for each. how can I eliminate all these different arrays I am trying to combine down to one for the whole things. Sometimes no accounts are returned in the array and I have issues in past that would blank out the main array I was sticking accounts into.
#Get a domain controller for the dva domain. $dc = Get-ADDomainController -DomainName dva -Discover -NextClosestSite #Add the Domains via the following #Create and Array and then add the array to the filter with the domain name and then add the filter to main array collections if it finds information $dvamailboxes = Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailboxes)" -Server dva | Select-Object -Expand DistinguishedName #After getting the mailbox OU then Create andother array for the accounts and select accounts per the date. #roll through dva looking for accounts $dvamailboxAccounts = foreach ($box in $($dvamailboxes)) { Get-ADUser -Server $dc -SearchBase $box -filter * -Property whenCreated | Where {$_.whenCreated -gt $dte} } #Select the objects from the Get-ADuser and put in an array for use later $dvaacctArray = $dvamailboxAccounts | select @{Name="userName";Expression={$_.SamAccountName.Trim()}}, @{Name="address";Expression={"dva"}}, @{Name="safeName";Expression={'VA-WIN-MAILBOX-ACCTS'}}, @{Name="platformId";Expression={'VA-WinLocalDisableAcct-Prod-Admin-26-1yr'}}, @{Name="secret";Expression={'12345678'}} #Append the array with the DVA accounts if($dvaacctArray -gt $null) { $mainemailaccounts += $dvaacctArray }
Then I do the same with the next domain
#Get the DC for the AAC domain
$dc = Get-ADDomainController -DomainName aac -Discover -NextClosestSite

 #Add the Domains via the following
 #Create and Array and then add the array to the filter with the domain name and then add the filter to main array collections if it finds information
 $aacmailboxes = Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailbox)" -Server aac |  Select-Object -Expand DistinguishedName
    
    
 #After getting the mailbox OU then Create andother array for the accounts and select accounts per the date.
 #roll through dva looking for accounts
 $aacmailboxAccounts = foreach ($box in $($aacmailboxes)) 
     {
         Get-ADUser -Server $dc -SearchBase $box -filter * -Property whenCreated | Where {$_.whenCreated -gt $dte}
     }
    
 #Select the objects from the Get-ADuser and put in an array for use later
 $aacacctArray = $aacmailboxAccounts | select @{Name="userName";Expression={$_.SamAccountName.Trim()}}, @{Name="address";Expression={"aac"}}, @{Name="safeName";Expression={'VA-WIN-MAILBOX-ACCTS'}},
 @{Name="platformId";Expression={'VA-WinLocalDisableAcct-Prod-Admin-26-1yr'}}, @{Name="secret";Expression={'12345678'}}
    
    
    
    
 ***But this is where the code will start getting large when trying the meld all the arrays into one as I keep adding more.  How can I reduce this to one arrya otherwise I will end up with about 30 statements like below adding up the arrays.
    
 #Append the array with the AAC accounts
 if($aacacctArray -gt $null -and $mainemailaccounts -gt $null)
     {
        $mainemailaccounts += $aacacctArray
     }
         elseif ($aacacctArray -gt $null -and $mainemailaccounts -eq $null)
             {
                 $mainemailaccounts += $aacacctArray
             }
             else
                 {
                  Write-Output "No accounts exist to onboard"
                  exit 1001
                 }
windows-server-powershell
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Combine the code on lines 8 - 15:

 [array]$mainemailaccounts += foreach ($box in $($aacmailboxes)){
                  Get-ADUser . . . |
                      Where-Object . . . |
                          Select-Object . . .
              }

In the end, all your users end up in $mailemailaccounts anyway.

You'll need to wrap the data gathering in a ForEach-Object loop that takes the list of domains you're working on.

This looks vaguely like the question I answers a couple of days ago with the difference that you're now acquiring the OUs instead of using the hash table I'd suggested (because how you named the OUs wasn't in the question).

0 Votes 0 ·
RichMatheisen-8856 avatar image
0 Votes"
RichMatheisen-8856 answered RichMatheisen-8856 commented

I think, based on the code you provided, that almost all of the arrays are unnecessary. You can probably wrap up all that your code does in something like this:

 [datetime]$dte = 0      # to be provided
    
 $domains = 'acc','dav'
 [array]$mainemailaccounts = @()
 $domains |
     ForEach-Object{
         #Get the DC for the domain
         $dc = Get-ADDomainController -DomainName $_ -Discover -NextClosestSite |
             Select-Object -Expand distinguishedName -First 1st
         # get the OUs for this domain
         Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailbox)" -Server $dc |  
             Select-Object -Expand DistinguishedName |
                 ForEach-Object{
                     $mainemailaccounts += Get-ADUser -filter * -Server $dc -SearchBase $_ -SearchScope OneLevel -Property whenCreated | 
                                             Where-Object {$_.whenCreated -gt $dte} |
                                                 Select-Object   @{Name="userName";Expression={$_.SamAccountName.Trim()}}, 
                                                                 @{Name="address";Expression={"aac"}}, 
                                                                 @{Name="safeName";Expression={'VA-WIN-MAILBOX-ACCTS'}},
                                                                 @{Name="platformId";Expression={'VA-WinLocalDisableAcct-Prod-Admin-26-1yr'}}, 
                                                                 @{Name="secret";Expression={'12345678'}}
                 }
     }
     if ($mainemailaccounts.count -eq 0){
         Write-Output "No accounts exist to onboard"
         exit 1001
     }
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

HI,
I was trying to get this working but keep running into an error tried my young knowledge base and could not solve

Get-ADDomainController : The format of the specified domain name is invalid
At C:\Users\Documents\Powershell Scripts\code2.ps1:8 char:16
+ ... $dc = Get-ADDomainController -DomainName [string]$domains -Disc ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-ADDomainController], ADException
+ FullyQualifiedErrorId : GetADDomainController:BeginProcessingOverride:DiscoverDC:1212,Microsoft.ActiveDirectory.Management.Commands.GetADDomainController


Get-ADOrganizationalUnit : Cannot validate argument on parameter 'Server'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At C:\Users\Documents\Powershell Scripts\code2.ps1:10 char:81
+ ... rganizationalUnit -LDAPFilter "(Name=Shared Mailboxes)" -Server $dc |
+ ~~~
+ CategoryInfo : InvalidData: (:) [Get-ADOrganizationalUnit], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.GetADOrganizationalUnit

I put the variable $domains in here, but looks like it wont take it. I tried [string]$Domains, and $domains.ToString()
$dc = Get-ADDomainController -DomainName $domains -Discover -NextClosestSite



0 Votes 0 ·

My bad. :-( Line 8 should look like this:

 $dc = Get-ADDomainController -DomainName $_ -Discover -NextClosestSite |

I overlooked the use of the constant "acc" as the domain name when I copied your original code.

Line 3 should, of course, should contain your domain NetBIOS names (or at least the ones you want to test with).

Line 14 should look line this:

 $mainemailaccounts += Get-ADUser -filter * -Server $dc -SearchBase $_ -SearchScope OneLevel -Property whenCreated | 

The previous Line 14 incorrectly specified the value to be used as the SearchBase and omitted the SearchScope (which may have lead to the search returning the accounts in any child OUs).

Both have been corrected in the code sample.

0 Votes 0 ·

hi,

I still get this on the server
Get-ADOrganizationalUnit : Cannot validate argument on parameter 'Server'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.

 [datetime]$dte = '08/15/2021'    
        
  $domains = 'dva', 'cem'
  [array]$mainemailaccounts = @()
  $domains |
      ForEach-Object{
          #Get the DC for the domain
          $dc = Get-ADDomainController -DomainName $_ -Discover -NextClosestSite |
          # get the OUs for this domain
          Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailboxes)" -Server $dc |  
              Select-Object -Expand DistinguishedName |
                  ForEach-Object{
0 Votes 0 ·
Show more comments
MotoX80 avatar image
0 Votes"
MotoX80 answered MotoX80 edited

A lot of what you posted all runs together and its really hard to read. You should edit your post and use the Code Sample tool (the 101010 icon) to format your code.

I'll assume that your arrays all contain the same type of object. This example shows how to combine similar named arrays using Get-Variable.

 $ArrArray1 = Get-ChildItem -Path C:\temp\foo1 | foreach { 
     [pscustomobject] @{
         Name = $_.Name 
         Time = $_.LastWriteTime 
     } 
 }
 $ArrArray2 = @()                                                  # an empty array 
 $ArrArray3 = Get-ChildItem -Path C:\windows\temp | foreach { 
     [pscustomobject] @{
         Name = $_.Name 
         Time = $_.LastWriteTime 
     } 
 }
    
 $Combined = @()                                                    # append to this empty array  
 get-variable | foreach {                                           # look at all variables
     if ($_.Name -match 'ArrArray') {          # find our array variables. Use some unique name that will match. 
         "Processing {0}, Count={1}" -f $_.name, $_.Value.count
         $Combined += $_.Value                                # append to our combined array
     }
 }     
    
 "Here is the combined array."
 $Combined 
 ""
 "Total entries = {0}" -f $Combined.Count


5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AintGotNoTime-6052 avatar image
0 Votes"
AintGotNoTime-6052 answered

Ok, it exceeded characters on comment but here is the total currently. So I have 33 domains in total to do this, so you can see each time I add another the mesh code at the end will get uncontrollable. i am hoping I can just use one array and keep combining the data with each pull of the domain data.

 #Get a domain controller for the dva domain.
 $dc = Get-ADDomainController -DomainName dva -Discover -NextClosestSite
    
 #Add the Domains via the following
 #Create and Array and then add the array to the filter with the domain name and then add the filter to main array collections if it finds information
 $dvamailboxes = Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailboxes)" -Server dva |  Select-Object -Expand DistinguishedName
    
    
 #After getting the mailbox OU then Create andother array for the accounts and select accounts per the date.
 #roll through dva looking for accounts
 $dvamailboxAccounts = foreach ($box in $($dvamailboxes)) 
     {
         Get-ADUser -Server $dc -SearchBase $box -filter * -Property whenCreated | Where {$_.whenCreated -gt $dte}
     }
    
 #Select the objects from the Get-ADuser and put in an array for use later
 $dvaacctArray = $dvamailboxAccounts | select @{Name="userName";Expression={$_.SamAccountName.Trim()}}, @{Name="address";Expression={"dva"}}, @{Name="safeName";Expression={'VA-WIN-MAILBOX-ACCTS'}},
 @{Name="platformId";Expression={'VA-WinLocalDisableAcct-Prod-Admin-26-1yr'}}, @{Name="secret";Expression={'12345678'}}
    
 #Append the array with the DVA accounts
 if($dvaacctArray -gt $null)
     {
        $mainemailaccounts += $dvaacctArray
     }
    
    
 ####New Mailbox Pull
 #aac mailbox arrays
 $aacmailboxes = @()
 $aacmailboxAccounts = @()
 $aacacctArray = @()
 #Get the DC for the AAC domain
 $dc = Get-ADDomainController -DomainName aac -Discover -NextClosestSite
    
 #Add the Domains via the following
 #Create and Array and then add the array to the filter with the domain name and then add the filter to main array collections if it finds information
 $aacmailboxes = Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailbox)" -Server aac |  Select-Object -Expand DistinguishedName
    
    
 #After getting the mailbox OU then Create andother array for the accounts and select accounts per the date.
 #roll through dva looking for accounts
 $aacmailboxAccounts = foreach ($box in $($aacmailboxes)) 
     {
         Get-ADUser -Server $dc -SearchBase $box -filter * -Property whenCreated | Where {$_.whenCreated -gt $dte}
     }
    
 #Select the objects from the Get-ADuser and put in an array for use later
 $aacacctArray = $aacmailboxAccounts | select @{Name="userName";Expression={$_.SamAccountName.Trim()}}, @{Name="address";Expression={"aac"}}, @{Name="safeName";Expression={'VA-WIN-MAILBOX-ACCTS'}},
 @{Name="platformId";Expression={'VA-WinLocalDisableAcct-Prod-Admin-26-1yr'}}, @{Name="secret";Expression={'12345678'}}
    
 #Append the array with the AAC accounts
 if($aacacctArray -gt $null -and $mainemailaccounts -gt $null)
     {
        $mainemailaccounts += $aacacctArray
     }
         elseif ($aacacctArray -gt $null -and $mainemailaccounts -eq $null)
             {
                 $mainemailaccounts += $aacacctArray
             }
             else
                 {
                  Write-Output "No accounts exist to onboard"
                  exit 1001
                 }
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

MotoX80 avatar image
0 Votes"
MotoX80 answered

So don't build 33 (or more) arrays, make the "loop" generic so that it can process any domain.

  $ALLmailboxes = @()
  $ALLmailboxAccounts = @()
  $ALLacctArray = @()
  $33Domains = @('aac','dva','abc','xyz','etc')
  Foreach ($Domain in $33Domains) {
      "Processing domain $Domain"
      $Domainmailboxes = @()
      $DomainmailboxAccounts = @()
      $DomainacctArray = @()
    
      $Domainmailboxes = Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailboxes)" -Server $Domain |  Select-Object -Expand DistinguishedName
    
    
      # rest of domain level processing goes here
         
    
      # All done, Now append the domain that we processed to the overall arrays.  
    
      $ALLmailboxes += $Domainmailboxes 
      $ALLmailboxAccounts += $DomainmailboxAccounts 
      $ALLacctArray += $DomainacctArray
     
     
  }
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AintGotNoTime-6052 avatar image
0 Votes"
AintGotNoTime-6052 answered AintGotNoTime-6052 commented

Ok, I got this working to filter through so far but 2 things, one it does not pull the samAccountName and I need the address to be the same as the domain I am searching through. I tried the variable but that was a no go.

 [datetime]$dte = '08/15/2021'
 $ALLmailboxes = @()
 $ALLmailboxAccounts = @()
 $ALLacctArray = @()
 $33Domains = @('dva', 'cem')
    
 Foreach ($Domain in $33Domains) {
     $Domainmailboxes = @()
     $DomainmailboxAccounts = @()
     $DomainacctArray = @()
        
     $dc = Get-ADDomainController -DomainName $Domain -Discover -NextClosestSite
     $Domainmailboxes = Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailboxes)" -Server $Domain |  Select-Object -Expand DistinguishedName
        
     Write-Host $Domainmailboxes | Format-Table -force
     
    
     $DomainmailboxAccounts = foreach ($box in $($Domainmailboxes)) 
      {
          Get-ADUser -Server $dc -SearchBase $box -filter * -Property whenCreated | Where {$_.whenCreated -gt $dte}
             
      }
        
     # rest of domain level processing goes here
     $DomainacctArray = $DomainmailboxAccounts | Select
                                                      @{Name="userName";Expression={$_.SamAccountName.Trim()}}, 
                                                      @{Name="address";Expression={'$Domain'}}, 
                                                      @{Name="safeName";Expression={'VA-WIN-MAILBOX-ACCTS'}},
                                                      @{Name="platformId";Expression={'VA-WinLocalDisableAcct-Prod-Admin-26-1yr'}}, 
                                                      @{Name="secret";Expression={'12345678'}}
        
     write-host = $DomainacctArray | Format-table -Force
     # All done, Now append the domain that we processed to the overall arrays.  
        
     #$ALLmailboxes += $Domainmailboxes 
     #$ALLmailboxAccounts += $DomainmailboxAccounts 
     #$ALLacctArray += $DomainacctArray
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Line 12 is wrong. The value of the -Server parameter should be the host name or distinguishedName of one of the DCs you get from the Get-ADDomainController cmdlet. While you may have only one DC in your current domain you have several in another domain. You need the Select-Object from my code to pick just one and to get the distinguishedName (or host name) -- you shouldn't use the entire object (or the ARRAY of objects) as the parameter value.

Line 13 is also wrong. You're using the NetBIOS name of the current domain as the value for the -Server parameter. You want that to be the $dc variable (after you correct line 12!).

You haven't included a -SearchScope parameter on line 20. If there are (or it there may be in the future) one or more child OUs you're going to include them in your results. Unless you're just tinkering, it's better to code defensively and anticipate what will affect your processing and results.

I don't know why the samAccountName isn't present. Fix the other problems first. Then try again. If you still have a problem add "samaccountname" to the -Property value on line 20 and see if that fixes it.


0 Votes 0 ·

Sorry for lateness, to many projects. I have it semi-working but in the end it only show the last accounts in the array, it should show any # of accounts of all the OU, which it goes through about 120. When I got it to pull accounts it only put in the samAccountname when I added it after line 20 to select it, but it does not select anything from lines 25 - 30.


      # rest of domain level processing goes here
      $DomainacctArray += $DomainmailboxAccounts | Select
                                                       @{Name="userName";Expression={$_.samAccountName.Trim()}}, 
                                                       @{Name="address";Expression={'test'}}, 
                                                       @{Name="safeName";Expression={'VA-WIN-MAILBOX-ACCTS'}},
                                                       @{Name="platformId";Expression={'VA-WinLocalDisableAcct-Prod-Admin-26-1yr'}}, 
                                                       @{Name="secret";Expression={'12345678'}}
       }  



0 Votes 0 ·

I am able to write out all the OU from each domain, but its the code after the Get-ADuser which seems to only get the last OU accounts in the array. I tried a += but still nothing
$DomainacctArray += $DomainmailboxAccounts, wondering if I need another loop there.

0 Votes 0 ·
LimitlessTechnology-2700 avatar image
0 Votes"
LimitlessTechnology-2700 answered

Hi there,

Account organizational units (OUs) contain user, group, and computer objects. Resource OUs contain resources and the accounts that are responsible for managing those resources. The forest owner is responsible for creating an OU structure to manage these objects and resources and for delegating control of that structure to the OU owner. You can get more info from here

https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/delegating-administration-of-account-ous-and-resource-ous

Hope this Answers all your queries , if not please do repost back .
If an Answer is helpful, please click "Accept Answer" and upvote it : )

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

AintGotNoTime-6052 avatar image
0 Votes"
AintGotNoTime-6052 answered AintGotNoTime-6052 commented

Ok, this code works with one issue, it only ever gets the accounts in the array of the last domain in the list of $33Domains, the purpose was to consolidate into one array, but it get no other accounts but the last domain.

 [datetime]$dte = '06/15/2021'
  $ALLmailboxes = @()
  $ALLmailboxAccounts = @()
  $ALLacctArray = @()
  $33Domains = @('dva', 'aac', 'cem')
        
  Foreach ($Domain in $33Domains) {
      $Domainmailboxes = @()
      $DomainmailboxAccounts = @()
      $DomainacctArray = @()
        
      $dc = Get-ADDomainController -DomainName $Domain -Discover -NextClosestSite
      [string]$dchost = $dc.HostName
    
      $Domainmailboxes = Get-ADOrganizationalUnit -LDAPFilter "(Name=Shared Mailboxes)" -Server $dchost |  Select-Object -Expand DistinguishedName
            
      #Write-Host $Domainmailboxes | Format-Table -force
         
        
          $DomainmailboxAccounts = foreach ($box in $($Domainmailboxes)) 
           {
               Get-ADUser -Server $dchost -SearchBase $box -filter * -Property whenCreated | Where {$_.whenCreated -gt $dte}
           }
            
    
              # rest of domain level processing goes here
             $DomainacctArray += $DomainmailboxAccounts | select @{Name="userName";Expression={$_.SamAccountName.Trim()}}, 
                                                                 @{Name="address";Expression={$Domain}}, 
                                                                 @{Name="safeName";Expression={'VA-WIN-MAILBOX-ACCTS-4'}},
                                                                 @{Name="platformId";Expression={'VA-WinLocalDisableAcct-Prod-Admin-26-1yr'}}, 
                                                                 @{Name="secret";Expression={'12345678'}}
    
        
       }  
    
      write-host = $DomainacctArray | Format-table -Force
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.


Replace lines 20 - 23 with this:

 $DomainmailboxAccounts = $Domainmailboxes |
     ForEach-Object {
         Get-ADUser -Server $dc -SearchBase $_ -filter * -Property whenCreated | Where {$_.whenCreated -gt $dte}
     }

The "ForEach" can either be an alias for the "ForEach-Object" cmdlet (e.g. when it's followed immediately by a code block), or as a part of the PowerShell language (e.g. when it's followed immediately by an expression. The Foreach-Object cmdlet emits anything written to the "success" stream (often referred to as STDOUT). The Foeeach statement doesn't write anything to a stream.

Have a look at the Foreach-Object cmdlet and you'll see it takes a number of parameters. The code block that follows Foreach-Object is taken to the value of the "-Process" parameter.

0 Votes 0 ·

ok, that works, but it still only grabs the data from the last domain in the chain of domains, it not grabbing all the data from each domain in the array.

0 Votes 0 ·

Yes, it is! But you're setting $DomainacctArray to an empty array for each domain on line #9, and the $DomainacctArray to an empty array on line #10. The way you've named that variable made me think that you were doing that intentionally. Now it appears that you mean for the $DomainacctArray to hold the mailboxes for ALL domains. If that's the case, declare "$DomainacctArray = @()" BEFORE you enter the 1st Foreach (maybe on line #6).

There are arrays declared on 2 - 4 that begin with "$ALL . . .", but they're never used! What's their purpose?

0 Votes 0 ·
Show more comments