如何使@'...'@在powershell.exe-命令“”中工作?

时间:2019-09-26 04:25:11

标签: powershell

背景

这是一个PowerShell脚本,用于刷新从Batch File to disable internet options proxy server获得的Internet代理设置。

function Refresh-System {
    $signature = @'
[DllImport("wininet.dll", SetLastError = true, CharSet=CharSet.Auto)]
public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);
'@

    $INTERNET_OPTION_SETTINGS_CHANGED   = 39
    $INTERNET_OPTION_REFRESH            = 37
    $type = Add-Type -MemberDefinition $signature -Name wininet -Namespace pinvoke -PassThru
    $a = $type::InternetSetOption(0, $INTERNET_OPTION_SETTINGS_CHANGED, 0, 0)
    $b = $type::InternetSetOption(0, $INTERNET_OPTION_REFRESH, 0, 0)
    return $a -and $b
}
Refresh-System

问题

我想在批处理文件或命令提示符中将其作为单个命令运行,例如

powershell.exe -Command "stmnt1; stmnt2; ..."

我从How to condense PowerShell script to fit on a single line中学到了。

方法

我试图将其完全合并为一行并执行它。

powershell -command "$signature = @'[DllImport("wininet.dll", SetLastError = true, CharSet=CharSet.Auto)] public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength)'@; $INTERNET_OPTION_SETTINGS_CHANGED   = 39; $INTERNET_OPTION_REFRESH            = 37; $type = Add-Type -MemberDefinition $signature -Name wininet -Namespace pinvoke -PassThru; $a = $type::InternetSetOption(0, $INTERNET_OPTION_SETTINGS_CHANGED, 0, 0); $b = $type::InternetSetOption(0, $INTERNET_OPTION_REFRESH, 0, 0);"

但是它给我返回了一个错误。

At line:1 char:16
+ $signature = @'[DllImport(wininet.dll, SetLastError = true, CharSet=C ...
+                ~
No characters are allowed after a here-string header but before the end
of the line.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedCharactersAfterHereStringHeader

问题

我该如何解决?有没有更好的方法来压缩上面的功能?

1 个答案:

答案 0 :(得分:2)

@变量周围的$signature字符是所谓的Here-String,专门用于可能包含换行符的文本块。

签名定义只是C#代码,并且该特定代码段实际上不需要包含的换行符即可起作用。因此,可以像常规字符串一样声明它。

$signature = '[DllImport("wininet.dll", SetLastError = true, CharSet=CharSet.Auto)] public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);'

但是,您还必须转义嵌入式双引号,根据this answer的“从cmd.exe或类似POSIX的外壳调用PowerShell的CLI”部分,这意味着您应该替换每个双引号。其中有"^""

是否存在将PowerShell代码嵌入批处理文件而不是其自己的.ps1文件的特定原因?因为这是您管理起来最省事的事情。

您的另一种选择是使用PowerShell通过-EncodedCommand参数运行Base64编码脚本的功能,而不必单一行地进行代码化和转义PowerShell代码。假设您已经拥有Refresh-System.ps1脚本,则可以执行以下操作来生成批处理文件。

$scriptText = Get-Content .\Refresh-System.ps1 -Raw
$scriptB64 = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($scriptText))
"powershell.exe -EncodedCommand `"$scriptB64`"" | Out-File refresh-system.cmd -Encoding ascii