Skip to content

Instantly share code, notes, and snippets.

@mdpuma
Last active November 9, 2025 14:54
Show Gist options
  • Select an option

  • Save mdpuma/3344d21f6206f7901b697ef767675ecf to your computer and use it in GitHub Desktop.

Select an option

Save mdpuma/3344d21f6206f7901b697ef767675ecf to your computer and use it in GitHub Desktop.
copy_vm_proxmox_lve.sh
#!/bin/bash
# Usage: ./copy_lvm.sh <source_lvm_path> <dest_lvm_path> <size>
SOURCE="192.168.5.10"
SOURCE_LVM="$1"
DEST_LVM="$2"
SIZE="$3"
function error_exit() {
echo "[ERROR] $1" >&2
exit 1
}
# Validate inputs
[ -z "$SOURCE_LVM" ] && error_exit "Source LVM path is required."
[ -z "$DEST_LVM" ] && error_exit "Destination LVM path is required."
[ -z "$SIZE" ] && error_exit "LVM size (e.g., 32G) is required."
# Check if source LVM exists and is closed
IS_OPEN_SRC=$(ssh "$SOURCE" "lvdisplay \"$SOURCE_LVM\" 2>/dev/null | awk '/LV Status/ {status=\$3} /# open/ {open=\$3} END {print open}'")
[ -z "$IS_OPEN_SRC" ] && error_exit "Cannot find source LVM $SOURCE_LVM on $SOURCE."
[ "$IS_OPEN_SRC" != "0" ] && error_exit "Source LVM $SOURCE_LVM is in use on $SOURCE."
# Check if destination LVM is closed
IS_OPEN_DEST=$(lvdisplay "$DEST_LVM" 2>/dev/null | awk '/# open/ {print $3}')
[ -z "$IS_OPEN_DEST" ] && error_exit "Cannot find destination LVM $DEST_LVM on local host."
[ "$IS_OPEN_DEST" != "0" ] && error_exit "Destination LVM $DEST_LVM is in use."
# Check if sizes match
SIZE_SRC=$(ssh "$SOURCE" "lvdisplay \"$SOURCE_LVM\" | awk '/LV Size/ {print \$3}'")
SIZE_DEST=$(lvdisplay "$DEST_LVM" | awk '/LV Size/ {print $3}')
[ "$SIZE_SRC" != "$SIZE_DEST" ] && error_exit "Source and destination LVM sizes do not match: $SIZE_SRC vs $SIZE_DEST."
# Confirm operation
echo "Ready to copy LVM from $SOURCE:$SOURCE_LVM to local $DEST_LVM"
echo "This will overwrite data on $DEST_LVM"
read -rp "Type 'yes' to proceed: " CONFIRM
if [[ "$CONFIRM" == "yes" || "$CONFIRM" == "y" ]]; then
echo "[INFO] Starting copy..."
ssh "$SOURCE" "dd if=/dev/$SOURCE_LVM bs=8M conv=sparse status=none" | \
pv -s "$SIZE" | \
dd of="/dev/$DEST_LVM" bs=8M conv=sparse status=none
echo "[INFO] Copy completed."
else
echo "[INFO] Copy cancelled by user."
exit 1
fi
#!/bin/bash
DEST="154.56.0.10"
SOURCE_LVM=$1
DEST_LVM=$2
SIZE=$3
if [ "$SIZE" = "" ]; then
echo "Please specify size of lvm, example 32G"
exit
fi
# check source lvm
IS_OPEN="$(lvdisplay $SOURCE_LVM | grep open | awk '{ print $3}')"
if [ $? -ne 0 ]; then
echo "Cant find source lvm $SOURCE_LVM on source"
exit;
fi
if [ "$IS_OPEN" != 0 ]; then
echo "Cant copy lvm $SOURCE_LVM which is in use on source"
exit
fi
# check destination lvm remote
IS_OPEN="$(ssh $DEST lvdisplay $DEST_LVM | grep open | awk '{ print $3 }')"
if [ "$IS_OPEN" != "0" ]; then
echo "Cant copy lvm $DEST_LVM which is in use on $DEST"
exit
fi
# compare sizes
SIZE1=$(ssh $DEST lvdisplay $DEST_LVM | grep LV\ Size | awk '{ print $3 }')
SIZE2=$(lvdisplay $SOURCE_LVM | grep LV\ Size | awk '{ print $3 }')
if [ "$SIZE1" != "$SIZE2" ]; then
echo "Cant copy due to different sizes"
exit
fi
echo "Proceed copying command: dd if=/dev/$SOURCE_LVM bs=16M conv=sparse | pv -s $3 | ssh $DEST dd of=/dev/$DEST_LVM bs=16M conv=sparse ? Type y or yes"
read int
if [ $int = "y" ] || [ $int = "yes" ]; then
dd if=/dev/$SOURCE_LVM bs=8M conv=sparse | pv -s $SIZE | ssh $DEST dd of=/dev/$DEST_LVM bs=8M conv=sparse
fi

how to trim inside vm

https://forum.proxmox.com/threads/thin-provisioned-windows-vms-use-full-capacity-in-proxmox-ceph-after-migration.83924/ https://learn.microsoft.com/en-us/sysinternals/downloads/sdelete

creating cloudbase cloudinit Windows templates

  • install windows
  • install virtio-win
  • install cloudbase-init
  • disable AccountLockout via gpedit.msc
  • enable RemoteDesktop
  • make sure that there is 2 partition (boot and os system (C))

https://cloudbase-init.readthedocs.io/en/latest/config.html https://vds9.iphost.md:8006/pve-docs/chapter-qm.html#_cloudbase_init_and_sysprep

recommended changes on to cloudbase-init.conf

[DEFAULT]
username=Administrator
groups=Administrators
inject_user_password=true
config_drive_raw_hhd=true
config_drive_cdrom=true
config_drive_vfat=true
bsdtar_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\bsdtar.exe
mtools_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\
verbose=true
debug=true
log_dir=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\log\
log_file=cloudbase-init.log
default_log_levels=comtypes=INFO,suds=INFO,iso8601=WARN,requests=WARN
logging_serial_port_settings=COM1,115200,N,8
mtu_use_dhcp_config=true
ntp_use_dhcp_config=true
local_scripts_path=C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\
check_latest_version=false

metadata_services=cloudbaseinit.metadata.services.configdrive.ConfigDriveService
plugins=cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin,cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin,cloudbaseinit.plugins.common.networkconfig.NetworkConfigPlugin,cloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugin
allow_reboot=false
first_logon_behaviour=no
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment