Jump to content
Sign in to follow this  
jwseek

Software install script doesn't install all software

Recommended Posts

jwseek

So I've been working on this script today to install a number of programs on a new Windows install. Basically, I'd like to be able to keep track of some files on a server and simply run this script to install all of them with no interaction. The catch is, I'm trying to avoid using the macro and interaction tools in auto-it. The reason behind that is it allows me to add programs to the script without rewriting it if I can find an unattended command line switch for them. I simply add them to an .ini file that the program reads and run through the array in that particular section with IniReadSection().

So the problem is, some of the programs don't run and install properly. I've tested each of the programs that I'm currently trying to install, and they all succeed individually but they won't install if run in the program...

[Global]
ServerName=server
InstallFolder=install
PatchesFolder=patches
InstallDrive=V:
PatchesDrive=Y:

[Patches]
.NET Framework 1.1=dotnetfx11.exe /q
;.NET Framework 1.1 Service Pack 1=Service Packs\dotnet11sp1.exe /q
.NET Framework 3.5=dotnetfx35.exe /passive /norestart
Visual C++ Redistributable 2005=vcredist_x86.exe /q
Windows Media Player 11=wmp11-windowsxp-x86-enu.exe /q

[Installs]
7zip=7zip.msi /passive
Firefox=Freeware\Firefox.msi /passive
Internet Explorer Flash Plugin=flash-ie.exe /S
Mozilla Flash Plugin=flash-mozilla.exe /S
Sun Java=java.exe /passive
Adobe Acrobat Reader=Productivity\AdbeRdr.msi /passive 

;HTMLSlideshow=HTMLSlideShowSetup.exe
;Synctoy=SyncToySetupPackage.exe
;TweakUI=TweakUiPowertoySetup.exe
;Image Resizer Powertoy=ImageResizerPowertoySetup.exe /S /v /qn
;Slideshow Powertoy=SlideshowPowertoySetup.exe /S /v /qn

So am I doing something wrong? Is this an issue more with msiexec than with AutoIT? What would you guys do?

AutoInstaller.au3

Share this post


Link to post
Share on other sites
Authenticity

I think this:

