2014-09-02 163 views
0

我試圖解析存檔安全日誌以跟蹤更改權限的問題。該腳本通過+10天之前的.evtx文件進行查詢。它目前輸出我想要的內容,但是當它清理舊日誌時(每天大約50GB,未壓縮,每個都通過午夜運行的另一個腳本存檔到它們自己的日常文件夾中),它開始抱怨日誌是在使用中並且不能被刪除。當我嘗試通過資源管理器刪除文件時,似乎正在使用的進程是DHCP客戶端或事件查看器,同時停止這兩種服務,但顯然我無法在沒有eventvwr的情況下運行。 DHCP客戶端用於網絡的好處,但不是必需的。如何解析和刪除Powershell中的存檔事件日誌

接觸.evtx文件的唯一東西就是這個腳本,它們沒有備份,它們不受其他任何東西的監控,它們不會被事件日誌服務自動分析,它們只是被存儲在磁盤上等待。

該腳本最初刪除的東西,因爲它去了,但後來失敗所有刪除被移動到最後,然後到KillLogWithFire()函數。即使計時器似乎沒有幫助。我也嘗試將文件移動到Processed子文件夾,但這不起作用的原因相同。

我認爲有一些方法可以釋放此腳本在任何文件上打開的任何句柄,但試圖在循環中的EventLog變量的.close()或.dispose()不起作用。

$XPath = @' 
*[System[Provider/@Name='Microsoft-Windows-Security-Auditing']] 
and 
*[System/EventID=4670] 
'@ 

$DeletableLogs = @() 
$logfile = "L:\PermChanges.txt" 
$AdminUsers = ("List","of","Admin","Users") 

$today = Get-Date 
$marker = " 
------------- 
$today 
------------- 
" 
write-output $marker >> $logfile 

Function KillLogWithFire($log){ 
    Try { 
     remove-item $log 
    } 
    Catch [writeerror]{ 
     $Timer += 1 
     sleep $timer 
     write-output "Killing log $log in $timer seconds" 
     KillLogWithFire($log) 
    } 
} 

Function LogPermissionChange($PermChanges){ 
    ForEach($PermChange in $PermChanges){ 
     $Change = @{} 
     $Change.ChangedBy = $PermChange.properties[1].value.tostring() 

     #Filter out normal non-admin users 
     if ($AdminUsers -notcontains $Change.ChangedBy){continue} 
     $Change.FileChanged = $PermChange.properties[6].value.tostring() 
     #Ignore temporary files 
     if ($Change.FileChanged.EndsWith(".tmp")){continue} 
     elseif ($Change.FileChanged.EndsWith(".partial")){continue} 

     $Change.MadeOn = $PermChange.TimeCreated.tostring() 
     $Change.OriginalPermissions = $PermChange.properties[8].value.tostring() 
     $Change.NewPermissions = $PermChange.properties[9].value.tostring() 

     write-output "{" >> $logfile 
     write-output ("Changed By   : "+ $Change.ChangedBy) >> $logfile 
     write-output ("File Changed   : "+ $Change.FileChanged) >> $logfile 
     write-output ("Change Made   : "+ $Change.MadeOn) >> $logfile 
     write-output ("Original Permissions : 
      "+ $Change.OriginalPermissions) >> $logfile 
     write-output ("New Permissions  : 
      "+ $Change.NewPermissions) >> $logfile 
     "} 
" >> $logfile 
    } 
} 

GCI -include Archive-Security*.evtx -path L:\Security\$Today.AddDays(-10) -recurse | ForEach-Object{ 
    Try{ 
     $PermChanges = Get-WinEvent -Path $_ -FilterXPath $XPath -ErrorAction Stop 
    } 
    Catch [Exception]{ 
     if ($_.Exception -match "No events were found that match the specified selection criteria."){ 
     } 
     else { 
      Throw $_ 
     } 
    } 
    LogPermissionChange($PermChanges) 
    $PermChanges = $Null 
    $DeletableLogs += $_ 
} 

foreach ($log in $DeletableLogs){ 
    $Timer = 0 
    Try{ 
     remove-item $log 
     } 
    Catch [IOException]{ 
     KillLogWithFire($log) 
    } 
} 

UPDATE

而不是編輯原始代碼,因爲我已經被告知不要做,我想後完整的代碼,現在使用作爲一個單獨的答案。初始部分,其解析日誌和運行每30分鐘是大多與上述相同:

$XPath = @' 
*[System[Provider/@Name='Microsoft-Windows-Security-Auditing']] 
and 
*[System/EventID=4670] 
'@ 

$DeletableLogs = @() 
$logfile = "L:\PermChanges.txt" 
$DeleteList = "L:\DeletableLogs.txt" 
$AdminUsers = ("List","Of","Admins") 

$today = Get-Date 
$marker = " 
------------- 
$today 
------------- 
" 
write-output $marker >> $logfile 

Function LogPermissionChange($PermChanges){ 
    ForEach($PermChange in $PermChanges){ 
     $Change = @{} 
     $Change.ChangedBy = $PermChange.properties[1].value.tostring() 

     #Filter out normal non-admin users 
     if ($AdminUsers -notcontains $Change.ChangedBy){continue} 
     $Change.FileChanged = $PermChange.properties[6].value.tostring() 
     #Ignore temporary files 
     if ($Change.FileChanged.EndsWith(".tmp")){continue} 
     elseif ($Change.FileChanged.EndsWith(".partial")){continue} 

     $Change.MadeOn = $PermChange.TimeCreated.tostring() 
     $Change.OriginalPermissions = $PermChange.properties[8].value.tostring() 
     $Change.NewPermissions = $PermChange.properties[9].value.tostring() 

     write-output "{" >> $logfile 
     write-output ("Changed By   : "+ $Change.ChangedBy) >> $logfile 
     write-output ("File Changed   : "+ $Change.FileChanged) >> $logfile 
     write-output ("Change Made   : "+ $Change.MadeOn) >> $logfile 
     write-output ("Original Permissions : 
      "+ $Change.OriginalPermissions) >> $logfile 
     write-output ("New Permissions  : 
      "+ $Change.NewPermissions) >> $logfile 
     "} 
" >> $logfile 
    } 
} 

GCI -include Archive-Security*.evtx -path L:\Security\ -recurse | ForEach-Object{ 
    Try{ 
     $PermChanges = Get-WinEvent -Path $_ -FilterXPath $XPath -ErrorAction Stop 
    } 
    Catch [Exception]{ 
     if ($_.Exception -match "No events were found that match the specified selection criteria."){ 
     } 
     else { 
      Throw $_ 
     } 
    } 
    LogPermissionChange($PermChanges) 
    $PermChanges = $Null 
    $DeletableLogs += $_ 
} 

foreach ($log in $DeletableLogs){ 
    write-output $log.FullName >> $DeleteList 
    } 

第二部分不刪除,包括上面承蒙TheMadTechnician提供的輔助函數。該代碼仍然是循環的直刪除比函數快,但並不總是成功的文件後,甚至年齡還沒有被觸動:

# Log Cleanup script. Works around open log issues caused by PS parsing of 
# saved logs in EventLogParser.ps1 

$DeleteList = "L:\DeletableLogs.txt" 
$DeletableLogs = get-content $DeleteList 

Function Close-LockedFile{ 
Param(
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)][String[]]$Filename 
) 
Begin{ 
    $HandleApp = 'C:\sysinternals\Handle.exe' 
    If(!(Test-Path $HandleApp)){Write-Host "Handle.exe not found at $HandleApp`nPlease download it from www.sysinternals.com and save it in the afore mentioned location.";break} 
} 
Process{ 
    $HandleOut = Invoke-Expression ($HandleApp+' '+$Filename) 
    $Locks = $HandleOut |?{$_ -match "(.+?)\s+pid: (\d+?)\s+type: File\s+(\w+?): (.+)\s*$"}|%{ 
     [PSCustomObject]@{ 
      'AppName' = $Matches[1] 
      'PID' = $Matches[2] 
      'FileHandle' = $Matches[3] 
      'FilePath' = $Matches[4] 
     } 
    } 
    ForEach($Lock in $Locks){ 
     Invoke-Expression ($HandleApp + " -p " + $Lock.PID + " -c " + $Lock.FileHandle + " -y") | Out-Null 
    If (! $LastexitCode) { "Successfully closed " + $Lock.AppName + "'s lock on " + $Lock.FilePath} 
    } 
} 
} 

Function KillLogWithFire($log){ 
    Try { 
     Close-LockedFile $Log - 
    } 
    Catch [System.IO.IOException]{ 
     $Timer += 1 
     sleep $timer 
    write-host "Killing $Log in $Timer seconds with fire." 
    KillLogWithFire($Log) 
    } 
} 

foreach ($log in $DeletableLogs){ 
    Try { 
     remove-item $log -ErrorAction Stop 
     } 
    Catch [System.IO.IOException]{ 
     $Timer = 0 
     KillLogWithFire($Log) 
     } 
    } 

remove-item $DeleteList 

回答

1

一個解決辦法是讓HANDLE.EXE並用它來關閉任何打開的手柄。這是我使用的大致基於this script的功能。它使用handle.exe,找到鎖定文件的內容,然後關閉鎖定該文件的句柄。

Function Close-LockedFile{ 
Param(
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)][String[]]$Filename 
) 
Begin{ 
    $HandleApp = 'C:\sysinternals\Handle.exe' 
    If(!(Test-Path $HandleApp)){Write-Host "Handle.exe not found at $HandleApp`nPlease download it from www.sysinternals.com and save it in the afore mentioned location.";break} 
} 
Process{ 
    $HandleOut = Invoke-Expression ($HandleApp+' '+$Filename) 
    $Locks = $HandleOut |?{$_ -match "(.+?)\s+pid: (\d+?)\s+type: File\s+(\w+?): (.+)\s*$"}|%{ 
     [PSCustomObject]@{ 
      'AppName' = $Matches[1] 
      'PID' = $Matches[2] 
      'FileHandle' = $Matches[3] 
      'FilePath' = $Matches[4] 
     } 
    } 
    ForEach($Lock in $Locks){ 
     Invoke-Expression ($HandleApp + " -p " + $Lock.PID + " -c " + $Lock.FileHandle + " -y") | Out-Null 
    If (! $LastexitCode) { "Successfully closed " + $Lock.AppName + "'s lock on " + $Lock.FilePath} 
    } 
} 
} 

