0

I have a Go application that takes in PowerShell commands as input, creates a new ps1 file, writes the commands to the file, then executes the script file.

It would be great if the file were not visible to users.

If there were some way to create the script file as a memory-mapped file and then execute that memory-mapped file, that would be a good solution.

Using CGo, I can call into C or C++ from the Go application. Since PowerShell can work with C# objects, I'm thinking that maybe we can somehow call into C# code (either from C/C++ or Go) and create a C# memory-mapped file object that PowerShell can then use to execute as a script.

Admittedly, I know nothing about how calling managed code from unmanaged code works.

So, is there some way to take this string containing PowerShell commands and execute it as a script without creating an on-disk file?

6
  • Both powershell.exe and pwsh take an -EncodedCommand command line argument that might be useful here. Why is it important to hide the script from the user? Commented Mar 19, 2021 at 1:59
  • Mostly because of Hyrum's Law. We don't want customers to be able to depend on implementation details/be able to modify the scripts. We've tried using the Windows %TEMP% directory, storing the scripts in a pseudorandom location in there, but there are security concerns with that approach. So, going straight from memory to PowerShell.exe, skipping the disk seems like the right thing. Commented Mar 19, 2021 at 2:23
  • Thanks for the -EncodedCommand suggestion. Unfortunately, it has a character limit of, I believe 32767 characters, which does not work for some of our scripts. That being said, maybe a solution would be to use the -EncodedCommand to spin up a PowerShell session which then proceeds to read the script a stdin pipe. Commented Mar 19, 2021 at 2:24
  • While we're at at, 1) the language is called Go (you don't say JavaLang or PythonLang either, right?); 2) memory-mapped file is not what you appear to think it is, you might consider doing a little research. Also, the concept explained by Mathias in their answer is common to all interpreted language hosts (usually called shells though it's not quite correct)—including Python, Ruby, Tcl and the gazillion others, so you can keep this in mind as it may come in handy the next time. Commented Mar 19, 2021 at 4:29
  • @kostix, thanks for the feedback. Agreed that a memory-mapped file does not appear to be what I need in this situation. However, what specifically makes you think that my understanding is wrong? Commented Mar 19, 2021 at 5:18

1 Answer 1

5

To make powershell.exe read script input as standard input, pass - as a command line argument:

package main

import (
    "bytes"
    "fmt"
    "log"
    "os/exec"
    "strings"
)

func main() {
    cmd := exec.Command("powershell", "-")
    cmd.Stdin = strings.NewReader("Write-Output 'Hello, World!'")
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("pwsh out: %q\n", out.String())
}

With Go 1.16 you can embed the script in the executable at build time:

package main

import (
    "bytes"
    _ "embed"
    "fmt"
    "log"
    "os/exec"
    "strings"
)

//go:embed script.ps1
var scriptBytes []byte

func main() {
    cmd := exec.Command("powershell", "-")
    cmd.Stdin = strings.NewReader(string(scriptBytes))
    var out bytes.Buffer
    cmd.Stdout = &out
    err := cmd.Run()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("pwsh out: %q\n", out.String())
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.