none
Powershell et façon de coder RRS feed

  • Question

  • Bonjour,

    Je tente de commencer un peu l'apprentissage plus sérieux de powershell et je me pose quelque question sur la façon dont doivent être traiter les résultats.

    Ex : Voici une fonction :

    function Test-ADRecyclebin
    {
        $recyclebin=(Get-ADOptionalFeature -Filter 'name -like "Recycle Bin Feature"').EnabledScopes
        if ($recyclebin)
        {
            write-output -inputobject "Enabled"
    
        }
        else
        {
            write-output -inputobject "Disabled"
        }
    }


    Je ne suis pas certain qu'elle soit exploitable dans un script telle quelle. Comment faudrait il la modifier pour cela ?

    La création d'un objet qui aurait juste un attribut "corbeille" et une valeur "activé / désactivé" me semble un peu surdimensionné mais je ne sais pas vraiment quelles sont les autres possbilitées.

    Je tiens à préciser qu'en réalité, cette fonction fait parti d'un script qui me permettra d'auditer un AD en récupérant de nombreuses informations. Je suis parti du principe que je pouvais créer une fonction pour chaque groupe d'information que je récupère (ex : une fonction pour la configuration que je souhaite récupérer pour le dns, une pour la topologie complete de l'ad, une pour les roles fsmo + domaines fonctionnel + corbeille ad activé) etc etc...

    Je commence à réussir à récupérer toutes les informations que je souhaite, mais je suis bloqué lorsqu'il s'agit de comprendre comment les "stocker" pour les exploiter ensuite.

    Ps: Le but n'étant pas d'avoir un résultat affiché dans la console bien évidement.

    Merci par avance pour le temps consacré à la réponse à cette question.


    Merci de marquer comme reponses les interventions qui vous ont ete utile.



    lundi 15 juillet 2019 19:07

Toutes les réponses

  • Dans ton script global, tu créés une variable de type ArrayList

    [System.Collections.arraylist]$Result = @()

    Dans ta fonction, tu renvois le résultat obtenu

    function Test-ADRecyclebin { $recyclebin=(Get-ADOptionalFeature -Filter 'name -like "Recycle Bin Feature"').EnabledScopes if ($recyclebin) { write-output -inputobject "Enabled" $ADRecycleBin = $true } else { write-output -inputobject "Disabled"
    $ADRecycleBin = $false }
    return $ADRecycleBin }

    tu appelles la fonction

    $RecycleBin = Test-ADRecyclebin

    Tu alimentes ta nouvelle variable créée plus tôt:

    $result += [PSCustomObject]@{"Property"="ADRecycleBin";"Value"=$RecycleBin

    et quand tu as tout récupéré, tu exportes en csv

    $result | export-csv -Path .\Result.csv -Encoding UTF8 -Delimiter ";" -NoTypeinformation

    That's all



    • Modifié Bawilanemo mardi 16 juillet 2019 11:42 typo
    • Proposé comme réponse ThibaultG jeudi 18 juillet 2019 17:27
    • Non proposé comme réponse matteu31400 vendredi 19 juillet 2019 13:04
    mardi 16 juillet 2019 11:36
  • Merci pour ta réponse.

    Du coup, J'ai testé et je vois pas comment l'exploiter. Je pensais que c'était une hashtable $result mais non.

    Dans mon cas par exemple, j'ai des fonctions un peu plus "complexe" qui ont pour sortie un objet du style

    function Get-ForestInformation {
        $forest = Get-ADForest
        $domainMaster = $forest.domainnamingmaster
        $schemaMaster = $forest.schemamaster
    
        #Find FSMO role in each domain
        $forest.domains | ForEach-Object { 
            $domain = Get-ADDomain $_
    
            [PSCustomObject]@{
                Domain = $_
                DomainMaster = $domainMaster
                SchemaMaster = $schemaMaster           
                InfrastructureMaster = $domain.infrastructuremaster
                RIDMaster = $domain.RIDMaster
                PDCEmulator = $domain.PDCEmulator  
                ForestFunctionalLevel=$forest.ForestMode
                DomainFunctionalLevel=$domain.domainmode         
            }    
        }
    }

    Dans ce cas si je fais ce script

    #Test if AD RecycleBin is activated
    function Test-ADRecyclebin
    {
        $recyclebin=(Get-ADOptionalFeature -Filter 'name -like "Recycle Bin Feature"').EnabledScopes
        if ($recyclebin)
        {
            $ADRecycleBin = "Enabled"
    
        }
        else
        {
            $ADRecycleBin = "Disabled"
        }
        $ADRecycleBin
    }
    
    #FSMO roles + functional level
    function Get-ForestInformation {
        $forest = Get-ADForest
        $domainMaster = $forest.domainnamingmaster
        $schemaMaster = $forest.schemamaster
    
        #Find FSMO role in each domain
        $forest.domains | ForEach-Object { 
            $domain = Get-ADDomain $_
    
            [PSCustomObject]@{
                Domain = $_
                DomainMaster = $domainMaster
                SchemaMaster = $schemaMaster           
                InfrastructureMaster = $domain.infrastructuremaster
                RIDMaster = $domain.RIDMaster
                PDCEmulator = $domain.PDCEmulator  
                ForestFunctionalLevel=$forest.ForestMode
                DomainFunctionalLevel=$domain.domainmode         
            }    
        }
    }
    
    [System.Collections.arraylist]$Result = @()
    $recyclebin=Test-ADRecyclebin
    $forestinfo=Get-ForestInformation
    $result+=[PSCustomObject]@{"Property"="ADRecycleBin";"Value"=$recyclebin}
    $result+=[PSCustomObject]@{"Property"="forestInfo";"Value"=$forestinfo}
    
    $result

    Je me retrouve avec $result comme ca

    Sauf que je vois pas comment récupérer les informations. Dans une hashtable, j'aurai fait

    $result.adrecyclebin par exemple et il me donnerait disabled sauf que la ca ne fonctionne pas.

    Je trouve l'idée de centraliser tous les résultats de mes fonctions dans un endroit TRES intéressante, mais dans le cas présent, je ne vois pas comment les traiter ensuite.

    Le but serait dans un premier temps de faire une sortie vers un fichier texte tout simplement car le fichier CSV ne se prête pas vraiment à la sortie d'un script pour un audit AD.

    Merci d'avance pour le retour :)


    Merci de marquer comme reponses les interventions qui vous ont ete utile.

    mardi 16 juillet 2019 16:20
  • Si je modifie la fin par ça j'ai bien ce que je veux :

    $Result = @{}
    $recyclebin=Test-ADRecyclebin
    $forestinfo=Get-ForestInformation
    $result+=@{ADRecycleBin=$recyclebin}
    $result+=@{forestInfo=$forestinfo}

    J'ai une hashtable qui contient les résultats de mes traitements.

    Cela me permet donc de l'enrichir et à la fin de sortir toutes les informations dont j'ai besoin.

    Est ce que cela parait correct ? Ou je vais rencontrer un problème ?


    Merci de marquer comme reponses les interventions qui vous ont ete utile.

    mardi 16 juillet 2019 16:33
  • Si jamais quelqu'un est en mesure de me répondre ou me donner un exemple je dis pas non :)

    Merci de marquer comme reponses les interventions qui vous ont ete utile.

    vendredi 19 juillet 2019 13:05
  • Il y a plusieurs méthodes pour cela

    Soit une hashtable avec toutes les valeurs

    Soit une arraylist avec une colonne par propriété

    Je te suggère l'arraylist, car son export en CSV est très simple

    La fin d ton script ressemblerait alors à ceci:

    [System.Collections.arraylist]$Result = @()
    $recyclebin = Test-ADRecyclebin
    $forestinfo = Get-ForestInformation
    $result += [PSCustomObject]@{"Property"="ADRecycleBin";"Value"=$recyclebin;
                                  "Domain"=$forestinfo.Domain;
                                  "DomainMaster"=$forestinfo.domainMaster;
                                  "SchemaMaster"=$forestinfo.schemaMaster;
                                  "InfrastructureMaster"=$forestinfo.infrastructuremaster;
                                  "RIDMaster"=$forestinfo.RIDMaster;
                                  "PDCEmulator"=$forestinfo.PDCEmulator;
                                  "ForestFunctionalLevel"=$forestinfo.ForestMode;
                                  "DomainFunctionalLevel"=$forestinfo.domainmode
                               }
    
    
    $result
    
    $result | export-csv -Path .\Result.csv -Encoding UTF8 -Delimiter ";" -NoTypeinformation -append
    
    

    Avec l'export du csv qui ajoutes les valeurs obtenues.

    B.

    vendredi 19 juillet 2019 13:43
  • Merci pour le retour.

    Le problème c'est que parfois j'ai plusieurs objets retournés.

    Pourrais tu m'expliquer comment tu ferais par exemple si tu voulais avoir dans ton CSV ces informations :

    get-process | fl name,id

    get-childitem c:\ | fl name,lastwritetime

    Merci par avance :)


    Merci de marquer comme reponses les interventions qui vous ont ete utile.

    vendredi 19 juillet 2019 14:39
  • NB: Attention quand tu utilises FT et FL, cela doit se faire uniquement pour l'affichage et non pour sauvegarder. car cela modifie complètement l'objet en sortie.

    Testes ces deux commandes pour vérifier cela

    get-process | fl name,id | Get-Member -Type Property
    get-process | Get-Member -Type Property

    Pour la suite de ton script, test cette méthode:

    function Get-ForestInformation {
        $forest = Get-ADForest
        $domainMaster = $forest.domainnamingmaster
        $schemaMaster = $forest.schemamaster
    
        #Find FSMO role in each domain
        $forest.domains | ForEach-Object {
            $domain = Get-ADDomain $_
    
            [PSCustomObject]@{
                Domain = $_
                DomainMaster = $domainMaster
                SchemaMaster = $schemaMaster
                InfrastructureMaster = $domain.infrastructuremaster
                RIDMaster = $domain.RIDMaster
                PDCEmulator = $domain.PDCEmulator
                ForestFunctionalLevel=$forest.ForestMode
                DomainFunctionalLevel=$domain.domainmode
            }
        }
    }
    
    function Test-ADRecyclebin
    {
        $recyclebin=(Get-ADOptionalFeature -Filter 'name -like "Recycle Bin Feature"').EnabledScopes
        if ($recyclebin) {
            $ADRecycleBin = $True
        } else {
            $ADRecycleBin = $False
        }
        $ADRecycleBin
    }
    
    [System.Collections.arraylist]$Result = @()
    
    $recyclebin = Test-ADRecyclebin
    $result+=[PSCustomObject]@{"CustomPropertyType"="AD";"CustomProperty"="ADRecycleBin";"Values"=[PSCustomObject]@{Enabled=$recyclebin}}
    
    $forestinfo = Get-ForestInformation
    $result+=[PSCustomObject]@{"CustomPropertyType"="AD";"CustomProperty"="forestInfo";"Values"=$forestinfo}
    
    $Processes = Get-Process | select Name, ID
    foreach ($Process in $Processes) {
      $result+=[PSCustomObject]@{"CustomPropertyType"="Processes";"CustomProperty"="Process";"Values"=$Process}
      }
    
    $FilesList = Get-ChildItem c:\ | select name, @{Name="LastWriteTime";Expression={"{0:dd/MM/yyyy HH:mm:ss}" -f $_.LastWriteTime}}, Extension
    foreach ($File in $FilesList) {
      $result+=[PSCustomObject]@{"CustomPropertyType"="FilesList";"CustomProperty"="File";"Values"=$File}
      }
    
    
    foreach ($PropertyType in $result | select CustomPropertyType -Unique) {
      Write-host "$($PropertyType.CustomPropertyType)" -Foregroundcolor Yellow
      foreach ($item in $Result | ? {$_.CustomPropertyType -eq $PropertyType.CustomPropertyType}) {
          Write-host "$(" " * 4)$($Item.CustomProperty)" -Foregroundcolor Magenta
          Foreach ($NoteProperty in $item.Values |gm -Type NoteProperty) {
            ("$(" " * 8){0,-30}: {1}" -f $NoteProperty.name, $item.Values.$($NoteProperty.name))
            }
          }
       }

    Ce qui donne ce type de sortie:

    Avec cette méthode, tu peux exporter $Result en CSV, et l'importer pour ré-afficher le résultat de manière lisible, comme dans exemple que je te donne.

    NB: Je reformate la date de LastWriteTime car celui pourrait être différent d'un serveur à l'autre

    B.


    • Modifié Bawilanemo samedi 20 juillet 2019 19:41
    samedi 20 juillet 2019 19:40
  • Bonjour et merci beaucoup pour le temps que tu me consacre :)

    En fait, je dois faire un audit AD avec des commandes que je vais pouvoir lancer depuis un DC et qui vont être capable de me fournir toutes les informations souhaitées et d'autre que je vais devoir lancer sur chaque DC car c'est du 2008r2 et que je doute que winrm soit activé pour avoir par exemple la configuration ip d'un autre DC, sa source de temps, ...

    Je prévois donc d'avoir 2 fichiers de script.

    1 que j'éxécute sur chaque DC qui va me récupérer toutes les informations que je souhaite du DC en question et qui fait un export CSV de ces infos avec le titre du fichier qui correspond au nom du serveur.

    Voici comment il est fait actuellement

    $CSVPath = "c:\Audit-$env:COMPUTERNAME.csv"
    if(test-path $CSVPath)
    {
        Remove-Item $CSVPath -Force
    }
    
    #ressource systeme 
    $LogicalCPUNb=(Get-WmiObject –class Win32_processor | Measure-Object -Property numberoflogicalprocessors -sum).sum
    $RAM=(Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1GB
    
    
    #Dc virtuels ou physiques 
    $DCType=(get-wmiobject win32_computersystem).model
    
    #Source de temps 
    $timeSource = w32tm /query /source
    
    #paramétrage IP 
    $NetworkConfig=get-netipconfiguration
    $NetworkConfig| foreach {
        $Interface=$_.InterfaceAlias
        $IPAddress=$_.IPv4Address.ipaddress
        $Mask=$_.IPv4Address.prefixLength
        $Gateway=$_.IPv4DefaultGateway.nexthop
        #Exclusion des serveur DNS ip v6
        $DNS1=($_.DNSServer.serveraddresses | where { $_ -notlike "f*"})
        $DNS2=($_.DNSServer.serveraddresses | where { $_ -notlike "f*"})
    
        $report = New-Object psobject
        $report | Add-Member -MemberType NoteProperty -name LogicalCPUNb -Value $LogicalCPUNb
        $report | Add-Member -MemberType NoteProperty -name RAM -Value $RAM
        $report | Add-Member -MemberType NoteProperty -name DCType -Value $DCType
        $report | Add-Member -MemberType NoteProperty -name timeSource -Value $timeSource
        $report | Add-Member -MemberType NoteProperty -name Interface -Value $Interface
        $report | Add-Member -MemberType NoteProperty -name IPAddress -Value $IPAddress
        $report | Add-Member -MemberType NoteProperty -name Mask -Value $Mask
        $report | Add-Member -MemberType NoteProperty -name Gateway -Value $Gateway
        $report | Add-Member -MemberType NoteProperty -name DNS1 -Value $DNS1
        $report | Add-Member -MemberType NoteProperty -name DNS2 -Value $DNS2
    
    
        $report | export-csv -path $CSVPath -NoTypeInformation -Append
    }

    L'autre fichier correspond à toutes les autres commandes (comme celles que j'ai incluse dans ce post telle que les rôles fsmo ou les niveau fonctionnels) mais également le traitement des fichiers CSV. donc je prévois un endroit avec le traitement de tous les fichiers CSV qui seraient stockés à un emplacement et que le script importerait pour les intégrer dans le fichier de sortie qu'il génère à la fin.

    Une partie de ce fichier correspond à ça actuellement mais par rapport à ce que je viens de voir, il semblerait que ce ne soit pas une bonne façon de faire.

    $forest.domains | ForEach-Object { 
        $domain = Get-ADDomain $_
    
        [PSCustomObject]@{
            Domain = $_         
            InfrastructureMaster = $domain.infrastructuremaster
            RIDMaster = $domain.RIDMaster
            PDCEmulator = $domain.PDCEmulator  
            DomainFunctionalLevel=$domain.domainmode         
        }  
    } | ft * | out-file $file -Append
    
    
    #membres des groupes administrateurs
    write-output "Membres des groupes avec privilèges" | out-file $file -Append
    write-output "Membres du groupe Administrateurs de l'entreprise"
    Get-ADGroupMember -Identity "Administrateurs de l’entreprise" -Recursive | fl name
    $forest.domains | ForEach-Object { 
        write-output "Domaine $_"
        write-output "Membres du groupe Admins du domaine"
        Get-ADGroupMember -Identity "Admins du domaine" -Recursive | fl name
    
    
    } | out-file $file -Append

    Dans l'exemple que tu donne, cela me permet de voir en partie comment on peut récupérer le résultat de différentes commande dans une seule et même variable et ensuite pouvoir afficher ce qu'on souhaite précisément. C'est vraiment sur ça qu'il faut que je travaille parce que même si j'arrive à lire ton script, je ne comprends pas encore la façon dont c'est articulé à la fin. Le traitement de $result

    Dans mon cas, c'est une sortie vers un fichier TXT que je vais prévoir dans un premier temps et je ferai des copier coller dans Word.

    Question : chaque résultat de commande doit être stocké dans $result de cette façon c'est bien ça ?

    Si je dois récupérer ça comme infos :

    #Forêts AD avec ses domaines
    #niveau fonctionnels forêt et domaine et rôles FSMO
    #membres des groupes administrateurs par domaine
    # Tous les DCs de la forêt et leur OS
    .....

    Donc pour chaque section, je stocke le resultat dans $result et ensuite lors de l'export final j'appelle la section en question pour la rediriger vers un fichier?



    Merci de marquer comme reponses les interventions qui vous ont ete utile.



    dimanche 21 juillet 2019 15:36