Beispiel #1
0
    def execute_cmd(self, command, encoding='437', environment=None):
        """
        Executes a command in a cmd shell and returns the stdout/stderr/rc of
        that process. This uses the raw WinRS layer and can be used to execute
        a traditional process.

        :param command: The command to execute
        :param encoding: The encoding of the output std buffers, this
            correlates to the codepage of the host and traditionally en-US
            is 437. This probably doesn't need to be modified unless you are
            running a different codepage on your host
        :param environment: A dictionary containing environment keys and
            values to set on the executing process.
        :return: A tuple of
            stdout: A unicode string of the stdout
            stderr: A unicode string of the stderr
            rc: The return code of the process

        Both stdout and stderr are returned from the server as a byte string,
        they are converted to a unicode string based on the encoding variable
        set
        """
        log.info("Executing cmd process '%s'" % command)
        with WinRS(self.wsman, environment=environment) as shell:
            process = Process(shell, command)
            process.invoke()
            process.signal(SignalCode.CTRL_C)

        return to_unicode(process.stdout, encoding), \
            to_unicode(process.stderr, encoding), process.rc
Beispiel #2
0
    def _put_file_old(self, in_path, out_path):
        script = u'''begin {
    $ErrorActionPreference = "Stop"
    $ProgressPreference = 'SilentlyContinue'

    $path = '%s'
    $fd = [System.IO.File]::Create($path)
    $algo = [System.Security.Cryptography.SHA1CryptoServiceProvider]::Create()
    $bytes = @()
} process {
    $bytes = [System.Convert]::FromBase64String($input)
    $algo.TransformBlock($bytes, 0, $bytes.Length, $bytes, 0) > $null
    $fd.Write($bytes, 0, $bytes.Length)
} end {
    $fd.Close()
    $algo.TransformFinalBlock($bytes, 0, 0) > $null
    $hash = [System.BitConverter]::ToString($algo.Hash)
    $hash = $hash.Replace("-", "").ToLowerInvariant()

    Write-Output -InputObject "{`"sha1`":`"$hash`"}"
}''' % out_path

        cmd_parts = self._shell._encode_script(script, as_list=True,
                                               strict_mode=False,
                                               preserve_rc=False)
        b_in_path = to_bytes(in_path, errors='surrogate_or_strict')
        if not os.path.exists(b_in_path):
            raise AnsibleFileNotFound('file or module does not exist: "%s"'
                                      % to_native(in_path))

        in_size = os.path.getsize(b_in_path)
        buffer_size = int(self.runspace.connection.max_payload_size / 4 * 3)
        sha1_hash = sha1()

        # copying files is faster when using the raw WinRM shell and not PSRP
        # we will create a WinRS shell just for this process
        # TODO: speed this up as there is overhead creating a shell for this
        with WinRS(self.runspace.connection, codepage=65001) as shell:
            process = Process(shell, cmd_parts[0], cmd_parts[1:])
            process.begin_invoke()

            offset = 0
            with open(b_in_path, 'rb') as src_file:
                for data in iter((lambda: src_file.read(buffer_size)), b""):
                    offset += len(data)
                    display.vvvvv("PSRP PUT %s to %s (offset=%d, size=%d" %
                                  (in_path, out_path, offset, len(data)),
                                  host=self._psrp_host)
                    b64_data = base64.b64encode(data) + b"\r\n"
                    process.send(b64_data, end=(src_file.tell() == in_size))
                    sha1_hash.update(data)

                # the file was empty, return empty buffer
                if offset == 0:
                    process.send(b"", end=True)

            process.end_invoke()
            process.signal(SignalCode.CTRL_C)

        return process.rc, process.stdout, process.stderr, sha1_hash.hexdigest()
Beispiel #3
0
 def test_winrs_standard(self, wsman_conn):
     with WinRS(wsman_conn) as shell:
         process = Process(shell, "cmd.exe", ["/c", "echo", "hi"])
         process.invoke()
         process.signal(SignalCode.CTRL_C)
         assert process.rc == 0
         assert process.stdout == b"hi\r\n"
         assert process.stderr == b""
