powershell

package
v0.0.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 27, 2019 License: Apache-2.0 Imports: 8 Imported by: 1

README

#generate

to generate zpsh_host.go go generate

You will have to change modpsh_host = windows.NewLazySystemDLL("psh_host.dll") to modpsh_host = windows.NewLazyDLL("psh_host.dll")

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/KnicKnic/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

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CallbackFuncPtr added in v0.0.4

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 added in v0.0.4

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

type CallbackResultsWriter interface {
	WriteString(string)
	Write(object Object, needsClose bool)
}

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 added in v0.0.3

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

func (obj Object) AddRef() Object

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) IsNull

func (obj Object) IsNull() bool

IsNull returns true if the backing powershell object is null

func (Object) JSONUnmarshal added in v0.0.3

func (obj Object) JSONUnmarshal(userObject interface{}) error

JSONUnmarshal calls the ToString function and unmarshals it into the supplied object

func (Object) ToString

func (obj Object) ToString() string

ToString returns the (System.Object).ToString() function

for nullptr returns nullptr

func (Object) Type

func (obj Object) Type() string

Type returns the (System.Object).GetType().ToString() function

for nullptr returns nullptr

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 added in v0.0.5

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) Close added in v0.0.2

func (runspace Runspace) Close()

Close and free a Runspace

func (Runspace) ExecCommand added in v0.0.2

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 added in v0.0.3

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 added in v0.0.2

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 added in v0.0.3

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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL