private/Install-SoftwareMicrosoftDeploymentToolkit.ps1
|
function Install-SoftwareMicrosoftDeploymentToolkit { <# .SYNOPSIS Downloads and installs Microsoft Deployment Toolkit from module metadata .DESCRIPTION Reads the MDT version, MSI URL, SHA256 hash, and retirement URL from OSDeploy module metadata. The function detects an installed MDT version, downloads or reuses the x64 MSI, validates its SHA256 hash, and installs it silently with msiexec when MDT is not already installed. DownloadOnly verifies and caches the installer without installing it. WhatIf and Confirm apply to the combined download, verification, and installation operation, although the version-specific cache directory is created before ShouldProcess. .PARAMETER DownloadOnly Downloads and verifies the MDT MSI without installing it. .EXAMPLE PS> Install-SoftwareMicrosoftDeploymentToolkit Downloads and verifies the configured MDT MSI and installs it when MDT is absent. .EXAMPLE PS> Install-SoftwareMicrosoftDeploymentToolkit -DownloadOnly Downloads and verifies the configured MDT MSI without installing it. .INPUTS None. This function does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject. Returns the detected or installed version, operation status, installer path and URL, and expected SHA256 hash. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-08-28 Requires Windows, Administrator rights, curl.exe, msiexec.exe, and complete $global:OSDeployModule.Software.mdt metadata. The function displays Microsoft's MDT retirement notice on every invocation. Change Summary: - Added metadata-driven download, checksum validation, and retirement guidance. .LINK https://learn.microsoft.com/en-us/intune/configmgr/mdt/ .LINK https://learn.microsoft.com/en-us/troubleshoot/mem/configmgr/mdt/mdt-retirement .LINK https://web.archive.org/web/20250616094712id_/https://download.microsoft.com/download/3/3/9/339BE62D-B4B8-4956-B58D-73C4685FC492/MicrosoftDeploymentToolkit_x64.msi #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] [OutputType([pscustomobject])] param ( [switch] $DownloadOnly ) if (-not $IsWindows) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Install-SoftwareMicrosoftDeploymentToolkit is supported only on Windows." } if (-not (Test-IsAdministrator)) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Install-SoftwareMicrosoftDeploymentToolkit requires Administrator rights. Re-run PowerShell as Administrator and try again." } $curl = Get-Command -Name 'curl.exe' -ErrorAction SilentlyContinue if (-not $curl) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] curl.exe is required but was not found. Ensure curl.exe is available in PATH (included with Windows 10 1803+)." } $msiExec = Get-Command -Name 'msiexec.exe' -ErrorAction SilentlyContinue if (-not $msiExec) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] msiexec.exe is required but was not found." } if (-not $global:OSDeployModule -or -not $global:OSDeployModule.Software.mdt) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] OSDeployCore module metadata is missing required mdt configuration." } $mdtConfig = $global:OSDeployModule.Software.mdt $retirementUrl = [string]$mdtConfig.retirement $mdtUrl = [string]$mdtConfig.msi $expectedSha256 = ([string]$mdtConfig.sha256).ToLowerInvariant() $expectedVersion = [string]$mdtConfig.version Write-Warning "[$(Get-Date -Format s)] Microsoft Deployment Toolkit (MDT) has an immediate retirement notice from Microsoft." Write-Warning "[$(Get-Date -Format s)] $retirementUrl" if ([string]::IsNullOrWhiteSpace($mdtUrl) -or [string]::IsNullOrWhiteSpace($expectedSha256) -or [string]::IsNullOrWhiteSpace($expectedVersion)) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] OSDeployCore module metadata mdt is incomplete. Required keys: msi, sha256, version." } $uninstallPaths = @( 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' ) $installedMdt = $null foreach ($uninstallPath in $uninstallPaths) { $installedMdt = Get-ItemProperty -Path $uninstallPath -ErrorAction SilentlyContinue | Where-Object { $_.PSObject.Properties['DisplayName'] -and $_.DisplayName -like 'Microsoft Deployment Toolkit*' } | Select-Object -First 1 if ($installedMdt) { break } } if ($installedMdt) { $installedVersion = [string]$installedMdt.DisplayVersion if ($installedVersion -eq $expectedVersion) { Write-Host "[$(Get-Date -Format s)] Microsoft Deployment Toolkit is already installed: $installedVersion (expected: $expectedVersion)" -ForegroundColor Green } else { Write-Warning "[$(Get-Date -Format s)] Microsoft Deployment Toolkit is installed but version mismatch. Installed: $installedVersion, Expected: $expectedVersion" } } $downloadDir = Join-Path -Path $Script:OSDeployCoreSoftwarePath -ChildPath "Microsoft.DeploymentToolkit_$expectedVersion" New-Item -Path $downloadDir -ItemType Directory -Force | Out-Null $installerPath = Join-Path -Path $downloadDir -ChildPath 'MicrosoftDeploymentToolkit_x64.msi' $skippedInstall = $false if ($PSCmdlet.ShouldProcess('Microsoft Deployment Toolkit', 'Download, verify SHA256, and install silently')) { $actualSha256 = if (Test-Path -Path $installerPath -PathType Leaf) { (Get-FileHash -Path $installerPath -Algorithm SHA256).Hash.ToLowerInvariant() } if ($actualSha256 -eq $expectedSha256) { Write-Host "[$(Get-Date -Format s)] Using cached Microsoft Deployment Toolkit MSI." -ForegroundColor DarkGray } else { Remove-Item -Path $installerPath -Force -ErrorAction SilentlyContinue Write-Host "[$(Get-Date -Format s)] Downloading Microsoft Deployment Toolkit MSI..." -ForegroundColor DarkGray & $curl.Source --insecure --location --retry 5 --output $installerPath --url $mdtUrl if ($LASTEXITCODE -ne 0) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] Failed to download MDT MSI (curl.exe exit code $LASTEXITCODE)." } $actualSha256 = (Get-FileHash -Path $installerPath -Algorithm SHA256).Hash.ToLowerInvariant() } if ($actualSha256 -ne $expectedSha256) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] MDT MSI checksum mismatch. Expected $expectedSha256 but got $actualSha256." } if ($DownloadOnly) { Write-Host "[$(Get-Date -Format s)] DownloadOnly: skipping installation." -ForegroundColor DarkGray return [pscustomobject]@{ ProductName = 'Microsoft Deployment Toolkit' Version = $expectedVersion WasInstalled = $false SkippedInstall = $false InstallerPath = $installerPath InstallerUrl = $mdtUrl Sha256 = $actualSha256 DownloadOnly = $true } } if ($installedMdt) { # MDT already installed; skip re-install return [pscustomobject]@{ ProductName = $installedMdt.DisplayName Version = $installedVersion WasInstalled = $false SkippedInstall = $true InstallerPath = $installerPath InstallerUrl = $mdtUrl Sha256 = $actualSha256 } } Write-Host "[$(Get-Date -Format s)] Installing Microsoft Deployment Toolkit..." -ForegroundColor DarkGray $msiArgs = @('/i', $installerPath, '/qn', '/norestart') $process = Start-Process -FilePath $msiExec.Source -ArgumentList $msiArgs -Wait -PassThru if ($process.ExitCode -ne 0) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] MDT installation failed with exit code $($process.ExitCode)." } Update-OSDeploySessionEnvironment $installedMdt = $null foreach ($uninstallPath in $uninstallPaths) { $installedMdt = Get-ItemProperty -Path $uninstallPath -ErrorAction SilentlyContinue | Where-Object { $_.PSObject.Properties['DisplayName'] -and $_.DisplayName -like 'Microsoft Deployment Toolkit*' } | Select-Object -First 1 if ($installedMdt) { break } } if (-not $installedMdt) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] MDT install completed but product was not found in uninstall registry." } $installedVersion = [string]$installedMdt.DisplayVersion if ($installedVersion -ne $expectedVersion) { throw "[$(Get-Date -Format s)] [$($MyInvocation.MyCommand.Name)] MDT installation completed but version mismatch. Installed: $installedVersion, Expected: $expectedVersion." } Write-Host "[$(Get-Date -Format s)] Microsoft Deployment Toolkit installed successfully: $installedVersion" -ForegroundColor Green return [pscustomobject]@{ ProductName = $installedMdt.DisplayName Version = $installedVersion WasInstalled = $true SkippedInstall = $false InstallerPath = $installerPath InstallerUrl = $mdtUrl Sha256 = $actualSha256 } } $skippedInstall = $true [pscustomobject]@{ ProductName = 'Microsoft Deployment Toolkit' Version = $null WasInstalled = $false SkippedInstall = $skippedInstall InstallerPath = $installerPath InstallerUrl = $mdtUrl Sha256 = $expectedSha256 } } |