Page 1 of 1

ChangeDriveLetter script for XYplorer

Posted: 04 Aug 2011 21:12
by highend
Take a look at the "Remarks:" section on top of the code on how to use it.

Paypal donations are always accepted :D

Code: Select all

/* 04.08.2011, change drive letters
   ::load "<xyscripts>\ChangeDriveLetter.xys";

   Remarks: XYplorer must have been started with admin rights. As an alternative you could create a task with highest privileges that
   executes the VBScript file and can be called with a temporary batch file (like schtasks /run /tn "ChangeDriveLetter"). A third way
   would be the use of psexec but it requires a small bit of configuration on your pc (enable Administrator account, give it a password,
   etc.). See http://technet.microsoft.com/de-de/sysinternals/bb897553 for further details.

*/

"_Initialize"
	global $SelectedDriveLetter, $DestinationDriveLetter, $ExcludedDriveLetters, $AvailableDriveLetters, $UsedDriveLetters, $VBSTempScriptFile;

	// Please change only the $ExcludedDriveLetters variable to fit your needs.
	// Don't forget to add the colon and the | character after each drive letter
	$ExcludedDriveLetters = "A:|B:|";

	// Don't change anything in the script below this point
	$SelectedDriveLetter = "";
	$DestinationDriveLetter = "";
	$UsedDriveLetters = "";
	$AvailableDriveLetters = "A:|B:|C:|D:|E:|F:|G:|H:|I:|J:|K:|L:|M:|N:|O:|P:|Q:|R:|S:|T:|U:|V:|W:|X:|Y:|Z:|";
	$VBSTempScriptFile = "%temp%\~ChangeDriveLetter.vbs";


"Change drive letter for...|<xypath>\.Icons\RSync_Upload.ico|1"
	;

"... &current drive"
	global $CurrentSelectedMenuItem;

	sub "_Initialize";

	$CurrentSelectedMenuItem = "current_drive";

	sub "_Main";

	status "Changed drive letter successfully";


"... &select drive"
	global $CurrentSelectedMenuItem;

	sub "_Initialize";

	$CurrentSelectedMenuItem = "selected_drive";

	sub "_Main";

	status "Changed drive letter successfully";


"- : Separator"

"Cancel"

"- : Separator"

"Edit this &script : edit"
	self $ScriptFile, file;
	openwith "<xydrive>\Tools\EditPlus\editplus.exe", ,$ScriptFile;


/*
Functions
*/

"_Main"
	global $SelectedDriveLetter, $DestinationDriveLetter, $ExcludedDriveLetters, $AvailableDriveLetters, $UsedDriveLetters, $VBSTempScriptFile;
	global $CurrentSelectedMenuItem;

	// Remove the $ExcludedDriveLetters from $AvailableDriveLetters
	foreach($Drive, $ExcludedDriveLetters, "|") {
		if($Drive == "") { break; }
		$Drive = $Drive . "|";
		$AvailableDriveLetters = replace($AvailableDriveLetters, "$Drive", "");
	}

	// Find all used drive letters
	// Create new tab and go to the "Computer" node
	tab("new", "Computer");
	// Report the names for all drives
	$UsedDriveLettersNames = report("{name}|");
	// Make a new "|" separated $UsedDriveLetters list
	foreach($Item, $UsedDriveLettersNames, "|") {
		if($Item == "") { break; }
		$DriveLetter = regexreplace($Item, "(.*\()([A-Za-z]:)(.*)", "$2");

		// Get single used drive letters to remove them from the $AvailableDriveLetters list
		$DriveLetterWithSeparator = $DriveLetter . "|";
		
		// Build $UsedDriveLetters list for later use
		$UsedDriveLetters = $UsedDriveLetters . $DriveLetter . "|";

		// Remove the $UsedDriveLetters from $AvailableDriveLetters
		$AvailableDriveLetters = replace($AvailableDriveLetters, "$DriveLetterWithSeparator", "");
	}
	// Close current tab
	#351;


	// Change drive letter for... current drive
	if($CurrentSelectedMenuItem == "current_drive") {
		$CurrentPath = "<curpath>";
		$SelectedDriveLetter = regexreplace($CurrentPath, ".*([A-Za-z]:)\\(.*)", "$1");

		$DestinationDriveLetter = inputselect("Please select the destination drive letter:", "$AvailableDriveLetters", "|", 1);
	}

	// Change drive letter for... selected drive
	if($CurrentSelectedMenuItem == "selected_drive") {
		$SelectedDriveLetter = inputselect("Please select the source drive letter:", "$UsedDriveLetters", "|", 1);

		$DestinationDriveLetter = inputselect("Please select the destination drive letter:", "$AvailableDriveLetters", "|", 1);
	}

	$SelectedDriveLetterForScript = "(" . chr(34) . "Select * from Win32_Volume Where Name = '" . $SelectedDriveLetter . "\\'" . chr(34) . ")";
	$DestinationDriveLetterForScript = "objVolume.DriveLetter = " . chr(34) . $DestinationDriveLetter . chr(34);

	writefile($VBSTempScriptFile, 'strComputer = "."'.<crlf>, o, ta);
	writefile($VBSTempScriptFile, 'Set objWMIService = GetObject("winmgmts:" _'.<crlf>, a, ta);
	writefile($VBSTempScriptFile, '& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")'.<crlf>, a, ta);
	writefile($VBSTempScriptFile, <crlf>, a, ta);
	writefile($VBSTempScriptFile, 'Set colVolumes = objWMIService.ExecQuery _'.<crlf>, a, ta);
	writefile($VBSTempScriptFile, $SelectedDriveLetterForScript.<crlf>, a, ta);
	writefile($VBSTempScriptFile, <crlf>, a, ta);
	writefile($VBSTempScriptFile, 'For Each objVolume in colVolumes'.<crlf>, a, ta);
	writefile($VBSTempScriptFile, $DestinationDriveLetterForScript.<crlf>, a, ta);
	writefile($VBSTempScriptFile, 'objVolume.Put_'.<crlf>, a, ta);
	writefile($VBSTempScriptFile, 'Next'.<crlf>, a, ta);

	open "$VBSTempScriptFile";

