neo1491 has asked for the wisdom of the Perl Monks concerning the following question:

Update 11/19/07 Live and learn... I learned that the entire script below can be reduced into a single line:
my $diskpart_out = `echo $diskpart_cmd|diskpart`;
I'm looking for a Perl script that sends commands to DiskPart.exe (ie: rescan and list disk/volume) and returns the output. Can anyone point me in the right direction? Update: I am trying to rescan the SCSI bus, detect all the PhysicalDrives connected to the system, then print out the return. DiskPart.exe has an option "rescan" and "list disk" which does just that. I'm attempting to write a script to automate this task.
open ( FH , "diskpart rescan|" ) || die ( "Failed to open filehandle.\ +n" ) ; my @inFile = <FH> ; # read all at once into array foreach (@inFile) { print $_."\t"; }

Replies are listed 'Best First'.
Re: diskpart.exe and perl
by shmem (Chancellor) on Nov 10, 2007 at 21:58 UTC
    See IPC::Open2.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      did that response help me or hurt me?
        How do you feel about it? My intention was to help. I don't know what diskpart.exe expects or sends, but IPC::Open2 is the right tool to deal with input and output to/from an external program.

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
        < quasi-snide>Perhaps you mistakenly believed PM to be a fee-free, script-writing service?</q-snide>

        Customarily, you'll get more useful assistance (which we do offer, freely, and often with real pleasure) if you

        • show us what you've tried (eg: code))
        • Show that you've put some effort into the job... as, for example, citing a node or document that (got you started || didn't quite do what you wanted, but left you with a subordinate problem || at least demonstrates that you've actually taken some steps toward becoming aware of perl's capabilities.

        I'd suggest you update your original node (update! not replace) with at bit more info... the above, plus what diskpart.exe expects as input and perhaps what its output looks like... and perhaps some code that reflects your attempt to understand and act on shmem's suggestion.

Re: diskpart.exe and perl (s/and/in/)
by tye (Sage) on Nov 11, 2007 at 00:57 UTC

    You might also consider just doing it directly in Perl. See the DiskGeom.plx sample script from the Win32API-File distribution for a starting point. See other IOCTL_DISK_* codes as documented in the Microsoft Windows SDK documentation.

    Update: I guess he didn't want to do the research and find items like IOCTL_DISK_FIND_NEW_DEVICES.

    - tye        

      thank you... but that script only sees drives already connected to the operating system... it doesn't rescan the scsi bus as you're creating additional physicaldrives... which is what i'm doing. i finally figured out how to send commands to microsoft diskpart and capture the response so i thought i'd post the final script for future reference. please keep in mind i'm a novice... so try not to laugh too hard at my syntax. i'd be very interested if anyone wants to critique my code and provide feedback.
      #!c:/Perl/bin/perl.exe -w use strict ; use warnings ; use English ; &send_diskpart_command ("rescan"); &send_diskpart_command ("list disk"); sub send_diskpart_command { my $debug = 0; my ($diskpart_command) = @_; if ($diskpart_command eq "") { print "\n***No command passed to the send_diskpart_comman +d subroutine***\n" ; return ; } # diskpart.exe requires a textfile input # deleting the textfile if it already exists then creating a new textf +ile with the diskpart_command my $file = "diskpart_cmd.txt"; if ($debug) { print "\nSearching for an existing copy of the text file +$file."; if (unlink($file) == 1) { print "\nThe file '$file' was found and deleted."; } else { print "\nThe file '$file' was not detected."; } } open (DPART, ">>$file") || die ("Could not open file. $!"); print DPART ($diskpart_command); if ( $debug ) { print "\nCreated file '$file'." ; } close (DPART); if ( $debug ) { print "\n\nSending $diskpart_command." ; } open ( FH , "diskpart /s diskpart_cmd.txt|" ) || die ("Could not + open file. $!"); print "\nCommand '$diskpart_command' sent to the host.\n"; if ( $debug ) { print "\n"; } my @inFile = <FH> ; # read all at once into array foreach (@inFile) { if ( $debug ) { print $_."\t"; } } close (FH); if ($debug) # delete the textfile { if (unlink($file) == 1) { print "\n\nThe file '$file' was deleted successfully.\ +n"; } else { print "\n\nThe file '$file' was not deleted.\n"; } } }
