Documentation
¶
Overview ¶
Package powershell allows hosting powershell sessions inside golang enabling bi directional communication between powershell and golang through .Net objects.
Overview ¶
This package can call commandlets, scripts, keep session state between multiple invocations, allows for custom callback routines, and trapping host output redirecting to a custom logger, calling back into golang from powershell.
Lifetimes ¶
All objects that you create or are returned to you must be Closed by you. There are Close routines on all objects that need to be closed. The one exception to this rule is if you are inside a callback and want to return an object that you generated to powershell, and have it closed after powershell has processed it.
Multithreading ¶
A single runspace is not multithreaded, do not try this! Objects generated in one runspace can be used in another assuming there is proper .Net concurrent access to those objects.
Reentrancy ¶
Reentrancy is supported, you can call powershell have it call back to golang, have that code call into powershell as long as this chain has a finite depth that is supported by powershell. This is accomplished by creating nested powershell commands anytime they are created in a callback handler or log routine.
Runspaces ¶
A runspace is where you execute your powershell commands and statements in. It is also a boundary for variables such as "$global". If you specify custom log routines or callback handlers they are also bound to the runspace. This is to enable you to bind context to the log routine or callback handler.
Please see the runspace section for more information on creating a runspace and executing scripts and commands https://godoc.org/github.com/1001101100/go-powershell/pkg/powershell#Runspace .
Scripts vs Commands ¶
ExecScript - Use when you want to save variables or create functions or execute a set of lines like how you would normally write in a .ps1 file. Do not use this to execute a .ps1 file (which is known as a command file). See the examples in the Runspace.ExecScript section
ExecCommand - Use when you simply want to call an existing commandlet or function or a .ps1 file. The results are returned. See the examples in the Runspace.ExecCommand section
Scopes ¶
Powershell uses dynamic scoping you can read more about it here https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-5.1
ExecScript and ExecCommand both have a parameter useLocalScope, what this means is do you wish to create a new child scope for this execution. If true then any variables you save inside powershell will not be accessible. If false then your variables will be persisted at global scope.
If you are still unsure, use true.
Index ¶
- type CallbackFuncPtr
- type CallbackHolder
- type CallbackResultsWriter
- type InvokeResults
- type Object
- type Runspace
- func (runspace Runspace) Close()
- func (runspace Runspace) ExecCommand(commandStr string, useLocalScope bool, namedArgs map[string]interface{}, ...) *InvokeResults
- func (runspace Runspace) ExecCommandJSONMarshalUnknown(commandStr string, useLocalScope bool, namedArgs map[string]interface{}, ...) *InvokeResults
- func (runspace Runspace) ExecScript(commandStr string, useLocalScope bool, namedArgs map[string]interface{}, ...) *InvokeResults
- func (runspace Runspace) ExecScriptJSONMarshalUnknown(commandStr string, useLocalScope bool, namedArgs map[string]interface{}, ...) *InvokeResults
Examples ¶
- CallbackHolder
- CallbackHolder (CallingPowershellInsideCallback)
- Runspace (CustomSimpleLogger)
- Runspace.ExecCommand
- Runspace.ExecCommand (WithNamedParameters)
- Runspace.ExecCommandJSONMarshalUnknown
- Runspace.ExecScript
- Runspace.ExecScript (SavingVariablesAcrossStatements)
- Runspace.ExecScriptJSONMarshalUnknown
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type CallbackFuncPtr ¶
type CallbackFuncPtr struct {
FuncPtr func(runspace Runspace, message string, input []Object, results CallbackResultsWriter)
}
CallbackFuncPtr a simple implementation of CallbackHolder that lets you pass in a function pointer for the callback
func (CallbackFuncPtr) Callback ¶
func (callback CallbackFuncPtr) Callback(runspace Runspace, message string, input []Object, results CallbackResultsWriter)
Callback is the function that will call the function pointer in CallbackFuncPtr
type CallbackHolder ¶
type CallbackHolder interface {
Callback(runspace Runspace, message string, input []Object, results CallbackResultsWriter)
}
CallbackHolder callback function pointer for Send-HostCommand callbacks
Example ¶
// create a callback object callback := CallbackFuncPtr{func(runspace Runspace, str string, input []Object, results CallbackResultsWriter) { switch str { // check if we are processing the "add 10" message case "add 10": // iterate through all items passed in for _, object := range input { numStr := object.ToString() num, _ := strconv.Atoi(numStr) // write the object back to powershell as a string results.WriteString(fmt.Sprint(num + 10)) } } }} // create a runspace (where you run your powershell statements in) runspace := CreateRunspace(nil, callback) // auto cleanup your runspace defer runspace.Close() statements := `1..3 | Send-HostCommand -message "add 10"` results := runspace.ExecScript(statements, true, nil) // auto cleanup all results returned defer results.Close() for _, num := range results.Objects { fmt.Println(num.ToString()) }
Output: 11 12 13
Example (CallingPowershellInsideCallback) ¶
package main import ( "fmt" "strconv" ) // the callback we want to add type callbackAdd10Nested struct { } func (callback callbackAdd10Nested) Callback(runspace Runspace, str string, input []Object, results CallbackResultsWriter) { switch str { // check if we are processing the "add 10" message case "add 10": // iterate through all items passed in for _, object := range input { numStr := object.ToString() num, _ := strconv.Atoi(numStr) num += 10 // convert object into a powershell integer // // execute in anonyous function to get scoped cleanup of results func() { execResults := runspace.ExecScript(`[int]$args[0]`, true, nil, fmt.Sprint(num)) defer execResults.Close() // we need to close our execResults.Object[0] for us after it has been processed // however we do not know when that is, so tell the results to auto do it // WE MUST NOT CLOSE IT OURSELVES IF SPECIFYING TRUE! results.Write(execResults.Objects[0], true) execResults.RemoveObjectFromClose(0) }() } } } func main() { callback := callbackAdd10Nested{} // create a runspace (where you run your powershell statements in) runspace := CreateRunspace(nil, callback) // auto cleanup your runspace defer runspace.Close() statements := `1..3 | Send-HostCommand -message "add 10"` results := runspace.ExecScript(statements, true, nil) // auto cleanup all results returned defer results.Close() for _, num := range results.Objects { fmt.Println(num.ToString()) } }
Output: 11 12 13
type CallbackResultsWriter ¶
CallbackResultsWriter allows you to write values to powershell when inside Send-HostCommand
type InvokeResults ¶
type InvokeResults struct { Objects []Object Exception Object // contains filtered or unexported fields }
InvokeResults the results of an Invoke on a psCommand
func (*InvokeResults) Close ¶
func (results *InvokeResults) Close()
Close is a convenience wrapper to close all result objects, and the exception so you do not have to
func (*InvokeResults) RemoveObjectFromClose ¶
func (results *InvokeResults) RemoveObjectFromClose(index int)
RemoveObjectFromClose remove object from objects that get closed from Close routine. Does not alter InvokeResults.Objects
Useful when calling powershell from inside a powershell callback and need to to call CallbackResultsWriter.Write(object, true) to have powershell cleanup the reference
func (*InvokeResults) Success ¶
func (results *InvokeResults) Success() bool
Success returns true if the powershell command executed successfully (threw no terminating exceptions)
type Object ¶
type Object struct {
// contains filtered or unexported fields
}
Object representing an object return from a powershell invocation
Should be called on all objects returned from a powershell invocation (not callback parameters)
See note on Object.Close for exceptions & more rules about Close
func (Object) AddRef ¶
AddRef returns a new Object that has to also be called Close on
This is useful in Callback processing, as those nativePowerShell_PowerShellObjects are auto closed, and to keep a reference after the function returns use AddRef
func (Object) Close ¶
func (obj Object) Close()
Close allows the memory for the powershell object to be reclaimed
Should be called on all objects returned from a powershell invocation (not callback parameters)
Exception: Do not call Close on the object when inside a callback and calling CallbackResultsWriter.Write() with autoclose
Needs to be called for every object returned from AddRef
func (Object) JSONUnmarshal ¶
JSONUnmarshal calls the ToString function and unmarshals it into the supplied object
type Runspace ¶
type Runspace struct {
// contains filtered or unexported fields
}
Runspace corresponds to a powershell runspace.
Use this object to execute all your powershell commands/scripts, see ExecScript and ExecCommand
use .Close() to free
Example (CustomSimpleLogger) ¶
// create a custom logger object customLogger := logger.SimpleFuncPtr{FuncPtr: func(str string) { fmt.Print("Custom: " + str) }} // create a runspace (where you run your powershell statements in) runspace := CreateRunspace(customLogger, nil) // auto cleanup your runspace defer runspace.Close() statements := `write-verbose "verbose_message";write-debug "debug_message"` results := runspace.ExecScript(statements, true, nil) // auto cleanup all results returned defer results.Close()
Output: Custom: Verbose: verbose_message Custom: Debug: debug_message
func CreateRemoteRunspace ¶
func CreateRemoteRunspace(loggerCallback logger.Simple, remoteMachine string, username string, password string) Runspace
CreateRemoteRunspace creates a runspace in which to run powershell commands
This function allows you to specify a logging callback ¶
For more details see logger.Simple.
Specify "" for username to not send username and password
You must call Close when done with this object
func CreateRunspace ¶
func CreateRunspace(loggerCallback logger.Simple, callback CallbackHolder) Runspace
CreateRunspace creates a runspace in which to run powershell commands
This function allows you to specify a logging callback as well as a callback routine that processes commands from powershell
For more details see logger.Simple and Callback holder types.
You must call Close when done with this object
func CreateRunspaceSimple ¶
func CreateRunspaceSimple() Runspace
CreateRunspaceSimple creates a runspace in which to run powershell commands
This function has no callback routines or logging callbacks.
You must call Close when done with this object
func (Runspace) ExecCommand ¶
func (runspace Runspace) ExecCommand(commandStr string, useLocalScope bool, namedArgs map[string]interface{}, args ...interface{}) *InvokeResults
ExecCommand - executes a command (cmdlets, command files (.ps1), functions, ...) in powershell
useLocalScope - true means to create a child scope, false means to use the global scope (this is probably what you want)
although namedArgs and args both state that they take interface, the only types they currently take are string and Object (a result from a previous powershell invocation)
Example ¶
// create a runspace (where you run your powershell statements in) runspace := CreateRunspaceSimple() // auto cleanup your runspace defer runspace.Close() // this will get the registry key for HKEY_LOCAL_MACHINE results := runspace.ExecCommand("get-item", true, nil, `hklm:\`) // auto cleanup the results defer results.Close() // print the .ToString() of a registry key, which is the key name fmt.Println(results.Objects[0].ToString())
Output: HKEY_LOCAL_MACHINE
Example (WithNamedParameters) ¶
// create a runspace (where you run your powershell statements in) runspace := CreateRunspaceSimple() // auto cleanup your runspace defer runspace.Close() // pass in map with named names to values results := runspace.ExecCommand("Get-ItemPropertyValue", true, map[string]interface{}{ "Path": "HKLM:\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "Name": "SoftwareType", }) // auto cleanup the results defer results.Close() // print the .ToString() of a registry key, which is the key name fmt.Println(results.Objects[0].ToString())
Output: System
func (Runspace) ExecCommandJSONMarshalUnknown ¶
func (runspace Runspace) ExecCommandJSONMarshalUnknown(commandStr string, useLocalScope bool, namedArgs map[string]interface{}, args ...interface{}) *InvokeResults
ExecCommandJSONMarshalUnknown - executes a command (cmdlets, command files (.ps1), functions, ...) in powershell
useLocalScope - true means to create a child scope, false means to use the global scope (this is probably what you want)
Although namedArgs and args both state that they take interface, string and Object (a result from a previous powershell invocation) will get sent to powershell directly. Any other type will first get marshaled to json using json.Marshal and sent as a string to powershell
Example ¶
// create a runspace (where you run your powershell statements in) runspace := CreateRunspace(logger.SimpleFmtPrint{}, nil) // auto cleanup your runspace defer runspace.Close() // write to host the parameters that are passed in command := `write-host "$args"; foreach($x in $args) {write-host $x};` results := runspace.ExecScriptJSONMarshalUnknown(command, true, nil, 1, 2, false, "test string", []int{1, 2, 3}, map[string]string{"fruit": "apple", "vegetable": "celery"}) // auto cleanup the results defer results.Close()
Output: 1 2 false test string [1,2,3] {"fruit":"apple","vegetable":"celery"} 1 2 false test string [1,2,3] {"fruit":"apple","vegetable":"celery"}
func (Runspace) ExecScript ¶
func (runspace Runspace) ExecScript(commandStr string, useLocalScope bool, namedArgs map[string]interface{}, args ...interface{}) *InvokeResults
ExecScript - executes a series of statements (not to be confused with .ps1 files which are commands) in powershell
useLocalScope - true means to create a child scope, false means to use the global scope (this is probably what you want)
although namedArgs and args both state that they take interface, the only types they currently take are string and Object (a result from a previous powershell invocation)
Example ¶
// create a runspace (where you run your powershell statements in) runspace := CreateRunspaceSimple() // auto cleanup your runspace defer runspace.Close() statements := `$os = $env:OS; "emitting your os is $os"` // execute a statement in powershell consisting of "emitting your os is $os" // $os will be Windows_NT results := runspace.ExecScript(statements, true, nil) // auto cleanup all results returned defer results.Close() fmt.Println(results.Objects[0].ToString())
Output: emitting your os is Windows_NT
Example (SavingVariablesAcrossStatements) ¶
// create a runspace (where you run your powershell statements in) runspace := 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 defering 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
func (Runspace) ExecScriptJSONMarshalUnknown ¶
func (runspace Runspace) ExecScriptJSONMarshalUnknown(commandStr string, useLocalScope bool, namedArgs map[string]interface{}, args ...interface{}) *InvokeResults
ExecScriptJSONMarshalUnknown - executes a series of statements (not to be confused with .ps1 files which are commands) in powershell
useLocalScope - true means to create a child scope, false means to use the global scope (this is probably what you want)
Although namedArgs and args both state that they take interface, string and Object (a result from a previous powershell invocation) will get sent to powershell directly. Any other type will first get marshaled to json using json.Marshal and sent as a string to powershell
Example ¶
// create a runspace (where you run your powershell statements in) runspace := CreateRunspace(logger.SimpleFmtPrint{}, nil) // auto cleanup your runspace defer runspace.Close() // emit a json object with the following fields command := `@{"Name"= "Knic";"Category"=4;"Human"=$true} |ConvertTo-Json -Depth 3` results := runspace.ExecScript(command, true, nil) // auto cleanup the results defer results.Close() // Unmarshal into custom object person var me person results.Objects[0].JSONUnmarshal(&me) fmt.Print("Name: ", me.Name, ", Category: ", me.Category, ", Human: ", me.Human)
Output: Name: Knic, Category: 4, Human: true