Wednesday, May 1, 2013

Discovering programs on a disk to run silent installers

I recently worked through my version of a PowerShell snip that has to discover in installer and run it.

In my case that installer is on an ISO that is attached to a VM.  And my script runs within the VM.

Now, this should be easy, just find the DVD drive, and run the installer.

Well, as always happens, it is not that easy in my case.  Come to find out, I could have multiple ISO attached at the moment my script is running, and I need to detect the correct one.  I also have to make sure that the installer exists before I try to run it and cause an error.  (there is always a need for error handling).

If I didn’t have this mess I could just assume that my ISO is D:\ and put in the path and move on.

First, ask yourself if the ISO will ALWAYS be on D:\?  If not, then you need to find the DVD drives and specifically those that have something mounted.  From within the running OS, not at some VM management layer.

I do that with the following:

# CD-ROM selects anything in the DVD drive.  The size ensures that something is mounted.
$dvdDrives = Get-Volume | where {$_.DriveType -eq "CD-ROM" -and $_.Size -gt 0}

I also have different installers for x86 and x64, so I have to detect the ‘bit-ness’ of the OS and smartly choose the correct installer.  A bit of searching turned me to this reliable way:

Switch ([System.IntPtr]::Size)
{
    4 {
        # x86
       }
    }
    8 {
       # x64
       }    
    }
}

Now, I have to build the path so that later on in my script I can run it.

If (Test-Path -Path ($dvd.DriveLetter + ":\Installer\") -PathType Container){
    $InstallMedia = Get-ChildItem -Path ($dvd.DriveLetter + ":\Installer\") -recurse -Filter "ServerInstaller.exe"
}

And, before attempting to run it, I need to test that the file really exists. And what is the literal path to the installer. Because how I got here was by testing for the folder structure, not by searching for the individual files (which would take a lot longer).

If ($InstallMedia -ne $null){
    If (Test-Path $InstallMedia .FullName){
        $InstallPath = $InstallMedia .FullName
    }
}

The entire script:

# CD-ROM selects anything in the DVD drive.  The size ensures that something is mounted.
$dvdDrives = Get-Volume | where {$_.DriveType -eq "CD-ROM" -and $_.Size -gt 0}

# Since a VM could have more than one DVD drive, we need to find the correct one.
foreach ($dvd in $dvdDrives){
    Switch ([System.IntPtr]::Size)
    {
        4 {
            If (Test-Path -Path ($dvd.DriveLetter + ":\x86\") -PathType Container){
                $Media = Get-ChildItem -Path ($dvd.DriveLetter + ":\x86\") -recurse -Filter "ServerSetup.exe"
            }
        }
        {
            If (Test-Path -Path ($dvd.DriveLetter + ":\x64\") -PathType Container){
                $Media = Get-ChildItem -Path ($dvd.DriveLetter + ":\x64\") -recurse -Filter "ServerSetup.exe"
            }    
        }
    }

    If ($Media -ne $null){
        If (Test-Path $Media.FullName){
            $FilePath = $Media.FullName
        }
    }
}

Start-Process -FilePath $FilePath –ArgumentList “/quiet “ -Wait -NoNewWindow
"Done waiting for the installer"

No comments: