Remotely run Powershell scripts within Automate using WinRM


#1

ManageIQ leverages the WinRM gem to execute commands and
Powershell scripts on remote Windows systems from the local ManageIQ appliance.
Below is some guidance on how to configure and use WinRM within Automate.

  1. Make sure the WinRM service has been configured correctly on the remote Windows server. This is well documented online but I found the following link particularly concise and useful:
    http://msdn.microsoft.com/en-us/library/aa384372(v=vs.85).aspx

The following error might be thrown when trying to connect to the WinRM service for the first time:

WinRM::WinRMHTTPTransportError: Bad HTTP response returned from server (401)..

Run the following commands locally on the Windows server in an elevated cmd prompt to try to solve the problem:

winrm set winrm/config/client/auth @{Basic="true"}
winrm set winrm/config/service/auth @{Basic="true"}
winrm set winrm/config/service @{AllowUnencrypted="true"}
  1. The execution policy on a Windows server determines which Powershell scripts (if any) will be allowed to run. Make sure an appropriate policy is set. See http://technet.microsoft.com/en-us/library/ee176961.aspx for more details.

  2. Below is a sample script that illustrates how to use the WinRM gem within Automate.

require 'json'
require 'winrm'

PS_SCRIPT = <<-PS_SCRIPT
$result = @{
  "date"     = Get-Date;
  "services" = Get-Service
}
$result | ConvertTo-JSON
PS_SCRIPT

url_params = {
  :ipaddress => "<hostname_or_ip>",
  :port      => 5985                # Default port 5985
}

connect_params = {
  :user         => "<username>",    # Example: domain\\user
  :pass         => "<password>",
  :disable_sspi => true
}

url = "http://#{url_params[:ipaddress]}:#{url_params[:port]}/wsman"
$evm.log("info", "Connecting to WinRM on URL :#{url}")

winrm   = WinRM::WinRMWebService.new(url, :ssl, connect_params)
results = winrm.run_powershell_script(PS_SCRIPT)

# results is a hash with 2 keys:
# 1) The first key :data is an array with two hashes
#   :stderr
#   :stdout
# 2) the second key is the :exitcode.

errors = results[:data].collect { |d| d[:stderr] }.join
$evm.log("error", "WinRM returned stderr: #{errors}") unless errors.blank?

data = results[:data].collect { |d| d[:stdout] }.join
json_hash = JSON.parse(data, :symbolize_names => true)
$evm.log("info", "WinRM returned hash: #{json_hash.inspect}")

Incorporating Chocolatey into the provisioning dialogs
Steps to Join Hyper V VMM to Manageiq
#2

On Windows servers the maximum length of string that you can use at the command prompt is 8191 characters. This applies to running locally on the windows server or remotely via WinRM. For more information refer to: http://support2.microsoft.com/kb/830473

To work around this you can break your PowerShell scripts up into multiple files and invoke them individually.


#3

Hi,

I love the use of WinRM for Windows management, as all Windows statements to date are advising PowerShell is the defacto automation tool for Windows the use of WinRM is the supported, advised and correct route to interacting with SCVMM. My only concerns would be around the authentication mechanisms used. By default in our implementation it would default to Negotiated authentication as we are not in a domain, and would then try for a NTLMv2 or v1 handshake, I believe that we would end up on NTLMv1 which is clear text password. This is v.bad, though the WinRM is all encrypted by default it would require another security requirement to determine if the level of encryption is sufficient at the customer/prospects site, e.g. if its 128bit, then most sites would be happy, but what about the sites that are 256bit? So to get over this, you really need Kerberos authentication. All sites that require hardened services will mandate a minimum of kerberos. I think though we should be sensible about roadmap too, e.g., if kerberos is going to take some more time, get the functionality in on Negotiated, and delivering provisioning etc…then get the kerberos added after provisioning?

The links to WinRM authentication
http://msdn.microsoft.com/en-us/library/aa384295(v=vs.85).aspx
https://www.myotherpcisacloud.com/post/2012/01/30/Monitoring-with-Windows-Remote-Management-(WinRM)-and-Powershell-Part-II.aspx


#4

Hi John, Xav,

Is there someone in the field that can test kerberos authentication in the above sample script in the near term? It looks like it could take some time for me to get a Kerberos test environment up and running internally.

So theoretically, assuming a user has been authenticated using Kerberos to connect to the remote Windows server, allowing requests to use the cached service ticket (so long as it has not expired), what we need to focus on (as I understand it) is changing how we create the WinRM service in the above ruby code to:

WinRM::WinRMWebService.new(url, :kerberos, :realm => 'MYREALM.COM')

However, what is not clear to me is which user is authenticated? Is it the user currently logged in locally who I assume owns the kerberos ticket? Or can someone else be authenticated when prompted for the Client Secret Key? If we are running the above sample script from within Automate how would Kerberos authentication be configured then?

Any ideas?

Thanks
B


#5

The sample script above was modified to use Kerberos authentication and tested at a customer site. This required the following changes be made to the script:

  1. The parameters in the hash connect_params were modified as follows:

    connect_params = {
    :realm => ‘MYREALM.COM’,
    :user => “”, # username@realm
    :pass => “”,
    :basic_auth_only => false,
    :disable_sspi => false
    }

  2. Set the security protocol to “:kerberos” when creating the WinRM service:

    winrm = WinRM::WinRMWebService.new(url, :kerberos, connect_params)


#6

How can we use negotiate mechanism,since kerberos doesnot support windows from linux platform,negotiate is an integrated windows authentication na.

HERE IS MY CODE
winrm = WinRM::WinRMWebService.new(“XXX.XX.X.XXX”, :plaintext, :user => “administrator”, :pass => “p@ssw0rd1”, :basic_auth_only => true)do puts “connected successfully” end


#7

I realize this is an old thread but it has some very useful information. An update is needed for step 1) to the winrm setup commands for Win2012R2 server. The commands need to be wrapped in a set of single quotes as follows:

winrm set winrm/config/client/auth '@{Basic="true"}'
winrm set winrm/config/service/auth '@{Basic="true"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'