Kickstart %pre Script Examples on RHEL

Deepak Prasad
Tested on RHEL 10.2 (Coughlan) — kickstart harness on vm2.lab.example via PXE from vm1.lab.example
Package pykickstart 3.52.12-1.el10
Applies to RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora
Privilege Installer boot access on the target host
Scope %pre and %pre-install timing, --log and --interpreter, disk wipe and inventory scripts from the lab harness, and copying installer logs to the installed system. Does not cover PXE server build or full kickstart grammar.
Related guides Automate RHEL installation with Kickstart
Kickstart %post script examples
Kickstart clearpart not working
Configure Kickstart PXE boot server
df and du command in Linux

Kickstart %pre runs in the Anaconda installer environment right after your kickstart file loads. It finishes before partitioning and package installation, so you still have the bare installer runtime—not the chrooted tree under /mnt/sysimage.

Typical %pre jobs:

  • Log disk layout and NIC MAC addresses before you wipe anything
  • Deactivate old LVM and wipe signatures when clearpart alone fails
  • Drop marker files in /tmp that %post --nochroot can copy later

This article walks through %pre and %pre-install examples from the RHEL 10 lab harness (rhel10-lab.cfg on vm1). Kickstart structure and ksvalidator live in Automate RHEL installation with Kickstart. Copy %pre logs to the installed system with %post --nochroot in Kickstart %post script examples.


What is a Kickstart %pre script?

Property Detail
Timing After kickstart load, before partitioning completes
Environment Installer runtime—not chrooted to the final system
Syntax Section starts with %pre and ends with %end
Tools lsblk, wipefs, ip, dmsetup, vgchange, and most /bin and /sbin utilities in the installer image

What is a Kickstart %pre-install script?

%pre-install runs after:

  • Disks are partitioned
  • File systems are created and mounted under /mnt/sysimage
  • Network is configured per kickstart network lines

Use %pre-install to inspect the mounted tree or add users and groups with fixed IDs before packages install. The section starts with %pre-install and ends with %end. It still runs outside a full chroot of the finished system.


Example 1: Log system state with --log

Add --log= so script output lands in a file under /tmp in the installer environment. The harness logs disk layout, NICs, and memory:

