Vigiar o ficheiro de alterações e executar o comando com o 'powershell'
Existe alguma forma simples (isto é, script) de ver o ficheiro em Powershell e executar comandos se o ficheiro mudar. Tenho pesquisado no Google, mas não encontro uma solução simples. Basicamente eu corro script em Powershell e se o arquivo muda então Powershell executar outros comandos.
Acho que cometi um erro. Eu não preciso de script, uma função necessária que eu possa incluir no meu arquivoeditar
$PROFILE.ps1
. Mas mesmo assim, estava a esforçar-me e mesmo assim não consigo escrevê-lo, por isso vou dar-lhe recompensa. Tem de ser assim:
function watch($command, $file) {
if($file #changed) {
#run $command
}
}
Existe um módulo NPM que está a fazer o que eu quero, {[[2]} , mas ele só vigia pastas Não ficheiros, e não é Powershell xD.
7 answers
Primeiro precisa de criar um observador do sistema de ficheiros e, posteriormente, subscrever um evento que o observador está a gerar. Este exemplo escuta Eventos "Criar", mas pode ser facilmente modificado para ter cuidado com a"mudança".
$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
}
Vou tentar reduzir isto às tuas necessidades.
Se executar isto como parte do seu programa "profile.ps1", deve ler o poder dos perfis o que explica os diferentes scripts de perfis disponÃveis e muito mais.
Também, você deve entender que esperar por uma mudança em uma pasta não pode ser executado como uma função no script. O script do perfil tem de ser terminado, para que a sua sessão PowerShell comece. Você pode, no entanto, usar uma função para registrar um evento.
O que isto faz, é registar um pedaço de código, para ser executado sempre que um evento é despoletado. Este código será executado no contexto da sua máquina PowerShell actual (ou shell) enquanto a sessão permanece aberta. Ele pode interagir com a sessão de host, mas não tem conhecimento do script original que registrou o código. O script original já deve ter terminado, quando o seu código for despoletado.
Aqui está o 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"
Depois de executar este código, mude QUALQUER ficheiro no "C:\temp" directory (or any other directory you specify). Verá um evento que desencadeia a execução do seu código.
Também, os eventos válidos do FileSystemWatcher que você pode registrar são "alterados", "criados", "excluÃdos"e " renomeados".
Requisitos
- escreva uma função para espere por uma alteração num ficheiro especÃfico
- Quando for detectada uma alteração, a função irá executar um comando predefinido e devolver a execução ao programa principal
- a localização e o comando do Ficheiro são passados à função como parâmetros
Já existe uma resposta usando os traços dos ficheiros. Quero seguir o meu resposta anterior e mostrar-lhe como isso pode ser realizado 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
Pode usar o System.IO.FileSystemWatcher
para monitorizar um ficheiro.
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = $searchPath
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
Ver também este artigo
- o meu código para ser Código, não um texto
- O meu código a ser executado na linha de E / S para que eu possa ver a saÃda da consola
- o meu código a ser chamado sempre que houve uma mudança, não uma vez
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
Pode passar na pasta/filtro / acção para vigiar se quiser algo mais genérico. Esperemos que este seja um ponto de partida útil para outra pessoa.
- calcular o hash de uma lista de ficheiros
- Guarde-o num dicionário
- Verifique cada faixa num intervalo
- efectuar a acção quando o hash é 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
}
}
}
}
Uso de exemplo:
$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
Minha solução foi um script de votação (intervalos de 3 segundos). O script tem uma pegada mÃnima no sistema e nota mudanças muito rapidamente. Durante o loop meu script pode fazer mais coisas (na verdade, eu verifico 3 pastas diferentes). O meu programa de sondagens é iniciado através do Gestor de Tarefas. O horário começa a cada 5 minutos com o parar a bandeira-quando-já-está-a correr. Desta forma, irá reiniciar após um reiniciamento ou após um estoiro.
Usar o Gerenciador de tarefas para a votação a cada 3 segundos é muito frequente para o Gerenciador de Tarefas. Quando você adicionar uma tarefa ao scheduler certifique-se de que você não usa unidades de rede (que iria pedir configurações extras) e dar os privilégios de lote do seu usuário. Dou um bom começo ao meu guião, fechando-o alguns minutos antes da meia-noite. O Gestor de Tarefas inicia o script todas as manhãs (a função init de my script will exit 1 minute around midnight).
Aqui está a função que eu precisava, que executa o bloco de comando cada vez que o arquivo muda.
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
}
}
Aqui está um que espera até o arquivo mudar, executa o bloqueia, depois sai.
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
}