Maintenance des PCs

Pourquoi ?

Exécuter des tâches de maitenance sur un ensemble de 600 machines n'est pas un chose simple. et c'est très répétitif...

Un script qui pourait effectuer certaines de ces tâches fastidueuses serait bien interressant, en particulier, en suivant deux axes. FAire de la maintenance précventive, agir avant que les problèmes ne remontent et faire de la maintenance curative, déployer une correction sur toutes les machines.

Les GPOs et WSUS permettent déjà de faire beaucoup, mais il n'est pas possible de mettre à jour des pilotes qui ne sont pas dans WSUS, ni de liberer de l'espace disque etc..

On recherchera donc les ojectifs suivants :

- Obtenir un diagnostique du PC
- Agir si des élèemnts posent problème

L'historique des pannes nous montre qu'il faut surveiller l'espace libre sur les disques, en particuliers C:\documents and settings (les profils) et C:\Windows\temp. Ces deux zones ont terrblement tendance à enfler. Il faut également scruter les journaux d'évènements. Avoir la liste des softs installés ainsi que le matériel nécisstant une mise à jour de son pilote, serait un plus.


Principe (détail)

Afin de disposer du privilège administrateur, on utilisera un script de demarrage machine qui utilise le compte SYSTEM.

Les tâches effectuées sont les suivantes :

- Bilan de l'utilisation des disques logiques
- Bilan de l'espace occupé par les profils et par le répertoire temp de windows, nettoyage de ces deux zones
- Bilan des logiciels installés, il sera possible de les désinstaller en fonction de leur emplacement dans AD
- Remontée du journal d'évènements

on utilise :

- Une ressource réseau
- Un script au niveau machine
- Des fichiers de configuration

Les améliorations à venir :

- Envoi d'un mail en cas d'évènement critique (pb disque, espace disque très faible)
- Recherche du matériel et mise à jour des pilotes (carte graphique, carte, chipset)
- Mise à jour automatique de certain logiciels
- Test des ressources réseau et de la présence des fichiers de ressource
- Suivi des actions effectuées sur un fichier log pour tous les PCs
- Installation / Désisntallation de composants Windows
- Configuration du réseau (partage, protocoles)


Problèmes

- le script plante sous 2003
- les dossiers profils ne sont pas tous supprimés
- le script est lent


Mise en oeuvre :

Partage :

Les logs sont remontés au niveau du serveur, il sont inscrits dans une ressource partagée.

Les ordinateurs exécutant ce script au niveau machine, c'est avec le compte ordinateur qu'ils vont travailler sur le réseau. Afin d'être au plus juste au niveau de ce partage, on affecte les droits suivants :

Au niveau de la sécurité du partage, les administrateurs du domaine, contrôle total, les ordinateurs du domaine, modifier.

Au niveau NTFS

- les administrateurs contrôle total.
- les ordinateurs du domaine lire, et création de fichier (expliqué ici)

Ainsi, un ordinateur crée le fichier, il en est le propriétaire et peut donc en faire ce qu'il veut.

Un autre dossier sera accessible en lecture seulement aux ordinateurs et CT aux administrateur, pour y placer les fichiers de configuration.

Script :

Celui-ci est placé dans la ressource netlogon, il peut être placé dans la gpo qui le lance ou dans le dossier datas ci dessus.

Il faut faire attention à deux variables :

xJours : défini le nb de jour de remontée des erreurs et des avertissements de l'observateur d'évènements

exec_interval : défini le nb de jours entre deux exécutions du script

enfin unclog défini le chemin UNC des journaux, les fichiers de configuration sont placé dans le dossier datas

