Skip to content

Instantly share code, notes, and snippets.

@chsbuffer
Last active May 10, 2022 19:19
Show Gist options
  • Save chsbuffer/264f73ca9a9d22e264c867cc5d9fcb31 to your computer and use it in GitHub Desktop.
Save chsbuffer/264f73ca9a9d22e264c867cc5d9fcb31 to your computer and use it in GitHub Desktop.
Resolving Windows file's Component, Deployment, Package, Package's Owner Package
<#
https://(gist.)github.com/chsbuffer 2022/05
i don't know where to get a script that can show something like https://forums.mydigitallife.net/threads/removing-features-from-an-online-win10-instalation.79311/#post-1511749
so i wrote one
Feel free to send documentation in comments, I don't know what is Component, Servicing, Deployment, Package, Owner
and what this script does. (though i wrote it)
#>
[CmdletBinding(DefaultParameterSetName = 'FullNameAll')]
param(
[Parameter(Mandatory = $true,
ParameterSetName = "FileNameAll",
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = "specify the file name, not recommend")]
[ValidateNotNullOrEmpty()]
[String]$FileName,
[Parameter(Mandatory = $true,
ParameterSetName = "FullNameAll",
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true)]
[ValidateNotNullOrEmpty()]
[String]$FullName,
[Parameter(Mandatory = $false,
Position = 1,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = "Override components Registry path")]
[String]$ComponentRegPath = "HKLM:\COMPONENTS",
[Parameter(Mandatory = $false,
Position = 2,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = "Override SOFTWARE Registry path")]
[String]$SoftwareRegPath = "HKLM:\SOFTWARE"
)
function Mount-Hive {
if ($ComponentRegPath -eq "HKLM:\COMPONENTS") {
if ( -not ( Test-Path "HKLM:\COMPONENTS\CanonicalData" ) ) {
Start-Process reg -Wait -Verb runas -ArgumentList "load HKLM\COMPONENTS $env:windir\system32\config\COMPONENTS"
}
}
if ( -not ( Test-Path "$ComponentRegPath\CanonicalData" ) ) {
Write-Error "components registry key not found"
exit(1223)
}
}
function Get-HardLink {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true,
HelpMessage = "Path to a location.")]
[ValidateNotNullOrEmpty()]
[String]
$Path
)
Process {
$Output = $( & fsutil.exe hardlink list $Path)
if ( $? ) {
$Output | ForEach-Object { [System.IO.FileInfo] $_ }
}
}
}
function Search-Component {
param (
[Parameter(Mandatory = $true, ParameterSetName = "FileNameAll")]
[ValidateNotNullOrEmpty()]
[String]$FileName,
[Parameter(Mandatory = $true, ParameterSetName = "FullNameAll")]
[ValidateNotNullOrEmpty()]
[String]$FullName
)
if ($FileName) {
foreach ($item in Get-ChildItem -Path "$ComponentRegPath\DerivedData\Components") {
if ( [Linq.Enumerable]::Any($item.Property, [Func[object, bool]] {
param([String]$s)
($s.StartsWith('f!')) -and ($s.SubString(2) -eq $FileName)
})
) {
return $item
}
}
} else {
$fsxs = (Get-HardLink -Path $FullName).Where( { $_.FullName.Contains("\Windows\WinSxS") })
if ($fsxs[0]) {
return Get-Item -Path "$ComponentRegPath\DerivedData\Components\$($fsxs[0].Directory.Name)"
}
}
}
function Search-Package {
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$Deployment
)
[Microsoft.Win32.RegistryKey] $deploymentKey = Get-Item -Path "$ComponentRegPath\CanonicalData\Deployments\$Deployment"
[String[]]$entries = $deploymentKey.Property
$packages = $entries | Where-Object { ($_.StartsWith('p!')) }
return $packages | ForEach-Object {
$bytes = $deploymentKey.GetValue($_) | Select-Object -Skip 8
$package = [System.Text.Encoding]::UTF8.GetString($bytes)
$package = $package.Substring(0, $package.LastIndexOf('.'))
$s = $entries.Contains("s!$($_.SubString(2))")
$i = $entries.Contains("i!$($_.SubString(2))")
return [PSCustomObject]@{
Name = $package
Installed = $s
Enabled = $i
Owners = Get-PackageOwner -Package $package
}
}
}
function Get-PackageOwner {
param (
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]$Package
)
[Microsoft.Win32.RegistryKey]$ownersKey = Get-Item -Path "$SoftwareRegPath\Microsoft\Windows\CurrentVersion\Component Based Servicing\Packages\$Package\Owners"
return $ownersKey.Property
}
Mount-Hive
if ($FileName) {
Write-Output "Resolving: $FileName"
$Component = Search-Component -FileName $FileName
} else {
Write-Output "Resolving: $FullName"
$Component = Search-Component -FullName $FullName
}
if (!$Component) {
Write-Error "Component not found"
exit(1)
}
Write-Host "____________________________________________________________`n"
Write-Output "Component: `n$($Component.PSChildName)`n"
$Deployment = $Component.Property.Where( { $_.StartsWith('c!') }, 'First' ).SubString(2)
Write-Output "Deployment: `n$Deployment`n"
$Packages = Search-Package -Deployment $Deployment
Write-Host "Packages: "
foreach ($_ in $Packages) {
Write-Output "`tName: $($_.Name)`n`t`tOwners: $($_.Owners)"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment