removing items

Hey,

I need little help, I configured the security event log to automatically backup and clear itself when it’s full, so .evtx files starting with word Archive are being created in the log folder.
I created a script which I want it to be run on weekly basis to extract a particular events related to deletion of files, save them in xml file and then delete those .evtx files.
however when I run the script it gives error that the .evtx files can’t be deleted because they are being used by another process, is there anyway around this? you can find below my script:

$loc = Get-ChildItem “D:\Logs\archive*”

Get-WinEvent -FilterHashtable @{ path = $loc ; ID = 4659} |

Select-Object -Property TimeCreated,

@{ n = “AccountName” ; e = {($_.Message.split(“`n”))[4].Substring(16) } } ,

@{ n = “ObjectName” ; e = {($_.Message.split(“`n”))[11].Substring(14) } } |

? {$.ObjectName -notlike “~$” -and $.ObjectName -notlike “.tmp”} |

Export-Clixml -Path “D:\Logs$(((Get-Date).AddDays(-1).ToShortDateString()).Replace(”/“,”-“)).xml”

Remove-Item -Path $loc

Really No body?

Are all of your .evtx files used by another process or just some or one? Did you try to figure out what process is blocking them?

I tried, and I think it is the same the powershell session that that the script is using to extract info from them, I tried to use start-sleep with up 10 seconds thinking that it might help but it didn’t, however after the script has been executed I can delete them normally via any mean

thanks

... and I think it is ...
The best way to know is not to guess. There are tools to determine what process is blocking a file - use it! ;-)

Declare the $loc again before the remove-item. Best guess, $loc has them committed to memory.

I decided to test this, and found something interesting;

I went into my event viewer and saved a handful of recent events (just random events, nothing special), then performed the same steps you were doing, pointing at the saved test.evtx file that I created and picking an ID that happened to appear a few times in the sample I grabbed. What was interesting is that after executing the command (Get-WinEvent), I could not delete the test.evtx file I’d created using Explorer (it claimed that DHCP Client was locking it, which I think is really odd, and somewhat doubtful). Waiting for a period of time did not change this, but after executing another command (a simple Get-ChildItem worked), the file was unlocked and I could delete it.

I was able to repeat this several times, so Get-WinEvent appears to be locking the file until you do something else with the shell.

Since a Start-Sleep didn’t fix this for you (I just tested, and it worked for me), I’m going to guess that when running from a script, it’s not going to drop the lock until the scope changes.

I have an idea and will post back after I’ve tested to see if it works.

Okay, this is a bit hacky, but by throwing the Get-WinEvent command into an Invoke-Command scriptblock, you will exit the context scope that is locking the file.

Long story short, this test code worked on my test file:

invoke-command -scriptblock { 
	$loc = ls 'C:\temp\test - Copy.evtx'
	get-winevent -FilterHashtable @{path = $loc; id = 63} 
}

rm $loc

So, give this a try and see if it fixes your problem:

Invoke-Command -ScriptBlock {
	$loc = Get-ChildItem "D:\Logs\archive*"

	Get-WinEvent -FilterHashtable @{ path = $loc ; ID = 4659} |
		Select-Object -Property TimeCreated,
			@{ n = "AccountName" ; e = {($_.Message.split("`n"))[4].Substring(16) } } ,
			@{ n = "ObjectName" ; e = {($_.Message.split("`n"))[11].Substring(14) } } |
		where {$_.ObjectName -notlike "*~$*" -and $_.ObjectName -notlike "*.tmp*"} |
	Export-Clixml -Path "D:\Logs\$(((Get-Date).AddDays(-1).ToShortDateString()).Replace("/","-")).xml"
}

Remove-Item -Path $loc

unfortunately “The Powershell bear” that hasn’t work either, I got the error:
Remove-Item : Cannot bind argument to parameter ‘Path’ because it is null.

but you kinda opened my eyes in the scope issue, so I’ll play a bit with invoke-command and see what I can get

oh yeah “Dan Potter” I don’t want to declare $loc again, the whole purpose of the variable anyway is that I don’t want the script when starts off checks against for instance 3 .evtx logs but before the it complete its execution the event log clears it self and saves new evtx file (I know the chances are really slim here but nonetheless) so the remove-item cmdlets remove 4 logs instead of 3
I want the script to deletes only what it has extracted information from

hi “Olaf Soyk” I checked using “find handle or Dll” of “Process Explorer” right after executing the cmdlet in the powershell, and it showed that svchost.exe was locking them, not really sure how much helpful this is

Unfortunately that’s much less helpfull than I hoped. :frowning: But lets try to improve the Bears code a little:

$loc = Get-ChildItem “D:\Logs\archive*”
Invoke-Command -ScriptBlock {
Get-WinEvent -FilterHashtable @{ path = $args[0] ; ID = 4659} |
Select-Object -Property TimeCreated,
@{ n = “AccountName” ; e = {($.Message.split(“`n”))[4].Substring(16) } } ,
@{ n = “ObjectName” ; e = {($
.Message.split(“`n”))[11].Substring(14) } } |
where {$.ObjectName -notlike “~$” -and $.ObjectName -notlike “.tmp”} |
Export-Clixml -Path “D:\Logs$(((Get-Date).AddDays(-1).ToShortDateString()).Replace(”/“,”-“)).xml”
} -ArgumentList $loc
Remove-Item -Path $loc
Does this do the trick?

