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>