Registry/Registry.ps1

#region Copyright & License

# Copyright © 2012 - 2022 François Chabot
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

#endregion

Set-StrictMode -Version Latest

<#
.SYNOPSIS
   Deletes a registry key if it is empty and, if the Recurse switch is used, recursively deletes all its empty ancestor keys, up to but not including the root key.
.DESCRIPTION
   This command deletes a registry key if it is empty and, if the Recurse switch is used, recursively deletes all its empty ancestor keys, up to but not including the
   root key.
.PARAMETER Key
   The name or path of the key.
.PARAMETER Recurse
   Whether to delete this key's empty ancestors as well.
.EXAMPLE
   PS> Clear-RegistryKey -Key HKLM:\SOFTWARE\BizTalk.Factory\BizTalk.Deployment\InstalledManifests
.EXAMPLE
   PS> Clear-RegistryKey -Key HKLM:\SOFTWARE\BizTalk.Factory\BizTalk.Deployment\InstalledManifests -Recurse
.NOTES
   © 2022 be.stateless.
#>

function Clear-RegistryKey {
   [CmdletBinding()]
   [OutputType([void])]
   param(
      [Parameter(Mandatory = $true)]
      [string]
      $Key,

      [Parameter(Mandatory = $false)]
      [switch]
      $Recurse
   )
   Resolve-ActionPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
   # proceeds while this key's parent has a parent and this parent's parent is not the drive, i.e. while not a root path, e.g. HKLM:\SOFTWARE, nor a drive, e.g. HKLM:\
   if ((Test-Path -Path $Key) -and ($i = Get-Item -Path $Key).PSParentPath -and (Get-Item -Path $i.PSParentPath).Name -ne $i.PSDrive.Root) {
      if ((Get-ChildItem -Path $Key | Test-None) -and (Get-ItemProperty -Path $Key | Test-None)) {
         Write-Verbose -Message "Registry clearing removed empty key '$Key'."
         Remove-Item -Path $Key
         if ($Recurse) {
            Clear-RegistryKey -Key (Split-Path -Path $Key -Parent) -Recurse
         }
      } else {
         Write-Verbose -Message "Registry clearing skipped non empty key '$Key'."
      }
   }
}

<#
.SYNOPSIS
   Gets the value of one entry under a specified registry key.
.DESCRIPTION
   This command gets the current value of a given entry located under a given registry key. It does not fail like the Get-ItemPropertyValue command if the key or entry
   does not exist and returns $null instead.
.PARAMETER Key
   The name or path of the key.
.PARAMETER Entry
   The name of the entry.
.EXAMPLE
   PS> Get-RegistryEntry -Key HKLM:\SOFTWARE\BizTalk.Factory\BizTalk.Deployment\InstalledManifests -Entry $Manifest.Properties.Name
.NOTES
   © 2022 be.stateless.
#>

