Execute PowerShell from Python

I originally wrote this to execute PowerShell scripts from a Flask web interface. You can now install Powershell on Linux. Crazy, ain’t it?

import subprocess
import datetime
import time
import os
import ast 
import json
# =======================================================
# Original name: lib_powershell.py
# =======================================================

class PowerShellProc():

    def __init__(self):
        self.pwrshell_path = r'C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe'
        self.station = r'\\repo\ps' # where the PS scripts live.

    def exec_pwrshell(self, pwr_script=None, script_path=None, args=[], ps_tuple_to_py=True, gm_flag=False, date2str=False):
        '''Out.exec_pwrshell('psscript.ps1' ,script_path=None, ps_tuple_to_py=True)
        script_path: overrides envrionment path.exists
        ps_tuple_to_py: Powershell tuples convert to dictionaries, set True to return a Python tuple.
        '''
        data = None
        exec_path = self.pwrshell_path
        
        if not os.path.exists(exec_path):
            raise IOError('Powershell not found at %s.' % exec_path)

        if not script_path:
            script_path = self.station
        
        if not os.path.exists(script_path):
            raise IOError('Script path not found at %s.' % script_path)

        if pwr_script:
            script_path = os.path.join(script_path, pwr_script)

        cmd = [exec_path, script_path]
        
        if args:
            if not isinstance(args, list):
                raise TypeError("Arguments must be passed as a list not %s." % str(type(args)))
            cmd.extend(args)

        proc = subprocess.Popen(cmd, 
                    shell=True,
                    stdin=subprocess.PIPE,
                    stdout=subprocess.PIPE,
                    )
        
        rtrn,perr = proc.communicate()
        rcode = proc.returncode

        #if rtrn:
            # Line directly below converts PowerShell Json to Python data structs.
            #data = self.ps_output_converstion(rtrn, tup=ps_tuple_to_py, gm=gm_flag, date2str=date2str)
        if perr:
            # Error string...
            data = json.dumps(perr.decode('utf-8','ignore'))
        else:
            #data = rtrn.decode('utf-8','ignore')
            data = self.ps_output_converstion(rtrn, tup=ps_tuple_to_py, gm=gm_flag, date2str=date2str)
        return rcode,data

    def ps_output_converstion(self, res, tup=True, gm=False, date2str=True):
        '''Converts Powershell string output to Python type'''
        
        res = res.decode('utf-8','ignore')
        
        if '\n' in res:
            res = res.replace('\n','')
        if '\r' in res:
            res = res.split('\r')[0]

        res = ast.literal_eval(res)
        
        # Data conversion if necessary.
        if type(res) == str:
            if 'date' in res.lower() or 'time' in res.lower():
                epoch_elem = elem[elem.find("(")+1:elem.rfind(")")]
                dt = self.ps_epoch_to_datetime(float(elem), gm=gm, date2str=date2str)
                res = dt
        if type(res) == list:
            for index, elem in enumerate(res):
                if 'date' in str(elem).lower() or 'date' in str(elem).lower():
                    epoch_elem = elem[elem.find("(")+1:elem.rfind(")")]
                    dt = self.ps_epoch_to_datetime(float(elem), gm=gm, date2str=date2str)
                    res.remove(elem)
                    res.insert(index,dt)
        if type(res) == dict:
            for field, value in res.items():
                if 'date' in str(value).lower():
                    epoch_elem = value[value.find("(")+1:value.rfind(")")]
                    dt = self.ps_epoch_to_datetime(float(epoch_elem), gm=gm, date2str=date2str)
                    res[field] = dt
            if tup:
                if 'Item1' in res:
                    l = [v for v in res.values()]
                    res = tuple(l)
        return res

    def ps_epoch_to_datetime(self, epoch_time, gm=False, date2str=False):
        '''Converts Powershell Date to Python datetime.'''
        if gm:
            struct = time.gmtime(epoch_time/1000.)
        else:
            struct = time.localtime(epoch_time/1000.)

        dt = datetime.datetime.fromtimestamp(time.mktime(struct))
        if date2str: dt = dt.ctime()
        return dt

    def py2json(self, data):
        return json.dumps(data) # This will convert datetime to string.

    def json2py(self, data):
        return json.loads(data)

'''
Examples of various data structures returned by a Powershell script.

>>> import lib_powershell
>>> ps = lib_powershell.PowerShellProc()
>>> ps.exec_pwrshell(pwr_script='test.ps1',script_path=r'E:\pyprod\prod_pwrshell',ps_tuple_to_py=False) # Tuple to dict.
(0, {'Item3': 1, 'Length': 3, 'Item1': 'Theresa Wilson', 'Item2': datetime.datetime(2018, 1, 1, 6, 0)})

>>> ps.exec_pwrshell(pwr_script='test.ps1',script_path=r'E:\pyprod\prod_pwrshell')
(0, (1, 3, 'Theresa Wilson', datetime.datetime(2018, 1, 1, 6, 0)))

>>> ps.exec_pwrshell(pwr_script='test.ps1',script_path=r'E:\pyprod\prod_pwrshell', gm_flag=True) # Mixed Tuple
(0, (1, 3, 'Theresa Wilson', datetime.datetime(2018, 1, 1, 11, 0)))

>>> ps.exec_pwrshell(pwr_script='test.ps1',script_path=r'E:\pyprod\prod_pwrshell')
(0, {'Oregon': 'Salem', 'Washington': 'Olympia', 'California': 'Sacramento'})

>>> ps.exec_pwrshell(pwr_script='test.ps1',script_path=r'E:\pyprod\prod_pwrshell') # Mixed array/arraylist
(0, ['a', 'b', 'c', 'd', 'e', 1, 2, 3])

>>> ps.exec_pwrshell(pwr_script='test.ps1',script_path=r'E:\pyprod\prod_pwrshell') # Int
(0, 1)

>>> ps.exec_pwrshell(pwr_script='test.ps1',script_path=r'E:\pyprod\prod_pwrshell') # String
(0, 'Hello')

# NOTE: Tuple returned is (process_return_code, powershell_return_data)
'''