Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
lazywinadmin opened this issue Oct 6, 2018 · 9 comments

Comments

@lazywinadmin
Copy link
Owner

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

@LxLeChat
Copy link

LxLeChat commented Oct 7, 2018

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

@Stephanevg
Copy link

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 :)

@lazywinadmin
Copy link
Owner Author

lazywinadmin commented Oct 7, 2018

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
Copy link
Owner Author

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

@Stephanevg
Copy link

Stephanevg commented Oct 7, 2018

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.

@lazywinadmin
Copy link
Owner Author

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

@LxLeChat
Copy link

LxLeChat commented Oct 8, 2018

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{}

}

`

@christophekumor
Copy link
Contributor

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...

@lazywinadmin
Copy link
Owner Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants