Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp	(revision 68023)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp	(revision 68024)
@@ -1384,13 +1384,6 @@
         return errorSyntax(USAGE_UNATTENDEDINSTALL, "Missing VM name/UUID");
 
-    if (!pszSettingsFile)
-    {
-        if (!pszUser)
-            return errorSyntax(USAGE_UNATTENDEDINSTALL, "Missing required --user (or --settings-file) option");
-        if (!pszPassword)
-            return errorSyntax(USAGE_UNATTENDEDINSTALL, "Missing required --password (or --settings-file) option");
-        if (!pszIsoPath)
-            return errorSyntax(USAGE_UNATTENDEDINSTALL, "Missing required --iso-path (or --settings-file) option");
-    }
+    if (!pszSettingsFile && !pszIsoPath)
+        return errorSyntax(USAGE_UNATTENDEDINSTALL, "Missing required --iso-path (or --settings-file) option");
 
     /*
@@ -1435,48 +1428,83 @@
                  Utf8Str(bstrUuid).c_str());
 
+        {
+            /*
+             * Instantiate and configure the unattended installer.
+             */
+            ComPtr<IUnattended> ptrUnattended;
+            CHECK_ERROR_BREAK(machine, CreateUnattendedInstaller(ptrUnattended.asOutParam()));
+
+            if (pszSettingsFile)
+                CHECK_ERROR_BREAK(ptrUnattended, LoadSettings(Bstr(pszSettingsFile).raw()));
+
+            if (pszIsoPath)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(IsoPath)(Bstr(pszIsoPath).raw()));
+            if (pszUser)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(User)(Bstr(pszUser).raw()));
+            if (pszPassword)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(Password)(Bstr(pszPassword).raw()));
+            if (pszFullUserName)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(FullUserName)(Bstr(pszFullUserName).raw()));
+            if (pszProductKey)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(ProductKey)(Bstr(pszProductKey).raw()));
+            if (pszAdditionsIsoPath)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(AdditionsIsoPath)(Bstr(pszAdditionsIsoPath).raw()));
+            if (fInstallAdditions >= 0)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(InstallGuestAdditions)(fInstallAdditions != (int)false));
+            if (fSetImageIdx)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(ImageIndex)(idxImage));
+            if (pszAuxiliaryBasePath)
+                CHECK_ERROR_BREAK(ptrUnattended, COMSETTER(AuxiliaryBasePath)(Bstr(pszAuxiliaryBasePath).raw()));
+
+            CHECK_ERROR_BREAK(ptrUnattended,Prepare());
+            CHECK_ERROR_BREAK(ptrUnattended,ConstructMedia());
+            CHECK_ERROR_BREAK(ptrUnattended,ReconfigureVM());
+
+            /*
+             * Retrieve and display the parameters actually used.
+             */
+            RTPrintf("Using values:\n");
+#define SHOW_ATTR(a_Attr, a_szText, a_Type, a_szFmt) do { \
+                    a_Type Value; \
+                    HRESULT hrc2 = ptrUnattended->COMGETTER(a_Attr)(&Value); \
+                    if (SUCCEEDED(hrc2)) \
+                        RTPrintf("  %22s = " a_szFmt "\n", a_szText, Value); \
+                    else \
+                        RTPrintf("  %22s = failed: %Rhrc\n", a_szText, hrc2); \
+                } while (0)
+#define SHOW_STR_ATTR(a_Attr, a_szText) do { \
+                    Bstr bstrString; \
+                    HRESULT hrc2 = ptrUnattended->COMGETTER(a_Attr)(bstrString.asOutParam()); \
+                    if (SUCCEEDED(hrc2)) \
+                        RTPrintf("  %22s = %ls\n", a_szText, bstrString.raw()); \
+                    else \
+                        RTPrintf("  %22s = failed: %Rhrc\n", a_szText, hrc2); \
+                } while (0)
+
+            SHOW_STR_ATTR(IsoPath,                  "isoPath");
+            SHOW_STR_ATTR(User,                     "user");
+            SHOW_STR_ATTR(Password,                 "password");
+            SHOW_STR_ATTR(FullUserName,             "fullUserName");
+            SHOW_STR_ATTR(ProductKey,               "productKey");
+            SHOW_STR_ATTR(AdditionsIsoPath,         "additionsIsoPath");
+            SHOW_ATTR(    InstallGuestAdditions,    "installGuestAdditions",    BOOL, "%RTbool");
+            SHOW_STR_ATTR(ValidationKitIsoPath,     "validationKitIsoPath");
+            SHOW_ATTR(    InstallTestExecService,   "installTestExecService",   BOOL, "%RTbool");
+            SHOW_STR_ATTR(AuxiliaryBasePath,        "auxiliaryBasePath");
+            SHOW_ATTR(    ImageIndex,               "imageIndex",               ULONG, "%u");
+            SHOW_STR_ATTR(ScriptTemplatePath,       "scriptTemplatePath");
+
+#undef SHOW_STR_ATTR
+#undef SHOW_ATTR
+        }
+
+        a->session->UnlockMachine();
+
         /*
-         * Instantiate and configure the unattended installer.
+         * Start the VM if requested.
          */
