Question Problème d'Array

Plus d'informations
il y a 16 ans 9 mois #4720 par Alan Pinard
Problème d'Array a été créé par Alan Pinard
Bonjour,

Je tente de concevoir un script qui ira chercher les erreurs, avertissements et accès interdits sur des serveurs distants.

Il va bon train sauf que maintenant je suis coincé depuis 2 jours sur le même problème. Je crois que ma compréhension est erronée car je ne trouve pas de solution.

J'aimerais vous en faire part afin que vous puissiez m'aider. Voici le script avec les commentaires:

Function GET-EventID {

$Ddate = Get-Date #Date du jour.
$ScriptTimeStamp = Get-Date -Format g #Date au format G
$Days = 7 #Avoir la date d'il y a 7 jours
$LastWeek = $Ddate.AddDays(-$Days) #Date actuel moins 7 jour
$a = 0 #Index pour mon array EventIDProperty

$EventIDProperty = \"\" | Select-Object Hostname,LogName,EventIDType,EventID,EventIDSource,EventIDDescription #Creation de propriété custom pour la variable $IEventIDProperty

Write-Host \"Démarrage du script à $ScriptTimeStamp\"

$ComputerName = \"Computer\"

Write-Host \"Ping sur $ComputerName...\"
$PingComputer = Get-WmiObject -Class \"Win32_PingStatus\" -Filter \"Address='$ComputerName'\"

If ($PingComputer.StatusCode -eq 0) {

Write-Host -ForegroundColor Green \"Ping sur $ComputerName -> Ok\"

$EventLog = System.Diagnostics.EventLog]::GetEventLogs($ComputerName) #Connexion au gestionnaire d'événement à distance

$LogTitleCount = $EventLog.Count #Récupère le nombre de log sur l'ordinateur distant

For ($i=0; $i -lt $LogTitleCount; $i++) {

$colItems = $EventLog[$i].Entries | Where-Object {($_.EntryType -eq \"Warning\" -or $_.EntryType -eq \"FailureAudit\" -or $_.EntryType -eq \"Error\") -and ($_.TimeWritten -ge $LastWeek)} #Recherche des erreurs, avertissement et accès non autorisés

$LogName = $EventLog[$i].LogDisplayName #Remplie la variable avec le nom de chaque log

$colItemsCount = $colItems.Count #Récupérer le nombre d'entrés recherchés

Write-Host \"# Warning, Error ->ColItemsCount -$LogName\"

ForEach ($Item in $colItems) {
$EventType = $Item.EntryType
$EventID = $Item.EventID
$EventIDSource = $Item.Source
$EventIDDescription = $Item.Message

$EventIDProperty = @{$a = @{Hostname = $ComputerName; LogName = $LogName; EventIDType = $EventType; EventID = $EventID; EventIDSource = $EventIDSource; EventIDDescription = $EventIDDescription}}
$a++
}#Fin du ForEach
}#Fin de la boucle For
}#Fin du IF

Else {
Write-Host -ForegroundColor Red \"|


Ping sur $ComputerName -> Not Ok\"
}#Fin du ELSE

$ScriptTimeStampFin = Get-Date -Format g
Write-Host \"Fin du script à $ScriptTimeStampFin\"
}#Fin de la fonction

GET-EventID # Utilisation de la fonction



Ce que je n'arrive pas à faire c'est de récupérer les informations de mon tableau à 2 dimensions. Je suis capable d'afficher les informations lorsque je je place ce code-ci dans la boucle for du remplissage de la variable $EventIDProperty

For ($ii=0; $ii -lt $a;$ii++){
Write-Host \"Variable II :\"$ii
Write-Host \"Hostname:\"$EventIDProperty.$ii.Hostname
Write-Host \"LogName:\"$EventIDProperty.$ii.LogName
Write-Host \"EventType:\"$EventIDProperty.$ii.EventIDType
Write-Host \"Source:\"$EventIDProperty.$ii.EventIDSource
Write-Host \"Description:\"$EventIDProperty.$ii.EventIDDescription
Write-Host \"


\"
}


Mais j'aimerais récupérer l'information après la le ELSE afin de faire ce que je veux avec la variable $EventIDProperty.

En espérant avoir été clair,


Merci,

Versiona

Alan Pinard
Version A

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

Plus d'informations
il y a 16 ans 9 mois #4721 par Laurent Dardenne
Réponse de Laurent Dardenne sur le sujet Re:Problème d'Array
Salut,
déjà ton tableau n'en est pas un, c'est une hashtable.
[code:1]
$Tableau=@()
$Hashtable=@{}
[/code:1]
Si tu veux récupérer des informations de ta fonction tu dois renvoyer un résultat dans le pipeline :
[code:1]
$EventIDProperty
#ou return $EventIDProperty
}#Fin de la fonction

