PowerShell脚本'timeoffs'属性找不到问题求助及空值处理咨询
问题:PowerShell脚本GetoffTime函数报错"The property 'timeoffs' cannot be found on this object"
编写的PowerShell脚本中GetoffTime函数执行时抛出错误:"The property 'timeoffs' cannot be found on this object",但已确认该属性确实存在。手动执行函数内的Invoke-WebRequest请求并通过ConvertFrom-Json转换后,能正常看到'timeoffs'属性;在Shell中直接执行该函数也无报错,但设置StrictMode 2.0后可复现错误。发现部分返回的JSON中timeoffs为空数组,需要解决报错并实现跳过空值的方法。
相关函数代码
function GetoffTime($startDate, $endDate, $teamUsers) { foreach ($user in $teamUsers){ $body = @{ "users" = @($user) } | ConvertTo-Json -compress $response = Invoke-WebRequest -Uri $URL -Method POST -Headers $headers -ContentType "application/json" -Body $body if ($response.StatusCode -eq "200") { $data = ConvertFrom-Json $response foreach($element in $data){ # 下面的if语句会抛出属性不存在的错误 if($element.items.timeoffs.start.date){ $timeoff += @{ username = $element.items.username date = $element.items.timeoffs.start.date | Sort-Object } } } catch { Log-msg } return $timeoff }
交互模式下空值示例
PS C:\Users> $data items ----- {@{username=user; email=user@search.com; timeoffs=System.Object[]}} PS C:\Users> $data.items username email timeoffs -------- ----- -------- user user@search.com {}
日志输出示例
PS C:\Users> GetTimeoffData $startDate $endDate $teamUsers 1727004858.89624 INFO Fetching timeoff data from Google Calendar https://myapi.com/v1/timeoffs/?timeMin=2024-08-01&timeMax=2024-09-30 user1 user = 'user1' json = '{"items":[{"username":"user1","email":"user1@search","timeoffs":[]}]}' user2 user = 'user2' json = '{"items":[{"username":"user2","email":"user2@search","timeoffs":[]}]}' ...(其余日志内容略)
解决方案
1. 根本原因
当timeoffs是空数组时,$element.items.timeoffs是一个空集合,此时尝试访问它的start属性,在StrictMode 2.0下会直接抛出属性不存在的错误——因为空数组没有start成员。而无StrictMode时PowerShell会静默返回$null,不会触发报错。
2. 修复步骤
(1)添加空值检查逻辑
先判断timeoffs是否非空,再访问内部属性:
foreach($element in $data){ # 先检查timeoffs是否有内容 if ($element.items.timeoffs -and $element.items.timeoffs.start.date) { $timeoff += @{ username = $element.items.username date = $element.items.timeoffs.start.date | Sort-Object } } }
(2)使用安全导航运算符(PowerShell 3.0+)
如果你的PowerShell版本支持(3.0及以上),可以用?.安全导航运算符,避免空值链报错:
foreach($element in $data){ $startDate = $element.items.timeoffs?.start?.date if ($startDate) { $timeoff += @{ username = $element.items.username date = $startDate | Sort-Object } } }
(3)初始化$timeoff变量
原代码中$timeoff未初始化,当没有符合条件的条目时会报错,建议在函数开头添加:
$timeoff = @()
(4)修正循环与响应解析逻辑
原代码中foreach($element in $data)遍历的是顶级属性,但从返回结果看$data只有items属性,且items是数组,应该直接遍历$data.items;同时解析响应时应使用$response.Content而非直接传入$response:
if ($response.StatusCode -eq 200) { # 用数字200而非字符串 $data = ConvertFrom-Json $response.Content foreach($item in $data.items){ $startDates = $item.timeoffs?.start?.date if ($startDates) { $timeoff += @{ username = $item.username date = $startDates | Sort-Object } } } }
3. 完整修复后的函数
function GetoffTime($startDate, $endDate, $teamUsers) { $timeoff = @() # 初始化结果数组 foreach ($user in $teamUsers){ $body = @{ "users" = @($user) } | ConvertTo-Json -compress try { # 将try放到循环内,避免单个用户请求失败中断整个函数 $response = Invoke-WebRequest -Uri $URL -Method POST -Headers $headers -ContentType "application/json" -Body $body if ($response.StatusCode -eq 200) { $data = ConvertFrom-Json $response.Content foreach($item in $data.items){ # 使用安全导航运算符避免空值报错 $startDates = $item.timeoffs?.start?.date if ($startDates) { $timeoff += @{ username = $item.username date = $startDates | Sort-Object } } } } } catch { Log-msg # 可补充错误信息:Log-msg "处理用户$user时出错: $_" } } return $timeoff }
内容的提问来源于stack exchange,提问作者neoluu
相关产品推荐
相关产品推荐

