3

I was trying to use the SSH.NET NuGet package to remotely execute a command to grab an app version that is installed on one iPhone connected to a Mac.

If executed on the Mac itself with below command, will get me its version:

ideviceinstaller -l|grep <bundleIdOfMyAppPackage>

So I build a small utility in C# with this package, hoping that I would leverage it. However, all I get is just an empty string. Would anyone let me know what I could do to get the result I want ? Thank you !

var host = "myhost";
var username = "username";
var password = "password";

using (var client = new SshClient(host, username, password))
{
    client.HostKeyReceived += delegate(object sender, HostKeyEventArgs e) { e.CanTrust = true; };

    client.Connect();
    var command = client.CreateCommand("ideviceinstaller -l|grep <bundleIdOfMyAppPackage>");
    command.Execute();

    var result = command.Result;
    Console.WriteLine(result);

    client.Disconnect();
}

The error that I've got from command.Error is

zsh1: command not found ideviceinstaller`

which is weird because I can see ideviceinstaller inside that folder if I browse to there.


I've got it working thanks to @Martin Prikryl by changing the command to:

/usr/local/bin/ideviceinstaller -l|grep <myAppBundleId>
0

1 Answer 1

2

The SSH.NET SshClient.CreateCommand (or SshClient.RunCommand) does not run shell in "login" mode and does not allocate a pseudo terminal for the session. As a consequence a different set of startup scripts is (might be) sourced (particularly for non-interactive sessions, .bash_profile is not sourced), than in your regular interactive SSH session. And/or different branches in the scripts are taken, based on an absence/presence of TERM environment variable.

Possible solutions (in preference order):

  1. Fix the command not to rely on a specific environment. Use a full path to ideviceinstaller in the command. E.g.:

     /path/to/ideviceinstaller ...
    

    If you do not know the full path, on common *nix systems, you can use which ideviceinstaller command in your interactive SSH session.

  2. Fix your startup scripts to set the PATH the same for both interactive and non-interactive sessions.

  3. Try running the script explicitly via login shell (use --login switch with common *nix shells):

     bash --login -c "ideviceinstaller ..."
    
  4. If the command itself relies on a specific environment setup and you cannot fix the startup scripts, you can change the environment in the command itself. Syntax for that depends on the remote system and/or the shell. In common *nix systems, this works:

     PATH="$PATH;/path/to/ideviceinstaller" && ideviceinstaller ...
    
  5. Another (not recommended) is to use "shell" channel to execute the command via SshClient.CreateShellStream or SshClient.CreateShell as these allocate pseudo terminal

     ShellStream shellStream = client.CreateShellStream(string.Empty, 0, 0, 0, 0, 0);
     shellStream.Write("ideviceinstaller\n");
    
     while (true)
     {
         string s = shellStream.Read();
         Console.Write(s);
     }
    

    Using the shell and pseudo terminal to automate a command execution can bring you nasty side effects.

Sign up to request clarification or add additional context in comments.

1 Comment

awesome !!! I've got it working. Thanks. I'll update my question

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.