-        ComPtr<IUnattended> unAttended;
-        CHECK_ERROR_BREAK(machine, COMGETTER(Unattended)(unAttended.asOutParam()));
-
-        /* Always calls 'done' to clean up from any aborted previous session. */
-        CHECK_ERROR_BREAK(unAttended,Done());
-
-        if (pszSettingsFile)
-            CHECK_ERROR_BREAK(unAttended, LoadSettings(Bstr(pszSettingsFile).raw()));
-
-        if (pszIsoPath)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(IsoPath)(Bstr(pszIsoPath).raw()));
-        if (pszUser)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(User)(Bstr(pszUser).raw()));
-        if (pszPassword)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(Password)(Bstr(pszPassword).raw()));
-        if (pszFullUserName)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(FullUserName)(Bstr(pszFullUserName).raw()));
-        if (pszProductKey)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(ProductKey)(Bstr(pszProductKey).raw()));
-        if (pszAdditionsIsoPath)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(AdditionsIsoPath)(Bstr(pszAdditionsIsoPath).raw()));
-        if (fInstallAdditions >= 0)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(InstallGuestAdditions)(fInstallAdditions != (int)false));
-        if (fSetImageIdx)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(ImageIndex)(idxImage));
-        if (pszAuxiliaryBasePath)
-            CHECK_ERROR_BREAK(unAttended, COMSETTER(AuxiliaryBasePath)(Bstr(pszAuxiliaryBasePath).raw()));
-
-        CHECK_ERROR_BREAK(unAttended,Prepare());
-        CHECK_ERROR_BREAK(unAttended,ConstructMedia());
-        CHECK_ERROR_BREAK(unAttended,ReconfigureVM());
-        CHECK_ERROR_BREAK(unAttended,Done());
-
-        /*
-         * Start the VM.
-         */
-        a->session->UnlockMachine();
-
+        if (RTStrICmp(pszSessionType, "none") != 0)
         {
             Bstr env;
-
 #if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
             /* make sure the VM process will start on the same display as VBoxManage */
@@ -1520,46 +1548,10 @@
                 }
             }
-        }
-
-        /*
-         * Retrieve and display the parameters actually used.
-         */
-        Bstr bstrAdditionsIsoPath;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(AdditionsIsoPath)(bstrAdditionsIsoPath.asOutParam()));
-        BOOL fInstallGuestAdditions = FALSE;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(InstallGuestAdditions)(&fInstallGuestAdditions));
-        Bstr bstrIsoPath;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(IsoPath)(bstrIsoPath.asOutParam()));
-        Bstr bstrUser;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(User)(bstrUser.asOutParam()));
-        Bstr bstrPassword;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(Password)(bstrPassword.asOutParam()));
-        Bstr bstrFullUserName;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(FullUserName)(bstrFullUserName.asOutParam()));
-        Bstr bstrProductKey;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(ProductKey)(bstrProductKey.asOutParam()));
-        Bstr bstrAuxiliaryBasePath;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(AuxiliaryBasePath)(bstrAuxiliaryBasePath.asOutParam()));
-        ULONG idxImageActual = 0;
-        CHECK_ERROR_BREAK(unAttended, COMGETTER(ImageIndex)(&idxImageActual));
-        RTPrintf("Got values:\n"
-                 " user:                  %ls\n"
-                 " password:              %ls\n"
-                 " fullUserName:          %ls\n"
-                 " productKey:            %ls\n"
-                 " image index:           %u\n"
-                 " isoPath:               %ls\n"
-                 " additionsIsoPath:      %ls\n"
-                 " installGuestAdditions: %RTbool\n"
-                 " auxiliaryBasePath:     %ls",
-                 bstrUser.raw(),
-                 bstrPassword.raw(),
-                 bstrFullUserName.raw(),
-                 bstrProductKey.raw(),
-                 idxImageActual,
-                 bstrIsoPath.raw(),
-                 bstrAdditionsIsoPath.raw(),
-                 fInstallGuestAdditions,
-                 bstrAuxiliaryBasePath.raw());
+
+            /*
+             * Do we wait for the VM to power down?
+             */
+        }
+
     } while (0);
 
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 68023)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 68024)
@@ -3767,5 +3767,5 @@
   <interface
     name="IUnattended" extends="$unknown"
