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 NtAccountName 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)]$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.*" } elseif($item -match '^((OU|CN)=([\w\d\s_-]+))*,DC=([\w\d\s_-]+),DC=(\w+)$') { $SamAccountName = '*' $SearchRoot = $item } else { $SamAccountName = $item $domain = '*' $Searchroot = ($global:ADs) -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 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.*" } elseif($item -like '*@*') { $SamAccountName,$domain = $item.split('@') $domain=$domain.Split('.')[0] $Searchroot = ($global:ADs) -like "$domain.*" } elseif($item -match '^((OU|CN)=([\w\d\s_-]+))*,DC=([\w\d\s_-]+),DC=(\w+)$') { $SamAccountName = '*' $SearchRoot = $item } else { $SamAccountName = $item $domain = '*' $Searchroot = ($global:ADs) -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 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 mstsallowlogon givenname codepage objectcategory description usnchanged instancetype 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 -like 'Password') { # $pwdlastset = $item.properties.pwdlastset $item.setpassword($Property.Value) | Out-Null } else { switch ($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' { $Item.InvokeSet('AllowLogon',$Property.Value) $Item.CommitChanges() } 'BalOnly' { $Item.InvokeSet('AllowLogon',!$Property.Value) $Item.CommitChanges() } default { $Item.Put($Property.name, @($Property.Value)) | Out-Null } } $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-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 '^((OU|CN)=([\w\d\s_-]+))*,DC=([\w\d\s_-]+),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 |