0

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.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
curiosity
  • 1
  • 1

0 Answers0