Beispiel #4
0
 def test_winrs_unicode(self, wsman_conn):
     with WinRS(wsman_conn, codepage=65001) as shell:
         process = Process(shell, "powershell.exe", [u"Write-Host こんにちは"])
         process.invoke()
         process.signal(SignalCode.CTRL_C)
         assert process.rc == 0
         assert process.stdout.decode('utf-8') == u"こんにちは\n"
         assert process.stderr == b""
Beispiel #5
0
 def test_winrs_stderr_rc(self, wsman_conn):
     with WinRS(wsman_conn) as shell:
         process = Process(shell, "cmd.exe",
                           ["/c echo out && echo err>&2 && exit 1"])
         process.invoke()
         process.signal(SignalCode.CTRL_C)
         assert process.rc == 1
         assert process.stdout == b"out \r\n"
         assert process.stderr == b"err \r\n"
Beispiel #6
0
 def test_winrs_noprofile(self, wsman_conn):
     with WinRS(wsman_conn, no_profile=True) as shell:
         process = Process(shell, "cmd.exe", ["/c", "set"])
         process.invoke()
         process.signal(SignalCode.CTRL_C)
         assert process.rc == 0
         assert "USERPROFILE=C:\\Users\\Default" in \
                process.stdout.decode('utf-8').splitlines()
         assert process.stderr == b""
Beispiel #7
0
 def test_winrs(self, functional_transports):
     for wsman in functional_transports:
         with wsman, WinRS(wsman) as shell:
             process = Process(shell, "echo", ["hi"])
             process.invoke()
             process.signal(SignalCode.CTRL_C)
             assert process.rc == 0
             assert process.stdout == b"hi\r\n"
             assert process.stderr == b""
Beispiel #8
0
 def test_winrs_send(self, wsman_conn):
     with WinRS(wsman_conn) as shell:
         process = Process(shell, "powershell.exe", ["-"])
         process.begin_invoke()
         process.send(b"Write-Host \"output 1\";", end=False)
         process.send(b"Write-Host \"output 2\";")
         process.end_invoke()
         process.signal(SignalCode.CTRL_C)
         assert process.rc == 0
         assert process.stdout == b"output 1\noutput 2\n"
         assert process.stderr == b""
Beispiel #9
0
 def test_winrs_operation_timeout(self, wsman_conn):
     wsman_conn.operation_timeout = 10
     with WinRS(wsman_conn) as shell:
         process = Process(
             shell, "powershell.exe",
             ["Write-Host hi; Start-Sleep 30; Write-Host hi again"])
         process.invoke()
         process.signal(SignalCode.CTRL_C)
         assert process.rc == 0
         assert process.stdout == b"hi\nhi again\n"
         assert process.stderr == b""
Beispiel #10
0
def get_winRS(config):

    errors = 0
    results = []
    try:
        ssl = config['protocol'].split('/')[1]
    except Exception as e:
        ssl = ""
    for member in config['members'].split(','):
        res = ""
        try:
            if ssl:
                client = WSMan(member,
                               ssl=True,
                               auth="ntlm",
                               cert_validation=False,
                               connection_timeout=3,
                               username=config['user'],
                               password=config['password'])
            else:
                client = WSMan(member,
                               ssl=False,
                               auth="ntlm",
                               cert_validation=False,
                               connection_timeout=3,
                               username=config['user'],
                               password=config['password'])

            with WinRS(client) as shell:
                process = Process(shell, REMCMD)
                print(process)
                stdout, stderr, _rc = process.invoke()
            if "decode" in dir(stdout):
                res = stdout.decode()
                err = stderr.decode()
            else:
                res = stdout
                err = stderr
            if err:
                print("get_winRS: {} -> err: {}".format(config, err),
                      file=sys.stderr)
                errors += 1
        except Exception as e:
            print("get_winRS: Connect to {} failed: {}".format(
                member, e.args[0]),
                  file=sys.stderr)
            errors += 1

        results.append(res)

    return errors, config, results
Beispiel #11
0
    def test_winrs_extra_opts(self, wsman_conn):
        with WinRS(wsman_conn,
                   name="shell 1",
                   lifetime=60,
                   idle_time_out=60,
                   working_directory="C:\\Windows") as shell:
            assert shell.name == "shell 1"
            assert shell.lifetime == 60
            assert shell.idle_time_out == "PT60.000S"
            assert shell.working_directory == "C:\\Windows"

            process = Process(shell, "powershell.exe", ["(pwd).Path"])
            process.invoke()
            process.signal(SignalCode.CTRL_C)
            assert process.rc == 0
            assert process.stdout == b"C:\\Windows\r\n"
            assert process.stderr == b""