-    uuid="a6ba3585-5fc3-4465-d61d-5b70540690af"
+    uuid="b365bb45-267f-44fa-c32a-cad265372f8e"
     wsmap="managed"
     reservedMethods="4" reservedAttributes="16"
@@ -3776,6 +3776,17 @@
       the Guest OS for fully automated install.
 
-      It is based on the IMachine:
-      <link to="IMachine::unattended"/> attribute.
+      The typical workflow is:
+      <ol>
+        <li>Call <link to="IMachine::createUnattendedInstaller"/> to create the object</li>
+        <li>Set the IUnattended attributes.</li>
+        <li>Call <link to="IUnattended::prepare"/> for the object to check the
+            attribute values and create an internal installer instance.</li>
+        <li>Call <link to="IUnattended::constructMedia"/> to create additional
+            media files (ISO/floppy) needed.</li>
+        <li>Call <link to="IUnattended::reconfigureVM"/> to reconfigure the VM
+            with the installation ISO, additional media files and whatnot </li>
+        <li>Optionally call <link to="IUnattended::done"/> to destroy the internal
+            installer and allow restarting from the second step.</li>
+      </ol>
     </desc>
 
@@ -3815,5 +3826,9 @@
     <attribute name="additionsIsoPath" type="wstring">
       <desc>
-        Guest Additions ISO image path
+        Guest Additions ISO image path.  This defaults to
+        <link to="ISystemProperties::defaultAdditionsISO"/> when the Unattended
+        object is instantiated.
+
+        This property is ignored when <link to="IUnattended::installGuestAdditions"/> is false.
       </desc>
     </attribute>
@@ -3826,4 +3841,21 @@
         distribution, only the installation of additions pointed to by
         <link to="IUnattended::additionsIsoPath"/>.
+      </desc>
+    </attribute>
+
+    <attribute name="validationKitIsoPath" type="wstring">
+      <desc>
+        VirtualBox ValidationKit ISO image path.  This is used when
+        <link to="IUnattended::installTestExecService"/> is set to true.
+      </desc>
+    </attribute>
+
+    <attribute name="installTestExecService" type="boolean">
+      <desc>
+        Indicates whether the test execution service (TXS) from the VBox
+        ValidationKit should be installed.
+
+        The TXS binary will be taken from the ISO indicated by
+        <link to="IUnattended::validationKitIsoPath"/>.
       </desc>
     </attribute>
@@ -3846,4 +3878,23 @@
         Used only with Windows installation CD/DVD:
         https://technet.microsoft.com/en-us/library/cc766022%28v=ws.10%29.aspx
+      </desc>
+    </attribute>
+
+    <attribute name="machine" type="IMachine" readonly="yes">
+      <desc>
+        The associated machine object.
+      </desc>
+    </attribute>
+
+    <attribute name="scriptTemplatePath" type="wstring">
+      <desc>
+        The unattended installation script template file.
+
+        The template default is based on the guest OS type and is determined by the
+        internal installer when when <link to="IUnattended::prepare"/> is invoked.
+        Most users will want the defaults.
+
+        After <link to="IUnattended::prepare"/> is called, it can be read to see
+        which file is being used.
       </desc>
     </attribute>
@@ -5386,8 +5437,4 @@
     </attribute>
 
-    <attribute name="unattended" type="IUnattended" readonly="yes">
-      <desc>Associated unattended install class, always present.</desc>
-    </attribute>
-
     <method name="lockMachine">
       <desc>
@@ -7968,4 +8015,13 @@
       <param name="progress" type="IProgress" dir="return">
         <desc>Progress object to track the operation completion.</desc>
