Public/Invoke-ATMDRegistryUpdate.ps1

function Invoke-ATMDRegistryUpdate {
    <#
    .SYNOPSIS
        Обновляет значения в реестре Windows.
    .DESCRIPTION
        Обновляет значение в реестре на основании представленных параметрв в виде объектов / хеш таблиц (см. пример).
    .PARAMETER RegistryValues
        Объект с описание ключей реестра (см. пример).
    .PARAMETER PassThru
        Используйте параметр -PassThru, чтобы получить список обработаных ключей реестра и код завершения операций.
    .EXAMPLE
        $Registry = @{
            keysToRemove = @('HKCU:\SOFTWARE\FluffyBeaver\keyToRemove1')
            keysToClear = @('HKCU:\SOFTWARE\ATMD\Script Operations\Network Places')
            keysToCreate = @('HKCU:\SOFTWARE\FluffyBeaver\keyToCreate1', 'HKCU:\SOFTWARE\FluffyBeaver\keyToCreate2')
            propertiesToRemove = @{
                key = 'HKCU:\SOFTWARE\FluffyBeaver'
                propertyName = 'propertiesToRemove1'
            }
 
            propertiesToClear = @{
                key = 'HKCU:\SOFTWARE\FluffyBeaver'
                propertyName = 'propertiesToClear1'
            }
            propertiesToSet = @(
                @{
                    key = 'HKCU:\SOFTWARE\ATMD\Environment Settings'
                    propertyName = 'RecycleBinAge'
                    propertyType = 'DWord'
                    value = '3'
                    description = 'Количество дней, которые файлы хранятся в Корзине'
                },
                {
                    key = 'HKCU:\SOFTWARE\ATMD\Environment Settings'
                    propertyName = 'DownloadsAge'
                    propertyType = 'DWord'
                    value = '7'
                    description = 'Количество дней, которые файлы хранятся в папке "Загрузки"'
                },
                {
                    key = 'HKCU:\SOFTWARE\ATMD\Environment Settings'
                    propertyName = 'DesktopWallpaperImagePath'
                    propertyType = 'String'
                    value = 'C:\Tools\_aux\pic\Wallpaper.jpg'
                    description = 'Путь к файлу картинке Рабочего стола'
                },
                {
                    key = 'HKCU:\SOFTWARE\ATMD\Environment Settings'
                    propertyName = 'BgInfoSettingsPath'
                    propertyType = 'String'
                    value = 'C:\Tools\BGInfo\BGInfo.bgi'
                    description = 'Путь к файлу параметров Backgroud Info (BGInfo)'
                },
                {
                    key = 'HKCU:\Keyboard Layout\Preload'
                    propertyName = '1'
                    propertyType = 'String'
                    value = '00000419'
                    description = 'Раскладка клавиатуры №419'
                },
                {
                    key = 'HKCU:\Keyboard Layout\Preload'
                    propertyName = '2'
                    propertyType = 'String'
                    value = '00000409'
                    description = 'Раскладка клавиатуры №409'
                }
            )
        }
 
        Invoke-ATMDRegistryUpdate -RegistryValues $Registry -PassThru -Verbose
    .INPUTS
        Перечень ключей и значний реестра, которые необходимо модифицировать
    .OUTPUTS
        Функция возвращает объект, содержащий перечень удалнных, обнавленных и созданных ключей реестра и их параметров, если указан параметр -PassThru
    .NOTES
        Цель написания этой функции - возможность быстро править ключи реестра на основании описания, которое будте храниться в JSON-файле.
        Фактически, данная функция просто собирает вместе несколько командлетов Powershell, и ряд стандартный проверок, вроде Test-Path и т.п.
        Возвращаемый результат и коды ошибок описаны следующим образом:
 
        $RESULT_REMOVE_REGKEY_EXCEPTION = 128 #Ошибка при удалении ключа реестра.
        $RESULT_CLEAR_REGKEY_EXCEPTION = 64 #Ошибка при очистки ключа реестра.
        $RESULT_CREATE_REGKEY_EXCEPTION = 32 #Ошибка при создании ключа реестра.
        $RESULT_REMOVE_REGPROPERTY_EXCEPTION = 16 #Ошибка при удалении значений ключа реестра.
        $RESULT_CLEAR_REGPROPERTY_EXCEPTION = 8 #Ошибка при очистки значений ключа реестра.
        $RESULT_SET_REGPROPERTY_EXCEPTION = 4 #Ошибка при установки значений ключа реестра.
        $RESULT_NO_ERROR = 0 #Ошибок нет.
 
        $Result = [PSCustomObject]@{
            RemovedKeys = @()
            CleanedKeys = @()
            CreatedKeys = @()
            RemovedProperties = @()
            CleanedProperties = @()
            SetProperties = @()
            ProblemItems = @()
            ExitCode = $RESULT_NO_ERROR
        }
 
        В массив $Result.ProblemItems попадают элементы, при работе с которыми возникли исключения. Остальные названия, думаю, понятны.
        Коды ошибок объединяются бинарными операциями. То есть, значение 96 указывает, что произошли ошибки при очистки ключа реестра и при создании ключа реестра:
        ($RESULT_CLEAR_REGKEY_EXCEPTION -bor $RESULT_CREATE_REGKEY_EXCEPTION) рабно 96.
    #>

    [CmdletBinding()]
    [OutputType([System.Object])]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0)]
        [System.Object]
        $RegistryValues,

        [Parameter(Mandatory = $false, ValueFromPipeline = $false, Position = 1)]
        [switch]
        $PassThru = $false
    )

    begin {
        # Для удобства чтения - коды ошибок в виде переменных с мнемоническими названиями.
        $RESULT_REMOVE_REGKEY_EXCEPTION = 128  #Ошибка при удалении ключа реестра.
        $RESULT_CLEAR_REGKEY_EXCEPTION = 64  #Ошибка при очистки ключа реестра.
        $RESULT_CREATE_REGKEY_EXCEPTION = 32  #Ошибка при создании ключа реестра.
        $RESULT_REMOVE_REGPROPERTY_EXCEPTION = 16  #Ошибка при удалении значений ключа реестра.
        $RESULT_CLEAR_REGPROPERTY_EXCEPTION = 8  #Ошибка при очистки значений ключа реестра.
        $RESULT_SET_REGPROPERTY_EXCEPTION = 4  #Ошибка при установки значений ключа реестра.
        $RESULT_NO_ERROR = 0  #Ошибок нет.

        $Result = [PSCustomObject]@{
            RemovedKeys       = @()
            CleanedKeys       = @()
            CreatedKeys       = @()
            RemovedProperties = @()
            CleanedProperties = @()
            SetProperties     = @()
            ProblemItems      = @()
            ExitCode          = $RESULT_NO_ERROR
        }
    }

    process {
        try {
            if ($IsLinux) {
                throw [System.Configuration.ConfigurationException]::New('This operation system does not supported.')
            }
            #region Удаляем ключи
            foreach ($Key in $RegistryValues.keysToRemove) {
                try {
                    if (Test-Path -Path $Key) {
                        Write-Verbose -Message "<Invoke-ATMDRegistryUpdate> Удаляем ключ $Key"
                        Remove-Item -Path $Key -Recurse -ErrorAction Stop
                        $Result.RemovedKeys += $Key
                    }
                }
                catch {
                    Write-Error -Message "При удалении ключа реестра $Key произшла ошибка $($PSItem.Exception.Message)"
                    $Result.ProblemItems += $Key
                    $Result.ExitCode = $Result.ExitCode -bor $RESULT_REMOVE_REGKEY_EXCEPTION
                }
            }
            #endregion Удаляем ключи

            #region Очищаем ключи
            foreach ($Key in $RegistryValues.keysToClear) {
                try {
                    if (Test-Path -Path $Key) {
                        Write-Verbose -Message "<Invoke-ATMDRegistryUpdate> Очищаем ключ $Key"
                        Clear-Item -Path $Key -ErrorAction Stop
                        $Result.CleanedKeys += $Key
                    }
                }
                catch {
                    Write-Error -Message "При очистки ключа реестра $Key произшла ошибка $($PSItem.Exception.Message)"
                    $Result.ProblemItems += $Key
                    $Result.ExitCode = $Result.ExitCode -bor $RESULT_CLEAR_REGKEY_EXCEPTION
                }
            }
            #endregion Очищаем ключи

            #region Создаем ключи
            foreach ($Key in $RegistryValues.keysToCreate) {
                try {
                    if (-not(Test-Path -Path $Key)) {
                        Write-Verbose -Message "<Invoke-ATMDRegistryUpdate> Создаем ключ $Key"
                        New-Item -Path $Key -Force -ErrorAction Stop
                        $Result.CreatedKeys += $Key
                    }
                }
                catch {
                    Write-Error -Message "При создании ключа реестра $Key произшла ошибка $($PSItem.Exception.Message)"
                    $Result.ProblemItems += $Key
                    $Result.ExitCode = $Result.ExitCode -bor $RESULT_CREATE_REGKEY_EXCEPTION
                }
            }
            #endregion Создаем ключи

            #region Удаляем значения
            foreach ($Property in $RegistryValues.propertiesToRemove) {
                try {
                    $CurrentValue = Get-ItemProperty -Path $Property.key -Name $Property.propertyName -ErrorAction SilentlyContinue
                    if ($CurrentValue) {
                        Write-Verbose -Message "<Invoke-ATMDRegistryUpdate> Удаляем значение $($Property.propertyName) ключа $($Property.key)"
                        Remove-ItemProperty -Path $Property.key -Name $Property.propertyName -ErrorAction Stop
                    }
                    else {
                        Write-Verbose -Message "<Invoke-ATMDRegistryUpdate> Значение $($Property.propertyName) ключа $($Property.key) не существует."
                    }
                    $Result.RemovedProperties += $($Property.key, $Property.propertyName -join '\')
                }
                catch {
                    Write-Error -Message "При удалении значения $($Property.propertyName) ключа реестра $($Property.key) произшла ошибка $($PSItem.Exception.Message)"
                    $Result.ProblemItems += $($Property.key, $Property.propertyName -join '\')
                    $Result.ExitCode = $Result.ExitCode -bor $RESULT_REMOVE_REGPROPERTY_EXCEPTION
                }
            }
            #endregion Удаляем значения

            #region Очищаем значения
            foreach ($Property in $RegistryValues.propertiesToClear) {
                try {
                    $CurrentValue = Get-ItemProperty -Path $Property.key -Name $Property.propertyName -ErrorAction SilentlyContinue
                    if ($CurrentValue) {
                        Write-Verbose -Message "<Invoke-ATMDRegistryUpdate> Очищаем значение $($Property.propertyName) ключа $($Property.key)"
                        Clear-ItemProperty -Path $Property.key -Name $Property.propertyName -ErrorAction Stop
                    }
                    else {
                        Write-Verbose -Message "<Invoke-ATMDRegistryUpdate> Значение $($Property.propertyName) ключа $($Property.key) не существует."
                    }
                    $Result.CleanedProperties += $($Property.key, $Property.propertyName -join '\')
                }
                catch {
                    Write-Error -Message "При очистки значения $($Property.propertyName) ключа реестра $($Property.key) произшла ошибка $($PSItem.Exception.Message)"
                    $Result.ProblemItems += $($Property.key, $Property.propertyName -join '\')
                    $Result.ExitCode = $Result.ExitCode -bor $RESULT_CLEAR_REGPROPERTY_EXCEPTION
                }
            }
            #endregion Очищаем значения

            #region Устанавливаем значения
            foreach ($Property in $RegistryValues.propertiesToSet) {
                try {
                    $CurrentValue = Get-ItemProperty -Path $Property.key -Name $Property.propertyName -ErrorAction SilentlyContinue
                    Write-Verbose -Message "<Invoke-ATMDRegistryUpdate> Устанавливаем значение $($Property.propertyName) ключа $($Property.key) в значение $($Property.value)"
                    # Тут будет подготовка значения для записи в реестр.
                    # Пока необходимость выявлена только для типа Binary
                    switch ($Property.propertyType) {
                        'Binary' {
                            $ValueToSet = $null
                            $Property.value -split ',' | ForEach-Object -Process {
                                $ValueToSet += [byte[]]($PSItem)
                            }
                            break
                        }
                        Default {
                            $ValueToSet = $Property.value
                        }
                    }
                    if (-not($CurrentValue)) {
                        if (-not(Test-Path -Path $Property.key)) {
                            New-Item -Path $Property.key -Force
                        }
                        New-ItemProperty -Path $Property.key -Name $Property.propertyName -PropertyType $Property.propertyType -Value $ValueToSet -ErrorAction Stop
                    }
                    else {
                        Set-ItemProperty -Path $Property.key -Name $Property.propertyName -Value $ValueToSet -ErrorAction Stop
                    }
                    $Result.SetProperties += $($Property.key, $Property.propertyName -join '\')
                }
                catch {
                    Write-Error -Message "При установкезначения $($Property.propertyName) ключа реестра $($Property.key) произшла ошибка $($PSItem.Exception.Message)"
                    $Result.ProblemItems += $($Property.key, $Property.propertyName -join '\')
                    $Result.ExitCode = $Result.ExitCode -bor $RESULT_SET_REGPROPERTY_EXCEPTION
                }
            }
            #endregion Устанавливаем значения
        }
        catch {
            # $PSCmdlet.ThrowTerminatingError($PSitem)
            Write-Error -Exception $PSItem.Exception
        }
    }

    end {
        if ($PassThru) {
            return $Result
        }
    }
}


# $Configuration = Get-Content -Path 'E:\Git\IaC\environment-config\LogonScripts\Atmd-LogonScript.json' -ErrorAction Stop | ConvertFrom-Json
# #$FileDeployment = ($Configuration | Where-Object { ($_.optionClass -eq 'UserSpecific') -and ($_.userName -eq 'ATMD\ilichev') }).options.registry
# $FileDeployment = ($Configuration | Where-Object { ($_.optionClass -eq 'general')}).options.registry
# Invoke-ATMDRegistryUpdate -RegistryValues $FileDeployment -PassThru -Verbose