function Get-RegistryEntry {
   [CmdletBinding()]
   [OutputType([object])]
   param(
      [Parameter(Position = 0, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [string]
      $Key,

      [Parameter(Position = 1, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [string]
      $Entry
   )
   Resolve-ActionPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
   if (Test-RegistryEntry -Key $Key -Entry $Entry) {
      Get-ItemPropertyValue -Path $Key -Name $Entry
   }
}

<#
.SYNOPSIS
   Deletes an entry under a registry key.
.DESCRIPTION
   This command deletes an entry under a registry key.
.PARAMETER Key
   The name or path of the key.
.PARAMETER Entry
   The name of the entry.
.EXAMPLE
   PS> Remove-RegistryEntry -Key HKLM:\SOFTWARE\BizTalk.Factory\BizTalk.Deployment\InstalledManifests -Entry $Manifest.Properties.Name
.NOTES
   © 2022 be.stateless.
#>

function Remove-RegistryEntry {
   [CmdletBinding()]
   [OutputType([void])]
   param(
      [Parameter(Position = 0, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [string]
      $Key,

      [Parameter(Position = 1, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [string]
      $Entry
   )
   Resolve-ActionPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
   if (Test-RegistryEntry -Key $Key -Entry $Entry) {
      Remove-ItemProperty -Path $Key -Name $Entry
   }
}

<#
.SYNOPSIS
   Creates or changes the value of an entry under a registry key.
.DESCRIPTION
   This command creates or changes the value of an entry under a registry key. This commands can also create a new key if it does not exist and the Force switch is
   used.
.PARAMETER Key
   The name or path of the key to create or open.
.PARAMETER Entry
   The name of the entry.
.PARAMETER Value
   The data to be stored.
.PARAMETER Type
   The registry data type to use when storing the data. The acceptable values for this parameter are:
   - Binary: Specifies binary data in any form. Used for REG_BINARY values.
   - DWord: Specifies a 32-bit binary number. Used for REG_DWORD values.
   - QWord: Specifies a 64-bit binary number. Used for REG_QWORD values.
   - String: Specifies a null-terminated string. Used for REG_SZ values.
   - MultiString: Specifies an array of null-terminated strings terminated by two null characters. Used for REG_MULTI_SZ values.
   - ExpandString: Specifies a null-terminated string that contains unexpanded references to environment variables that are expanded when the value is retrieved.
     Used for REG_EXPAND_SZ values.
   - Unknown: Indicates an unsupported registry data type, such as REG_RESOURCE_LIST values.
.PARAMETER Force
   Whether to create a new registry key if it does not exist.
.EXAMPLE
   PS> Set-RegistryEntry -Key HKLM:\SOFTWARE\BizTalk.Factory\BizTalk.Deployment\InstalledManifests -Entry $Manifest.Properties.Name -Value $Manifest.Properties.Path
.EXAMPLE
   PS> Set-RegistryEntry -Key HKLM:\SOFTWARE\Key -Entry name -Value 12 -Type DWord -Force
.NOTES
   © 2022 be.stateless.
#>

function Set-RegistryEntry {
   [CmdletBinding()]
   [OutputType([void])]
   param(
      [Parameter(Position = 0, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [string]
      $Key,

      [Parameter(Position = 1, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [string]
      $Entry,

      [Parameter(Position = 2, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [object]
      $Value,

      [Parameter(Position = 3, Mandatory = $false)]
      [ValidateNotNullOrEmpty()]
      [Microsoft.Win32.RegistryValueKind]
      $Type,

      [Parameter(Mandatory = $false)]
      [switch]
      $Force
   )
   Resolve-ActionPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
   if (-not(Test-Path -Path $Key) -and $Force) {
      New-Item -Path $Key -Force | Out-Null
   }
   if (Test-RegistryEntry -Key $Key -Entry $Entry) {
      Set-ItemProperty -Path $Key -Name $Entry -Value $Value
   } else {
      New-ItemProperty -Path $Key -Name $Entry -Value $Value -PropertyType $Type | Out-Null
   }
}


<#
.SYNOPSIS
   Determines if an entry under a registry key exists.
.DESCRIPTION
   This command determines if an entry under a registry key exists. It returns $True if the key exists and contains the entry. It returns $False otherwise.
.PARAMETER Key
   The name or path of the key.
.PARAMETER Entry
   The name of the entry.
.EXAMPLE
   PS> Test-RegistryEntry -Key HKLM:\SOFTWARE\BizTalk.Factory\BizTalk.Deployment\InstalledManifests -Entry $Manifest.Properties.Name
.NOTES
   © 2022 be.stateless.
#>

function Test-RegistryEntry {
   [CmdletBinding()]
   [OutputType([bool])]
   param(
      [Parameter(Position = 0, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [string]
      $Key,

      [Parameter(Position = 1, Mandatory = $true)]
      [ValidateNotNullOrEmpty()]
      [string]
      $Entry
   )
   Resolve-ActionPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState
   [bool]((Test-Path -Path $Key) -and (Get-Item -Path $Key | Where-Object -Property Property -Contains $Entry))
}

# SIG # Begin signature block
# MIII0QYJKoZIhvcNAQcCoIIIwjCCCL4CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUVDxiMgU+3ocfCDh5AZSxQt6M
# /zqgggVMMIIFSDCCAzCgAwIBAgIJAJkr3mJdTBkUMA0GCSqGSIb3DQEBCwUAMEEx
# PzA9BgNVBAMeNgBpAGMAcgBhAGYAdABzAG8AZgB0AHcAYQByAGUAQABzAHQAYQB0
# AGUAbABlAHMAcwAuAGIAZTAeFw0yMTA2MjUxNDEyMjNaFw00MTA2MjAxNDEyMjNa
# MEExPzA9BgNVBAMeNgBpAGMAcgBhAGYAdABzAG8AZgB0AHcAYQByAGUAQABzAHQA
# YQB0AGUAbABlAHMAcwAuAGIAZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
# ggIBAOeqdUHBv7sxSeX3aj6yPKj7PAvs8izpVXjyEBl5aR8mQneVcXuF53AH7EW1
# 6E5p4+Az5pJPGUD5c3tXhiGMF7vgLhQjO6hlaVBRIqiIYHikNLwMNy6YBMc/QQYM
# rPhqHEFsZ53dkBIIj3M8e3kFcTFA09n25yDtTPDab4nd9yUhc9Qc8+nfpIzfYsoP
# 1pZ3nCzhw6hN2/44v1dkQrG3dRYwt+px65p6NPNZWEJpt4VCJjIFh+lBYJdxm9d4
# X/rAnlHIkbv7liOavWDzgHVabS3hdAWtcDmynm+7+FcZDFqPWNCl3e4SS7xe4s/R
# CKFKA0IsfKkSk9YJlLgeSQIEXUOOWXJAGaLqnRD8xWLZsc4Oi9GZg7XV1mv/S88c
# oztXnwtAN3OOlRKBh2QbomMgxeMO0GvsLE/cq5Q/YKAoz+KGr/7LcZq9jzQ8IPus
# ZvWLeDXmxPiwJjpZc1koLgfGIEX2NStQTT3QmacWr9thrWcKvI+4uBmI4exS9B4a
# R3nV91w5EY+2RoYsHqej9LWwNamO96+jMX9pxprTX+EkLUuMAikw/po8sBC9MUUn
# 5pMWmUv7DCtQOLGGBDDMMMkn4ZcjpCEEdPGHRKfqNnD27ssGtDjiNzfQrsm67toU
# bBwUF+gyJq/YckWquYJhA9ZOFWEADuIwGnsOzsoRvuQyY+p9AgMBAAGjQzBBMA4G
# A1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDAzAXBgNVHREEEDAO
# ggxzdGF0ZWxlc3MuYmUwDQYJKoZIhvcNAQELBQADggIBACithYM3qckZRc9+Xbfu
# a6gWr3HwjrW+FHKgjfrcOm8ZnLVapb9xFqsqrRQqd3RXWQDINEGrtI2rSfrzyfoK
# UiTgldIfQNP1ZcGY229d++90t3hdo2mlt05hjYlbMENloJHpsEP0vQZmwOcEimCT
# ex1pymYM+P9pj3j8UD1PT1eIZot6or8fBRl63UybyDSrM7L4UOkkAOniKxWy5pW6
# 6duS8SR+SZpr3Bv44NyXPj0Nv+MIpLmsLrd7XPBFmnGxzY01ZO9vzi9KEhM2wT5i
# jPqHDNOvfPiADtAa+EyUBzdJiqy9heCz/TMZQgMWGwtfqJNxWZmsHcha2anW4Qt+
# mzrLO4GojWoVog9uVSAq+l0a+YQsd1u1kUmm4vgZCFyUA+lEp4LkI7ca2VBHkLPD
# w+u2DoDMRiqFPZjO7BCKjGc0jj9B/qGR3JVt+tqDdB621xXf2YGF2oFvxZQ/keGt
# 0ujfJ+JwN3nCulDAA4773q6KUnfykyrvAgITNbRJL6TngeRKtw9VIJBPxzqMzLpV
# 5ggXNituwLaD1CCBJ1oo9DZHpL9gplXp1wGrelJOTiJhh+pdNsPtRH7CrranWa5h
# LFLuigqin0eewQ5giJ1VaiBVEseOmiZog+27UpFIv40aDzgGL3YxB/Mu0ojwrQtp
# WLmqJCmWnR5qxOm0yK+zNWe0MYIC7zCCAusCAQEwTjBBMT8wPQYDVQQDHjYAaQBj
# AHIAYQBmAHQAcwBvAGYAdAB3AGEAcgBlAEAAcwB0AGEAdABlAGwAZQBzAHMALgBi
# AGUCCQCZK95iXUwZFDAJBgUrDgMCGgUAoHgwGAYKKwYBBAGCNwIBDDEKMAigAoAA
# oQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w
# DAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQxFgQUHQWeUb71AcSqANR3PPqbwHru
# lp4wDQYJKoZIhvcNAQEBBQAEggIApzC3G17jz+1CXDA2o2UxqEd0yoKYzqHxnqiB
# PjxsDKcrNxRsW5RfJhXpGkkcwkgceVTm5Nr08Wg7hrZZDkqOU+Pb0lDdLVJZSOXN
# 5s+p5sVd7KzCe4Zu/EExLkNIPwgmqMvntM0+pI+Ur2fW9DtUx/LQgaZgSRdJ4QWv
# CmHEqZu8ABqRZc0kJUKtaBrUi4XqcF2mtCszhgDPqY6BGszdt2ImynY26Yr0Xb7+
# 6TgLn6xZ9GJJMmNOfrw/P4w7J7zSeV74bKohPADzS418ez/ci8wRmYXf94PA9L95
# E5+lziRBAuMt11HlnZSttO8mE+/Yl4ENvb9KVf4fUfVJCQYsQtha+haxTnzcYxmR
# h000foww+rAWOkJYKowiifLSW01oxxIwPKtbttwACq83RxF5qFxN97VpHeMqoqzc
# h7j6gLbzYTcVelUo1ty5yJWM42v13Aeer+zrvyDbqkimUAp52Z3JYTtGIqD4r2/z
# eWdkVIIPCBtN9dCcmZ+MBnx3ip6fd7mfP+Ag8PIWfOt1D17CMS4wCof2TyaGqgNo
# CbK1mQ2ydX4ODjEAIfF8xL41IqHzuHm53X3h5XUr6/wCEIdNbk4UuVwOB0TiWs0A
# b1xMPizH5bIPIAG3KmKsfoV6XOa8wKhH0OQiYLELnix3WQ+pX/voTSRZRZYSzFMx
# 2QfEr88=
# SIG # End signature block