Skip to content

Commit fa9c178

Browse files
authored
DynamicDependency: Expanded powershell cmdlets (#5854)
* Extended DynamicDependencies' Powershell * Fixed some bugs * New: Get-PackageDependency [-All | -PackageDependencyId <pdi> | -PackageFamilyName <pkgfamilyname>] * Improved docs * Removed debugging code * Added ResolvedPackage (packagefullname) to output
1 parent fb192bf commit fa9c178

File tree

4 files changed

+796
-81
lines changed

4 files changed

+796
-81
lines changed

dev/DynamicDependency/Powershell/Add-PackageDependency.ps1

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
the resolved package is added before others of the same rank. For more
2626
information, see https://learn.microsoft.com/windows/win32/api/appmodel/ne-appmodel-addpackagedependencyoptions
2727
28+
.PARAMETER SpecifiedPackageFamilyOnly
29+
Only add the target package family to the package graph.
30+
By default the target package family and its resolved dependencies
31+
are added to the package graph.
32+
2833
.LINK
2934
https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-addpackagedependency
3035
#>
@@ -35,7 +40,9 @@ param(
3540

3641
[int]$Rank=0,
3742

38-
[switch]$PrependIfRankCollision
43+
[switch]$PrependIfRankCollision,
44+
45+
[switch]$SpecifiedPackageFamilyOnly
3946
)
4047

4148
Set-StrictMode -Version 3.0
@@ -55,10 +62,27 @@ if ($PrependIfRankCollision -eq $true)
5562
$options = $options -bor [Microsoft.Windows.ApplicationModel.DynamicDependency.AddPackageDependencyOptions]::PrependIfRankCollision
5663
}
5764

