Goal
The goal of this project is to enable you to quickly write golang code and interact with windows via powershell and not use exec. Because powershell is a powerful scripting language you will sometimes want to call back into golang. This is also enabled by this project. Also due to sometimes wanting to host .net and powershell giving you an easy way to wrap .net modules and functions and objects, this project also enables that.
Features:
- Call from golang to powershell
- Call from powershell to golang (via special Send-HostCommand commandlet)
- Easy logging - Trap host output in powershell and call custom logging routines in golang
- Uses syscall - so do not need to use cGo
Status
It works
- call scripts / cmdlets
- reuse variables between calls / invocation
- Call from golang to powershell
- Call from powershell back to golang (via special Send-HostCommand commandlet)
- trap host output in powershell and call custom logging routines in golang
- has automated tests
- Docs - if you missed the badge above go to https://godoc.org/github.com/1001101100/go-powershell/pkg/powershell
This project is not api stable, however I believe it will be simple if you do use the current api to migrate to any future changes.
TODO:
- add some code for easy back and forth json serialization of complex objects
- more examples / tests
- example / helper classes around exception
- a doc overview
- plumb through callback handler for each specific logging type (verbose, debug, warning, ...)
- support for default loggers, like glog or log (in separate package)
Usage
package main
import (
"fmt"
"github.com/1001101100/go-powershell/pkg/powershell"
)
func main() {
// create a runspace (where you run your powershell statements in)
runspace := powershell.CreateRunspaceSimple()
// auto cleanup your runspace
defer runspace.Close()
// gets whatever environment variable we request
// wrapping $args[0] inside $() so powershell understands [0] associated with $args
getEnvironmentVariable := `$environVariable = get-childitem "env:\$($args[0])";`
// Execute the statement
// false - says to not execute the statement in a temporary child scope
// meaning that the variables will be available to future invocations
// nil - means we didn't name any arguments
// "OS" - after first 3 parameters comes the unnamed arguments which we reference via $args[index]
results1 := runspace.ExecScript(getEnvironmentVariable, false, nil, "OS")
//not deferring close as we do not need the results
results1.Close()
returnEnvironmentInfo := `"emitting your $($environVariable.Name) is $($environVariable.Value)"`
// true - we are choosing the create in a temporary child scope, the parent scope variables are still accessible to us
// we could however choose to specify false and be in the same scope
results2 := runspace.ExecScript(returnEnvironmentInfo, false, nil)
// auto cleanup all results returned
defer results2.Close()
// print the string result of the first object from the last statement (which happens to already be a string)
fmt.Println(results2.Objects[0].ToString())
// Output: emitting your OS is Windows_NT
}
Dependencies
This project has a dependency on native-powershell. This is a c++/cli project that enables interacting with powershell through a C DLL interface.
Using native-powershell
- Simply fetch the dependencies,
go get -d .
and then make sure to build, go build
- Copy the precompiled psh_host.dll into your location so it can be found when running the app
- cmd -
copy %GOPATH%\src\github.com\KnicKnic\go-powershell\bin\psh_host.dll .
- powershell -
copy "$($env:GOPATH)\src\github.com\KnicKnic\go-powershell\bin\psh_host.dll" .
- I ended up checking in the psh_host.dll and host.h (to make things easy)
- I could not find a better way to go about this and still have things be easy.
Docs
https://grokbase.com/t/gg/golang-nuts/154m672a6t/go-nuts-linking-cgo-with-visual-studio-x64-release-libraries-on-windows