Overview
Script Running the script Why not do this manually
imagick powershell
Written: Mar-2026

Installing imagick on a Windows localhost WAMP

Fed up with the ambiguity in installing imagick on Windows, I decided to script it up. I run a number of environments - linux and Windows - and the Windows one had problems with installing imagick after upgrades. This comes down to a problem with the installation location of the CORE_*dll and IM_MOD_RL*dll files which seem to need to be in the ImageMagic folder instead of the PHP location.

Script

It's not pretty - but I found this worked for me...

Place this script into a tools folder that your Windows path runs through, I use c:/wamp64/bin folder and the script assumes that - if you are using a different location then check line 97

powerscript  ::  c:/wamp64/bin/install-imagick.ps1

################################################
# install-imagick.ps1 - Install or repair Imagick for WAMP PHP
# Features: automatic version detection, download/cache, stray DLL quarantine, ImageMagick check
################################################

# 1 - Detect Apache and PHP via live probe 
Write-Host "nn"
Write-Host "################################################" -ForegroundColor Gray
$tsNow = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

$tsNow = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
do {
    # Check if Apache is running (httpd process)
    $apache = Get-Process -Name "httpd" -ErrorAction SilentlyContinue
    if ($apache) {
        Write-Host "    Apache is running. Continuing..." -ForegroundColor Green
        break
    }

    Write-Host "    $tsNow" -ForegroundColor Yellow
    $response = Read-Host "    WAMP/Apache is not detected as running. Please start WAMP and press [Enter]"
    $tsNow = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
} while (-not $apache)

Write-Host "`n    - Detecting Apache and PHP via live probe -" -ForegroundColor Cyan
$apacheService = Get-WmiObject Win32_Service | Where-Object { $_.Name -match "apache" }
if (!$apacheService) {
    Write-Host "ERROR: No Apache service detected." -ForegroundColor Red
    return
}

$apacheExePath = $apacheService.PathName -replace '"',''
$apacheExePath = $apacheExePath.Split(" ")[0]
$apacheDir = Split-Path $apacheExePath
Write-Host "    Apache executable detected at: " -ForegroundColor Green -NoNewline
Write-Host "$apacheExePath"




# 2 - Extract DocumentRoot 
Push-Location $apacheDir
$configDump = & $apacheExePath -t -D DUMP_RUN_CFG 2>&1
Pop-Location
$docRootLine = $configDump | Where-Object { $_ -match "DocumentRoot" }
if (!$docRootLine) { Write-Host "ERROR: Could not detect DocumentRoot." -ForegroundColor Red; return }
$docRoot = ($docRootLine -replace '.*"(.*)".*','$1').Trim()
Write-Host "    DocumentRoot detected: " -ForegroundColor Green -NoNewline
Write-Host "$docRoot"




# 3 - Probe Apache PHP 
$probeFileName = "__apache_php_probe.php"
$probePath = Join-Path $docRoot $probeFileName
$probeCode = @"
<?php
echo json_encode([
    'php_ini' => php_ini_loaded_file(),
    'version' => PHP_VERSION,
    'majorMinor' => PHP_MAJOR_VERSION.'.'.PHP_MINOR_VERSION,
    'zts' => PHP_ZTS ? 'TS' : 'NTS',
    'arch' => PHP_INT_SIZE*8 . 'bit',
    'extension_dir' => ini_get('extension_dir'),
    'modules' => get_loaded_extensions()
]);
?>
"@
Set-Content -Path $probePath -Value $probeCode -Encoding ASCII
$probeUrl = "http://localhost/$probeFileName"
try {
    $apachePhpInfo = (Invoke-WebRequest $probeUrl -UseBasicParsing -TimeoutSec 5).Content | ConvertFrom-Json
}
catch {
    Write-Host "    ERROR: Could not access localhost. Is Apache running?" -ForegroundColor Red
    Remove-Item $probePath -ErrorAction SilentlyContinue
    return
}




# 4 - Set PHP variables 
$phpVer  = $apachePhpInfo.majorMinor
$iniPath = $apachePhpInfo.php_ini
$arch    = if ($apachePhpInfo.arch -eq '64bit') { 'x64' } else { 'x86' }
$ts      = $apachePhpInfo.zts
$apacheExtensionDir = $apachePhpInfo.extension_dir
$apacheModules      = $apachePhpInfo.modules




# 5 - Detect PHP executable in WAMP 
$wampPath = "C:\wamp64\bin\php"
$phpDirs  = Get-ChildItem -Path $wampPath -Directory
$phpExe   = $phpDirs | ForEach-Object {
    $candidate = Join-Path $_.FullName "php.exe"
    if (Test-Path $candidate) {
        return $candidate
    }
} | Select-Object -First 1

if (-not $apacheExtensionDir) {
    Write-Host "    ERROR: Could not locate php.exe.nn`n" -ForegroundColor Red
    return
}
$phpDir = Split-Path $apacheExtensionDir
$extDir = Join-Path $phpDir "ext"
Write-Host "    Apache PHP version detected: " -ForegroundColor Green -NoNewline
Write-Host "$phpVer ($ts, $arch)"
Write-Host "    Apache php.ini detected at: " -ForegroundColor Green -NoNewline
Write-Host "$iniPath"
Write-Host "    Using [Apache] PHP executable: " -ForegroundColor Green -NoNewline
Write-Host "$apacheExtensionDir`n"



