Web Listing 1: DumpStartups.pl use Getopt::Long; use Win32::API::Prototype; use Win32::TieRegistry; use Win32::Shortcut; use Win32::AdminMisc; use strict; use vars qw( %HIVES %PATHS %Config $Value $EXECUTABLE_EXTENSIONS $CSIDL_STARTUP $CSIDL_COMMON_STARTUP $SHGFP_TYPE_CURRENT ); %HIVES = ( CUser => "HKCU", LMachine => "HKLM", Drive => "Drive", ); ApiLink( "shell32", "HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath )" ) || die; $CSIDL_STARTUP = 0x0007; # Start Menu\Programs\Startup $CSIDL_COMMON_STARTUP = 0x0018; # Users\Startup $SHGFP_TYPE_CURRENT = 1; # Current value (not default) # If there is no PATHEXT environment variable create one $ENV{PATHEXT} = ".cmd;.com;.bat;.vbs;" unless( "" ne $ENV{PATHEXT} ); $EXECUTABLE_EXTENSIONS = join( "|", ( split( ";", $ENV{PATHEXT} . ";.pif;.lnk" ) ) ); %PATHS = ( registry => [ '/CUser/Software/Microsoft/Windows/CurrentVersion/Run', '/CUser/Software/Microsoft/Windows/CurrentVersion/RunOnce', '/LMachine/Software/Microsoft/Windows/CurrentVersion/RunServices', '/LMachine/Software/Microsoft/Windows/CurrentVersion/RunServicesOnce', '/LMachine/Software/Microsoft/Windows/CurrentVersion/Run', '/LMachine/Software/Microsoft/Windows/CurrentVersion/RunOnce', ], file => [ GetSpecialDirectory( $CSIDL_STARTUP ), GetSpecialDirectory( $CSIDL_COMMON_STARTUP ), ] ); %Config = ( remove => [] ); Configure( \%Config ); if( $Config{help} ) { Syntax(); exit; } $Registry->Delimiter("/"); my @RunValues; foreach my $Path ( @{$PATHS{registry}} ) { push( @RunValues, ProcessKey( $Path ) ); } foreach my $Path ( @{$PATHS{file}} ) { push( @RunValues, ProcessDir( $Path ) ); } $~ = "DumpHeader"; write; $~ = "DumpData"; if( scalar @{$Config{remove}} ) { foreach my $Index ( @{$Config{remove}} ) { local $Value; $Value = $RunValues[ $Index ]; $Value->{_index} = $Index; Remove( $Value ); # Write AFTER calling Remove(). The write format may delete # some of the $Value hash reference members. write; } } else { my $TotalIndex = scalar @RunValues; for( my $Index = 0; $Index < $TotalIndex; $Index++ ) { local $Value; $Value = $RunValues[ $Index ]; $Value->{_index} = $Index; write; } } sub ProcessKey { my( $Path ) = @_; my @ValueList = (); my( $Location ) = ( $Path =~ /\/([^\/]+)\// ); # Open the registry key with the MAXIMUM_ALLOWED permission if( my $Key = $Registry->Open( $Path, {Access => 0x2000000} )) foreach my $ValueName ( $Key->ValueNames() ) { # Assume all of these values are strings... my $Data = $Key->{ "/$ValueName" }; push( @ValueList, { _name => $ValueName, _path => $Path, _data => $Data, _location => $Location } ); } } return( @ValueList ); } sub ProcessDir { my( $Dir ) = @_; my @ValueList = (); my @DirList = (); if( opendir( STARTUP_DIR, $Dir ) ) { while( my $File = readdir( STARTUP_DIR ) ) { my $Path = "$Dir/$File"; next if( "." eq $File || ".." eq $File ); if( -d $Path ) { push( @DirList, $Path ); next; } if( $File =~ /\.lnk$/i ) { # Process Shortcut... my $Shortcut = new Win32::Shortcut( $Path ); my $Name = $Shortcut->{Description}; { my %FileInfo; if( Win32::AdminMisc::GetFileInfo( $Shortcut->{Path}, \%FileInfo ) ) { $Name = $FileInfo{FileDescription} || $File; } } push( @ValueList, { _name => $Name, _path => $Path, _data => "\"$Shortcut->{Path}\" $Shortcut->{Arguments}", _location => "Drive" } ); } elsif( $File =~ /($EXECUTABLE_EXTENSIONS)$/i ) { # Process other files... my $Name = $File; my %FileInfo; if( Win32::AdminMisc::GetFileInfo( $Path, \%FileInfo ) ) { $Name = $FileInfo{FileDescription} if( "" ne $FileInfo{FileDescription} ); } push( @ValueList, { _name => $Name, _path => $Path, _data => $Path, _location => "Drive" } ); } } closedir( STARTUP_DIR ); foreach my $Path ( @DirList ) { push( @ValueList, ProcessDir( $Path ) ); } } return( @ValueList ); } sub Remove { my( $Item ) = @_; my $Result = 0; my $Input; print "Removing: $Item->{_name} from path $Item->{_path}\n"; print "Are you sure: Yes or No? "; $Input = lc ; chomp( $Input ); if( "y" eq $Input || "yes" eq $Input ) { if( "drive" eq lc $Item->{_location} ) { # We have a location on a drive... print "Deleting file: '$Item->{_path}'\n"; $Result = unlink( $Item->{_path} ); } else { # We have a registry key... my $Path = "$Item->{_path}/$Item->{_name}"; $Result = delete $Registry->{$Path}; print "Deleting reg key value: '$Path'\n"; } if( $Result ) { print "REMOVED!\n"; } else { print "FAILED to remove! Error: " . Win32::FormatMessage( Win32::GetLastError() ); } } else { print " WILL NOT REMOVE $Item->{_name}!\n"; } } sub GetSpecialDirectory { my( $FolderType ) = @_; my $pszPath = NewString( 1024 ); if( 0 == SHGetFolderPath( undef, $FolderType, undef, $SHGFP_TYPE_CURRENT, $pszPath ) ) { $pszPath =~ s/\x00//g; return( $pszPath ); } return( undef ); } sub Configure { my( $Config ) = @_; my $Result; Getopt::Long::Configure( "prefix_pattern=(-|\/)" ); $Result = GetOptions( $Config, qw( remove|r=i@ help|h|? ) ); $Config->{help} = 1 unless( $Result ); } sub Syntax { my( $Script ) = ( $0 =~ m#([^\\/]+)$# ); my $Line = "-" x length( $Script ); print STDERR << "EOT"; $Script $Line Manages autostart applications. Syntax: $0 [-r ] -r Index......Removes an item referenced by index number. Use as many of these items as necessary. Examples: perl $0 -r 3 -r 4 EOT } format DumpHeader = @<<<< @<<<<<<< @<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< "Index", "Location", "Name", "Path" ----- -------- --------------------- ----------------------------------------- . format DumpData = @<<<< @<<<<<<< ^<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $Value->{_index}, $HIVES{$Value->{_location}}, $Value->{_name}, $Value->{_data} ~ ^<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $Value->{_name}, $Value->{_data} ~ ^<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $Value->{_name}, $Value->{_data} ~ ^<<<<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< $Value->{_name}, $Value->{_data} . ?? ?? ?? ?? 1 1