Auteur de questions
Powershell et façon de coder

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.
- Modifié matteu31400 lundi 15 juillet 2019 19:08
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
-
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.
-
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.
-
-
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.
-
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.
-
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
-
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.
- Modifié matteu31400 dimanche 21 juillet 2019 15:41