| 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
/tmpthat%post --nochrootcan 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
networklines
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:
%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
%endBOOTIF 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.
/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:
sudo head -20 /var/log/kickstart_pre.logSample output shape from the lab harness:
=== %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=unsetThe %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:
%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}"
%endPair with kickstart storage lines:
ignoredisk --drives=sdb
clearpart --all --initlabel --drives=sda
autopart --type=lvm --nohomeExample 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:
%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"
%endAfter install, when logs were copied to /var/log/:
cat /var/log/kickstart_python_pre.log
cat /var/log/kickstart_bash_pre.logThis is a sample python script called at %pre stage
This is a sample bash script called at %pre stageExample 4: %pre-install on mounted sysimage
Log layout after partitions exist but before packages install:
%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
%endCompare %pre and %pre-install logs. The latter should show mount points under /mnt/sysimage. After install, when the log was copied:
sudo grep -E 'sysimage|sysroot' /var/log/kickstart_pre_install.log/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:
%pre
#!/bin/bash
touch /tmp/pre-without-log-marker
%endCopy markers and logs in %post --nochroot:
%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
%endReferences
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.