' Remontée des journaux Application et Système
' pierre CHOFFARDET
' Mettre le script en GPO demarrage machine par exemple
' filtrage d'évenements
' espace libre sur le(s) disque(s)
' Version 0.1
' 0.2 désinstallation composants windows
'--------------------------------------------------
'Option Explicit
On error resume next
Dim objFSO, dtmStartDate, dtmEndDate , objF, objEvent
Dim DateToCheck, strComputer, sUnc, objFiltre, Ligne
Dim objWMIService, colEvents, colItems, objItem, capacite
Dim objDictionary , fileLog, CreateLog
Dim nbJours, sOrdi
Dim objUnstSofts , strUninstall
Dim WshShell, objShell, objFolderW, objFolderItem, objFolder, fc, f1, sf, profil, Name, profil2
Dim objDiskDrive, colDiskDrives
Dim colSoftware, objSoftWare
Dim ORootDSE, DomaineLdap ' recherche du nom de domaine
Dim objConnection, objCommand ' connexion et command à LDAP
Dim objNet, strOrdi ' nom de l'ordinateur récupéré par l'objet objNet
Dim PDepart, Cond, Recup ' requete : domaine de recherche, condition, données récupérées
Dim Oresult 'résultat de la requete
Dim champs, OU,salle,secteur 'champs : dn de l'objet computer trouvé dans AD; salle : OU contenant l'ordinateur; secteur OU parente de salle
Dim dicUSofts 'dictionaire des logiciels à désintaller clé : Id du soft valeur : lieux de désinstallation du soft
Dim IdSoft 'Identifiant du logiciel
Dim rapLog, uncLog, uncJournal, fileINF, fileFiltre, fileUninstall, fileRap
Dim objXP, cmd, taille, total
' chemin UNC du dossier qui centrlise les journaux
rapLog =""
uncLog="\\srv-sus-imp\log$\"
uncJournal = UncLog & "maintenance\journaux\"
fileINF = uncLog & "maintenance\datas\XP.INF"
fileFiltre = uncLog & "maintenance\datas\filtre.txt"
fileUninstall = uncLog & "maintenance\datas\uninstall.sft"
fileRap= uncLog & "maintenance\logs.log"
Const ForReading = 1, ForWriting = 2, ForAppending = 8
Const CONVERT_TO_LOCAL_TIME = True
Const xjours=7
Const exec_interval=30

Set objShell = CreateObject("Shell.Application")
Set WshShell = WScript.CreateObject("WScript.Shell")
Set objNet = CreateObject("WScript.Network")
strOrdi=objNet.ComputerName
fileLog = uncJournal & strOrdi &".log"
strComputer = "."
Set objFSO = CreateObject("Scripting.FileSystemObject")

' vérification de la date du fichier et test de son age

If objFSO.FileExists(fileLog) then
objF = objFSO.OpenTextFile(fileLog, ForReading)
nbJours = CInt(DateDiff("d",objF.ReadLine,Now))
objF.close
If nbJours < exec_interval then
CreateLog = 0
else
objFSO.DeleteFile(fileLog)
objF.delete
End if
else
nbJours = -1
CreateLog = 1
End if

' si les conditions son réunies, alors, éxécution du script
If CreateLog = 1 then

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")

Set ORootDSE = GetObject("LDAP://rootDSE")
DomaineLdap=ORootDSE.GET("defaultNamingContext")

Set objConnection = CreateObject("ADODB.Connection") ' connexion à AD
objConnection.Open "Provider=ADsDSOObject;"
Set objCommand = CreateObject("ADODB.Command")
objCommand.ActiveConnection=objConnection
' Recherche de l'OU contenant l'odinateur (salle) et de l'OU parent (secteur)
PDepart = "<LDAP://"&DomaineLdap&">"
Cond= "(&(name="& strOrdi &")(objectcategory=Computer))"
Recup = "memberof,distinguishedname"
objCommand.CommandText= PDepart&";"&Cond&";"&Recup&";subtree"
Set Oresult=objCommand.Execute

IF Oresult.RecordCount = 1 Then
champs=split(oResult.Fields("distinguishedname"),",")
OU = split(champs(1),"=")
salle = OU(1)
OU = Split(champs(2),"=")
secteur = OU(1)
Else
salle="Pas trouvé"
secteur="Pas trouvé"
objF.Close
End If
sOrdi = objNet.ComputerName

