# Reads a .csv file captured by SysInternal's procmon, and lists all of the # files that were created while an installer was running, and registry items that were written to. use strict; use warnings; use Data::Dumper; my $csv_filename = shift or die "Syntax: $0 \n"; open FIN, "<$csv_filename" or die "Unable to read from '$csv_filename': $!\n"; while () { next if (/^\xEF\xBB\xBF/); # skip the first line (the one with the UTF-8 byte-order mark) my %fields; @fields{qw[ sequence timeofday process pid operation path result detail ]} = parse_csv($_); my $operation; if ($fields{result} eq 'SUCCESS') { if ($fields{operation} eq 'CreateFile') { if ($fields{detail} =~ /OpenResult: Created/) { if ($fields{detail} =~ /^Desired Access: Read Data\/List Directory/) { $operation = "create directory"; $fields{path} .= "\\"; } else { $operation = "create file" } } elsif ($fields{detail} =~ /OpenResult: Opened/) { if ($fields{detail} =~ /^Desired Access:[^:]* Delete/) { $operation = "delete"; } } # } elsif ($fields{operation} eq 'RegCreateKey') { # $operation = "reg create"; } elsif ($fields{operation} eq 'RegSetValue') { $operation = "reg write"; } elsif ($fields{operation} eq 'RegDeleteKey') { $operation = "reg delete"; } } if ($operation) { printf "%-20s %-17s %s\n", substr($fields{process},0,20), $operation, $fields{path}; } } # there are more thorough solutions http://www.perlmeme.org/tutorials/parsing_csv.html sub parse_csv { local $_ = shift; my @ret; while (1) { if (s/^"((?:[^"]+|"")*)"(?!")//) { push(@ret, $1); $ret[-1] =~ s/""/"/g; } elsif (s/^([^"]+)//) { push(@ret, $1); } last unless /\S/; s/^,//; } return @ret; }