HEX
Server: Apache
System: Windows NT MAGNETO-ARM 10.0 build 22000 (Windows 10) AMD64
User: Michel (0)
PHP: 7.4.7
Disabled: NONE
Upload Files
File: C:/Windows/OEM/Unattend.wsf
<package>
    <job id="setup">
        <?job debug="true" ?>

        <runtime>
            <named name="ConfigurationPass" type="string"
                helpstring="The configuration pass to apply." />
        </runtime>

        <object id="FSO" progid="Scripting.FileSystemObject" />
        <object id="WshShell" progid="WScript.Shell" />

        <script language="VBScript" src="Utility.vbs" />
        <script language="VBScript" src="AspJson.vbs" />

        <script language="VBScript">

            Class OfflineFlags
                Public ConfigureBootStatusPolicy
                Public ConfigureTimeSettings
                Public ConfigureSanPolicy
                Public ConfigureRdpKeepAlive
                Public ConfigureBCD
                Public ConfigureTimeService
                Public SetScreenAlwaysOn
                Public ConfigureRecoveryEnabled
                Public CopyCustomData
                Public RunAzSecAgent
                Public ConfigureCertificates
                Public ConfigureWinRm
                Public ConfigureAutomaticUpdates
                Public UpdateRDPCertificateThumbprint
                Public ConfigureGuestAgentService

                Public PreprovisionFlags
                Public ReprovisionFlags

                Private Sub Class_Initialize
                    ConfigureBootStatusPolicy           = &H00000001&
                    ConfigureTimeService                = &H00000002&
                    ConfigureTimeSettings               = &H00000004&
                    ConfigureSanPolicy                  = &H00000008&
                    ConfigureRdpKeepAlive               = &H00000010&
                    SetScreenAlwaysOn                   = &H00000020&
                    ConfigureBCD                        = &H00000040&
                    ConfigureRecoveryEnabled            = &H00000080&
                    CopyCustomData                      = &H00000100&
                    RunAzSecAgent                       = &H00000200&
                    ConfigureCertificates               = &H00000400&
                    ConfigureWinRm                      = &H00000800&
                    ConfigureAutomaticUpdates           = &H00001000&
                    UpdateRDPCertificateThumbprint      = &H00002000&
                    ConfigureGuestAgentService          = &H00004000&

                    ' Procedures to bypass when running preprovision pass
                    ' We do not bypass the admin username as we expect a random
                    ' username from the host for preprovisioned VMs
                    PreprovisionFlags = CopyCustomData _
                                        Or RunAzSecAgent _
                                        Or ConfigureCertificates _
                                        Or ConfigureWinRm _
                                        Or ConfigureAutomaticUpdates _
                                        Or UpdateRDPCertificateThumbprint

                    ' Since guest agent is installed during preprovision
                    ' reprovision will consider guest agent as offlined
                    ReprovisionFlags = ConfigureGuestAgentService
                End Sub
            End Class

            Class SetupStage
                Public StageType
                Public StageName
                Public StageInstanceIndex
                Public HasMultipleInstances
                Public StageStartTime
                Public StageEndTime
            End Class

            ' Following constants are defined as part of WillReboot documentation here:
            ' https://technet.microsoft.com/en-us/library/cc722061(v=ws.10).aspx
            Const UNATTEND_SYNCHRONOUS_COMMAND_RETURN_CODE_NO_REBOOT_REQUIRED = 0
            Const UNATTEND_SYNCHRONOUS_COMMAND_RETURN_CODE_REBOOT_REQUIRED =  1

            Const GUEST_FIRSTBOOT_COMPLETION_KVP_NAME = "FirstBootComplete"

            Const ERROR_INSTALL_FAILURE = &H00000643&

            Const EventTypeTimeShift = 1
            Const EventTypeStage = 2

            Const GuestParametersPath = "HKLM\Software\Microsoft\Virtual Machine\Guest\Parameters"
            Const AzureProvisioningOfflinedFlagsValue = "AzureProvisioningOfflinedFlags"
            Const AzureProvisioningOfflinedTagValue = "AzureProvisioningOfflinedTag"
            Const AzureProvisioningOfflinedFlagsPath = "HKEY_LOCAL_MACHINE\SYSTEM\Setup"
            Const AzureProvisioningPath = "HKEY_LOCAL_MACHINE\SYSTEM\Setup\AzureProvisioning"
            Const ReprovisioningAgentName = "AzureRPA"

            Dim g_Trace, oTraceEvent
            Dim m_Environment
            Dim g_objGuestInterface, g_objOS
            Dim g_objOfflinedFeatures
            Dim g_objEffectiveOfflinedFeatures
            Dim g_OfflineFlags
            Dim g_TracedStages : g_TracedStages = Array()

            Dim winPAVersion
            Dim containerId
            Dim mediaIdentifier

            Dim g_exitCode : g_exitCode = UNATTEND_SYNCHRONOUS_COMMAND_RETURN_CODE_NO_REBOOT_REQUIRED

            Dim kvp_pa_provision_state               : kvp_pa_provision_state               = "provisioning_PA_ProvisionState"
            Dim kvp_pa_provision_tick_count          : kvp_pa_provision_tick_count          = "provisioning_PA_TickCount"
            Dim kvp_pa_provision_completion_time     : kvp_pa_provision_completion_time     = "provisioning_PA_CompletionTime"
            Dim kvp_pa_provision_setup_etl           : kvp_pa_provision_setup_etl           = "provisioning_PA_SetupEtl"
            Dim kvp_pa_provision_media_identifier    : kvp_pa_provision_media_identifier    = "provisioning_PA_MediaIdentifier"
            Dim kvp_pa_provision_page_file_changed   : kvp_pa_provision_page_file_changed   = "provisioning_PA_PageFileChanged"
            Dim kvp_pa_provision_san_policy_changed  : kvp_pa_provision_san_policy_changed  = "provisioning_PA_SanPolicyChanged"
            Dim kvp_pa_provision_discover_wireserver : kvp_pa_provision_discover_wireserver = "provisioning_PA_DiscoverWireServer"

            Dim configurationPass                 : configurationPass                 = WScript.Arguments.Named("ConfigurationPass")
            Dim kvp_pa_start_time                 : kvp_pa_start_time                 = configurationPass & "_PA_StartTime"
            Dim kvp_pa_completion_time            : kvp_pa_completion_time            = configurationPass & "_PA_CompletionTime"
            Dim kvp_pa_version                    : kvp_pa_version                    = configurationPass & "_PA_Version"
            Dim kvp_pa_containerId                : kvp_pa_containerId                = configurationPass & "_PA_ContainerId"
            Dim kvp_pa_tick_count                 : kvp_pa_tick_count                 = configurationPass & "_PA_TickCount"
            Dim kvp_pa_offlinedFlags              : kvp_pa_offlinedFlags              = configurationPass & "_PA_OfflinedFlags"
            Dim kvp_pa_effectiveOfflinedFlags     : kvp_pa_effectiveOfflinedFlags     = configurationPass & "_PA_EffectiveOfflinedFlags"
            Dim kvp_pa_offlinedTag                : kvp_pa_offlinedTag                = configurationPass & "_PA_OfflinedTag"
            Dim kvp_pa_preprovision               : kvp_pa_preprovision               = configurationPass & "_PA_Preprovision"

            Dim g_isSpecializePass            : g_isSpecializePass            = False
            Dim g_isOobeSystemPass            : g_isOobeSystemPass            = False
            Dim g_isErrorHandlerPass          : g_isErrorHandlerPass          = False
            Dim g_isRoleReadyPass             : g_isRoleReadyPass             = False
            Dim g_isReprovisionPass           : g_isReprovisionPass           = False
            ' While this is not a provisioning agent pass itself
            ' preprovision impacts the behavior of the specialize and oobeSystem passes
            Dim g_isPreprovisionPass          : g_isPreprovisionPass          = False

            Select Case configurationPass
                Case "specialize"             : g_isSpecializePass            = True
                Case "oobeSystem"             : g_isOobeSystemPass            = True
                Case "errorHandler"           : g_isErrorHandlerPass          = True
                Case "reprovision"            : g_isReprovisionPass           = True
                Case "roleReady"              : g_isRoleReadyPass             = True
            End Select

            Set g_OfflineFlags = New OfflineFlags

            WScript.Echo "Microsoft(R) Azure(TM) Provisioning Agent"
            WScript.Echo "Copyright (c) Microsoft Corporation. All rights reserved."
            WScript.Echo ""

            Set g_Trace = GetScriptObject(WScript, "Tracing.wsf", "TraceSource")
            g_Trace.Name = "Unattend"

            Set g_objGuestInterface = GetScriptObject(WScript, "GuestInterface.wsf", "GuestInterface")
            Set g_objGuestInterface.WScript = WScript

            Set g_objOS = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
            Set g_objOS.WScript = WScript

            Set oTraceEvent = g_Trace.CreateEvent("INFO")
            With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("UnattendStart"))
                With .appendChild(oTraceEvent.ownerDocument.createElement("Parameters"))
                    .setAttribute "ConfigurationPass", configurationPass
                End With
            End With
            g_Trace.TraceEvent oTraceEvent

            If configurationPass = "" Then
                WScript.Echo "Usage: Unattend.wsf "
                WScript.Echo "  [/ConfigurationPass:[specialize|oobeSystem|reprovision|errorHandler|roleReady|]]"

                WScript.Quit 1
            End If

            'Delete old registries
            If g_isSpecializePass = True Then
                DeleteKvpRegistry g_Trace
                DeleteRegistry g_Trace, AzureProvisioningPath, "", True
                DeleteRestartFlag
                DeleteShutdownFlag
            End If

            SetKvpRegistry kvp_pa_start_time, g_Trace.GetCurrentTime(), g_Trace

            ' Emit the WinPA version
            If g_isSpecializePass = True Or g_isErrorHandlerPass = True Then
                mediaIdentifier = GetMediaIdentifier()
                If Not IsNull(mediaIdentifier) And Len(mediaIdentifier) <> 0 Then
                    SetKvpRegistry kvp_pa_provision_media_identifier, mediaIdentifier, g_Trace
                End If

                winPAVersion = GetWinPAVersion(WshShell, FSO)
                SetKvpRegistry kvp_pa_version, winPAVersion, g_Trace
            End If

            ' Emit the ContainerId
            If g_isOobeSystemPass = True Or g_isReprovisionPass = True Or g_isErrorHandlerPass = True Then
                containerId = GetRegistryValue(g_Trace, GuestParametersPath, "VirtualMachineName", "REG_SZ", False)
                SetKvpRegistry kvp_pa_containerId, containerId, g_Trace
            End If


            ' OVF will not exist during RoleReady pass
            ' we cannot initialize the environment successfully without the OVF
            If g_isRoleReadyPass <> True Then
                Call InitializeEnvironment

                If g_isReprovisionPass <> True Then
                    g_isPreprovisionPass = IsPreprovisionPass()
                    SetKvpRegistry kvp_pa_preprovision, CStr(g_isPreprovisionPass), g_Trace
                End If
            End If

            ' Emit offlined flags
            Set g_objOfflinedFeatures = GetOfflinedFeatures()
            SetKvpRegistry kvp_pa_offlinedFlags, g_objOfflinedFeatures.Flags, g_Trace
            SetKvpRegistry kvp_pa_offlinedTag, g_objOfflinedFeatures.Tag, g_Trace

            Set g_objEffectiveOfflinedFeatures = New OfflinedFeatures
            g_objEffectiveOfflinedFeatures.Flags = g_objOfflinedFeatures.Flags
            g_objEffectiveOfflinedFeatures.Tag = g_objOfflinedFeatures.Tag

            ' Set offline flags for preprovision
            If g_isPreprovisionPass = True Then
                g_objEffectiveOfflinedFeatures.Flags = g_objEffectiveOfflinedFeatures.Flags Or g_OfflineFlags.PreprovisionFlags
            End If

            ' Set offline flags for reprovision
            If g_isReprovisionPass = True Then
                g_objEffectiveOfflinedFeatures.Flags = g_objEffectiveOfflinedFeatures.Flags Or g_OfflineFlags.ReprovisionFlags
            End If
            SetKvpRegistry kvp_pa_effectiveOfflinedFlags, g_objEffectiveOfflinedFeatures.Flags, g_Trace

            g_exitCode = ExecuteConfigurationPass()

            ' Note that this call can result in a reboot occurring mid run
            ExecutePostConfigurationPass

            Set oTraceEvent = g_Trace.CreateEvent("INFO")
            With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("UnattendEnd"))
                 .setAttribute "ExitCode", g_exitCode
            End With
            g_Trace.TraceEvent oTraceEvent

            WScript.Echo "Done"
            WScript.Quit g_exitCode

            ' This function returns an exit code for the script to exit with.
            Function ExecuteConfigurationPass

                Dim success : success = True

                ExecuteConfigurationPass = UNATTEND_SYNCHRONOUS_COMMAND_RETURN_CODE_NO_REBOOT_REQUIRED

                WScript.Echo "Executing configuration pass '" & configurationPass & "'"

                g_objOS.Initialize
                If TraceError(g_Trace, "ExecuteConfigurationPass: g_objOS.Initialize failed") <> 0 Then
                    Exit Function
                End If

                If g_isSpecializePass = True Then
                    On Error Resume Next

                    Dim pageFileReturnValue, sanPolicyReturnValue, imcInjected
                    pageFileReturnValue = False
                    sanPolicyReturnValue = False

                    imcInjected = ImcWasInjected()

                    SetKvpRegistry kvp_pa_provision_state, "Provisioning", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: SetKvpRegistry ProvisionState failed"

                    pageFileReturnValue = InstrumentProcedure("ConfigurePageFile", "", True, False, "PA_specialize_1_ConfigurePageFile", g_Trace)
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigurePageFile failed"
                    SetKvpRegistry kvp_pa_provision_page_file_changed, pageFileReturnValue, g_Trace

                    InstrumentProcedureWithOfflinedFeatures "ConfigureBootStatusPolicy", "", False, False, "PA_specialize_2_ConfigureBootStatusPolicy", g_Trace, _
                                                            g_OfflineFlags.ConfigureBootStatusPolicy, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureBootStatusPolicy failed"

                    InstrumentProcedureWithOfflinedFeatures "ConfigureTimeSettings", "", False, False, "PA_specialize_3_ConfigureTimeSettings", g_Trace, _
                                                            g_OfflineFlags.ConfigureTimeSettings, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureTimeSettings failed"

                    sanPolicyReturnValue = InstrumentProcedureWithOfflinedFeatures("ConfigureSanPolicy", "", True, False, "PA_specialize_4_ConfigureSanPolicy", g_Trace, _
                                                                                    g_OfflineFlags.ConfigureSanPolicy, g_objEffectiveOfflinedFeatures)
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureSanPolicy failed"
                    SetKvpRegistry kvp_pa_provision_san_policy_changed, sanPolicyReturnValue, g_Trace

                    InstrumentProcedureWithOfflinedFeatures "ConfigureRdpKeepAlive", "", False, False, "PA_specialize_5_ConfigureRdpKeepAlive", g_Trace, _
                                                            g_OfflineFlags.ConfigureRdpKeepAlive, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureRdpKeepAlive failed"

                    InstrumentProcedureWithOfflinedFeatures "CopyCustomData", "", False, False, "PA_specialize_6_CopyCustomData", g_Trace, _
                                                            g_OfflineFlags.CopyCustomData, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: CopyCustomData failed"

                    InstrumentProcedure "CopyTempDriveWarningReadme", "", False, False, "PA_specialize_7_CopyTempDriveWarningReadme", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: CopyTempDriveWarningReadme failed"

                    InstrumentProcedure "EjectIso", "", False, False, "PA_specialize_8_EjectIso", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: EjectIso failed"

                    ' Optimization for single reboot at the most.
                    ' If IMC was injected and PA disagreed with the page file or SAN policy value set by IMC and
                    ' PA reset them, PA needs to tell setup that a reboot is needed by returning 1.
                    ' If IMC was not injected and PA disagrees on the page file and SAN policy value, we return
                    ' 0 (i.e. no reboot required) and rely on Windows Setup to reboot based on Windows Setup
                    ' setting the computer name - this is the existing behavior today.
                    If ((pageFileReturnValue = True Or sanPolicyReturnValue = True) And imcInjected = True) Then
                        ExecuteConfigurationPass = UNATTEND_SYNCHRONOUS_COMMAND_RETURN_CODE_REBOOT_REQUIRED
                    End If
                End If

                If g_isOobeSystemPass = True Then

                    On Error Resume Next

                    InstrumentProcedure "ConfigureAdministratorUsername", "", False, False, "PA_oobeSystem_0_ConfigureAdministratorUsername", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureAdministratorUsername failed"

                    InstrumentProcedure "InitializeGuest", "", False, False, "PA_oobeSystem_1_InitializeGuest", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: InitializeGuest failed"

                    InstrumentProcedureWithOfflinedFeatures "RunAzSecAgent", "", False, False, "PA_oobeSystem_2_RunAzSecAgent", g_Trace, _
                                                            g_OfflineFlags.RunAzSecAgent, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: RunAzSecAgent failed"

                    InstrumentProcedureWithOfflinedFeatures "ConfigureCertificates", "", False, False, "PA_oobeSystem_3_ConfigureCertificates", g_Trace, _
                                                            g_OfflineFlags.ConfigureCertificates, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureCertificates failed"

                    InstrumentProcedureWithOfflinedFeatures "ConfigureWinRm", "", False, False, "PA_oobeSystem_4_ConfigureWinRm", g_Trace, _
                                                            g_OfflineFlags.ConfigureWinRm, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureWinRm failed or did not run."

                    ' Continue with rest of the steps
                    InstrumentProcedureWithOfflinedFeatures "ConfigureBCD", "", False, False, "PA_oobeSystem_5_ConfigureBCD", g_Trace, _
                                                            g_OfflineFlags.ConfigureBCD, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureBCD failed"

                    InstrumentProcedure "ConfigureRecoveryEnabled", "", False, False, "PA_oobeSystem_6_ConfigureRecoveryEnabled", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureRecoveryEnabled failed"

                    InstrumentProcedureWithOfflinedFeatures "ConfigureTimeService", "", False, False, "PA_oobeSystem_7_ConfigureTimeService", g_Trace, _
                                                            g_OfflineFlags.ConfigureTimeService, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureTimeService failed"

                    InstrumentProcedure "ConfigureLicensing", "", False, False, "PA_oobeSystem_8_ConfigureLicensing", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureLicensing failed"

                    InstrumentProcedureWithOfflinedFeatures "UpdateRDPCertificateThumbprint", "", False, False, "PA_oobeSystem_9_UpdateRDPCertificateThumbprint", g_Trace, _
                                                            g_OfflineFlags.UpdateRDPCertificateThumbprint, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: UpdateRDPCertificateThumbprint failed"

                    InstrumentProcedureWithOfflinedFeatures "ConfigureAutomaticUpdates", "", False, False, "PA_oobeSystem_10_ConfigureAutomaticUpdates", g_Trace, _
                                                            g_OfflineFlags.ConfigureAutomaticUpdates, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureAutomaticUpdates failed"

                    InstrumentProcedureWithOfflinedFeatures "SetScreenAlwaysOn", "", False, False, "PA_oobeSystem_11_SetScreenAlwaysOn", g_Trace, _
                                                            g_OfflineFlags.SetScreenAlwaysOn, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: SetScreenAlwaysOn failed"

                    If g_objOfflinedFeatures.Flags <> 0 Then
                        InstrumentProcedure "DeleteOfflinedFlags", "", False, False, "PA_oobeSystem_12_DeleteOfflinedFlags", g_Trace
                        TraceError g_Trace, "ExecuteConfigurationPass: DeleteOfflinedFlags failed"
                    End If

                    If g_isPreprovisionPass = True Then
                        InstrumentProcedure "ConfigureReprovisioning", "", False, False, "PA_oobeSystem_13_ConfigureReprovisioning", g_Trace
                        success = success And (TraceError(g_Trace, "ExecuteConfigurationPass: ConfigureReprovisioning failed") = 0)
                    End if

                    SetCompletionTimeInfo kvp_pa_provision_tick_count, kvp_pa_provision_completion_time
                    TraceError g_Trace, "ExecuteConfigurationPass: SetCompletionTimeInfo failed"

                    If success = True Then
                        If g_isPreprovisionPass = True Then
                            InstrumentProcedure "ReportPreprovisioned", "", False, False, "PA_oobeSystem_14_ReportPreprovisioned", g_Trace
                            TraceError g_Trace, "ExecuteConfigurationPass: ReportPreprovisioned failed"
                        Else
                            InstrumentProcedure "ReportReady", "", False, False, "PA_oobeSystem_15_ReportReady", g_Trace
                            TraceError g_Trace, "ExecuteConfigurationPass: ReportReady failed"
                        End If
                    Else
                        Dim failDescription

                        If g_isPreprovisionPass Then
                            failDescription = "Preprovisioning failed."
                        Else
                            failDescription = "Provisioning failed."
                        End If

                        InstrumentProcedure "ReportNotReady", QuoteString("ProvisioningFailed") & ", " & QuoteString(failDescription), False, False, "PA_oobeSystem_18_ReportNotReady", g_Trace
                        TraceError g_Trace, "ExecuteConfigurationPass: ReportNotReady failed"

                        ExecuteConfigurationPass = ERROR_INSTALL_FAILURE
                    End If
                End If

                If g_isErrorHandlerPass = True Then

                    On Error Resume Next

                    InstrumentProcedure "InitializeGuest", "", False, False, "PA_errorHandler_0_InitializeGuest", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: InitializeGuest failed"

                    InstrumentProcedure "ReportNotReady", " ""ProvisioningFailed"", ""This installation of Windows is undeployable."" ", False, False, "PA_errorHandler_1_ReportNotReady", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: ReportNotReady failed"
                End If

                If g_isReprovisionPass = True Then
                    On Error Resume Next

                    SetKvpRegistry kvp_pa_provision_state, "Provisioning", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: SetKvpRegistry ProvisionState failed"

                    InstrumentProcedure "ConfigureAdministratorUser", "", False, False, "PA_reprovision_0_ConfigureAdministratorUser", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureAdministratorUser failed"

                    InstrumentProcedure "InitializeGuest", "", False, False, "PA_reprovision_1_InitializeGuest", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: InitializeGuest failed"

                    InstrumentProcedureWithOfflinedFeatures "CopyCustomData", "", False, False, "PA_reprovision_2_CopyCustomData", g_Trace, _
                                                            g_OfflineFlags.CopyCustomData, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: CopyCustomData failed"

                    InstrumentProcedureWithOfflinedFeatures "RunAzSecAgent", "", False, False, "PA_reprovision_3_RunAzSecAgent", g_Trace, _
                                                            g_OfflineFlags.RunAzSecAgent, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: RunAzSecAgent failed"

                    InstrumentProcedureWithOfflinedFeatures "ConfigureCertificates", "", False, False, "PA_reprovision_4_ConfigureCertificates", g_Trace, _
                                                            g_OfflineFlags.ConfigureCertificates, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureCertificates failed"

                    InstrumentProcedureWithOfflinedFeatures "ConfigureWinRm", "", False, False, "PA_reprovision_5_ConfigureWinRm", g_Trace, _
                                                            g_OfflineFlags.ConfigureWinRm, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureWinRm failed or did not run."

                    InstrumentProcedureWithOfflinedFeatures "UpdateRDPCertificateThumbprint", "", False, False, "PA_reprovision_6_UpdateRDPCertificateThumbprint", g_Trace, _
                                                            g_OfflineFlags.UpdateRDPCertificateThumbprint, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: UpdateRDPCertificateThumbprint failed"

                    InstrumentProcedureWithOfflinedFeatures "ConfigureAutomaticUpdates", "", False, False, "PA_reprovision_7_ConfigureAutomaticUpdates", g_Trace, _
                                                            g_OfflineFlags.ConfigureAutomaticUpdates, g_objEffectiveOfflinedFeatures
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureAutomaticUpdates failed"

                    InstrumentProcedure "ConfigureTimeZone", "", False, False, "PA_reprovision_8_ConfigureTimeZone", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: ConfigureTimeZone failed"

                    InstrumentProcedure "SetReprovisioningAgentKvps", "", False, False, "PA_reprovision_9_SetReprovisioningAgentKvps", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: SetReprovisioningAgentKvps failed"

                    InstrumentProcedure "DeleteReprovisioningTasks", "", False, False, "PA_reprovision_10_DeleteReprovisioningTasks", g_Trace
                    success = success And (TraceError(g_Trace, "ExecuteConfigurationPass: DeleteReprovisioningTasks failed") = 0)

                    InstrumentProcedure "EjectIso", "", False, False, "PA_reprovision_11_EjectIso", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: EjectIso failed"

                    SetCompletionTimeInfo kvp_pa_provision_tick_count, kvp_pa_provision_completion_time
                    TraceError g_Trace, "ExecuteConfigurationPass: SetCompletionTimeInfo failed"

                    If success = True Then
                        InstrumentProcedure "ReportReady", "", False, False, "PA_reprovision_12_ReportReady", g_Trace
                        TraceError g_Trace, "ExecuteConfigurationPass: ReportReady failed"
                    Else
                        InstrumentProcedure "ReportNotReady", QuoteString("ProvisioningFailed") & ", " & QuoteString("Reprovisioning pass failed."), False, False, "PA_oobeSystem_13_ReportNotReady", g_Trace
                        TraceError g_Trace, "ExecuteConfigurationPass: ReportNotReady failed"
                        ExecuteConfigurationPass = ERROR_INSTALL_FAILURE
                    End If
                End If

            End Function

            Sub ExecutePostConfigurationPass
                Dim restartRequired, guestAgentRestartRequired, shutdownRequired, guestAgentKvp, guestAgentConfigureOfflineMode, kvpPrefix

                kvpPrefix = "PA_" & configurationPass & "_"

                ' Offline mode configuration for guest agent
                '  can only occur when the VHD is offline or during
                '  oobeSystem pass for preprovision scenario
                guestAgentConfigureOfflineMode = False

                ' By default we don't have to shutdown for reprovision
                ' PreprovisionedOSDisk can change that
                shutdownRequired = IsPreprovisionedOSDisk()

                ' By default we don't have to restart for reprovision
                ' Guest Agent can change that
                restartRequired = False

                If g_isOobeSystemPass = True Then
                    guestAgentConfigureOfflineMode = g_isPreprovisionPass
                    ' Restart during preprovision in oobeSystem is required
                    '  in order to launch the reprovision agent
                    restartRequired = g_isPreprovisionPass
                End If

                If g_isReprovisionPass = True Then
                    InstrumentProcedure "DeleteReprovisioningFile", "", False, False, kvpPrefix & "94_DeleteReprovisioningFile", g_Trace
                    TraceError g_Trace, "ExecuteConfigurationPass: DeleteReprovisioningFile failed"
                End If

                If g_isOobeSystemPass = True Or g_isReprovisionPass = True Then
                    On Error Resume Next

                    guestAgentKvp = kvpPrefix & "95_ConfigureGuestAgentService"
                    guestAgentRestartRequired = InstrumentProcedureWithOfflinedFeatures("ConfigureGuestAgentService", _
                                                                                        QuoteString(guestAgentKvp & "_") & ", " & _
                                                                                        QuoteString(guestAgentConfigureOfflineMode), _
                                                                                        True, False, guestAgentKvp, g_Trace, _
                                                                                        g_OfflineFlags.ConfigureGuestAgentService, _
                                                                                        g_objEffectiveOfflinedFeatures)
                    TraceError g_Trace, "ExecutePostConfigurationPass: ConfigureGuestAgentService failed"

                    restartRequired = restartRequired Or guestAgentRestartRequired
                End If

                If g_isOobeSystemPass = True Then
                    InstrumentProcedure "LogSetupTraceEvents", "", False, False, kvpPrefix & "96_LogSetupTraceEvents", g_Trace
                    TraceError g_Trace, "ExecutePostConfigurationPass: LogSetupTraceEvents failed"
                End If

                SetCompletionTimeInfo kvp_pa_tick_count, kvp_pa_completion_time
                TraceError g_Trace, "ExecuteConfigurationPass: SetCompletionTimeInfo failed"

                If g_isOobeSystemPass = True Or g_isReprovisionPass = True Then
                    InstrumentProcedure "SendOnPluginProvisionEnd", "", False, False, kvpPrefix & "97_SendOnPluginProvisionEnd", g_Trace
                    TraceError g_Trace, "ExecutePostConfigurationPass: SendOnPluginProvisionEnd failed"
                End If

                If IsFinalPass() = True Then
                    InstrumentProcedure "SendProvisioningDiagnostics", "", False, False, kvpPrefix & "98_SendProvisioningDiagnostics", g_Trace 
                    TraceError g_Trace, "ExecutePostConfigurationPass: SendProvisioningDiagnostics failed"

                    SetKvpRegistry GUEST_FIRSTBOOT_COMPLETION_KVP_NAME, "", g_Trace

                    DeleteRegistry g_Trace, AzureProvisioningPath, "", True
                End If

                ' Only restart if exitcode is 0.
                ' Otherwise, something went wrong during provisioning
                ' and we want to retain our exit code when we're done.
                ' A restart would clear it.
                If restartRequired = True And shutdownRequired = False And g_exitCode = 0 Then
                    InstrumentProcedure "RestartMachine", "", False, False, kvpPrefix & "99_RestartMachine", g_Trace
                    TraceError g_Trace, "ExecutePostConfigurationPass: RestartMachine"
                End If

                ' Only restart if exitcode is 0.
                ' Otherwise, something went wrong during provisioning
                ' and we want to retain our exit code when we're done.
                ' A shutdown would clear it.
                If shutdownRequired = True And g_exitCode = 0 Then
                    InstrumentProcedure "ShutdownMachine", "", False, False, kvpPrefix & "100_ShutdownMachine", g_Trace
                    TraceError g_Trace, "ExecutePostConfigurationPass: ShutdownMachine"
                End If
            End Sub

            Function IsFinalPass
                If (g_isOobeSystemPass = True And g_isPreprovisionPass <> True) Or (g_isReprovisionPass = True) Then
                    IsFinalPass = True
                Else
                    IsFinalPass = False
                End If
            End Function

            Sub ConfigureBootStatusPolicy
                Set bootConfig = GetScriptObject(WScript, "BootConfig.wsf", "BootConfig")
                Set bootConfig.WScript = WScript
                bootConfig.Initialize

                bootConfig.ConfigureBootStatusPolicy
            End Sub

            Sub ConfigureAdministratorUsername
                On Error Resume Next
                Dim newUserName

                Set os = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
                Set os.WScript = WScript
                os.Initialize

                If m_Environment is Nothing Then
                    Exit Sub
                End If

                Set objOSDParams = m_Environment.GetOSDParameters()

                Set objUserName = objOSDParams.selectSingleNode("wa:AdminUsername")
                If Not (objUserName is Nothing) Then
                    newUserName = objUserName.text
                    os.RenameDefaultAdministratorAccount newUserName
                End If
            End Sub

            Sub ConfigureAdministratorUser
                On Error Resume Next

                Set os = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
                Set os.WScript = WScript
                os.Initialize

                If m_Environment is Nothing Then
                    Exit Sub
                End if

                os.ResetDefaultAdministratorUser m_Environment.SettingsFilePath
            End Sub

            Sub ConfigureTimeZone
                On Error Resume Next
                Dim newTimeZone

                Set os = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
                Set os.WScript = WScript
                os.Initialize

                If m_Environment is Nothing Then
                    Exit Sub
                End if

                Set objOSDParams = m_Environment.GetOSDParameters()
                Set objTimeZone = objOSDParams.selectSingleNode("wa:TimeZone")

                If Not objTimeZone is Nothing Then
                    newTimeZone = objTimeZone.text
                    If Not IsNull(newTimeZone) And Len(newTimeZone) <> 0 And newTimeZone <> "UTC" Then
                        os.ResetTimeZone newTimeZone
                    End If
                End if
            End Sub

            Sub ConfigureBCD
                On Error Resume Next
                Set bootConfig = GetScriptObject(WScript, "BootConfig.wsf", "BootConfig")
                Set bootConfig.WScript = WScript
                bootConfig.Initialize

                bootConfig.ConfigureBCD
            End Sub

            Sub ConfigureRecoveryEnabled
                On Error Resume Next
                Set bootConfig = GetScriptObject(WScript, "BootConfig.wsf", "BootConfig")
                Set bootConfig.WScript = WScript
                bootConfig.Initialize

                bootConfig.ConfigureRecoveryEnabledFlag
            End Sub

            ' This function returns True if reboot is required; otherwise returns False.
            Function ConfigurePageFile
                Dim pageFilePath, pageFileSize, pageFileParams, pageFileSet, pageFileSettings
                Dim driveName, index, useDefaultPath, useDefaultSize
                Dim rebootRequired, oRegExp, tempPageFile, usableDriveName, filename
                On Error Resume Next

                ConfigurePageFile = False
                useDefaultPath = False
                useDefaultSize = False
                rebootRequired = False

                ' First test the parameters provided.
                pageFileParams = GetPageFileParams()
                If IsNull(pageFileParams(0)) Then
                    pageFilePath = ""
                    useDefaultPath = True
                Else
                    pageFilePath = pageFileParams(0)
                End If

                ' Null values means that we use defaults
                If IsNull(pageFileParams(1)) Then
                    pageFileSize = ""
                    useDefaultSize = True
                Else
                    pageFileSize = pageFileParams(1)
                End If

                ' Log the configuration values
                Set oTraceEvent = g_Trace.CreateEvent("INFO")
                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("ConfigurePageFile"))
                    With .appendChild(oTraceEvent.ownerDocument.createElement("EnvironmentSettings"))
                        .setAttribute "Path", pageFilePath
                        .setAttribute "Size", pageFileSize
                    End With
                End With
                g_Trace.TraceEvent oTraceEvent

                Set os = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
                Set os.WScript = WScript
                os.Initialize

                ' Cache PageFile settings for diagnostics
                pageFileSettings = os.GetPageFileSettings(True)
                SetCacheValue g_Trace, "OriginalPageFileSettings", "REG_MULTI_SZ", pageFileSettings

                ' If IMC has already set the PageFile and it was invalid, a TempPageFile should be in use.
                ' Use the TempPageFile as an indicator that the PageFile path or size are invalid.
                tempPageFile = os.GetTempPageFileSettings(True)
                If Not IsNull(tempPageFile) And tempPageFile = 1 Then
                    rebootRequired = True
                    useDefaultPath = True
                    useDefaultSize = True
                End If

                ' Validate the PageFile size provided.
                Set oRegExp = New RegExp
                If useDefaultSize = False Then
                    oRegExp.Pattern = "^[0-9]+$"
                    If Not oRegExp.Test(pageFileSize) Then
                        Err.Raise vbObjectError + 9, "Unattend.wsf", "PageFile must be an unsigned long"
                        TraceError g_Trace, "Error configuring pagefile with size " & pageFileSize
                        useDefaultSize = True
                    End If
                End If

                ' Validate the filename
                If useDefaultPath = False Then
                    filename = FSO.GetFileName(pageFilePath)
                    If Not IsValidFileName(filename) Then
                        Err.Raise vbObjectError + 10, "Unattend.wsf", "PageFile contains invalid file name characters"
                        TraceError g_Trace, "ConfigurePageFile: Error configuring PageFile at " & pageFilePath
                        useDefaultPath = True
                        useDefaultSize = True
                    End If
                End If

                ' Validate the file extension
                If useDefaultPath = False Then
                    If LCase(FSO.GetExtensionName(filename)) <> "sys" Then
                        Err.Raise vbObjectError + 11, "Unattend.wsf", "PageFiles must use .sys extensions"
                        TraceError g_Trace, "ConfigurePageFile: Error configuring PageFile at " & pageFilePath
                        useDefaultPath = True
                        useDefaultSize = True
                    End If
                End If

                ' Validate the drive letter
                If useDefaultPath = False Then
                    driveName = FSO.GetDriveName(pageFilePath)
                    usableDriveName = driveName
                    ' ?: is a valid drive for PageFile paths.
                    ' However, GetDriveName doesn't recognize it.
                    If Len(usableDriveName) = 0 Then
                        ' Check if our drive is ?:
                        index = InStr(pageFilePath, "?:\")
                        If index > 0 Then
                            driveName = "?:"
                            usableDriveName = FSO.GetDriveName(WshShell.ExpandEnvironmentStrings("%SYSTEMDRIVE%"))
                        Else
                            ' Drive is not ?: and is not recognized, use the default values.
                            Err.Raise vbObjectError + 11, "Unattend.wsf", "Unable to find drive in PageFile path"
                            TraceError g_Trace, "ConfigurePageFile: Error configuring PageFile at " & pageFilePath
                            useDefaultPath = True
                            useDefaultSize = True
                        End If
                    ' Drive is the DVD drive which exists at the moment, but is not a valid location.
                    ElseIf LCase(usableDriveName) = LCase(GetConfigSetDrive()) Then
                        Err.Raise vbObjectError + 12, "Unattend.wsf", "PageFile cannot be placed in DVD drive"
                        TraceError g_Trace, "ConfigurePageFile: Error configuring PageFile at " & pageFilePath
                        useDefaultPath = True
                        useDefaultSize = True
                    End If
                End If

                ' Drive is recognized but does not exist, use the default values.
                If useDefaultPath = False And Not FSO.DriveExists(usableDriveName) Then
                    Err.Raise vbObjectError + 13, "Unattend.wsf", "Unable to identify drive of PageFile path"
                    TraceError g_Trace, "ConfigurePageFile: Error configuring PageFile at " & pageFilePath
                    useDefaultPath = True
                    useDefaultSize = True
                End If

                ' Check that the pagefile is being placed in root directory
                If useDefaultPath = False And LCase(driveName & "\" & filename) <> LCase(pageFilePath) Then
                    Err.Raise vbObjectError + 14, "Unattend.wsf", "PageFile is only supported in root directory"
                    TraceError g_Trace, "ConfigurePageFile: Error configuring PageFile at " & pageFilePath
                    useDefaultPath = True
                    useDefaultSize = True
                End If

                ' If any of the above validations failed,
                ' use default values for the PageFile path.
                If useDefaultPath = True Then
                    pageFilePath = GetDefaultPageFilePath()
                End If

                ' If any of the above validations failed,
                ' use default values for the PageFile size.
                If useDefaultSize = True Then
                    pageFileSize = 0
                End If

                ' Setting minimum and maximum page file size to same value'
                pageFileSet = os.SetPageFile(pageFilePath, pageFileSize, pageFileSize)
                rebootRequired = rebootRequired Or pageFileSet

                Set oTraceEvent = g_Trace.CreateEvent("INFO")
                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("ConfigurePageFile"))
                    With .appendChild(oTraceEvent.ownerDocument.createElement("Settings"))
                        .setAttribute "Path", pageFilePath
                        .setAttribute "Size", pageFileSize
                        .setAttribute "RebootRequired", BoolToString(rebootRequired)
                    End With
                End With
                g_Trace.TraceEvent oTraceEvent

                ConfigurePageFile = rebootRequired
            End Function

            Sub ConfigureLicensing
                ' Check if there is a KMS Server configured in the provisioning agent.
                Dim objOSDParams, objKmsElement, keyManagementServiceMachine, useAVMA

                If m_Environment is Nothing Then
                    Exit Sub
                End If

                Set objPlatformParams = m_Environment.GetPlatformProvisioningParameters()

                Set objKmsElement = objPlatformParams.selectSingleNode("wa:KmsServerHostname")
                If Not (objKmsElement is Nothing) Then keyManagementServiceMachine = objKmsElement.text

                Set objUseAVMA = objPlatformParams.selectSingleNode("wa:UseAVMA")
                If Not (objUseAVMA is Nothing) Then
                    If LCase(objUseAVMA.text) = "true" Then
                       useAVMA = True
                    End If
                End If

                Set objLicensing = GetScriptObject(WScript, "Licensing.wsf", "SoftwareLicensing")
                Set objLicensing.WScript = WScript
                objLicensing.Initialize

                objLicensing.ConfigureLicensing keyManagementServiceMachine, useAVMA
            End Sub

            Sub UpdateRDPCertificateThumbprint
                Dim sThumbprint
                On Error Resume Next

                sThumbprint = g_objOS.GetRdpCertificateThumbprint()

                Dim properties : Set properties = CreateObject("Scripting.Dictionary")
                properties.Add "CertificateThumbprint", sThumbprint

                If TraceError(g_Trace, "UpdateRDPCertificateThumbprint: GetRdpCertificateThumbprint failed") = 0 Then
                    g_objGuestInterface.PutProvisioningStatus Null, Null, Null, properties
                    TraceError g_Trace, "UpdateRDPCertificateThumbprint: PutProvisioningStatus failed"
                End If

                ' KVP Diagnostics
                Dim kvp_cert_acquisition, kvpMessage

                kvp_cert_acquisition = WScript.Arguments.Named("ConfigurationPass") & "_PA_CertAquisition"
                kvpMessage = "[" & g_Trace.GetCurrentTime() & "]" & ": [GetRdpCertificateThumbprint] "

                If sThumbprint = "" Then
                    kvpMessage = kvpMessage & "Failed to acquire cert thumbprint"
                Else
                    kvpMessage = kvpMessage & "Cert thumprint is: " & sThumbprint
                End If

                SetKvpRegistry kvp_cert_acquisition, kvpMessage, g_Trace
            End Sub

            Sub ConfigureCertificates
                Dim objCertMgr
                On Error Resume Next

                Set objCertMgr = GetScriptObject(WScript, "Certificates.wsf", "CertificateManager")
                Set objCertMgr.WScript = WScript

                objCertMgr.Initialize g_objGuestInterface
                objCertMgr.InstallCertificates()
            End Sub

            Sub ConfigureTimeSettings
                g_objOS.ConfigureTimeSettings
            End Sub

            Sub ConfigureTimeService
                g_objOS.ConfigureTimeService
            End Sub

            ' Adds AzureRPA to the boot execute list and creates the reprovision task
            Sub ConfigureReprovisioning
                Dim exitCode
                Dim taskName : taskName = "\Microsoft\AzureIaasReprovisioningTask"
                Dim taskFile : taskFile = "%SystemRoot%\OEM\AzureIaasReprovisioningTask.xml"

                Dim systemRoot : systemRoot = WshShell.ExpandEnvironmentStrings("%SystemRoot%")
                Dim fileName   : fileName = systemRoot & "\System32\" & ReprovisioningAgentName & ".exe"

                If FSO.FileExists(fileName) Then
                    FSO.DeleteFile fileName, True
                End If
                FSO.MoveFile systemRoot & "\OEM\" & ReprovisioningAgentName & ".exe", fileName

                exitCode = g_objOS.CreateScheduledTask(taskName, taskFile)
                If exitCode <> 0 Then
                    Err.Raise vbObjectError + 5, "Unattend.wsf", "Failed to schedule reprovision task (" & exitCode & ")"
                    Exit Sub
                End If

                Dim registryPath, registryKeyName, registryValue

                registryPath = "HKLM\System\CurrentControlSet\Control\Session Manager"
                registryKeyName = "SetupExecute"
                registryValue = GetRegistryValue(g_Trace, registryPath, registryKeyName, "REG_MULTI_SZ", True)

                If IsEmpty(registryValue) <> True And IsNull(registryValue) <> True Then
                    If UBound(Filter(registryValue, ReprovisioningAgentName, True)) = -1 Then
                        Dim arrLen : arrLen = UBound(registryValue) + 1
                        ReDim Preserve registryValue(arrLen)
                        registryValue(arrLen) = ReprovisioningAgentName
                    End If
                Else
                    registryValue = Array(ReprovisioningAgentName)
                End If

                    SetRegistryValue g_Trace, registryPath, registryKeyName, "REG_MULTI_SZ", registryValue, False
            End Sub

            ' Removes AzureRPA from the boot execute list and remove the reprovisioning task
            Sub DeleteReprovisioningTasks
                Dim exitCode
                Dim errMsg : errMsg = ""
                Dim registryPath : registryPath = "HKLM\System\CurrentControlSet\Control\Session Manager"
                Dim registryKeyName : registryKeyName = "SetupExecute"
                Dim registryValue : registryValue = GetRegistryValue(g_Trace, registryPath, registryKeyName, "REG_MULTI_SZ", True)

                ' Clear out registryValue for reconstruction
                registryValue = Filter(registryValue, ReprovisioningAgentName, False)

                ' Continue on failure until the end in order to ensure that the boot tasks are removed
                SetRegistryValue g_Trace, registryPath, registryKeyName, "REG_MULTI_SZ", registryValue, False
                If Err.Number <> 0 Then
                    errMsg = "Failed to remove " & ReprovisioningAgentName & " from " & registryKeyName & " registry key (" & Err.Number & ")"
                End If

                exitCode = g_objOS.DeleteScheduledTask("\Microsoft\AzureIaasReprovisioningTask")
                If exitCode <> 0 Then
                    errMsg = errMsg & vbCrLf & "Failed to delete scheduled reprovision task (" & exitCode & ")"
                End If

                If Len(errMsg) > 0 Then
                    Err.Raise vbObjectError + 7, "Unattend.wsf", errMsg
                End If

            End Sub

            Sub DeleteReprovisioningFile
                On Error Resume Next

                Dim systemRoot : systemRoot = WshShell.ExpandEnvironmentStrings("%SystemRoot%")
                Dim fileName   : fileName = systemRoot & "\System32\" & ReprovisioningAgentName & ".exe"
                Dim fileExists : fileExists  = FSO.FileExists(fileName)
                Dim fileDeleted : fileDeleted = False

                Set oTraceEvent = g_Trace.CreateEvent("INFO")

                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("DeleteReprovisioningFile"))
                    If fileExists = True Then
                        FSO.DeleteFile fileName, True
                        If TraceError(g_Trace, "DeleteReprovisioningFile: Failed to delete reprovisioning file") = 0 Then
                            fileDeleted = True
                        End If
                    End If
                
                    .setAttribute "ReprovisioningFilePresent", BoolToString(fileExists)
                    .setAttribute "ReprovisioningFileDeleted", BoolToString(fileDeleted)
                End With

                g_Trace.TraceEvent oTraceEvent

            End Sub

            Sub ConfigureAutomaticUpdates
                Dim objOSDParams, objAUElement, os

                If m_Environment is Nothing Then
                    Exit Sub
                End If

                Set objOSDParams = m_Environment.GetOSDParameters()
                Set objAUElement = objOSDParams.selectSingleNode("wa:EnableAutomaticUpdates")

                If Not (objAUElement is Nothing) Then
                    Set os = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
                    Set os.WScript = WScript
                    os.Initialize

                    If LCase(objAUElement.text) = "true" Then
                        os.ConfigureAutomaticUpdates True
                    ElseIf LCase(objAUElement.text) = "false" Then
                        os.ConfigureAutomaticUpdates False
                    End If
                End If
            End Sub

            Function ConfigureGuestAgentService(kvpPrefix, offlineMode)
                On Error Resume Next
                Dim objOSDParams, objGAElement, restartRequired
                restartRequired = False
                ConfigureGuestAgentService = False
                If m_Environment is Nothing Then
                    Exit Function
                End If

                Set objOSDParams = m_Environment.GetPlatformProvisioningParameters()
                Set objGAElement = objOSDParams.selectSingleNode("wa:ProvisionGuestAgent")

                If Not (objGAElement is Nothing) Then
                    If LCase(objGAElement.text) = "true" Then
                        Set objOSDParams = m_Environment.GetPlatformProvisioningParameters()
                        Set objGAZipName = objOSDParams.selectSingleNode("wa:GuestAgentPackageName")
                        If Not (objGAZipName is Nothing) Then
                            Set ga = GetScriptObject(WScript, "GuestAgent.wsf", "GuestAgent")
                            Set ga.WScript = WScript
                            ga.Initialize objGAZipName.text
                            restartRequired = ga.ConfigureGuestAgent(kvpPrefix, CBool(offlineMode))
                            Set oTraceEvent = g_Trace.CreateEvent("INFO")
                            With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("ConfigureGuestAgentService"))
                                .setAttribute "ConfigureGuestAgentReturnValue", restartRequired
                            End With
                            g_Trace.TraceEvent oTraceEvent
                            ConfigureGuestAgentService = restartRequired
                        Else
                            Set oTraceEvent = g_Trace.CreateEvent("ERROR")
                            With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("ConfigureGuestAgentService"))
                                .setAttribute "GuestAgentPackageNameFound", CStr(False)
                            End With
                            g_Trace.TraceEvent oTraceEvent
                        End If
                    Else
                        UninstallGuestAgent kvpPrefix
                    End If
                Else
                    UninstallGuestAgent kvpPrefix
                End If
            End Function

            Function ConfigureGuestAgentServiceOfflined(kvpPrefix, offlineMode)
                On Error Resume Next
                Dim objOSDParams, objGAElement, restartRequired
                restartRequired = False
                ConfigureGuestAgentServiceOfflined = False
                If m_Environment is Nothing Then
                    Exit Function
                End If

                Set objOSDParams = m_Environment.GetPlatformProvisioningParameters()
                Set objGAElement = objOSDParams.selectSingleNode("wa:ProvisionGuestAgent")

                If Not (objGAElement is Nothing) Then
                    If LCase(objGAElement.text) = "true" Then
                        Set ga = GetScriptObject(WScript, "GuestAgent.wsf", "GuestAgent")
                        Set ga.WScript = WScript
                        ga.Initialize ""
                        restartRequired = ga.ConfigureGuestAgentOfflined(kvpPrefix, CBool(offlineMode))
                        Set oTraceEvent = g_Trace.CreateEvent("INFO")
                        With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("ConfigureGuestAgentServiceOfflined"))
                            .setAttribute "ConfigureGuestAgentOfflinedReturnValue", restartRequired
                        End With
                        g_Trace.TraceEvent oTraceEvent
                        ConfigureGuestAgentServiceOfflined = restartRequired
                    Else
                        UninstallGuestAgent kvpPrefix
                    End If
                Else
                    UninstallGuestAgent kvpPrefix
                End If
            End Function

            Sub UninstallGuestAgent(kvpPrefix)
                Set ga = GetScriptObject(WScript, "GuestAgent.wsf", "GuestAgent")
                Set ga.WScript = WScript
                ga.Initialize ""
                ga.UninstallGuestAgent "ServiceOnly", kvpPrefix
            End Sub

            Sub RestartMachine
                On Error Resume Next

                Dim file

                Set oTraceEvent = g_Trace.CreateEvent("INFO")
                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("RestartMachine"))
                    .setAttribute "RestartingMachine", "True"
                End With
                g_Trace.TraceEvent oTraceEvent
                Set file = FSO.CreateTextFile(GetRestartTagFilePath(), True)
                file.Close
            End Sub

            Sub DeleteRestartFlag
                On Error Resume Next

                Dim filePath    : filePath    = GetRestartTagFilePath()
                Dim fileExists  : fileExists  = FSO.FileExists(filePath)
                Dim fileDeleted : fileDeleted = False

                Set oTraceEvent = g_Trace.CreateEvent("INFO")

                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("DeleteRestartFlag"))
                    If fileExists = True Then
                        FSO.DeleteFile(filePath)
                        If TraceError(g_Trace, "DeleteRestartFlag: Failed to delete restart tag file") = 0 Then
                            fileDeleted = True
                        End If
                    End If
                
                    .setAttribute "RestartTagFilePresent", fileExists
                    .setAttribute "RestartTagFileDeleted", fileDeleted
                End With

                g_Trace.TraceEvent oTraceEvent
            End Sub

            Function GetRestartTagFilePath()
                GetRestartTagFilePath = FSO.BuildPath(FSO.GetSpecialFolder(0), "OEM\RestartMachine.tag")
            End Function

            Sub ShutdownMachine
                On Error Resume Next

                Dim file

                Set oTraceEvent = g_Trace.CreateEvent("INFO")
                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("ShutdownMachine"))
                    .setAttribute "ShutdownMachine", "True"
                End With
                g_Trace.TraceEvent oTraceEvent
                Set file = FSO.CreateTextFile(GetShutdownTagFilePath(), True)
                file.Close
            End Sub

            Sub DeleteShutdownFlag
                On Error Resume Next

                Dim filePath    : filePath    = GetShutdownTagFilePath()
                Dim fileExists  : fileExists  = FSO.FileExists(filePath)
                Dim fileDeleted : fileDeleted = False

                Set oTraceEvent = g_Trace.CreateEvent("INFO")

                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("DeleteShutdownFlag"))
                    If fileExists = True Then
                        FSO.DeleteFile(filePath)
                        If TraceError(g_Trace, "DeleteShutdownFlag: Failed to delete shutdown tag file") = 0 Then
                            fileDeleted = True
                        End If
                    End If
                
                    .setAttribute "ShutdownTagFilePresent", fileExists
                    .setAttribute "ShutdownTagFileDeleted", fileDeleted
                End With

                g_Trace.TraceEvent oTraceEvent
            End Sub

            Function GetShutdownTagFilePath()
                GetShutdownTagFilePath = FSO.BuildPath(FSO.GetSpecialFolder(0), "OEM\ShutdownMachine.tag")
            End Function

            ' This function returns True if reboot is required; otherwise returns False.
            Function ConfigureSanPolicy
                ConfigureSanPolicy = g_objOS.ConfigureSanPolicy
            End Function

            Function ConfigureSanPolicyOfflined
                ConfigureSanPolicyOfflined = g_objOS.ConfigureSanPolicyOfflined
            End Function

            Sub ConfigureRdpKeepAlive
                g_objOS.ConfigureRdpKeepAlive True, 1
            End Sub

            Sub CopyCustomData
                Dim configSetDrive, sourceFile, targetFileName, localFolder
                Dim objOSDParams, objCustomData
                On Error Resume Next

                configSetDrive = GetConfigSetDrive()
                If IsNull(configSetDrive) Then
                    Set oTraceEvent = g_Trace.CreateEvent("ERROR")
                    With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("CopyCustomData"))
                        .Text = "Could not find E6DA6616-8EC4-48E0-BE93-58CE6ACE3CFB.tag in any of the drives"
                    End With
                    g_Trace.TraceEvent oTraceEvent
                    Exit Sub
                End If
                configSetDrive = configSetDrive & "\"
                sourceFile = FSO.BuildPath(configSetDrive, "CustomData.bin")
                'verify custom file exists
                If (Not FSO.FileExists(sourceFile)) Then
                    ' verify whether the CustomData field exists in the ovf_env file
                    ' if it exists, the CustomData.bin should exist too
                    Set objOSDParams = m_Environment.GetOSDParameters()
                    Set objCustomData = objOSDParams.selectSingleNode("wa:CustomData")
                    If Not (objCustomData is Nothing) Then
                        ' the error message will be logged after the sub exit
                        Err.Raise vbObjectError + 2, "Unattend.wsf", "CustomData present in configuration set but " + sourceFile + " file not found"
                    End If
                    Exit Sub
                End If
                ' try creating local folder
                localFolder = WshShell.ExpandEnvironmentStrings("%SYSTEMDRIVE%") + "\AzureData"
                If (Not FSO.FolderExists(localFolder)) Then
                    FSO.CreateFolder(localFolder)
                    If (Err.number <> 0) Then
                        TraceError g_Trace, "CopyCustomData: Error creating folder " + localFolder
                        Exit Sub
                    End If
                End If
                'set proper folder ACLs: S-1-5-18 is the Sid for NT AUTHORITY\SYSTEM and S-1-5-32-544 is the Sid for BUILTIN\Administrators
                ExecuteAndTraceWithResults "%SystemRoot%\System32\icacls "+ localFolder +  " /inheritance:r /grant:r *S-1-5-18:(OI)(CI)F *S-1-5-32-544:(OI)(CI)F", g_trace
                'delete existing file if any
                targetFileName = FSO.BuildPath(localFolder, "\CustomData.bin")
                If FSO.FileExists(targetFileName) Then
                    'file already exists: take ownership, delete existing file if any. We need to take ownership because the file was created with another owner
                    'and even though we have full privileges, the system would not delete the file
                    ExecuteAndTraceWithResults "%SystemRoot%\System32\takeown /F "+ targetFileName, g_trace
                    FSO.DeleteFile targetFileName, true
                    If (Err.number <> 0) Then
                        TraceError g_Trace, "CopyCustomData: Error deleting existing file " + targetFileName
                        Exit Sub
                    End If
                End If
                'now copy the file
                FSO.CopyFile sourceFile, targetFileName
                'this displays the message if Err.number is not 0, and also clears the error
                TraceError g_Trace, "CopyCustomData: Error copying file"
            End Sub

            Sub EjectIso
                On Error Resume Next

                Dim attempt : attempt = 1
                Dim oResults
                Const retryDelayMS = 1000
                Const maxAttempt = 3

                Do While attempt <= maxAttempt
                    Set oResults = ExecuteAndTraceWithResults ("%SystemRoot%\OEM\WaGuest.exe /ejectiso", g_Trace)
                    If oResults.ExitCode = 0 Then
                        Exit Sub
                    End If

                    SetKvpRegistry "provisioning_PA_EjectIsoFailures", attempt, g_Trace

                    If attempt < maxAttempt Then
                        WScript.Sleep retryDelayMS
                    End If

                    attempt = attempt + 1
                Loop

                Err.Raise vbObjectError + 15, "Unattend.wsf", "Failed to eject ISO"
            End Sub

            Function GetConfigSetDrive
                Dim oResults
                Dim configDriveValue
                Const key = "ConfigurationDrive"

                configDriveValue = GetRegistryValue(g_Trace, AzureProvisioningPath, key, "REG_SZ", True)

                If IsNull(configDriveValue) Or Len(configDriveValue) = 0 Then
                    Set oResults = ExecuteAndTraceWithResults("%SystemRoot%\OEM\WaGuest.exe /cdrom", g_Trace)
                    If oResults.ExitCode = 0 Then
                        configDriveValue = Trim(Replace(oResults.StdOut, vbCrLf, ""))
                        SetRegistryValue g_Trace, _
                            AzureProvisioningPath, _
                            key, _
                            "REG_SZ", _
                            configDriveValue, False
                    Else
                        Err.Raise vbObjectError + 5, "Unattend.wsf", "Unable to locate a CD-ROM"
                    End If
                End If

                GetConfigSetDrive = configDriveValue & ":"
            End Function

            Sub CopyTempDriveWarningReadme
                Dim resourceDrive, configSetDrive, sourcePath, warningReadmeFileName, sourceFile, destFile
                On Error Resume Next

                warningReadmeFileName = "DATALOSS_WARNING_README.txt"

                'Identify the drive containing the mounted ISO and its enclosed PA bits
                configSetDrive = GetConfigSetDrive()
                TraceError g_Trace, "CopyTempDriveWarningReadme: GetConfigSetDrive failed"
                If IsNull(configSetDrive) Or IsEmpty(configSetDrive) Then
                    Set oTraceEvent = g_Trace.CreateEvent("ERROR")
                    With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("CopyTempDriveWarningReadme"))
                        .Text = "Could not find the drive with the PA bits and provisioning configurationset content"
                    End With
                    g_Trace.TraceEvent oTraceEvent
                    Exit Sub
                End If
                configSetDrive = configSetDrive & "\"
                sourcePath = configSetDrive & "$$\OEM\"

                'Verify the warning README file exists in the source location w/ the PA bits
                sourceFile = FSO.BuildPath(sourcePath, warningReadmeFileName)
                If (Not FSO.FileExists(sourceFile)) Then
                    Err.Raise vbObjectError + 2, "Unattend.wsf", "CopyTempDriveWarningReadme: Unable to find source file: " + sourceFile + ". Exiting subroutine..."
                    Exit Sub
                End If
                Set oTraceEvent = g_Trace.CreateEvent("INFO")
                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("CopyTempDriveWarningReadme"))
                    .Text = "configSetDrive: " & configSetDrive & ", sourcePath: " & sourcePath & ", sourceFile: " & sourceFile
                End With
                g_Trace.TraceEvent oTraceEvent

                'Identify the resource drive for the instance (typically D:)
                resourceDrive = GetResourceDrive(g_Trace)
                TraceError g_Trace, "CopyTempDriveWarningReadme: GetResourceDrive failed"
                If IsNull(resourceDrive) Or IsEmpty(resourceDrive) Then
                    Set oTraceEvent = g_Trace.CreateEvent("ERROR")
                    With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("CopyTempDriveWarningReadme"))
                        .Text = "Could not find the resource drive. Exiting subroutine..."
                    End With
                    g_Trace.TraceEvent oTraceEvent
                    Exit Sub
                End If
                resourceDrive = resourceDrive & "\"
                Set oTraceEvent = g_Trace.CreateEvent("INFO")
                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("CopyTempDriveWarningReadme"))
                    .Text = "resourceDrive: " & resourceDrive & ", destFile: " & destFile
                End With
                g_Trace.TraceEvent oTraceEvent

                destFile = FSO.BuildPath(resourceDrive, warningReadmeFileName)

                'Copy the README file to the resource drive
                FSO.CopyFile sourceFile, destFile
                'this displays the message if Err.number is not 0, and also clears the error
                TraceError g_Trace, "CopyTempDriveWarningReadme: Error copying file: " & readmeFileName
            End Sub

            Sub ConfigureWinRm
                const winRmHttpPort = 5985
                const winRmHttpsPort = 5986
                const NET_FW_IP_PROTOCOL_TCP = 6
                On Error Resume Next

                Dim oResults
                Dim objWinRmElement, objOSDParams, objListeners, objListener, objListenerType

                If m_Environment is Nothing Then
                    Err.Raise vbObjectError + 2, "Unattend.wsf", "ovf-env.xml was not loaded."
                    Exit Sub
                End If

                Set objOSDParams = m_Environment.GetOSDParameters()

                Set objWinRmElement = objOSDParams.selectSingleNode("wa:WinRM")
                If Not (objWinRmElement is Nothing) Then
                    Set os = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
                    Set os.WScript = WScript
                    os.Initialize

                    'Iterate through all the listeners and create listener endpoints as necessary.
                    Set objListeners = objWinRmElement.selectSingleNode("Listeners")
                    Set objListener = objListeners.selectNodes("Listener")

                    If objListener.Length > 0 Then
                        os.RemoveWinRmListeners
                    End If

                    For i = 0 to objListener.Length - 1
                        Set objListenerType = objListener(i).selectSingleNode("Protocol")

                        If LCase(objListenerType.Text) = "http" Then
                            os.ConfigureWinRmHttpListener winRmHttpPort
                            TraceError g_Trace, "ConfigureWinRm: Could not configure HTTP listener"

                            os.AddFirewallRule "Windows Remote Management (HTTP-In) (Azure)", "System", NET_FW_IP_PROTOCOL_TCP, winRmHttpPort, "*", True
                            TraceError g_Trace, "ConfigureWinRm: Could not configure HTTP listener firewall rule"
                        ElseIf LCase(objListenerType.Text) = "https" Then
                            Set objCertificateThumbprint = objListener(i).selectSingleNode("CertificateThumbprint")
                            os.ConfigureWinRmHttpsListener winRmHttpsPort, objCertificateThumbprint.Text
                            TraceError g_Trace, "ConfigureWinRm: Could not configure HTTPS listener"

                            os.AddFirewallRule "Windows Remote Management (HTTPS-In) (Azure)", "System", NET_FW_IP_PROTOCOL_TCP, winRmHttpsPort, "*", True
                            TraceError g_Trace, "ConfigureWinRm: Could not configure HTTPS listener firewall rule"
                        End If
                    Next

                    os.ChangeWinRmServiceStartModeAuto
                    TraceError g_Trace, "ConfigureWinRm: ChangeWinRmServiceStartModeAuto failed"
                    os.RestartWinRmService(WScript)
                Else
                    Set oTraceEvent = g_Trace.CreateEvent("INFO")
                    With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("ConfigureWinRm"))
                        .Text = "WinRM node was not found in configuration"
                    End With
                    g_Trace.TraceEvent oTraceEvent
                End If
            End Sub

            Sub SetScreenAlwaysOn
                Dim oResults

                Set oResults = ExecuteAndTraceWithResults("powercfg /setacvalueindex SCHEME_CURRENT SUB_VIDEO VIDEOIDLE 0", g_Trace)

                If oResults.ExitCode <> 0 Then
                    Err.Raise vbObjectError + 3, "Unattend.wsf", "Failed to configure screen to be always-on"
                End If
            End Sub

            Sub RunAzSecAgent
                Dim oResults
                Dim logFilePath
                Dim waSecAgentExePath, waSecAgentExeCmdString

                logFilePath = FSO.BuildPath(FSO.GetSpecialFolder(0), "Panther")

                waSecAgentExePath = FSO.GetSpecialFolder(0)
                waSecAgentExePath = FSO.BuildPath(waSecAgentExePath, "OEM\")
                waSecAgentExePath = FSO.BuildPath(waSecAgentExePath, "WaSecAgent\")
                waSecAgentExeCmdString = waSecAgentExePath & "WaSecAgentProv.exe -installCACerts " & logFilePath & " " & g_objGuestInterface.WireServerAddress

                Set oResults = ExecuteAndTraceWithResults(waSecAgentExeCmdString , g_Trace)

                If oResults.ExitCode <> 0 Then
                    Err.Raise vbObjectError + 4, "Unattend.wsf", "Failed to run WaSecAgentProv.exe"
                End If
            End Sub

            Sub InitializeEnvironment
                Dim objEnv, configSetDrive
                Set objEnv = GetScriptObject(WScript, "Environment.wsf", "Environment")
                Set objEnv.WScript = WScript
                Set m_Environment = Nothing

                On Error Resume Next
                ' Log OS version
                If g_isOobeSystemPass = True Then
                    Dim os : Set os = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
                    Set os.WScript = WScript
                    os.Initialize
                    Dim osBuildLabEx : osBuildLabEx = GetOSBuildLabEx
                    Dim osProductName : osProductName = GetOSProductName
                    If TraceError(g_Trace, "Set Kvp value: osBuildLabEx failed") = 0 Then
                        Dim kvp_os_version: kvp_os_version = WScript.Arguments.Named("ConfigurationPass") & "_PA_OSVersion"
                        SetKvpRegistry kvp_os_version, osProductName & " " & osBuildLabEx, g_Trace 'OS version
                    End If
                End If

                configSetDrive = GetConfigSetDrive()
                If IsNull(configSetDrive) Then
                    Set oTraceEvent = g_Trace.CreateEvent("ERROR")
                    With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("InitializeEnvironment"))
                        .Text = "Could not find E6DA6616-8EC4-48E0-BE93-58CE6ACE3CFB.tag in any of the drives"
                    End With
                    g_Trace.TraceEvent oTraceEvent
                    Exit Sub
                End If

                objEnv.Initialize configSetDrive
                If TraceError(g_Trace, "InitializeEnvironment: objEnv.Initialize failed") = 0 Then
                    Set m_Environment = objEnv
                End If
            End Sub

            Sub InitializeGuest
                WScript.Echo "Initializing Control System"
                On Error Resume Next
                g_objGuestInterface.Initialize()
                If TraceError(g_Trace, "InitializeGuest: g_objGuestInterface.Initialize failed") <> 0 Then
                    Exit Sub
                End If
            End Sub

            Sub ReportNotReady(sSubStatus, sDescription)
                SetKvpRegistry kvp_pa_provision_state, sSubStatus, g_Trace
                g_objGuestInterface.PutProvisioningStatus "NotReady", sSubstatus, sDescription, Nothing
                TraceError g_Trace, "ReportNotReady: PutProvisioningStatus failed"
            End Sub

            Sub ReportReady
                SetKvpRegistry kvp_pa_provision_state, "Provisioned", g_Trace
                g_objGuestInterface.PutProvisioningStatus "Ready", Null, Null, Nothing
                TraceError g_Trace, "ReportReady: PutProvisioningStatus failed"
            End Sub

            Sub ReportPreprovisioned
                SetKvpRegistry kvp_pa_provision_state, "Preprovisioned", g_Trace
                g_objGuestInterface.PutProvisioningStatus "Ready", Null, Null, Nothing
                TraceError g_Trace, "ReportPreprovisioned: PutProvisioningStatus failed"
            End Sub

            ' Logs the ticks since boot and the current time into
            ' the kvpTickCount and kvpCompletionTime registries respectively
            Sub SetCompletionTimeInfo(kvpTickCount, kvpCompletionTime)
                On Error Resume Next

                Dim oResults, arr
                Set oResults = ExecuteAndTraceWithResults("%SystemRoot%\OEM\WaGuest.exe /timeinfo", g_Trace)
                ' Expected output is:
                ' <tickcount> <timestamp>
                If oResults.ExitCode = 0 Then
                    arr = Split(oResults.StdOut, " ")
                    If UBound(arr) = 1 Then
                        SetKvpRegistry kvpTickCount, arr(0), g_Trace
                        SetKvpRegistry kvpCompletionTime, arr(1), g_Trace
                        Exit Sub
                    End If
                End If

                SetKvpRegistry kvpTickCount, "-1", g_Trace
                SetKvpRegistry kvpCompletionTime, g_Trace.GetCurrentTime(), g_Trace
            End Sub

            ' Parses the given string into an array of SetupStage objects.
            ' Expected format of str is a space delimited set of the following:
            '     <type>;<name>;<instance>;<start time>;<end time>
            ' Where:
            '     type: TimeShift (1), Stage (2)
            '     name: The name of the stage
            '     instance: The index of the instance of the stage
            '     start time: The start time of the stage
            '     end time: the end time of the stage
            Function ParseTracedStages(str)
                On Error Resume Next

                Dim counter : counter = 0
                Dim ary : ary = Split(Trim(str), " ")
                Dim ret, cache
                ReDim ret(UBound(ary))
                ReDim cache(UBound(ary))

                For Each data In ary
                    Dim dataAry : dataAry = Split(data, ";")
                    Dim obj : Set obj = New SetupStage

                    If UBound(dataAry) = 4 Then
                        obj.StageType = CLng(dataAry(0))
                        obj.StageName = dataAry(1)
                        obj.StageInstanceIndex = CLng(dataAry(2))
                        obj.StageStartTime = dataAry(3)
                        obj.StageEndTime = dataAry(4)

                        Set ret(counter) = obj
                        cache(counter) = QuoteString(obj.StageName)

                        counter = counter + 1
                    End If
                Next

                For Each obj In ret
                    obj.HasMultipleInstances = UBound(Filter(cache, QuoteString(obj.StageName), True)) > 0
                Next

                ParseTracedStages = ret
            End Function

            Sub LogSetupTraceEvents
                On Error Resume Next

                Dim oResults, output

                Dim filePath : filePath = FSO.BuildPath(FSO.GetSpecialFolder(0), "Panther\setup.etl")
                Set oResults = ExecuteAndTraceWithResults("%SystemRoot%\OEM\WaGuest.exe /parsesetuptrace " & QuoteString(filePath) , g_Trace)
                If oResults.ExitCode <> 0 Then
                    Err.Raise vbObjectError + 9, "Failed to parse setup trace."
                    Exit Sub
                End If

                output = Trim(oResults.StdOut)

                g_TracedStages = ParseTracedStages(output)
                SetKvpRegistry kvp_pa_provision_setup_etl, output, g_Trace
            End Sub

            Sub SendOnPluginProvisionEnd
                On Error Resume Next

                Dim oJson : Set oJson = New JSON
                Dim oStageTimes, startTime, endTime, tickCount, operation, hasData, indexStage
                Dim provisioningStartTime, provisioningTickCount
                Dim stages : stages = Array("specialize", "oobeSystem", "roleReady", "errorHandler", "reprovision")

                provisioningStartTime = ""

                For Each stage In stages
                    Set oStageTimes = New JSON

                    tickCount = GetKvpRegistry(stage & "_PA_TickCount")
                    startTime = GetKvpRegistry(stage & "_PA_StartTime")
                    endTime = GetKvpRegistry(stage & "_PA_CompletionTime")
                    hasData = False

                    If Not IsNull(tickCount) And Not IsEmpty(tickCount) Then
                        oStageTimes.Add "TickCount", CLng(tickCount)
                        hasData = True
                    End If

                    If Not IsNull(startTime) And Not IsEmpty(startTime) Then
                        oStageTimes.Add "StartTime", startTime
                        hasData = True

                        ' Keep track of the specialize start time
                        ' as the provisioning start time
                        If stage = "specialize" Then
                            provisioningStartTime = startTime
                        End If
                    End If

                    If Not IsNull(endTime) And Not IsEmpty(endTime) Then
                        oStageTimes.Add "EndTime", endTime
                        hasData = True
                    End If
                    
                    If hasData = True Then
                        oJson.Add stage, oStageTimes
                    End If
                Next

                endTime = GetKvpRegistry(kvp_pa_provision_completion_time)

                If g_isReprovisionPass = True Then
                    Dim startTickCount : startTickCount = GetKvpRegistry("provisioning_AzureRPA_TickCount")
                    If IsNull(startTickCount) Or startTickCount < 0 Then
                        startTickCount = 0
                    End If

                    provisioningTickCount = GetKvpRegistry(kvp_pa_provision_tick_count) - startTickCount
                    provisioningStartTime = g_Trace.DateTimeAdd(endTime, -tickCount)
                Else
                    For Each obj In g_TracedStages
                        Set oStageTimes = New JSON
                        hasData = False

                        indexStage = obj.StageName
                        If obj.HasMultipleInstances = True Then
                            indexStage = indexStage & "[" & obj.StageInstanceIndex & "]"
                        End If

                        If obj.StageType = EventTypeStage Then
                            If Len(obj.StageStartTime) > 0 Then
                                oStageTimes.Add "StartTime", obj.StageStartTime
                                hasData = True

                                ' Keep track of the setupcl start time
                                ' as the provisioning start time
                                If obj.StageName = "SetupCl" Then
                                    provisioningStartTime = obj.StageStartTime
                                End If
                            End If

                            If Len(obj.StageEndTime) > 0 Then
                                oStageTimes.Add "EndTime", obj.StageEndTime
                                hasData = True
                            End If
                        End If

                        If hasData = True Then
                            oJson.Add indexStage, oStageTimes
                        End If
                    Next

                    provisioningTickCount = CLng(GetKvpRegistry(kvp_pa_provision_tick_count))
                End If

                Set oStageTimes = New JSON
                oStageTimes.Add "TickCount", provisioningTickCount
                oStageTimes.Add "StartTime", provisioningStartTime
                oStageTimes.Add "EndTime", GetKvpRegistry(kvp_pa_provision_completion_time)
                oJson.Add "provisioning", oStageTimes

                If g_isPreprovisionPass = True Then
                    operation = "OnPluginPreprovisionEnd"
                ElseIf g_isReprovisionPass = True Then
                    operation = "OnPluginReprovisionEnd"
                Else
                    operation = "OnPluginProvisionEnd"
                End If

                Dim durationMS : durationMS = g_Trace.GetElapsedMSSinceNow(startTime)
                g_objGuestInterface.SendTelemetry operation, oJson.Serialize(), durationMS
            End Sub

            Sub SendProvisioningDiagnostics()
                On Error Resume Next

                Dim startTime : startTime = g_Trace.GetCurrentTime()

                Dim oJson : Set oJson = New JSON
                Dim oPageFileJson : Set oPageFileJson = New JSON
                Dim sysprepSetVmMode, discoverWireServer, scratch

                Set os = GetScriptObject(WScript, "OperatingSystem.wsf", "OperatingSystem")
                Set os.WScript = WScript
                os.Initialize

                discoverWireServer = GetKvpRegistry(kvp_pa_provision_discover_wireserver)
                Err.Clear
                oJson.Add "DiscoverWireServerUsed", Not IsNull(discoverWireServer) And CBool(discoverWireServer)

                oJson.Add "MediaIdentifier", GetMediaIdentifier()
                oJson.Add "ImcSequence", GetImcSequence()
                oJson.Add "ResourceDrive", GetResourceDrive(g_Trace)
                oJson.Add "SanPolicyChanged", CBool(GetKvpRegistry(kvp_pa_provision_san_policy_changed))

                pageFileParams = GetPageFileParams()

                oPageFileJson.Add "Changed", CBool(GetKvpRegistry(kvp_pa_provision_page_file_changed))
                scratch = GetCacheValue(g_Trace, "OriginalPageFileSettings", "REG_MULTI_SZ")
                If Not IsNull(scratch) Then
                    For i = 0 To UBound(scratch)
                        scratch(i) = Replace(scratch(i), "\", "\\")
                    Next
                End If
                oPageFileJson.Add "OriginalSettings", scratch

                scratch = os.GetPageFileSettings(True)
                If Not IsNull(scratch) Then
                    For i = 0 To UBound(scratch)
                        scratch(i) = Replace(scratch(i), "\", "\\")
                    Next
                End If
                oPageFileJson.Add "CurrentSettings", scratch

                scratch = pageFileParams(0)
                If Not IsNull(scratch) Then
                    scratch = Replace(scratch, "\", "\\")
                End If
                oPageFileJson.Add "ConfigurationPath", scratch

                oPageFileJson.Add "ConfigurationSize", pageFileParams(1)
                oJson.Add "PageFile", oPageFileJson

                sysprepSetVmMode = GetSysprepSetVmMode()
                oJson.Add "SysprepSetVmMode", Not IsNull(sysprepSetVmMode) And sysprepSetVmMode = 1

                Dim durationMS : durationMS = g_Trace.GetElapsedMSSinceNow(startTime)
                g_objGuestInterface.SendTelemetry "ProvisioningDiagnostics", oJson.Serialize(), durationMS

            End Sub

            Sub DeleteKvpRegistry(tracer)
                Const fullPath = "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Virtual Machine\Guest"

                Dim regEx, matches, match, distinctStages, distinctStage, stageCount
                Dim strCommand, oResults, line, arr, lines, exitLoop, stageGroup

                distinctStages = Array()
                Set regEx = New RegExp
                regEx.IgnoreCase = False
                regEx.Pattern = "^((([^\s_]+)_)?(AzureRPA|PA)_[^\s]+)|(" & GUEST_FIRSTBOOT_COMPLETION_KVP_NAME & ")$"
                ' The third group in regEx.Pattern is the stage
                stageGroup = 2

                On Error Resume Next

                strCommand = "%comspec% /c REG QUERY " & QuoteString(fullPath)
                Set oResults = ExecuteWithResults(strCommand)

                For Each line In Split(oResults.StdOut, vbCrLf)
                    line = Trim(line)
                    If Len(line) <> 0 Then
                        arr = Split(line, "    ")

                        ' Make sure we are not in another key
                        If InStr(arr(0), "Guest\") <> 0 Then
                            Exit For
                        End If

                        Set matches = regEx.Execute(arr(0))
                        If matches.Count > 0 Then
                            WshShell.RegDelete(fullPath & "\" & arr(0))

                            ' We only want to log the KVP status once.
                            ' We will keep each logged stage in distinctStages.
                            ' If we encounter a new stage, we'll log it.
                            stage = matches(0).SubMatches(stageGroup)
                            If Len(stage) <> 0 Then
                                ' We need to quote the stage because Filter performs a contains string check.
                                distinctStage = QuoteString(stage)
                                If UBound(Filter(distinctStages, distinctStage, True)) = -1 Then
                                    TraceKvpStatus tracer, stage, "INFO", "success", "DeleteKvpRegistry"
                                    stageCount = UBound(distinctStages) + 1
                                    ReDim Preserve distinctStages(stageCount)
                                    distinctStages(stageCount) = distinctStage
                                End If
                            End If
                        End If
                    End If
                Next

                TraceError tracer, "DeleteKvpRegistry: Delete registry for previous configuration passes failed."
            End Sub

            Sub SetReprovisioningAgentKvps
                Dim registryData

                On Error Resume Next

               'Read InitialTickCount from AzureRPA
                registryData = GetRegistryValue(g_Trace, AzureProvisioningPath, "InitialTickCount", "REG_DWORD", True)
                If IsNull(registryData) <> True Then
                    SetKvpRegistry "provisioning_AzureRPA_InitialTickCount", registryData, g_Trace
                End If

                'Read UpdateTickCount from AzureRPA
                registryData = GetRegistryValue(g_Trace, AzureProvisioningPath, "UpdateTickCount", "REG_DWORD", True)
                If IsNull(registryData) <> True Then
                    SetKvpRegistry "provisioning_AzureRPA_UpdateTickCount", registryData, g_Trace
                End If

                'Read LastErrorCode from AzureRPA, could be null if reprovisioning succeeded
                registryData = GetRegistryValue(g_Trace, AzureProvisioningPath, "LastErrorCode", "REG_DWORD", True)
                If IsNull(registryData) <> True Then
                    SetKvpRegistry "provisioning_AzureRPA_LastErrorCode", registryData, g_Trace
                End If

                'Read LastErrorTickCount from AzureRPA, could be null if reprovisioning succeeded
                registryData = GetRegistryValue(g_Trace, AzureProvisioningPath, "LastErrorTickCount", "REG_DWORD", True)
                If IsNull(registryData) <> True Then
                    SetKvpRegistry "provisioning_AzureRPA_LastErrorTickCount", registryData, g_Trace
                End If
            End Sub

            Private Function GetPageFileParams()
                Dim PageFileParams : PageFileParams = Array(Null, Null)
                Dim path, size

                If m_Environment is Nothing Then
                    GetPageFileParams = PageFileParams
                    Exit Function
                End If

                Set objOSDParams = m_Environment.GetOSDParameters()
                Set objPageFile = objOSDParams.selectSingleNode("wa:PageFile")
                if Not (objPageFile is Nothing) Then
                    Set objPageFilePath = objPageFile.selectSingleNode("wa:Path")
                    If Not (objPageFilePath is Nothing) Then
                        path = Trim(objPageFilePath.text)
                        If Len(path) > 0 Then
                            PageFileParams(0) = path
                        End If
                    End If

                    Set objPageFileSize = objPageFile.selectSingleNode("wa:Size")
                    If Not (objPageFileSize is Nothing) Then
                        size = Trim(objPageFileSize.text)
                        If Len(size) > 0 Then
                            PageFileParams(1) = size
                        End If
                    End If
                End If

                GetPageFileParams = PageFileParams
            End Function

            Private Function GetDefaultPageFilePath()
                Dim drive : drive = GetResourceDrive(g_Trace)
                TraceError g_Trace, "GetDefaultPageFilePath: GetResourceDrive failed"

                If IsNull(drive) Or Len(drive) = 0 Then
                    drive = "?:"
                End If

                GetDefaultPageFilePath = drive & "\pagefile.sys"
            End Function

            ' This function queries the registry for IMC sequence number.
            ' If it finds the sequence number to be 0xf (the value is set by host agent when injecting IMC),
            ' the function returns true. It returns false otherwise.
            Private Function ImcWasInjected()
                const fullPath = "HKLM\SYSTEM\CurrentControlSet\Control\InitialMachineConfig"
                const imcSequenceSetByDimc = &Hf

                Dim registryValue

                ImcWasInjected = False

                registryValue = GetImcSequence()

                If IsNull(registryValue) Then
                    Set oTraceEvent = g_Trace.CreateEvent("INFO")
                    With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("ImcWasInjected"))
                        .Text = "Failed to find a value for IMC sequence number."
                    End With
                    g_Trace.TraceEvent oTraceEvent
                    Exit Function
                End If

                If imcSequenceSetByDimc = registryValue Then
                    ImcWasInjected = True
                End If
            End Function

            Private Function GetImcSequence()
                Const fullPath = "HKLM\SYSTEM\CurrentControlSet\Control\InitialMachineConfig"
                GetImcSequence = GetRegistryValue(g_Trace, fullPath, "Sequence", "REG_DWORD", True)
            End Function

            Private Function GetMediaIdentifier()
                Const fullPath = "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\MediaIdentifier"
                GetMediaIdentifier = GetRegistryValue(g_Trace, fullPath, "BuildGUID", "REG_SZ", True)
            End Function

            Private Function GetSysprepSetVmMode()
                Const fullPath = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup\OOBE"
                GetSysprepSetVmMode = GetRegistryValue(g_Trace, fullPath, "SysprepSetVMMode", "REG_DWORD", True)
            End Function

            ' Function retrieves the offlined flags from the setup registry keys
            Private Function GetOfflinedFeatures()
                Dim offlinedFeatures : Set offlinedFeatures = New OfflinedFeatures

                offlinedFeatures.Tag = GetRegistryValue(g_Trace, AzureProvisioningOfflinedFlagsPath, AzureProvisioningOfflinedTagValue, "REG_SZ", True)
                offlinedFeatures.Flags = GetRegistryValue(g_Trace, AzureProvisioningOfflinedFlagsPath, AzureProvisioningOfflinedFlagsValue, "REG_DWORD", True)

                If IsEmpty(offlinedFeatures.Tag) Or IsNull(offlinedFeatures.Tag) Then
                    offlinedFeatures.Tag = ""
                End If

                If IsNull(offlinedFeatures.Flags) Then
                    offlinedFeatures.Flags = 0
                End If

                Set GetOfflinedFeatures = offlinedFeatures
            End Function

            ' Wipes the offlined flags from the registry
            Sub DeleteOfflinedFlags
                DeleteRegistry g_Trace, AzureProvisioningOfflinedFlagsPath, AzureProvisioningOfflinedTagValue, True
                DeleteRegistry g_Trace, AzureProvisioningOfflinedFlagsPath, AzureProvisioningOfflinedFlagsValue, True
            End Sub

            ' Checks the environment file if this is a preprovision pass
            ' It is a preprovision pass if PreprovisionedVm=True or PreprovisionedVMType is present (regardless of its value)

            Private Function IsPreprovisionPass()
                Dim IsPreprovisionedVm, IsPreprovisionedVMTypePresent
                IsPreprovisionPass = False
                IsPreprovisionedVm = False
                IsPreprovisionedVMTypePresent = False

                Set objPlatformParams = m_Environment.GetPlatformProvisioningParameters()
                Set objPreprovisionedVm = objPlatformParams.selectSingleNode("wa:PreprovisionedVm")
                If Not (objPreprovisionedVm is Nothing) Then
                    If LCase(objPreprovisionedVm.text) = "true" Then
                       IsPreprovisionedVm = True
                    End If
                End If

                Set objPreprovisionedVMType = objPlatformParams.selectSingleNode("wa:PreprovisionedVMType")
                If Not (objPreprovisionedVMType is Nothing) Then
                    If Len(objPreprovisionedVMType.text) <> 0 Then
                        IsPreprovisionedVMTypePresent = True
                    End If
                End If

                If IsPreprovisionedVm = True Or IsPreprovisionedVMTypePresent = True Then
                    IsPreprovisionPass = True
                End If

                Set oTraceEvent = g_Trace.CreateEvent("INFO")
                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("IsPreprovisionPass"))
                    .Text = IsPreprovisionPass
                End With
                g_Trace.TraceEvent oTraceEvent
            End Function

            Private Function IsPreprovisionedOSDisk()
                IsPreprovisionedOSDisk = False

                Set objPlatformParams = m_Environment.GetPlatformProvisioningParameters()
                Set objPreprovisionedVMType = objPlatformParams.selectSingleNode("wa:PreprovisionedVMType")
                If Not (objPreprovisionedVMType is Nothing) Then
                    If LCase(objPreprovisionedVMType.text) = "preprovisionedosdisk" Then
                        IsPreprovisionedOSDisk = True
                    End If
                End If

                Set oTraceEvent = g_Trace.CreateEvent("INFO")
                With oTraceEvent.appendChild(oTraceEvent.ownerDocument.createElement("IsPreprovisionedOSDisk"))
                    .Text = IsPreprovisionedOSDisk
                End With
                g_Trace.TraceEvent oTraceEvent
            End Function
        </script>
    </job>
</package>