通过Invoke-AzVMRunCommand上传SQL文件到Azure VM失败,文件内容为空
问题原因
你这个脚本用了嵌套的Here-String,通过Invoke-AzVMRunCommand传到Azure VM执行时,远程PowerShell环境对内部的单引号Here-String(@'...'@)解析出了问题,导致$sqlContent变量没拿到预期的SQL语句,最后写入文件的内容就是空的。
具体来说:
- 你用双引号Here-String(
@"..."@)包裹了要远程执行的整个脚本,里面又嵌套了单引号Here-String来定义SQL内容。 - 脚本传到VM上执行时,远程PowerShell没法正确识别单引号Here-String的边界,结果
$sqlContent是空值,自然生成的SQL文件就没内容。
修复办法
给你三个可行的修复方案:
方案1:别用嵌套Here-String,直接拼SQL字符串
把SQL语句直接写成普通字符串赋值,避开嵌套解析的坑:
$databaseName = "testDB" $script = @" if (-not (Test-Path -Path 'C:\Temp')) { New-Item -Path 'C:\Temp' -ItemType Directory -Force } \$sqlContent = "IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = '$databaseName') BEGIN CREATE DATABASE [$databaseName]; END; GO SELECT name FROM sys.databases; GO" Set-Content -Path 'C:\Temp\CreateDB.sql' -Value \$sqlContent -Force sqlcmd -S localhost -E -i 'C:\Temp\CreateDB.sql' "@
方案2:转义内部Here-String的结束符
要是非得用嵌套Here-String,就在内部单引号Here-String的结束符'@后面加个反引号(`),让外层双引号Here-String别提前结束解析:
$databaseName = "testDB" $script = @" if (-not (Test-Path -Path 'C:\Temp')) { New-Item -Path 'C:\Temp' -ItemType Directory -Force } \$sqlContent = @' IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = '$databaseName') BEGIN CREATE DATABASE [$databaseName]; END; GO SELECT name FROM sys.databases; GO '@` Set-Content -Path 'C:\Temp\CreateDB.sql' -Value \$sqlContent -Force sqlcmd -S localhost -E -i 'C:\Temp\CreateDB.sql' "@
方案3:跳过写文件,直接传SQL给sqlcmd(更高效)
其实没必要生成SQL文件,直接把SQL语句通过管道传给sqlcmd就行,少一步文件操作:
$databaseName = "testDB" $script = @" if (-not (Test-Path -Path 'C:\Temp')) { New-Item -Path 'C:\Temp' -ItemType Directory -Force } \$sqlCmd = @" IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = '$databaseName') BEGIN CREATE DATABASE [$databaseName]; END; GO SELECT name FROM sys.databases; GO "@ \$sqlCmd | sqlcmd -S localhost -E "@
小提示
用Invoke-AzVMRunCommand传带复杂引号或Here-String的脚本时,最好先在本地输出$script变量看看解析后的内容对不对,确认没问题再远程执行,省得踩解析的坑。
内容的提问来源于stack exchange,提问作者Álvaro
相关产品推荐
相关产品推荐

