Как получить отрицательные коды возврата от powershell до ansible - PullRequest
2 голосов
/ 20 апреля 2020

Я пытаюсь вернуть отрицательный код возврата из скрипта PowerShell (.ps1) в Ansible. Однако коды -ve, которые возвращает скрипт, по некоторым причинам преобразуются в большое + ve целое число. Скрипт работает нормально, если коды возврата + целые числа ve.

BTW Большое целое число + ve можно вычислить следующим образом:

4294967197 = 4294967296-99 (где -99 - код возврата от PowerShell и 4294967296 = 4

C:\> powershell -NoProfile %USERPROFILE%\Documents\ps_file_create.ps1

C:\> echo %errorlevel%
-99
* 3)

Цените любую помощь. Спасибо!

Подробности:

  • ansible версия: 2.9.6
  • PS Версия: 5.1.14393.3383
  • Windows: Server 2016 версия 1607 (сборка ОС 14393.3383)
  • python: 2.7.5

Также, если я попробую это из командной строки Windows, это будет работать! :

*1024*

Это то, что я пробовал ... все, что я прокомментировал в скриптах ansible / ps ниже, я попробовал (я также попробовал win_shell и получил те же результаты)

PowerShell Скрипт (ps_file_create.ps1):

$return_code = -99  ## createfile $FileName
#return $return_code
#exit $return_code
$host.SetShouldExit($return_code)
exit

Ansible код:

  - name: Execute the PowerShell Script that returns a -ve return code 
    #win_command: powershell -NonInteractive -NoProfile Invoke-Expression -Command ".\ps_file_create.ps1" 
    #win_command: powershell -NonInteractive -NoProfile .\ps_file_create.ps1
    #win_command: powershell -NonInteractive -NoProfile -file ".\ps_file_create.ps1" 
    #win_command: powershell -NonInteractive -NoProfile -Command ".\ps_file_create.ps1" 
    win_command: powershell .\ps_file_create.ps1 
    args:
      chdir: '%USERPROFILE%\Documents'
    register: win_ps_out   
    ignore_errors: true       

  - name: Print Results of tasks
    debug:
      msg: 
        - "Powershell Out put: {{ win_ps_out  | to_nice_json}}"

Вывод:

TASK [Print Results of tasks]*****************************************************************
    ok: [myserver.xyz.abc.com] =>
      msg:
      - |-
        Powershell Out put: {
            "changed": true,
            "cmd": "powershell .\\ps_file_create.ps1",
            "delta": "0:00:00.532040",
            "end": "2020-04-20 01:32:30.515580",
            "failed": true,
            "msg": "non-zero return code",
            "rc": 4294967197,  ##  Expected -99 ##
            "start": "2020-04-20 01:32:29.983539",
            "stderr": "",
            "stderr_lines": [],
            "stdout": "",
            "stdout_lines": []
        }

Ответы [ 2 ]

1 голос
/ 20 апреля 2020

Что произойдет, если в вашем скрипте PowerShell вы просто попробуете:

exit -99

, несмотря на использование $host.SetShouldExit($return_code)

При использовании cmd.exe, я пытаюсь сделать так, что результат выглядит следующим образом Хорошо:

c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -command "exit -99"
echo %errorlevel%
-99

На самом деле ваш код дает тот же результат:

c:\windows\system32\WindowsPowerShell\v1.0\powershell.exe -command "$host.SetShouldExit(-99)"
echo %errorlevel%
-99

Вы должны взглянуть на сторону Ansible, где он, похоже, интерпретируется как 64-битный, на стороне PowerShell это 32 бита.

0 голосов
/ 22 апреля 2020

Короче говоря, вот обходной путь. Вы можете определить условные задачи или условный вывод следующим образом:

---
- hosts: windows
  tasks:
  - name: Execute the PowerShell Script that returns a -ve return code
    win_command: powershell .\ps_file_create.ps1 
    args:
      chdir: '%USERPROFILE%\Documents'
    register: win_ps_out   
    ignore_errors: true       

  - name: Conditional task for positive rc
    debug:
      msg: "PowerShell rc: {{ win_ps_out.rc }}"
    when: win_ps_out.rc <= 2147483647

  - name: Conditional task for negative rc
    debug:
      msg: "PowerShell rc: {{ win_ps_out.rc - 4294967296 }}"
    when: win_ps_out.rc > 2147483647

  - name: Conditional output
    debug:
      msg: "PowerShell rc: {% if win_ps_out.rc > 2147483647 %}{{ win_ps_out.rc - 4294967296 }}{% else %}{{ win_ps_out.rc }}{% endif %}"

Вывод для кода возврата 42:

TASK [Conditional task for positive rc] ****************************************
ok: [192.168.0.200] => {
    "msg": "PowerShell rc: 42"
}

TASK [Conditional task for negative rc] ****************************************
skipping: [192.168.0.200]

TASK [Conditional output] ******************************************************
ok: [192.168.0.200] => {
    "msg": "PowerShell rc: 42"
}

И для кода возврата -99:

TASK [Conditional task for positive rc] ****************************************
skipping: [192.168.0.200]

TASK [Conditional task for negative rc] ****************************************
ok: [192.168.0.200] => {
    "msg": "PowerShell rc: -99"
}

TASK [Conditional output] ******************************************************
ok: [192.168.0.200] => {
    "msg": "PowerShell rc: -99"
}

Фон

Код возврата, указанный в вопросе, является "правильным". Двоичное представление отрицательного целочисленного значения обычно вычисляется методом two'splement . Например, двоичное представление -99 (использующее 32 бита):

‭1111 1111 1111 1111 1111 1111 1001 1101‬

Но, читая эти биты, вы не знаете, представляют ли они отрицательное число в форме дополнения до двух или просто большое положительное число. Вы можете интерпретировать эти биты либо как небольшое отрицательное число -99, либо как большое положительное число 4.294.967.197, которое вы видите в своих выходных данных.

PowerShell возвращает именно те 4 байта, которые показаны выше. Вы можете подтвердить, что PowerShell использует 32-разрядные коды выхода даже в 64-разрядной операционной системе:

PS C:\> [Environment]::Is64BitProcess -and [Environment]::Is64BitOperatingSystem
True
PS C:\> $process = Start-Process powershell -ArgumentList "exit 0xffffffff" -Wait -PassThru
PS C:\> $process.ExitCode
-1
PS C:\> $process = Start-Process powershell -ArgumentList "exit 0x1ffffffff" -Wait -PassThru
PS C:\> $process.ExitCode
0
PS C:\> $process.ExitCode.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Int32                                    System.ValueType

Вы можете видеть, что код выхода имеет тип Int32, а также что PowerShell имеет код выхода 0, если «реальный» код выхода превышает диапазон Int32.

Так что PowerShell здесь не делает ничего плохого. Пользователь, который оценивает эти 4 байта, должен интерпретировать их как целое число со знаком или без знака. Так что до ansible.

Насколько я знаю, у вас не так много возможностей повлиять ansible на то, как получить результаты от задачи. Для обработки результатов вы можете использовать только фильтры и алгоритмы.

Насколько я знаю, не существует такого типа приведения типов ({{ win_ps_out.rc | int }} на самом деле является фильтром jinja2, а не приведением типов). И ansible, похоже, не заботится о переменных размерах. Например, ansible не знает int32 или int64. Просто int, и это может быть очень большое число, даже большее, чем int64. Итак, что делает ansible, это берет 4 байта из PowerShell и сохраняет их как целое число с дополнительными - я не знаю, сколько - ведущими нулями. Это будет пример для 64 битов:

‭0000 0000 0000 0000 0000 0000 0000 0000 1111 1111 1111 1111 1111 1111 1001 1101‬

Теперь это число не может быть интерпретировано как отрицательное число в форме дополнения до двух, потому что самый старший бит установлен в 0. Это может быть интерпретировано как 4.294.967.197, что происходит в вашем случае.

Теперь вы можете обработать это значение. В верхней части моего ответа я представляю два обходных пути для обработки возвращенного значения и обработки его как целого числа со знаком размером 32 бита.

...