Creating automated Windows Installation Script.

Discussion in 'Windows 8' started by Pimmeke1989, Mar 17, 2014.

  1. Pimmeke1989

    Pimmeke1989 MDL Novice

    Aug 13, 2012
    9
    2
    0
    #1 Pimmeke1989, Mar 17, 2014
    Last edited: Mar 17, 2014
    Hello everybody,
    A while ago I started to make a script for a fully, fast and simple Installation for multiple Windows Versions.
    The main idea was to deploy the install.wim image you can find on the Windows DVD with the IMAGEX command.
    Slowly it started to grow, and now I have a bootable USB with a Win PE4.0 witch automatically runs a small program i made in Visual Studio, which can install Windows 7, 8 and 8.1.
    The program only makes a text file with the following infomation in it:
    -Which Disk you want to install it to (Adds "Disk 0" to txt)
    -The OS you want (Adds "Windows 8.1 Pro" to txt)
    -And if you have Win 8 or 8.1, if you want an UEFI based boot (Adds "UEFI" to txt)
    When you finish the program, it loads an script which reads the text file and installs the wanted things.
    This all works really well, and my record for installing the full OS is about 30 seconds!! (USB3.0 on an SSD)

    The next thing I wanted was that the user can choose which programs has to be pre-installed.
    But I didn't want to add them to the WIM-file, because you can't choose the wanted programs.
    What it now does is copy the installer files to the just created OS-partition, and execute an installer script which installs every program in silent mode. This script is called with the SetupComplete.cmd.
    This method also works.

    Little summary of the installation progress:
    -First it will install the OS, unpacking the wanted Wim-file
    -After that, if you want additional software, it wil copy the right files to the just created OS-partition.
    -When it boots, an account has to be created.
    -After creating the account, it wil install the software right before it boots to the desktop.

    But now comes my questions:
    -The SetupComplete.cmd is called right after the user created an account. I want these programs installed BEFORE the user has created an account. I've tried some methods with adding an unattend.xml to the installation of the OS, and I got it booting to the Audit mode, but I couldn't run an additional script to install the software and exit the Audit mode.
    -I want to make a recovery program, so that the end-user can safely recover it's system. This has to be added to the advanced boot options as an extra option (the menu you get after you press restart with the shift-key pressed).

    I hope some people here can help me. I'm a new programmer, as a hobby.
    When this program is finished, I will make it available for everybody.
    In the attachments is a screen of the program, sorry for the language, it's in Dutch, as I'm from the Netherlands.
    The first dropdown box you can choose the OS, the second one the Disk
     

    Attached Files:

  2. Tito

    Tito Super Mod / Adviser
    Staff Member

    Nov 30, 2009
    18,681
    18,584
    340
  3. abbodi1406

    abbodi1406 MDL KB0000001

    Feb 19, 2011
    16,190
    84,688
    340
    #3 abbodi1406, Mar 17, 2014
    Last edited by a moderator: Apr 20, 2017
  4. Pimmeke1989

    Pimmeke1989 MDL Novice

    Aug 13, 2012
    9
    2
    0
    I already achieved something like this, but this is not what I wanted. HALIKUS uses the SetupComplete.cmd too, but that one is called right after making an account.
    What I'm trying to do is that the first boot of the System automatically goes to Audit mode, then it will install the wanted software, and right after that the system reboots, and it goes to Account Creation.
    But HALIKUS Tool is indeed very handy!!
     
  5. murphy78

    murphy78 MDL DISM Enthusiast

    Nov 18, 2012
    7,389
    11,614
    240
    I'm not sure you want to. Some things don't work properly in Audit mode. I know from personal experience that Windows Update still doesn't work even after the s14 update and all hotfixes.
     
  6. Pimmeke1989

    Pimmeke1989 MDL Novice

    Aug 13, 2012
    9
    2
    0
    @abbodi1406
    Thanks for this, I will try it when I have the chance. It looks familiar, like i tried it before. Where do I put this file in the just installed Windows direction?
     
  7. abbodi1406

    abbodi1406 MDL KB0000001

    Feb 19, 2011
    16,190
    84,688
    340
    I only test it as autounattend.xml in the dvd root
    you can try to add it as $oem$\$1\unattend.xml so it get copied to the system drive
     
  8. HALIKUS

    HALIKUS MDL Addicted

    Jul 29, 2009
    526
    371
    30
  9. Pimmeke1989

    Pimmeke1989 MDL Novice

    Aug 13, 2012
    9
    2
    0
    Thanks for your reply!

    The first two things you say I already have figured it out. The Windows Installation is working, and so is the copying the software to a folder in de C-drive.
    I will go further in detail about the script I'm using, so you can understand what I want.

    1. The first thing the script does is formatting the hard drive with a DISKPART script. (diskpart.exe /s format.txt, where the Windows Partition gets the letter W)
    2. Then it will install the wanted OS onto that drive (IMAGEX.EXE /apply WIN7-64.wim 2 W:)
    3. Next thing is to install the BCD (bcdboot.exe W:\Windows)
    4. Now the copying of the wanted software starts, it will do this in two steps, first it creates a folder (W:\Software), and then it copies al the needed files to there (Xcopy)
    5. Then the script wil end, and the computer reboots and will start booting Windows

    All these things are fully working, I've tested it multiple times on different machines.
    But now the tricky part. A lot of Laptop manufacturers, for example ASUS, install their software the first time the machine boots. It first creates an Administrator Account in Audit/Sysprep mode, and it wil automatically install their software. Then the computer reboots, and the customer can create their account and use their machine. I want to do exactly the same.
    I already tried the SetupComplete.cmd file, copying it to W:\Windows\Setup\Scripts\, and it does work, but after creating an account.
    Then I tried to paste an Unattend.xml file in W:\Windows\system32\sysprep\, and it does boot automatically to an Admin account, but it constantly reboots to it.
    The reason I want to do this, is that I work at an Customers Desk in a computer store, and it will save us a lot of time helping customers.
     
  10. murphy78

    murphy78 MDL DISM Enthusiast

    Nov 18, 2012
    7,389
    11,614
    240
    Hmm... is it not possible to have an $oem$\$$\Setup\State\state.ini with a modified state.ini telling your system to boot to audit mode?
     
  11. Pimmeke1989

    Pimmeke1989 MDL Novice

    Aug 13, 2012
    9
    2
    0
    @abbodi1406 & HALIKUS
    Thanks to you two I've got it working!
    This is what I have done now:
    -After step 4, it copies the Unattend.xml (the one abbodi1406 posted) to W:\Windows\Panther
    -When it reboots, it automatically goes to Audit mode and installs the software.
    -When done, it reboots and the user can make an account, no interaction needed.
    It workst perfectly now, it only needs some tweaking to get the final result.

    Now I have one challenge left:
    I want to create a second partition, let's call it Recovery, where the files needed are placed to boot a new customized PE4.0 environment where the same tool as from my usb is placed to reinstall the OS.
    I already added an boot option to the winre.wim, and it is shown Advanced Startup in Windows 8 (I used this tutorial h t t p ://technet.microsoft.com/en-us/library/jj126994.aspx)
    But now it has to boot the boot.wim I place in the Recovery partition...
     
  12. HALIKUS

    HALIKUS MDL Addicted

    Jul 29, 2009
    526
    371
    30
    #12 HALIKUS, Mar 18, 2014
    Last edited by a moderator: Apr 20, 2017
    First thing i can suggest is you can put the "software" dir inside $oem$\$1\software and it will automatically copy to the root of the system drive. It saves the xcopy step, but i respect the fact you have a working solution and don't abide by their methods.

    OEMs vary with how they deploy images and are just like "us" where they have have to think outside the box to install things out of the box ;) I've seen drivers and software installed various ways like integrated into the wim, installed via a cmd from a directory on the system root, installed from a directory on a hidden partition, deployed from a Data.wim, etc.

    Do you want the same applications installed on every PC, or do you have to be selective about it?

    If the answer is the same on every PC, i would install an image, install the apps, sysprep and generalize, then capture the wim. When you install it do the diskpart, deploying of the wim and the bcd part the same, but when it's done, leave it and don't reboot. When the customer turns it on the first time, he will see the second portion of setup where they will be given the opportunity to create their account and proceed to the desktop where the sysprepped apps will be pre-installed. This method would also be much quicker than installing the apps on the fly each deployment. I see no reason why this method wouldn't work for you.

    Now, if you are like me and need to install win7\8\8.1 x86\x64 (preferably) from a single USB where you want to use a common $oem$ folder for all OS and have the ability to choose what is installed, then my setupcomplete.exe is what you should use. I have a 52 index install.wim so i rely on my $oem$ ingenuity and only offline service a few select OS each month with hotfixes.

    It's the day after St Pattys so i hope i was coherent :)

    Being hungover i took to long to type and see there were more replies. I think i know what you want to do with the winpe. During my installs, i have setupcomplete launch the following autoit exe that installs winpe as a boot option. It does the following:

    1: searches for "WinPE" in the bcd and searches for c:\windows\system32\boot.wim
    2: if "WinPE" exists, it searches for \sources\boot.wim (or \sources\boot64.wim) and copies it to c:\windows\system32\boot.wim. DONE.
    3: If "Winpe" doesn't exist in the bcd, it adds the bcd entries and then copies over boot.wim.

    You can try to use mine or maybe adapt the idea to a cmd. I have it in cmd form too if it helps. It's actually pretty easy to do if you understand the commands.
    Code:
    #RequireAdmin
    #Region ;**** Directives created by AutoIt3Wrapper_GUI ****
    #AutoIt3Wrapper_Icon=..\APPS\au3.ico
    #AutoIt3Wrapper_Compression=4
    #AutoIt3Wrapper_Compile_Both=y
    #AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
    #AutoIt3Wrapper_Add_Constants=n
    #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
    
    #include <Array.au3>
    #include <Constants.au3>
    #include <File.au3>
    #include <String.au3>
    
    
    Global $WinPEx86 = "sources\boot.wim"
    Global $WinPEx64 = "sources\boot64.wim"
    Global $BCDTimeout = "5"
    
    
    HotKeySet("{F1}", "Quit") ;Press ESC key to quit
    Func Quit()
    Exit
    EndFunc   ;==>Quit
    
    
    DllCall("kernel32.dll", "int", "Wow64DisableWow64FsRedirection", "int", 1) ; This disables 32bit applications from being redirected to syswow64 instead of system32 by default ;
    If Not IsAdmin() Then; This enables cmd to run as admin
    RunAs($user, $domain, $pass, 0, @ScriptName, @ScriptDir)
    EndIf
    
    
    ;Detect OS properly
    Global $OSBuild = 1
    $OSBuild = FileGetVersion("user32.dll")
    If (StringRegExp($OSBuild, "^(.*)\.(.+)\.(.+)\.(.*)$")) Then
    $OSBuild = StringRegExp($OSBuild, "^(.*)\.(.+)\.(.+)\.(.*)$", 1)
    $OSBuild = $OSBuild[2]
    Else
    $OSBuild = @OSBuild
    EndIf
    ;MsgBox(64, @OSBuild, $OSBuild, 1)
    
    
    _WinPE()
    Exit
    
    
    
    ;Find bootwim
    Func _FindFileBootwim($bootwim, $sSearch4 = "ALL")
    If StringLeft($bootwim, 1) <> "\" Then $bootwim = "\" & $bootwim
    Local $aDrives4 = DriveGetDrive($sSearch4)
    For $i4 = 1 To $aDrives4[0]
    If FileExists($aDrives4[$i4] & $bootwim) Then Return $aDrives4[$i4]
    Next
    Return SetError(1, 0, "")
    EndFunc   ;==>_FindFileBootwim
    
    
    Func _WinPE()
    ;set bcd perameters
    $bcdedit = @SystemDir & "\bcdedit.exe"
    Global $DOS, $Message
    $DOS = Run(@ComSpec & " /c bcdedit /enum", "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)
    ProcessWaitClose($DOS)
    $Message = StdoutRead($DOS)
    
    If StringInStr($Message, "winload.efi") Then
    MsgBox(4096, "EFI Mode", "EFI Mode exists", 1)
    $winload = "winload.efi"
    Else
    MsgBox(4096, "BIOS Mode", "BIOS Mode exists", 1)
    $winload = "winload.exe"
    EndIf
    
    
    ;Copy WinPE with ini path
    If FileExists(@WindowsDir & "\system32\boot.wim") Then
    Else
    If @OSArch = "X86" Then
    $bootwim = _FindFileBootwim($WinPEx86)
    If FileExists($bootwim & "\" & $WinPEx86) Then
    _ProgressTXT("WinPE", "WinPE copy x86 to C:\Windows\system32\boot.wim.", 1000, 14)
    MsgBox(4096, "WinPE", "WinPE copy x86 to C:\Windows\system32\boot.wim", 1)
    FileCopy($bootwim & "\" & $WinPEx86, @WindowsDir & "\system32\", 9)
    EndIf
    EndIf
    If @OSArch = "X64" Then
    $bootwim = _FindFileBootwim($WinPEx64)
    If FileExists($bootwim & "\" & $WinPEx64) Then
    _ProgressTXT("WinPE", "WinPE copy x64 to C:\Windows\system32\boot.wim.", 1000, 14)
    MsgBox(4096, "WinPE", "WinPE copy x64 to C:\Windows\system32\boot.wim", 1)
    FileCopy($bootwim & "\" & $WinPEx64, @WindowsDir & "\system32\boot.wim", 9)
    Else
    $bootwim = _FindFileBootwim($WinPEx86)
    If FileExists($bootwim & "\" & $WinPEx86) Then
    _ProgressTXT("WinPE", "WinPE copy x86 to C:\Windows\system32\boot.wim.", 1000, 14)
    MsgBox(4096, "WinPE", "WinPE copy x86 to C:\Windows\system32\boot.wim", 1)
    FileCopy($bootwim & "\" & $WinPEx86, @WindowsDir & "\system32\", 9)
    EndIf
    EndIf
    EndIf
    EndIf
    
    
    ;WinPE
    If StringInStr($Message, "WinPE") Then
    MsgBox(4096, "WinPE", "WinPE exists", 1)
    Else
    ;Winpe Ramdisk
    If FileExists(@WindowsDir & "\system32\boot.wim") Then
    MsgBox(4096, "WinPE", "WinPE BCD Entries", 1)
    ;RunWait(@ComSpec & " /c " & $bcdedit & ' /create /d "WinPERamdisk" /device > ' & @TempDir & "\bcd_out.txt", @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & ' /create /device > ' & @TempDir & "\bcd_Winpe.txt", @SystemDir & "\", @SW_HIDE)
    Sleep(1000)
    $file = FileOpen(@TempDir & "\bcd_Winpe.txt", 0)
    $line = FileReadLine($file)
    FileClose($file)
    $pos1 = StringInStr($line, "{")
    $pos2 = StringInStr($line, "}")
    If $pos2 - $pos1 = 37 Then
    $ramdisk = StringMid($line, $pos1, $pos2 - $pos1 + 1)
    ;RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $ramdisk & ' description "WinPERamdisk"', @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $ramdisk & " ramdisksdidevice partition=c:", @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $ramdisk & " ramdisksdipath \Windows\system32\boot.sdi", @SystemDir & "\", @SW_HIDE)
    EndIf
    ;boot.wim
    RunWait(@ComSpec & " /c " & $bcdedit & ' /create /d "WinPE" /application osloader > ' & @TempDir & "\bcd_Winpe2.txt", @SystemDir & "\", @SW_HIDE)
    ;RunWait(@ComSpec & " /c " & $bcdedit & ' /create /application osloader > ' & @TempDir & "\bcd_out2.txt", @SystemDir & "\", @SW_HIDE)
    Sleep(1000)
    $2file = FileOpen(@TempDir & "\bcd_Winpe2.txt", 0)
    $2line = FileReadLine($2file)
    FileClose($2file)
    $2pos1 = StringInStr($2line, "{")
    $2pos2 = StringInStr($2line, "}")
    If $2pos2 - $2pos1 = 37 Then
    $guid = StringMid($2line, $2pos1, $2pos2 - $2pos1 + 1)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $guid & " systemroot \Windows", @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $guid & " detecthal Yes", @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $guid & " winpe Yes", @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $guid & " osdevice ramdisk=[c:]\windows\system32\boot.wim," & $ramdisk, @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $guid & " device ramdisk=[c:]\windows\system32\boot.wim," & $ramdisk, @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $guid & " path \Windows\system32\" & $winload, @SystemDir & "\", @SW_HIDE)
    ;RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $guid & ' description "WinPE"', @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /set " & $guid & ' locale en-US', @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & " /displayorder " & $guid & ' /addlast', @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & ' Default {current}', @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & ' /set {current} bootmenupolicy standard', @SystemDir & "\", @SW_HIDE)
    RunWait(@ComSpec & " /c " & $bcdedit & ' /timeout 5', @SystemDir & "\", @SW_HIDE)
    FileDelete(@TempDir & "\bcd_Winpe2.txt")
    FileDelete(@TempDir & "\bcd_Winpe.txt")
    EndIf
    EndIf
    EndIf
    MsgBox(4096, "WinPE", "WinPE Done", 1)
    EndFunc   ;==>_WinPE
    
    
    
    ;_ProgressTXT("SetupComplete", "SetupComplete " & @OSArch & " Begin.", 1500, 16)
    Func _ProgressTXT($SplashtxtTitle, $SplashtxtMsg, $SplashtxtTime, $SplashtxtSize)
    $Label = GUICtrlCreateLabel("" & $SplashtxtMsg & "", 5, 460, 334, 17)
    SplashTextOn($SplashtxtTitle, $SplashtxtMsg, -1, 50, 350, 0, 1, "", $SplashtxtSize)
    WinSetOnTop($SplashtxtTitle, "", 1)
    ;SplashTextOn ( "title", "text" [, w [, h [, x pos [, y pos [, opt [, "fontname" [, "fontsz" [, "fontwt"]]]]]]]] )
    ;SplashTextOn("SetupComplete", "SetupComplete " & @OSArch & " Begin.", -1, 50, 350, 5, 2, "", 16)
    Sleep($SplashtxtTime)
    SplashOff()
    EndFunc   ;==>_ProgressTXT