107 votes

Comment surveiller un dossier et déclencher une action en ligne de commande lorsqu'un fichier est créé ou modifié ?

J'ai besoin de mettre en place une sorte de script sur ma machine Vista, de sorte que chaque fois qu'un fichier est ajouté à un dossier particulier, cela déclenche automatiquement un processus d'arrière-plan qui opère sur le fichier. (Le processus d'arrière-plan est juste un utilitaire de ligne de commande qui prend le nom du fichier comme argument, ainsi que quelques autres options prédéfinies).

J'aimerais faire cela en utilisant les fonctionnalités natives de Windows, si possible, pour des raisons de performance et de maintenance. J'ai envisagé d'utiliser le planificateur de tâches, mais après avoir parcouru le système de déclenchement pendant un certain temps, je n'ai pas été en mesure de lui donner beaucoup de sens, et je ne suis même pas sûr qu'il soit capable de faire ce dont j'ai besoin.

J'apprécierais toute suggestion. Merci !

119voto

Janis Veinbergs Points 4959

Au travail, nous utilisons Powershell pour surveiller les dossiers.
Il peut être utilisé depuis Windows Vista (.NET et PowerShell sont préinstallés) sans aucun outil supplémentaire.

Ce script surveille un certain dossier et écrit un fichier journal. Vous pouvez remplacer l'action et faire ce que vous voulez, par exemple appeler un outil externe.

Exemple de fichier journal

11/23/2014 19:22:04, Created, D:\\source\\New Text Document.txt
11/23/2014 19:22:09, Changed, D:\\source\\New Text Document.txt
11/23/2014 19:22:09, Changed, D:\\source\\New Text Document.txt
11/23/2014 19:22:14, Deleted, D:\\source\\New Text Document.txt

StartMonitoring.ps1

### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = "D:\source"
    $watcher.Filter = "*.*"
    $watcher.IncludeSubdirectories = $true
    $watcher.EnableRaisingEvents = $true  

### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
    $action = { $path = $Event.SourceEventArgs.FullPath
                $changeType = $Event.SourceEventArgs.ChangeType
                $logline = "$(Get-Date), $changeType, $path"
                Add-content "D:\log.txt" -value $logline
              }    
### DECIDE WHICH EVENTS SHOULD BE WATCHED 
    Register-ObjectEvent $watcher "Created" -Action $action
    Register-ObjectEvent $watcher "Changed" -Action $action
    Register-ObjectEvent $watcher "Deleted" -Action $action
    Register-ObjectEvent $watcher "Renamed" -Action $action
    while ($true) {sleep 5}

Mode d'emploi

  1. Créer un nouveau fichier texte
  2. Copiez et collez le code ci-dessus
  3. Adaptez les paramètres suivants à vos propres besoins :
    • dossier à surveiller : $watcher.Path = "D:\source"
    • filtre de fichiers pour n'inclure que certains types de fichiers : $watcher.Filter = "*.*"
    • inclure les sous-répertoires oui/non : $watcher.IncludeSubdirectories = $true
  4. Sauvegardez-le et renommez-le en StartMonitoring.ps1
  5. Commencez le suivi en Clic droit " Exécuter avec PowerShell

Pour arrêter le monitoring, il suffit de fermer votre fenêtre PowerShell

Autres lectures

6voto

Linker3000 Points 26898

Vous semblez être sur la bonne voie - vous pourriez utiliser le planificateur de tâches pour exécuter régulièrement un fichier .bat ou .cmd et ce fichier pourrait commencer par une ligne pour vérifier l'existence du fichier requis - en fait, je vérifierais l'inexistence du fichier ; par exemple :

@ECHO OFF
REM Example file
IF NOT EXIST C:\SOMEWHERE\SUBFOLDER\THISFILE.THS EXIT 1
REM All this gets done if the file exists...
:
:
EXIT 0

Vous pouvez également modifier ce code et le faire tourner en boucle avec un délai d'une minute, par exemple, et placer une référence au fichier batch dans le dossier de démarrage de Windows :

@ECHO OFF
REM Example file
:LOOP    
IF NOT EXIST C:\SOMEWHERE\SUBFOLDER\THISFILE.THS GOTO SKIP01
REM All this gets done if the file exists...
:
:
:SKIP01
REM Crafty 1 minute delay...
PING 1.1.1.1 -n 10 -w 6000 >NUL
GOTO LOOP

Il existe d'autres moyens d'obtenir un délai en fonction de la version de Windows utilisée et des kits de ressources supplémentaires installés, mais la commande PING fonctionne pratiquement en toutes circonstances. Dans la commande PING ci-dessus, 10 PINGS fantômes sont exécutés avec un délai de 6000ms (c'est-à-dire 6 secondes) entre eux, vous pouvez jouer avec ces valeurs pour obtenir le délai dont vous avez besoin entre les boucles de fichiers batch.

6voto

bigmattyh Points 1414

Merci à tous pour les suggestions.

J'ai fini par écrire un VBScript qui était grossièrement basé sur l'idée de Linker3000 de sonder le dossier, et d'utiliser le planificateur de tâches pour le faire fonctionner au démarrage. J'ai fini par obtenir la syntaxe de base de cette ressource et fait les ajustements nécessaires.

J'aimerais encore l'optimiser à un moment donné, en faisant fonctionner les entrailles du script sur un système événementiel, mais je n'ai plus le temps de travailler dessus, et, eh bien, ceci est suffisant.

Voici le script, au cas où cela intéresserait quelqu'un (avec le segment de conversion non pertinent expurgé pour plus de clarté) :

' FOLDER TO MONITOR
strFolder = "J:\monitored-folder"

' FREQUENCY TO CHECK IT, IN SECONDS
nFrequency = 10

strComputer = "."
strQueryFolder = Replace(strFolder, "\", "\\\\")
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" &     strComputer & "\root\cimv2") 
Set colMonitoredEvents = objWMIService.ExecNotificationQuery ("SELECT * FROM __InstanceCreationEvent WITHIN " & nFrequency & " WHERE Targetinstance ISA 'CIM_DirectoryContainsFile' and TargetInstance.GroupComponent='Win32_Directory.Name=""" & strQueryFolder & """'") 

Do 
    Set objLatestEvent = colMonitoredEvents.NextEvent
    strNewFile = objLatestEvent.TargetInstance.PartComponent
    arrNewFile = Split(strNewFile, "=")
    strFilePath = arrNewFile(1)
    strFilePath = Replace(strFilePath, "\\", "\")
    strFilePath = Replace(strFilePath, Chr(34), "")
    strFileName = Replace(strFilePath, strFolder, "")
    strTempFilePath = WScript.CreateObject("Scripting.FileSystemObject").GetSpecialFolder(2) & "\TEMP.M4A"

    ' DO THE OPERATION STUFF
    ' ...
Loop

(Aussi, je ne veux pas laisser cette question officiellement sans réponse -- et je déteste accepter ma propre réponse à la question -- mais j'ai upvote la réponse de Linker3000 en guise de remerciement).

5voto

weberjn Points 421

Si l'action consiste simplement à copier les fichiers modifiés, vous pouvez utiliser robocopy /MON:1

Je ne sais pas si robocopy utilise FileSystemWatcher ou fonctionne par sondage pour les changements.

3voto

Sun Points 5974

Vous pouvez regarder DropIt (gratuit). Le programme est approprié pour traiter les fichiers entrants de manière automatisée. Vous pouvez déplacer, copier, supprimer et passer des paramètres à d'autres programmes en ligne de commande pour convertir des images, diviser des PDF, etc.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X