我把handle.exe保存在C:\ Sysinternals中,你可能想調整函數中的路徑,或者在那裏保存可執行文件。

+0

謝謝,遺憾的是根據句柄問題的文件沒有打開,所以這並沒有幫助我。 :(但它確實向我展示瞭如何在交互式/不可讀的輸出方式中使用Handle,所以請注意這一點。再次感謝。 – 2014-09-03 16:34:27

+0

所以,只需要清楚,你可以在函數中添加一行, Close-LockedFile $ log'就在你的'Remove-Item $ log'這行之前?或者你只是在腳本的外部看着Handle的文件,並且看不到任何東西鎖定它們?不批評,只是想在同一頁面上。 – TheMadTechnician 2014-09-03 17:24:07

+0

昨天我在處理Handle,並沒有顯示任何文件被鎖定,而PS窗口反覆吐出文件中的使用錯誤;我沒有嘗試將此代碼添加到上面的腳本中,但是我嘗試過代碼在不同的腳本中,並且還沒有打開關於打開文件的任何阻塞錯誤,這在我之前一直都有。如果你想知道,我不介意測試上述內容嗎? – 2014-09-03 17:49:25

0

我有一個非常類似的問題,經過大量的搜索發現這篇文章。雖然handle.exe工作,當我第一次嘗試時,我注意到-c帶有警告「關閉手柄可能導致應用程序或系統不穩定」

我也使用get-winevent,它似乎(有時)鎖定.evtx正在處理的文件。我寫了一個循環等待5秒重試。有時最多需要2分鐘或文件才能發佈,我已經在一夜之間運行了一次,並且有數百次重試。

當我第一次使用處理它完美的工作。然後我將它實現到腳本中,後來發現它正在循環一個「無法解釋的錯誤」。最後,我不得不重新啓動服務器以重新開始工作,因此從腳本中刪除handle.exe並返回到等待文件關閉。

我可以通過停止腳本並關閉powershell ise來可靠地釋放該文件。一旦ISE關閉,文件可以被刪除而不會出現問題。

不幸的是,我需要這個腳本繼續運行,而不是被保持打開的文件阻擋。我很驚訝,不得不求助於sysinternals來釋放文件,並且powershell不提供關閉文件的簡單方法。

0

我和GTEM有同樣的問題,在處理數百個事件日誌文件時,關閉句柄會導致損壞。最終Get-WinEvent將無法正常工作。它會凍結或給我相同的「無法解釋的錯誤」。 因此,我用MS開了一個重要案例。他們把我引導到我正在存儲Get-WinEvent事件的實際變量是什麼鎖定了文件。我想如果你仍然在使用這個變量,它實際上並不解鎖文件。所以爲了解決這個問題,我在將變量傳遞給一個新變量後,向腳本添加了一些代碼。您可以看到我在下面列出的第三個區域添加的代碼。

#*************************************************************************** 
#region *** Get the log entries. 
# clear the log entry for each pass 
$LogEntry = @() 

# Get the vent from the log file and export it to the logentry variable and output to the screen 
Get-WinEvent -Path $NewPath -FilterXPath $XPathFilter -ErrorAction SilentlyContinue | Tee-Object -Variable LogEntry 
#endregion *** End get the log entries 
#*************************************************************************** 

#*************************************************************************** 
#region *** This is where I copy it to the new variable for later output. 
# if there are any log entries 
if ($LogEntry.Count -gt 0) { 

    # Add the log entries to the log file 
    $LogEntries += $LogEntry 

} # if there are any log entries 
#endregion *** End were I copy to the new variable. 
#*************************************************************************** 

#*************************************************************************** 
#region *** This is where I added code to allow me to remove the file lock. 
# Remove the variable to release the evtx file lock 
Remove-Variable -Name LogEntry 

# Garbage collect to remove any additional memory tied to the file lock. 
[GC]::Collect() 

# sleep for 1 seconds 
Sleep -Seconds 1 
#endregion **** Code to remove the file lock. 
#*************************************************************************** 

完成此操作後,我不再需要使用Handle.exe來關閉文件了。