Private/Set-OSDStageOfflineTaskbar.ps1

function Set-OSDStageOfflineTaskbar {
    [CmdletBinding()]
    param([Parameter(Mandatory)][string]$WindowsPath,[Parameter(Mandatory)][AllowEmptyCollection()][object[]]$Pins,[Parameter(Mandatory)][scriptblock]$Commit)
    $mapping=Get-OSDStageTaskbarPinsPolicy -WindowsDirectory (Join-Path $WindowsPath 'Windows')
    $xml=ConvertTo-OSDStageTaskbarXml -Pins $Pins
    $path=Join-Path $WindowsPath 'Windows\OEM\OSDStage\TaskbarLayoutModification.xml'
    Invoke-OSDStageOfflineSoftware -WindowsPath $WindowsPath -Action {
        param($Software)
        $cv=$Software.OpenSubKey('Microsoft\Windows NT\CurrentVersion')
        try {
            if (-not $cv) { throw 'The target Windows version is missing.' }
            Assert-OSDStageTaskbarPinsPlatform -Build ([int]$cv.GetValue('CurrentBuildNumber')) -Revision ([int]$cv.GetValue('UBR')) -InstallationType ([string]$cv.GetValue('InstallationType')) -EditionId ([string]$cv.GetValue('EditionID'))
            $systemRoot=[string]$cv.GetValue('SystemRoot')
        }
        finally { if ($cv) { $cv.Dispose() } }
        if ($systemRoot -notmatch '^[A-Za-z]:\\Windows$') { throw 'Cannot resolve the future Windows directory from the target SOFTWARE hive.' }
        $futurePath=$systemRoot + '\OEM\OSDStage\TaskbarLayoutModification.xml'
        $key=$null;$owner=$null
        $old=$null;$oldKind=$null;$oldEnabled=$null;$oldEnabledKind=$null;$oldHash=$null;$oldBytes=$null;$written=$false
        try {
            $key=$Software.CreateSubKey($mapping.Key)
            if ($key.GetValue('ReapplyStartLayoutEveryLogon',0) -ne 0) { throw 'An existing policy forces the layout to apply again at every logon. Nothing was replaced.' }
            $owner=$Software.CreateSubKey('OSDStage\DesktopSettings')
            $old=$key.GetValue($mapping.FileName,$null,[Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
            if ($null -ne $old) { $oldKind=$key.GetValueKind($mapping.FileName) }
            $oldEnabled=$key.GetValue($mapping.EnabledName)
            if ($null -ne $oldEnabled) { $oldEnabledKind=$key.GetValueKind($mapping.EnabledName) }
            $oldHash=$owner.GetValue('TaskbarSha256')
            if ($null -ne $old -or $null -ne $oldEnabled -or (Test-Path -LiteralPath $path) -or $oldHash) {
                if ($old -ne $futurePath -or $oldEnabled -ne 1 -or $oldKind -ne $mapping.FileKind -or $oldEnabledKind -ne [Microsoft.Win32.RegistryValueKind]::DWord -or -not $oldHash -or -not (Test-Path -LiteralPath $path -PathType Leaf) -or
                    (Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash -ne $oldHash) { throw 'Existing taskbar configuration is not an intact OSDStage-owned layout. Nothing was replaced.' }
                $oldBytes=[IO.File]::ReadAllBytes($path)
            }
            New-Item -ItemType Directory -Path (Split-Path $path -Parent) -Force -ErrorAction Stop | Out-Null
            $written=$true;[IO.File]::WriteAllText($path,$xml,[Text.UTF8Encoding]::new($false))
            $key.SetValue($mapping.FileName,$futurePath,$mapping.FileKind)
            $key.SetValue($mapping.EnabledName,1,[Microsoft.Win32.RegistryValueKind]::DWord)
            $owner.SetValue('TaskbarSha256',(Get-FileHash -LiteralPath $path -Algorithm SHA256).Hash,[Microsoft.Win32.RegistryValueKind]::String)
            & $Commit
        }
        catch {
            if ($written) {
                if ($null -ne $oldBytes) { [IO.File]::WriteAllBytes($path,$oldBytes) } else { [IO.File]::Delete($path) }
                if ($null -ne $old) { $key.SetValue($mapping.FileName,$old,$oldKind) } else { $key.DeleteValue($mapping.FileName,$false) }
                if ($null -ne $oldEnabled) { $key.SetValue($mapping.EnabledName,$oldEnabled,$oldEnabledKind) } else { $key.DeleteValue($mapping.EnabledName,$false) }
                if ($oldHash) { $owner.SetValue('TaskbarSha256',$oldHash,[Microsoft.Win32.RegistryValueKind]::String) } else { $owner.DeleteValue('TaskbarSha256',$false) }
            }
            throw
        }
        finally { if ($owner) { $owner.Dispose() };if ($key) { $key.Dispose() } }
    }
}