Home » HOW TO: Execute a PowerShell script on any machine using Ngrok and Power Automate

HOW TO: Execute a PowerShell script on any machine using Ngrok and Power Automate

One of the biggest bugbears of Power Automate cloud, for me anyway, is when, let’s say, I need to access information from Active Directory. Not Azure Active Directory; the old fashioned one. It’s on-premises; YAWN. I can’t be arsed to install an on-premises gateway (not that there is a “PowerShell” connector anyway).

Fear not. You can expose your PC to the internet, and execute your PowerShell scripts from Power Automate and get the response of the script within seconds, using Ngrok!

What is Ngrok?

ngrok delivers instant ingress to your apps in any cloud, private network, or devices with authentication, load balancing, and other critical controls.

Here’s what to do:

First, install ngrok. To do this, download ngrok from https://ngrok.com/download and extract the zip to any location on your PC. I chose “C:\”.

  1. Set up an ngrok account and obtain your authtoken
  2. Configure ngrok
    • Open a command prompt or PowerShell terminal with administrator privileges.
    • Navigate to the directory where you extracted ngrok (e.g., cd C:\ngrok).
    • Run the following command to configure ngrok with your authtoken
      • If you are using Command Prompt, enter “ngrok authtoken YOUR_AUTHTOKEN”. If you are using PowerShell, enter “./ngrok authtoken YOUR_AUTHTOKEN”
    • Create a PowerShell script to start an HTTP listener:
      • Open a text editor, such as Notepad.
      • Copy and paste the following code into the text editor:
    $url = 'http://+:8080'
    $listener = New-Object System.Net.HttpListener
    $listener.Prefixes.Add($url + '/')
    $listener.Start()
    Write-Host "Listening on $url..."
    
    while ($listener.IsListening) {
        $context = $listener.GetContext()
        $request = $context.Request
        $response = $context.Response
    
        if ($request.HttpMethod -eq "POST") {
            $reader = New-Object System.IO.StreamReader($request.InputStream)
            $scriptToExecute = $reader.ReadToEnd()
    
            try {
                $output = Invoke-Expression $scriptToExecute | Out-String
                $response.StatusCode = 200
            } catch {
                $output = "Error executing the script: " + $_.Exception.Message
                $response.StatusCode = 500
            }
        } else {
            $output = "Invalid request method. Please use POST."
            $response.StatusCode = 400
        }
    
        $buffer = [System.Text.Encoding]::UTF8.GetBytes($output)
        $response.ContentLength64 = $buffer.Length
        $response.ContentType = "text/plain"
        $response.AddHeader("Content-Type", "text/plain; charset=utf-8")
        $response.OutputStream.Write($buffer, 0, $buffer.Length)
        $response.Close()
    }
    

    Note:

    Save the file with a .ps1 extension (e.g., http_listener.ps1).

    4. Start the HTTP listener – Open a PowerShell terminal with administrator privileges. Navigate to the directory where you saved http_listener.ps1. Change the execution policy for PowerShell by executing Set-“ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process”. Then, run the script with the following command: ./http_listener.ps1 – you must leave this script open and running!

    5. Start ngrok to expose the HTTP listener – Open another command prompt or PowerShell terminal as admin. Navigate to the directory where you extracted ngrok. Run the following command to expose the HTTP listener on a public URL, so "ngrok http 8080“. Note the “Forwarding” URL displayed in the terminal, which will look like http://<unique_id>.ngrok.io. Don’t worry about the bits after the ” >> “.

    6. In Power Automate, create a new flow and simply add the HTTP action. Create a POST request to the URI using forwarding URI you copied from command prompt.

    Now, let’s give it a spin…

    Write your PowerShell!

    To keep this simple for this walkthrough, although there is no reason you can’t be as creative as you like, I just issued a POST request with my PowerShell script, as:

    (Get-ChildItem -Path "C:\Users\philg\Downloads" -File).Count
    

    You just simply paste this into the BODY element of the HTTP action in Power Automate. No headers, no JSON formatting needed etc. Try any script you like.

    Now, I’ve done a count of files within this folder on my PC manually. It should be 880.

    Here it is in action! Yep, 880 it is!

    So how is this any different to, say, deploying a Function App or Runbook?

    Well, using Ngrok, there is no need to provision new landing zones, security rules, PIM roles or any of that palaver and, crucially, Ngrok natively lives on your own machine – thus, as we see in this example, can access YOUR files natively.

    Also, you can use Ngrok and Power Automate dynamically to chuck any PowerShell commands you like at it and get the response in Power Automate – thus calling PowerShell in a flow, effectively – which you can’t do as-easy with a function app or runbook.

    Enjoy!

    PhilGlew-Deval

    3 thoughts on “HOW TO: Execute a PowerShell script on any machine using Ngrok and Power Automate

    1. Hi Phil,

      This looks brilliant – I started following you on LinkedIn just so I could get to this article. Are you able to explain what the security implications are? I’m guessing NGrok sets up the device to behave almost like an API server looking for the Auth Token, but is there something we’d need to do to allow access through a firewall or to defend this endpoint from a drive-by?

    Comments are closed.

    Back to top