-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMSIX.Limitations.ps1
More file actions
299 lines (263 loc) · 13.9 KB
/
Copy pathMSIX.Limitations.ps1
File metadata and controls
299 lines (263 loc) · 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# =============================================================================
# MSIX Limitations knowledge base
# -----------------------------------------------------------------------------
# Curated list of what MSIX cannot do (or where it requires PSF / app workarounds).
# Sourced from current Microsoft Learn documentation; vendor-specific opinions
# are tagged separately so you can filter them out.
#
# References (all checked against current MS Learn — date stamped per item):
# - https://learn.microsoft.com/windows/msix/desktop/desktop-to-uwp-known-issues
# - https://learn.microsoft.com/windows/msix/packaging-tool/know-your-installer
# - https://learn.microsoft.com/windows/msix/packaging-tool/convert-an-installer-with-services
# - https://learn.microsoft.com/windows/msix/desktop/desktop-to-uwp-behind-the-scenes
# =============================================================================
$script:MsixLimitations = @(
@{
Id = 'no-drivers'
Title = 'Drivers are not supported'
Source = 'msft-docs'
Severity = 'blocker'
Description = 'MSIX cannot install kernel-mode drivers, file-system filter drivers, or any signed-driver components. Apps that bundle their own drivers must split them into a separate non-MSIX installer.'
Workaround = 'Ship the driver via a separate signed MSI/INF and depend on it as an OS prereq.'
},
@{
Id = 'install-dir-readonly'
Title = 'Installation directory is read-only at runtime'
Source = 'msft-docs'
Severity = 'medium'
Description = 'The package install location under C:\Program Files\WindowsApps is mounted read-only. Apps that write log/config files alongside their executable will fail.'
Workaround = 'Preferred (Win11 25H2+): Set-MsixFileSystemWriteVirtualization. Alternative: Use PSF FileRedirectionFixup or MFRFixup, or change the app to write to %LocalAppData%.'
},
@{
Id = 'cwd-system32'
Title = 'Working directory defaults to System32'
Source = 'msft-docs'
Severity = 'medium'
Description = 'Packaged apps launch with CWD=C:\Windows\System32 (or SysWOW64), not their install folder. Apps that read companion files via relative paths break.'
Workaround = 'Set workingDirectory in PSF config.json (Add-MsixPsfV2 -WorkingDirectory).'
},
@{
Id = 'hklm-redirected'
Title = 'HKLM writes are redirected to a private hive'
Source = 'msft-docs'
Severity = 'medium'
Description = 'Writes to HKLM are diverted to an isolated binary file per package. Other apps cannot see them. Reads merge through the virtual registry.'
Workaround = 'For genuine per-machine state, ship a separate config script. Otherwise, RegLegacyFixups can grant write access to specific keys.'
},
@{
Id = 'appdata-private'
Title = 'AppData is private per package'
Source = 'msft-docs'
Severity = 'medium'
Description = '%AppData% is redirected to %LocalAppData%\Packages\<PFN>\LocalCache\Roaming. Two apps cannot share data via AppData unless they ship in the same package.'
Workaround = 'Use a known shared location (Documents, ProgramData with explicit ACL) for cross-app data.'
},
@{
Id = 'inproc-shellext'
Title = 'In-process shell extensions cannot be registered'
Source = 'msft-docs'
Severity = 'medium'
Description = 'Classic IContextMenu / drop handlers normally load in-process into explorer.exe and are blocked by MSIX. Use the desktop9 surrogate-server pattern for legacy COM, or desktop4 IExplorerCommand for new extensions.'
Workaround = 'Add-MsixLegacyContextMenu (Win11 21H2+) or Add-MsixFileExplorerContextMenu.'
},
@{
Id = 'service-elevation'
Title = 'Packages with services need admin elevation to install'
Source = 'msft-docs'
Severity = 'low'
Description = 'Services are supported (since MPT 1.2019.1220.0) but require admin to install and per-machine deployment.'
Workaround = 'Deploy via Intune/SCCM with admin context.'
},
@{
Id = 'sxs-assemblies'
Title = 'WinSxS shared assemblies cannot be loaded'
Source = 'msft-docs'
Severity = 'medium'
Description = 'Apps dynamically linking to C:\Windows\WinSxS DLLs (older C runtimes, etc.) will not find them inside the package.'
Workaround = 'Statically link the redistributable, or ship the DLLs alongside the executable inside the package.'
},
@{
Id = 'shortcut-args'
Title = 'Start-menu shortcuts cannot pass arguments natively'
Source = 'mixed'
Severity = 'medium'
Description = 'The MSIX-installed shortcut points at the Application entry, with no native way to inject command-line arguments.'
Workaround = "PSF arguments field (New-MsixPsfArgument + Add-MsixPsfV2)."
},
@{
Id = 'multi-pkg-fileassoc'
Title = 'Multiple installed packages cannot register the same file extension'
Source = 'msft-docs'
Severity = 'low'
Description = 'File-type associations are exclusive per family. Last-write-wins or both apps register but only one is the default handler.'
Workaround = 'Ensure only the intended package owns the extension.'
},
@{
Id = 'dotnet-pre-462'
Title = '.NET Framework pre-4.6.2 requires extra validation'
Source = 'msft-docs'
Severity = 'low'
Description = 'Apps targeting .NET 2.0/3.5 generally work but may show performance issues; .NET 3.5 feature must be installed on the target machine.'
Workaround = 'Retarget to 4.6.2+ where possible.'
},
@{
Id = 'com-discovery'
Title = 'External processes may not see in-package COM servers'
Source = 'mixed'
Severity = 'medium'
Description = 'COM servers registered via the package manifest are visible inside the container, but classic out-of-process discovery from non-packaged callers can fail without explicit OutOfProcessServer + RuntimeBehavior tuning.'
Workaround = 'Use windows.comServer extension with appropriate OutOfProcessServer config; expose only intended classes.'
},
@{
Id = 'no-windows-services-deps'
Title = 'Cannot depend on services that live outside the package'
Source = 'msft-docs'
Severity = 'low'
Description = 'Service dependencies must resolve to services included in the package; cross-package service dependencies are not supported.'
Workaround = 'Bundle the dependent service in the same package, or run it as a separate non-MSIX install.'
},
@{
Id = 'protocol-handler-private'
Title = 'Custom URL/protocol handlers are scoped to the package'
Source = 'mixed'
Severity = 'low'
Description = 'A protocol handler registered by the manifest is visible to the OS but the launching app/browser must support packaged-app activation. Some legacy callers do not.'
Workaround = 'Test from edge/non-packaged callers; some require the handler to be registered for both URL and FileType activation.'
},
@{
Id = 'signing-publisher-mismatch'
Title = 'Manifest Publisher must match the signing certificate Subject'
Source = 'msft-docs'
Severity = 'low'
Description = 'signtool fails with 0x8007000B if the AppxManifest Publisher and the cert Subject differ exactly (case-sensitive, including spaces).'
Workaround = 'Update-MsixSigner -Publisher … (this module already handles re-stamping the publisher).'
}
)
function Get-MsixLimitation {
<#
.SYNOPSIS
Lists known MSIX limitations and their workarounds.
.DESCRIPTION
Returns entries from the module's curated MSIX-limitation knowledge
base. Each entry describes a documented scenario where the MSIX
runtime cannot host an application as-is, along with the recommended
workaround (PSF fixup, manifest extension, or out-of-band install).
Most entries are sourced directly from Microsoft Learn and tagged
'msft-docs'; a smaller set comes from community/vendor practice and
is tagged 'mixed'. Use -ExcludeVendor to limit the output to the
documented-by-Microsoft subset.
.PARAMETER Id
Filter to one limitation by id.
.PARAMETER Severity
Filter by severity: blocker, medium, low.
.PARAMETER ExcludeVendor
Exclude entries where Source != 'msft-docs' (i.e. drop vendor-flavoured
items that are not directly documented by Microsoft).
.OUTPUTS
[pscustomobject] one per limitation with properties Id, Title, Source,
Severity, Description, Workaround.
.EXAMPLE
Get-MsixLimitation -Severity blocker
.EXAMPLE
Get-MsixLimitation -ExcludeVendor | Format-Table Id, Severity, Title
.EXAMPLE
Get-MsixLimitation -Id 'install-dir-readonly' | Select-Object -ExpandProperty Workaround
#>
[CmdletBinding()]
param(
[string]$Id,
[ValidateSet('blocker','medium','low')]
[string]$Severity,
[switch]$ExcludeVendor
)
$list = $script:MsixLimitations | ForEach-Object { [pscustomobject]$_ }
if ($Id) { $list = $list | Where-Object Id -eq $Id }
if ($Severity) { $list = $list | Where-Object Severity -eq $Severity }
if ($ExcludeVendor) { $list = $list | Where-Object Source -eq 'msft-docs' }
return $list
}
function Test-MsixAgainstLimitation {
<#
.SYNOPSIS
Inspects an MSIX file and reports which documented limitations are
likely to apply, based on heuristics on the manifest and unpacked
content.
.DESCRIPTION
Unpacks the supplied .msix into a temporary workspace, parses
AppxManifest.xml, and walks the Applications / Extensions tree to
flag scenarios that are known to hit MSIX limitations (e.g. an
executable nested under a subfolder triggers the CWD=System32 and
install-dir-readonly limitations; a windows.service extension flags
elevation requirements). Limitations that always apply to a packaged
Win32 app (HKLM redirection, private AppData) are appended to the
result for completeness.
Complements Get-MsixStaticAnalysis. The workspace is removed
afterwards.
.PARAMETER PackagePath
The .msix file to analyse.
.OUTPUTS
[pscustomobject] one per matched limitation, deduplicated by Id. Same
shape as Get-MsixLimitation.
.EXAMPLE
Test-MsixAgainstLimitation -PackagePath .\app.msix |
Format-Table Id, Severity, Title
.EXAMPLE
# Merge with a full static-analysis run
$hits = Test-MsixAgainstLimitation -PackagePath .\app.msix
$static = Get-MsixStaticAnalysis -PackagePath .\app.msix
$hits, $static.Findings
#>
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$PackagePath
)
$toolsRoot = Get-MsixToolsRoot
$fileinfo = Get-Item -LiteralPath $PackagePath
$workspace = New-MsixWorkspace -PackageName "$($fileinfo.BaseName)-limits"
$hits = @()
try {
$r = Invoke-MsixProcess -FilePath (_MsixToolPath -Name 'MakeAppx.exe' -Root $toolsRoot) -ArgumentList @('unpack', '/p', $fileinfo.FullName, '/d', $workspace, '/o')
Assert-MsixProcessSuccess -Result $r -Operation 'MakeAppx unpack'
[xml]$manifest = Get-MsixManifest -Path "$workspace\AppxManifest.xml"
# cwd-system32 / install-dir-readonly: any executable in a subfolder + writable companions
foreach ($app in @($manifest.Package.Applications.Application | Where-Object { $null -ne $_ })) {
if ($app.Executable -and $app.Executable.Contains('\')) {
$hits += (Get-MsixLimitation -Id 'cwd-system32')
$hits += (Get-MsixLimitation -Id 'install-dir-readonly')
break
}
}
# com-discovery: any com:Extension
if ($manifest.Package.Extensions.Extension -or
($manifest.Package.Applications.Application.Extensions.Extension |
Where-Object { $_.Category -eq 'windows.comServer' })) {
$hits += (Get-MsixLimitation -Id 'com-discovery')
}
# no-windows-services-deps: any windows.service extension
if ($manifest.Package.Applications.Application.Extensions.Extension |
Where-Object { $_.Category -eq 'windows.service' }) {
$hits += (Get-MsixLimitation -Id 'no-windows-services-deps')
$hits += (Get-MsixLimitation -Id 'service-elevation')
}
# protocol handlers
if ($manifest.Package.Applications.Application.Extensions.Extension |
Where-Object { $_.Category -eq 'windows.protocol' }) {
$hits += (Get-MsixLimitation -Id 'protocol-handler-private')
}
# multi-package file association
if ($manifest.Package.Applications.Application.Extensions.Extension |
Where-Object { $_.Category -eq 'windows.fileTypeAssociation' }) {
$hits += (Get-MsixLimitation -Id 'multi-pkg-fileassoc')
}
# always applicable for any packaged Win32 app
$hits += (Get-MsixLimitation -Id 'hklm-redirected')
$hits += (Get-MsixLimitation -Id 'appdata-private')
return $hits | Sort-Object Id -Unique
} finally {
Remove-Item -LiteralPath $workspace -Recurse -Force -ErrorAction SilentlyContinue
}
}
# Backward-compatible plural aliases
Set-Alias Get-MsixLimitations Get-MsixLimitation
Set-Alias Test-MsixAgainstLimitations Test-MsixAgainstLimitation