65+
if ($SpecifiedPackageFamilyOnly -eq $true)
66+
{
67+
$options2 = [Microsoft.Windows.ApplicationModel.DynamicDependency.AddPackageDependencyOptions2]::SpecifiedPackageFamilyOnly
68+
if ($PrependIfRankCollision -eq $true)
69+
{
70+
$options2 = $options2 -bor [Microsoft.Windows.ApplicationModel.DynamicDependency.AddPackageDependencyOptions2]::PrependIfRankCollision
71+
}
72+
}
73+
5874
$packageDependencyContext = [IntPtr]0
5975
$packageFullName = ""
60-
$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::Add(
61-
$PackageDependencyId, $Rank, $options, [ref] $packageDependencyContext, [ref] $packageFullName)
76+
if ($SpecifiedPackageFamilyOnly -eq $true)
77+
{
78+
$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::Add2(
79+
$PackageDependencyId, $Rank, $options2, [ref] $packageDependencyContext, [ref] $packageFullName)
80+
}
81+
else
82+
{
83+
$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::Add(
84+
$PackageDependencyId, $Rank, $options, [ref] $packageDependencyContext, [ref] $packageFullName)
85+
}
6286
if ($hr -lt 0)
6387
{
6488
$win32ex = [System.ComponentModel.Win32Exception]::new($hr)
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# Copyright (c) Microsoft Corporation and Contributors.
2+
# Licensed under the MIT License.
3+
4+
<#
5+
.SYNOPSIS
6+
Return the process ids of processes using the package dependency.
7+
8+
.DESCRIPTION
9+
Return the process ids of processes using the package dependency.
10+
11+
This does not add the package to the invoking process' package graph.
12+
13+
NOTE: -All, -PackageDependencyId and -PackageFamilyName are mutually exclusive.
14+
15+
.PARAMETER PackageDependencyId
16+
Find package dependencies with this id.
17+
18+
.PARAMETER All
19+
Find all package dependencies.
20+
21+
.PARAMETER PackageFamilyName
22+
Find package dependencies with this package family.
23+
24+
.PARAMETER ScopeIsSystem
25+
Find package dependencies created with CreatePackageDependencyOptions_ScopeIsSystem.
26+
27+
.LINK
28+
https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-findpackagedependency
29+
https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-getpackagedependencyinformation
30+
https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-getprocessesusingpackagedependency
31+
#>
32+
[CmdletBinding(SupportsShouldProcess=$true)]
33+
param(
34+
[Parameter(ParameterSetName='All')]
35+
[switch]$All,
36+
37+
[Parameter(ParameterSetName='Id')]
38+
[string]$PackageDependencyId,
39+
40+
[Parameter(ParameterSetName='Package')]
41+
[string]$PackageFamilyName,
42+
43+
[switch]$ScopeIsSystem
44+
)
45+
46+
Set-StrictMode -Version 3.0
47+
48+
$ErrorActionPreference = "Stop"
49+
50+
$ERROR_SUCCESS = 0
51+
52+
function Is-PackageDependencyId
53+
{
54+
param(
55+
[string]$id
56+
)
57+
58+
if (($id -ne $null) -and ($id.Length -ge 3))
59+
{
60+
$prefix = $id.Substring(0, 2)
61+
return (($prefix -eq 'T:') -or ($prefix -eq 'P:'))
62+
}
63+
return $false
64+
}
65+
66+
function Is-PackageFamilyName
67+
{
68+
param(
69+
[string]$packageFamilyName
70+
)
71+
72+
$rc = [Microsoft.Windows.ApplicationModel.PackageFamilyName]::Verify($packageFamilyName)
73+
return $rc == $ERROR_SUCCESS
74+
}
75+
76+
function Get-Processes
77+
{
78+
param(
79+
[string]$id
80+
)
81+
82+
[uint32]$processIdsCount = 0
83+
[uint32[]]$processIds = $null
84+
$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::GetProcesses(
85+
$id, $ScopeIsSystem, [ref] $processIdsCount, [ref] $processIds)
86+
if ($hr -lt 0)
87+
{
88+
$win32ex = [System.ComponentModel.Win32Exception]::new($hr)
89+
Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
90+
}
91+
return $processIds
92+
}
93+
94+
# Import the MSIX Dynamic Dependency module
95+
if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
96+
{
97+
$module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
98+
Import-Module -Name $module -ErrorAction Stop
99+
}
100+
101+
$ids = [ordered]@{}
102+
if ($PSCmdlet.ParameterSetName -eq 'None')
103+
{
104+
if ([string]::IsNullOrWhiteSpace($PackageDependencyId))
105+
{
106+
$All = $true
107+
}
108+
elseif (Is-PackageFamilyName $PackageDependencyId)
109+
{
110+
$PackageFamilyName = $PackageDependencyId
111+
$PackageDependencyId = $null
112+
$PSCmdlet.ParameterSetName = 'Package'
113+
}
114+
else
115+
{
116+
$PSCmdlet.ParameterSetName = 'Id'
117+
}
118+
}
119+
120+
121+
122+
if (-not [string]::IsNullOrWhiteSpace($PackageDependencyId))
123+
{
124+
$ids.Add($PackageDependencyId, $null)
125+
}
126+
else #if ($PSCmdlet.ParameterSetName -eq 'Package')
127+
{
128+
$findPackageDependencyCriteria = New-Object Microsoft.Windows.ApplicationModel.DynamicDependency.FindPackageDependencyCriteria
129+
$findPackageDependencyCriteria.User = [IntPtr]::Zero
130+
$findPackageDependencyCriteria.ScopeIsSystem = $ScopeIsSystem
131+
if ($PSCmdlet.ParameterSetName -eq 'Package')
132+
{
133+
$findPackageDependencyCriteria.PackageFamilyName = $PackageFamilyName
134+
}
135+
else # -All
136+
{
137+
$findPackageDependencyCriteria.PackageFamilyName = "" #$null
138+
}
139+
[uint]$packageDependencyIdsCount = 0
140+
[string[]]$packageDependencyIds = $null
141+
$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::Find(
142+
$findPackageDependencyCriteria, [ref] $packageDependencyIdsCount, [ref] $packageDependencyIds);
143+
if ($hr -lt 0)
144+
{
145+
$win32ex = [System.ComponentModel.Win32Exception]::new($hr)
146+
Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
147+
}
148+
else
149+
{
150+
Write-Host "Package Dependencies: $packageDependencyIdsCount"
151+
}
152+
ForEach ($pdi in $packageDependencyIds)
153+
{
154+
$ids.Add($pdi, $null)
155+
}
156+
}
157+
158+
ForEach ($pdi in $ids.Keys)
159+
{
160+
$pids = Get-Processes $pdi
161+
162+
[string]$familyName = $null
163+
[ulong]$minVersion = 0
164+
$processorArchitectures = 0
165+
$lifetimeKind = 0
166+
[string]$lifetimeArtifact = $null
167+
$options = 0
168+
$lifetimeExpiration = New-Object DateTime
169+
$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::GetInfo(
170+
$pdi, [ref] $familyName, [ref] $minVersion, [ref] $processorArchitectures,
171+
[ref] $lifetimeKind, [ref] $lifetimeArtifact, [ref] $options, [ref] $lifetimeExpiration)
172+
if ($hr -lt 0)
173+
{
174+
$win32ex = [System.ComponentModel.Win32Exception]::new($hr)
175+
Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
176+
}
177+
if ($lifetimeExpiration.Ticks -eq 0)
178+
{
179+
$lifetimeExpiration = $null
180+
}
181+
182+
$packageFullName = .\Get-PackageDependencyResolved.ps1 $pdi
183+
184+
$pd = [PSCustomObject]@{
185+
PackageDependencyId = $pdi
186+
PackageFamilyName = $familyName
187+
ResolvedPackage = $packageFullName
188+
MinVersion = $minVersion
189+
ProcessorArchitectures = $processorArchitectures
190+
LifetimeKind = $lifetimeKind
191+
LifetimeArtifact = $lifetimeArtifact
192+
Options = $options
193+
LifetimeExpiration = $lifetimeExpiration
194+
ProcessIDs = $pids
195+
}
196+
$pd | Format-List
197+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright (c) Microsoft Corporation and Contributors.
2+
# Licensed under the MIT License.
3+
4+
<#
5+
.SYNOPSIS
6+
Return the process ids of processes using the package dependency.
7+
8+
.DESCRIPTION
9+
Return the process ids of processes using the package dependency.
10+
11+
This does not add the package to the invoking process' package graph.
12+
13+
.PARAMETER PackageDependencyId
14+
The ID of the resolved package dependency.
15+
16+
.LINK
17+
https://learn.microsoft.com/windows/win32/api/appmodel/nf-appmodel-getprocessesusingpackagedependency
18+
#>
19+
[CmdletBinding(SupportsShouldProcess=$true)]
20+
param(
21+
[Parameter(Mandatory=$true)]
22+
[string]$PackageDependencyId,
23+
24+
[switch]$ScopeIsSystem
25+
)
26+
27+
Set-StrictMode -Version 3.0
28+
29+
$ErrorActionPreference = "Stop"
30+
31+
# Import the MSIX Dynamic Dependency module
32+
if (-not (Get-Module | Where-Object {$_.Name -eq 'MsixDynamicDependency'}))
33+
{
34+
$module = Join-Path $PSScriptRoot 'MsixDynamicDependency.psm1'
35+
Import-Module -Name $module -ErrorAction Stop
36+
}
37+
38+
[uint32]$processIdsCount = 0
39+
[uint32[]]$processIds = $null
40+
$hr = [Microsoft.Windows.ApplicationModel.DynamicDependency.PackageDependency]::GetProcesses(
41+
$PackageDependencyId, $ScopeIsSystem, [ref] $processIdsCount, [ref] $processIds)
42+
if ($hr -lt 0)
43+
{
44+
$win32ex = [System.ComponentModel.Win32Exception]::new($hr)
45+
Write-Error "Error 0x$($hr.ToString('X')): $($win32ex.Message)" -ErrorAction Stop
46+
}
47+
else
48+
{
49+
Write-Host "Processes: $processIdsCount"
50+
}
51+
52+
$processIds

0 commit comments

Comments
 (0)