1
param([string]$roles,[string]$members)

Suppose I am passing input on the command line like this:

PS> role1,role2,role3,role4 member1,member2,,,,member3,,member4

The array I expect for this would be:

$array = @(
    @('role1', 'member1,member2'),
    @('role2', ''),
    @('role3', 'member3'),
    @('role4', 'member4')
)

I know to turn string to array:

$roles = 'role1,role2,role3,role4' -split ','
$members = 'member1,member2,,,,member3,,member4' -split ',,'

Now how do I combine $roles with $members so that each role will be associated with member(s)? and how wouldIi generate the array dynamically?

Pseudocode:

$array = @()

($roles+$members) | %{
    $role = $_.roles
    if ($_.members) {
        $_.members -split ',,' | ForEach-Object { $array += $role $_ }
    } else {
        $array += $role 
    }
}

Note: I am splitting members as an index of its own for each double comma because apparently semicolons aren't accepted on a command line because they break the command line, so I have to use double comma as delimiter.

Note 2: notice the 4 commas: ,,,, this indicates that role2 does not have members to add, so in essence it means between the 4 commas is no input for member to that index/item (role2), i.e. ,,EMPTY,,.

6
  • 1
    embedded-in a-string semicolons will work. it's only the ones that are NOT in strings that are seen as command delimiters. ///// is there a reason you don't use something like -RoleMember 'Role_A;Person_1,Person_2', 'Role_B;Person_2', 'Role_4;Person_1,Person_5'? Commented Jul 30, 2019 at 21:06
  • @Lee_Dailey TBH, the script is too complicated to change. i wouldnt know how to parse an input like that. i can make one common variable called $RoleMember per your suggestion, but then to minimize the amount of changes required for my script, i'd need to set each of the $CUBE_ROLE and $CUBE_MEMBER variables to the parsed $RoleMember combined input, which i wouldnt mind if thats not gonna require much changes to my existing script. Commented Jul 30, 2019 at 21:15
  • I would recommend using hashtables instead of arrays with two members. Commented Jul 30, 2019 at 21:38
  • @Cataster - if your script is that complex ... then you likely need to break it into functions internally that handle the strongly recommended minimum in each. one func for one narrow thing. then rework your script. ///// if that is not doable, then you need to write a pre-processor script that gathers the info, formats it as needed, and then submits it to the "too big to change" script. ///// however, any time a script is "too big to change" or "too complex to change" ... you almost certainly need to rewrite it. Commented Jul 30, 2019 at 22:13
  • 1
    @Cataster - real life ... [grin] ///// still, you CAN write a pre-processor for it to handle complex inputs. Commented Jul 30, 2019 at 22:23

3 Answers 3

2

If you really want to stick with this parameter format, you can create the desired output array as follows:

$roles = 'role1,role2,role3,role4' -split ','
$members = 'member1,member2,,,,member3,,member4' -split ',,'

$i = 0
$array = @(foreach ($role in $roles) {
  , ($role, $members[$i++])
})

Note that if you pass your arguments from PowerShell, you need to quote them, as PowerShell will otherwise parse them as an array.

And with quoting you're free to use ; in lieu of ,,, for instance, to separate the member groups.

A better way to represent the argument data for later processing is to create an array of custom objects rather than a nested array:

$roles = 'role1,role2,role3,role4' -split ','
$members = 'member1,member2,,,,member3,,member4' -split ',,'

$i = 0
$array = @(foreach ($role in $roles) {
   [pscustomobject] @{
     Role = $role
     Members = $members[$i++] -split ','
   }
})

Each object in $array now has a .Role and a .Members property, the latter containing the individual members as a an array of strings.

Alternatively, you could create a[n ordered] hashtable from the input, keyed by role name, but that is only necessary if you need to access roles by name or if you wanted to rule out duplicate roles having been specified.


Here's an alternative argument format that is easier to understand:

$rolesAndMembers = 'role1 = member1,member2 ; role2= ; role3=member3 ; role4=member4'

$array = @(foreach ($roleAndMembers in ($rolesAndMembers -replace ' ' -split ';')) {
  $role, $members = $roleAndMembers -split '='
  [pscustomobject] @{
    Role = $role
    Members = $members -split ','
  }
})
Sign up to request clarification or add additional context in comments.

Comments

2

Your parameter format is rather bizarre, but here's one way:

$roles = 'role1,role2,role3,role4' -split ','
$members = 'member1,member2,,,,member3,,member4' -split ',,'

$result = @()
for ( $i = 0; $i -lt $roles.Count; $i++ ) {
  $result += ,@($roles[$i],$members[$i])
}

I would recommend redesigning the script to use standard PowerShell parameters (the engineering effort would be worth it, IMO).

Comments

1

I'd strongly recommend using hashtables/dictionaries to pass these role mappings:

param(
    [System.Collections.IDictionary]$RoleMembers
)

# now we can access each mapping by role name:
$RoleMembers['role1'] # member1, member2

# or iterate over them like an array:
foreach($role in $RoleMembers.Keys){
    $RoleMembers[$role]
}

You could use one of the construct the input argument from your current input strings:

$roles = 'role1,role2,role3,role4' -split ','
$members = 'member1,member2,,,,member3,,member4' -split ','

$roleMembers = @{}

for ($i = 0; $i -lt $roles.Count; $i++) {
  # `Where Length -ne 0` to filter out empty strings
  $roleMembers[$roles[$i]] = $members[($i*2)..($i*2+1)] |Where Length -ne 0
}

7 Comments

Your definition for $members is inaccurate. OP really does mean -split ',,'. It would be better if they had used ; for the delimiter, like so: $members = 'member1,member2;;member3;member4' -split ';'.
@BaconBits i thought at first i wanst able to use ; so i stuck with the alternative double commas. but Lee_Dailey explained if i quote them i can use semicolon, which i am fine with.
so even with or without semicolon, i am getting this incorrect output (trying the construct solution): role1 member1,member2 role3 role4 role2 {member3, member4}
@Cataster note that the hashtable doesn't retain the order, try: $roleMembers.GetEnumerator() |sort Name
thanks, that does take care of the ordering issue, the output is still incorrect though. role2 is getting values {member3, member4}, and role3 and role4 are empty. the correct output would be: role1 has member1, member2. role2 is empty. role3 has member3, and role4 has member4 in this example
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.