Issue
My code below works in every instance except for if one object is $null
and the other object has one item. When that situation occurs the output becomes 1 letter like it is indexing and I am not sure why.
How do I combine the two objects to make a final report?
$ADGroups = Get-ADPrincipalGroupMembership -Identity $UserSam | Select-Object distinguishedName, name | Where-Object { ($_.distinguishedName -ne 'CN=Domain Users,CN=Users,DC=com') }
#record AD groups
$ADResult = @()
if ($null -eq $ADGroups) {
Write-Warning "No AD Groups"
$ADResult = [PSCustomObject]@{
ADGroups = @()
ADGroupsdistinguishedName = @()
}
}
Else {
$ADResult = $ADGroups | ForEach-Object {
[PSCustomObject]@{
ADGroups = $_.name
ADGroupsdistinguishedName = $_.distinguishedName
}
}
}
#============= Now Google, get user groups and record
$GoogleGroups = gam print groups member $email members managers owners | ConvertFrom-Csv
# Record Google Groups
$GResult = @()
If ($null -eq $GoogleGroups) {
Write-Warning "No Google Groups"
$GResult = [PSCustomObject]@{
GoogleGroups = @()
Role = @()
}
}
Else {
$group = $null
$GResult = ForEach ($group in $GoogleGroups) {
#this records what role the user had in the group(s)
$GoogleMember = gam print group-members group $group.email members | ConvertFrom-Csv | Select-Object -ExpandProperty email
$Role = $null
If ( $GoogleMember -contains $EMAIL) {
$Role = 'Member'
}
Else {
$GoogleManager = gam print group-members group $group.email managers | ConvertFrom-Csv | Select-Object -ExpandProperty email
If ($GoogleManager -contains $EMAIL) {
$Role = 'Manager'
}
Else {
$Role = 'Owner'
}
}
[PSCustomObject]@{
GoogleGroups = $group.email
Role = $role
}
$group = $null
}
}
# ---------now report that will be dropped off at end
[int]$max = $ADResult.count
if ([int]$GResult.count -gt $max) { [int]$max = $GResult.count }
If ($max -eq 1 -or $max -eq 0) {
$Result = [PSCustomObject]@{
PrimaryEmail = $email
Title = $UserInfo.title
Department = $UserInfo.Department
Manager = $Manager
ADGroupName = $ADResult.ADGroups
ADGroupNameDistinguishedName = $ADResult.ADGroupsdistinguishedName
GoogleGroup = $GResult.GoogleGroups
Role = $GResult.role
DateOfSeparation = (Get-Date).ToString("yyyy_MM_dd")
UserDistinguishedName = $UserInfo.distinguishedName
UserOU = $UserInfo.Ou
PrimaryGroup = $UserInfo.primaryGroup.Split('=').Split(',')
}
}
Else {
$Result = for ( $i = 0; $i -lt $max; $i++) {
[PSCustomObject]@{
PrimaryEmail = $email
Title = $UserInfo.title
Department = $UserInfo.Department
ADGroupName = $ADResult.ADGroups[$i]
ADGroupNameDistinguishedName = $ADResult.ADGroupsdistinguishedName[$i]
GoogleGroup = $GResult.GoogleGroups[$i]
Role = $GResult.role[$i]
DateOfSeparation = (Get-Date).ToString("yyyy_MM_dd")
UserDistinguishedName = $UserInfo.distinguishedName
UserOU = $UserInfo.Ou
PrimaryGroup = $UserInfo.primaryGroup.Split('=').Split(',')[$i]
}
}
}
$Result | Export-Csv 'C:\temp\Groups.csv' -NoTypeInformation
Solution
Going by the abstract description of your problem:
You’re seeing an unfortunate asymmetry in PowerShell:
-
In the pipeline, a
[string]
instance is considered a single object.PS> ('foo' | Measure-Object).Count 1
-
With respect to indexing, it is considered an array of characters.
PS> 'foo'[0] f
A general feature of capturing a PowerShell pipeline‘s output is that if a command situationally outputs just a single object, that object is captured as-is, whereas two or more output objects result in a regular PowerShell array, of type [object[]]
.
-
Typically, this isn’t a problem, because PowerShell’s unified handling of scalars and collections allows you to index even into a scalar (single object), i.e. to implicitly treat a single object as if it were a single-element array:
PS> (Write-Output 42, 43)[0] 42 PS> (Write-Output 42)[0] 42 # still OK, even though only *one* object was output; same as: (42)[0]
-
However, with a single
[string]
instance as the output it becomes a problem, for the reasons stated above:PS> (Write-Output 'foo', 'bar')[0] foo # OK PS> (Write-Output 'foo')[0] f # !! Indexing into a *single string* treats it as *character array*
The same applies to values returned via member-access enumeration, perhaps surprisingly :
PS> (Get-Item $HOME, /).FullName[0]
C:\Users\Jdoe
PS> (Get-Item $HOME).FullName[0]
C # !! Indexing into a *single string* treats it as *character array*
Workarounds:
-
Enclose the command of interest in
@(...)
, the array-subexpression operator so as to ensure that its output is always considered an array.PS> @(Write-Output 'foo')[0] foo # OK
-
Alternatively, when capturing a command’s output in a variable, type-constrain that variable to
[array]
(same as[object[]]
) or a strongly typed array,[string[]]
:PS> [array] $output = Write-Output 'foo'; $output[0] foo # OK
Answered By – mklement0
Answer Checked By – Mary Flores (BugsFixing Volunteer)