Re: ChangeDriveLetter script for XYplorer

Posted: 09 Aug 2011 17:58
by rhoelzl
Not bad! :)

Thanks for this. I have hacked the code a bit to make it always change the current drive, see below. This way you can make it into a nice user button. I recommend ":rename" as icon.

Re: ChangeDriveLetter script for XYplorer

Posted: 09 Aug 2011 18:20
by rhoelzl
Hello again,

I have attached the following code at the end of the script:

Code: Select all

   $NewPath = replace("<curpath>",$SelectedDriveLetter,$DestinationDriveLetter);
   tab("relocate", $NewPath);
The idea is to stay in the current folder after drive letter change to make it more practical.

But I get some very strange behavior with this code: Apparently, changing drive letters takes a a short while, so as soon as "relocate" is called I only see the "path does not exist" error message. Which would be fine because with a little delay the folder should become available, so everything should be fine.

But what really happens is that I see that error message only for a very short period (less than a second) and then I get "forwarded" to %computer%. Am I doing something wrong? Or is this a bug?

Re: ChangeDriveLetter script for XYplorer

Posted: 09 Aug 2011 20:02
by highend
Am I doing something wrong? Or is this a bug?
Don't know.

Have you tried to use a while loop with exists() to only change the folder when it gets available?

Re: ChangeDriveLetter script for XYplorer

Posted: 09 Aug 2011 22:21
by rhoelzl
I had tried that but it did not work.

But now I have figured out that for some reason you need to add an additional wait. I don't really know why, but here you go, this works well.

Of course another nice upgrade would be to cycle through all open tabs, looking for all paths using the old letter and replacing it with the new one. But currently I am too lazy for that. :P

Code: Select all

/* 04.08.2011, change drive letters
   ::load "<xyscripts>\ChangeDriveLetter.xys";

   Remarks: XYplorer must have been started with admin rights. As an alternative you could create a task with highest privileges that
   executes the VBScript file and can be called with a temporary batch file (like schtasks /run /tn "ChangeDriveLetter"). A third way
   would be the use of psexec but it requires a small bit of configuration on your pc (enable Administrator account, give it a password,
   etc.). See http://technet.microsoft.com/de-de/sysinternals/bb897553 for further details.

*/

   global $CurrentSelectedMenuItem;
   sub "_Initialize";
   $CurrentSelectedMenuItem = "current_drive";
   sub "_Main";
   status "Changed drive letter successfully";
   
   

