I want to automate this Powershell script so that it automatically run when user open
param(
[Parameter(Position=0)]
[string]$Filter,
[int]$Duration,
[switch]$KeepAll,
[string]$procmon
)
function convert-FilterToObj
{
$FilterObj = @() #Init blank array
#Filters must be seperated by ;
$Filter = $filter.split(';')
$Filter | % {
#Use builtin split method to convert comma seperated string into array
$_ = $_.split(',')
#Checking our array for exactly four objects
if(($_ | measure).count -ne 4)
{return "Error: Filter is not in correct format."}
else
{
#Convert filter into an object, remove spaces from Column/Relation
$CurrentFilter = New-Object system.Object
$CurrentFilter | Add-Member noteproperty -Name "Column" -Value $_[0].replace(' ','')
$CurrentFilter | Add-Member noteproperty -Name "Relation" -Value $_[1].replace(' ','')
$CurrentFilter | Add-Member noteproperty -Name "Value" -Value $_[2]
$CurrentFilter | Add-Member noteproperty -Name "Action" -Value $_[3]
#Add current filter to output object
$FilterObj += $CurrentFilter
}
}
return $FilterObj
}
function convert-LargeValues
{
param($Value)
if($Value.Length -gt 2)
{
$FirstByte = [string]::Join("",$Value[1..2])
$SecondByte = $Value[0]
}
else
{
$FirstByte = $Value
$SecondByte = 0
}
return "0x$FirstByte","0x$SecondByte"
}
function get-ProcmonRunningStatus
{
#Check if process monitor is currently running
sleep -Seconds 1
if((Get-Process procmon -ea silentlycontinue) -eq $null)
{return "False"}
else
{return "True"}
}
function write-ProcmonFilterValue
{
#Start of filter is 1 declare type as an array of bytes
[Byte[]]$FilterRegkey = "0x1"
#Followed by number of filters
$NumFilters = [convert]::tostring((($FilterObj | measure).count),"16")
#Multiple registry keys can overflow when using largeValues
#A function was created to split these large values into two bytes
$FilterRegKey += (convert-LargeValues -value $NumFilters)
#Two padding bytes
$FilterRegkey += "0x0","0x0"
#Header is written, build filters from friendly strings
$FilterObj | % {
#Check for syntax errors
if($FilterRegkey -match "Error")
{return}
#First write column code, and 9c divider
switch($_.Column)
{
"ProcessName" {$FilterRegKey += "0x75","0x9c"}
"PID" {$FilterRegKey += "0x76","0x9c"}
"Result" {$FilterRegKey += "0x78","0x9c"}
"Detail" {$FilterRegkey += "0x79","0x9c"}
"Duration" {$FilterRegKey += "0x8d","0x9c"}
"ImagePath" {$FilterRegKey += "0x84","0x9c"}
"RelativeTime" {$FilterRegKey += "0x8c","0x9c"}
"CommandLine" {$FilterRegKey += "0x82","0x9c"}
"User" {$FilterRegKey += "0x83","0x9c"}
"Operation" {$FilterRegKey += "0x77","0x9c"}
"ImagePath" {$FilterRegKey += "0x84","0x9c"}
"Session" {$FilterRegKey += "0x85","0x9c"}
"Path" {$FilterRegKey += "0x87","0x9c"}
"TID" {$FilterRegKey += "0x88","0x9c"}
"Duration" {$FilterRegKey += "0x8D","0x9c"}
"TimeOfDay" {$FilterRegKey += "0x8E","0x9c"}
"Version" {$FilterRegKey += "0x91","0x9c"}
"EventClass" {$FilterRegKey += "0x92","0x9c"}
"AuthenticationID" {$FilterRegKey += "0x93","0x9c"}
"Virtualized" {$FilterRegKey += "0x94","0x9c"}
"Integrity" {$FilterRegKey += "0x95","0x9c"}
"Category" {$FilterRegKey += "0x96","0x9c"}
"Parent PID" {$FilterRegKey += "0x97","0x9c"}
"Architecture" {$FilterRegKey += "0x98","0x9c"}
"Sequence" {$FilterRegKey += "0x7A","0x9c"}
"Company" {$FilterRegKey += "0x80","0x9c"}
"Description" {$FilterRegkey += "0x81","0x9c"}
default {
[string]$FilterRegKey = "Error: Check Column values."
return
}
}
#Add two zero bytes padding before comparison
$FilterRegkey += "0x0","0x0"
#Now add Relation byte
switch($_.Relation)
{
"is" {$FilterRegKey += "0x0"}
"isNot" {$FilterRegkey += "0x1"}
"lessThan" {$filterregkey += "0x2"}
"moreThan" {$FilterRegkey += "0x3"}
"endsWith" {$FilterRegkey += "0x5"}
"BeginsWith" {$FilterRegkey += "0x4"}
"Contains" {$FilterRegKEy += "0x6"}
"excludes" {$FilterRegkey += "0x7"}
default {
[string]$FilterRegKey = "Error: Check Relation values."
return}
}
#Add three zero bytes before Action (Include/Exclude)
$FilterRegKey += "0x0","0x0","0x0"
#Now Include/Exclude
if ($_.Action -match "incl"){$FilterRegkey += "0x1"}
elseif($_.Action -match "excl"){$FilterRegKey += "0x0"}
else{[string]$FilterRegkey = "Error: Check Action Values.";return}
#Add length of <Value> string.
#Length is hex value of (characters * 2(account for nulls) + 2)(account for spacer bytes)
$NumPathChars = [Convert]::tostring(((($_.value.toCharArray() | measure).count * 2) + 2),"16")
$FilterRegKey += (convert-LargeValues -value $NumPathChars)
#Two zero bytes padding
$FilterRegkey += "0x0","0x0"
#Convert string "Value" to binary Ascii array (ie. A = 0x41)
$_.Value.toCharArray() | % {
$FilterRegkey += (convert-largeValues -value ([Convert]::ToString(([char]$_ -as [int]),"16")))
}
# Current Filter calculated, pad with 10 zero bytes
# Changes made by Balaprasath Rajan - Microsoft.
# The third and fourth byte replaced with $.Value/256 and $_.value/256 for PIDs
$FilterRegkey += "0x0","0x0"
if($_.Column -like "PID" )
{
$processID = [int]$_.Value
if ($processID -ge 256)
{
[Byte]$quotient = "0x"+[Convert]::ToString([math]::floor($processID/256), 16)
[Byte]$remainder = "0x"+[Convert]::ToString([math]::floor($processID%256), 16)
$FilterRegkey += $remainder,$quotient
}
elseif($processID -lt 256)
{
[Byte]$quotient = "0x0"
[Byte]$remainder = "0x"+[Convert]::ToString([math]::floor($processID%256), 16)
$FilterRegkey += $remainder,$quotient
}
}
else
{
[Byte]$quotient = "0x0"
[Byte]$remainder = "0x0"
$FilterRegkey += $remainder,$quotient
}
$FilterRegkey += "0x0","0x0","0x0","0x0","0x0","0x0"
}
#Check for syntax errors
if($FilterRegkey -match "Error")
{return ($FilterRegkey | sort | get-unique)}
Write-Output $FilterRegKey
#Set filter
New-ItemProperty "HKCU:\Software\Sysinternals\Process Monitor" "FilterRules" -Value $FilterRegKey `
-PropertyType Binary -Force -ErrorVariable SetRegKeyErr | Out-Null
if(($setRegKeyErr | measure).count -ne 0)
{Return "Error: Writing registry failed."}
else{return 0}
}
##Main
#Function used for cleaning up temp files
function cleanup
{
#CSV file only exists on the last step
$ExistCSV = "False"
if((test-path $tempCSV) -eq $true)
{
$ExistCSV = "True"
del $tempCSV -Force
}
del $tempPml -Force
if((Test-Path $TempPML) -eq $true)
{return "Failed to delete temp files." }
elseif($ExistCSV -eq "True" -and ((Test-Path $ExistCSV) -eq $true))
{return "Failed to delete temp files."}
else
{return 0}
}
#First check if process monitor is currently running.
if((get-ProcmonRunningStatus) -eq "True")
{return "Error: Process Monitor already running."}
#Check if running as admin
if( -not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(`
[Security.Principal.WindowsBuiltInRole] "Administrator"))
{return "Error: Script must run with Admin rights."}
##Setup running enviroment based on specified paramaters
#Default duration to 60 seconds if not set.
if($Duration -eq 0)
{$Duration = 30}
#If procmon ends with a "\", remove
if(($procmon[$procmon.Length - 1]) -eq '\')
{$procmon.Remove((($procmon.Length) - 1),1)}
#Include profiling events only if paramater switch set
if($KeepAll.tostring() -ne "True" -and ($Filter.length) -ne 0)
{
#$Filter += ";EventClass,is,profiling,exclude"
#Set "Drop Filtered Events"
New-ItemProperty "HKCU:\Software\Sysinternals\Process Monitor" "DestructiveFilter" `
-Value ("0x1","0x0","0x0","0x0") -PropertyType Binary -Force | out-null
}
#Convert user input into proper object
if(($Filter.length) -ne 0)
{
Write-Verbose "Converting user supplied filter into object format."
$FilterObj = convert-FiltertoObj
if($FilterObj -match "Error:")
{return $FilterObj}
}
else
{
Write-Verbose "No filter specified, writing one that will never trigger."
$Filter = "pid,is,12345,exclude"
$FilterObj = convert-FiltertoObj
if($FilterObj -match "Error:")
{return $FilterObj}
}
#Attempt to write filter
Write-Verbose "Attemping to write filter registry value."
$FilterWriteResult = write-ProcmonFilterValue
if($FilterWriteResult -match "Error:")
{return $FilterWriteResult}
#If no directory specified try current folder
if(($procmon.Length) -eq 0)
{$procmon = "."}
Set-Location $procmon
#Cheap way to get a pseudorandom tempfile name with benifit of timestamp
$FileDate=((get-date).TimeOfDay.ToString().Replace('.','_')).replace(':','_')
#$TempPML = ".\Temp_$FileDate.pml"
$TempPML = Join-Path -Path $procmon -ChildPath "Temp_$FileDate.pml"
$TempCSV = ".\Temp_$FileDate.csv"
#Test for executable
Write-Verbose "Testing for Procmon.exe."
if((Test-Path "$procmon\procmon.exe") -eq $false)
{return "Error: Procmon.exe not found.`n"}
#Run procmon backed to file, supress prompts
Write-Verbose "Attempting to start Process Monitor."
start-process -filepath ".\Procmon" -argument "/backingfile $TempPML /quiet /accepteula" `
-WindowStyle Hidden
#Sleep for a number of seconds procmon should run
Write-Verbose "Process Monitor running for $Duration seconds."
Sleep -seconds $Duration
#Gracefully terminate procmon, wait for completion
Start-Process -FilePath ".\procmon" -argument "/terminate /accepteula" -Wait -WindowStyle Hidden
#Verify procmon is stopped
if((get-ProcmonRunningStatus) -eq "True")
{
$retErr = "Error: Process Monitor already running. Graceful Terminate failed.`n"
if((cleanup) -ne 0)
{$retErr += "Error: Cleanup of temp files failed."}
return $retErr
}
#Convert PML to CSV
Write-Verbose "Converting native PML to CSV. "
Start-Process -FilePath ".\procmon" -argument "/openlog $TempPml /saveAs $TempCSV /accepteula" `
-Wait -WindowStyle Hidden
#Verify procmon stopped
if((get-ProcmonRunningStatus) -eq "True")
{return "Error: Process Monitor still running. Graceful PML -> CSV conversion failed."}
#Attempt to import the newly converted CSV
$OutputObj = import-csv $TempCSV -ErrorVariable ImportCSVErr
if(($ImportCSVErr | Measure-Object).count -ne 0)
{return "Error: Loading converted CSV file failed.`n"}
#Cleanup
<#if((cleanup) -ne 0)
{Write-Warning "Final cleanup of temp files failed."}
#>
#Go back from whence we came and return fruits of our labor
Pop-Location
return $OutputObj
Currently it update pml file then stop process monitor and then save in CSV. I want process monitor should not be stop and continuously updating data in the CSV file and possible I want all the filter process log update directly to CSV.