text
%pre --log=/tmp/kickstart_pre.log
#!/bin/bash
set -x
RUN_TAG="ks-lab-$(date +%Y%m%d-%H%M%S)"
echo "RUN_TAG=${RUN_TAG}"
echo "=== %pre $(date -Is) ==="
echo "--- lsblk ---"
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
echo "--- ip link (name mac driver) ---"
for n in /sys/class/net/*; do
  name=$(basename "$n")
  [[ "$name" == "lo" ]] && continue
  mac=$(cat "$n/address")
  drv=$(basename "$(readlink -f "$n/device/driver" 2>/dev/null)" 2>/dev/null || echo "?")
  echo "NIC ${name} mac=${mac} driver=${drv}"
done
ip -br link
ip -br addr
echo "BOOTIF=${BOOTIF:-unset}"
df -Th
free -m
echo "${RUN_TAG}" > /tmp/ks-lab-run-tag
%end

BOOTIF is set when pxelinux uses IPAPPEND 2. On HTTP iPXE netboot without that append line, the log may show BOOTIF=unset. Pin the install NIC with --device=<MAC> in kickstart network lines instead.

NOTE
Logs in /tmp during install are not on the installed system after reboot unless you copy them in %post --nochroot.

After install, when logs were copied, check the target:

bash
sudo head -20 /var/log/kickstart_pre.log

Sample output shape from the lab harness:

output
=== %pre 2026-08-09T14:12:11+00:00 ===
--- lsblk ---
NAME               SIZE TYPE FSTYPE      MOUNTPOINT
sda                 20G disk
|-sda1               1M part
|-sda2               2G part xfs
`-sda3              18G part LVM2_member
  |-rhel_vm2-swap    3G lvm  swap
  `-rhel_vm2-root   25G lvm  xfs
sdb                 10G disk
`-sdb1              10G part LVM2_member
  `-rhel_vm2-root   25G lvm  xfs
NIC eth0 mac=08:00:27:7b:9e:bd driver=e1000
NIC eth1 mac=08:00:27:cf:43:4b driver=e1000
BOOTIF=unset

The %pre transcript shows layout before wipe and clearpart run. Both disks still carry an old rhel_vm2 LVM stack from prior lab installs. After a successful harness run, new LVM names appear on sda only (for example rhel_vm200-root); sdb may still show a leftover LVM partition because ignoredisk --drives=sdb keeps Anaconda off that disk.

Check mount usage with df -Th; see df and du command in Linux for -h, -T, and filtering pseudo-filesystems.


Example 2: Wipe install disk before clearpart

When clearpart alone fails, wipe the install disk in %pre:

text
%pre --log=/tmp/kickstart_pre.log
#!/bin/bash
set -x
INSTALL_DISK=sda
udevadm settle
vgchange -an 2>/dev/null || true
dmsetup remove_all 2>/dev/null || true
wipefs -af "/dev/${INSTALL_DISK}" || true
for part in /dev/${INSTALL_DISK}*; do
  [[ -b "$part" ]] && wipefs -af "$part" || true
done
lsblk "/dev/${INSTALL_DISK}"
%end

Pair with kickstart storage lines:

text
ignoredisk --drives=sdb
clearpart --all --initlabel --drives=sda
autopart --type=lvm --nohome

Example 3: Use --interpreter for Python and Bash

--interpreter= runs the section with a specific binary. On RHEL 10 the installer provides /usr/bin/bash and /usr/libexec/platform-python:

text
%pre --interpreter=/usr/libexec/platform-python --log=/tmp/kickstart_python_pre.log
print("This is a sample python script called at %pre stage")
%end

%pre --interpreter=/usr/bin/bash --log=/tmp/kickstart_bash_pre.log
echo "This is a sample bash script called at %pre stage"
%end

After install, when logs were copied to /var/log/:

bash
cat /var/log/kickstart_python_pre.log
cat /var/log/kickstart_bash_pre.log
output
This is a sample python script called at %pre stage
This is a sample bash script called at %pre stage

Example 4: %pre-install on mounted sysimage

Log layout after partitions exist but before packages install:

text
%pre-install --log=/tmp/kickstart_pre_install.log
#!/bin/bash
echo "=== %pre-install $(date -Is) ==="
df -Th
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
mount | grep sysimage || true
%end

Compare %pre and %pre-install logs. The latter should show mount points under /mnt/sysimage. After install, when the log was copied:

bash
sudo grep -E 'sysimage|sysroot' /var/log/kickstart_pre_install.log
output
/dev/mapper/rhel_vm200-root xfs  16G  345M  16G  3% /mnt/sysroot
/dev/sda2                   xfs  2.0G  71M  1.9G  4% /mnt/sysroot/boot
/dev/mapper/rhel_vm200-root on /mnt/sysimage type xfs (rw,relatime,seclabel,...)
/dev/sda2 on /mnt/sysimage/boot type xfs (rw,relatime,seclabel,...)

RHEL 10 Anaconda may list /mnt/sysroot in df output while mount still reports bind paths under /mnt/sysimage. Either pattern confirms the new root and boot file systems were mounted before the package phase ran.


Example 5: %pre without --log (marker file)

The harness includes a minimal %pre section without --log to demonstrate marker files copied by %post:

text
%pre
#!/bin/bash
touch /tmp/pre-without-log-marker
%end

Copy markers and logs in %post --nochroot:

text
%post --nochroot --log=/mnt/sysimage/var/log/kickstart_post_nochroot.log
#!/bin/bash
for f in /tmp/kickstart_pre.log /tmp/kickstart_pre_install.log /tmp/pre-without-log-marker; do
  [[ -f "$f" ]] && cp -av "$f" /mnt/sysimage/var/log/
done
%end

References


Summary

Use %pre for work before partitioning: logging hardware, wiping old LVM, and dropping /tmp markers. Use %pre-install when you need to inspect /mnt/sysimage after partitions exist but before packages land.

Add --log= when you want a transcript in the installer environment, and --interpreter= when Python or Bash should run the section body directly. Nothing under /tmp survives reboot on its own. Copy those logs with %post --nochroot so /var/log/ on the finished system keeps the same story Anaconda saw during install.


Frequently Asked Questions

1. Does %pre run inside the installed system chroot?

No. %pre runs in the Anaconda installer environment before partitioning completes. %pre-install runs after /mnt/sysimage is mounted but still outside a full chroot of the final system.

2. Where do %pre log files go after install?

Logs under /tmp in the installer environment are removed at reboot unless you copy them with %post --nochroot into /mnt/sysimage/var/log/.

3. When does %pre-install run compared to %pre?

%pre runs before partitioning. %pre-install runs after partitions exist and file systems are mounted under /mnt/sysimage but before the main package install phase finishes.

4. Can I install packages inside %pre?

No. %pre runs before the target root is fully built. Install packages with kickstart %packages or in %post after chroot. Use %pre only for inspection, wipe, or generating snippets for Anaconda to consume.

5. What happens if a %pre script fails?

Without --erroronfail Anaconda may continue and leave you with a broken layout. Add --erroronfail on %pre while testing new wipe logic so the install stops immediately when wipefs or vgchange fails.

6. Does %pre need a shebang when I use --interpreter?

No. When you set --interpreter=/usr/bin/bash or platform-python, Anaconda invokes that binary on the section body. A shebang line is optional and is not required for the interpreter flag to work.
Omer Cakmak

Linux Administrator

Highly skilled at managing Debian, Ubuntu, CentOS, Oracle Linux, and Red Hat servers. Proficient in bash scripting, Ansible, and AWX central server management, he handles server operations on OpenStack, KVM, Proxmox, and VMware.

  • Debian
  • Ubuntu
  • Linux
  • Red Hat Enterprise Linux
  • Shell Script
  • System Administration