Func LoadINIFile()
    ;determine whether the sections with in the ini file are correct for this particular ini load
    $iniSectionList = IniReadSectionNames($iniFile)
    If $iniSectionList[0] = $iniSections And $iniSectionList[1] = "Global" Then
        $loadINI = MsgBox(1, "Loading INI File...", "This will change all initialized data (including networking data)", 3)
        $serverName = "\\" & IniRead($iniFile, "Global", "ServerName", "")
        $installFolder = $serverName & IniRead($iniFile, "Global", "InstallFolder", "")
        $patchesFolder = $serverName & IniRead($iniFile, "Global", "PatchesFolder", "")
        $installDrive = IniRead($iniFile, "Global", "InstallDrive", "Z:\")
        $patchesDrive = IniRead($iniFile, "Global", "patchesDrive", "Y:\")
        $patchesSetup = IniReadSection($iniFile, "Patches")
        $installSetup = IniReadSection($iniFile, "Installs")
    Else
        MsgBox(48, "Invalid Program INI File", "The file you selected does not contain the proper formatting for loading as an INI file")
    EndIf
EndFunc   ;==>LoadINIFileoÝ÷ ÚÈhºW[z·°®+mzv¬jëh×6Func LoadINIFile()
    ;determine whether the sections with in the ini file are correct for this particular ini load
    $iniSectionList = IniReadSectionNames($iniFile)
    If $iniSectionList[0] = $iniSections And $iniSectionList[1] = "Global" Then
        $loadINI = MsgBox(1, "Loading INI File...", "This will change all initialized data (including networking data)", 3)
        $serverName = "\\" & IniRead($iniFile, "Global", "ServerName", "")
        $installFolder = $serverName & "\" & IniRead($iniFile, "Global", "InstallFolder", "")
        $patchesFolder = $serverName & "\" & IniRead($iniFile, "Global", "PatchesFolder", "")
        $installDrive = IniRead($iniFile, "Global", "InstallDrive", "Z:")
        $patchesDrive = IniRead($iniFile, "Global", "patchesDrive", "Y:")
        $patchesSetup = IniReadSection($iniFile, "Patches")
        $installSetup = IniReadSection($iniFile, "Installs")
    Else
        MsgBox(48, "Invalid Program INI File", "The file you selected does not contain the proper formatting for loading as an INI file")
    EndIf
EndFunc   ;==>LoadINIFile

Don't know if it has anything to do with the problem...

Share this post


Link to post
Share on other sites
bo8ster

I would suggest adding some scaffolding to nail down your problem. ConsoleWrite or debug messages are good. Below is taken from the FAQs.

Func dbg($msg)

DllCall("kernel32.dll", "none", "OutputDebugString", "str", $msg)

EndFunc

Very hard to fix if you don't know where it is broken.


Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites
jwseek

First off, thanks to Authenticity for pointing out some bits I missed in the ini load function. I loaded the default ini at startup, and since I wasn't deviating from that behaviour (even though I might need to in the future), I didn't notice the mistakes. Unfortunately...

So I want to reiterate that this problem is with the installation of programs through AutoIt. Installing these programs one at a time with these switches results in a successful install. Installing these programs with the following loops causes some of the programs to fail:

For $i = 1 To $patchesSetup[0][0]
    ProgressSet($i, "Installing " & $patchesSetup[$i][0])
    $PID = Run($patchesFolder & '\' & $patchesSetup[$i][1], $patchesFolder)
    ProcessWaitClose($PID)
Next

ProgressSet(33, "Copying install folder to " & $copyLocation)
DirCopy($installFolder, $copyLocation, 1)
ProgressSet(66, "Installing Software...")

For $i = 1 To $installSetup[0][0]
    ProgressSet(33 + $i, "Installing " & $installSetup[$i][0])
    $PID = Run($installFolder & '\' & $installSetup[$i][1], $installFolder)
    ProcessWaitClose($PID)
Next

When I'm using this ini file to define what should be installed:

[Global]
ServerName=server
InstallFolder=install
PatchesFolder=patches
InstallDrive=V:
PatchesDrive=Y:

[Patches]
.NET Framework 1.1=dotnetfx11.exe /q
;.NET Framework 1.1 Service Pack 1=Service Packs\dotnet11sp1.exe /q
.NET Framework 3.5=dotnetfx35.exe /passive /norestart
Visual C++ Redistributable 2005=vcredist_x86.exe /q
Windows Media Player 11=wmp11-windowsxp-x86-enu.exe /q

[Installs]
7zip=7zip.msi /passive
Firefox=Freeware\Firefox.msi /passive
Internet Explorer Flash Plugin=flash-ie.exe /S
Mozilla Flash Plugin=flash-mozilla.exe /S
Sun Java=java.exe /passive
Adobe Acrobat Reader=Productivity\AdbeRdr.msi /passive

For instance, the patches all seem to install with the exception of the .NET Framework 1.1 service pack. Then 7-zip, Firefox and Adobe all won't install. I assumed it was because some of the installs are spawning processes that lock access to msiexec, but I don't know. Also, bo8ster's recommendation sounds promising, but I don't entirely understand how to implement it.

Share this post


Link to post
Share on other sites
Authenticity

Maybe the Installs path doesn't exists and making Run fail?

Share this post


Link to post
Share on other sites
jwseek

No...they're all there in the same path. I checked three times. The installs actually start, they just fail. Like I said, this may actually be an issue with msiexec and not AutoIt, but I was hoping somebody could help me narrow it down...

Share this post


Link to post
Share on other sites
jwseek

So there are moments in my life where I find myself extremely embarrassed. This is one of those moments.

I mentioned the msiexec process about 5 times in this thread, and I just realized that to properly execute .msi files, one has to execute them like this:

msiexec /i filename.msi

Pretty silly thing to forget, but there it is...

The corrected code:

#Region;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Icon=favicon.ico
#AutoIt3Wrapper_Compression=4
#AutoIt3Wrapper_Res_Description=Script to install all needed software on new computers
#AutoIt3Wrapper_Res_Fileversion=0.3.0.7
#AutoIt3Wrapper_Res_FileVersion_AutoIncrement=y
#AutoIt3Wrapper_Res_SaveSource=y
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_res_requestedExecutionLevel=requireAdministrator
#AutoIt3Wrapper_Run_Tidy=y
#EndRegion;**** Directives created by AutoIt3Wrapper_GUI ****

#Region Include Statements
#include <GUIConstants.au3>
#EndRegion Include Statements

#Region Variable Declarations
$programTitle = "AutoInstaller"
$iniFile = "autoinstaller.ini"
$iniSections = IniRead($iniFile, "Global", "IniSections", "3")
$serverName = "\\" & IniRead($iniFile, "Global", "ServerName", "")
$installFolder = $serverName & "\" & IniRead($iniFile, "Global", "InstallFolder", "install")
$patchesFolder = $serverName & "\" & IniRead($iniFile, "Global", "PatchesFolder", "patches")
$installDrive = IniRead($iniFile, "Global", "InstallDrive", "Z:")
$patchesDrive = IniRead($iniFile, "Global", "patchesDrive", "Y:")
$patchesSetup = IniReadSection($iniFile, "Patches")
$installSetup = IniReadSection($iniFile, "Installs")
$copyLocation = "D:\BIN"
$BaseX = 20
$BaseY = 15
$CurX = 0
$CurY = 0

Dim $driveMapErrors[6]
$driveMapErrors[0] = "Undefined or Other"
$driveMapErrors[1] = "Access to the remote share was denied"
$driveMapErrors[2] = "The device is already assigned"
$driveMapErrors[3] = "Invalid device name"
$driveMapErrors[4] = "Invalid remote share"
$driveMapErrors[5] = "Invalid password"
#EndRegion Variable Declarations

Opt("TrayIconHide", 1)

$hGUI = GUICreate($programTitle, 280, 210)
Opt("GUICoordMode", 1)

#Region Drop-Down Menu
$fileMenu = GUICtrlCreateMenu("&File")
$iniLoadMenuItem = GUICtrlCreateMenuItem("&Load Ini File", $fileMenu)
$exitProgramMenuItem = GUICtrlCreateMenuItem("E&xit", $fileMenu)
$helpMenu = GUICtrlCreateMenu("&Help")
$aboutMenuItem = GUICtrlCreateMenuItem("About...", $helpMenu)
#EndRegion Drop-Down Menu

#Region Create GUI
$CurX = $BaseX
$CurY = $BaseY
$computerTypeHomeRadio = GUICtrlCreateRadio("Home System", $CurX, $CurY)
$CurY += 25
$computerTypeWorkRadio = GUICtrlCreateRadio("Business System", $CurX, $CurY)
$CurY += 35
GUICtrlCreateLabel("Destination for BIN directory:", $CurX, $CurY)
$CurY += 20
$copyLocationInput = GUICtrlCreateInput($copyLocation, $CurX, $CurY, 150)
$CurX += 160
$browseCopyLocation = GUICtrlCreateButton("Browse...", $CurX, $CurY - 3)
$CurX = $BaseX
$CurY += 45
$executeButton = GUICtrlCreateButton("Install Software", $CurX, $CurY)
$CurX += 135
$exitButton = GUICtrlCreateButton("Exit Program", $CurX, $CurY)
#EndRegion Create GUI

GUISetState()
GUICtrlSetState($computerTypeHomeRadio, $GUI_DISABLE)
GUICtrlSetState($computerTypeWorkRadio, $GUI_DISABLE)

; Run the GUI until the dialog is closed

Do
    $msg = GUIGetMsg()
    Switch $msg
        Case $aboutMenuItem
            MsgBox(0, "", "Version: " & FileGetVersion("AutoInstaller.exe"))

        Case $exitProgramMenuItem
            $msg = $GUI_EVENT_CLOSE

        Case $exitButton
            $msg = $GUI_EVENT_CLOSE

        Case $iniLoadMenuItem
            $iniFile = FileOpenDialog("Select config file", @ScriptDir, "INI files (*.ini)", 1)
            If $iniFile Then
                LoadINIFile()
            EndIf

        Case $browseCopyLocation
            $copyLocation = browseFolder()
            If StringCompare($copyLocation, "") <> 0 Then
                GUICtrlSetData($copyLocationInput, $copyLocation)
            Else
                $copyLocation = GUICtrlRead($copyLocationInput)
            EndIf

        Case $executeButton
            modCallingWindow("AutoInstaller.exe", @SW_MINIMIZE)
            ProgressOn("Installing patches and software...", "Mapping Network Drives...")
            $temp = MapDrives()
            If $temp = 1 Then
                ProgressSet(10, "", "Installing Windows patches...")
                For $i = 1 To $patchesSetup[0][0]
                ;MsgBox(0, "", $patchesFolder & '\' & $patchesSetup[$i][1] & @LF & $patchesSetup[$i][0])
                    ProgressSet($i, "Installing " & $patchesSetup[$i][0])
                    If StringInStr($patchesSetup[$i][1], "msi", 2) = 0 Then
                        $PID = Run($patchesFolder & '\' & $patchesSetup[$i][1], $patchesFolder)
                    Else
                        $PID = Run("msiexec /i " & $patchesFolder & '\' & $patchesSetup[$i][1], $patchesFolder)
                    EndIf
                    ProcessWaitClose($PID)
                Next
                ProgressSet(33, "Copying install folder to " & $copyLocation)
            ;MsgBox(0, "", "Copy from " & $installFolder & " to " & $copyLocation)
                DirCopy($installFolder, $copyLocation, 1)
                ProgressSet(66, "Installing Software...")
                For $i = 1 To $installSetup[0][0]
                ;MsgBox(0, "", $installFolder & '\' & $installSetup[$i][1] & @LF & $installSetup[$i][0])
                    ProgressSet(66 + $i, "Installing " & $installSetup[$i][0])
                    If StringInStr($installSetup[$i][1], "msi", 2) = 0 Then
                        $PID = Run($installFolder & '\' & $installSetup[$i][1], $installFolder)
                    Else
                        $PID = Run("msiexec /i " & $installFolder & "\" & $installSetup[$i][1], $installFolder)
                    EndIf
                    ProcessWaitClose($PID)
                Next
                ProgressSet(100, "Done", "Completed!")
                Sleep(3000)
                ProgressOff()
                modCallingWindow("AutoInstaller.exe", @SW_RESTORE)
                MsgBox(64, "Completed Installation", "Successfully completed installation and copying procedures...")
            Else
                MsgBox(48, "Failed Networking!", "Networking drives to install directories failed...")
            EndIf
    EndSwitch
Until $msg = $GUI_EVENT_CLOSE

DriveMapDel($installDrive)
DriveMapDel($patchesDrive)
GUIDelete()

#Region General Functions
Func browseFolder()
    Local $tempFolder = ""
    $tempFolder = FileSelectFolder("Select Location for BIN Directory:", "")
    Return $tempFolder
EndFunc  ;==>browseFolder

Func LoadINIFile()
;determine whether the sections with in the ini file are correct for this particular ini load
    $iniSectionList = IniReadSectionNames($iniFile)
    If $iniSectionList[0] = $iniSections And $iniSectionList[1] = "Global" Then
        $loadINI = MsgBox(1, "Loading INI File...", "This will change all initialized data (including networking data)", 3)
        $serverName = "\\" & IniRead($iniFile, "Global", "ServerName", "")
        $installFolder = $serverName & "\" & IniRead($iniFile, "Global", "InstallFolder", "install")
        $patchesFolder = $serverName & "\" & IniRead($iniFile, "Global", "PatchesFolder", "patches")
        $installDrive = IniRead($iniFile, "Global", "InstallDrive", "Z:")
        $patchesDrive = IniRead($iniFile, "Global", "patchesDrive", "Y:")
        $patchesSetup = IniReadSection($iniFile, "Patches")
        $installSetup = IniReadSection($iniFile, "Installs")
    Else
        MsgBox(48, "Invalid Program INI File", "The file you selected does not contain the proper formatting for loading as an INI file")
    EndIf
EndFunc  ;==>LoadINIFile

Func IsVisible($handle)
    If BitAND(WinGetState($handle), 2) Then
        Return 1
    Else
        Return 0
    EndIf
EndFunc  ;==>IsVisible

Func modCallingWindow($title, $state)
    Local $activeWindowList = WinList()
    Local $windowNumber = 0
    For $i = 1 To $activeWindowList[0][0]
        If $activeWindowList[$i][0] <> "" And IsVisible($activeWindowList[$i][1]) Then
            Local $windowTitle = StringTrimLeft($activeWindowList[$i][0], StringLen($activeWindowList[$i][0]) - StringLen($title))
            If $windowTitle = $title Then
                $windowNumber = $i
                WinSetState($activeWindowList[$i][0], "", $state)
            EndIf
        EndIf
    Next
EndFunc  ;==>modCallingWindow
#EndRegion General Functions

#Region Networking Functions
Func MapDrives()
    DriveMapDel($installDrive)
    DriveMapDel($patchesDrive)
    $res = DriveMapAdd($installDrive, $installFolder)
    If $res <> 1 Then
        SplashOff()
        MsgBox(16, "Drive Mapping", "Error mapping drive!" & @LF & "Error Code: " & $driveMapErrors[@error])
        Return $res
    EndIf
    $res = DriveMapAdd($patchesDrive, $patchesFolder)
    If $res <> 1 Then
        SplashOff()
        MsgBox(16, "Drive Mapping", "Error mapping drive!" & @LF & "Error Code: " & $driveMapErrors[@error])
        Return $res
    EndIf
    Return $res
EndFunc  ;==>MapDrives
#EndRegion Networking Functions

Share this post


Link to post
Share on other sites
Danny35d

So there are moments in my life where I find myself extremely embarrassed. This is one of those moments.

I mentioned the msiexec process about 5 times in this thread, and I just realized that to properly execute .msi files, one has to execute them like this:

msiexec /i filename.msi

Pretty silly thing to forget, but there it is...

Or instead of Run() use ShellExecute() and you don't have to worry about .exe or .msi

AutoIt Scripts:NetPrinter - Network Printer UtilityRobocopyGUI - GUI interface for M$ robocopy command line

Share this post


Link to post
Share on other sites
jwseek

But then I'd have to parse the arguments that I add to the end of every install procedure to make them non-interactive. This is also pretty easy, and there's less string manipulation. Although, I wish I would have noticed that sooner...

Share this post


Link to post
Share on other sites
bo8ster

I do some installing of programs in batch files - i know AutoIt is the way but thats just how it turned out.

To install postgres I do the following in the batch file

CODE
msiexec /q /i postgresql-8.3-int.msi INTERNALLAUNCH=1 ADDLOCAL=server,nls,psql,pgadmin DOSERVICE="1" SERVICEDOMAIN="%COMPUTERNAME%" SERVICEACCOUNT="postgres" SERVICEPASSWORD="AdminUser" CREATESERVICEUSER="1" SUPERPASSWORD="mypassword" PL_PGSQL="1" DATADIR="E:\dbpath"

If I where to do this in AutoIt I would do something like

ShellExecuteWait('msiexec', ' /q /i postgresql-8.3-int.msi INTERNALLAUNCH=1 ADDLOCAL=server,nls,psql,pgadmin DOSERVICE="1" SERVICEDOMAIN="%COMPUTERNAME%" SERVICEACCOUNT="postgres" SERVICEPASSWORD="AdminUser" CREATESERVICEUSER="1" SUPERPASSWORD="mypassword" PL_PGSQL="1" DATADIR="E:\dbpath")

The use of ProcessWaitClose is good but I believe ShellExecuiteWait is more flexible. You don't get the pid, but you should not need it.

Hope that helps.


Post your code because code says more then your words can. SciTe Debug mode - it's magic: #AutoIt3Wrapper_run_debug_mode=Y. Use Opt("MustDeclareVars", 1)[topic="84960"]Brett F's Learning To Script with AutoIt V3[/topic][topic="21048"]Valuater's AutoIt 1-2-3, Class... is now in Session[/topic]Contribution: [topic="87994"]Get SVN Rev Number[/topic], [topic="93527"]Control Handle under mouse[/topic], [topic="91966"]A Presentation using AutoIt[/topic], [topic="112756"]Log ConsoleWrite output in Scite[/topic]

Share this post


Link to post
Share on other sites
Danny35d

ShellExecuteWait('postgresql-8.3-int.msi', 'INTERNALLAUNCH=1 ADDLOCAL=server,nls,psql,pgadmin DOSERVICE="1" SERVICEDOMAIN="'& @ComputerName & '" SERVICEACCOUNT="postgres" SERVICEPASSWORD="AdminUser" CREATESERVICEUSER="1" SUPERPASSWORD="mypassword" PL_PGSQL="1" DATADIR="E:\dbpath" /qr', @ScriptDir)


AutoIt Scripts:NetPrinter - Network Printer UtilityRobocopyGUI - GUI interface for M$ robocopy command line

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×