powershell scripting cmd

Mire el archivo para ver los cambios y ejecute el comando con powershell



scripting cmd (7)

  1. Calcular el hash de una lista de archivos
  2. Guárdelo en un diccionario.
  3. Verifique cada hash en un intervalo
  4. Realizar acciones cuando el hash es diferente

function watch($f, $command, $interval) { $sha1 = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider $hashfunction = ''[System.BitConverter]::ToString($sha1.ComputeHash([System.IO.File]::ReadAllBytes($file)))'' $files = @{} foreach ($file in $f) { $hash = iex $hashfunction $files[$file.Name] = $hash echo "$hash`t$($file.FullName)" } while ($true) { sleep $interval foreach ($file in $f) { $hash = iex $hashfunction if ($files[$file.Name] -ne $hash) { iex $command } } } }

Ejemplo de uso:

$c = ''send-mailmessage -to "[email protected]" -from "[email protected]" -subject "$($file.Name) has been altered!"'' $f = ls C:/MyFolder/aFile.jpg watch $f $c 60

¿Hay alguna forma simple (es decir, script) para ver el archivo en powershell y ejecutar comandos si el archivo cambia. He estado buscando en Google pero no puedo encontrar una solución simple. Básicamente ejecuto el script en PowerShell y si el archivo cambia, PowerShell ejecuta otros comandos.

EDITAR

Ok, creo que cometí un error. No necesito script, una función de necesidad que puedo incluir en mi archivo $PROFILE.ps1 . Pero aún así, me estaba poniendo duro y todavía no puedo escribirlo, así que daré recompensas. Tiene que verse así:

