PowerShell脚本运行成功但报“对象引用未设置”错误,求原因
我来帮你分析这个问题——你的脚本能正常执行但抛出“Object reference not set to an instance object”错误,核心原因大概率和集合方法的兼容性或者空值处理有关,结合你的代码和XML文件,我给你拆解一下:
你的PowerShell脚本
[xml]$file = get-content "c:\Windows\personalsettings\PersonalSettings.xml" $xmlProperties = $file.SelectNodes("/Objects/Object/Property") If ($xmlProperties.Where({ $_.InnerText -eq 'FireFox' }, 'First')) { Invoke-expression "C:\Windows\SetDefaultBrowser\setdefaultbrowser" } If ($xmlProperties.Where({ $_.InnerText -eq 'Chrome' }, 'First')) { Invoke-expression "C:\Windows\psu\protected\SetDefaultBrowser\setdefaultbrowser" }
对应的XML文件
<?xml version="1.0"?> <Objects> <Object> <Property Name="Browser">Firefox</Property> <Property Name="PDF">Adobe Reader</Property> </Object> </Objects>
错误原因分析
PowerShell版本不兼容
.Where()方法.Where()是PowerShell 4.0及以上版本才引入的集合扩展方法。如果你的运行环境是PowerShell 3.0或更低版本,XmlNodeList类型(也就是$xmlProperties的类型)并没有这个方法,调用$xmlProperties.Where(...)时会尝试访问一个不存在的成员,直接触发空引用异常。
之所以脚本还能“执行成功”,可能是因为错误被标记为非终止错误(取决于你的PowerShell错误偏好设置),脚本继续跑完了后续逻辑。拼写错误导致空值触发隐式错误
你的第一个判断里写的是FireFox(第二个F大写),但XML里是Firefox(小写f),这会导致第一个.Where()找不到匹配项,返回$null。在某些PowerShell版本中,If语句对$null进行隐式布尔转换时,可能意外触发空引用错误——虽然这个错误不影响脚本继续执行,但会被输出到控制台。
解决方法
根据你的情况,推荐几个可行的修复方案:
方案1:改用兼容性更好的管道命令(推荐)
把.Where()换成Where-Object+Select-Object -First 1,这种写法在所有PowerShell版本中都能正常工作,还能避免空引用问题:
[xml]$file = get-content "c:\Windows\personalsettings\PersonalSettings.xml" $xmlProperties = $file.SelectNodes("/Objects/Object/Property") # 修正拼写错误,和XML里的Firefox一致 If ($xmlProperties | Where-Object { $_.InnerText -eq 'Firefox' } | Select-Object -First 1) { Invoke-Expression "C:\Windows\SetDefaultBrowser\setdefaultbrowser" } If ($xmlProperties | Where-Object { $_.InnerText -eq 'Chrome' } | Select-Object -First 1) { Invoke-Expression "C:\Windows\psu\protected\SetDefaultBrowser\setdefaultbrowser" }
方案2:先检查集合是否为空,再使用.Where()
如果坚持用.Where()方法,先确认$xmlProperties不是空集合,同时修正拼写错误:
[xml]$file = get-content "c:\Windows\personalsettings\PersonalSettings.xml" $xmlProperties = $file.SelectNodes("/Objects/Object/Property") # 先检查是否有节点,避免空集合调用方法 If ($xmlProperties) { If ($xmlProperties.Where({ $_.InnerText -eq 'Firefox' }, 'First')) { Invoke-Expression "C:\Windows\SetDefaultBrowser\setdefaultbrowser" } If ($xmlProperties.Where({ $_.InnerText -eq 'Chrome' }, 'First')) { Invoke-Expression "C:\Windows\psu\protected\SetDefaultBrowser\setdefaultbrowser" } }
方案3:升级PowerShell版本
如果你的环境允许,直接升级到PowerShell 5.1或更高版本,原生支持.Where()方法,就能避免版本兼容带来的问题。
内容的提问来源于stack exchange,提问作者PRobles

