---
title: 'How to ssh with azure cli and use zmodem to transfer with iterm2 and mac'
url: 'https://grav.munn.me/my-blog/how-to-ssh-with-azure-cli-and-use-zmodem-to-transfer-with-iterm2-and-mac'
markdown: 'https://grav.munn.me/my-blog/how-to-ssh-with-azure-cli-and-use-zmodem-to-transfer-with-iterm2-and-mac.md'
date: '2025-08-13'
description: 'This is quite a post. I needed to transfer files back and forth to an ssh server behind bastion on azure. Alas, its not too terribly well documented, so I thought I would make a document explaining how to do it. First I am going to define some terms. Referencing the microsoft destination here are t…'
---

This is quite a post. I needed to transfer files back and forth to an ssh server behind bastion on azure. Alas, its not too terribly well documented, so I thought I would make a document explaining how to do it. First I am going to define some terms.

Referencing the microsoft destination here are the cli arguments explained (they do a TERRIBLE job of this)

- [Microsoft general bastion documentation](https://learn.microsoft.com/en-us/cli/azure/network/bastion?view=azure-cli-latest)
- [Microsoft Bastion ssh cli reference (reprinted in part)](https://learn.microsoft.com/en-us/cli/azure/network/bastion?view=azure-cli-latest#az-network-bastion-ssh)

```bash
az network bastion ssh --auth-type
                 [--ids] = horrible slashy thing with evil vm resource ids (not necessary)
                 [--name] = Name of the actual (not vm!) bastion server
                 [--resource-group] = Resource group of the bastion server
                 [--resource-port] (not applicable for ssh)
                 [--ssh-key] (your local key, I just use ssh-agent)
                 [--subscription] the subscription with the proper bastion/vm
                 [--target-ip-address] n/a
                 [--target-resource-id] VERY EVIL long path you get from properties of vm
                 [--username] remote username of the local user on the VM
```

Here is an example with everything filled out:

```bash
az network bastion ssh --name MyHappyPastion-eus-VNet-bastion --resource-group MyHappyResourceGroupforBastion --target-resource-id /subscriptions/<subscriptionguid>/resourceGroups/<resource group>-RG/providers/Microsoft.Compute/virtualMachines/<vmname> --auth-type PASSWORD --username <vmuser> --subscription my-sub-name
```

This is 1/2 of the magic. You can get the resource vm by going to the vm and finding its "resource ID" which is that evil path I talked about. This also assumes you are properly logged into said sub with appropriate az login commands.

## Now for the Cool part: Zmodem transfer w/o portforwarding OR any scp/sftp subsystems and NO direct connectivity to remote network

1. Install lrzsz on the remote vm (it might be a different package name, basically zmodem on unix).
2. Install lrzsz on your mac (alas this doesn't work as nicely for unix!) brew install lrzsz
3. Follow [this guide](https://github.com/aurora/iterm2-zmodem) (assuming you have iterm2 installed!)
4. PROFIT!

## Appendix 1: saved text of github in case it disappears

```bash
#!/usr/bin/env bash

#
# iterm2-zmodem
#
# copyright (c) 2013 by Harald Lapp <harald@octris.org>
#
# AppleScript portion from:
# http://stackoverflow.com/questions/4309087/cancel-button-on-osascript-in-a-bash-script
# licensed under cc-wiki with attribution required 
#

#
# This script can be found at:
# https://github.com/aurora/iterm2-zmodem
#

#
# This is a re-implementation of the shell scripts "iterm2-recv-zmodem.sh" and
# "iterm2-send-zmodem.sh" found at https://github.com/mmastrac/iterm2-zmodem
#

# usage
if [[ $1 != "sz" && $1 != "rz" ]]; then
    echo "usage: $0 sz|rz"
    exit
fi

# send Z-Modem cancel sequence
function cancel {
    echo -e \\x18\\x18\\x18\\x18\\x18
}

# send notification using growlnotify
function notify {
    local msg=$1

    if command -v growlnotify >/dev/null 2>&1; then
        growlnotify -a /Applications/iTerm.app -n "iTerm" -m "$msg" -t "File transfer"
    else
        echo "# $msg" | tr '\n' ' '
    fi
}

#setup
[[ $LRZSZ_PATH != "" ]] && LRZSZ_PATH=":$LRZSZ_PATH" || LRZSZ_PATH=""

PATH=$(command -p getconf PATH):/usr/local/bin$LRZSZ_PATH
ZCMD=$(
    if command -v $1 >/dev/null 2>&1; then
        echo "$1"
    elif command -v l$1 >/dev/null 2>&1; then
        echo "l$1"
    fi
)

# main
if [[ $ZCMD = "" ]]; then
    cancel
    echo

    notify "Unable to find Z-Modem tools"
    exit
elif [[ $1 = "rz" ]]; then
    # receive a file
    DST=$(
        osascript \
            -e "tell application \"iTerm\" to activate" \
            -e "tell application \"iTerm\" to set thefile to choose folder with prompt \"Choose a folder to place received files in\"" \
            -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"
    )

    if [[ $DST = "" ]]; then
        cancel
        echo 
    fi

    cd "$DST"

    notify "Z-Modem started receiving file"

    $ZCMD -e -y
    echo 

    notify "Z-Modem finished receiving file"
else
    # send a file
    SRC=$(
        osascript \
            -e "tell application \"iTerm\" to activate" \
            -e "tell application \"iTerm\" to set thefile to choose file with prompt \"Choose a file to send\"" \
            -e "do shell script (\"echo \"&(quoted form of POSIX path of thefile as Unicode text)&\"\")"
    )

    if [[ $SRC = "" ]]; then
        cancel
        echo 
    fi

    notify "Z-Modem started sending
$SRC"

    $ZCMD -e "$SRC"
    echo 

    notify "Z-Modem finished sending
$SRC"
fi
```

# Z-Modem integration for iTerm2- backup in case github blows up

## Preface

The purpose of this script is to add Z-Modem file transfer support to (in theory) any ssh session from within iTerm2.

This script is inspired by and would probably not exist without the scripts "[iterm2-recv-zmodem.sh](http://iterm2-recv-zmodem.sh)" and "[iterm2-send-zmodem.sh](http://iterm2-send-zmodem.sh)" (c) by Matt Mastracci, <https://github.com/mmastrac/iterm2-zmodem>.

The motivation to not forking but rewriting the scripts was mainly to put the functionality into a single shell script to make it possible to share common code used by both sending and receiving funtionality and to make it more easy to extend the functionality in future.

## Installation

### Prework

For sending and receiving files the Z-Modem tools are required on both machines involved in the transfer. I recommend installing the lrzsz package which should be available in most Linux distributions or which can be downloaded and build from source from:

<http://ohse.de/uwe/software/lrzsz.html>

A recent version of iTerm2 is required for Mac OS X to make things work, downloadable from:

<http://www.iterm2.com/>

Optionally the script supports Growl notifications. For this to work the Growl application and the additional tool "growlnotify" is needed.

### Installation and configuration

The script iterm2-zmodem should by copied to /usr/local/bin.

It's required to setup the following "Triggers" in iTerm2:

```
Regular expression: \*\*B0100
Action:             Run Coprocess
Parameters:         /usr/local/bin/iterm2-zmodem sz

Regular expression: \*\*B00000000000000
Action:             Run Coprocess
Parameters:         /usr/local/bin/iterm2-zmodem rz
```

The script "iterm2-zmodem" tries to determine the names (lrz, rz, lsz, sz) and locations of the binaries of growlnotify and the Z-Modem tools. The pathes searched are:

```
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
```

If the Z-Modem tools are installed in some unusual place, the path can be specified when configuring the triggers using the LRZSZ\_PATH environment variable, the "Parameters" setting of the trigger has to be modified in this case to become for example:

```
Parameters:         LRZSZ_PATH=/opt/lrzsz/bin /usr/local/bin/iterm2-zmodem rz
```

## Usage

The file transfer is initiated on the remote machine by executing rz respectively lrz (for receiving a file on the remote machine) or by executing sz respectively lsz (for sending a file to the remote machine). See the command usage information of the Z-Modem tools for additional details.

Note, that sending files will overwrite the destination file on the local machine, if it already exists.

## Disclaimer

Use with caution. This software may contain serious bugs. I can not be made responsible for any damage the software may cause to your system or files.

## License

### iterm2-zmodem

iterm2-zmodem

Copyright (C) 2013 by Harald Lapp <harald@octris.org>

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

### 3rd party code

The AppleScript portion included in the script is inspired by <http://stackoverflow.com/questions/4309087/cancel-button-on-osascript-in-a-bash-script> licensed under cc-wiki with attribution required

---

## Navigation

- Parent: [My Blog](https://grav.munn.me/my-blog.md)
- Previous: [how to use native python wheel packages on alpine](https://grav.munn.me/my-blog/how-to-use-native-python-wheel-packages-on-alpine.md)
- Next: [How to use pass command to read qr codes for totp](https://grav.munn.me/my-blog/how-to-use-pass-command-to-read-qr-codes-for-totp.md)