function watch($command, $file) { if($file #changed) { #run $command } }

Hay un módulo npm que está haciendo lo que quiero, watch , pero solo busca carpetas, no archivos, y no es powershell xD.


Agregaré otra respuesta, porque la anterior no cumplió con los requisitos.

Requisitos

  • Escribir una función para ESPERAR un cambio en un archivo específico
  • Cuando se detecta un cambio, la función ejecutará un comando predefinido y devolverá la ejecución al script principal
  • La ruta del archivo y el comando se pasan a la función como parámetros

Ya hay una respuesta usando hashes de archivos. Quiero seguir mi respuesta anterior y mostrarle cómo se puede lograr esto usando FileSystemWatcher.

$File = "C:/temp/log.txt" $Action = ''Write-Output "The watched file was changed"'' $global:FileChanged = $false function Wait-FileChange { param( [string]$File, [string]$Action ) $FilePath = Split-Path $File -Parent $FileName = Split-Path $File -Leaf $ScriptBlock = [scriptblock]::Create($Action) $Watcher = New-Object IO.FileSystemWatcher $FilePath, $FileName -Property @{ IncludeSubdirectories = $false EnableRaisingEvents = $true } $onChange = Register-ObjectEvent $Watcher Changed -Action {$global:FileChanged = $true} while ($global:FileChanged -eq $false){ Start-Sleep -Milliseconds 100 } & $ScriptBlock Unregister-Event -SubscriptionId $onChange.Id } Wait-FileChange -File $File -Action $Action


Aquí está la solución que terminé basada en varias de las respuestas anteriores aquí. Yo específicamente quería:

  1. Mi código es código, no una cadena
  2. Mi código se ejecutará en el hilo de E / S para poder ver la salida de la consola
  3. Mi código se llamará cada vez que haya un cambio, ni una sola vez

Nota al margen: he dejado los detalles de lo que quería ejecutar debido a la ironía de usar una variable global para comunicarse entre hilos para poder compilar el código Erlang.

Function RunMyStuff { # this is the bit we want to happen when the file changes Clear-Host # remove previous console output & ''C:/Program Files/erl7.3/bin/erlc.exe'' ''program.erl'' # compile some erlang erl -noshell -s program start -s init stop # run the compiled erlang program:start() } Function Watch { $global:FileChanged = $false # dirty... any better suggestions? $folder = "M:/dev/Erlang" $filter = "*.erl" $watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{ IncludeSubdirectories = $false EnableRaisingEvents = $true } Register-ObjectEvent $Watcher "Changed" -Action {$global:FileChanged = $true} > $null while ($true){ while ($global:FileChanged -eq $false){ # We need this to block the IO thread until there is something to run # so the script doesn''t finish. If we call the action directly from # the event it won''t be able to write to the console Start-Sleep -Milliseconds 100 } # a file has changed, run our stuff on the I/O thread so we can see the output RunMyStuff # reset and go again $global:FileChanged = $false } } RunMyStuff # run the action at the start so I can see the current output Watch

Puede pasar la carpeta / filtro / acción al reloj si desea algo más genérico. Esperemos que este sea un punto de partida útil para otra persona.


Aquí hay otra opción.

Solo necesitaba escribir el mío para ver y ejecutar pruebas dentro de un contenedor Docker. La solución de Jan es mucho más elegante, pero FileSystemWatcher está roto dentro de los contenedores Docker actualmente. Mi enfoque es similar al de Vasili, pero mucho más vago, confiando en el tiempo de escritura del sistema de archivos.

Aquí está la función que necesitaba, que ejecuta el bloque de comandos cada vez que cambia el archivo.

function watch($command, $file) { $this_time = (get-item $file).LastWriteTime $last_time = $this_time while($true) { if ($last_time -ne $this_time) { $last_time = $this_time invoke-command $command } sleep 1 $this_time = (get-item $file).LastWriteTime } }

Aquí hay uno que espera hasta que el archivo cambie, ejecuta el bloque y luego sale.

function waitfor($command, $file) { $this_time = (get-item $file).LastWriteTime $last_time = $this_time while($last_time -eq $this_time) { sleep 1 $this_time = (get-item $file).LastWriteTime } invoke-command $command }


Aquí hay un ejemplo que he encontrado en mis fragmentos. Esperemos que sea un poco más completo.

Primero necesita crear un observador del sistema de archivos y luego suscribirse a un evento que el observador está generando. Este ejemplo escucha los eventos "Crear", pero podría modificarse fácilmente para estar atento a "Cambiar".

$folder = "C:/Users/LOCAL_~1/AppData/Local/Temp/3" $filter = "*.LOG" $Watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{ IncludeSubdirectories = $false NotifyFilter = [IO.NotifyFilters]''FileName, LastWrite'' } $onCreated = Register-ObjectEvent $Watcher -EventName Created -SourceIdentifier FileCreated -Action { $path = $Event.SourceEventArgs.FullPath $name = $Event.SourceEventArgs.Name $changeType = $Event.SourceEventArgs.ChangeType $timeStamp = $Event.TimeGenerated Write-Host "The file ''$name'' was $changeType at $timeStamp" Write-Host $path #Move-Item $path -Destination $destination -Force -Verbose }

Intentaré reducir esto a sus requisitos.

Si ejecuta esto como parte de su script "profile.ps1", debería leer The Power of Profiles, que explica los diferentes scripts de perfil disponibles y más.

Además, debe comprender que esperar un cambio en una carpeta no se puede ejecutar como una función en el script. El script de perfil debe estar terminado para que se inicie su sesión de PowerShell. Sin embargo, puede usar una función para registrar un evento.

Lo que esto hace es registrar un fragmento de código, que se ejecutará cada vez que se active un evento. Este código se ejecutará en el contexto de su host PowerShell actual (o shell) mientras la sesión permanezca abierta. Puede interactuar con la sesión de host, pero no tiene conocimiento del script original que registró el código. El script original probablemente ya haya terminado, para cuando se active su código.

Aquí está el código:

Function Register-Watcher { param ($folder) $filter = "*.*" #all files $watcher = New-Object IO.FileSystemWatcher $folder, $filter -Property @{ IncludeSubdirectories = $false EnableRaisingEvents = $true } $changeAction = [scriptblock]::Create('' # This is the code which will be executed every time a file change is detected $path = $Event.SourceEventArgs.FullPath $name = $Event.SourceEventArgs.Name $changeType = $Event.SourceEventArgs.ChangeType $timeStamp = $Event.TimeGenerated Write-Host "The file $name was $changeType at $timeStamp" '') Register-ObjectEvent $Watcher -EventName "Changed" -Action $changeAction } Register-Watcher "c:/temp"

Después de ejecutar este código, cambie cualquier archivo en el directorio "C: / temp" (o cualquier otro directorio que especifique). Verá un evento que desencadena la ejecución de su código.

Además, los eventos válidos de FileSystemWatcher que puede registrar son "Modificado", "Creado", "Eliminado" y "Renombrado".


Puede usar System.IO.FileSystemWatcher para monitorear un archivo.

$watcher = New-Object System.IO.FileSystemWatcher $watcher.Path = $searchPath $watcher.IncludeSubdirectories = $true $watcher.EnableRaisingEvents = $true

Ver también este artículo


Tuve un problema similar. Primero quise usar eventos de Windows y registrarme, pero esto sería menos tolerante a fallas como la solución a continuación.
Mi solución fue un script de sondeo (intervalos de 3 segundos). El script tiene una huella mínima en el sistema y nota los cambios muy rápidamente. Durante el ciclo, mi script puede hacer más cosas (en realidad verifico 3 carpetas diferentes).

Mi script de sondeo se inicia a través del administrador de tareas. El cronograma se inicia cada 5 minutos con el indicador de detener cuando ya se está ejecutando. De esta manera, se reiniciará después de un reinicio o después de un bloqueo.
Usar el administrador de tareas para sondear cada 3 segundos es demasiado frecuente para el administrador de tareas. Cuando agrega una tarea al planificador, asegúrese de no usar unidades de red (eso requeriría configuraciones adicionales) y otorgue privilegios por lotes a su usuario.

Le doy a mi guión un comienzo limpio al cerrarlo unos minutos antes de la medianoche. El administrador de tareas inicia el script cada mañana (la función init de mi script saldrá 1 minuto alrededor de la medianoche).