summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart Preston <stuart@chef.io>2018-03-09 10:02:10 -0800
committerStuart Preston <stuart@chef.io>2018-03-09 10:02:10 -0800
commit0875f93aad1680cb6346ff98d7cc1291c69e3e9e (patch)
tree16c9f4cff742ba4cc058aab9206370a7bb4d5102
parente3bbbb4cbe7f8d0a6f15416f4b9bf86e3ea83dbb (diff)
downloadchef-sp/powershell_exec.tar.gz
Addressing feedback, adding docs and examplessp/powershell_exec
Signed-off-by: Stuart Preston <stuart@chef.io>
-rw-r--r--RELEASE_NOTES.md2
-rw-r--r--lib/chef/mixin/powershell_exec.rb69
2 files changed, 70 insertions, 1 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 15e95c736a..d1e082ffbe 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -6,7 +6,7 @@ _This file holds "in progress" release notes for the current release under devel
## New Windows PowerShell mixin `powershell_exec`
-Since our supported Windows platforms can all run .NET Framework 4.0 and PowerShell 4.0 we have taken time to add a new interop that will allow faster and safer interactions with the system PowerShell. You will be able to use the `powershell_exec` mixin in most places where you would have previously used `powershell_out`.
+Since our supported Windows platforms can all run .NET Framework 4.0 and PowerShell 4.0 we have taken time to add a new interop that will allow faster and safer interactions with the system PowerShell. You will be able to use the `powershell_exec` mixin in most places where you would have previously used `powershell_out`. For comparison, a basic benchmark test to return the `$PSVersionTable` 100 times completed 7.3X faster compared to the `powershell_out` method. The majority of the time difference is because of less time spent in invocation. So we believe it has big future potential where multiple calls to PowerShell are required inside (for example) a custom resource.
# Chef Client Release Notes 13.7:
diff --git a/lib/chef/mixin/powershell_exec.rb b/lib/chef/mixin/powershell_exec.rb
index 4e276b307d..cdd5450fa3 100644
--- a/lib/chef/mixin/powershell_exec.rb
+++ b/lib/chef/mixin/powershell_exec.rb
@@ -17,6 +17,75 @@
require "chef/powershell"
+# The powershell_exec mixin provides in-process access to PowerShell engine via
+# a COM interop (installed by the Chef Client installer).
+#
+# powershell_exec returns a Chef::PowerShell object that provides 3 methods:
+#
+# .result - returns a hash representing the results returned by executing the
+# PowerShell script block
+# .errors - this is an array of string containing any messages written to the
+# PowerShell error stream during execution
+# .error? - returns true if there were error messages written to the PowerShell
+# error stream during execution
+#
+# Some examples of usage:
+#
+# > powershell_exec("(Get-Item c:\\windows\\system32\\w32time.dll).VersionInfo"
+# ).result["FileVersion"]
+# => "10.0.14393.0 (rs1_release.160715-1616)"
+#
+# > powershell_exec("(get-process ruby).Mainmodule").result["FileName"]
+# => C:\\opscode\\chef\\embedded\\bin\\ruby.exe"
+#
+# > powershell_exec("$a = $true; $a").result
+# => true
+#
+# > powershell_exec("not-found").errors
+# => ["ObjectNotFound: (not-found:String) [], CommandNotFoundException: The
+# term 'not-found' is not recognized as the name of a cmdlet, function, script
+# file, or operable program. Check the spelling of the name, or if a path was
+# included, verify that the path is correct and try again. (at <ScriptBlock>,
+# <No file>: line 1)"]
+#
+# > powershell_exec("not-found").error?
+# => true
+#
+# > powershell_exec("get-item c:\\notfound -erroraction stop")
+# WIN32OLERuntimeError: (in OLE method `ExecuteScript': )
+# OLE error code:80131501 in System.Management.Automation
+# The running command stopped because the preference variable
+# "ErrorActionPreference" or common parameter is set to Stop: Cannot find
+# path 'C:\notfound' because it does not exist.
+#
+# *Why use this and not powershell_out?* Startup time to invoke the PowerShell
+# engine is much faster (over 7X faster in tests) than writing the PowerShell
+# to disk, shelling out to powershell.exe and retrieving the .stdout or .stderr
+# methods afterwards. Additionally we are able to have a higher fidelity
+# conversation with PowerShell because we are now working with the objects that
+# are returned by the script, rather than having to parse the stdout of
+# powershell.exe to get a result.
+#
+# *How does this work?* In .NET terms, when you run a PowerShell script block
+# through the engine, behind the scenes you get a Collection<PSObject> returned
+# and simply we are serializing this, adding any errors that were generated to
+# a custom JSON string transferred in memory to Ruby. The easiest way to
+# develop for this approach is to imagine that the last thing that happens in
+# your PowerShell script block is "ConvertTo-Json". That's exactly what we are
+# doing here behind the scenes.
+#
+# There are a handful of current limitations with this approach:
+# - Windows UAC elevation is controlled by the token assigned to the account
+# that Ruby.exe is running under.
+# - Terminating errors will result in a WIN32OLERuntimeError and typically are
+# handled as an exception.
+# - There are no return/error codes, as we are not shelling out to
+# powershell.exe but calling a method inline, no errors codes are returned.
+# - There is no settable timeout on powershell_exec method execution.
+# - It is not possible to impersonate another user running powershell, the
+# credentials of the user running Chef Client are used.
+#
+
class Chef
module Mixin
module PowershellExec