Question 2011 Scripting Games : Advanced Events 1

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

Ci-après le code que j'ai posté pour l'évènement 1 (section avancée) pour les Scritping Games 2011 :

[code:1]

# This advanced function is suitable to incorporate into a module
# We assume it is used with a user account that has sufficient admin rigths on all targeted computers
Function Get-ProcessModuleVersions(){

[CmdletBinding(DefaultParameterSetName=\"ComputersFromList\"«»)]
param(
[Parameter(Mandatory=$true)]
[String]$ModuleName,
[Parameter(Mandatory=$true,ParameterSetName=\"ComputersFromList\"«»)]
$Filepath,
[Parameter(ParameterSetName=\"ComputersFromAD\"«»)]
[Switch] $GetComputersFromAD
)

# If '-GetComputersFromAD' parameter is used, we need to collect all Windows computers from AD
# .Net Framework is used to be sure this script can be run on both Windows XP and Windows 7, so we don't need any external module
if($GetComputersFromAD){
$objDomain = New-Object System.DirectoryServices.DirectoryEntry
$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = '(&(objectCategory=computer)(operatingSystem=*Windows*))'

$objSearcher.PropertiesToLoad.Add(\"name\"«») | Out-Null

$colResults = $objSearcher.FindAll()

$MyComputersList = $null
$MyComputersList = @()

foreach ($objResult in $colResults){
$objComputer = $objResult.Properties
$MyComputersList += $objComputer.name
}

$CptList = $MyComputersList
}
else{
if(!(Test-Path $Filepath)){
Write-Host \"The file $Filepath can not be found !\" -ForegroundColor Red
exit
}
else{
$CptList = Get-Content $Filepath
}
}

# This ScriptBlock will be used for Windows PowerShell Remoting
# First start notepad process, then collect Module informations, when available
$ScriptBlock = {
param([string]$StrModuleName)
$ModuleInfos = \"\" | select ModuleName, Size, FileName, FileVersion
Start-Process notepad
$NotepadProcess = Get-Process notepad
if($NotepadProcess){
$MyModule = $NotepadProcess.Modules | ?{$_.ModuleName -eq $StrModuleName}
if($MyModule){
$ModuleInfos.ModuleName = $MyModule.ModuleName
$ModuleInfos.Size = $MyModule.Size
$ModuleInfos.FileName = $MyModule.FileName
$ModuleInfos.FileVersion = $MyModule.FileVersion
}
}
return $ModuleInfos
}

# Preparing results array
$ResultsList = $null
$ResultsList = @()

# This 2 variables will be used to show state of progress
$nbcomputers = $CptList.Count
$i = 0

# Starting to collect informations for each computer of the collection
foreach($Computer in $CptList){

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

if($Computer.Trim() -ne \"\"«»){
# Preparing a string array before collecting informations for targeted computer
$MyComputerInfos = \"\" | Select Computer, ModuleName, Size, FileName, FileVersion
$MyComputerInfos.Computer = $Computer

# We try to invoke the script block on the remote computer
try{
$MyProcessInfos = Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $ModuleName -ComputerName $Computer -ErrorAction Stop
}
catch{
Write-Error \"An error has occured while invoking command on $Computer : $($error[0].exception.message)\"
$MyProcessInfos = $null
}

if($MyProcessInfos.ModuleName){
$MyComputerInfos.ModuleName = $MyProcessInfos.ModuleName
$MyComputerInfos.Size = $MyProcessInfos.Size
$MyComputerInfos.FileName = $MyProcessInfos.FileName
$MyComputerInfos.FileVersion = $MyProcessInfos.FileVersion
}
else{
$MyComputerInfos.ModuleName = \"?\"
$MyComputerInfos.Size = \"?\"
$MyComputerInfos.FileName = \"?\"
$MyComputerInfos.FileVersion = \"?\"
}

# Adding informations for targeted computer to results array
$ResultsList += $MyComputerInfos
}
$i++

}

# Now we format the results array in csv and write it to the output
Write-Output ($ResultsList | ConvertTo-Csv -NoTypeInformation)
}

# This command can be used in order to get 'Windows Spooler Driver' version
# on each Windows computer found in Active Directory
Get-ProcessModuleVersions -Modulename \"WINSPOOL.DRV\" -GetComputersFromAD

# This command can be used in order to get 'Windows Spooler Driver' version on a computers list file
# Get-ProcessModuleVersions -Modulename \"WINSPOOL.DRV\" -Filepath '.\Computers.txt'[/code:1]

... Le scénario étant le suivant :

You are the network administrator for a small business with 200 users and four servers on the network. You are responsible for managing Active Directory Domain Services (AD DS) running on a single Windows Server 2008 R2 machine, Exchange Server 2007 running on Windows Server 2008, SQL Server 2008 also running on a Windows Server 2008 machine, and a File and Print Server running Windows Server 2003. Your workstations are a combination of Windows XP, Windows Vista and Windows 7. Because one of your servers also runs Windows Software Update Services (WSUS), you have deployed Windows PowerShell 2.0 to all of your workstations and servers on the network. Your boss, who is the CIO and the comptroller was listening to the radio on the way into work today, and he heard a report about a zero-day exploit of a particular component. The radio report mentioned the name of the component, and it stated that it only existed on certain servers. Unfortunately, the reporter was a bit vague with the details. Because of this vagueness, your boss wants you to scan every machine on the network for the affected component.

For the purposes of this event, you will only need to run the script against your local computer, but you should include the capability to run it against multiple machines. You should use the Notepad process, and report the version of the “Windows Spooler Driver” module that is used by the Notepad process. You should display a Comma Separated Value output with a header and values for the following: ModuleName, Size, FileName, FileVersion. A sample output is shown in the following image.


Premier point négatif : pas de \"Command based help\"....

Message édité par: Matthew BETTON, à: 27/04/11 21:39

Message édité par: Matthew BETTON, à: 27/04/11 21:40<br><br>Message édité par: Matthew BETTON, à: 8/05/11 22:03

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

Plus d'informations
il y a 14 ans 10 mois #9485 par Matthew BETTON
Cette fonction peut être intégrée dans un module.

Elle devait permettre, selon le scénario, de récupérer la version (et quelques autres informations) du module 'Windows Spooler Driver' sur une liste d'ordinateurs, via l'exécution à distance du process 'notepad.exe'.

Premières remarques :

- IL n'y a pas de \&quot;Command based help\&quot;, pour la réutilisation du code par d'autres administrateurs ;
- La fonction ne prend pas en charge les Credentials ;
- Pour la récupération des noms de machines dans l'AD, il y a nettement plus simple (cf. composant [adsisearcher]) ;
- L'utilisation d'Alias, ce qui ne simplifie pas la lecture du code ;
- La déclaration d'un objet de type 'PSObject' pour chaque machine traitée, aurait été préférable...

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

Plus d'informations
il y a 14 ans 10 mois #9504 par Matthew BETTON
En fait, n'ayant pas trop le temps en ce moment... Je vais directement mettre ici le lien vers les 10 scripts que j'aurais posté lors de ces Scripting Games 2011 (\&quot;faignant !\&quot; :P ) :

J'ai fini 12ème au classement général, pour la catégorie Advanced.

Je ne regrette franchement pas d'y avoir participé. J'y ai appris beaucoup de choses, comme j'en apprends encore via les solutions postées par les experts .

... et je compte bien recommencer l'année prochaine ;)

@ +

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

Plus d'informations
il y a 14 ans 10 mois #9574 par Arnaud Petitjean
Toutes mes félicitations Matthew !!! :woohoo:

12e au classement mondial n'est pas rien; surtout qu'il y avait des épreuves particulièrement difficiles dans la section advanced !

Arnaud

MVP PowerShell et créateur de ce magnifique forum :-)
Auteur de 6 livres PowerShell aux éditions ENI
Fondateur de la société Start-Scripting
Besoin d'une formation PowerShell ?

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

Plus d'informations
il y a 14 ans 10 mois #9579 par Laurent Dardenne
Salut,
je viens juste de lire ton post, alors je me permets qq remarques, en sachant que c'est tjr plus facile que de réaliser :-)

D'aprés un post du blog MS PowerShell, cette usage est le plus lent (un cmdlet opère de multiples contrôles), entre la redirection vers $null ou l'affectation à $null :
[code:1]
$objSearcher.PropertiesToLoad.Add(\&quot;name\&quot;«») | Out-Null
[/code:1]

Puisqu'il n'y a pas de bloc process on est assuré que $MyComputersList est à null
[code:1]
$MyComputersList = $null
$MyComputersList = @()
[/code:1]
Là tu as du perdre des points ! Un appel à Write-Error ou mieux un appel àThrow ( new-object System.ArgumentException ...) est préférable.
L'appelant ne sait pas ce qui se passe, sauf une fin de fonction :-/
[code:1]
if(!(Test-Path $Filepath)){
Write-Host \&quot;The file $Filepath can not be found !\&quot; -ForegroundColor Red
exit
}
[/code:1]
Si c'est un prérequis à l'exécution de la fonction, on peut utiliser sur ce paramètre un attribut ValidateScript.
Ensuite la gestion du ParameterSetName n'est pas explicite, j'en déduit que l'usage du switch détermine le jeux de paramètre 'ComputersFromAD'.
Du coup je me dis que le jeux de paramètre n'a qu'un usage documentaire.

Si j'ai bien compris le code suivant, je pense qu'ici aussi tu as du perdre des points :
[code:1]
Start-Process notepad
$NotepadProcess = Get-Process notepad
[/code:1]
Le paramètre -PassThru du cmdlet Start-Process pouvait suffire.
Et j'ai l'impression que tu supposes que tu ne peux avoir qu'un seul process Notepad d'actif.
Et de ce que j'ai compris, d'après ton commentaire \&quot;Windows PowerShell Remoting\&quot;, pour moi il n'était pas possible d'exécuter à distance une appli GUI.
Donc là j'ai doute.Mais si tu l'as codé ainsi c'est que ça marche !
Ceci dit je veux bien que tu me le confirmes :lol:

Sinon je lis que tu utilises pour les constructions d'objet la syntaxe de la v1, celle de la v2 est plus concise :
[code:1]
New-object PSobject -property @(Nom=$Valeur}
[/code:1]
Sur une classe dotnet quelconque elle permet également d'appeler des méthodes dans la foulée, voir la doc en ligne.

Et ici comme convention de valeur nulle, autant se satisfaire de $null, car ici ton choix t'oblige à la documenter
[code:1]
$MyComputerInfos.ModuleName = \&quot;?\&quot;
[/code:1]

Pour la construction de collection le code suivant facilite l'écriture, mais n'est pas efficiente :
[code:1]
$ResultsList += $MyComputerInfos
[/code:1]
L'usage, par exemple, d'un arraylist est déjà plus performant.
[code:1]
- IL n'y a pas de \&quot;Command based help\&quot;, pour la réutilisation du code par d'autres administrateurs ;
[/code:1]
De mon côté je préfére un code qui n'est pas documenté, mais qui est robuste, à son contraire.
D'avoir les deux, c'est de la gourmandise...

En tout cas c'est agréable de lire du code structuré, et c'est aussi ce qui permet d'en voir les faiblesses, et donc de le rendre plus fort.
Un autre aspect du dynamisme ;-)

Tutoriels PowerShell

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

Plus d'informations
il y a 14 ans 10 mois #9580 par Laurent Dardenne
Matthew BETTON écrit:

Je vais directement mettre ici le lien vers les 10 scripts que j'aurais posté lors de ces Scripting Games 2011 (\&quot;faignant !\&quot; :P ) :

Je trouve ça dommage, car tes contributions enrichiraient les lecteurs de ce site. Reste à vérifier si Google référence tes scripts sur ces urls.

Et puis pour quelqu'un qui fait le néant , je te trouve assez constructif :)

Message édité par: Laurent Dardenne, à: 6/05/11 20:56<br><br>Message édité par: Laurent Dardenne, à: 9/05/11 12:58

Tutoriels PowerShell

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

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