Skip to main content

Using ssh to Communicate From IBM i to PC

IBM i expert Rob Berendt explains a workaround to IBM Client Access for Windows.

Image of computer screen on a blue background.

As many people start to upgrade their PCs to Windows 10, or their PC based servers to Windows 2019, they are finding out that the deprecated IBM Client Access for Windows is no longer supported on those newer operating systems. A simple solution is to migrate to IBM i Access Client Solutions, often called iACS. More details about iACS can be found here.

One of the features missing from iACS is the remote command daemon so that you could run RUNRMTCMD from your IBM i and have it execute a command on your PC. There were many issues with RUNRMTCMD, not the least being your password was sent in the clear. That daemon was deemed a security risk here and not allowed to access any Windows server.  We ended up doing a kludge of workarounds—one was using RUNRMTCMD to a Windows client, which then talked to a Windows server.

As time went on, we decided to drink the ssh Kool Aid and get all of our Windows based clients and servers on supported versions of Windows and replace Client Access for Windows with iACS. Instead of using RUNRMTCMD we would use ssh to execute commands on the Windows boxes.

To test this I decided to make my Windows 10 client my first target. In this case, my Windows 10 client was the ssh server or target; my IBM i was the ssh client.

One of my goals was to do this using a private/public key pair and not to use passwords. This just makes more sense than either using a user whose password never changes or having to change scripts to match new passwords.

Client Setup on IBM i

DSPSFWRSC should show the following software loaded:

  ID     Option  Feature Description                       
5770SS1  33       5111    Portable App Solutions Environment
5733SC1  *BASE    5050    IBM Portable Utilities for i
5733SC1  1        5050    OpenSSH, OpenSSL, zlib    

Some of this can be done with QSHELL (5770SS1-30) but I'll stick with PASE for the rest of this article.

All user IDs should be 8 characters or less. We have a shop standard in place to follow this rule but until I saw this I couldn't remember why. Our passwords are much longer as we use QPWDLVL of 3. My user profile is ROB. Modify the following to meet your situation.

Make sure your home directory exists, and has the right authority.

> mkdir /home/ROB
  mkdir: 0653-358 Cannot create /home/ROB.
  /home/ROB: Do not specify an existing file.
> chmod 755 /home/ROB

Create a DSA or RSA key pair that has no passphrase associated with it. Use the commands below to create either a DSA or RSA key pair:

ssh-keygen -t dsa -N ""

ssh-keygen -t rsa -N ""

I used the following. I ended up giving mine a different name than the default of id_rsa. I figured this may make things easier when I start setting up multiple keys and I had the source/target systems in the name. If you leave it blank and just press enter it will also create the .ssh subdirectory but the files will be id_rsa and Changing these names like I did will confuse some people.

> ssh-keygen -t rsa -N ""                                      

  Generating public/private rsa key pair.                      

  Enter file in which to save the key (/home/ROB/.ssh/id_rsa):

> /home/ROB/.ssh/GDI_GDL57          

  Created directory '/home/ROB/.ssh'.

  Your identification has been saved in /home/ROB/.ssh/GDI_GDL57.

  Your public key has been saved in /home/ROB/.ssh/



> chmod 600 /home/ROB/.ssh/GDI_GDL57



If your home directory is not named like /home/ROB then I suggest you change it to this (again, replacing ROB to match your user profile).


If you have to run the CHGUSRPRF then you should sign off and back on again.

The default on CRTUSRPRF is *USRPRF which will make it /home/USRPRF where USRPRF is the name of the user profile. In my case, it would become /home/ROB.

I like to use a CONFIG file to store my connections in. The benefits are explained here

To do so:


> touch ~/.ssh/config    


> chmod 600 ~/.ssh/config


While I’m sure there is a dandy utility to edit files while in PASE I stick with what I know:

F21=CL command entry


Our Windows domain is dekko-1. I can ping my PC from IBM i using 

PING RMTSYS('GDL57.dekko-1')

************Beginning of data**************

Host gdl57                                  

    HostName gdl57.dekko-1                  

    User rob                                

    IdentityFile ~/.ssh/GDI_GDL57           

 ************End of Data********************

Setup on Windows 10 or Windows Server 2019

I’m going to be following the instructions from this website. Since you're going to end up using PowerShell for many things in this process anyway, I’ll just use that for all of it and bypass the GUI.

Launch PowerShell as an administrator. I love the search bar at the bottom of Windows 10. So I simply type in powershell there, but don't press enter. It lists PowerShell near the top of the list. I right click on that and select "Run as administrator."

First, let's see if ssh is installed:

