若有個需求:要求記錄下某個目錄下的所有操作,包括創建文件、修改文件、重命名、刪除文件的操作,將以上所有的操作全部記錄到日志中,或者做其他操作。.NET提供了一個方法叫做“System.IO.FileSystemWatcher”,方便powershell來調用。具體使用方法,我慢慢解釋。
一、監控某個目錄下的所有操作
方案一:
$folder = "c:\test" #定義要監控哪個目錄 $timeout = 1000 #設置監控的時間間隔 $filesystemwatcher = new-object System.IO.FileSystemWatcher $folder #使用FileSystemWatcher方法開啟文件監控
echo "ctrl+c will exit" while ($true) { $result = $filesystemwatcher.WaitForChanged("all",$timeout) #監控種類,all代表監控所有操作,$timeout表示監控的時間間隔 if($result.TimedOut -eq $false) #$result.TimedOut返回true或false,若目錄下不操作返回true,
{ $time = date -UFormat "%Y-%m-%d %H-%M-%S" $type = $result.ChangeType $name = $result.Name $oldname = $result.OldName echo "$time $type $name $oldname " #顯示如下信息,時間、 操作的類型、操作文件的名稱、操作文件原來的名稱,只有重命名后才會顯示 } }
測試:
在c:\test目錄下增刪改查一些文件

終端返回的結果:

在所執行的終端執行ctrl+c或者關閉終端即可終止監控程序。
方案二:
該方案與方案一不同的一點是,方案二會在后台運行,但方案一由while循環運行。
$watcher = New-Object System.IO.FileSystemWatcher #啟動監控實例 $watcher.Path = "c:\test\" #監控的路徑 $watcher.IncludeSubdirectories = $true #是否監控子目錄下的文件操作 $watcher.EnableRaisingEvents = $true #默認是true
#重寫changed、created、deleted、renamed方法 $changed = Register-ObjectEvent $watcher "Changed" -Action { $time = date -UFormat "%Y-%m-%d %H-%M-%S" write-host " $time Changed: $($eventArgs.FullPath)" } $created = Register-ObjectEvent $watcher "Created" -Action { $time = date -UFormat "%Y-%m-%d %H-%M-%S" write-host "$time Created: $($eventArgs.FullPath)" } $deleted = Register-ObjectEvent $watcher "Deleted" -Action { $time = date -UFormat "%Y-%m-%d %H-%M-%S" write-host "$time Deleted: $($eventArgs.FullPath)" } $renamed = Register-ObjectEvent $watcher "Renamed" -Action { $time = date -UFormat "%Y-%m-%d %H-%M-%S" write-host "$time Renamed: $($eventArgs.FullPath)" }
測試:
在被監控的目錄下增刪改查操作


返回的結果:

但是方案二退出與方案一的不一致。
1、退出當前執行的終端,可以退出整個監控程序
2、手動注銷事件,注銷以上重新的方法,需要在程序運行的終端執行
Unregister-Event $changed.Id Unregister-Event $created.Id Unregister-Event $deleted.Id Unregister-Event $renamed.Id

紅框內的內容是輸入進去的。
二、實時同步
有了目錄監控的能力,可以擴展一下,實現文件實時同步。
有兩個目錄,目錄A中凡是有了任何操作,便同步到B目錄中,實現實時同步。具體代碼如下:
【注意】
代碼中監聽操作的時間隔是1000ms,若兩相鄰操的時間間隔作小於1000ms時,就會出現不同步的問題
$folder = "\\share-server\t" #監聽的源目錄
$timeout = 1000 #時間間隔,ms
$filesystemwatcher = new-object System.IO.FileSystemWatcher $folder
$filesystemwatcher.IncludeSubdirectories = $true #開啟監聽子目錄的功能
$des = "c:\test" #同步的目標目錄
$logpath = "c:\test\logs\a.log" #日志記錄的位置,需要提前創建好日志的父目錄
echo "ctrl+c will exit"
cp -Force -Recurse $folder\* $des #先將源目錄中的所有文件拷貝到子目錄中
while ($true) #開啟監聽
{
$result = $filesystemwatcher.WaitForChanged("all",$timeout)
if($result.TimedOut -eq $false)
{
$time = date -UFormat "%Y-%m-%d %H:%M:%S"
$type = $result.ChangeType
$name = $result.Name
$oldname = $result.OldName
echo "$time $type $name oldname:$oldname " >> $logpath #輸出日志
$isfile = $true
$filefullpath = $folder + "\" + $name #源文件的全路徑
$dstpath = $des + "\" + $name #目標文件的全路勁
if( Test-Path $filefullpath ){ $filepath = $filefullpath } #當刪除時,源文件的全路徑不存在,需要借助目標文件的全路徑來判斷是文件還是目錄
if( Test-Path $dstpath ){ $filepath = $dstpath }
if ( (ls $filepath) -is [IO.fileinfo]) #判斷是文件還是目錄
{
$isfile = $true
}
else
{
$isfile = $false
}
#根據不同的操作類型做出不同的操作
if( $type -eq "Changed" )
{
if( $isfile )
{
cp $filefullpath $dstpath
echo "cp $filefullpath $dstpath" >> $logpath
}
}
if( $type -eq "Created" )
{
if( $isfile )
{
New-Item $dstpath
echo "cp $filefullpath $des" >> $logpath
}
else
{
mkdir $dstpath
echo "mkdir $dstpath" >> $logpath
}
}
if( $type -eq "Deleted" )
{
rm -Recurse -Force $dstpath
echo "rm $dstpath" >> $logpath
}
if( $type -eq "Renamed" )
{
cd $des
mv $oldname $name
echo "mv $oldname $name" >> $logpath
}
}
}
測試:


日志結果:

【注意】
以上代碼存在一個缺陷,當文件在不同的目錄下移動時,會有異常,只有修改一下代碼邏輯便可實現。