No it doesn’t do the trick,

I should say that after all the testing I’ve done, I noticed that it sometimes manages to delete one or two logs but not all of them

If it works occasionally, perhaps it just needs a delay to release the file. I found this to check for locked files.

Put in a check for the file being locked, with maybe a limit of 10 loops with 1 second delays. Then remove the file once unlocked. You should probably log the lock checks to see how long it typically takes to release. Might not need full 1 second delays, might only need a few tenths.

Since I only tried it out with a single evtx file, you may need to use a foreach loop. Maybe this:

Invoke-Command -ScriptBlock {
    $loc = Get-ChildItem "D:\Logs\archive*"
    $output = @()

    foreach ($file in $loc) {
        $output += Get-WinEvent -FilterHashtable @{ path = $file ; ID = 4659} |
            Select-Object -Property TimeCreated,
                @{ n = "AccountName" ; e = {($_.Message.split("`n"))[4].Substring(16) } } ,
                @{ n = "ObjectName" ; e = {($_.Message.split("`n"))[11].Substring(14) } } |
            where {$_.ObjectName -notlike "*~$*" -and $_.ObjectName -notlike "*.tmp*"}
    }
    
    $output | Export-Clixml -Path "D:\Logs\$(((Get-Date).AddDays(-1).ToShortDateString()).Replace("/","-")).xml"
}

Remove-Item -Path $loc

In my testing, it never released the lock until the script moved on to something else. I could sit and wait a full minute and it would remain, but as soon as I executed something else, it unlocked.

I don’t think timing has anything to do with it, and I don’t think a retry loop will help. I think it’s going to need the read to be pushed into a new, temporary scope that will close the lock when the scope is disposed.

If that’s really the problem we could try something like this:

$loc = Get-ChildItem “D:\Logs\archive*”
Invoke-Command -ScriptBlock {
Get-WinEvent -FilterHashtable @{ path = $args[0] ; ID = 4659} |
Select-Object -Property TimeCreated,
@{ n = “AccountName” ; e = {($.Message.split(“`n”))[4].Substring(16) } } ,
@{ n = “ObjectName” ; e = {($
.Message.split(“`n”))[11].Substring(14) } } |
where {$.ObjectName -notlike “~$” -and $.ObjectName -notlike “.tmp”} |
Export-Clixml -Path “D:\Logs$(((Get-Date).AddDays(-1).ToShortDateString()).Replace(”/“,”-“)).xml”
} -ArgumentList $loc
$foo = Get-ChildItem -File -Path $ENV:TMP -ErrorAction SilentlyContinue
Remove-Variable -Name foo
Remove-Item -Path $loc -Force
I keep my fingers crossed. :wink:

Unfortunately Olaf that didn’t work also :frowning:

Did you try my second suggestion above?

Here it is again in case you didn’t see it:

Invoke-Command -ScriptBlock {
    $loc = Get-ChildItem "D:\Logs\archive*"
    $output = @()

    foreach ($file in $loc) {
        $output += Get-WinEvent -FilterHashtable @{ path = $file ; ID = 4659} |
            Select-Object -Property TimeCreated,
                @{ n = "AccountName" ; e = {($_.Message.split("`n"))[4].Substring(16) } } ,
                @{ n = "ObjectName" ; e = {($_.Message.split("`n"))[11].Substring(14) } } |
            where {$_.ObjectName -notlike "*~$*" -and $_.ObjectName -notlike "*.tmp*"}
    }
    
    $output | Export-Clixml -Path "D:\Logs\$(((Get-Date).AddDays(-1).ToShortDateString()).Replace("/","-")).xml"
}

Remove-Item -Path $loc

hi bear

Yeah I kinda missed it, but I’ve just tried it today and I got this error:

Remove-Item : Cannot bind argument to parameter ‘Path’ because it is null.

however, I’ve been trying all these hacky things, and I ended up with a solution that is working fine:
I created 2 powershell scripts and a batch file, the first script (first.ps1) has:

$loc = Get-ChildItem “D:\Logs\archive*”

Get-WinEvent -FilterHashtable @{ path = $loc ; ID = 4659} |

Select-Object -Property TimeCreated,

@{ n = “AccountName” ; e = {($_.Message.split(“`n”))[4].Substring(16) } } ,

@{ n = “ObjectName” ; e = {($_.Message.split(“`n”))[11].Substring(14) } } |

where {$.ObjectName -notlike “~$” -and $.ObjectName -notlike “.tmp”} |

Export-Clixml -Path “D:\Logs$(((Get-Date).AddDays(-1).ToShortDateString()).Replace(”/“,”-“)).xml”

$loc | Export-Clixml -Path “D:\Logs\loc.xml”

the second Script (second.ps1) has:

Remove-Item -Path (Import-Clixml -Path “D:\Logs\loc.xml”)

And the batch file (final.bat) has:

powershell.exe -file “D:\Logs\Scripts\first.ps1”
powershell.exe -file “D:\Logs\Scripts\second.ps1”

Now before using the batch file I created a third script which included both 1 & 2 scripts but I ended up with the same negative result.

so currently that is my stupid solution for the problem, :wink: any comments?

thanks