PS C:\WINDOWS\system32> Get-WindowsCapability -Online | ? Name -like 'OpenSSH*'

Name  : OpenSSH.Client~~~~

State : NotPresent

Name  : OpenSSH.Server~~~~

State : NotPresent

Now let's install it:

Add-WindowsCapability-Online -NameOpenSSH.Client~~~~

Add-WindowsCapability-Online -NameOpenSSH.Server~~~~

Get-WindowsCapability-Online | ? Name -like 'OpenSSH*'

Now they both have a state of Installed.

Make sure the firewall rule OpenSSH-Server-In-TCP is there and Enabled = True.


If it's not there then:

New-NetFirewallRule-Namesshd-DisplayName'OpenSSH Server (sshd)'-EnabledTrue-DirectionInbound-ProtocolTCP-ActionAllow-LocalPort22

Now let's set it to start automatically:


Start it


Remember that file /home/ROB/.ssh/ file I created back on the IBM i? This is the public key part of the public/private key pair.  We need to get that on to this PC. If you use ftp, do it with binary mode. We need to add this file to the PC. The file will be in one of two places based on whether or not the user is part of the local Administrators group.

If the user is not in the local Administrators group:

The key will be stored in C:\Users\rob\.ssh replacing rob with whatever user is appropriate to you.

Look for a .ssh folder. If one doesn't exist, create it. 

Note, Windows Explorer won't let you create the folder with the name ".ssh". Instead, use ".ssh." with an extra dot at the end. The extra dot will be removed, and you'll have a folder correctly named .ssh

If there is no file named authorized_keys in this .ssh directory you can simply copy the file you copied from your IBM i to create authorized_keys.  If there is a file named authorized_keys then copy the contents of the file you copied from your IBM i to the end of the existing authorized_keys appending it to the end starting at a new line.

If they are in the local Administrators group:

The public key will be stored in C:\ProgramData\ssh 

If there is no file named administrators_authorized_keys in this ssh directory you can simply copy the file you copied from your IBM i to create administrators_authorized_keys.  If there is a file named administrators_authorized_keys then copy the contents of the file you copied from your IBM i to the end of the existing administrators_authorized_keys appending it to the end starting at a new line.

Note:  I did have some issues using iACS to copy the file as it failed to find the .ssh directory in /home/ROB.  Probably something to do with file permissions.  Going to it directly allowed me to find the file but it would not copy it down.  Trying FileZilla showed me that it could not copy it down due to permissions on the target directory on the PC.  I had to put it in another directory on the PC and then use Windows File Explorer to copy it.  Even that I had to use administrator privileges.

Back in your PowerShell session run:

$acl = Get-Acl C:\ProgramData\ssh\administrators_authorized_keys

$acl.SetAccessRuleProtection($true, $false)

$administratorsRule = New-Object"Administrators","FullControl","Allow")

$systemRule = New-Object"SYSTEM","FullControl","Allow")



$acl | Set-Acl

To test your connection:


> ssh gdl57 'dir \users\rob\*.* >\users\rob\diroutput3.txt'

  ssh: connect to host gdl57 port 22: Connection refused   


To find out why I got the "Connection refused" I went back to PowerShell:

Get-Service sshd

Status   Name               DisplayName

------   ----               -----------

Stopped  sshd               OpenSSH SSH Server

Set-Service -Name sshd -StartupType 'Automatic'

Start-Service sshd

Get-Service sshd

Status   Name               DisplayName

------   ----               -----------

Running  sshd               OpenSSH SSH Server

Then I returned to QP2TERM and tried it again:

> ssh gdl57 'dir \users\rob\*.* >\users\rob\diroutput3.txt'                     

  The authenticity of host 'gdl57.dekko-1 (' can't be established.   

  ECDSA key fingerprint is SHA256:euodvI3161T4admEYhBIaF8Zfv1ZBhur7gt4gNKAXHI.  

  Are you sure you want to continue connecting (yes/no/[fingerprint])?          

> yes                                                                          

  Warning: Permanently added 'gdl57.dekko-1' (ECDSA) to the list of known hosts.


This updated the file /home/ROB/.ssh/known_hosts on my IBM i.

Now when I look at my PC in the /users/rob directory I see a file called diroutput3.txt.

Even though I've done as much as I can using QP2TERM I had a devil of a time passing parameters to that for production so I use qshell instead for production.

QSH CMD('ssh gdl57 "dir \users\rob\*.* >\users\rob\diroutput3.txt"')

This can now be used instead of RUNRMTCMD.


Stay on top of all things tech!
View upcoming & on-demand webinars →