求助:将注册表条目导入root/cimv2自定义WMI类
问题需求
在root/cimv2命名空间创建自定义WMI类,自动遍历HKLM:\SOFTWARE\OSDBuild注册表项的所有条目并导入该类。已有注册表写入代码,但WMI导入代码无法正常运行。
原注册表写入代码的小问题修正
原代码存在几处拼写错误,修正后版本:
$RegKeyName = "OSDBuild" # Set values $tsenv = New-Object -COMObject Microsoft.SMS.TSEnvironment $FullRegKeyName = "HKLM:\SOFTWARE\" + $regkeyname # Create Registry key New-Item -Path $FullRegKeyName -type Directory -Force -ErrorAction SilentlyContinue # Get values $InstallTime = Get-Date -Format G $OSDStartTime = $tsenv.Value("OSDStartTSTime") $AdvertisementID = $tsenv.Value("_SMSTSAdvertID") $Organisation = $tsenv.Value("_SMSTSOrgName") $TaskSequenceID = $tsenv.Value("_SMSTSPackageID") $Packagename = $tsenv.Value("_SMSTSPackageName") $MachineName = $env:computername $Installationmode = $tsenv.Value("_SMSTSLaunchMode") $BuildRevision = $tsenv.Value("BuildRevision") $OSName = $tsenv.Value("OSName") $OSDDateUTC = (Get-Date).ToUniversalTime() #Calculate time elapsed $OSDTimeSpan = New-TimeSpan -start $OSDStartTime -end $InstallTime $OSDDuration = "{0:hh}:{0:mm}:{0:ss}" -f $OSDTimeSpan # Write values New-ItemProperty $FullRegKeyName -Name "InstalledDate" -value $InstallTime -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "OSDStartTime" -value $OSDStartTime -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "OSDDuration" -value $OSDDuration -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "OrganisationName" -value $Organisation -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "AdvertisementID" -value $AdvertisementID -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "TaskSequenceID" -value $TaskSequenceID -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "Task Sequence Name" -value $Packagename -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "Installation Type" -value $Installationmode -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "Computername" -value $MachineName -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "OSVersion" -value (Get-CimInstance Win32_Operatingsystem).version -PropertyType String -Force | Out-Null New-ItemProperty $FullRegKeyName -Name "BuildRevision" -value $BuildRevision -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "OSVersionName" -value $OSName -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null New-ItemProperty $FullRegKeyName -Name "OSDDateUTC" -value $OSDDateUTC -Type STRING -Force -ErrorAction SilentlyContinue | Out-Null
原WMI导入代码的问题分析
- 重复赋值
$registryKey:多次赋值后仅保留最后一个值,导致所有WMI实例的RegistryKeyName错误,应使用注册表项的实际名称(如OSDBuild)。 - CimInstance创建逻辑错误:重复调用
New-CimInstance,且无需先转换为PSCustomObject,直接通过属性哈希表创建即可。 - 未处理类已存在的情况:重复运行会报错,需先检查类是否存在,按需跳过或重建。
- 缺少错误处理:未判断注册表路径是否存在,可能导致后续操作失败。
修正后的WMI导入代码
# 定义命名空间和类名 $namespace = "root\cimv2" $className = "OSDBuild" $registryPath = "HKLM:\SOFTWARE\OSDBuild" # 检查注册表路径是否存在 if (-not (Test-Path $registryPath)) { Write-Error "注册表路径 $registryPath 不存在" exit 1 } # 检查WMI类是否存在,不存在则创建 $existingClass = Get-CimClass -Namespace $namespace -ClassName $className -ErrorAction SilentlyContinue if (-not $existingClass) { # 定义类属性 $classProperties = @( New-CimProperty -Name "RegistryKeyName" -CimType String -Flags "Key, ReadOnly" New-CimProperty -Name "RegistryValueName" -CimType String -Flags "Key, ReadOnly" New-CimProperty -Name "RegistryValueData" -CimType String -Flags "ReadOnly" ) # 创建类 New-CimClass -Namespace $namespace -ClassName $className -PropertyDefinition $classProperties | Out-Null Write-Host "已创建WMI类 $namespace\$className" } else { Write-Host "WMI类 $namespace\$className 已存在,跳过创建" } # 获取注册表项的名称(如OSDBuild) $registryKeyName = (Get-Item $registryPath).PSChildName # 获取注册表所有值 $registryValues = Get-ItemProperty -Path $registryPath # 遍历注册表值并创建WMI实例 foreach ($property in $registryValues.PSObject.Properties) { # 跳过PowerShell内置属性 if ($property.Name -in "PSPath", "PSParentPath", "PSChildName", "PSDrive", "PSProvider") { continue } # 准备实例属性 $instanceProps = @{ RegistryKeyName = $registryKeyName RegistryValueName = $property.Name RegistryValueData = $property.Value.ToString() } # 检查该实例是否已存在,避免重复创建 $existingInstance = Get-CimInstance -Namespace $namespace -ClassName $className -Filter "RegistryKeyName='$registryKeyName' AND RegistryValueName='$($property.Name)'" -ErrorAction SilentlyContinue if (-not $existingInstance) { # 创建并保存WMI实例 New-CimInstance -Namespace $namespace -ClassName $className -Property $instanceProps | Out-Null Write-Host "已导入注册表值: $($property.Name) = $($property.Value)" } else { Write-Host "注册表值 $($property.Name) 已存在于WMI类中,跳过" } }
代码说明
- 类存在性检查:避免重复创建类导致的错误。
- 注册表路径检查:提前判断路径是否存在,防止后续操作失败。
- 实例去重:通过键属性(RegistryKeyName + RegistryValueName)检查是否已存在,避免重复导入。
- 数据类型统一:将注册表值转为String,匹配WMI类的属性类型。
内容的提问来源于stack exchange,提问作者user25512276
相关产品推荐
相关产品推荐

