AdsiPS
AdsiPS copied to clipboard
New Feature - Compare Accounts (group memberships mostly, possibly other types...)
It would be nice to be able to compare accounts to detect missing group membership for examples
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
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 :)
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)
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
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 👍 this was what i had in mind as a step two 😄 Thanks guys for your help!
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{}
}
`
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...
Thanks for your work @LxLeChat @christophekumor ! Feel free to PR if you notice any gaps