$Result=GET-EventID # Utilisation de la fonction
$Result
[/code:1]
Tu peux consulter ce tutoriel sur les structures de données sous PS, voir aussi celui sur les pipelines.

De mon coté j'utiliserais plutôt une structure de données de type Arraylist en lieu et place d'un tableau.
Mais cela dépend du besoin, une structure de données par machine ou une structure de données contenant le détail de chaque machine.
Par exemple :
[code:1]
$EventCollection[]
$S.Computer[].EventCollection[]
#ou
$S.\"ComputerName\".EventCollection[][/code:1]
Elle dépendra aussi des traitements que tu comptes effectuer sur ces collections d'eventlog...<br><br>Message édité par: Laurent Dardenne, à: 31/05/09 09:22

Tutoriels PowerShell

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

Plus d'informations
il y a 16 ans 9 mois #4723 par Alan Pinard
Réponse de Alan Pinard sur le sujet Re:Problème d'Array
Bonjour Laurent,

Donc c'est pire que je pensais, je ne faisais pas de différence entre un tableau et un hashtable.:lol:

Je vais prendre le soin d'aller lire la documentation dont tu m'as fourni la référence afin de bien comprendre les différences et d'utiliser les bons étéments.

JE vous reviens avec mon code modifier un peu plus tard.

Merci,


VersionA.

Alan Pinard
Version A

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

Plus d'informations
il y a 16 ans 9 mois #4724 par Alan Pinard
Réponse de Alan Pinard sur le sujet Re:Problème d'Array
Bonjour et bonne après-midi tout le monde,

Bonjour Laurent,

Je n'ai pas très bien compris les ArrayList en lisant la documentation que tu m'a fourni. Par contre, j'ai mieux compris les HashTables.

Par ailleurs, j'aimerais comprendre les ArrayList. J'aimerais savoir comment ça fonctionne et c'est quoi la différence par rapport au HashTable.

De plus, je ne sais pas trop comment en construire un :S .

Voici ce que je veux faire avec ma fonction, voir les détailles:

J'aimerais récupérer les informations d'erreur, d'avertissement et d'accès refusé dans les logs des serveurs. Je souhaite récupérer les noms de logs dynamiquement sur chaque serveur. Ensuite, Je démarrer une boucle qui va récupérer ce que je veux dans chaque log et de les retourner dans un format ou je pourrai récupérer les informations pour les exporter en HTML, CSV, XML ou autre ...

Je trouvais intéressant d'utiliser un Hashtable car je pouvais créer une structure qui avait du sens. Aussi, je pouvais utiliser chaque \&quot;propriété\&quot; comme par exemple $EventIDProperty.0.Eventid.

Ce que j'aimerais maintenant, ce serait comme vous le dite, en utilisant une structure qui utilise par exemple le nom du serveur à la place du $a (qui est un nombre). Visuellement, j'aimerais faire ceci:

-Server1
|-&gt;LogName
|-&gt;EventID
|-&gt;Source
|-&gt;Message
|-&gt;CreatedDate
-Server2
|-&gt;LogName
|-&gt;EventID
|-&gt;Source
|-&gt;Message
|-&gt;CreatedDate
-Server3
|-&gt;LogName
|-&gt;EventID
|-&gt;Source
|-&gt;Message
|-&gt;CreatedDate


