Thursday, April 17, 2008

System Disk And Drive Letter In Perl

There's no easy way to discover the system disk and drive letter on Windows, so I came up with this tedious work-around. Basically, you use Windows Scripting Host (WSH) to write a file that Perl can then read. Someone may wonder why I'm not using Win32:: packages - well, they don't implement the whole CIMv2 spec, so you'll begin running into errors such as Win32::OLE(0.1707) error 0x80020009: "Exception occurred", smartly described as a "Generic Error". It's a nightmare to dig through MSDN to figure out what the heck an ambiguous error like this means.

So the simple workaround: write a VBScript file that contains this code:

Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colDiskDrives = objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive")
For Each objDrive In colDiskDrives
strDeviceID = Replace(objDrive.DeviceID, "\", "\\")
Set colPartitions = objWMIService.ExecQuery _
("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
strDeviceID & """} WHERE AssocClass = " & _
"Win32_DiskDriveToDiskPartition")
For Each objPartition In colPartitions
If objPartition.BootPartition = True Then
bootinfo = objPartition.DiskIndex
Set colLogicalDisks = objWMIService.ExecQuery _
("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & _
objPartition.DeviceID & """} WHERE AssocClass = " & _
"Win32_LogicalDiskToPartition")
For Each objLogicalDisk In colLogicalDisks
bootinfo = bootinfo & " " & objLogicalDisk.DeviceID
Next
strOutputFile = "./theboot.txt"
Set objFileSystem = CreateObject("Scripting.fileSystemObject")
Set objOutputFile = objFileSystem.CreateTextFile(strOutputFile, TRUE)
objOutputFile.WriteLine(bootinfo)
objOutputFile.Close
Set objFileSystem = Nothing
End If
Next
Next

There are zillion ways to write this code to the filesystem in Perl; I leave that up to you. Execute the file (with a .vbs extension) on the system shell (DOS), and have Perl read the file theboot.txt (or whatever you call your file) - parse it for the physical disk number (given by Win32_DiskDrive.DeviceID) and the drive letter (given by Win32_LogicalDisk.DeviceID). Associating the two WMI classes is weird, as the code above shows, but it works. In the code, the file is written in the format [disk_number] [drive_letter].

Note that I use for-loops in this workaround, so if you have multiple boot disks, only one will be discovered.
Also, don't rely on DISKPART for this job, especially if you are scripting things. It works well interactively, but I've found it unreliable on systems with large drive counts - in such cases, the disk number won't always be the same.

This workaround essentially saved my day: reliance on diskpart had cost me a couple of lost OSes as it sometimes reported that there was no system partition or could not find drives whatsoever, especially if you had a lot of drives. The WMI/CIM solution seems bullet-proof - for now.

Saturday, April 12, 2008

Developing PHP On NetBeans

I'm finally making the move to developing in PHP - or at least I must for the time being because of an important project I am working on. To make things easy on myself, I need a familiar development environment - NetBeans 6.x is just perfect for that. Here's how you set up NetBeans to talk PHP.
  1. Ensure you don't have previous installations of PHP. Presence of such will confuse the hell out of your new installations.
  2. Download the Wamp server. This package contains an Apache HTTP web server, MySql database, and the PHP engine, along with some admin utilities and a Wamp server console. Believe me, this stack takes the nightmare out of configuring PHP on Windows.
  3. Download the PHP plugin for NetBeans: Tools | Plugins -> Available Plugins tab -> Search [php]. Install the PHP scripting plugin, which includes an editor, runtime, and documentation. We probably won't use the runtime that comes with this plugin, as we need to use Wamp and other debug tools that it does not support. NB will need to restart after this install.
After NB returns, test the setup by creating a simple PHP project:
  1. File | New Project ... -> PHP | PHP Project [Next] -> (set project properties) [Next].
  2. Web server configuration: click [Manage] -> Connection name = Wamp2, Local web server with file access [Next].
  3. Manual configuration [Browse] to %where_you_installed_wamp%\bin\apache\apache2.2.8\conf\httpd.conf for the Apache config file. [Next]
  4. Http server settings - just change the port number to something no other app is using. I choose 81 on localhost (Remember to update httpd.conf to listen on port 81 as well).
  5. Finish up and close the dialogs. NB creates a new project and opens index.php for you to edit. You can start wil basic HTML in a .php file. If on running the project you see a good page, all is well.
Note that you won't need to configure the web server every time you create subsequent projects. Also, I'll leave debugging and other configurations to future posts.