Server 2012 R2中PowerShell计划任务流水线执行报错求助
问题排查:Server 2012 R2流水线中PowerShell计划任务注册失败
问题现象
- 脚本在Server 2012 R2手动执行时,创建计划任务功能正常;但通过企业流水线执行时,该部分代码报错,其余逻辑运行正常。
- 脚本在Server 2016和Server 2019的流水线中执行完全正常。
报错代码片段
# Get path where command is being run from $here = Split-Path $script:MyInvocation.MyCommand.Path $driversPath = (Join-Path $here 'drivers') $PS1File = (Join-Path $driversPath 'Install-ChipsetDrivers.ps1') $action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File $PS1File -EXEFilesPath $driversPath" $trigger = New-ScheduledTaskTrigger -AtStartup $principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest Register-ScheduledTask -TaskName 'Install Chipset Drivers' -Action $action -Trigger $trigger -Principal $principal -Description 'Installs any Chipset drivers that are missing' -ErrorAction Stop -Force
错误信息
Register-ScheduledTask: Cannot process argument transformation on parameter 'Trigger'. Cannot convert
value "Microsoft.PowerShell.ScheduledJob.ScheduledJobTrigger" to type
"Microsoft.Management.Infrastructure.CimInstance[]". Error: "Cannot convert the
"Microsoft.PowerShell.ScheduledJob.ScheduledJobTrigger" value of type
"Deserialized.Microsoft.PowerShell.ScheduledJob.ScheduledJobTrigger" to type
"Microsoft.Management.Infrastructure.CimInstance".
原因分析
这个问题是PowerShell远程/流水线执行时的对象序列化问题导致的:
- Server 2012 R2默认使用PowerShell 4.0,流水线执行通常通过远程会话或作业环境运行,此时
New-ScheduledTaskTrigger返回的对象会被序列化为Deserialized.Microsoft.PowerShell.ScheduledJob.ScheduledJobTrigger类型,但Register-ScheduledTask需要原生的Microsoft.Management.Infrastructure.CimInstance类型对象,序列化后的对象无法直接转换。 - 手动执行时是本地会话,对象保持原生类型,因此无问题;Server 2016/2019默认使用PowerShell 5.1+,对这类对象的序列化/反序列化兼容性更好,不会触发错误。
解决方法
有两种可行的修复方案:
方案1:使用CIM原生命令创建触发器
直接通过CIM命令构造计划任务触发器,避免序列化问题:
# 替换原有的New-ScheduledTaskTrigger代码 $triggerParams = @{ Setting = @{ Enabled = $true AtStartup = $true } } $trigger = New-CimInstance -ClassName MSFT_TaskTrigger -Namespace Root/Microsoft/Windows/TaskScheduler -Property $triggerParams -ClientOnly
方案2:在本地会话中执行计划任务注册逻辑
将计划任务注册代码封装成本地脚本块执行,避免对象跨会话序列化:
# 替换原计划任务注册的所有代码 $taskScriptBlock = { $here = $args[0] $driversPath = Join-Path $here 'drivers' $PS1File = Join-Path $driversPath 'Install-ChipsetDrivers.ps1' $action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$PS1File`" -EXEFilesPath `"$driversPath`"" $trigger = New-ScheduledTaskTrigger -AtStartup $principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest Register-ScheduledTask -TaskName 'Install Chipset Drivers' -Action $action -Trigger $trigger -Principal $principal -Description 'Installs any Chipset drivers that are missing' -ErrorAction Stop -Force } # 在本地会话中执行脚本块 Invoke-Command -ScriptBlock $taskScriptBlock -ArgumentList $here
修改后的完整脚本片段(以方案1为例)
# Registers a Scheduled Task that will attempt to install drivers (mostly chipset drivers) that cannon be installed via their INF files at image creation. This scheduled task will be removed once run. $driversPath = (Join-Path $here 'drivers') $PS1File = (Join-Path $driversPath 'Install-ChipsetDrivers.ps1') $action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File $PS1File -EXEFilesPath $driversPath" # 使用CIM命令创建触发器 $triggerParams = @{ Setting = @{ Enabled = $true AtStartup = $true } } $scheduledTrigger = New-CimInstance -ClassName MSFT_TaskTrigger -Namespace Root/Microsoft/Windows/TaskScheduler -Property $triggerParams -ClientOnly $principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest Register-ScheduledTask -TaskName 'Install Chipset Drivers' -Action $action -Trigger $scheduledTrigger -Principal $principal -Description 'Installs any Chipset drivers that are missing' -ErrorAction Stop -Force
内容的提问来源于stack exchange,提问作者Keith
相关产品推荐
相关产品推荐