"_Initialize"
   global $SelectedDriveLetter, $DestinationDriveLetter, $ExcludedDriveLetters, $AvailableDriveLetters, $UsedDriveLetters, $VBSTempScriptFile;

   // Please change only the $ExcludedDriveLetters variable to fit your needs.
   // Don't forget to add the colon and the | character after each drive letter
   $ExcludedDriveLetters = "A:|B:|C:|D:|";

   // Don't change anything in the script below this point
   $SelectedDriveLetter = "";
   $DestinationDriveLetter = "";
   $UsedDriveLetters = "";
   $AvailableDriveLetters = "A:|B:|C:|D:|E:|F:|G:|H:|I:|J:|K:|L:|M:|N:|O:|P:|Q:|R:|S:|T:|U:|V:|W:|X:|Y:|Z:|";
   $VBSTempScriptFile = "%temp%\~ChangeDriveLetter.vbs";








/*
Functions
*/

"_Main"
   global $SelectedDriveLetter, $DestinationDriveLetter, $ExcludedDriveLetters, $AvailableDriveLetters, $UsedDriveLetters, $VBSTempScriptFile;
   global $CurrentSelectedMenuItem;

   // Remove the $ExcludedDriveLetters from $AvailableDriveLetters
   foreach($Drive, $ExcludedDriveLetters, "|") {
      if($Drive == "") { break; }
      $Drive = $Drive . "|";
      $AvailableDriveLetters = replace($AvailableDriveLetters, "$Drive", "");
   }

   // Find all used drive letters
   // Create new tab and go to the "Computer" node
   tab("new", "Computer");
   // Report the names for all drives
   $UsedDriveLettersNames = report("{name}|");
   // Make a new "|" separated $UsedDriveLetters list
   foreach($Item, $UsedDriveLettersNames, "|") {
      if($Item == "") { break; }
      $DriveLetter = regexreplace($Item, "(.*\()([A-Za-z]:)(.*)", "$2");

      // Get single used drive letters to remove them from the $AvailableDriveLetters list
      $DriveLetterWithSeparator = $DriveLetter . "|";
      
      // Build $UsedDriveLetters list for later use
      $UsedDriveLetters = $UsedDriveLetters . $DriveLetter . "|";

      // Remove the $UsedDriveLetters from $AvailableDriveLetters
      $AvailableDriveLetters = replace($AvailableDriveLetters, "$DriveLetterWithSeparator", "");
   }
   // Close current tab
   #351;


   // Change drive letter for... current drive
   if($CurrentSelectedMenuItem == "current_drive") {
      $CurrentPath = "<curpath>";
      $SelectedDriveLetter = regexreplace($CurrentPath, ".*([A-Za-z]:)\\(.*)", "$1");

      $DestinationDriveLetter = inputselect("Please select the new drive letter for drive " . $SelectedDriveLetter, "$AvailableDriveLetters", "|", 1);
   }

   // Change drive letter for... selected drive
   if($CurrentSelectedMenuItem == "selected_drive") {
      $SelectedDriveLetter = inputselect("Please select the source drive letter:", "$UsedDriveLetters", "|", 1);

      $DestinationDriveLetter = inputselect("Please select the destination drive letter:", "$AvailableDriveLetters", "|", 1);
   }

   $SelectedDriveLetterForScript = "(" . chr(34) . "Select * from Win32_Volume Where Name = '" . $SelectedDriveLetter . "\\'" . chr(34) . ")";
   $DestinationDriveLetterForScript = "objVolume.DriveLetter = " . chr(34) . $DestinationDriveLetter . chr(34);

   writefile($VBSTempScriptFile, 'strComputer = "."'.<crlf>, o, ta);
   writefile($VBSTempScriptFile, 'Set objWMIService = GetObject("winmgmts:" _'.<crlf>, a, ta);
   writefile($VBSTempScriptFile, '& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")'.<crlf>, a, ta);
   writefile($VBSTempScriptFile, <crlf>, a, ta);
   writefile($VBSTempScriptFile, 'Set colVolumes = objWMIService.ExecQuery _'.<crlf>, a, ta);
   writefile($VBSTempScriptFile, $SelectedDriveLetterForScript.<crlf>, a, ta);
   writefile($VBSTempScriptFile, <crlf>, a, ta);
   writefile($VBSTempScriptFile, 'For Each objVolume in colVolumes'.<crlf>, a, ta);
   writefile($VBSTempScriptFile, $DestinationDriveLetterForScript.<crlf>, a, ta);
   writefile($VBSTempScriptFile, 'objVolume.Put_'.<crlf>, a, ta);
   writefile($VBSTempScriptFile, 'Next'.<crlf>, a, ta);

   open "$VBSTempScriptFile";
   
   $NewPath = replace("<curpath>",$SelectedDriveLetter,$DestinationDriveLetter);
   while ( exists($NewPath) == 0) {wait 100;};
   wait 100;
   tab("relocate", $NewPath);