Python – Executer des commandes sur une machine Windows distante.

par | Juin 26, 2025 | Script, Uncategorized | 0 commentaires

Le script ci-dessous propose d’utiliser le module pypsrp (https://pypi.org/project/pypsrp/) pour executer n’importe quelle commande (cmd/powershell) sur une machine windows distante.

Dans cet exemple l’authentification se fait via kerberos, mais le parametre auth de wsman peut utiliser basiccertificatenegotiatentlmkerberoscredssp

wsman = WSMan(target, ssl=False, auth='kerberos')

Par defaut le mode winrm utilisé (–winrm-mode) est runspacepool qui est plus compatible avec des commandes ou des blocs de code powershell.

Un test de connectivité winrm (–test-winrm-port, par defaut activé) permet de tester la connexion avant d’executer la commande.

Le paramètre –execute-remote-action etant par defaut desactivé (False), il est necessaire de l’activer (–execute-remote-action True) pour executer effectivement la commande.

help = """
SCRIPT D'EXECUTION DE COMMANDES WINRM SUR UNE MACHINE WINDOWS CIBLE DEFINIE EN ARGUMENT.

Description :
Ce script a été développé à l'occasion d'une demande de reboots récurrents de nombreuses machines Windows. Il a été implémenté de manière à pouvoir être réutilisé pour d'autre commandes `winrm` que le reboot.


ARGUMENTS:
- --get-help True: Affiche l'aide.
- --win-computer: Nom de la machine cible Windows sur laquelle exécuter la commande. (Requis)
- --execute-remote-action True: Execute les actions sur les machines distantes. (Valeur par défaut: False)
- --remote-command: Commande à exécuter sur les machines distantes. (Valeur par défaut: whoami)
- --test-winrm-port True: Test de la connexion au port WinRM des machines distantes avec le module socket. (Valeur par défaut: True)
- --winrm-mode: methode d'execution de la commande sur la machine distante. (Valeur par défaut: runspacepool)




Exemple d'utilisation:
  - Executer la commande "whoami" sur la machine "mycomputer" avec le test de connexion au port WinRM:
  python run_winrm_cmd_on_host.py --win-computer mycomputer --execute-remote-action True --test-winrm-port True --remote-command "get-process"

  

  """


import sys
import os
import argparse
from pypsrp.shell import Process, WinRS
from pypsrp.powershell import PowerShell, RunspacePool
from pypsrp.wsman import WSMan
import socket


if __name__ == '__main__':


        ###########################################
        # Arguments du script
        ###########################################

        
        parser = argparse.ArgumentParser()

        parser.add_argument(
        '--get-help',
        type=str,
        choices=['True', 'False'],
        default='False',
        help='Affiche l\'aide.'
        )

        parser.add_argument(
        '--win-computer',
        type=str,
        help='machine cible Windows'
        )

        parser.add_argument(
        '--execute-remote-action',
        type=str,
        choices=['True', 'False'],
        default='False',
        help='Execute effectivement les actions sur les machines distantes.'
        )

        parser.add_argument(
        '--remote-command',
        type=str,
        default="whoami",
        help='Commande à exécuter sur les machines distantes.'
        )

        parser.add_argument(
        '--test-winrm-port',
        type=str,
        choices=['True', 'False'],
        default='True',
        help='Test de la connexion au port WinRM des machines distantes avec le module socket.'
        )

        parser.add_argument(
        '--winrm-mode',
        type=str,
        choices=['winrs', 'runspacepool'],
        default='runspacepool',
        help='methode d\'execution de la commande sur la machine distante.'
        )


        args = parser.parse_args()
        

        if args.get_help == 'True':
                print(
                help        
                )
                sys.exit(0)


           

        ############################################################################
        ### VERIFICATION DE LA CONNEXION A LA MACHINE CIBLE AVEC LE MODULE SOCKET
        ############################################################################
        
        if args.test_winrm_port == 'True':
                print("---------------------------------------------------------------------------------------------------------------------------------------------")
                print(f"TEST DE RESOLUTION DE NOM ET CONNEXION AU PORT 5985 (WINRM) pour la machine {args.win_computer} avec le module socket")
                print("---------------------------------------------------------------------------------------------------------------------------------------------")


                try:
                                
                                sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                                sock.settimeout(5)
                                sockresult = sock.connect_ex((args.win_computer,5985))

                                if not socket.gethostbyname(args.win_computer):
                                        print("!!! resolution KO pour " + args.win_computer +"!!!")
                                        wincomputer_resolved = False
                                        exit(1)
                                        
                                        

                                if not (sockresult == 0):
                                        print("!!! WinRM TCP KO pour  " + args.win_computer +"!!!")
                                        wincomputer_resolved = True
                                        winrm_port_open = False
                                        exit(1)
                                        
                                        
                                
                                else:
                                        print("resolution OK et WinRM OK pour " + args.win_computer )
                                        
                                sock.close()
                               
                except Exception as error:
                                print(f"ERREUR: {error}")
                                exit(1)
                                

                                

                print("---------------------------------------------------------------------------------------------------------------------------------------------")


        
        ########################################
        ### ACTION SUR LA MACHINE AVEC WINRM
        ########################################
        


# Action executee si argument execute_remote_action = True et si la machine est joignable
        if args.execute_remote_action == 'True':
        

                

                        ### METHODE 1: WINRS
                        if args.winrm_mode == 'winrs':

                                try:
                                        target = args.win_computer
                                        print(f"EXECUTION DE LA COMMANDE SUR LA MACHINE \"{target}\"")
                                        print("------------------------------------------------------------------------------------------------------------------------------")
                                        #creates a http connection with no encryption and kerberos auth
                                        wsman = WSMan(target, ssl=False, auth='kerberos')
                                        
                                        # # create a shell with wsman
                                        with wsman, WinRS(wsman) as shell:
                                                # execute a process with arguments in the background
                                                process = Process(shell, args.remote_command)
                                                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
                                                output = str(process.stdout, errors='ignore')
                                                print(output)
                                                print("------------------------------------------------------------------------------------------------------------------------------\r")



                                except Exception as error:
                                        print(f"ERREUR: {error}")
                                        pass

                                

                        ### METHODE 2: RUNSPACEPOOL
                        if args.winrm_mode == 'runspacepool':

                                try:
                                        target = args.win_computer
                                        print(f"EXECUTION DE LA COMMANDE SUR LA MACHINE \"{target}\"")
                                        print("------------------------------------------------------------------------------------------------------------------------------")
                                        # creates a https connection with explicit kerberos auth and implicit credentials
                                        wsman = WSMan(target, ssl=False, auth="kerberos", cert_validation=False)

                                        
                                        with wsman, RunspacePool(wsman) as pool:

                                                # POUR EXECUTER UNE COMMANDE POWERSHELL SPECIFIQUE (IL FAUT FINIR AVEC OUT-STRING POUR AVOIR UN RETOUR DE TYPE STRING)
                                                # EX: execute 'Get-Process | Select-Object Name | out-string'
                                                ps = PowerShell(pool)
                                                #ps.add_cmdlet("get-process").add_cmdlet("Select-Object").add_argument("Name").add_cmdlet("Out-String")
                                                ps.add_script(args.remote_command + " | out-string")
                                                ps.invoke()
                                                for out in ps.output:
                                                        print(out)
                                                
                                                        
                                except Exception as error:
                                        print(f"ERREUR: {error}")
                                        pass

        
       

0 commentaires

Soumettre un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *