private/Initialize-OSDeployBootAssetPath.ps1
|
#Requires -PSEdition Core function Initialize-OSDeployBootAssetPath { <# .SYNOPSIS Migrates renamed OSDeploy Boot asset folders and profile paths .DESCRIPTION Migrates legacy shared script and wallpaper folders below Boot-Assets to their boot-prefixed names without overwriting destination conflicts. When ProfilePath is specified, profile-local script folders and matching saved WinPEScript and MediaScript path segments are migrated before profile validation. .PARAMETER ProfilePath Specifies an optional build profile directory containing osdeployboot.json. .EXAMPLE PS> Initialize-OSDeployBootAssetNames -ProfilePath 'C:\ProgramData\OSDeployCore\boot-assets\osdeployboot-profiles\Contoso-amd64' Migrates shared and Contoso profile content to the current asset folder names. .INPUTS None. This function does not accept pipeline input. .OUTPUTS None. .NOTES Author: David Segura Company: Recast Software Version: 1.0.0 Date: 2026-09-11 Destination-side conflicts are preserved. A legacy directory is removed only after all movable content has left it. Profile JSON is replaced atomically when changed. #> [CmdletBinding()] param ( [System.String] $ProfilePath ) $FunctionName = $MyInvocation.MyCommand.Name $moveDirectoryContent = { param ( [System.String]$SourcePath, [System.String]$DestinationPath ) if (-not (Test-Path -LiteralPath $SourcePath -PathType Container)) { return } if (-not (Test-Path -LiteralPath $DestinationPath -PathType Container)) { New-Item -ItemType Directory -Path $DestinationPath -Force | Out-Null } foreach ($Item in @(Get-ChildItem -LiteralPath $SourcePath -Force -ErrorAction SilentlyContinue)) { $DestinationItem = Join-Path $DestinationPath $Item.Name if (Test-Path -LiteralPath $DestinationItem) { if ($Item.PSIsContainer -and (Test-Path -LiteralPath $DestinationItem -PathType Container)) { & $moveDirectoryContent $Item.FullName $DestinationItem continue } Write-Warning "[$FunctionName] Could not migrate '$($Item.FullName)' because '$DestinationItem' already exists." continue } try { Move-Item -LiteralPath $Item.FullName -Destination $DestinationPath -ErrorAction Stop Write-Verbose "[$FunctionName] Migrated '$($Item.FullName)' to '$DestinationPath'" } catch { Write-Warning "[$FunctionName] Could not migrate '$($Item.FullName)' to '$DestinationPath': $($_.Exception.Message)" } } if (-not (Get-ChildItem -LiteralPath $SourcePath -Force -ErrorAction SilentlyContinue | Select-Object -First 1)) { Remove-Item -LiteralPath $SourcePath -Force -ErrorAction SilentlyContinue } } $SharedFolderMap = [ordered]@{ 'media-script' = 'boot-mediascript' 'build-mediascript' = 'boot-mediascript' 'winpe-script' = 'boot-winpescript' 'build-winpescript' = 'boot-winpescript' 'winpe-wallpaper' = 'boot-wallpaper' 'build-winpewallpaper' = 'boot-wallpaper' } foreach ($LegacyFolderName in $SharedFolderMap.Keys) { & $moveDirectoryContent ` (Join-Path $Script:OSDeployBootAssetsPath $LegacyFolderName) ` (Join-Path $Script:OSDeployBootAssetsPath $SharedFolderMap[$LegacyFolderName]) } if ([System.String]::IsNullOrWhiteSpace($ProfilePath) -or -not (Test-Path -LiteralPath $ProfilePath -PathType Container)) { return } $ProfileFolderMap = [ordered]@{ 'build-mediascript' = 'boot-mediascript' 'build-winpescript' = 'boot-winpescript' } foreach ($LegacyFolderName in $ProfileFolderMap.Keys) { & $moveDirectoryContent ` (Join-Path $ProfilePath $LegacyFolderName) ` (Join-Path $ProfilePath $ProfileFolderMap[$LegacyFolderName]) } $ProfileFile = Join-Path $ProfilePath 'osdeployboot.json' if (-not (Test-Path -LiteralPath $ProfileFile -PathType Leaf)) { return } try { $ProfileContent = Get-Content -LiteralPath $ProfileFile -Raw -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop $ProfileChanged = $false $PropertyFolderMap = [ordered]@{ WinPEScript = [ordered]@{ 'winpe-script' = 'boot-winpescript' 'build-winpescript' = 'boot-winpescript' } MediaScript = [ordered]@{ 'media-script' = 'boot-mediascript' 'build-mediascript' = 'boot-mediascript' } } foreach ($PropertyName in $PropertyFolderMap.Keys) { $Property = $ProfileContent.PSObject.Properties[$PropertyName] if (-not $Property -or $null -eq $Property.Value) { continue } $IsArray = $Property.Value -is [System.Array] $UpdatedValues = @( foreach ($Entry in @($Property.Value)) { $UpdatedEntry = $Entry if ($Entry -is [System.String]) { foreach ($LegacyFolderName in $PropertyFolderMap[$PropertyName].Keys) { $EscapedFolderName = [System.Text.RegularExpressions.Regex]::Escape($LegacyFolderName) $Pattern = "(^|[\\/])$EscapedFolderName(?=([\\/]|$))" $UpdatedEntry = $UpdatedEntry -ireplace $Pattern, "`${1}$($PropertyFolderMap[$PropertyName][$LegacyFolderName])" } if ($UpdatedEntry -cne $Entry) { $ProfileChanged = $true } } $UpdatedEntry } ) $Property.Value = if ($IsArray) { [System.Object[]]$UpdatedValues } else { $UpdatedValues[0] } } if ($ProfileChanged) { $TemporaryPath = Join-Path $ProfilePath ".$([System.Guid]::NewGuid()).tmp" try { $ProfileContent | ConvertTo-Json -Depth 5 -WarningAction SilentlyContinue | Out-File -LiteralPath $TemporaryPath -Encoding utf8 -ErrorAction Stop [System.IO.File]::Move($TemporaryPath, $ProfileFile, $true) } finally { if (Test-Path -LiteralPath $TemporaryPath) { Remove-Item -LiteralPath $TemporaryPath -Force -ErrorAction SilentlyContinue } } } } catch { Write-Warning "[$FunctionName] Could not update build profile '$ProfileFile': $($_.Exception.Message)" } } |