Search code examples
powershellgoogle-chrome-extensionpowershell-2.0powershell-3.0chrome-native-messaging

How to use powershell as native messaging host?


My requirement is to read the content from the file and send it to the chrome browser extension. I am using native messaging. I did all the configuration for native messaging but failed to send messages from the native messaging host to the extension. I am getting error like "Error when communicating with the native messaging host". I got to know that it was due to the wrong implementation of the native messaging protocol.

The Actual protocol from native messaging is : "The same format is used to send messages in both directions: each message is serialized using JSON, UTF-8 encoded and is preceded with 32-bit message length in native byte order. The maximum size of a single message from the native messaging host is 1 MB, mainly to protect Chrome from misbehaving native applications. The maximum size of the message sent to the native messaging host is 4 GB."

My code is as below: native-messaging-example-host.ps1:

$file = "D:\temp\test\test.txt"
$data = Get-content $file -Raw
$Objectdata = $data |ConvertFrom-Json
$formatedData = $Objectdata |Select-Object -Property message |ConvertTo-Json -Depth 1 -Compress
$encconsumerkey= [System.Text.UTF8Encoding]::new().GetBytes($formatedData)
$Writer = New-Object System.IO.BinaryWriter([System.Console]::OpenStandardOutput());
$Writer.Write([Int32]$encconsumerkey.length)
$Writer.Write($encconsumerkey)
$Writer
$Writer.Flush()
$Writer.Close()

My Batch Script which calls the above PowerShell script

MyExample1.bat

@echo off
color 1F
echo.

C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File "D:\projects-repo\CromeNativeMessaging\NativeHost\native-messaging-example-host.ps1"

:EOF
echo Waiting seconds
timeout /t 10 /nobreak > NUL

NativeMessageHello.json

{
    "name": "native.messaging.trail.example",
    "description": "My Example1",
    "path": "D:/projects-repo/CromeNativeMessaging/NativeHost/MyExample1.bat",
    "type": "stdio",
    "allowed_origins": [
      "chrome-extension://lknkdjfamgnamaeaebinefklcobjpphm/"
    ]
  }

Someone please help me where I am doing wrong.


Solution

  • I'm assuming that your script is being called from outside PowerShell via the PowerShell CLI (powershell.exe for Windows PowerShell, pwsh for PowerShell (Core) 7+).

    There are two problems with your script, one potential, the other definite - I am not certain that fixing them is enough to solve your problem:

    • A potential problem is that the [System.Text.Encoding]::UTF8 encoding is an encoding with BOM,[1] whereas it's safe to assume that Chrome does not expect your data to have a BOM in this scenario and may fail on encountering one.

    • A definite problem is the $Writer statement (the line containing only $Writer) in your code, which causes implicit output[2] to PowerShell's success output stream, which is relayed via stdout to an outside caller, in the form of a formatted representation of the $Writer object (that is invariably text).

      • That is, this statement "pollutes" the binary data you're sending to stdout.

        • In general, prepending $null = suppresses unwanted implicit output;[3] here, it seems you can simply remove the statement.
      • The same goes for the batch file that wraps your PowerShell command: it too mustn't produce its own stdout output, so you must either remove the echo commands or redirect their output to stderr, with >&2


    [1] in .NET Framework and as of .NET 6; changing this is being discussed for a future .NET version.

    [2] See this answer for more information about PowerShell's implicit output behavior.

    [3] See this answer form more information about output suppression.