修改MDT VBS脚本, 解决OSD识别Surface Pro 7+ 硬件类别出错

微软的MDT提供一个ZtiGather.wsf的tool来识别客户端的系统类别。对应不同的系统类型,会生成对应的OSD系统变量,如服务器(IsServer),台式机(IsDesktop),笔记本(IsLaptop)。

这个变量对于我们部署app来说是很方便的,可以在一个task sequence里安装各个硬件类型的app,而不用为每个硬件类型都创建1个task sequence,简化工作量,也简化了维护的复杂度。

比如,我们可以设置Laptop类型的机器安装***软件,而服务器和台式机类型不用安装,就可以设置***安装的条件为IsLaptop = True.

这个功能的实现是根据读取WMI的ChassiType来实现的, 具体的配置和值如下。

  • Other (1)

  • Unknown (2)

  • Desktop (3)

  • Low Profile Desktop (4)

  • Pizza Box (5)

  • Mini Tower (6)

  • Tower (7)

  • Portable (8)

  • Laptop (9)

  • Notebook (10)

  • Hand Held (11)

  • Docking Station (12)

  • All in One (13)

  • Sub Notebook (14)

  • Space-Saving (15)

  • Lunch Box (16)

  • Main System Chassis (17)

  • Expansion Chassis (18)

  • SubChassis (19)

  • Bus Expansion Chassis (20)

  • Peripheral Chassis (21)

  • Storage Chassis (22)

  • Rack Mount Chassis (23)

  • Sealed-Case PC (24)

  • Tablet (30)

  • Convertible (31)

  • Detachable (32)

https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-systemenclosure

通过检测,我们可以看到ChassisTypes的值为1,根据上表,1 代表Other,和VM一样,所以当Surface Pro 7+做image的时候,OSD不认为机器类型是Laptop,IsLaptop变量值为false,带来的结果就是所有笔记本需要安装的app都不会安装。

根据和微软售后的确认,这个设置应该是个Bug,后面出的机器可能会修复这个问题,可是远水救不了近渴。

修改MDT VBS脚本, 解决OSD识别Surface Pro 7+ 硬件类别出错

那么我们可以自己解决么?答案是肯定的。

既然我们已经知道MDT是通过ZtiGather这个脚本来识别机器类型的, 那我们可以尝试修改他识别的那个函数部分来修正这个问题。