Re: diskpart.exe and perl
by jdporter (Paladin) on Nov 11, 2007 at 14:06 UTC

    Maybe it's just a matter of style, but I would write that as either:

    for ( `diskpart rescan` ) { . . . }
    or
    open FH, "diskpart rescan |" or die "open diskpart|: $!" while (<FH>) { . . . } close FH;
    And I think there may be a chomp or two missing in there...

    A word spoken in Mind will reach its own level, in the objective world, by its own weight
Re: diskpart.exe and perl
by bigteks (Initiate) on Jul 28, 2010 at 20:24 UTC

    Actually your subroutine is worthwhile if the thing you want to do in diskpart requires more than one line, for example to change drive letters.

    Here's how I used it for a drive letter changing script:

    &send_diskpart_command("select volume $VolNo\nremove letter=$OldLetter +\nassign letter=$NewLetter");

    Works like a charm.

    The send_diskpart_command subroutine does have a bug though - the textfile cleanup is inside a debug if-block so the textfile only gets cleaned up when debug is turned on. Easy to fix though.

      Here is my version that does drive letter changes. It has little error checking. Usage is:

      drivechange.pl x y

      where x is the current drive letter and y is the new drive letter. Here is the code:

      #! perl -sl use strict; my $Foundit = 0; my $Token = ""; my $Line = ""; my $VolNo = 0; my $VolLet = ""; my $Trash = ""; my $Vol = ""; my $Num = 0; my $Goal = uc($ARGV[0]); my $NewGoal = uc($ARGV[1]); # Find out all the drive letters my @vols = split "\n", `echo list volume | diskpart`; # Find out which volume corresponds to drive letter F foreach $Line (@vols){ next if(!defined($Line)); ($Token,$Num,$Vol,$Trash) = split(' ',$Line,4); if(($Token =~ /^Volume$/) && ($Vol =~ /^$Goal$/)){ $Foundit = 1; $VolLet = $Vol; $VolNo = $Num; } } if($Foundit == 1){ &send_diskpart_command("select volume $VolNo\nremove letter=$Goal\ +nassign letter=$NewGoal"); } else { print("Couldn't find Volume $Goal.\n"); } sub send_diskpart_command { my $debug = 0; my ($diskpart_command) = @_; if ($diskpart_command eq "") { print "\n***No command passed to the send_diskpart_command subrout +ine***\n" ; return ; } # diskpart.exe requires a textfile input # deleting the textfile if it already exists # then creating a new textfile with the diskpart_command my $file = "diskpart_cmd.txt"; if ($debug) { print "\nSearching for an existing copy of the text +file $file."; } if (unlink($file) == 1) { if ($debug) {print "\nThe file '$file' was found and deleted.";} } else { if ($debug) {print "\nThe file '$file' was not detected.";} } open (DPART, ">>$file") || die ("Could not open file. $!"); print DPART ($diskpart_command); if ( $debug ) { print "\nCreated file '$file'." ; } close (DPART); if ( $debug ) { print "\n\nSending $diskpart_command." ; } open ( FH , "diskpart /s diskpart_cmd.txt|" ) || die ("Could not o +pen file. $!"); if ($debug) { print "\nCommand '$diskpart_command' sent to the hos +t.\n"; } if ( $debug ) { print "\n"; } my @inFile = <FH> ; # read all at once into array foreach (@inFile) { if ( $debug ) { print $_."\t"; } } close (FH); if ($debug) # delete the textfile { if (unlink($file) == 1) { print "\n\nThe file '$file' was deleted successfully.\n"; } else { print "\n\nThe file '$file' was not deleted.\n"; } } }