# 6 - Check ImageMagick 
Write-Host "`n    - Checking for ImageMagick installation -" -ForegroundColor Cyan
$magickExe = Get-Command IMDisplay.exe -ErrorAction SilentlyContinue
if ($magickExe) {
    # Determine actual path to the exe
    $exePath = if ($magickExe.Source) { $magickExe.Source } else { $magickExe.Definition }
    $magickDir = Split-Path $exePath

    Write-Host "    ImageMagick found in PATH: $exePath in $magickDir" -ForegroundColor Green
}
else {
    Write-Host "    ImageMagick not found. You may install it from https://imagemagick.org" -ForegroundColor Red
    return
}
# 6.1 - Check Windows PATH includes ImageMagick folder 
Write-Host "`n    - Verifying ImageMagick folder is in Windows PATH -" -ForegroundColor Cyan
if ($magickDir) {
    # Get current PATH as an array
    $pathEntries = $env:Path -split ';'
    # Normalize: remove trailing slashes, case-insensitive
    $pathEntriesNormalized = $pathEntries | ForEach-Object { ($_ -replace '\\+$','').ToLower() }
    $magickDirNormalized    = $magickDir.TrimEnd('\').ToLower()
    if ($pathEntriesNormalized -contains $magickDirNormalized) {
        Write-Host "    ImageMagick folder is present in PATH: $magickDir" -ForegroundColor Green
    }
    else {
        Write-Host "    WARNING: ImageMagick folder is NOT in PATH: $magickDir" -ForegroundColor Red
        Read-Host "    Please confirm you have added it to your system PATH environment variable before continuing"
    }
}



# 7 - Detect correct Imagick build 
Write-Host "`n    - Checking for for php_imagick download -" -ForegroundColor Cyan
$zipName = "php_imagick-3.7.0-$phpVer-$ts-vs16-$arch.zip"
$fullUrl = "https://downloads.php.net/~windows/pecl/releases/imagick/3.7.0/$zipName"
$cacheDir = Join-Path $wampPath "_imagick_cache"
if (!(Test-Path $cacheDir)) {
    New-Item -ItemType Directory -Path $cacheDir | Out-Null
}
$tempZip = Join-Path $cacheDir $zipName
$tempDir = Join-Path $env:TEMP "imagick_files"
if (Test-Path $tempDir) {
    Remove-Item $tempDir -Recurse -Force
}

if (-not (Test-Path $tempZip)) {
    Write-Host "    Downloading " -ForegroundColor Green -NoNewline
    Write-Host "$zipName ..." -ForegroundColor Gray -NoNewline
    Write-Host "..." -ForegroundColor Green -NoNewline
    [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
    Invoke-WebRequest -Uri $fullUrl -OutFile $tempZip -UseBasicParsing
} else {
    Write-Host "    Using cached download: " -ForegroundColor Green -NoNewline
    Write-Host "$tempZip" -ForegroundColor Gray
}

# Extract DLLs for reference
Write-Host "    Expanding downloaded file..."  -ForegroundColor Green
Expand-Archive -Path $tempZip -DestinationPath $tempDir -Force
$expectedDLLs = Get-ChildItem $tempDir -Filter "*.dll" | ForEach-Object { $_.Name }


# 7.1 Ensure WAMP is stopped
do {
    # Check if Apache is running (httpd process)
    Write-Host "    WAMP/Apache now needs to be stopped..." -ForegroundColor Green
    $apache = Get-Process -Name "httpd" -ErrorAction SilentlyContinue
    if ($apache) {
        $response = Read-Host "    Please now stop WAMP and press [Enter] to continue (timestamp:$tsNow)"
    }

    $apache = Get-Process -Name "httpd" -ErrorAction SilentlyContinue
    $tsNow = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
} while ($apache)
Write-Host "    WAMP/Apache seen as stopped..." -ForegroundColor Green




# 8 - Checking for stray DLLs in PHP folders or full-drive (optional) 
Write-Host "`n    - Checking for stray Imagick files -" -ForegroundColor Cyan
# Ask the user if they want a deep scan
$deepSearch = Read-Host "    Perform deep scan for stray Imagick DLLs across the drive? [y/N]"
$searchDrives = if ($deepSearch -match '^[Yy]') { Get-PSDrive -PSProvider FileSystem } else { $phpDirs }
# Collect all DLLs from the downloaded zip
$zipDlls = Get-ChildItem $tempDir -Filter "*.dll" -File
# Separate deployment destinations
$phpDlls   = $zipDlls | Where-Object { $_.Name -like "php_*.dll" }
$otherDlls = $zipDlls | Where-Object { $_.Name -notlike "php_*.dll" }
# Case-insensitive HashSet of names from zip
$zipNameSet = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::OrdinalIgnoreCase)
foreach ($dll in $zipDlls) { $null = $zipNameSet.Add($dll.Name) }
# Expected PHP root & ext directories
$phpRootDirs = $phpDirs | ForEach-Object { $_.FullName }
$phpExtDirs  = $phpDirs | ForEach-Object { Join-Path $_.FullName "ext" }
# Start scanning
foreach ($driveOrFolder in $searchDrives) {
    $rootPath = if ($driveOrFolder -is [System.Management.Automation.PSDriveInfo]) { $driveOrFolder.Root } else { $driveOrFolder.FullName }
    Write-Host "    Scanning root: ${rootPath}" -ForegroundColor Green
    # List top-level folders first for trace
    $topFolders = Get-ChildItem -Path $rootPath -Directory -ErrorAction SilentlyContinue
    foreach ($top in $topFolders) {
        Write-Host ("`n        Scanning top-level folder: ") -ForegroundColor Green -NoNewline
        Write-Host ("$($top.FullName)") -ForegroundColor Gray
        $strayFilesByFolder = @{}  # init per top folder
        # Get all files in this top folder once
        Write-Host ("            Scanning folder...") -NoNewline -ForegroundColor Yellow
        Write-Host "`r" -NoNewline
        $allFiles = Get-ChildItem -Path $top.FullName -Recurse -File -ErrorAction SilentlyContinue |
                    Where-Object { $_.FullName -notmatch "_imagick_quarantine" }

        $counter = 0
        foreach ($f in $allFiles) {
            $counter++
            if ($counter % 123 -eq 0) {
                Write-Host ("            Checked $counter files ...") -ForegroundColor Yellow -NoNewline
                Write-Host "`r" -NoNewline
            }
            # Check PHP DLLs
            if ($phpDlls.Name -contains $f.Name -and $phpExtDirs -notcontains $f.DirectoryName) {
                if (-not $strayFilesByFolder.ContainsKey($f.DirectoryName)) { $strayFilesByFolder[$f.DirectoryName] = @() }
                $strayFilesByFolder[$f.DirectoryName] += $f
            }
            # Check other DLLs
            if ($otherDlls.Name -contains $f.Name -and $magickDir -notcontains $f.DirectoryName) {
                if (-not $strayFilesByFolder.ContainsKey($f.DirectoryName)) { $strayFilesByFolder[$f.DirectoryName] = @() }
                $strayFilesByFolder[$f.DirectoryName] += $f
            }
        }
        Write-Host "            Checked $counter files." -ForegroundColor Green # finish the counter line
        #  report and quarantine as before 
        foreach ($folder in $strayFilesByFolder.Keys) {
            $files = $strayFilesByFolder[$folder]
            Write-Host "`n            Stray files found in ${folder}:" -ForegroundColor Red
            foreach ($f in $files) {
                Write-Host ("                {0,-30} {1}" -f $f.Name, $f.LastWriteTime) -ForegroundColor Red
            }
            $quarantineDir = Join-Path $folder "_imagick_quarantine"
            $move = Read-Host "`n            Quarantine these files into $quarantineDir ? [y/N]"
            if ($move -match '^[Yy]') {
                if (!(Test-Path $quarantineDir)) { New-Item -ItemType Directory -Path $quarantineDir | Out-Null }
                foreach ($f in $files) { Move-Item $f.FullName -Destination $quarantineDir -Force }
                Write-Host "            Moved $($files.Count) file(s) to $quarantineDir" -ForegroundColor Green
            }
        }
    }
}



# 9 Install downloaded files...
Write-Host "`n    --- Preparing to install Imagick DLLs into $apacheDir and $magickDir..." -ForegroundColor Cyan
# 9.1. Define all DLL patterns to deploy
$copyPatterns = @(
    "php_imagick.dll",
    "CORE_RL_*.dll",
    "IM_MOD_RL_*.dll"
)
# 9.2. Stage 1 — Delete any existing DLLs
Write-Host "`n    Removing existing DLLs..." -ForegroundColor Cyan
foreach ($pattern in $copyPatterns) {
    $dllFiles = Get-ChildItem -Path $phpDir -Filter $pattern -ErrorAction SilentlyContinue
    foreach ($dll in $dllFiles) {
        Remove-Item $dll.FullName -Force -ErrorAction Stop
        #Write-Host "    Deleted existing ${dll.FullName}" -ForegroundColor Yellow
    }
}
Write-Host "`n    All old DLLs matching deploy patterns have been deleted."
# Read-Host "    Press Enter when ready to copy new DLLs into place (verify via File Explorer if desired)"
# 9.3. Stage 2 — Copy new DLLs into place
Write-Host "`n    Deploying new DLLs..." -ForegroundColor Cyan
foreach ($pattern in $copyPatterns) {
    $dllFiles = Get-ChildItem -Path $tempDir -Filter $pattern -ErrorAction SilentlyContinue
    foreach ($dll in $dllFiles) {
        # Determine destination folder
        $destPath = switch -Regex ($dll.Name) {
            "^php_imagick\.dll$" { Join-Path $extDir $dll.Name }
            "^CORE_RL_.*\.dll$"  { Join-Path $magickDir $dll.Name }
            "^IM_MOD_RL_.*\.dll$" { Join-Path $magickDir $dll.Name }
            Default { $null }
        }

        if (-not $destPath) {
            Write-Warning "No destination pattern matched for $($dll.Name), skipping..."
            continue
        }
        Copy-Item -Path $dll.FullName -Destination $destPath -Force
        Unblock-File $destPath
        Write-Host "    Copied $($dll.Name) to $destPath" -ForegroundColor Green
    }
}

Write-Host "`n    DLL deployment complete. Remember to restart Apache/WAMP services."
Write-Host "    DLLs installed and unblocked successfully." -ForegroundColor Green




# 10 - Final verification / cleanup -
Remove-Item $tempDir -Recurse -ErrorAction SilentlyContinue
Write-Host "`n    - REPAIR FINISHED -" -ForegroundColor Green
$tsNow = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
Write-Host "    IMPORTANT: Restart WAMP Services now."
Read-Host "    Please now restart WAMP and press [Enter] to continue (timestamp: $tsNow)"
# Verify CLI PHP
Write-Host "`n    Verifying Module Load via CLI..." -ForegroundColor Cyan
$check = & $phpExe -m | Select-String "imagick"
if ($check) { Write-Host "    RESULT: Imagick loaded successfully!" -ForegroundColor Green }
else { Write-Host "    WARNING: Imagick not loaded in CLI." -ForegroundColor Yellow }
# Verify Apache PHP
Write-Host "    Verifying Module Load via Apache PHP..." -ForegroundColor Cyan
$probeUrl = "http://localhost/$probeFileName"
try {
    $apachePhpInfo = (Invoke-WebRequest $probeUrl -UseBasicParsing -TimeoutSec 5).Content | ConvertFrom-Json
}
catch {
    Write-Host "    WARNING: Could not access Apache PHP probe.nn`n" -ForegroundColor Yellow; Remove-Item $probePath -ErrorAction SilentlyContinue
    return
}
if ($apachePhpInfo.modules -contains "imagick") {
    Write-Host "    RESULT: Imagick loaded successfully in Apache PHP!" -ForegroundColor Green
}
else {
    Write-Host "    WARNING: Imagick not loaded in Apache PHP. Check php.ini and Apache error_log." -ForegroundColor Yellow
}



# Cleanup probe
Remove-Item $probePath -ErrorAction SilentlyContinue
Write-Host "################################################" -ForegroundColor Gray
Write-Host "nn"

Running the script

Simply run the script using a PowerShell window...

The script will

1-5. create a small probe webpage to run on the localhost in order to acquire which versions you're running, and where

6. It then looks for the ImageMagick app and prompts the user to install it if not

7-8. Then it tries to download the appropriate php_imagick version from https://downloads.php.net/~windows/pecl/releases/imagick/... and then does a scan for "stray" versions of the files in the download, asking if you want to to quarantine them if they're not in the right places

9. It then replaces any existing DLLs with those found in the download, distributing the php_*dll into the php/ext folder, and the CORE_RL*.dll and IM_MOD_RL*.dll into the ImageMagick folder

You will find # comments in the script to match those numbered steps.

Why not do this manually

No reason - but this will do a scan to look for any "stray" files for you, and it will automate the download of the right install file based on the localhost web-probe - as you change versions of PHP you can just run this script again to get the right version installed without thinking about it.

WARNING : BUYER-BEWARE: This script will download and manipulate files on your Windows environment - take a moment to look through the script to ensure that no rogue commands run on your PC.

powershell output..
> install-imagick.ps1



################################################
    Apache is running. Continuing...

    - Detecting Apache and PHP via live probe -
    Apache executable detected at: c:\\wamp64\\bin\\apache\\apache2.4.54.2\\bin\\httpd.exe
    DocumentRoot detected: C:/wamp64/www
    Apache PHP version detected: 8.2 (TS, x64)
    Apache php.ini detected at: C:\\wamp64\\bin\\apache\\apache2.4.54.2\\bin\php.ini
    Using [Apache] PHP executable: c:/wamp64/bin/php/php8.2.0/ext/


    - Checking for ImageMagick installation -
    ImageMagick found in PATH: C:\ImageMagick\IMDisplay.exe in C:\ImageMagick

    - Verifying ImageMagick folder is in Windows PATH -
    ImageMagick folder is present in PATH: C:\ImageMagick

    - Checking for for php_imagick download -
    Using cached download: C:\\wamp64\\bin\\php\\_imagick_cache\\php_imagick-3.7.0-8.2-TS-vs16-x64.zip
    Expanding downloaded file...
    WAMP/Apache now needs to be stopped...
    Please now stop WAMP and press [Enter] to continue (timestamp:2026-03-04 18:03:18):


square