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 {
    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 d'une OU
        .DESCRIPTION
            Retoune tous les Objet ADSI Groups d'un ensemble d'OU et qui
        .PARAMETER Searchroot
            liste des DistingishedName a parcourir
        .PARAMETER samAccountName
            pattern de recherche
        .EXAMPLE
            Get-ADSIGroup
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]$NtAccountName
    )
    begin {
        $Searcher = New-Object DirectoryServices.DirectorySearcher
    }
    process {
        foreach ($Item in $NtAccountName) {
            if($item -like '*\*'){
                $domain,$SamAccountName = $item.split('\')
            } elseif($item -like '*@*') {
                $SamAccountName,$domain = $item.split('@')
            } else {
                $SamAccountName = $item
                $domain = '*'
            }
            $Searchroot = (Get-AllADs) -like "$domain*"
            $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 ntaccountName
        .DESCRIPTION
            Retoune tous les Objet ADSI Users d'un ensemble d'OU et qui
        .PARAMETER NtAccountName
            pattern de recherche
        .EXAMPLE
            Get-ADSIUser (whoami)
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]$NtAccountName
    )
    begin {
        $Searcher = New-Object DirectoryServices.DirectorySearcher
    }
    process {
        foreach ($Item in $NtAccountName) {
            if($item -like '*\*'){
                $domain,$SamAccountName = $item.split('\')
            } elseif($item -like '*@*') {
                $SamAccountName,$domain = $item.split('@')
            } else {
                $SamAccountName = $item
                $domain = '*'
            }
            $Searchroot = (Get-AllADs) -like "$domain*"
            $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 Set-ADSIPassword {
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]$NtAccountName
    )
    begin {}
    process {
        $NtAccountName | Get-ADSIUser | %{
            # $dataObject = New-Object Windows.forms.DataObject
            $login = $($_.properties.userprincipalname) -replace ('(.+)@(.+)\..+', '$2\$1')
            try {
                $Cred = Get-Credential -Message "Definir un nouveau Mdp.`r`nValider a Vide, pour generer automatiqument d'apres la stategie RGPD" -UserName $login
                $mdp = $Cred.GetNetworkCredential().Password
                if(!$mdp){ # validé a vide
                    $lesspass = $cred.UserName | Update-LessPassword
                    [System.Windows.Forms.Clipboard]::SetDataObject($lesspass.Password, $true)
                    Invoke-BalloonTip -Title 'Set LessPassword' -Message "Mdp [$($lesspass.NtAccountName)] dans le Press-Papier" -Type Info
                } else { # valide mdp Manuel
                    ([ADSI]$_.Path).setpassword($mdp)
                    [System.Windows.Forms.Clipboard]::SetDataObject($mdp, $true)
                    Invoke-BalloonTip -Title 'Set Password Manuel' -Message "Mdp [$($cred.UserName)] dans le Press-Papier" -Type Info
                }
            } catch [System.Runtime.InteropServices.ExternalException] { # echec
                Invoke-BalloonTip -Title 'Update Password' -Message "Mdp [$($cred.UserName)] dans le Press-Papier" -Type Error
                Write-LogStep -prefix "L.$($_.InvocationInfo.ScriptLineNumber)" "Change Mdp ",$_ error
            } catch { # Abandon
                Write-LogStep -prefix "L.$($_.InvocationInfo.ScriptLineNumber)" "Change Mdp ",$_ error
            }
        }
    }
    end {}
}
function Set-AdsiProperties {
    param (
        [Parameter(ValueFromPipeline = $true)] $AdsiItems = $null,
        [Parameter(ValueFromRemainingArguments=$true)]$ExtraParameters
    )
    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) {
            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}
            
            try {
                foreach ($Property in $Properties.GetEnumerator()) {
                    $Item.Properties.($Property.name) | Write-Object -back black -fore Yellow
                    $Property | Write-Object -back black -fore Cyan
                    $Item.Put($Property.name, @($Property.Value))
                    $Item.SetInfo()
                }
                Write-LogStep "Mofification ",$Property.keys ok
            } catch {
                Write-LogStep -prefix "L.$($_.InvocationInfo.ScriptLineNumber)" "Mofification [$($Property.name)]",$_ Error
            }
        }
    }
    end {}
}
Function Get-ADSIMemberOf{
    Param(
        [Parameter(ValueFromPipeline=$true)]$ADSIObject,
        $Groups = $null,
        [switch]$Recurse
    )
    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-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 samAccountName
            pattern de recherche
        .EXAMPLE
            Get-ADSIGroup
        .NOTES
            Alban LOPEZ 2019
            alban.lopez@gmail.com
            http://git/PowerTech/
        #>

    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipeline = $true)]$ComputerName
    )
    begin {
        $Searcher = New-Object DirectoryServices.DirectorySearcher
    }
    process {
        foreach ($Item in $ComputerName) {
            if($item -match "\.\w.+"){
                $SamAccountName,$domain = $item.split('.')
                $domain = $domain -join('.')
            } elseif($item -match "@\w.+") {
                $SamAccountName,$domain = $item.split('@')
            } else {
                $SamAccountName = $item
                $domain = '*'
            }

            $Searchroot = @((Get-AllADs) -like $domain)
            $Searcher.Filter = "(objectCategory=computer)"
            if($SamAccountName) {
                $Searcher.Filter = "(&(objectCategory=computer)(name=$SamAccountName))"
            }
            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 {
    }
}


# Export-ModuleMember -Function 'Convert-AdsiUsers','Convert-AdsiFactUsers'
Write-LogStep 'Chargement du module ',$PSCommandPath,"$((Get-AllADs).count) Forets" ok