python3 PowerShell stdout 西里尔语编码

python3 powershell stdout cyrillic encoding

提问人:Norbert Yuhas 提问时间:9/20/2023 最后编辑:Norbert Yuhas 更新时间:9/21/2023 访问量:54

问:

我需要执行以下操作:我通过 ssh 从 Python 连接到 Windows 服务器,并在其上运行 powershell 命令。我需要从该服务器获得响应并进一步使用它。 如果我提出这样的请求:

command_company = (
            'powershell.exe -noprofile -command "'
            'Get-ADUser -Filter \\"sAMAccountName -like \'j.d\'\\" -Properties sAMAccountName, Mobile | Select-Object -ExpandProperty Mobile"'
        )

然后一切都对我有用,我得到了一个手机号码。 如果我确实喜欢这样:

command_company = (
            'powershell.exe -noprofile -command "'
            'Get-ADUser -Filter \\"sAMAccountName -like \'j.d\'\\" -Properties sAMAccountName, Company | Select-Object -ExpandProperty Company"'
        )

那么我没有收到错误:

powershell.exe -noprofile -command "Get-ADUser -Filter \"sAMAccountName -like 'j.d'\" -Properties sAMAccountName, Company | Select-Object -ExpandProperty Company"
env: {}, command: powershell.exe -noprofile -command "Get-ADUser -Filter \"sAMAccountName -like 'j.d'\" -Properties sAMAccountName, Company | Select-Object -ExpandProperty Company", subsystem: None, exit_status: None, exit_signal: None, returncode: None, stdout: , stderr:
Output:
Exit Code: None

我猜这可能是 powershell 发送的响应的编码问题。 如果我直接在 PS 中执行请求

Get-ADUser -Filter "sAMAccountName -like 'j.d'" -Properties sAMAccountName, Company | Select-Object -ExpandProperty Company

我得到答案:

PS C:\Windows\system32> C:\ServiceScripts\Test.ps1
ООО МерседесБенцРус

如何更改响应编码?

完整代码:

async def run_ssh_command(user_login):
    async with asyncssh.connect(edited) as conn:

        command_company = (
            'powershell.exe -noprofile -command "'
            'Get-ADUser -Filter \\"sAMAccountName -like \'j.d\'\\" -Properties sAMAccountName, Company | Select-Object -ExpandProperty Company"'
        )
        print(command_company)
        result = await conn.run(command_company)
        print(result)
        output_company = result.stdout
        exit_code = result.exit_status
        print(f"Output: {output_company}")
        print(f"Exit Code: {exit_code}")
        await client.send_message(chat_id, f'From: {output_company}', reply_to=reply_to_msg_id)
        return output_company
Python PowerShell 编码 UTF-8

评论


答:

0赞 Norbert Yuhas 9/20/2023 #1

我用paramiko替换了ssh,选择了cp866作为编码 在此版本中,一切正常:

async def run_ssh_command(user_login):
    client = paramiko.SSHClient()

    try:
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        client.connect('Edited')

        command_company = (
            'powershell.exe -noprofile -command "'
            'Get-ADUser -Filter \'sAMAccountName -like \'\'{0}\'\'\' -Properties sAMAccountName, Company | Select-Object -ExpandProperty Company"'.format(user_login)
        )

        print(command_company)

        stdin, stdout, stderr = client.exec_command(command_company)

        output_company = stdout.read().decode('cp866')

        exit_code = stdout.channel.recv_exit_status()

        print(f"Output: {output_company}")
        print(f"Exit Code: {exit_code}")

        return output_company

    except Exception as e:
        print(f"An error occurred: {str(e)}")
        return None

    finally:
        client.close()
1赞 mklement0 9/21/2023 #2

通过切换到不同的 SSH 库,您似乎找到了解决方案,该库允许您指定用于解码显式接收的 stdout 输出的字符编码。

  • 让我补充一些背景信息......

  • ...并提供可能适用于您的原始代码的 Python v3+ 解决方案:我不知道 SSH 如何影响这一点(您的原始库 asyncsh 声称使用 UTF-8),但下面的示例代码肯定适用于使用 UTF-8 的本地 PowerShell 调用,如图所示。


两个版本中的 PowerShell CLI(适用于 Windows PowerShell.exe 的 PowerShell、适用于 PowerShell (Core) 7+ 的 pwsh.exe) ) 基于活动(输出)控制台代码页(默认为系统的 OEM 代码页)对其 stdout 输出进行编码

如果不想对其进行硬编码,就像在代码中一样,可以使用以下命令来确定它:

from ctypes import windll; cp = windll.kernel32.GetConsoleOutputCP()

如果要改用 UTF-8(如果 PowerShell 命令输出无法在 OEM 代码页中表示的字符),则必须使用 UTF-8,可以执行以下操作:

import subprocess
import sys
from ctypes import windll

# Sample text containing an ASCII char., 
# a non-ASCII char that can be mapped onto at least some OEM code pages, 
# and one that cannot.  
text = 'e€╳' 
# A sample PowerShell command that simply echoes the text.
command = f"powershell.exe -noprofile -c '{text}'"

# Save the current console output code page and temporarily change it to
# UTF-8 (65001)
oldCp = windll.kernel32.GetConsoleOutputCP()
windll.kernel32.SetConsoleOutputCP(65001)

# Call the PowerShell CLI, which now emits UTF-8 text.
# Note the use of .decode(), which is based on sys.getdefaultencoding(), 
# which is UTF-8 in v3+, and the .strip() call to remove a trailing newline.
out = subprocess.run(command, stdout=subprocess.PIPE).stdout.decode().strip()

# Restore the previous output console code page.
windll.kernel32.SetConsoleOutputCP(oldCp)

# Print the captured output and its byte representation.
print('received text: ' + out)
print(out.encode()) # byte representation

注意:

  • 以上仅确保 PowerShell 子进程发出 UTF-8,并且其输出在 Python 进程中解码,这与 Python 本身用于其输出流的字符编码无关。

  • 要将 Python v3.7+ 本身置于 Python UTF-8 模式,使其将输入解码为 UTF-8 并生成 UTF-8 输出,请传递命令行选项或定义值为 before 调用的环境变量。-X utf8PYTHONUTF81

    • (仅)如果这样做,则上述调用的替代方法是将作为附加参数传递给调用。.decode()text=Truesubprocess.run()

    • 独立地,作为附加参数传递而不是调用也是一种选择。encoding='utf-8'.decode()