Set objF = objFSO.CreateTextFile(fileLog)
objF.WriteLine Now
objF.WriteLine "Journal de : " & sOrdi & " le : " & Date & " à : " & Time
objF.WriteLine "Salle : "& salle & " Secteur : " & secteur
objF.WriteLine "nb de jours depuis la dernière fois : " & nbJours
objF.WriteLine "----------------------------------------------------------"
Set colItems = objWMIService.ExecQuery("Select * from Win32_Processor")
For Each objItem in colItems
objF.WriteLine "Processeur : " & objItem.Manufacturer & " " & objItem.Name & " (" & objItem.Description & ")"
objF.WriteLine "Fréquence : " & objItem.CurrentClockSpeed & " MHZ Cache L2 : " & objItem.L2CacheSize & " ko"
Next
objF.WriteLine "----------------------------------------------------------"
Set colItems = objWMIService.ExecQuery ("Select * from Win32_DisplayControllerConfiguration")
For Each objItem in colItems
objF.WriteLine "carte graphique : " & objItem.Name
objF.WriteLine "Video Mode: " & objItem.VideoMode
Next
objF.WriteLine "----------------------------------------------------------"
Set colItems = objWMIService.ExecQuery("Select * from Win32_PhysicalMemory")
For Each objItem in colItems
capacite = round(objItem.Capacity/1024/1024,1)
objF.WriteLine "Bank : " & objItem.BankLabel &" Capacité : " & capacite & " Mo"
objF.WriteLine "type : " & objItem.DataWidth &" bits"
objF.WriteLine "Device Locator: " & objItem.DeviceLocator
objF.WriteLine "Form Factor: " & objItem.FormFactor
objF.WriteLine "Manufacturer: " & objItem.Manufacturer
objF.WriteLine "Memory Type: " & objItem.MemoryType
objF.WriteLine "Speed: " & objItem.Speed
Next
objF.WriteLine "----------------------------------------------------------"
Const wbemFlagReturnImmediately = &h10
Const wbemFlagForwardOnly = &h20
Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_NetworkAdapter", "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly)

For Each objItem In colItems
if objItem.AdapterType <> "" then
objF.WriteLine "AdapterType: " & objItem.AdapterType & "("& objItem.AdapterTypeId &")"
objF.WriteLine "Name: " & objItem.Name & "(" & objItem.MACAddress & ")"
end if
Next
objF.WriteLine "----------------------------------------------------------"
' récupération de l'espace libre sur les disques physiques
Set colDiskDrives = objWMIService.ExecQuery ("Select * from Win32_PerfFormattedData_PerfDisk_LogicalDisk Where " & "Name <> '_Total'")
For Each objDiskDrive in colDiskDrives
objF.WriteLine "Drive " & objDiskDrive.Name & " Libre : " & round(objDiskDrive.FreeMegabytes/1024,2) & " Go" & VbCrLf
Next

' recherche de l'espace occupé par windows\temp
Const WINDOWS = &H24&
' Ou est le repertoire windows

