0

tldr; I need to fill an array, which is populated in a function, within constricted language. Until now i found only ways, which are not do able in constricted language.

So basicly i want to loop through the AD and identify looping groups and where users are placed looping wise.

To Achive this i wrote a function which calls itslef. The function returns 4 diffrent objects. These objects are needed to handle the loop.

But the function scope needs to return the value to the script scope ("top most") as otherwise the script will loop infinitly on the first object already.

Unfortunatly this is in constrained language, which means the most common resolves wont work.

Shortend Code Sample

$ReturnValue1 = @()
$ReturnValue2 = @()
$ReturnValue3 = @()
$ReturnValue4 = @()

Function Get-ADInfos
{
Param(
    $Entitys
)
foreach($Entity in $Entitys){
$Object = New-Object -TypeName PSObject
    if($Entity.objectClass -eq "user"){
        if($ReturnValue2.User.distinguishedName -contains $Entity)
            #Do Something
            $ReturnValue1 += $Object
            Write-Host "$Entity is already scanned"
        }else{
            #Do something
            $ReturnValue2 += $didsomething
            Get-ADInfos $Values #looping
        }
    }elseif($Entity.objectClass -eq "group"){
        if($ReturnValue4.Group.distinguishedName -contains $Entity){
            #Do Something
            $ReturnValue3 += $didsomething
        }else{
            #Do Something
            $ReturnValue4 += $didsomething
            Get-ADInfos $Values
        }
    }else{
        write-host "finished"
    }
}

Full Code for Repro (Older) #Note: To use constrained language for testing.

$User = @()
$Gruppen = @()
$LoopUser = @()
$LoopGroup = @()

Function Get-ADInfos
{
Param(
    $Entry
)

#$Entry = Get-ADGroup "Domain Users"

if($Entry.objectClass -eq "user"){
    $Entitys = Get-ADPrincipalGroupMembership $Entry
}elseif($Entry.objectClass -eq "group"){
    $Entitys = Get-ADGroupMember $Entry
}else{}

foreach($Entity in $Entitys){
    if($Entity.objectClass -eq "user"){
        if($User.user -contains $Entity){
            $Row = "" | Select User, Group
            $Row.User = $Entity
            $Row.Group = $Entry
            $LoopUser += $Row #return to "master" scope
            Write-Host "$Entity is already scanned"
        }else{
            $Row = "" | Select User, Group
            $Row.User = $Entity
            $Row.Group = $Entry
            $User += $Row #return to "master" scope
            Write-Host "$Entity is in $group"
            Get-ADInfos $Entity
        }
    }elseif($Entity.objectClass -eq "group"){
        if($Groups.group -contains $Entity){
            $Row = "" | Select ScannedGroup, ParentGroup
            $Row.ScannedGroup = $Entity
            $Row.ParentGroup = $Entry
            $LoopGroup += $Row #return to "master" scope
            
            Write-Host "$Entity is already scanned"
        }else{
            $Row = "" | Select Group
            $Row.Group = $Entity
            $Groups += $Row #return to "master" scope
            Write-Host "$Entity scanned"
            Get-ADInfos $Entity
        }
    }else{
        write-host "finished"
    }
}
}

Get-ADGroup "Domain Users" | Get-ADInfos
Kevin
  • 193
  • 1
  • 4
  • 16

1 Answers1

3

PowerShell Arrays are immutable (fixed size collections):

$User = @()
$User.add('item')
MethodInvocationException: Exception calling "Add" with "1" argument(s): "Collection was of a fixed size."

This means that -besides the inefficient use of the increase assignment operator (+=)- it will create a new copy of the of array in each child scope when you try to change it:

$User = @()
function Test {
    $User += 'Item'
    Write-Host 'Child scope:' $User
}
Test
Write-Host 'Parent scope:' $User

Yields:

Child scope: Item
Parent scope:

Instead, I recommend you to use List<T> Class knowing that you can use the List<T>.Add(T) Method and the fact that objects are referenced by default:

$User = [Collections.Generic.List[object]]::new()
function Test { $User.Add('item') }
Test
$User # Yields: item

Addendum
As your script appears to run under constrained language mode, you will not be allowed to use the List<T> type or anything similar you might consider to use native PowerShell HashTables instead. See also: Mutable lists in Constrained Language Mode.

To apply this to your script:

  1. Change all the arrays (that have a shared scope) to hashtables.
    e.g.: $User = @()$User = @{}
  2. Change your assignments.
    e.g.: $User += $Row$User[$User.Count] = $Row
  3. Change the conditions.
    e.g.: $User.user -contains $Entity$User.Values.user -contains $Entity
iRon
  • 20,463
  • 10
  • 53
  • 79
  • Does this work with actual "tables"? As i need to refernce to the $User.User or $User.Group, so can i still use the $row then to add to the List? Is the List capable to store obejcts or is it only string value then? – Kevin Oct 19 '22 at 08:35
  • 1
    It can store any object: `[Collections.Generic.List[` ***`object`*** `]]`, the string `'item'` is just an example. – iRon Oct 19 '22 at 08:38
  • Thank you for the clarification, as i tried it, it brougth up an error, that the list has a fixed size, how do i work around that, thats the reason why i used the insufficent += method of the array. – Kevin Oct 19 '22 at 08:40
  • That means that you didn't use the [`List` Class](https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1) as explained in the answer. – iRon Oct 19 '22 at 08:45
  • Just found out that i can't use this as company restrictions hit there. I can only use "core types", it says CannotCreateTypeConstrainedLanguage – Kevin Oct 19 '22 at 08:55
  • 1
    See: [Mutual lists in Constrained Language Mode](https://stackoverflow.com/q/74125063/1701026) – iRon Oct 19 '22 at 12:11
  • I dont really understand how i can use this, i havent realized how i actualy can fill it with values, as i have paired values like Line1: Username, Group. And how i can then use those values aswell. – Kevin Oct 20 '22 at 05:05
  • It is quite some usefull information all in all, but it doesnt resolve my problem, that i can't use it in my instance because i cant work with it this way. – Kevin Oct 21 '22 at 05:11
  • Ro be able to help you, you will need to be more specific on the *current* problem. As stated before, I recommend you to create a [mcve] and open a new question with where youre current issue lies. – iRon Oct 21 '22 at 06:50