1

Background

This is a PowerShell script for refreshing Internet proxy settings which I got from Batch File to disable internet options proxy server.

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

Problem

I want to run it in batch file or command prompt as a single command such as

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

Which I learned from How to condense PowerShell script to fit on a single line.

Approach

I've tried to combine it altogether into one line and execute it.

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);"

But it returned me an error.

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

Question

How do I solve it? Is there any better ways to condense the function above?

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
Unknown123
  • 966
  • 6
  • 15
  • I wish people would stop trying to wrap PowerShell into batch files. Write a PowerShell script. Run that PowerShell script. Done. – Ansgar Wiechers Sep 26 '19 at 07:36
  • Please use the `edit` function to update your question instead of spreading the information in comments. – harper Sep 26 '19 at 08:07
  • @AnsgarWiechers I haven't found any native commands from windows to disable or enable system proxy settings. Only by changing the registry won't instantaneously renew the settings. I would like to keep everything in batch file actually. I'll embed the code into the batch file to make it compact. Moreover, using Visual Basic will be a whole lot mess. Using 3rd-party binaries makes a hassle. It's because there's nothing else that can be done better in this case except using PowerShell as far as I have known. – Unknown123 Sep 26 '19 at 11:50
  • @AnsgarWiechers "I'm new to powershell" is not a fluff in my opinion, it helps any person to know of how depth they should answer my question – Unknown123 Sep 26 '19 at 13:49
  • @Unknown123 Quite on the contrary. Whether you (the person asking a question) new to a language or not is entirely irrelevant for the question. – Ansgar Wiechers Sep 26 '19 at 13:56

1 Answers1

2

The @ characters around the $signature variable are what's known as a Here-String and are explicitly intended for blocks of text that may include new lines.

The signature definition is just C# code and that particular code snippet doesn't actually need the included line breaks to function. So can just declare it like a regular string instead.

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

However, you're also going to have to deal with escaping the embedded double quotes which according to the "Calling PowerShell's CLI from cmd.exe or POSIX-like shells" section of this answer means you should replace each of them with "^""

Is there a particular reason the PowerShell code has to be embedded in the batch file rather than its own .ps1 file along side it that your batch file references? Because that's the least hassle if you can manage it.

Your other option instead of having to one-line'ify and escape the PowerShell code is to use PowerShell's ability to run a Base64 encoded script via the -EncodedCommand parameter. Assuming you have your Refresh-System.ps1 script already, you could do something like this to generate the batch file.

$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
Ryan Bolger
  • 1,275
  • 8
  • 20
  • After escaping the double quotes, this is the most condensed batch command that I could successfully use `powershell -command "$signature = '[DllImport("^""wininet.dll"^"", SetLastError = true, CharSet=CharSet.Auto)] public static extern bool InternetSetOption(IntPtr hInternet, int dwOption, IntPtr lpBuffer, int dwBufferLength);'; $type = Add-Type -MemberDefinition $signature -Name wininet -Namespace pinvoke -PassThru; $type::InternetSetOption(0,39,0,0); $type::InternetSetOption(0,37,0,0);" > nul` – Unknown123 Sep 26 '19 at 13:34
  • Yes I need to embed it. I would like to keep everything in batch file. I haven't found any native commands from windows to disable or enable system proxy settings. Only by changing the registry won't instantaneously renew the settings. I'll embed the code into the batch file to make it compact. Moreover, using Visual Basic will be a whole lot mess. Using 3rd-party binaries makes a hassle. It's because there's nothing else that can be done better in this case except using PowerShell as far as I have known. – Unknown123 Sep 26 '19 at 13:34
  • You have solved my questions. But please one last thing, in case in the future I need to use Here-String in the `powershell.exe -command` argument, what should I do? How do I insert the the line breaks? – Unknown123 Sep 26 '19 at 13:38
  • 1
    You should use the last option of encoding the script to Base64. – Ryan Bolger Sep 26 '19 at 14:11