找到GetAssetInfo()这个函数,替换为下面的部分,变更后的逻辑简单来说就根据WMI的Model信息来判断Surface Pro系列的机器类型,而不看ChassisType值了。

	'//---------------------------------------------------------------------------
	'//  Function:	GetAssetInfo()
	'//  Purpose:	Get asset information using WMI
	'//---------------------------------------------------------------------------
	Function GetAssetInfo

	 	Dim bIsLaptop, bIsDesktop, bIsServer, bOnBattery, bFoundBattery, bFoundAC
		Dim sAssetTag, sSerialNumber, sMake, sModel, sProduct, sUUID, sMemory, sArchitecture, sProcessorSpeed, sCapableArchitecture

		Dim objResults, objInstance
		Dim i
		Dim bisX64, bIsUEFI, bSupportsSLAT, bSupportsX64, bSupportsX86


		oLogging.CreateEntry "Getting asset info", LogTypeInfo


		' Get the SMBIOS asset tag from the Win32_SystemEnclosure class

		Set objResults = objWMI.InstancesOf("Win32_SystemEnclosure")
		bIsLaptop = false
		bIsDesktop = false
		bIsServer = false
		For each objInstance in objResults

			If objInstance.ChassisTypes(0) = 12 or objInstance.ChassisTypes(0) = 21 then
				' Ignore docking stations
			Else

				If not IsNull(objInstance.SMBIOSAssetTag) then
					sAssetTag = Trim(objInstance.SMBIOSAssetTag)
				End if
				Select Case objInstance.ChassisTypes(0)
				Case "8", "9", "10", "11", "12", "14", "18", "21", "17", "32" 	'Added Chassis Type 17 for Surface Pro , also added Chassis Type 32 for Latitude 5285
					bIsLaptop = true
				Case "3", "4", "5", "6", "7", "15", "16", "13" ' Added Chassis Type 13 for AIO models
					bIsDesktop = true
				Case "23"
					bIsServer = true
				Case Else
					' Do nothing
				End Select

			End if

		Next
		If sAssetTag = "" then
			oLogging.CreateEntry "Unable to determine asset tag via WMI.", LogTypeInfo
		End if


		' Get the serial number from the Win32_BIOS class.

		Set objResults = objWMI.InstancesOf("Win32_BIOS")
		For each objInstance in objResults

	                ' Get the serial number

			If not IsNull(objInstance.SerialNumber) then
				sSerialNumber = Trim(objInstance.SerialNumber)
			End if

		Next
		If sSerialNumber = "" then
			oLogging.CreateEntry "Unable to determine serial number via WMI.", LogTypeInfo
		End if


		' Figure out the architecture from the environment

		If oEnv("PROCESSOR_ARCHITEW6432") <> "" then
			If UCase(oEnv("PROCESSOR_ARCHITEW6432")) = "AMD64" then
				sArchitecture = "X64"
			Else
				sArchitecture = UCase(oEnv("PROCESSOR_ARCHITEW6432"))
			End if
		ElseIf UCase(oEnv("PROCESSOR_ARCHITECTURE")) = "AMD64" then
			sArchitecture = "X64"
		Else
			sArchitecture = UCase(oEnv("PROCESSOR_ARCHITECTURE"))
		End if
		
		

		' Get the processor speed from the Win32_Processor class.

		bSupportsX86 = false
		bSupportsX64 = false
		bSupportsSLAT = false
		Set objResults = objWMI.InstancesOf("Win32_Processor")
		For each objInstance in objResults

			' Get the processor speed

			If not IsNull(objInstance.MaxClockSpeed) then
				sProcessorSpeed = Trim(objInstance.MaxClockSpeed)
			End if


			' Determine if the machine supports SLAT (only supported with Windows 8)

			On Error Resume Next
			bSupportsSLAT = objInstance.SecondLevelAddressTranslationExtensions
			On Error Goto 0
			

			' Get the capable architecture

			If not IsNull(objInstance.Architecture) then
				Select Case objInstance.Architecture
				Case 0
			
					' If the processor is running a x86 OS, then there is *Still* the possibility that it can 
					' support a x64 OS. We need to run a quick processor check to see if it supports x64.

					bisX64 = FALSE
					On Error Resume Next
					bisX64 = oUtility.BDDUtility.Is64Bit
					On Error Goto 0

					If bisX64 = TRUE then
						sCapableArchitecture = "AMD64 X64 X86"
						bSupportsX86 = true
						bSupportsX64 = true
					Else
						sCapableArchitecture = "X86"
						bSupportsX86 = true
					End if

				Case 6
					sCapableArchitecture = "IA64"
				Case 9
					sCapableArchitecture = "AMD64 X64 X86"
					bSupportsX86 = true
					bSupportsX64 = true
				Case Else
					SCapableArchitecture = "Unknown"
				End Select
			End if


			' Stop after first processor since all should match

			Exit For

		Next
		If sProcessorSpeed = "" then
			oLogging.CreateEntry "Unable to determine processor speed via WMI.", LogTypeInfo
		End if
		If sCapableArchitecture = "" then
			oLogging.CreateEntry "Unable to determine capable architecture via WMI.", LogTypeInfo
		End if


		' Get the make, model, and memory from the Win32_ComputerSystem class

		Set objResults = objWMI.InstancesOf("Win32_ComputerSystem")
		For each objInstance in objResults

			If not IsNull(objInstance.Manufacturer) then
				sMake = Trim(objInstance.Manufacturer)
			End if
			If not IsNull(objInstance.Model) then
				sModel = Trim(objInstance.Model)
			End if
			If not IsNull(objInstance.TotalPhysicalMemory) then
				sMemory = Trim(Int(objInstance.TotalPhysicalMemory / 1024 / 1024))
			End if

		Next
		If sMake = "" then
			oLogging.CreateEntry "Unable to determine make via WMI.", LogTypeInfo
		End if
		If sModel = "" then
			oLogging.CreateEntry "Unable to determine model via WMI.", LogTypeInfo
		End If


		' Get the Lenovo Model Version from the Win32_ComputerSystemProduct class
		' http://smulpuru.wordpress.com/2011/02/16/mdt-custom-variable-for-lenovo-model-drivergroup/
		' Added 10/08/2013 - dhedges
		
		'If sMake = "LENOVO" Then
			'Set objResults = objWMI.InstancesOf("Win32_ComputerSystemProduct")
			'For Each objInstance In objResults
				'sLenovoModel = objInstance.Version
			'Next
			'If sLenovoModel = "" Then
				'sLenovoModel = Null
				'oLogging.CreateEntry "Unable to determine LenovoModel tag via WMI", LogTypeInfo
			'End If
		'End If

		' Get the UUID from the Win32_ComputerSystemProduct class

		Set objResults = objWMI.InstancesOf("Win32_ComputerSystemProduct")
		For each objInstance in objResults

			If not IsNull(objInstance.UUID) then
				sUUID = Trim(objInstance.UUID)
			End if

		Next
		If sUUID = "" then
			oLogging.CreateEntry "Unable to determine UUID via WMI.", LogTypeInfo
		End if


		' Get the product from the Win32_BaseBoard class

		Set objResults = objWMI.InstancesOf("Win32_BaseBoard")
		For each objInstance in objResults

			If not IsNull(objInstance.Product) then
				sProduct = Trim(objInstance.Product)
			End if

		Next
		If sProduct = "" then
			oLogging.CreateEntry "Unable to determine product via WMI.", LogTypeInfo
		End if


		' Determine if we are running UEFI

		bIsUEFI = FALSE
		On Error Resume Next
		bIsUEFI = oUtility.BDDUtility.IsUEFI
		On Error Goto 0


		' See if we are running on battery

		If oEnv("SystemDrive") = "X:" and oFSO.FileExists("X:\Windows\Inf\Battery.inf") then
			
			' Load the battery driver

			oShell.Run "drvload X:\Windows\Inf\Battery.inf", 0, true
			
		End if

		bFoundAC = False
		bFoundBattery = False
		Set objResults = objWMI.InstancesOf("Win32_Battery")
		For each objInstance in objResults
			bFoundBattery = True
			If objInstance.BatteryStatus = 2 then
				bFoundAC = True
			End if 
		Next
		If bFoundBattery and (not bFoundAC) then
			bOnBattery = True
		Else
			bOnBattery = False
		End if
		
		'set IsLaptop to true as long as Surface Pro model detected no matter what the chassistype is

		If ((instr(sModel,"Surface Pro")) > 0) and (sMake = "Microsoft Corporation") then
			bIsLaptop = true
		End if

		oEnvironment.Item("AssetTag") = sAssetTag
		oEnvironment.Item("SerialNumber") = sSerialNumber
		oEnvironment.Item("Make") = sMake
		oEnvironment.Item("Model") = sModel
		oEnvironment.Item("Product") = sProduct
		oEnvironment.Item("UUID") = sUUID
		oEnvironment.Item("Memory") = sMemory
		oEnvironment.Item("Architecture") = sArchitecture
		oEnvironment.Item("ProcessorSpeed") = sProcessorSpeed
		oEnvironment.Item("CapableArchitecture") = sCapableArchitecture
		oEnvironment.Item("IsLaptop") = oUtility.ConvertBooleanToString(bIsLaptop)
		oEnvironment.Item("IsDesktop") = oUtility.ConvertBooleanToString(bIsDesktop)
		oEnvironment.Item("IsServer") = oUtility.ConvertBooleanToString(bIsServer)
		oEnvironment.Item("IsUEFI") = oUtility.ConvertBooleanToString(bIsUEFI)
		oEnvironment.Item("IsOnBattery") = oUtility.ConvertBooleanToString(bOnBattery)
		oEnvironment.Item("SupportsX86") = oUtility.ConvertBooleanToString(bSupportsX86)
		oEnvironment.Item("SupportsX64") = oUtility.ConvertBooleanToString(bSupportsX64)
		If bSupportsSLAT or oEnvironment.Item("SupportsSLAT") = "" then
			oEnvironment.Item("SupportsSLAT") = oUtility.ConvertBooleanToString(bSupportsSLAT)
		Else
			oLogging.CreateEntry "Property SupportsSLAT = " & oEnvironment.Item("SupportsSLAT"), LogTypeInfo
		End if

		oLogging.CreateEntry "Finished getting asset info", LogTypeInfo

		GetAssetInfo = Success

	End Function


创建一个新的MDT包,在Surface Pro 7+ 上跑一次OSD image,会发现所有笔记本要安装的app全部成功安装了。

至此,问题解决,而且以后出的Surface Pro系列都会识别为Laptop类型。


上一篇:微软被曝正为其服务器和Surface PC自研ARM芯片


下一篇:亲测解决:自定义相机Camera2前后置拍照时相片翻转、旋转等显示问题