Set objFolderW = objShell.Namespace(WINDOWS)
Set objFolderItem = objFolderW.Self
Set objFolder = objFSO.GetFolder(objFolderItem.Path&"\temp")
objF.WriteLine "Repétertoire C:\Windows\temp " & round (objFolder.Size/1024/1024,2) & " Mo" & VbCrLf
Set fc = objFolder.Files
For Each f1 in fc
On error resume next
f1.delete true
'On error goto 0
Next
Set sf = objFolder.SubFolders
For Each f1 in sf
'on supprime tous les sous répertoires
f1.delete true
Next
Set objFolder = objFSO.GetFolder("C:\Documents and Settings")
profil=round(objFolder.Size/1024/1024,2)
objF.WriteLine "Repétertoire C:\Documents and Settings " & profil & " Mo" & VbCrLf
' Netoyage des profils
if (profil>100 ) then
' on essaye proprement avec delprof
WshShell.Run ("\\voillaume\netlogon\scripts\delprof.exe /Q /I /R" )
Set sf = objFolder.SubFolders
For Each f1 in sf
name = lcase(f1.name)
'on supprime tous les répertoires qui contiennent un '_' et qui ont survécu à delprof
if ( name<>"all users" and name <>"default user" and name <> "localservice" and name <> "networkservice" and (InStr(name, "_")>0 or InStr(name, ".voi")>0 or name="lv" or name="lvtstc" or name = "lvisp") or name = "elevetstc" or name ="dell") Then
' 1ère tentative
on error resume next
f1.delete
'on error goto 0
' il résiste l'éfronté
if objFSO.FolderExists("C:\Documents and Settings\"& name) then
'if InStr(name, ".voi")>0 then
'ligne = split(name, ".")
'name = ligne(0)
'end if
'cmd = " -on ""C:\Documents and Settings\"& name & """ -ot file -actn ace "
'cmd = cmd & " -ace ""n:%USERDOMAIN%\"& name & ";p:change"""
'WshShell.Run "\\voillaume\netlogon\scripts\setacl.exe "& cmd ,3 , true
' remise à plat des sécurités
cmd = " -on ""C:\Documents and Settings\"& name
cmd = cmd & " -actn clear -clr ""dacl,sacl"""
cmd = cmd & " -actn rstchldrn -rst ""dacl,sacl"""
WshShell.Run "\\voillaume\netlogon\scripts\setacl.exe "& cmd ,3 , true
' 2 ème tentative...
on error resume next
f1.delete
'on error goto 0
end if
end if
Next
Set sf = objFolder.SubFolders
objF.WriteLine "dossiers restants :"
total = 0
For Each f1 in sf
taille = round(f1.size/1024/1024,2)
objF.WriteLine f1.name & " ("& taille &" Mo)"
total = total + taille
Next
profil2=profil - total
objF.WriteLine "Netoyage des profils, récupération de : " & profil2 & "Mo"
end if

' Lecture du fichier de désisntallation des softs

set objUnstSofts = objFSO.OpenTextFile(fileUninstall, ForReading)
Set dicUSofts = CreateObject("Scripting.Dictionary")
Do Until objUnstSofts.AtEndOfStream
Ligne=Split(objUnstSofts.ReadLine,";")
DicUSofts.Add Ligne(0), Ligne(2)
Loop
objUnstSofts.Close

objF.WriteLine "Nom" & vbtab & "Editeur" & vbtab & "Version" & vbtab & "Id"
Set colSoftware = objWMIService.ExecQuery ("Select * from Win32_Product")

For Each objSoftware in colSoftware
objF.WriteLine objSoftware.IdentifyingNumber&";"&objSoftware.Name&" "& objSoftware.Version
IdSoft=objSoftware.IdentifyingNumber
if IdSoft = "{FF77941A-2BFA-4A18-BE2E-69B9498E4D55}" then
WshShell.Run ("\\voillaume\netlogon\scripts\uchclean.bat" )
objSoftware.Uninstall()
objF.WriteLine "------------------------"
objF.WriteLine "Suppression de UchClean"
objF.WriteLine "------------------------"
rapLog = rapLog & sOrdi& ";"& Now &";"& "Suppression de UchClean" & VbCrLf
end If
if ((InStr(dicUSofts(IdSoft),"All_lpr") = 1) OR InStr(dicUSofts(IdSoft),salle)>0 OR (InStr(dicUSofts(IdSoft),secteur)>0)) then
objSoftware.Uninstall()
objF.WriteLine "-----------------------------------------------------"
objF.WriteLine "Désintallation de : " & objSoftware.Name
objF.WriteLine "-----------------------------------------------------"
rapLog = rapLog & sOrdi& ";"& Now &";"& "Suppression de : " & objSoftware.Name & VbCrLf
end if
Next
'désisntallation des composants WINDOWS
' fichier XP.INF au format : Nom;fichier inf;section inf;fichier à trouver pour lancer l'éxécution
objF.WriteLine "---------------------------------------------"
objF.WriteLine "Supression de composant windows, si besoin..."
Set objXP=objFSO.openTextFile(fileINF,ForReading)
Do Until objXP.AtEndOfStream
ligne=Split(objXP.ReadLine,";")
if objFSO.fileExists(ligne(3)) And (InSTR(ligne(4),"[All_lpr]")=1 Or InSTR(ligne(4),"["&salle&"]")>1) Then
WshShell.Run "rundll32 advpack.dll, LaunchINFSection %SYSTEMROOT%\Inf\"& Ligne(1)& " ,"& Ligne(2),1, true
objF.WriteLine "Suppression du composant windows : " & Ligne(0)
rapLog = rapLog & sOrdi& ";"& Now &";"& "Suppression de : " & Ligne(0) & VbCrLf
end If
Loop
objXP.close
objF.WriteLine "---------------------------------------------"

objF.WriteLine "----------------------------------------------------------"
objF.WriteLine " Journaux"
objF.WriteLine "----------------------------------------------------------"
' filtre des journaux, lecture du fichier filtre.txt
Set objDictionary = CreateObject("Scripting.Dictionary")
Set objFiltre=objFSO.openTextFile(fileFiltre,ForReading)

Do Until objFiltre.AtEndOfStream
Ligne=Split(objFiltre.ReadLine,";")
objDictionary.Add Ligne(1), Ligne(0)
Loop
objFiltre.close

' du script center, récupération des journaux depuis xjours
Set dtmStartDate = CreateObject("WbemScripting.SWbemDateTime")
Set dtmEndDate = CreateObject("WbemScripting.SWbemDateTime")
DateToCheck = CDate(Date)
dtmStartDate.SetVarDate DateToCheck-xjours, CONVERT_TO_LOCAL_TIME
dtmEndDate.SetVarDate DateToCheck , CONVERT_TO_LOCAL_TIME

Set colEvents = objWMIService.ExecQuery ("Select * from Win32_NTLogEvent Where TimeWritten >= '" & dtmStartDate & "' and TimeWritten < '" & dtmEndDate & "'")

For Each objEvent in colEvents
if ((Lcase(objEvent.Type) = "erreur" or Lcase(objEvent.Type)="avertissement") and not (objDictionary.item(CStr(objEvent.EventCode))=objEvent.SourceName)) Then
objF.WriteLine "Journal : " & objEvent.LogFile
objF.WriteLine "Event Type: " & objEvent.Type
objF.WriteLine "Time : " & Mid(objEvent.TimeWritten,7,2) & "-" & Mid(objEvent.TimeWritten,5,2) &"-" & Mid(objEvent.TimeWritten,1,4) _
& " à : " & Mid(objEvent.TimeWritten,9,2) & ":" & Mid(objEvent.TimeWritten,11,2) &":" & Mid(objEvent.TimeWritten,13,2)
objF.WriteLine "Event Code: " & objEvent.EventCode & " Source : " & objEvent.SourceName
objF.WriteLine "Utilisateur : " & objEvent.User
objF.WriteLine "Message : " & objEvent.Message
objF.WriteLine "-----------------"
end If
Next
objF.WriteLine "fin à : " & Now
objF.WriteLine "------------------------"
objF.Close
if rapLog <> "" then
Set objF=objFSO.openTextFile(fileRap,ForAppending)
objF.WriteLine rapLog
objF.Close
end if
end if


fichier de désisntallation des logiciels :

celui-ci se nome uninstall.sft

exemple de fichier :

{7148F0A8-6813-11D6-A77B-00B0D0142000};Java 2 Runtime Environment, SE v1.4.2;All_lpr
{7148F0A8-6813-11D6-A77B-00B0D0142030}; Java 2 Runtime Environment, SE v1.4.2_03;All_lpr
{7148F0A8-6813-11D6-A77B-00B0D0142060};Java 2 Runtime Environment, SE v1.4.2_06;All_lpr
{3248F0A8-6813-11D6-A77B-00B0D0150000};J2SE Runtime Environment 5.0;All_lpr
{3248F0A8-6813-11D6-A77B-00B0D0150020};J2SE Runtime Environment 5.0 Update 2;All_lpr
{3248F0A8-6813-11D6-A77B-00B0D0150050};J2SE Runtime Environment 5.0 Update 5;All_lpr
{3248F0A8-6813-11D6-A77B-00B0D0150060};J2SE Runtime Environment 5.0 Update 6;All_lpr
{3248F0A8-6813-11D6-A77B-00B0D0160000};Java(TM) SE Runtime Environment 6;All_lpr
{3248F0A8-6813-11D6-A77B-00B0D0160010};Java(TM) SE Runtime Environment 6 Update 1;All_lpr
{83F7144B-CE67-483B-BB16-AE66902439E4};eDrawings 2004 SP03;B13,B21
{6BE2A4A4-99FB-48ED-AE1E-4E850389F804};PartitionMagic 8;B23,C19
{ABEB838C-A1A7-4C5D-B7E1-8B4314600777};MSN Messenger 7.0;B22

les lignes sont obtenues à partir du fichier log. A la fin, on ajoute :

;All_lpr, si on veut supprimer ce logiciel de tout le domaine

;C19,C18 pour supprimer le logiciel des salles C19 et C18

 

filtre des évènements : filtre.txt

suppression de composants windows

FreeCell;games.inf;FreecellUninstall;C:\WINDOWS\system32\freecell.exe;[All_lpr]
Dame de Pique;games.inf;HeartsUninstall;C:\WINDOWS\system32\mshearts.exe;[All_lpr]
Démineur;games.inf;MinesweeperUninstall;C:\WINDOWS\system32\winmine.exe;[All_lpr]
Solitaire;games.inf;SolitaireUninstall;C:\WINDOWS\system32\sol.exe;[All_lpr]
Spider;games.inf;SpiderUninstall;C:\WINDOWS\system32\spider.exe;[All_lpr]
s
Pinball;Pinball.inf;PINBALL.Remove;C:\Program Files\Windows NT\Pinball\Pinball.exe;[All_lpr]
msn;msnmsn.inf;msnexplr.Uninstall;C:\Program Files\MSN\MSNCoreFiles\Install\msnsusii.exe;[All_lpr]
messenger;msmsgs.inf;BLC.Remove;C:\Program Files\Messenger\msmsgs.exe;[All_lpr]