Question [Fonction] Recherche objets Active Directory

Plus d'informations
il y a 7 ans 1 mois #16030 par Matthew BETTON
Bonjour,

Cette fonction permet de rechercher des objets User, Computer ou Group dans un annuaire Active Directory.

Cette fonction permet de s'affranchir de la présence d'un module (ex : ActiveDirectory des RSAT) ou d'un snappin (ex : Quest AD) sur la machine.

Ce code est bien entendu donné à titre d'exemple et peut être adapté, en fonction du besoin :)

[code:1]
Function Get-ADSIobjects {

<#
.SYNOPSIS
Récupération d'objets Active Directory

.DESCRIPTION
Ce script permet de récupérer une liste d'objets Active Directory depuis un domaine particulier.
Il peut s'agir d'objets de type : Computer, User, Group ou organizationalUnit.

.PARAMETER Name
Le nom du ou des objets à trouver dasn l'annuaire Active Directory.
Utilisez l'astérisque pour remplacer zéro ou plusieurs caractères.

.PARAMETER Class
La classe de l'objet Active Directory à chercher : 'User', 'Computer', 'Group' ou 'organizationalUnit'.

.PARAMETER LDAPpath
La chaine LDAP correspondant au domaine à requêter. Par défaut, il s'agit du domaine courant.
Cette valeur peut également permettre de préciser le chemin (OU) de recherche. Sinon, la recherche a lieu sur tout le domaine.

.PARAMETER PageSize
Le PageSize qui sera utilisé dans le cadre de la requête LDAP. par défaut, la valeur du PageSize est à 1000.
msdn.microsoft.com/fr-fr/library/ms180880%28v=vs.80%29.aspx

.PARAMETER Sizelimit
Le Sizelimit qui sera utilisé dans le cadre de la requête LDAP. par défaut, la valeur du PageSize est à 0.
msdn.microsoft.com/fr-fr/library/ms180880%28v=vs.80%29.aspx

.PARAMETER PropertiesToLoad
Spécifie la liste des attributs de chaque objet Active Directory qui seront récupérés par la requête LDAP.
Il est possible de spécifier que l'on souhaite récupérer tous les attributs de l'objet LDAP via un astérisque.

.PARAMETER Subtree
Si une OU est spécifiée dans le chemin de recherche (VOir paramètre 'LDAPpath'), ce switch permet d'indiquer que la recherche peut avoir lieu dans les sous arboressences.

.OUTPUTS
Une liste d'objets personnalisés (AD[Class]) correspondant à la liste des objets Active Directory récupérés par la requête LDAP.

.EXAMPLE
C:\PS>Get-ADSIobjects -Name TR* -Class Group

Cette commande permet de récupérer tous les groupes AD nommés 'TR*' dans le domaine 'contoso.com'

.EXAMPLE
C:\PS>Get-ADSIobjects -Name adm* -Class User -LDAPpath \"LDAP://DC=contoso,DC=com\"

Cette commande permet de récupérer tous les comptes utilisateurs nommés 'adm*' dans le domaine 'contoso.com'.
Comme les propriétés à récupérer ne sont pas spécifiées, il s'agira des propriétés par défaut ('name', 'description', 'distinguishedname').

.EXAMPLE
C:\PS>Get-ADSIobjects -Name adm* -Class User -LDAPpath \"LDAP://DC=contoso,DC=com\" -PropertiesToLoad name, distinguishedname

Cette commande permet de récupérer tous les comptes utilisateurs nommés 'adm*' dans le domaine 'contoso.com'.
Seules les propriétés Name et distinguishedName sont récupérées lors de la recherche LDAP.

#>

[CmdletBinding()]
[OutputType(\"ADUser\",\"ADComputer\",\"ADGroup\",\"ADorganizationalUnit\"«»)]
param(
[Parameter(Position=0,Mandatory=$False)]
[String]$Name = \"*\",
[Parameter(Mandatory=$True)]
[ValidateSet(\"Group\",\"Computer\",\"User\",\"organizationalUnit\"«»)]
[String]$Class,
[Parameter(Mandatory=$False)]
[String]$LDAPpath = (\"LDAP://\" + ([ADSI]\"\"«»).distinguishedname),
[Parameter(Mandatory=$False)]
[int]$PageSize = 1000,
[Parameter(Mandatory=$False)]
[int]$SizeLimit = 0,
[Parameter(Mandatory=$False)]
[String[]]$PropertiesToLoad = @('name', 'description', 'distinguishedname', 'samaccountname'),
[Parameter(Mandatory=$False)]
[Switch]$Subtree
)

Write-Debug \"Création de l'objet DirectorySearcher sur '$LDAPpath'\"
try{
$objDomain = [ADSI]$LDAPpath
$objSearcher = new-object system.DirectoryServices.DirectorySearcher($objDomain)
}
catch{
Write-Error \"Une erreur s'est produite lors de la création de l'objet DirectorySearcher sur '$LDAPpath' : $($_.Exception.Message)\"
if($objSearcher -ne $null){
$objSearcher.Dispose()
}
return $null
}

Write-Debug \"Recherche des objets Active Directory avec le filtre '$LDAPfilter' sur '$LDAPpath'\"
try{
$objSearcher.PageSize = $PageSize
$objSearcher.SizeLimit = $SizeLimit
$LDAPfilter = \"(&(objectClass=$Class)(name=$Name))\"
if($Subtree){
$objSearcher.SearchScope = \"Subtree\"
}
Foreach($Property in $PropertiesToLoad){ $objSearcher.PropertiesToLoad.Add($Property.ToLower()) | Out-Null }
$objSearcher.Filter = $LDAPfilter
$Objects = $objSearcher.FindAll()
}
catch{
Write-Error \"Une erreur s'est produite lors de la recherche des objets Active Directory avec le filtre '$LDAPfilter' sur '$LDAPpath' : $($_.Exception.Message)\"
return $null
}
finally{
if($objSearcher -ne $null){
$objSearcher.Dispose()
}
}

Write-Debug \"Création d'un ou plusieurs objets personnalisés ( Requête '$LDAPfilter' sur '$LDAPpath')\"

Foreach($Object in $Objects){
try{
$objCustom = New-Object PSObject
$objCustom.PSObject.TypeNames.Insert(0,\"AD$Class\"«»)
Foreach($PropertyName in $Object.properties.Propertynames){
if($PropertyName -ne 'adspath'){
Add-Member -InputObject $objCustom -MemberType NoteProperty -Name $PropertyName -Value $Object.properties.item($PropertyName)
}
}
$objCustom
}
catch{
Write-Error \"Une erreur s'est produite lors de la création d'un ou plusieurs objets personnalisés ( Requête '$LDAPfilter' sur '$LDAPpath') : $($_.Exception.Message)\"
}
}

}

[/code:1]

Edit : Corrections ou modification des fonctionnalités suite aux remarques de Laurent.

@ +

Matthew

Message édité par: Matthew BETTON, à: 25/09/13 21:06

Message édité par: Matthew BETTON, à: 27/09/13 07:19

Message édité par: Matthew BETTON, à: 3/10/13 20:13

Message édité par: Matthew BETTON, à: 5/10/13 23:21<br><br>Message édité par: Matthew BETTON, à: 1/11/13 15:15

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 7 ans 1 mois #16032 par Laurent Dardenne
Pour cette partie :
[code:1]
catch{
Write-Error \&quot;Une erreur s'est produite lors de la création de l'objet DirectorySearcher sur '$LDAPpath' : $($_.Exception.Message)\&quot;
return $null
}
[/code:1]
Peut être faut-il libérer l'objet ?

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 7 ans 1 mois #16034 par Matthew BETTON
Laurent Dardenne écrit:

Pour cette partie :
[code:1]
catch{
Write-Error \&quot;Une erreur s'est produite lors de la création de l'objet DirectorySearcher sur '$LDAPpath' : $($_.Exception.Message)\&quot;
return $null
}
[/code:1]
Peut être faut-il libérer l'objet ?


Merci Laurent.

Je viens de corriger.

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 7 ans 1 mois #16036 par Laurent Dardenne
Matthew BETTON écrit:

Je viens de corriger.

J'avais un doute sur le comportement du constructeur en cas d'exception. J'ai donc recherché qq infos :
[code:1]
$Code=@'
//from
//http://blogs.msdn.com/b/siddjain/archive/2009/10/12/c-quirks-finalizer-is-called-if-constructor-throws-an-exception-but-it-is-not-called-if-method-throws-an-exception.aspx?Redirected=true
public class Foo
{
public Foo(bool throwException)
{
if (throwException)
{
throw new System.InvalidOperationException();
}
}

~Foo() { System.Console.WriteLine(\&quot;destructor called\&quot;«»); }

public void Test() { throw new System.InvalidOperationException(); }
}

'@
Add-type -TypeDefinition $code

$o=10
$o=new-object foo($false)
$o -eq $null
#$false
$o
#\&quot;Foo\&quot;

$o=10
$o=new-object foo($true)
$o -eq $null
#$false
$o
#10
[/code:1]
Dans le dernier cas, si on test la valeur $null sur l'objet celui-ci renvoi $false, ce qui fait que l'appel à Dispose() peut échouer ou supprimer l'ancien objet affecté à la variable.

Voir aussi ce post et celui-ci .

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 7 ans 4 semaines #16039 par Matthew BETTON
Punaise :ohmy:

Edit : Quelques corrections.<br><br>Message édité par: Matthew BETTON, à: 27/09/13 07:18

Connexion ou Créer un compte pour participer à la conversation.

Plus d'informations
il y a 7 ans 3 semaines #16079 par Laurent Dardenne
Après relecture, m'est avis que ceci :
[code:1]$objList += $objCustom[/code:1]
Peut-être optimisé.
Mais je ne sais pas quel comportement tu voulais offrir en renvoyant tjr une collection, qui peut être vide.
D'émettre l'objet directement dans le pipe reste possible.
De typer l'objet personnalisé ne serait pas de trop.

Et pour ceci :
[code:1]
Write-Error \&quot;Une erreur s'est produite lors de la création d'un ou plusieurs objets personnalisés ...\&quot;
$objList = $null

[/code:1]
Le fait de stopper le script est peut être à revoir, car si j'ai plusieurs objets en erreur pour des causes différentes, je dois relancer le script autant de fois qu'il y a d'erreur.

Une autre approches serait d'implémenter le paramètre -Strict .

Enfin pour $LDAPpath je le placerais en Mandatory, car par défaut l'appel échouera.
Il est possible de configurer ce paramètre, mais cela dépend de l'usage de chacun ( global, module ou script).

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.180 secondes
Propulsé par Kunena