Finalement, je voudrais récupérer les informations sur chaque serveur.

En espérant avoir été clair,:dry:

Versiona

Alan Pinard
Version A

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

Plus d'informations
il y a 16 ans 9 mois #4725 par Laurent Dardenne
Réponse de Laurent Dardenne sur le sujet Re:Problème d'Array
Salut Versiona,
Versiona écrit:

J'aimerais savoir comment ça fonctionne et c'est quoi la différence par rapport au HashTable.

Je pensais que le tutoriel était suffisant sur ce point, mais je suis peut être trompé. La différence, sommaire, entre une hashtable et un arraylist et que sous PS la hashtable est gérée plus simplement et ne nécessite pas de passer par un appel à New-Object.
Les deux sont des collections d'objets, mais l'accès d'une hashtable se fait par une clé, pour l'arraylist par un indice, qui est aussi une clé, mais lors d'une nouvelle insertion il n'y a pas de recherche de doublons. L'indice est géré en interne, avec une hastable c'est toi qui le détermine.
On fait indice+1 pour un arraylist, et isExist(Key) dans une hashtable, dans ce cas c'est un moins performant. Ensuite il y a d'autres considérations à prendre en compte, et dans ce cas tu peux consulter cet article dotnet,certes d'un niveau avancé :
mehdi-fekih.developpez.com/articles/dotnet/dictionnaires/
Mais ce n'est peut être pas nécessaire d'aller si loin ;-)
Versiona écrit:

De plus, je ne sais pas trop comment en construire un

[code:1]
#Initialise la collection à 5 éléments
$Liste = New-Object System.Collections.ArrayList(5)
#Ajoute 10 éléments
1..10|Foreach {[void]$Liste.Add($_)}
[/code:1]
Je te conseillais un arraylist, une liste/collection, car à la différence d'un simple array, un tableau, sa taille augmente sans avoir à recopier puis détruire l'ancien contenu.
C'est plus efficace.
Versiona écrit:

Je trouvais intéressant d'utiliser un Hashtable car je pouvais créer une structure qui avait du sens.

Oui tu as raison, comme je te le disais c'est le besoin qui détermine la structure.
Versiona écrit:

Aussi, je pouvais utiliser chaque \&quot;propriété\&quot; comme par exemple $EventIDProperty.0.Eventid.

Il faut savoir si un accès indicé suffit, l'usage de $a me laisse penser que oui.
L'intérêt d'une hashtable et de pouvoir combiner des structures de données, cf chapitre 6.3 IMBRICATION DE STRUCTURE.
La première est une hastable, chaque clé contient le nom de la machine, ensuite la valeur de chaque clé pointe sur une seconde hashtable où chaque clé à son tour point cette fois ci sur un arraylist :
[code:1]
$Computers=@{}
$Computers.Computer1=@{}
#On utilisera les guillemets avec une variable
#$Computers.\&quot;$ComputerName\&quot;=@{}
$Computers.Computer1.LogSys=New-Object System.Collections.ArrayList(3)
[void]$computers.Computer1.LogSys.Add(\&quot;test\&quot;«»)
[void]$computers.Computer1.LogSys.Add(@{EventIDType = \&quot;X\&quot;
EventID = 12
EventIDSource = \&quot;XY\&quot;
EventIDDescription = \&quot;Test EventID\&quot;
})
[void]$computers.Computer1.LogSys.Add(\&quot;... Objet suivant...\&quot;«»)
$computers.Computer1.LogSys
$computers.Computer1.LogSys[1]
$computers.Computer1.LogSys[1].EventidDescription
$Computers.Computer1.LogApp=New-Object System.Collections.ArrayList(3)
...
$Computers.Computer2=@{}
$Computers.Computer2.LogAudit=New-Object System.Collections.ArrayList(3)
[/code:1]
Ton script principal doit créer la premiére hashtable et ta fonction renvoyer la seconde :
[code:1]
$Computers=@{}
\&quot;Computer1\&quot;,\&quot;Computer2\&quot;| % {$Computers.\&quot;$_\&quot;= Get GET-EventID $_}
[/code:1]
Mais tu peux procéder autrement