+      </param>
+    </method>
+
+    <method name="createUnattendedInstaller">
+      <desc>
+        Creates a new <link to="IUnattended"/> guest installation object.
+      </desc>
+      <param name="unattended" type="IUnattended" dir="return">
+        <desc>New unattended object.</desc>
       </param>
     </method>
Index: /trunk/src/VBox/Main/include/MachineImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineImpl.h	(revision 68023)
+++ /trunk/src/VBox/Main/include/MachineImpl.h	(revision 68024)
@@ -776,7 +776,4 @@
     const ComObjPtr<BIOSSettings>      mBIOSSettings;
     const ComObjPtr<BandwidthControl>  mBandwidthControl;
-#ifdef VBOX_WITH_UNATTENDED
-    const ComObjPtr<Unattended>        mUnattended;
-#endif
 
     typedef std::vector<ComObjPtr<NetworkAdapter> > NetworkAdapterVector;
@@ -984,5 +981,4 @@
     HRESULT getVMProcessPriority(com::Utf8Str &aVMProcessPriority);
     HRESULT setVMProcessPriority(const com::Utf8Str &aVMProcessPriority);
-    HRESULT getUnattended(ComPtr<IUnattended> &aUnattended);
 
     // wrapped IMachine methods
@@ -1202,4 +1198,5 @@
     HRESULT restoreSnapshot(const ComPtr<ISnapshot> &aSnapshot,
                             ComPtr<IProgress> &aProgress);
+    HRESULT createUnattendedInstaller(ComPtr<IUnattended> &aUnattended);
     HRESULT applyDefaults(const com::Utf8Str &aFlags);
 
Index: /trunk/src/VBox/Main/src-server/MachineImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 68023)
+++ /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 68024)
@@ -7184,35 +7184,4 @@
 }
 
-HRESULT Machine::getUnattended(ComPtr<IUnattended> &aUnattended)
-{
-#ifdef VBOX_WITH_UNATTENDED
-    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
-    if (mUnattended.isNotNull())
-        aUnattended = mUnattended;
-    else
-    {
-        /* Do on-demand creation. */
-        alock.release();
-        AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
-        if (mUnattended.isNull())
-        {
-            unconst(mUnattended).createObject();
-            HRESULT hrc = mUnattended->init(this);
-            if (FAILED(hrc))
-            {
-                mUnattended->uninit();
-                unconst(mUnattended).setNull();
-                return hrc;
-            }
-        }
-        aUnattended = mUnattended;
-    }
-    return S_OK;
-#else
-    NOREF(aUnattended);
-    return E_NOTIMPL;
-#endif
-}
-
 HRESULT Machine::cloneTo(const ComPtr<IMachine> &aTarget, CloneMode_T aMode, const std::vector<CloneOptions_T> &aOptions,
                          ComPtr<IProgress> &aProgress)
@@ -8445,8 +8414,4 @@
     mBandwidthControl->init(this);
 
-#ifdef VBOX_WITH_UNATTENDED
-    Assert(mUnattended.isNull()); /* Created on-demand. */
-#endif
-
     return S_OK;
 }
@@ -8525,12 +8490,4 @@
         unconst(mBIOSSettings).setNull();
     }
-
-#ifdef VBOX_WITH_UNATTENDED
-    if (mUnattended)
-    {
-        mUnattended->uninit();
-        unconst(mUnattended).setNull();
-    }
-#endif
 
     /* Deassociate media (only when a real Machine or a SnapshotMachine
@@ -15158,4 +15115,23 @@
 }
 
+HRESULT Machine::createUnattendedInstaller(ComPtr<IUnattended> &aUnattended)
+{
+#ifdef VBOX_WITH_UNATTENDED
+    ComObjPtr<Unattended> ptrUnattended;
+    HRESULT hrc = ptrUnattended.createObject();
+    if (SUCCEEDED(hrc))
+    {
+        AutoReadLock wlock(this COMMA_LOCKVAL_SRC_POS);
+        hrc = ptrUnattended->init(this);
+        if (SUCCEEDED(hrc))
+            hrc = ptrUnattended.queryInterfaceTo(aUnattended.asOutParam());
+    }
+    return hrc;
+#else
+    NOREF(aUnattended);
+    return E_NOTIMPL;
+#endif
+}
+
 HRESULT Machine::applyDefaults(const com::Utf8Str &aFlags)
 {
