From 625c86109e121dc0cef2931d187ca0d1a0e8baf7 Mon Sep 17 00:00:00 2001 From: Alessandro Pilotti Date: Tue, 4 Mar 2014 01:53:45 +0200 Subject: [PATCH] Executes Powershell as sysnative by default "ps1" and "ps1_sysnative" Powershell scripts are executed as sysnative when present. "ps1_x86" has been introduced to forcefully execute the script in a syswow64 Powershell. Multi part Powershell text/x-shellscript content is always executed as sysnative when available. --- cloudbaseinit/osutils/windows.py | 37 ++++++++++++++++++ .../windows/userdataplugins/shellscript.py | 16 +++++--- .../plugins/windows/userdatautils.py | 39 ++++++++----------- 3 files changed, 64 insertions(+), 28 deletions(-) diff --git a/cloudbaseinit/osutils/windows.py b/cloudbaseinit/osutils/windows.py index f4413376..ae294f6d 100644 --- a/cloudbaseinit/osutils/windows.py +++ b/cloudbaseinit/osutils/windows.py @@ -16,6 +16,7 @@ import _winreg import ctypes +import os import re import time import win32process @@ -661,3 +662,39 @@ class WindowsUtils(base.BaseOSUtils): fw_protocol = self._get_fw_protocol(protocol) fw_profile = fw_profile.GloballyOpenPorts.Remove(port, fw_protocol) + + def is_wow64(self): + ret_val = wintypes.BOOL() + if not kernel32.IsWow64Process(kernel32.GetCurrentProcess(), + ctypes.byref(ret_val)): + raise Exception("IsWow64Process failed") + return bool(ret_val.value) + + def get_system32_dir(self): + return os.path.expandvars('%windir%\\system32') + + def get_sysnative_dir(self): + return os.path.expandvars('%windir%\\sysnative') + + def check_sysnative_dir_exists(self): + sysnative_dir_exists = os.path.isdir(self.get_sysnative_dir()) + if not sysnative_dir_exists and self.is_wow64(): + LOG.warning('Unable to validate sysnative folder presence. ' + 'If Target OS is Server 2003 x64, please ensure ' + 'you have KB942589 installed') + return sysnative_dir_exists + + def execute_powershell_script(self, script_path, sysnative=True): + if sysnative and self.check_sysnative_dir_exists(): + base_dir = self.get_sysnative_dir() + else: + base_dir = self.get_system32_dir() + + powershell_path = os.path.join(base_dir, + 'WindowsPowerShell\\v1.0\\' + 'powershell.exe') + + args = [powershell_path, '-ExecutionPolicy', 'RemoteSigned', + '-NonInteractive', '-File', script_path] + + return self.execute_process(args, False) diff --git a/cloudbaseinit/plugins/windows/userdataplugins/shellscript.py b/cloudbaseinit/plugins/windows/userdataplugins/shellscript.py index 1063ab10..959998c9 100644 --- a/cloudbaseinit/plugins/windows/userdataplugins/shellscript.py +++ b/cloudbaseinit/plugins/windows/userdataplugins/shellscript.py @@ -33,19 +33,18 @@ class ShellScriptPlugin(base.BaseUserDataPlugin): file_name = part.get_filename() target_path = os.path.join(tempfile.gettempdir(), file_name) + shell = False + powershell = False + if file_name.endswith(".cmd"): args = [target_path] shell = True elif file_name.endswith(".sh"): args = ['bash.exe', target_path] - shell = False elif file_name.endswith(".py"): args = ['python.exe', target_path] - shell = False elif file_name.endswith(".ps1"): - args = ['powershell.exe', '-ExecutionPolicy', 'RemoteSigned', - '-NonInteractive', '-File', target_path] - shell = False + powershell = True else: # Unsupported LOG.warning('Unsupported script type') @@ -54,7 +53,12 @@ class ShellScriptPlugin(base.BaseUserDataPlugin): try: with open(target_path, 'wb') as f: f.write(part.get_payload()) - (out, err, ret_val) = osutils.execute_process(args, shell) + + if powershell: + (out, err, + ret_val) = osutils.execute_powershell_script(target_path) + else: + (out, err, ret_val) = osutils.execute_process(args, shell) LOG.info('User_data script ended with return code: %d' % ret_val) LOG.debug('User_data stdout:\n%s' % out) diff --git a/cloudbaseinit/plugins/windows/userdatautils.py b/cloudbaseinit/plugins/windows/userdatautils.py index 82c09384..4f7ac869 100644 --- a/cloudbaseinit/plugins/windows/userdatautils.py +++ b/cloudbaseinit/plugins/windows/userdatautils.py @@ -26,6 +26,10 @@ LOG = logging.getLogger(__name__) def execute_user_data_script(user_data): osutils = osutils_factory.get_os_utils() + shell = False + powershell = False + sysnative = True + target_path = os.path.join(tempfile.gettempdir(), str(uuid.uuid4())) if re.search(r'^rem cmd\s', user_data, re.I): target_path += '.cmd' @@ -34,31 +38,16 @@ def execute_user_data_script(user_data): elif re.search(r'^#!/usr/bin/env\spython\s', user_data, re.I): target_path += '.py' args = ['python.exe', target_path] - shell = False elif re.search(r'^#!', user_data, re.I): target_path += '.sh' args = ['bash.exe', target_path] - shell = False - elif re.search(r'^#ps1\s', user_data, re.I): + elif re.search(r'^#(ps1|ps1_sysnative)\s', user_data, re.I): target_path += '.ps1' - args = ['powershell.exe', '-ExecutionPolicy', 'RemoteSigned', - '-NonInteractive', '-File', target_path] - shell = False - elif re.search(r'^#ps1_sysnative\s', user_data, re.I): - if os.path.isdir(os.path.expandvars('%windir%\\sysnative')): - target_path += '.ps1' - args = [os.path.expandvars('%windir%\\sysnative\\' - 'WindowsPowerShell\\v1.0\\' - 'powershell.exe'), - '-ExecutionPolicy', - 'RemoteSigned', '-NonInteractive', '-File', target_path] - shell = False - else: - # Unable to validate sysnative presence - LOG.warning('Unable to validate sysnative folder presence. ' - 'If Target OS is Server 2003, please ensure you ' - 'have KB942589 installed') - return 0 + powershell = True + elif re.search(r'^#ps1_x86\s', user_data, re.I): + target_path += '.ps1' + powershell = True + sysnative = False else: # Unsupported LOG.warning('Unsupported user_data format') @@ -67,7 +56,13 @@ def execute_user_data_script(user_data): try: with open(target_path, 'wb') as f: f.write(user_data) - (out, err, ret_val) = osutils.execute_process(args, shell) + + if powershell: + (out, err, + ret_val) = osutils.execute_powershell_script(target_path, + sysnative) + else: + (out, err, ret_val) = osutils.execute_process(args, shell) LOG.info('User_data script ended with return code: %d' % ret_val) LOG.debug('User_data stdout:\n%s' % out)