Beispiel #12
0
    def test_winrs_environment(self, wsman_conn):
        complex_chars = r'_-(){}[]<>*+-/\?"' '!@#$^&|;:i,.`~0'
        env_block = OrderedDict([
            ('env1', 'var1'),
            (1234, 5678),
            (complex_chars, complex_chars),
        ])

        with WinRS(wsman_conn, environment=env_block) as shell:
            process = Process(shell, "cmd.exe", ["/c", "set"])
            process.invoke()
            process.signal(SignalCode.CTRL_C)
            env_list = process.stdout.decode('utf-8').splitlines()
            assert process.rc == 0
            assert "env1=var1" in env_list
            assert "1234=5678" in env_list
            assert "%s=%s" % (complex_chars, complex_chars) in env_list
            assert process.stderr == b""
Beispiel #13
0
    def test_winrs_fail_poll_process(self, wsman_conn):
        with WinRS(wsman_conn) as shell:
            process = Process(shell, "cmd.exe", ["/c", "echo", "hi"])

            # if I poll before beginning it should fail
            with pytest.raises(WSManFaultError) as err:
                process.poll_invoke()
            assert err.value.code == 87
            assert err.value.message == \
                "Received a WSManFault message. (Code: 87, Machine: {0}, " \
                "Reason: The parameter is incorrect., Provider: Shell cmd " \
                "plugin, Provider Path: %systemroot%\\system32\\winrscmd.dll" \
                ", Provider Fault: The parameter is incorrect.)"\
                .format(err.value.machine)
            assert err.value.provider == "Shell cmd plugin"
            assert err.value.provider_fault == "The parameter is incorrect."
            assert err.value.provider_path == \
                "%systemroot%\\system32\\winrscmd.dll"
            assert err.value.reason == "The parameter is incorrect."
Beispiel #14
0
    def test_winrs_no_cmd_shell(self, wsman_conn):
        with WinRS(wsman_conn) as shell:
            process = Process(shell,
                              "powershell.exe", ["Write-Host", "hi"],
                              no_shell=True)

            # this will fail as you need to provide the full path when not
            # running in cmd shell
            with pytest.raises(WSManFaultError) as exc:
                process.invoke()
            assert exc.value.provider_fault == "The system cannot find the file specified."
            assert exc.value.code == 2147942402

            # fix the execute path and invoke again
            process.executable = r"C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe"
            process.invoke()
            process.signal(SignalCode.CTRL_C)

            assert process.rc == 0
            assert process.stdout == b"hi\n"
            assert process.stderr == b""
Beispiel #15
0
def arg_check():
    if len(sys.argv) < 2:
        print('Warning: Need to provide ip for windows instance.')
        sys.exit(1)


if __name__ == '__main__':
    arg_check()

    server = sys.argv[1]
    ps = sys.argv[2]

    # creates a http connection with no encryption and basic auth
    wsman = WSMan(server,
                  ssl=False,
                  auth="basic",
                  encryption="never",
                  username="******",
                  password="******")

    with WinRS(wsman) as shell:
        # execute a process with arguments in the background
        process = Process(shell, ps)
        process.begin_invoke()  # start the invocation and return immediately
        process.poll_invoke()  # update the output stream
        process.end_invoke()  # finally wait until the process is finished
        process.signal(SignalCode.CTRL_C)
        print('stdout', process.stdout)
        print('stderr', process.stderr)
        print('rc', process.rc)