Tutoriels PowerShell

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

Plus d'informations
il y a 16 ans 9 mois #4737 par Laurent Dardenne
Réponse de Laurent Dardenne sur le sujet Re:Problème d'Array
Une possible solution remaniée utilisant le pipeline.
C'est un peu plus dense, l'approche est identique mais je n'utilise pas les mêmes structures de contrôle ( boucle foreach vs cmdlet Foreach-Object).
[code:1]
Function GET-EventID([String]$Computername,[int32]$Days=-7,[switch]$FullDebug) {
#$Computername : Nom de l'ordinateur à interroger
#$Days : Nombre de jour à déduire de la date courante, détermine la date de recherche
#$FullDebug : Détermine si en mode debug on affiche le détail de chaque event trouvé

function Write-FullDebug
{
Write-Debug \&quot;$LogName : Add\&quot;
Write-Debug \&quot;`t $($EventIDProperties.ID)\&quot;
Write-Debug \&quot;`t $($EventIDProperties.EntryType)\&quot;
Write-Debug \&quot;`t $($EventIDProperties.Source)\&quot;
Write-Debug \&quot;`t $($EventIDProperties.Message)\&quot;
}
#Pas de recherche dans le futur
if ($Days -gt 0)
{Write-Error \&quot;Le paramètre `$Days doit être inférieure ou égale à zéro.\&quot;;Break}

$DateDuJour = Get-Date

Write-Host (\&quot;Démarrage du script à {0:G}\&quot; -f $DateDuJour)

Write-Host \&quot;Ping sur $ComputerName...\&quot;
$PingComputer = Get-WmiObject -Class \&quot;Win32_PingStatus\&quot; -Filter \&quot;Address='$ComputerName'\&quot;

If ($PingComputer.StatusCode -eq 0) {
$DateRecherche=$DateDuJour.AddDays($Days)
#Contient la liste des journaux
$ErreursDesJournaux=@{}
#Structure :
# $ErreursDesJournaux : object de type hashtable
# $ErreursDesJournaux.\&quot;$LogName\&quot; : \&quot;$LogName1\&quot; est utilisée comme nom de clé, par exemple $LogName=\&quot;Application\&quot;
# $ErreursDesJournaux.Application : Pointe sur une liste des erreurs présentes dans le journal nommé 'Application'
# $ErreursDesJournaux.Application[0] : Accéde à la première erreur.

#
Récupère la liste des journaux de l'ordinateur courant, distant ou pas.
#Une exception sur GetEventLogs provoque l'arrêt du pipeline principal
# System.ArgumentException: Valeur 'xxx' non valide pour le paramètre 'machineName'.
[System.Diagnostics.EventLog]::GetEventLogs($ComputerName)|`
#On utilise les blocs du pipeline principalement l'affichage
Foreach-Object -begin{Write-Host -ForegroundColor Green \&quot;Accés aux journaux sur $ComputerName -&gt; Ok\&quot;} -process{
#
Analyse les entrées de chaque journal
#Nom du journal d'eventlog en cours d'analyse
$LogName=$_.LogDisplayName
#On crée une nouvelle entrée dans la hashtable, elle pointe sur une liste des erreurs présentes dans le journal courant
#La liste peut être vide (il n'existe aucune erreur)
$ErreursDesJournaux.\&quot;$LogName\&quot;=New-Object System.Collections.ArrayList(3)
Write-Debug \&quot;$LogName : Create \&quot;
#Une exception sur $_.Entries provoque l'arrêt de ce pipeline imbriqué
# SecurityException L'utilisateur ne dispose pas des autorisations nécessaires pour exécuter cette opération.
# Dans ce cas la liste aussi sera vide (On ne sait pas si ce journal contient des erreurs)
$_.Entries |`
Where-Object {
#
Recherche dans le journal courant les entrées de type : avertissement, accès non autorisé et erreur.
# et qui sont supérieures à la date de recherche indiquée
#Optimisation : on inverse les critéres de recherche et on filtre en premier sur la date
($_.TimeWritten -ge $DateRecherche ) -and
($_.EntryType -ne 4 -and $_.EntryType -ne 8) #4 =\&quot;Information\&quot;, 8=\&quot;SuccessAudit\&quot;
}|`
Foreach-Object {
#
Ajoute les entrées dans une liste
#Création d'un objet personnalisé dans lequel on recopie les informations qui nous intéresse.
$EventIDProperties = \&quot;\&quot; | Select-Object ID,EntryType,Source,Message
$EventIDProperties.ID= $_.EventID;
$EventIDProperties.EntryType= $_.EntryType;
$EventIDProperties.Source= $_.Source;
$EventIDProperties.Message = $_.Message
#Ajoute le nouvel objet dans la liste
[void]$ErreursDesJournaux.\&quot;$LogName\&quot;.Add($EventIDProperties)

if ($FullDebug)
{ Write-FullDebug}
}#Fin du ForEach Entries
Write-Host (\&quot;# Warning, Error -&gt; {0}:{1}\&quot; -F $LogName,$ErreursDesJournaux.\&quot;$LogName\&quot;.Count)
}#Fin du ForEach EventLog
}#Fin du IF
Else
{ #On utilise la couleur rouge pour les erreurs et la jaune pour les warnings
Write-Host -Fore DarkYellow \&quot;|
Ping sur $ComputerName -&gt; Not Ok\&quot; }

Write-Host (\&quot;Fin du script à {0:G}\&quot; -f [DateTime]::Now)
#Renvoi dans le pipeline la nouvelle hashtable
$ErreursDesJournaux
}#GET-EventID

#
Premier essai
#Ici on ne mémorise pas le nom de la machine
$Result=GET-EventID \&quot;$Env:Computername\&quot;
#Ici mémorise le nom de la machine
#$Result=@{\&quot;$Env:Computername\&quot;=(GET-EventID \&quot;$Env:Computername\&quot;«»)}
#ou encore
$Code=\&quot;`$Result=`$Result|add-member ScriptMethod ComputerName -value {`\&quot;$Env:Computername`\&quot;} -pass\&quot;
invoke-expression $Code

#
Second essai
#Construit une hashtable contenant d'autre hashtable
$Computers=@{}
#Chaque entrée de la hashtable $Computers a pour nom de clé le nom de la machine
#Ici on mémorise le nom de la machine
\&quot;LocalHost\&quot;,\&quot;$Env:Computername\&quot;,\&quot;Inconnu\&quot;| % {$Computers.\&quot;$_\&quot;= GET-EventID $_}
#La date de recherche n'est pas mémorisée
#Le calcul de la date de recherche peut poser pb si l'inventaire se fait la nuit et à cheval sur 2 jour.
#Exemple : début 23h50 fin 00h05

#Exceptions propables :
# IOException machineName est introuvable.
# SecurityException L'utilisateur ne dispose pas des autorisations nécessaires pour exécuter cette opération.
# UnauthorizedAccessException L'utilisateur ne dispose pas des droits d'accès à la base de registres appropriés.
#
# ArgumentException Le paramètre machineName est un nom d'ordinateur non valide.
# InvalidOperationException Vous n'avez pas d'accès en lecture sur le Registre.
# - ou -
# Il n'y a pas de service Journal des événements sur l'ordinateur.
[/code:1]
J'ai joins le fichier en cas de pb d'affichage sous Joomla.
En réfléchissant il reste un petit pb, on ne connait plus les erreurs possibles déclenchées lors de son exécution.
Une entrée de la hashtable peut être vide mais on n'en connait pas la raison, idem pour une liste des entrée en erreurs. J'ai second script mémorisant les erreurs, si besoin je te le joins.

La pièce jointe test_eventlogv3.ps1 est absente ou indisponible


Tutoriels PowerShell
Pièces jointes :

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

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