PSAdsi.psm1


# ipmo .\RDS.DragonFly.psd1 -Force; rds LOGEXI@OPEN.ADDS
# https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx

function Get-AllADs {
    <#
        .SYNOPSIS
            Liste toutes le Foret accessible
        .DESCRIPTION
            les ForestName : Current + AllTrustRelationships
            Prefer to Use $global:ADs
        .EXAMPLE
            Get-AllADs
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
        #>


    begin {
    }
    process {
        if (!$global:ADs){
            $global:ADs = @()
            try {
                $global:ADs += ([System.DirectoryServices.ActiveDirectory.Domain]::getCurrentDomain()).Forest.name
                $global:ADs += ([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().GetAllTrustRelationships()).targetName
                $global:ADs += ([System.DirectoryServices.ActiveDirectory.Domain]::getCurrentDomain().GetAllTrustRelationships()).targetName
            } catch {
                Write-LogStep 'Chargement [Domain-Forest] ',$_ error
            }
            [array]::sort($global:ADs)
        }
    }
    end {
        return $global:ADs
    }
}
function Get-ADSIGroup {
    <#
        .SYNOPSIS
            liste tous les Groups qui correcponde a un pattern
        .DESCRIPTION
            recherche dans toute les AD
        .PARAMETER NtGroupName
            pattern de recherche
        .EXAMPLE
            Get-ADSIGroup 'MyDomain\Groupe *'
        .EXAMPLE
            'Groupe *@Domain.tld' | Get-ADSIGroup
        .EXAMPLE
            Get-ADSIGroup 'Groupe admin@*.tld'
        .EXAMPLE
            Get-ADSIGroup '*\*'
        .EXAMPLE
            'OU=compta,DC=open,DC=tld' | Get-ADSIGroup
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]
            [alias("NtAccountName")]
                $NtGroupName
    )
    begin {
        $Searcher = New-Object DirectoryServices.DirectorySearcher
    }
    process {
        foreach ($Item in $NtGroupName) {
            if($item -like '*\*'){
                $domain,$SamAccountName = $item.split('\')
                $Searchroot = ($global:ADs) -like "$domain.*"
                Write-Verbose "NtAccount > $Item"
            } elseif($item -like '*@*') {
                $SamAccountName,$domain = $item.split('@')
                $domain=$domain.Split('.')[0]
                $Searchroot = ($global:ADs) -like "$domain.*"
                Write-Verbose "UPN > $Item"
            } elseif($item -match '^(CN=[^,]+,)?(OU=[^,]+)*,DC=([^,]+),DC=(\w+)$') {
                $SamAccountName = '*'
                $SearchRoot = $item
                Write-Verbose "OU > $Item"
            } else {
                $SamAccountName = $item
                $domain = '*'
                $Searchroot = ($global:ADs) -like "$domain.*"
                Write-Verbose "FULL > $Item"
            }
            $Searcher.Filter = "(objectCategory=group)"
            if($SamAccountName) {
                $Searcher.Filter = "(&(objectCategory=group)(samAccountName=$SamAccountName))"
            }
            # (&(objectClass=group)(email=*))
            foreach($AD in $Searchroot){
                $Searcher.SearchRoot = "LDAP://$($AD -replace('^(.+)\.(.+)$','DC=$1,DC=$2'))"
                try {
                    $Searcher.FindAll() | ?{$_} # | ForEach-Object {[adsi]$_.path}).Properties
                    Write-LogStep "Collecte ADSI [$AD]",$samAccountName ok
                } catch {
                    Write-LogStep "Collecte ADSI [$SamAccountName@$AD]",$_ error
                }
            }
        }
    }
    end {}
}
function Get-ADSIUser {
    <#
        .SYNOPSIS
            liste tous les Users d'une par le pattern ntaccountName
        .DESCRIPTION
            Retoune tous les Objet ADSI Users d'un ensemble d'OU et qui
        .PARAMETER NtAccountName
            pattern de recherche
        .EXAMPLE
            Get-ADSIUser (whoami)
        .EXAMPLE
            Get-ADSIUser 'jDoe@domain.tld'
        .EXAMPLE
            '*\jDoe' | Get-ADSIUser
        .EXAMPLE
            'OU=paris,OU=User,DC=open,DC=tld' | Get-ADSIUser
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]$NtAccountName
    )
    begin {
        $Searcher = New-Object DirectoryServices.DirectorySearcher
    }
    process {
        foreach ($Item in $NtAccountName) {
            if($item -like '*\*'){
                $domain,$SamAccountName = $item.split('\')
                $Searchroot = ($global:ADs) -like "$domain.*"
                Write-Verbose "NtAccount > $Item"
            } elseif($item -like '*@*') {
                $SamAccountName,$domain = $item.split('@')
                $domain=$domain.Split('.')[0]
                $Searchroot = ($global:ADs) -like "$domain.*"
                Write-Verbose "UPN > $Item"
            } elseif($item -match '^(CN=[^,]+,)?(OU=[^,]+)*,DC=([^,]+),DC=(\w+)$') {
                $SamAccountName = '*'
                $SearchRoot = $item
                Write-Verbose "OU > $Item"
            } else {
                $SamAccountName = $item
                $domain = '*'
                $Searchroot = ($global:ADs) -like "$domain.*"
                Write-Verbose "FULL > $Item"
            }
            $Searcher.Filter = "(objectCategory=user)"
            if($SamAccountName) {
                $Searcher.Filter = "(&(objectCategory=user)(samAccountName=$SamAccountName))"
            }
            # (&(objectClass=user)(email=*))
            foreach($AD in $Searchroot){
                $Searcher.SearchRoot = "LDAP://$($AD -replace('^(.+)\.(.+)$','DC=$1,DC=$2'))"
                try {
                    $Searcher.FindAll() | ?{$_} # | ForEach-Object {[adsi]$_.path}).Properties
                    Write-LogStep "Collecte ADSI [$AD]",$samAccountName ok
                } catch {
                    Write-LogStep "Collecte ADSI [$SamAccountName@$AD]",$_ error
                }
            }
        }
    }
    end {}
}
# function Get-ADSIPwdPolicy {
# <#
# .SYNOPSIS
# liste toutes les strategies de Pwd
# .DESCRIPTION
# Retoune tous les Objet ADSI Password Settings
# .PARAMETER Name
# pattern de recherche
# .EXAMPLE
# Get-ADSIPwdPolicy 'open\*'
# .EXAMPLE
# Get-ADSIPwdPolicy
# .NOTES
# Alban LOPEZ 2019
# alban.lopez@gmail.com
# #>
# [CmdletBinding()]
# param (
# [Parameter(ValueFromPipeline = $true)]$NtAccountName
# )
# begin {
# $Searcher = New-Object DirectoryServices.DirectorySearcher
# }
# process {
# foreach ($Item in $NtAccountName) {
# if($item -like '*\*'){
# $domain,$SamAccountName = $item.split('\')
# $Searchroot = ($global:ADs) -like "$domain.*"
# } elseif($item -like '*@*') {
# $SamAccountName,$domain = $item.split('@')
# $domain=$domain.Split('.')[0]
# $Searchroot = ($global:ADs) -like "$domain.*"
# } else {
# $SamAccountName = $item
# $domain = '*'
# $Searchroot = ($global:ADs) -like "$domain.*"
# }
# $Searcher.Filter = "(Name=$SamAccountName)"
# foreach($AD in $Searchroot){
# $Searcher.SearchRoot = "LDAP://CN=Password Settings Container,CN=System,$($AD -replace('^(.+)\.(.+)$','DC=$1,DC=$2'))"
# try {
# $Searcher.FindAll() | ?{$_} # | ForEach-Object {[adsi]$_.path}).Properties
# Write-LogStep "Collecte ADSI [$AD]",$samAccountName ok
# } catch {
# Write-LogStep "Collecte ADSI [$SamAccountName@$AD]",$_ error
# }
# }
# }
# }
# end {}
# }
# function Get-ADSIUserPwdPolicy {
# <#
# .SYNOPSIS
# recherche la strategies de Pwd
# .DESCRIPTION
# Retoune user Password Settings
# .PARAMETER Name
# pattern de recherche
# .EXAMPLE
# Get-ADSIObject (whoami)
# .EXAMPLE
# Get-ADSIPwdPolicy
# .EXAMPLE
# '*\jDoe' | Get-ADSIObject
# .EXAMPLE
# 'OU=paris,OU=User,DC=open,DC=tld' | Get-ADSIObject
# .NOTES
# Alban LOPEZ 2019
# alban.lopez@gmail.com
# #>
# [CmdletBinding()]
# param (
# [Parameter(ValueFromPipeline = $true)]$NtAccountName
# )
# begin {
# $Searcher = New-Object DirectoryServices.DirectorySearcher
# }
# process {
# foreach ($Item in $NtAccountName) {
# $users = Get-ADSIUser $item
# foreach ($user in $users) {
# $AllMemberOf = @()
# $memberOf = ($user | Get-ADSIMemberOf -Recurse)
# $AllMemberOf += $memberOf.MemberOf.distinguishedName
# $AllMemberOf += $MemberOf.NestedMemberOf.distinguishedName
# # $AllMemberOf | Write-Object -backGroundColor Black -foreGroundColor Cyan
# Get-ADSIPwdPolicy "$(($user.properties.distinguishedname -split(',DC='))[-2])\*" | ?{
# # $_.properties.'msds-psoappliesto' | Write-Object -backGroundColor Black -foreGroundColor red
# $AllMemberOf -contains $_.properties.'msds-psoappliesto'
# }
# }
# }
# }
# end {}
# }
function Set-AdsiProperties {
    <#
        .SYNOPSIS
            Modifie un ensemble de proprietes sur chacun des objets
        .DESCRIPTION
            selement les propriete accessible en ecriture directe
        .PARAMETER AdsiItems
            Liste des compte AD
        .PARAMETER ExtraParameters
            Disable
            Enable
            PasswordNeverExpire
            CantChangePassword
            TsAllow
            BalOnly

            mstsallowlogon
            givenname
            codepage
            objectcategory
            description
            usnchanged
            instancetype
            mail
            logoncount
            name
            badpasswordtime
            msds-supportedencryptiontypes
            badpwdcount
            lastlogontimestamp
            usncreated
            sn
            company
            userparameters
            objectguid
            memberof
            whencreated
            adspath
            useraccountcontrol
            cn
            countrycode
            primarygroupid
            dscorepropagationdata
            lastlogon
            msexchomaadminwirelessenable
            extensionattribute1
            [...]
            extensionattribute15
            othermailbox
            samaccountname
            lastlogoff
            displayname
            accountexpires
            userprincipalname
        .EXAMPLE
            Set-AdsiProperties -displayname 'Jhon Doe'
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
        #>

    param (
        [Parameter(ValueFromPipeline = $true)] $AdsiItems = $null,
        [Parameter(ValueFromRemainingArguments=$true)]$ExtraParameters,
        [switch]$PassThru
    )
    begin {
        $Properties = @{}
        $UnnamedParams = @()
        $Name = $null
        $ExtraParameters | ForEach-Object -Process {
            if ($_ -match "^-") {
                if ($Name) {
                    $Properties.$Name = $true
                }
                $Name = $_ -replace "^-|:$"
            } else {
                if ($Name) {
                    $Properties.$Name += $_
                    $Name = $null
                } else {
                    $UnnamedParams += $_
                }
            }
        } -End {
            if ($Name) {
                $Properties.$Name = $true
            }
        }
        # $properties | Write-Object -back black -fore Yellow
    }
    process {
        foreach ($item in $AdsiItems) {
            # $whenchanged = $item.properties.whenchanged

            # $item | Write-Object -back black -fore DarkYellow
            if ($item -is [System.DirectoryServices.SearchResult]) {
                $item = [adsi]$item.path
            }
            # elseif ($item -is [string]) {
                # if ($item -match '^LDAP:\/\/CN=(.+),(OU=([\w\d\s_-]+))*,DC=([\w\d\s_-]+),DC=(com|adds)$') {
                # $item = [adsi]$item
                # } elseif ($item -match '^CN=(.+),(OU=([\w\d\s_-]+))*,DC=([\w\d\s_-]+),DC=(com|adds)$') {
                # $item = [adsi]"LDAP://$item"
                # } elseif ($item -match '^S-1-5-21-') {
                # $item = [adsi]"LDAP://<SID=$item>"
                # } else {
            if ($item -isnot [System.DirectoryServices.DirectoryEntry]) {
                Write-LogStep "Format de parametre","[ADSI] required !" error
                break;
            }
            # $Item.Properties | ft * # %{$_.PropertyName;$_.Value}
            $Changed = @()
            foreach ($Property in $Properties.GetEnumerator()) {
                $item.GetInfo() | Out-Null # ceci reset la fille d'attente des autre .Put()
                try {
                    if ($Property.name -match '^Password$') {
                        # $pwdlastset = $item.properties.pwdlastset
                        $item.setpassword($Property.Value) | Out-Null
                    } else {
                        switch -regex ($Property.name) {
                            '^Disable$' {
                                if (!($item.Properties.useraccountcontrol.value -band 2) -eq $Property.Value) {
                                    # write-host $Item.Properties.useraccountcontrol.value,' > ' -NoNewline -fore Red
                                    $Item.Put('useraccountcontrol', $item.Properties.useraccountcontrol.value -bxor 2) | Out-Null
                                    # write-host ($Item.Properties.useraccountcontrol.value -bxor 2) -fore Red
                                }
                            }
                            '^Enable$' {
                                if ([bool]($item.Properties.useraccountcontrol.value -band 2) -eq $Property.Value) {
                                    # write-host $Item.Properties.useraccountcontrol.value,' > ' -NoNewline -fore green
                                    $Item.Put('useraccountcontrol', $item.Properties.useraccountcontrol.value -bxor 2) | Out-Null
                                    # write-host ($Item.Properties.useraccountcontrol.value -bxor 2) -fore green
                                }
                            }
                            '^PasswordNeverExpire$' {
                                if (!($item.Properties.useraccountcontrol.value -band 65536) -eq $Property.Value) {
                                    # write-host $Item.Properties.useraccountcontrol.value,' > ' -NoNewline -fore green
                                    $Item.Put('useraccountcontrol', $item.Properties.useraccountcontrol.value -bxor 65536) | Out-Null
                                    # write-host ($Item.Properties.useraccountcontrol.value -bxor 65536) -fore green
                                }
                            }
                            '^CantChangePassword$' {
                                if (!($item.Properties.useraccountcontrol.value -band 64) -eq $Property.Value) {
                                    # write-host $Item.Properties.useraccountcontrol.value,' > ' -NoNewline -fore green
                                    $Item.Put('useraccountcontrol', $item.Properties.useraccountcontrol.value -bxor 64) | Out-Null
                                    # write-host ($Item.Properties.useraccountcontrol.value -bxor 64) -fore green
                                }
                            }
                            '^(TsAllow|AllowLogon)?$' {
                                # write-host 'TsAllow' -fore red
                                $Item.InvokeSet('allowlogon', [int]$Property.Value)
                            }
                            '^BalOnly$' {
                                # write-host 'BalOnly' -fore red
                                $Item.InvokeSet('allowlogon',[int](!$Property.Value))
                            }
                            '^MemberOf$' {
                                $groups = Get-ADSIGroup -NtGroupName $Property.Value | %{[adsi]$_.Path}
                                # $groups = Get-ADSIGroup -NtGroupName 'open\groupe sotrima *' | %{[adsi]$_.Path}
                                foreach ($group in $groups) {
                                    try {
                                        $group.add($item.path) # $group.members.add($item.path)
                                    } catch {
                                        write-color '[',($error[0].Exception.innerException.gettype().BaseType),']' -ForeGroundColor Red,Gray,Red -ea 0
                                        Write-LogStep -prefix "L.$($_.InvocationInfo.ScriptLineNumber)" "",$_ error
                                    }
                                }
                            }
                            default {
                                $Item.Put($Property.name, @($Property.Value)) | Out-Null
                            }
                        }
                        $Item.CommitChanges()
                        $Item.SetInfo() | Out-Null
                    }
                    $Changed += $Property.name
                } catch {
                    Write-LogStep -prefix "L.$($_.InvocationInfo.ScriptLineNumber) %caller%" '',"[$($Property.name)]",$_ Error
                }
            }
            if ($PassThru -and $Changed) {
                $Item.refreshcache() | Out-Null
                # $item.GetInfo() | Out-Null # ceci reset la fille d'attente des autre .Put()
                $item
            }
        }
    }
    end {}
}
# -mstsallowlogon $true -givenname 'Jh0n' -codepage 1 -objectcategory 'CN=Group,CN=Schema,CN=Configuration,DC=open,DC=adds' -description 'kjg321' -usnchanged '102267828' -instancetype '5' -mail 'kjg3@f21.fr'
# -logoncount 3 -name 'J Doe' -badpasswordtime 131941170462578977 -badpwdcount '0' -lastlogontimestamp 132018623536360111 -usncreated 39795111 -sn 'JOE' -company 'kjg321'
# -userparameters 'kjg321' -objectguid 'kjg321' -memberof @('CN=Groupe SOTRIMA Global,OU=Sotrima,DC=open,DC=adds') -whencreated 'kjg321' -adspath 'kjg321' -useraccountcontrol 'kjg321' -cn 'kjg321' -countrycode 'kjg321' -primarygroupid 'kjg321' -dscorepropagationdata 'kjg321' -lastlogon 'kjg321' -msexchomaadminwirelessenable 'kjg321' -extensionattribute15 'kjg321' -othermailbox 'kjg321' -samaccountname 'kjg321' -lastlogoff 'kjg321' -displayname 'kjg321' -accountexpires 136080899111100000 -userprincipalname 'jhondhoe@open.adds'
Function Get-ADSIMemberOf{
    <#
        .SYNOPSIS
            Identifi les groupe dont est membre un Object
        .DESCRIPTION
            Membre direct et indirect (sans doublon)
        .PARAMETER ADSIObject
            Object a analyser
        .PARAMETER Recurse
            Mode recursif pour les groupe indirect
        .PARAMETER Groups
            Ne pas utiliser, reservé pour le mode recursif
        .EXAMPLE
            Get-ADSIMemberOf
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
        #>


    Param(
        [Parameter(ValueFromPipeline=$true)]$ADSIObject,
        [switch]$Recurse,
        $Groups = $null
    )
    begin {
    }
    process {
        # Write-verbose $ADSIObject.Path
        if($null -eq $Groups){
            $Groups = [PSCustomObject]@{
                MemberOf      = @()
                NestedMemberOf = @()
            }
            Foreach($Memberof in $ADSIObject.properties.memberof){
                $Group = [adsi]"LDAP://$MemberOf"
                $Groups.Memberof += $group
                if($Group.properties.memberof -and $Recurse){
                    $Groups = $group | Get-ADSIMemberOf -Groups $Groups -Recurse
                }
            }
        } else {
            Foreach($Memberof in $ADSIObject.properties.memberof){
                $path = "LDAP://$MemberOf"
                if($Groups.MemberOf.path -contains $path){
                    # write-verbose "Deja [DirectMemberOf] $path"
                }elseif($Groups.NestedMemberOf.path -contains $path){
                    # write-verbose "Deja [NestedMemberOf] $path"
                } else {
                    # write-verbose "Nouveau [NestedMemberOf] $path"
                    $Group = [adsi]$path
                    $Groups.NestedMemberof += $group
                    $Groups = $group | Get-ADSIMemberOf -Groups $Groups -Recurse
                }
            }
        }
        # Write-Object $Groups.memberOf.Path -Depth 1 -backGroundColor Black -foreGroundColor darkGreen
        # Write-Object $Groups.NestedMemberOf.Path -Depth 1 -backGroundColor Black -foreGroundColor Green
        $Groups
    }
    end {
    }
}
Function Get-ADSIMembers{
    <#
        .SYNOPSIS
            Identifi les groupe dont est membre un Object
        .DESCRIPTION
            Membre direct et indirect (sans doublon)
        .PARAMETER ADSIObject
            Object a analyser
        .PARAMETER Recurse
            Mode recursif pour les groupe indirect
        .PARAMETER Items
            Ne pas utiliser, reservé pour le mode recursif
        .EXAMPLE
            Get-ADSIMembers
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
        #>


    Param(
        [Parameter(ValueFromPipeline=$true)]$AdsiGroup,
        [switch]$Recurse,
        $Items = $null
    )
    begin {
        
    }
    process {
        # Write-Object $AdsiGroup.Path,$AdsiGroup.properties.member
        if($null -eq $Items){
            $Items = [PSCustomObject]@{
                Members       = @()
                Groups        = @()
                NestedMembers = @()
                NestedGroups  = @()
            }
            Foreach($Member in $AdsiGroup.properties.member){
                $item = [adsi]"LDAP://$Member"
                if ($item.properties.objectcategory -eq 'CN=Group,CN=Schema,CN=Configuration,DC=open,DC=adds' -and $Recurse) {
                    $Items.groups += $item
                } else {
                    $Items.Members += $item
                }
            }
            foreach ($Group in $Items.groups) {
                $Items = $Group | Get-ADSIMembers -Items $Items -Recurse # -Unique:$Unique
            }
        } else {
            Foreach($Member in $AdsiGroup.properties.member){
                $item = [adsi]"LDAP://$Member"
                if ($item.properties.objectcategory -eq 'CN=Group,CN=Schema,CN=Configuration,DC=open,DC=adds'){
                    # Write-Host ' -> ',$item.path -fore DarkYellow
                    if ($Items.NestedGroups.path -notcontains $item.path -and $Items.Groups.path -notcontains $item.path) {
                        $Items.NestedGroups += $item
                        $Items = $item | Get-ADSIMembers -Items $Items -Recurse # -Unique:$Unique
                    }
                } elseif($Items.NestedMembers.path -notcontains $item.path -and $Items.Members.path -notcontains $item.path) {
                    # Write-Host ' -> ',$item.path -fore Yellow
                    $Items.NestedMembers += $item
                } else {
                    # Write-Host ' -X ',$item.path -fore Red
                }
            }
        }
        $Items
    }
    end {
    }
}
# function Get-ADSIObject {
# <#
# .SYNOPSIS
# liste tous les Objects qui correcponde a un pattern
# .DESCRIPTION
# recherche dans toute les AD
# .PARAMETER NtGroupName
# pattern de recherche
# .EXAMPLE
# Get-ADSIGroup 'MyDomain\Groupe *'
# .EXAMPLE
# 'Groupe *@Domain.tld' | Get-ADSIGroup
# .EXAMPLE
# Get-ADSIGroup 'Groupe admin@*.tld'
# .EXAMPLE
# Get-ADSIGroup '*\*'
# .EXAMPLE
# 'OU=compta,DC=open,DC=tld' | Get-ADSIGroup
# .NOTES
# Alban LOPEZ 2019
# alban.lopez@gmail.com
# #>
# [CmdletBinding()]
# param (
# [Parameter(ValueFromPipeline = $true)]
# [alias("NtAccountName")]
# $Identity ='*',
# [validateset('user','group','computer','Container','Domain-Policy','Organizational-Unit',$null)][string]$type = $null
# )
# begin {
# $Searcher = New-Object DirectoryServices.DirectorySearcher
# switch ($type) {
# # 'group' { $filterProperty = 'samAccountName' }
# 'user' { $filterProperty = 'samAccountName' }
# # 'computer' { }
# Default { $filterProperty = 'name' }
# }
# }
# process {
# foreach ($Item in $Identity) {
# if($item -like '*\*'){
# $domain,$SamAccountName = $item.split('\')
# $Searchroot = ($global:ADs) -like "$domain.*"
# Write-Verbose "NtAccount > $Item"
# } elseif($item -like '*@*') {
# $SamAccountName,$domain = $item.split('@')
# $domain=$domain.Split('.')[0]
# $Searchroot = ($global:ADs) -like "$domain.*"
# Write-Verbose "UPN > $Item"
# } elseif($item -match '^(CN=[^,]+,)?(OU=[^,]+)*,DC=([^,]+),DC=(\w+)$') {
# $SamAccountName = '*'
# $SearchRoot = $item
# Write-Verbose "OU > $Item"
# } else {
# $SamAccountName = $item
# $domain = '*'
# $Searchroot = ($global:ADs) -like "$domain.*"
# Write-Verbose "FULL > $Item"
# }
# if($SamAccountName -and $type) {
# $Searcher.Filter = "(&(objectCategory=$type)($filterProperty=$SamAccountName))"
# } elseif($SamAccountName) {
# $Searcher.Filter = "($filterProperty=$SamAccountName)"
# } elseif($type) {
# $Searcher.Filter = "(objectCategory=$type)"
# } else {continue}
# # (&(objectClass=group)(email=*))
# foreach($AD in $Searchroot){
# $Searcher.SearchRoot = "LDAP://$($AD -replace('^(.+)\.(.+)$','DC=$1,DC=$2'))"
# try {
# $Searcher.FindAll() | ?{$_} # | ForEach-Object {[adsi]$_.path}).Properties
# Write-LogStep "Collecte ADSI [$AD]",$samAccountName ok
# } catch {
# Write-LogStep "Collecte ADSI [$SamAccountName@$AD]",$_ error
# }
# }
# }
# }
# end {}
# }