Beispiel #16
0
    def copy(self, src, dest):
        """
        Copies a single file from the current host to the remote Windows host.
        This can be quite slow when it comes to large files due to the
        limitations of WinRM but it is designed to be as fast as it can be.
        During the copy process, the bytes will be stored in a temporary file
        before being copied.

        When copying it will replace the file at dest if one already exists. It
        also will verify the checksum of the copied file is the same as the
        actual file locally before copying the file to the path at dest.

        :param src: The path to the local file
        :param dest: The path to the destionation file on the Windows host
        :return: The absolute path of the file on the Windows host
        """
        def read_buffer(b_path, buffer_size):
            offset = 0
            sha1 = hashlib.sha1()

            with open(b_path, 'rb') as src_file:
                for data in iter((lambda: src_file.read(buffer_size)), b""):
                    log.debug("Reading data of file at offset=%d with size=%d"
                              % (offset, buffer_size))
                    offset += len(data)
                    sha1.update(data)
                    b64_data = base64.b64encode(data) + b"\r\n"

                    yield b64_data, False

                # the file was empty, return empty buffer
                if offset == 0:
                    yield b"", False

            # the last input is the actual file hash used to verify the
            # transfer was ok
            actual_hash = b"\x00\xffHash: " + to_bytes(sha1.hexdigest())
            yield base64.b64encode(actual_hash), True

        src = os.path.expanduser(os.path.expandvars(src))
        b_src = to_bytes(src)
        src_size = os.path.getsize(b_src)
        log.info("Copying '%s' to '%s' with a total size of %d"
                 % (src, dest, src_size))

        # check if the src size is twice as large as the max payload and fetch
        # the max size from the server, we only check in this case to save on a
        # round trip if the file is small enough to fit in 2 msg's, otherwise
        # we want to get the largest size possible
        buffer_size = int(self.wsman.max_payload_size / 4 * 3)
        if src_size > (buffer_size * 2) and \
                self.wsman.max_envelope_size == 153600:
            log.debug("Updating the max WSMan envelope size")
            self.wsman.update_max_payload_size()
            buffer_size = int(self.wsman.max_payload_size / 4 * 3)
        log.info("Creating file reader with a buffer size of %d" % buffer_size)
        read_gen = read_buffer(b_src, buffer_size)

        command = u'''begin {
    $ErrorActionPreference = "Stop"
    $path = [System.IO.Path]::GetTempFileName()
    $fd = [System.IO.File]::Create($path)
    $algo = [System.Security.Cryptography.SHA1CryptoServiceProvider]::Create()
    $bytes = @()
    $expected_hash = ""
} process {
    $base64_string = $input

    $bytes = [System.Convert]::FromBase64String($base64_string)
    if ($bytes.Count -eq 48 -and $bytes[0] -eq 0 -and $bytes[1] -eq 255) {
        $hash_bytes = $bytes[-40..-1]
        $expected_hash = [System.Text.Encoding]::UTF8.GetString($hash_bytes)
    } else {
        $algo.TransformBlock($bytes, 0, $bytes.Length, $bytes, 0) > $null
        $fd.Write($bytes, 0, $bytes.Length)
    }
} end {
    $output_path = "%s"
    $dest = New-Object -TypeName System.IO.FileInfo -ArgumentList $output_path
    $fd.Close()

    try {
        $algo.TransformFinalBlock($bytes, 0, 0) > $null
        $actual_hash = [System.BitConverter]::ToString($algo.Hash)
        $actual_hash = $actual_hash.Replace("-", "").ToLowerInvariant()

        if ($actual_hash -ne $expected_hash) {
            $msg = "Transport failure, hash mistmatch"
            $msg += "`r`nActual: $actual_hash"
            $msg += "`r`nExpected: $expected_hash"
            throw $msg
        }
        [System.IO.File]::Copy($path, $output_path, $true)
        $dest.FullName
    } finally {
        [System.IO.File]::Delete($path)
    }
}''' % to_unicode(dest)
        encoded_command = to_string(base64.b64encode(to_bytes(command,
                                                              'utf-16-le')))

        with WinRS(self.wsman) as shell:
            process = Process(shell, "powershell.exe",
                              ["-NoProfile", "-NonInteractive",
                               "-EncodedCommand", encoded_command])
            process.begin_invoke()
            log.info("Starting to send file data to remote process")
            for input_data, end in read_gen:
                process.send(input_data, end)
            log.info("Finished sending file data to remote process")
            process.end_invoke()

        stderr = self.sanitise_clixml(process.stderr)
        if process.rc != 0:
            raise WinRMError("Failed to copy file: %s" % stderr)
        output_file = to_unicode(process.stdout).strip()
        log.info("Completed file transfer of '%s' to '%s'"
                 % (src, output_file))
        return output_file
Beispiel #17
0
 def test_winrs_open_already_opened(self, wsman_conn):
     with WinRS(wsman_conn) as shell:
         shell.open()
     shell.close()