从Function App调用Invoke-AzVMRunCommand时参数为空的问题
问题:Invoke-AzVMRunCommand传参为空的排查与解决
问题现象
队列触发的PowerShell Function App调用Invoke-AzVMRunCommand执行Azure VM上的脚本时,脚本能正常启动,但始终接收不到传入的参数。
Function App代码
# Input bindings are passed in via param block. param($QueueItem, $TriggerMetadata) $ErrorActionPreference = "Stop" try { $SasToken = $Env:SasToken $PDB = $QueueItem['PDB'] $FileName = $QueueItem['FileName'] $StorageAccount = 'https://STORAGENAME.blob.core.windows.net/CONTAINER/' $BlobURI = "{0}{1}{2}" -f $StorageAccount, $FileName, $sasToken $ScriptPath = "F:\azCopy\CopyToDump.ps1" $ScriptFile = "CopyToDump.ps1" $params = @{ "PDB" = $PDB; "BlobURI" = $BlobURI } # 直接用"-ScriptPath $ScriptPath"时提示找不到路径,参考帖子后用了Out-File,但不清楚原理 Out-File -InputObject $ScriptPath -FilePath ScriptToRun.ps1 Invoke-AzVMRunCommand ` -ResourceGroupName 'RESOURCE_GROUP' ` -VMName 'VM_NAME' ` -CommandId 'RunPowerShellScript' ` -ScriptPath ScriptToRun.ps1 ` -Parameter @{ PDB = $PDB; BlobURI = $BlobURI } Remove-Item -Path ScriptToRun.ps1 Write-Host "Done" } catch { $_.Exception.Message }
VM上的目标脚本(CopyToDump.ps1)
param( [string]$PDB, [string]$BlobURI ) $logFile = "F:\azcopy\Info.txt" Function Write-Log { param( [Parameter(Mandatory = $true)][string] $message, [Parameter(Mandatory = $false)] [ValidateSet("INFO", "WARN", "ERROR")] [string] $level = "INFO" ) # 生成时间戳 $timestamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss") # 写入日志文件 Add-Content -Path $logFile -Value "$timestamp [$level] - $message" } try { $folder = switch ($PDB) { 'QA' {'094D2AA1A909459BA36ABEEA7F7732F6'} 'DEV' {'0B2305B6305547F389F96C800630CD21'} } $dpdump = "F:\app\oracle\admin\hs\dpdump\$folder" Write-Log -level INFO -message "---------------------------" Write-Log -level INFO -message "Copying: $BlobURI" Write-Log -level INFO -message "To folder $dpdump" Write-Log -level INFO -message "---------------------------" Write-Log -level INFO -message "F:\azCopy\AzCopy.exe copy $BlobURI $dpdump --overwrite=ifsourcenewer --check-md5=FailIfDifferent" Write-Log -level INFO -message "---------------------------" & F:\azCopy\AzCopy.exe copy $BlobURI $dpdump --overwrite=ifsourcenewer --check-md5=FailIfDifferent } catch { Write-Log -level ERROR -message "Error running script" Write-Log -level ERROR -message $_.Message exit -1 }
已尝试的传参方式
以下几种传参写法均未解决参数为空的问题:
-Parameter @{ PDB = $PDB; BlobURI = $BlobURI } -Parameter @{ "PDB" = $PDB; "BlobURI" = $BlobURI } -Parameter @{ PDB = "$PDB"; BlobURI = "$BlobURI" } -Parameter @{ "PDB" = "$PDB"; "BlobURI" = "$BlobURI" } -Parameter $params
解决方案
1. 修复脚本路径的核心错误
你当前用Out-File -InputObject $ScriptPath -FilePath ScriptToRun.ps1的写法完全错误:这只是把VM上的脚本路径字符串写入了本地文件,而非脚本内容。Invoke-AzVMRunCommand的-ScriptPath参数要求传入Function App运行环境本地的脚本路径,而非VM上的路径,这是导致后续一系列问题的根源。
推荐两种正确的处理方式:
方式一:直接嵌入脚本内容
把VM上的脚本内容直接定义在Function App代码中,用-ScriptContent参数传递:
# 定义要在VM上执行的脚本内容 $scriptContent = @' param( [string]$PDB, [string]$BlobURI ) $logFile = "F:\azcopy\Info.txt" Function Write-Log { param( [Parameter(Mandatory = $true)][string] $message, [Parameter(Mandatory = $false)] [ValidateSet("INFO", "WARN", "ERROR")] [string] $level = "INFO" ) $timestamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss") Add-Content -Path $logFile -Value "$timestamp [$level] - $message" } try { $folder = switch ($PDB) { 'QA' {'094D2AA1A909459BA36ABEEA7F7732F6'} 'DEV' {'0B2305B6305547F389F96C800630CD21'} } $dpdump = "F:\app\oracle\admin\hs\dpdump\$folder" Write-Log -level INFO -message "---------------------------" Write-Log -level INFO -message "Copying: $BlobURI" Write-Log -level INFO -message "To folder $dpdump" Write-Log -level INFO -message "---------------------------" Write-Log -level INFO -message "F:\azCopy\AzCopy.exe copy $BlobURI $dpdump --overwrite=ifsourcenewer --check-md5=FailIfDifferent" Write-Log -level INFO -message "---------------------------" & F:\azCopy\AzCopy.exe copy $BlobURI $dpdump --overwrite=ifsourcenewer --check-md5=FailIfDifferent } catch { Write-Log -level ERROR -message "Error running script" Write-Log -level ERROR -message $_.Message exit -1 } '@ # 调用Invoke-AzVMRunCommand Invoke-AzVMRunCommand ` -ResourceGroupName 'RESOURCE_GROUP' ` -VMName 'VM_NAME' ` -CommandId 'RunPowerShellScript' ` -ScriptContent $scriptContent ` -Parameter $params
方式二:从存储账户下载脚本到本地
若脚本内容较长,可将脚本上传至存储账户,在Function App中先下载到临时目录,再用-ScriptPath传递:
# 下载脚本到Function App临时目录 $localScriptPath = Join-Path $env:TEMP "CopyToDump.ps1" Invoke-WebRequest -Uri "https://STORAGENAME.blob.core.windows.net/CONTAINER/CopyToDump.ps1$sasToken" -OutFile $localScriptPath # 执行VM命令 Invoke-AzVMRunCommand ` -ResourceGroupName 'RESOURCE_GROUP' ` -VMName 'VM_NAME' ` -CommandId 'RunPowerShellScript' ` -ScriptPath $localScriptPath ` -Parameter $params # 清理临时文件 Remove-Item $localScriptPath
2. 验证参数来源的有效性
在Function App代码中添加日志,确认队列传递的参数是否存在:
Write-Host "QueueItem中的PDB值: $PDB" Write-Host "生成的BlobURI: $BlobURI"
3. 确认VM脚本的参数接收
在VM脚本开头添加日志,直接输出接收的参数值,排查是否是脚本内部处理问题:
param( [string]$PDB, [string]$BlobURI ) $logFile = "F:\azcopy\Info.txt" Write-Log -level INFO -message "接收到的PDB参数: $PDB" Write-Log -level INFO -message "接收到的BlobURI参数: $BlobURI" # 后续原有代码...
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

