Question 2011 Scripting Games : Advanced Event 3

Plus d'informations
il y a 14 ans 10 mois #9587 par Matthew BETTON
Bonsoir,

Ci-après le script que j'ai posté lors des Scripting Games 2011, dans le cadre de l'Advanced Event 3.

Le scénario était le suivant :

You are in charge of server monitoring at a medium-sized company that consists of three geographically dispersed sites and 50 servers. The servers are running a combination of Windows Server 2008 R2 and Windows Server 2008. You want to query all classic event logs and the ETL diagnostic logs that are enabled and have had data written during the date in which the report is run. No matter when the report runs, it should return the most recent event written in the log, but only if the event occurred during the date in which the report runs. Your report should include the following information: The date and time that the event occurred, the name of the event provider, the event ID, and the message that is associated with that event. Remember, you only want to return the most recent event from each classic event log and ETL log that is enabled, and has had events written during the day in which the report runs. Output like that shown in the following image would meet the requirements of this scenario.


Mon script :

[code:1]#
# 2011 Scripting Games : Advanced Event 3
# Script : Get-TodayLastEvents.ps1
# Synopsis : Use PowerShell to Query Classic Event and ETL Diagnostic Logs
# Author : Matthew BETTON (France / Basse-Normandie / Manche (50))
#
# Prerequisites :
# - We assume this script is used with a user account that has sufficient admin rigths on all targeted computers ;
# - The 'ActiveDirectory' PowerShell module must be available on the local machine ;
# - .Net Framework 3.5 or later version on targeted servers (Needed by Get-WinEvent PoSh Cmdlet).
#

# Command line parameters declaration block
# By default : recover 1 event by log
# No parameter is mandatory but allow the user of this script to filter events by severity or ID
# If '-Wrap' switch is used : Displays text that exceeds the column width on the next line.
param(
$EventNumber = 1,
[ValidateSet(\"Information\", \"Error\", \"Warning\"«»)]
[String]$EventSeverity,
$EventID,
[Switch]$Wrap
)

# If not already loaded, try to load ActiveDirectory Module before using 'Get-ADComputer' Cmdlet
if(-not (Get-Module ActiveDirectory)){
try{
Import-Module ActiveDirectory -ErrorAction Stop
}
catch{
Write-Host \"Can't load ActiveDirectory PowerShell Module... Exiting !\" -ForegroundColor Red
exit
}
}

# Request AD DS for Windows server names
$ServersList = Get-ADComputer -filter {operatingSystem -like \"*windows*server*\"} | ForEach-Object{$_.Name}

# Prepare ScriptBlock before running it on each remote computer
$ScriptBlock = {
param(
$SBeventNumber,
$SBeventSeverity,
$SBeventID
)
# Get today's date
$Today = [datetime]::today

# Find today's last events, for each log
$TodayLastEvents = Get-WinEvent -ListLog * -ErrorAction silentlycontinue `
| Where-Object { $_.recordcount } `
| Foreach-Object { Get-WinEvent -LogName $_.logname -MaxEvents $SBeventNumber } `
| Where-Object { $_.TimeCreated -gt $Today }

if($SBeventID){
$TodayLastEvents = $TodayLastEvents | Where-Object{$_.Id -eq $SBeventID}
}

if($SBeventSeverity){
$TodayLastEvents = $TodayLastEvents | Where-Object{$_.LevelDisplayName -eq $SBeventSeverity}
}

return $TodayLastEvents
}

# Total of numbers computers
$nbcomputers = $ServersList.Count
# Initialize counter
$i = 0

# Start collecting informations for each computer in the lit
foreach($Computer in $ServersList){

# Calculate percentage of completion
[int]$count = ($i / $nbcomputers) * 100
# Display a progress bar
Write-Progress -Activity \"Collecting informations from $nbcomputers computer(s)...\" -PercentComplete $count -CurrentOperation \"processing on $Computer\" -Status \"Please wait ($count %)\"

# Now try to invoke the script block on the remote computer
try{
$ComputerEvents = Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $EventNumber, $EventSeverity, $EventID -ComputerName $Computer -ErrorAction Stop
}
catch{
Write-Error \"An error has occured while invoking command on $Computer : $($error[0].exception.message)\"
$i++
Continue
}

# Output results
if($ComputerEvents){
Write-Output \"Today's last event(s) ($($ComputerEvents.count)) for $computer :\"
if($Wrap){
Write-Output $ComputerEvents | Format-Table LogName, TimeCreated, ProviderName, Id, Message, LevelDisplayName -Wrap
}
else{
Write-Output $ComputerEvents | Format-Table LogName, TimeCreated, ProviderName, Id, Message, LevelDisplayName
}
}
else{
Write-Output \"No event today for $computer !\"
}

# Update $i before to continue to the next computer, in order to increase progress bar
$i++

}[/code:1]

Pour les personnes que cela intéresse, voici le lien vers la solution de l'expert .

Toutes les remarques seront les bienvenues !

;)

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

Plus d'informations
il y a 14 ans 10 mois #9588 par Matthew BETTON
Pour information, voici les remarques de Ed Wilson, à propos de mon script :

You might ping remote machine first to speed up processing when a remote machine is off line. Also might check for admin rights and report status. I LOVE your use of write-progress, and your loading the AD modules. You do not test for the presence of AD module. You might consider a nested progress bar to show status through collection of computers, AND status on the computer itself.

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

Plus d'informations
il y a 14 ans 10 mois #9655 par Laurent Dardenne
salut,
ici
[code:1]
catch{
Write-Host \"Can't load ActiveDirectory PowerShell Module... Exiting !\" -ForegroundColor Red
exit
}
[/code:1]
j'aurais plutôt redéclenché une exception personnalisée, car si j'intégre ton script dans ma solution je ne sais pas si sa fin est normale ou due à une absence de prérequis.

Au niveau de la saisie, au lieu de :
[code:1]$TodayLastEvents = Get-WinEvent -ListLog * -ErrorAction silentlycontinue `
|Where-Object { $_.recordcount }
#...
[/code:1]
tu peux faire ceci :
[code:1]$TodayLastEvents = Get-WinEvent -ListLog * -ErrorAction silentlycontinue|
Where-Object { $_.recordcount }
#...
[/code:1]
A partir du moment où tu utilises le pipe, le parseur recherche une instruction sur la même ligne ou sur la ligne suivante, pas besoin \"d'échapper\" la ligne.

Tutoriels PowerShell

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

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