{"id":7828,"date":"2025-11-05T14:55:52","date_gmt":"2025-11-05T20:55:52","guid":{"rendered":"https:\/\/gregsowell.com\/?p=7828"},"modified":"2025-11-05T14:55:52","modified_gmt":"2025-11-05T20:55:52","slug":"connecting-to-windows-over-openssh-using-the-ansible-automation-platform","status":"publish","type":"post","link":"https:\/\/gregsowell.com\/?p=7828","title":{"rendered":"Connecting To Windows Over OpenSSH Using The Ansible Automation Platform"},"content":{"rendered":"<p>The tried and true method to connect to a Windows host using Ansible has been WinRM since the inception of Ansible.  Now this upstart OpenSSH is here for Windows and folks want to use it for their automation.  <\/p>\n<p>I&#8217;ve heard that connecting to a Windows host over SSH should be just the same as using WinRM, but in my experience this isn&#8217;t the case.  Using OpenSSH has caused some odd\/unpredictable issues with various modules&#8230;rendering some all but unusable.  For example I recently was using the <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/collections\/ansible\/windows\/win_hotfix_module.html\">win_hotfix<\/a> module and it all but refused to work correctly in my testing.  Your milage may vary, I just wanted to give a word of warning in advance.<\/p>\n<h2>OpenSSH Configuration<\/h2>\n<p>First, the <a href=\"https:\/\/docs.ansible.com\/ansible\/latest\/os_guide\/windows_ssh.html\">Ansible OpenSSH for Windows documentation <\/a>is pretty solid.<br \/>\nUsing the instructions to turn on and enable worked well:<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">Get-WindowsCapability -Name OpenSSH.Server* -Online |\r\n    Add-WindowsCapability -Online\r\nSet-Service -Name sshd -StartupType Automatic -Status Running\r\n\r\n$firewallParams = @{\r\n    Name        = &#039;sshd-Server-In-TCP&#039;\r\n    DisplayName = &#039;Inbound rule for OpenSSH Server (sshd) on TCP port 22&#039;\r\n    Action      = &#039;Allow&#039;\r\n    Direction   = &#039;Inbound&#039;\r\n    Enabled     = &#039;True&#039;  # This is not a boolean but an enum\r\n    Profile     = &#039;Any&#039;\r\n    Protocol    = &#039;TCP&#039;\r\n    LocalPort   = 22\r\n}\r\nNew-NetFirewallRule @firewallParams\r\n\r\n$shellParams = @{\r\n    Path         = &#039;HKLM:\\SOFTWARE\\OpenSSH&#039;\r\n    Name         = &#039;DefaultShell&#039;\r\n    Value        = &#039;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe&#039;\r\n    PropertyType = &#039;String&#039;\r\n    Force        = $true\r\n}\r\nNew-ItemProperty @shellParams<\/code><\/pre>\n<p>It&#8217;s not enough to just turn on OpenSSH, you also need to change what it&#8217;s default shell is.  Here, as in the documentation, I&#8217;m setting it to be powershell.  This way when Ansible connects and attempts to do work it will happen via PowerShell rather than cmd.exe:<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\"># Set default to powershell.exe\r\n$shellParams = @{\r\n    Path         = &#039;HKLM:\\SOFTWARE\\OpenSSH&#039;\r\n    Name         = &#039;DefaultShell&#039;\r\n    Value        = &#039;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe&#039;\r\n    PropertyType = &#039;String&#039;\r\n    Force        = $true\r\n}\r\nNew-ItemProperty @shellParams<\/code><\/pre>\n<p>I had to additionally adjust the firewall beyond what the Ansible documentation showed to allow remote hosts to access OpenSSH:<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">Set-NetFirewallRule -Name &quot;OpenSSH-Server-In-TCP&quot; -Enabled True -Profile Domain,Private,Public<\/code><\/pre>\n<h2>Configure AAP<\/h2>\n<p>In AAP I have to tell it what communication method to talk to my Windows host with.  I could assign these options directly on the host, but for this special group of Windows hosts I&#8217;ve created an inventory group named &#8220;windows-openssh&#8221; with the following values:<\/p>\n<pre class=\"gs-code\"><code class=\"language-plaintext\">ansible_remote_tmp: C:\\Windows\\Temp\\ansible\r\nansible_pipelining: true\r\nansible_connection: ssh<\/code><\/pre>\n<p>ansible_remote_tmp: Here you can see I setup a temp directory where files will be temporarily stored on the remote host so Ansible can execute them.<br \/>\nThe remaining are optional.<br \/>\nansible_pipelining: Tries to issue multiple commands without having to create multiple connections.<br \/>\nansible_connection: This is defining ssh as the connection type, which is the default option, this isn&#8217;t needed.  Since most folks utilize WinRM I spell it out here for documentation.  <\/p>\n<h2>Privilege Escalation Windows<\/h2>\n<p>This isn&#8217;t specific to OpenSSH on Windows, but rather something that is a gotcha for folks.  If you are doing privilege escalation <em>&#8220;become: true&#8221;<\/em> on Windows you will need to instruct Ansible how to properly do it.  In your credential, be sure to set the &#8220;Privilege Escalation Method&#8221; to &#8220;runas&#8221;.  You&#8217;ll likely need to set the Escalation Username information too.<br \/>\n<a href=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2025\/11\/win-priv.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2025\/11\/win-priv-300x64.png\" alt=\"\" width=\"300\" height=\"64\" class=\"aligncenter size-medium wp-image-7831\" srcset=\"https:\/\/gregsowell.com\/wp-content\/uploads\/2025\/11\/win-priv-300x64.png 300w, https:\/\/gregsowell.com\/wp-content\/uploads\/2025\/11\/win-priv-768x164.png 768w, https:\/\/gregsowell.com\/wp-content\/uploads\/2025\/11\/win-priv.png 898w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<h2>Conclusion<\/h2>\n<p>Well, it&#8217;s not too crazy to get it all setup, but again, your milage may vary.  I wholly expect support to just keep getting better.  Well, good luck and happy OpenSSH&#8217;n to your Windows hosts \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The tried and true method to connect to a Windows host using Ansible has been WinRM since the inception of Ansible. Now this upstart\u2026<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[49,13,15],"tags":[],"class_list":["post-7828","post","type-post","status-publish","format-standard","hentry","category-ansible","category-server","category-windows"],"_links":{"self":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7828","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=7828"}],"version-history":[{"count":3,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7828\/revisions"}],"predecessor-version":[{"id":7832,"href":"https:\/\/gregsowell.com\/index.php?rest_route=\/wp\/v2\/posts\/7828\/revisions\/7832"}],"wp:attachment":[{"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=7828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=7828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gregsowell.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=7828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}