{"id":13566972,"url":"https://github.com/tuxedoar/ssh-commander","last_synced_at":"2026-05-01T19:05:12.652Z","repository":{"id":57470832,"uuid":"194192942","full_name":"tuxedoar/ssh-commander","owner":"tuxedoar","description":"Execute commands on several remote hosts, with SSH.","archived":false,"fork":false,"pushed_at":"2021-01-05T00:00:29.000Z","size":66,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-09-29T17:13:54.828Z","etag":null,"topics":["command-line-tool","python","ssh","sysadmin","sysadmin-tool"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tuxedoar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-06-28T02:29:39.000Z","updated_at":"2024-05-07T08:22:24.000Z","dependencies_parsed_at":"2022-09-26T17:40:38.712Z","dependency_job_id":null,"html_url":"https://github.com/tuxedoar/ssh-commander","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/tuxedoar/ssh-commander","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuxedoar%2Fssh-commander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuxedoar%2Fssh-commander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuxedoar%2Fssh-commander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuxedoar%2Fssh-commander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tuxedoar","download_url":"https://codeload.github.com/tuxedoar/ssh-commander/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tuxedoar%2Fssh-commander/sbom","scorecard":{"id":903142,"data":{"date":"2025-08-11","repo":{"name":"github.com/tuxedoar/ssh-commander","commit":"31d245750eb4c4321af1c39719df6220256cd26a"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-24T16:24:41.205Z","repository_id":57470832,"created_at":"2025-08-24T16:24:41.205Z","updated_at":"2025-08-24T16:24:41.205Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32508939,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line-tool","python","ssh","sysadmin","sysadmin-tool"],"created_at":"2024-08-01T13:02:20.583Z","updated_at":"2026-05-01T19:05:12.630Z","avatar_url":"https://github.com/tuxedoar.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# SSH Commander\nThis *Command Line Interface* (CLI) tool, allows you to execute various commands on several remote hosts, using the SSH \nprotocol. As a result, you get a per-host generated output of each command you specified.\n\nYou simply specify a plain text file with a list of remote hosts to connect to (domain names or IP addresses), and a \ncomma-separated list of commands to execute on those. Note that access credentials (user and password) must be the same for all \nthe target hosts!.\n\n## Highlights and features\n* Key-based authentication support (\u003e= v0.3)\n* Multithreaded sessions (\u003e= v0.2).\n* Almost no setup required, after installed!.\n* Easy to use CLI syntax.\n* Colorized output (\u003e= v0.2)!.\n\n## Requirements\nMake sure your system meets the following requirements:\n* [Python 3](https://www.python.org/downloads/) (\u003e= 3.7)\n* [paramiko](https://github.com/paramiko/paramiko) (tested with v2.7.2)\n* [colorama](https://github.com/tartley/colorama) (tested with v0.4.4)\n* [coloredlogs](https://pypi.org/project/coloredlogs/) (tested with v15.0)\n\n## Installation\nThe recommended method for installing this tool, is using `pip`:\n```\npip install ssh-commander\n```\n\n## Usage\nWhen using `ssh-commander`, respect the following syntax:\n```\nusage: ssh-commander [-h] [-p [PORT]] [-i IDENTITY_FILE] [-T] [-v]\n                     FILE USER COMMANDS\n\nExcecute commands on several remote hosts, with SSH.\n\npositional arguments:\n  FILE                  Plain text file with list of hosts\n  USER                  User to login on remote hosts\n  COMMANDS              Comma separated commands to be executed on remote\n                        hosts\n\noptional arguments:\n  -h, --help            show this help message and exit\n  -p [PORT], --port [PORT]\n                        Specify SSH port to connect to hosts\n  -i IDENTITY_FILE, --identity_file IDENTITY_FILE\n                        Public key auth file\n  -T, --trust_unknown   Trust hosts with no entries at known_hosts file \n  -v, --version         Show current version\n```\n\n### Setup your targeted hosts\n\nFirst, remember to create a text file (name it whatever you like), where you list the target hosts. Its content, may look like \nthis:\n```\n# This is a comment. It'll be ignored!.\n192.168.0.10\n192.168.0.11\n192.168.0.12\n```\n\n### Authentication\nSince v0.3, `ssh-commander` supports the following *authentication methods*:\n* Password-based authentication.\n* SSH key-based authentication.\n\nIn this regard, `ssh-commander` tries to mimmick the [OpenSSH](https://www.openssh.com/)\nclient default behaviour. In practical terms, this means that:\n* If any valid *key file* is found at `~/.ssh/`, it'll attempt a *key-based authentication* on all the targeted hosts!.\n* If no valid *key file* is found nor provided, you'll be asked for a *password*, to be used as the *authentication method* for \nall remote hosts.\n\nIn any case, both the *SSH key* or the provided *password*, should be valid on ALL\nthe targeted hosts, for doing the authentication!.\n\n#### Password-based authentication\nA *password* is prompted ONLY if no previous valid *key file* was found, at default location (`~/.ssh/`). When using \n*password-based authentication*, note that the latter, is gonna be asked only once. Therefore, remember that those credentials, \nshould be valid on all targeted hosts!.\n\n#### SSH key-based authentication\nAs explained previously, firstly, `ssh-commander` will try a *key-based authentication*, by looking for valid *keys* at the \n`~/.ssh/` directory.\n\nThe following types of keys are looked for:\n* `id_dsa`\n* `id_ecdsa`\n* `id_ed25519`\n* `id_rsa`\n\nAn alternative key file location, can be specified by using the `-i` CLI\noption!.\n\n### Known hosts validation\nBy default, `ssh-commander` will take a look at the `~/.ssh/known_hosts` file and check that each targeted host, has a matching \nentry in it. If it doesn't, it'll warn you and ask for an explicit confirmation, about whether you trust each of those hosts \nanyway or not!.\n\nNote that if you answer negatively to the trust confirmation, nothing is done and the program exits with a notification.\n\nIf you don't want this validation to be performed, you can use the `-T` option, to blindly trust the remote hosts!.\n\n### Examples\nLet's say you have some managed switches (or routers): \n```\nssh-commander hosts.txt root \"terminal length 0, sh port-security\"\n```\nThey could rather be some GNU/Linux servers, as well:\n```\nssh-commander hosts.txt foones \"hostname, whoami\"\n```\nDo not validate remote hosts against the `known_hosts` file:\n```\nssh-commander -T hosts.txt foones \"hostname, whoami\"\n```\nSpecify an alternative SSH *key file* location, for *key-based authentication*:\n```\nssh-commander -i ~/ssh_keys/id_rsa hosts.txt foones \"hostname, whoami\"\n```\n\n## License\nThis program is licensed under the GPLv3.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuxedoar%2Fssh-commander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftuxedoar%2Fssh-commander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftuxedoar%2Fssh-commander/lists"}