AdsiPS icon indicating copy to clipboard operation
AdsiPS copied to clipboard

New Feature - Compare Accounts (group memberships mostly, possibly other types...)

Open lazywinadmin opened this issue 7 years ago • 9 comments

It would be nice to be able to compare accounts to detect missing group membership for examples

lazywinadmin avatar Oct 06 '18 23:10 lazywinadmin

Maybe we can create a Compare-ADSIUserMembership cmdlet

Compare-ADSIUserMembership -Identity UserA -ReferenceIdentity UserB

the main code consisting of fetching both users groups, storing the result in 2 hashtables (fast) and outputting any group, in the first hashtable, not present in the second hashtable.

Output could be a psobject consisting of a 3 properties : Identity, ReferenceIdentity, NotMemberOf

For a second iteration of the cmdlet we could add pipeline support, where you pipe idendities, and the cmdlet will only support the -ReferenceIdentity parameter

"UserA","UserB","UserC" | Compare-ADSIUserMemberShipt -ReferenceIdentity UserX

LxLeChat avatar Oct 07 '18 12:10 LxLeChat

I actually really like the idea, as i would have a good use case for it.

i agree with the cmdlet description of @lxlechat.

it would be nice to have the following features:

  • allowing to return an array of groups which are identical based on a reference identiy given.
  • allow to return an array of groups which are missing based on a reference identity.

this could be implement using a switch -GetMissing (where the default behaviour would be to return an array of identical groups with the identity name.

i could image the object return could be somewhat like this:

Identity [object of type identity] Group, [array of groups]

to be discussed of course :)

Stephanevg avatar Oct 07 '18 13:10 Stephanevg

Thanks @LxLeChat @Stephanevg for looking at this! These are some good ideas.

Here are my thoughts for this function:

Scope

I think this function should cover "Account" types, which mean User, Computer, Group and Service account types

Properties to evaluate

  • memberof
  • description
  • location information ?
  • custom properties ?

Not sure all the account types have these properties, this could be evaluated at the beginning of the prop

Other idea

  • Should we only look for direct membership ? (maybe for the first version)
  • Should we look at recursive cycling ?
Group-A
  └─ Group-B
           └─ Group-C
                    └─ Group-A (recursive cycle)

lazywinadmin avatar Oct 07 '18 17:10 lazywinadmin

As discussed on the chat, we can also try to rely on Compare-Object and Get-ADSIObject instead of reinventing the wheel 😄

function Compare-ADSIObject
{param($ReferenceObject,$DifferenceObject,$Property)

# possibly use @PSBoundParameters ?
Compare-Object -ReferenceObject $ReferenceObject -DifferenceObject $DifferenceObject -Properties $property
}

Compare-ADSIObject -ReferenceObject contoso\myaccountA -DifferenceObject contoso\myaccountB -Properties memberof

lazywinadmin avatar Oct 07 '18 18:10 lazywinadmin

Hi @lazywinadmin I agree on -not to reinvinte the wheel- and using compare-Object, to write a compare-ADSIObjeccould be a good idea. I still think, the use case to ahve a specific cmdlet that returns eithers the identical/not identifcal first layer of groups, is something that I can imagine would be usefull.

I would suggest that the Compare-ADSIObject could be the base function, used by the Compare-ADSIUserMembership. This would open the door to a bunch of Compare-ADSI* functions which would allow to answer most common use cases, and still make the compare-ADSIObjectavailable to the end users for the ones that would like to have something really specific.

Stephanevg avatar Oct 07 '18 20:10 Stephanevg

@Stephanevg 👍 this was what i had in mind as a step two 😄 Thanks guys for your help!

lazywinadmin avatar Oct 08 '18 04:10 lazywinadmin

I tried this, it works.. pretty slow but it works... :)

` Function Compare-ADSIObject {

[CmdletBinding()]
PARAM (
    [Parameter(Mandatory=$True)]
    [String]$ReferenceObject ,
    [Parameter(Mandatory=$True)]
    [String]$DifferenceObject,
    [Parameter(Mandatory=$False)]
    [String]$Properties
)

## Begin Block
Begin{}

## Process Block
Process{
    ## Fetch ReferenceObject and DifferenceObject
    $RefIdentity = Get-ADSIObject -SamAccountName $PSBoundParameters['ReferenceObject']
    $DifIdentity = Get-ADSIObject -SamAccountName $PSBoundParameters['DifferenceObject']

    ## Check if bother identities are of same type
    If ( !($RefIdentity.ObjectClass -eq $DifIdentity.ObjectClass) ) {
        Throw "ReferenceObject and DifferenceObject must be of same class.."
    }

    ## Don't know if this is useful, but i though this is a good idea
    Switch -Regex ( $RefIdentity.ObjectClass ) {
        'user$'{
            $URefIdentity = Get-ADSIUser -Identity $RefIdentity.SamAccountName
            $UDifIdentity = Get-ADSIUser -Identity $DifIdentity.SamAccountName
        }
        'group$'{
            $GRefIdentity = Get-ADSIGroup -Identity $RefIdentity.SamAccountName
            $GDifIdentity = Get-ADSIGroup -Identity $DifIdentity.SamAccountName
        }
    }
    ## Reference: https://blogs.technet.microsoft.com/janesays/2017/04/25/compare-all-properties-of-two-objects-in-windows-powershell/
    $objprops = $URefIdentity | Get-Member -MemberType Property,NoteProperty | ForEach-Object Name
    $objprops += $UDifIdentity | Get-Member -MemberType Property,NoteProperty | ForEach-Object Name
    $objprops = $objprops | Sort-Object | Select-Object -Unique

    $diffs = @()
    foreach ($objprop in $objprops) {
        ## Compare each property
        $diff = Compare-Object -ReferenceObject $URefIdentity -DifferenceObject $UDifIdentity -Property $objprop
        if ($diff) {            
            $diffprops = @{
                PropertyName=$objprop
                RefValue= ( $diff | Where-Object {$_.SideIndicator -eq '<='} | ForEach-Object $($objprop) )
                DiffValue= ( $diff | Where-Object {$_.SideIndicator -eq '=>'} | ForEach-Object $($objprop) )
            }
            New-Object PSObject -Property $diffprops
            #$diffs += New-Object PSObject -Property $diffprops
        }
    }

    #if ($diffs) {return ($diffs | Select PropertyName,RefValue,DiffValue)} 

    <#
    ## If property is empty, default behavior is comparing group membership
    If ( $null -eq $PSBoundParameters['Properties'] ) {

    }
    #>
}

## End Block
End{}

}

`

LxLeChat avatar Oct 08 '18 12:10 LxLeChat

Hey guys, as i talked in the slack channel, i was working on my functions to make an Audit about AD groups in my team at work. I Adapted them to fit AdsiPS, i just made PR. I'll make derivatives of these functions to add other Compare-* features i'll try to translate your ideas and more...

christophekumor avatar Oct 12 '18 16:10 christophekumor

Thanks for your work @LxLeChat @christophekumor ! Feel free to PR if you notice any gaps

lazywinadmin avatar Oct 13 '18 01:10 lazywinadmin