http://www.perlmonks.org?node_id=150404
Category: NT Admin
Author/Contact Info Arcanumemail: arcanum@theworldofdreams.com
Description: I needed a program to audit disk usage on NT/Win2k servers. I couldn't find anything that would fit my needs, and the Boss was too cheap to pay for commercial software, so I decided to roll my own. This Perl script makes guesses at total disk usage for web content, logs files, and databases. I say it makes guesses because we compress the Logs directories to save space, and I used a simple divide by four to compensate for this compression. That's close enough to the real ratio for large amounts of files.

Just some background so you know what's happening:

-Clients keep their web content in e:\web\{their directory}
-The logs are stored in e:\web\{their directory}\logs
-Access databases are stored on the d:\ drive
-SQL databases are stored on up to two data servers, with NetBIOS mappings to make this work (m:\ and n:\)

Obviously this is custom tailored for our needs, but it can serve as a pretty decent guideline for your own program. I'm just a hack; I'm very much a Perl novice, so this may look be a bit crude. However, it does its job for us, so I can't complain. :)

Comments and questions are welcome. Thanks.

Edit by dws for formating and code tags

###########################################
# Audit script to get a good estimate      #
# of total disk space used by each client #
###########################################

print "\n\nEnter the path of the directory to check:
(i.e. e:\\\\web, note the double-backslashes - these are necessary)\n\
+n\n";

$path=<STDIN>;        #parent of the directories to get sizes of
chomp($path);

print "\n\nEnter the minimum in megs:\n\n\n";

$minsize=<STDIN>;        #disk space usage to check against
print "\n\n\n";
chomp($minsize);

$minsize=$minsize*1048576;    #converted to bytes

$sdbpath1="m:/";    #SQL Database paths
$sdbpath2="n:/";
$adbpath="d:/dbase";    #Access Database path

chdir($path);
@files=`dir /b`;    #uses the 'bare' switch of the 'dir' command
            #to get a list of directories to size

open (OUTFILE, ">c:/audit.txt");

print OUTFILE "Folder\t\t\tLogs (Megs)\t\tDatabases (Megs)\t\tTotal (M
+egs)\n\n";

foreach $file (@files){
    chomp($file);

    ##############################################
    # This loop recursively sizes one directory  #
    # at a time from the list in @files, using   #
    # the DOS command 'dir /s'.             #
    # It then uses some array manipulation         #
    # and substitution to get the total in bytes #
    ##############################################


    if (-d $file){
        @temparray=`dir /s "$file"`;
        pop(@temparray);
        $tempout=pop(@temparray);
        $tempout =~ s/ //g;
        $tempout =~ s/,//g;
        $tempout =~ s/bytes//;
        $tempout =~ s/.{0,8}File\(s\)//;

        chdir($file);

        #########################################
        # After changing to the client's    #
        # directory, use 'dir /s' again        #
        # to get the size of the logs directory #
        #########################################

        @logarray=`dir /s Logs`;
        pop(@logarray);
        $logtemp=pop(@logarray);
        $logtemp =~ s/ //g;
        $logtemp =~ s/,//g;
        $logtemp =~ s/bytes//;
        $logtemp =~ s/.{0,8}File\(s\)//;

        chdir($sdbpath1);

        ###################################
        # Same story for the SQL database #
        # directories              #
        ###################################

        if (-d $file){
            @sdbarray1=`dir /s "$file"`;
            pop(@sdbarray1);
            $sdbtemp1=pop(@sdbarray1);
            $sdbtemp1 =~ s/ //g;
            $sdbtemp1 =~ s/,//g;
            $sdbtemp1 =~ s/bytes//;
            $sdbtemp1 =~ s/.{0,8}File\(s\)//;
        }
        else{
            $sdbtemp1=0;
        }

        chdir($sdbpath2);

        if (-d $file){
            @sdbarray2=`dir /s "$file"`;
            pop(@sdbarray2);
            $sdbtemp2=pop(@sdbarray2);
            $sdbtemp2 =~ s/ //g;
            $sdbtemp2 =~ s/,//g;
            $sdbtemp2 =~ s/bytes//;
            $sdbtemp2 =~ s/.{0,8}File\(s\)//;
        }
        else{
            $sdbtemp2=0;
        }

        chdir($adbpath);

        ###############################
        # ...And the Access Databases #
        ###############################

        if (-d $file){
            @adbarray=`dir /s "$file"`;
            pop(@adbarray);
            $adbtemp=pop(@adbarray);
            $adbtemp =~ s/ //g;
            $adbtemp =~ s/,//g;
            $adbtemp =~ s/bytes//;
            $adbtemp =~ s/.{0,8}File\(s\)//;
        }
        else{
            $adbtemp=0;
        }


        $dbtemp=$sdbtemp1+$sdbtemp2+$adbtemp;    #add database totals
        
        $tempout=$tempout-$logtemp;    #subtract uncompressed log
                        #size from total
        $logtemp=$logtemp/4;        #guesstimate for compressed
                        #log files
        $tempout=$tempout+$logtemp;    #add compressed log size
                        #back to total

        $tempout=$tempout+$dbtemp;    #add  database size

        if ($tempout > $minsize){
            $logtemp=$logtemp/1048576;    #convert to megabytes
            $tempout=$tempout/1048576;
            $dbtemp=$dbtemp/1048576;
            printf OUTFILE ("$file\t\t%.2f\t\t\t%.2f\t\t\t\t%.2f\n", $
+logtemp, $dbtemp, $tempout);
            
        }
        
        chdir($path);
    }
}


close OUTFILE;
Replies are listed 'Best First'.
Re: audit.pl
by cjf (Parson) on Mar 09, 2002 at 10:39 UTC

    Hi, just a few general suggestions that will make your life a bit easier:

    • use strict
    • Turn on warnings (-w)
    • Check all of your open calls like so:
      open OUTFILE, ">outfile.txt" or die "Can't open outfile.txt: $!\n";

     

      Thanks for your suggestions.

      I generally use the -w flag, but I didn't want this to throw warnings to unsuspecting users. It should only be used by 3 people, anyhow. Using -w on the command line doesn't trow warnings for this one.

      I've never used strict, but I have seen it mentioned before. It is my understanding that it forces me to predefine my variables. This will avoid problems down the line caused by variables with uncertain values. Is that correct?

      Error checking has never been one of my strong points :P But yes, you are correct, I should check for the ability to open the output file.

      By the way, how would I add the -w flag to the script in Windows? Most of my (limited) Perl coding has been on Linux, so I've just needed to add it to the #!/usr/bin/perl line.

      Thanks again!