function Add-ADSIMemberOf {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)] $ADSIObject = $null,
        [string[]]$Groups = $null
    )
    begin {
        $AdsiGroup = $Groups | Get-ADSIGroup | %{[adsi]$_.Path}
    }
    process {
        foreach ($item in $ADSIObject) {
            # $item = ($item | Get-ADSIUser)
            $AdsiGroup.add($item.Path)
        }
    }
    end {}
}

function Remove-ADSIMemberOf {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)] $ADSIObject = $null,
        [string[]]$Groups = $null
    )
    begin {
        $AdsiGroup = $Groups | Get-ADSIGroup  | %{[adsi]$_.Path}
        # $AdsiGroup.Properties.distinguishedname | Write-Object -fore red
    }
    process {
        foreach ($item in $ADSIObject) {
            # $item.Properties.memberof | Write-Object -fore red -backGroundColor Black
            $RemoveGroup = $item.Properties.memberof | ?{$AdsiGroup.Properties.distinguishedname -contains $_} | %{[adsi]"LDAP://$_"}
            # $item = ($item | Get-ADSIUser)
            # $RemoveGroup.path,$item.Path | Write-Object -fore red -backGroundColor Black
            $RemoveGroup | %{$_.remove($item.Path)}
        }
    }
    end {}
}
function Get-ADSIComputer {
    <#
        .SYNOPSIS
            liste tous les Ordineteur d'une OU
        .DESCRIPTION
            Retoune tous les Objet ADSI Ordinateur d'un ensemble d'OU et qui
        .PARAMETER Searchroot
            liste des DistingishedName a parcourir
        .PARAMETER ComputerName
            pattern de recherche
        .EXAMPLE
            Get-ADSIComputer 'open\PC01'
        .EXAMPLE
            'OU=portable,OU=ordi,DC=open,DC=tld' | Get-ADSIComputer
        .EXAMPLE
            '*\PC*' | Get-ADSIComputer
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]$ComputerName
    )
    begin {
        $Searcher = New-Object DirectoryServices.DirectorySearcher
    }
    process {
        foreach ($Item in $ComputerName) {
            if($item -like '*\*'){
                $domain,$Name = $item.split('\')
                $Searchroot = ($global:ADs) -like "$domain.*"
            } elseif($item -like '*@*') {
                $Name,$domain = $item.split('@')
                $domain=$domain.Split('.')[0]
                $Searchroot = ($global:ADs) -like "$domain.*"
            } elseif($item -match '^(CN=[^,]+,)?(OU=[^,]+)*,DC=([^,]+),DC=(\w+)$') {
                $Name = '*'
                $SearchRoot = $item
            } else {
                $Name = $item
                $domain = '*'
                $Searchroot = ($global:ADs) -like "$domain.*"
            }
            $Searcher.Filter = "(objectCategory=computer)"
            if($name) {
                $Searcher.Filter = "(&(objectCategory=computer)(name=$name))"
            }
            foreach($AD in $Searchroot){
                $Searcher.SearchRoot = "LDAP://$($AD -replace('^(.+)\.(.+)$','DC=$1,DC=$2'))"
                try {
                    $Searcher.FindAll() # | ForEach-Object {[adsi]$_.path}).Properties
                    Write-LogStep "Collecte ADSI [$AD]",$name ok
                } catch {
                    Write-LogStep "Collecte ADSI [$name@$AD]",$_ error
                }
            }
        }
    }
    end {
    }
}



if (Get-Module PsWrite) {
    # Export-ModuleMember -Function Convert-RdSession, Get-RdSession
    Write-LogStep 'Chargement du module ',$PSCommandPath ok
} else {
    function Script:Write-logstep {
        param ( [string[]]$messages, $mode, $MaxWidth, $EachLength, $prefixe, $logTrace )
        Write-Verbose "$($messages -join(',')) [$mode]"
    }
}
Get-AllADs