none
repertorier les serveurs ou le compte administrateur local est utilisé RRS feed

  • Question

  • Bonjour,

    Dans le besoin de lister les serveurs ainsi qu'un certain groupe de machine dans mon AD qui utilisent encore le compte admin Local, j'ai créé un petit script:

     $adsi = [ADSI]"WinNT://MonServeur"
    
    $adsi.Children | where {$_.SchemaClassName -eq 'user'} | ft name,lastlogin 

    Ce script me permet de lister cela mais poste par poste.

    Je souhaiterai l'appliquer à une OU mais je ne vois pas trop comment procéder...

    Merci pour votre aide

    mercredi 2 septembre 2020 09:42

Réponses

  • bonjour grobabs

    Tel quel ton code ne donnera pas le résultat attendu.

    • Il faut déjà que tu rende le code non dépendant de la machine sur laquelle il va être exécuté.
    • J'ai également teste ton code, il retourne l'ensemble des comptes et leur lastLogin et pas seulement le compte recherché
    • Il n'y a pas de gestion des erreurs (OK, à cette étape ce n'est pas très grave)

    cela pourrait donner quelque chose comme ça pour une recherche sur n'importe quelle machine

    # Compte recherché
    $SearchAccount = "Administrateur"
    $adsi = [ADSI]"WinNT://$Env:COMPUTERNAME"
    
    $adsi.Children | 
        Where-Object {($_.SchemaClassName -eq 'user') -and ($_.Name -eq $SearchAccount)} |
        Select-Object Name, LastLogin

    A cette étape, tu as un code "reusable" sur n'importe quelle machine.

    Voyons comment traiter la suite. Comment obtenir la liste des machines d'une - et même de plusieurs OUs ?

    Get-ADComputer -SearchBase retourne la liste des machines dans le DN passé en paramètre -SearchBase.

    On y est, mettons ça en musique

    #region Variables
    # Compte recherché
    $SearchAccount = "Administrateur"
    # DN de l'OU sur laquelle rechercher. Si plusieurs, les séparer par une virgule
    $OU = "OU=Domain Controllers,DC=LAB,DC=LOCAL"
    #endregion Variables
    
    $Computers = foreach ($Obj in $OU)
        {
        # Pour chaque OU qu'il y a dans la liste des OU, collecte des machines
        Get-ADComputer -SearchBase $Obj -Filter * 
        }
    # A cette étape, tu auras la liste complète de tes machines sur lesquels agir
    # plus qu'à faire une boucle foreach pour récupérer et mettre le tout dans une variable
    $Result = foreach ($comp in $Computers)
        {
        $adsi = [ADSI]"WinNT://$($comp.Name)"
        $adsi.Children | 
        Where-Object {($_.SchemaClassName -eq 'user') -and ($_.Name -eq $SearchAccount)} |
        Select-Object Name, LastLogin
        }
    
    # Et maintenant je sors le résultat
    # en console
    $Result
    # dans un fichier
    $Result | Out-File "$PSScriptRoot\AdministreursInUse-Au-$(Get-Date -f "dd-MM-yy").txt" 
    

    Pas mal, mais encore aucune gestion des erreurs. Il va falloir gérer cela. Que se passe-t-il si on n'arrive pas à joindre une machine distante (hors ligne par exemple) ? Comment gérer cela ?

    Un traitement par Try ... Catch ... peut être une réponse. Reprenons le code et changeons donc dans les boucles foreach.

    try

    {

    Do-Something -ErrorActionStop

    # Il est important de mettre le paramètre -ErrorAction Stop afin qu'en cas d'erreur dans le try,

    # on envoi bien vers le catch. } catch { # On trap l'erreur dans la variable automatique $_ Write-Output "Houps ! Une erreur est survenue : $_" }

    Ici ce n'est qu'un code exemple. Imaginons que tu te trompes dans les DN des OUs cibles. La cmdlet GetAdComputer dans sa boucle foreach va se planter. Si tu remplace le Do-Something -ErrorAction Stop ci-dessus par Get-ADComputer ... -ErrorAction Stop, tu auras ta gestion des erreurs humaines pour les OUs cibles.

    et pour le traitement ADSI ? Est-ce réellement utile ? Tu n'interroges pas les machines mais l'AD.

    Tel quel le script est donc réutilisable maintenant, comment faire tourner tout cela ?

    Réponse : Une tâche planifiée idéalement sur n'importe quel serveur (pas ton PC car il peut être éteint). Un serveur d'administration par ex.

    La tâche planifiée doit tourner avec quel compte ?

    Réponse : LocalSystem ne convient pas. En effet, LocalSystem n'a aucun droit pour faire une query sur l'AD et les queries en anonymous ne sont pas autorisées by design (et c'est tant mieux pour la sécurité). Un simple compte de domaine (membre uniquement de Domain users) - dédié à cette tâche - suffira. Ne pas oublier de mettre le mot de passe en "never expires", afin de ne pas voir ta tâche  ne plus tourner quand viendra le temps de changer le mot de passe. Ce compte n'est pas destiner à ouvrir une session avec. Idéalement, il devrait y avoir une GPO qui s'applique à l'OU dans laquelle tu le mets avec "DOn't logon interactively", mais passons pour le moment. Ta tâche planifiée doit tourner avec ce compte : saisir le login et le password et ça va tourner. Houps, ce compte n'a aucun droit sur le serveur ! Ajoute donc ce compte dans le groupe Administrateur local de la machine et le tour est joué.

    Nota : Il est important de noter sur quelle (s) machine (s) (oui, tu peux l'utiliser sur d'autres machines pour faire la même chose) ce compte tourne. Parce que si tu changes le mot de passe, ça va s'arrêter partout, ... alors il vaut mieux prévenir que guérir :-)

    Tel que décrit, le script n'est pas destiné à un usage interactif, mais à un usage planifié sans intervention humaine. On peut même envisager des améliorations  (autre type de sortie, envoi par mail du résultat dans le corps du mail ou en attachement, ...).

    MOT FINAL : L'objectif recherché ici n'est pas de te fournir un code tout cuit prêt à utiliser, mais de t'expliquer la démarche pour :

    - Faire du code réutilisable

    - Faire du code qui ne nécessite aucune action humaine

    - Faire du code qui gère les erreurs

    Bref être efficace quand tu veux scripter. Ma démarche personne  est la suivante :

    • J'identifie la cmdlet qui me donne le résultat attendu
    • J'étends alors le périmètre d'action avec une boucle foreach
    • J'ajoute la gestion des erreurs, la mise en place d'un logging du script (conseillé EZLog, module PS qui est une simple tuerie. Perso, je l'utilise comme sur l'exemple3 qui est donné sur le Github du module.).
    • Je documente le script (Synopsis, Exemples, ...) comme il faut.

    Bon scripting

    Olivier

    jeudi 3 septembre 2020 06:34

Toutes les réponses

  • bonjour grobabs

    Tel quel ton code ne donnera pas le résultat attendu.

    • Il faut déjà que tu rende le code non dépendant de la machine sur laquelle il va être exécuté.
    • J'ai également teste ton code, il retourne l'ensemble des comptes et leur lastLogin et pas seulement le compte recherché
    • Il n'y a pas de gestion des erreurs (OK, à cette étape ce n'est pas très grave)

    cela pourrait donner quelque chose comme ça pour une recherche sur n'importe quelle machine

    # Compte recherché
    $SearchAccount = "Administrateur"
    $adsi = [ADSI]"WinNT://$Env:COMPUTERNAME"
    
    $adsi.Children | 
        Where-Object {($_.SchemaClassName -eq 'user') -and ($_.Name -eq $SearchAccount)} |
        Select-Object Name, LastLogin

    A cette étape, tu as un code "reusable" sur n'importe quelle machine.

    Voyons comment traiter la suite. Comment obtenir la liste des machines d'une - et même de plusieurs OUs ?

    Get-ADComputer -SearchBase retourne la liste des machines dans le DN passé en paramètre -SearchBase.

    On y est, mettons ça en musique

    #region Variables
    # Compte recherché
    $SearchAccount = "Administrateur"
    # DN de l'OU sur laquelle rechercher. Si plusieurs, les séparer par une virgule
    $OU = "OU=Domain Controllers,DC=LAB,DC=LOCAL"
    #endregion Variables
    
    $Computers = foreach ($Obj in $OU)
        {
        # Pour chaque OU qu'il y a dans la liste des OU, collecte des machines
        Get-ADComputer -SearchBase $Obj -Filter * 
        }
    # A cette étape, tu auras la liste complète de tes machines sur lesquels agir
    # plus qu'à faire une boucle foreach pour récupérer et mettre le tout dans une variable
    $Result = foreach ($comp in $Computers)
        {
        $adsi = [ADSI]"WinNT://$($comp.Name)"
        $adsi.Children | 
        Where-Object {($_.SchemaClassName -eq 'user') -and ($_.Name -eq $SearchAccount)} |
        Select-Object Name, LastLogin
        }
    
    # Et maintenant je sors le résultat
    # en console
    $Result
    # dans un fichier
    $Result | Out-File "$PSScriptRoot\AdministreursInUse-Au-$(Get-Date -f "dd-MM-yy").txt" 
    

    Pas mal, mais encore aucune gestion des erreurs. Il va falloir gérer cela. Que se passe-t-il si on n'arrive pas à joindre une machine distante (hors ligne par exemple) ? Comment gérer cela ?

    Un traitement par Try ... Catch ... peut être une réponse. Reprenons le code et changeons donc dans les boucles foreach.

    try

    {

    Do-Something -ErrorActionStop

    # Il est important de mettre le paramètre -ErrorAction Stop afin qu'en cas d'erreur dans le try,

    # on envoi bien vers le catch. } catch { # On trap l'erreur dans la variable automatique $_ Write-Output "Houps ! Une erreur est survenue : $_" }

    Ici ce n'est qu'un code exemple. Imaginons que tu te trompes dans les DN des OUs cibles. La cmdlet GetAdComputer dans sa boucle foreach va se planter. Si tu remplace le Do-Something -ErrorAction Stop ci-dessus par Get-ADComputer ... -ErrorAction Stop, tu auras ta gestion des erreurs humaines pour les OUs cibles.

    et pour le traitement ADSI ? Est-ce réellement utile ? Tu n'interroges pas les machines mais l'AD.

    Tel quel le script est donc réutilisable maintenant, comment faire tourner tout cela ?

    Réponse : Une tâche planifiée idéalement sur n'importe quel serveur (pas ton PC car il peut être éteint). Un serveur d'administration par ex.

    La tâche planifiée doit tourner avec quel compte ?

    Réponse : LocalSystem ne convient pas. En effet, LocalSystem n'a aucun droit pour faire une query sur l'AD et les queries en anonymous ne sont pas autorisées by design (et c'est tant mieux pour la sécurité). Un simple compte de domaine (membre uniquement de Domain users) - dédié à cette tâche - suffira. Ne pas oublier de mettre le mot de passe en "never expires", afin de ne pas voir ta tâche  ne plus tourner quand viendra le temps de changer le mot de passe. Ce compte n'est pas destiner à ouvrir une session avec. Idéalement, il devrait y avoir une GPO qui s'applique à l'OU dans laquelle tu le mets avec "DOn't logon interactively", mais passons pour le moment. Ta tâche planifiée doit tourner avec ce compte : saisir le login et le password et ça va tourner. Houps, ce compte n'a aucun droit sur le serveur ! Ajoute donc ce compte dans le groupe Administrateur local de la machine et le tour est joué.

    Nota : Il est important de noter sur quelle (s) machine (s) (oui, tu peux l'utiliser sur d'autres machines pour faire la même chose) ce compte tourne. Parce que si tu changes le mot de passe, ça va s'arrêter partout, ... alors il vaut mieux prévenir que guérir :-)

    Tel que décrit, le script n'est pas destiné à un usage interactif, mais à un usage planifié sans intervention humaine. On peut même envisager des améliorations  (autre type de sortie, envoi par mail du résultat dans le corps du mail ou en attachement, ...).

    MOT FINAL : L'objectif recherché ici n'est pas de te fournir un code tout cuit prêt à utiliser, mais de t'expliquer la démarche pour :

    - Faire du code réutilisable

    - Faire du code qui ne nécessite aucune action humaine

    - Faire du code qui gère les erreurs

    Bref être efficace quand tu veux scripter. Ma démarche personne  est la suivante :

    • J'identifie la cmdlet qui me donne le résultat attendu
    • J'étends alors le périmètre d'action avec une boucle foreach
    • J'ajoute la gestion des erreurs, la mise en place d'un logging du script (conseillé EZLog, module PS qui est une simple tuerie. Perso, je l'utilise comme sur l'exemple3 qui est donné sur le Github du module.).
    • Je documente le script (Synopsis, Exemples, ...) comme il faut.

    Bon scripting

    Olivier

    jeudi 3 septembre 2020 06:34
  • Bonjour grobabs,

    Si vous avez avancé dans votre problématique, veuillez ne pas oublier de marquer comme réponse les conseils des intervenants qui vous ont aidé. 

    Je vous remercie par avance pour votre retour.

    Cordialement,

    Biliana


    Votez! Appel à la contribution TechNet Community Support. LE CONTENU EST FOURNI "TEL QUEL" SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE. S'il vous plaît n'oubliez pas de "Marquer comme réponse" les réponses qui ont résolu votreproblème. C'est une voie commune pour reconnaître ceux qui vous ont aidé, et rend plus facile pour les autres visiteurs de trouver plus tard la résolution.

    mercredi 30 septembre 2020 13:37