@react-native-windows/cli 0.80.0-preview.7 → 0.81.0-preview.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,274 +1,465 @@
1
- <#
2
- Licensed to the Apache Software Foundation (ASF) under one
3
- or more contributor license agreements. See the NOTICE file
4
- distributed with this work for additional information
5
- regarding copyright ownership. The ASF licenses this file
6
- to you under the Apache License, Version 2.0 (the
7
- "License"); you may not use this file except in compliance
8
- with the License. You may obtain a copy of the License at
9
-
10
- http://www.apache.org/licenses/LICENSE-2.0
11
-
12
- Unless required by applicable law or agreed to in writing,
13
- software distributed under the License is distributed on an
14
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
- KIND, either express or implied. See the License for the
16
- specific language governing permissions and limitations
17
- under the License.
18
- #>
19
- $code = @"
20
- using System;
21
- using System.Runtime.CompilerServices;
22
- using System.Runtime.InteropServices;
23
- namespace StoreAppRunner
24
- {
25
- public enum ActivateOptions
26
- {
27
- None = 0,
28
- DesignMode = 0x1,
29
- NoErrorUI = 0x2,
30
- NoSplashScreen = 0x4
31
- }
32
-
33
- [ComImport]
34
- [Guid("2e941141-7f97-4756-ba1d-9decde894a3d")]
35
- [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
36
- public interface IApplicationActivationManager
37
- {
38
- IntPtr ActivateApplication([In] String appUserModelId, [In] String arguments, [In] ActivateOptions options, [Out] out UInt32 processId);
39
- IntPtr ActivateForFile([In] String appUserModelId, [In] IntPtr itemArray, [In] String verb, [Out] out UInt32 processId);
40
- IntPtr ActivateForProtocol([In] String appUserModelId, [In] IntPtr itemArray, [Out] out UInt32 processId);
41
- }
42
- [ComImport]
43
- [Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]
44
- public class ApplicationActivationManager : IApplicationActivationManager
45
- {
46
- [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
47
- public extern IntPtr ActivateApplication([In] String appUserModelId, [In] String arguments, [In] ActivateOptions options, [Out] out UInt32 processId);
48
- [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
49
- public extern IntPtr ActivateForFile([In] String appUserModelId, [In] IntPtr itemArray, [In] String verb, [Out] out UInt32 processId);
50
- [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
51
- public extern IntPtr ActivateForProtocol([In] String appUserModelId, [In] IntPtr itemArray, [Out] out UInt32 processId);
52
- }
53
- }
54
- "@
55
-
56
- function Uninstall-App {
57
- param(
58
- [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
59
- [string] $ID <# package.appxmanifest//Identity@name #>
60
- )
61
-
62
- $package = Get-AppxPackage $ID
63
-
64
- if($package) {
65
- $pfn = $package.PackageFullName
66
- $command = "Remove-AppxPackage $pfn -ErrorAction Stop"
67
- try {
68
- Invoke-Expression $command
69
- } catch {
70
- Invoke-Expression-MayElevate $command -ErrorAction Stop
71
- }
72
- }
73
- }
74
-
75
- #
76
- # Checks whether the machine is missing a valid developer license.
77
- #
78
- function CheckIfNeedDeveloperLicense
79
- {
80
- $Result = $true
81
- try
82
- {
83
- $Result = (Get-WindowsDeveloperLicense | Where-Object { $_.IsValid }).Count -eq 0
84
- }
85
- catch {}
86
-
87
- return $Result
88
- }
89
-
90
- function IsElevated {
91
- return [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544");
92
- }
93
-
94
- function RunElevatedPowerShellSync([string]$Command) {
95
- $process = Start-Process Powershell -ArgumentList "$Command" -Verb RunAs -ErrorAction Stop -PassThru
96
- if ($process -ne $null) {
97
- $process.WaitForExit();
98
- if ($process.ExitCode -ne 0) {
99
- $code = $process.ExitCode;
100
- throw "Command exited with code $code";
101
- }
102
- } else {
103
- throw "Process creation failed for $Command";
104
- }
105
- }
106
-
107
- function Invoke-Expression-MayElevate([string]$Command) {
108
- if (!(IsElevated))
109
- {
110
- RunElevatedPowerShellSync($Command) -ErrorAction Stop
111
- }
112
- else
113
- {
114
- Invoke-Expression ("& $Command") -ErrorAction Stop
115
- }
116
- }
117
-
118
- function EnableDevmode {
119
- $RegistryKeyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
120
-
121
- if (-not(Test-Path -Path $RegistryKeyPath)) {
122
- New-Item -Path $RegistryKeyPath -ItemType Directory -Force
123
- }
124
-
125
- $value = get-ItemProperty -Path $RegistryKeyPath -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue
126
- if (($value -eq $null) -or ($value.AllowDevelopmentWithoutDevLicense -ne 1)) {
127
- Invoke-Expression-MayElevate("Set-ItemProperty -Path $RegistryKeyPath -Name AllowDevelopmentWithoutDevLicense -Value 1 -ErrorAction Stop") -ErrorAction Stop;
128
- }
129
- $value = get-ItemProperty -Path $RegistryKeyPath -Name AllowAllTrustedApps -ErrorAction SilentlyContinue
130
- if (($value -eq $null) -or ($value.AllowAllTrustedApps -ne 1)) {
131
- Invoke-Expression-MayElevate("Set-ItemProperty -Path $RegistryKeyPath -Name AllowAllTrustedApps -Value 1 -ErrorAction Stop") -ErrorAction Stop;
132
- }
133
- }
134
-
135
- #
136
- # Checks whether the package certificate must be installed on the machine.
137
- #
138
- function CheckIfNeedInstallCertificate
139
- {
140
- param(
141
- [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
142
- [string] $ScriptDir <# Full path to the dir where Add-AppDevPackage.ps1 is stored #>
143
- )
144
-
145
- $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" }
146
- if ($PackagePath -eq $null)
147
- {
148
- $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.msix") | Where-Object { $_.Mode -NotMatch "d" }
149
- }
150
-
151
- $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.appxbundle") | Where-Object { $_.Mode -NotMatch "d" }
152
- if ($BundlePath -eq $null)
153
- {
154
- $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.msixbundle") | Where-Object { $_.Mode -NotMatch "d" }
155
- }
156
-
157
- # There must be exactly 1 package/bundle
158
- if (($PackagePath.Count + $BundlePath.Count) -lt 1)
159
- {
160
- Throw "The app package has not been found at dir $ScriptDir"
161
- }
162
- if (($PackagePath.Count + $BundlePath.Count) -gt 1)
163
- {
164
- Throw "To many app packages have been found at dir $ScriptDir"
165
- }
166
-
167
- if ($PackagePath.Count -ne 1) # there is *.appxbundle
168
- {
169
- $PackagePath = $BundlePath
170
- }
171
-
172
- $PackageSignature = (Get-AuthenticodeSignature $PackagePath)
173
- $Valid = ($PackageSignature -and $PackageSignature.Status -eq "Valid")
174
- return (-not $Valid)
175
- }
176
-
177
- function Install-App {
178
- param(
179
- [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
180
- [string] $Path, <# Full path to Add-AppDevPackage.ps1 #>
181
- [switch] $Force = $false
182
- )
183
- $needInstallCertificate = CheckIfNeedInstallCertificate (Join-Path $Path "..");
184
- if (!$Force -and ((CheckIfNeedDeveloperLicense) -or ($needInstallCertificate)))
185
- {
186
- # we can't run the script with -force param if license/certificate installation step is required
187
- Invoke-Expression ("& `"$Path`"")
188
- }
189
- else
190
- {
191
- $Path = [System.IO.Path]::GetFullPath($Path);
192
- Invoke-Expression-MayElevate("`"$Path`" -force") -ErrorAction Stop;
193
- }
194
- }
195
-
196
- function Install-AppFromDirectory {
197
- param(
198
- [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
199
- [string] $Path <# Full path to actual AppxManifest.xml #>
200
- )
201
-
202
- Add-AppxPackage -Path $Path -Register -ForceApplicationShutdown
203
- }
204
-
205
- function Install-AppFromAppx {
206
- param(
207
- [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
208
- [string] $Path <# Full path to actual .appx #>
209
- )
210
-
211
- Add-AppxPackage -Path $Path -ForceApplicationShutdown
212
- }
213
-
214
- function Start-Locally {
215
- param(
216
- [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
217
- [string] $ID, <# package.appxmanifest//Identity@name #>
218
-
219
- [Parameter(Mandatory=$false, Position=1, ValueFromPipelineByPropertyName=$true)]
220
- [string[]] $argv
221
- )
222
-
223
- $package = Get-AppxPackage $ID
224
- $manifest = Get-appxpackagemanifest $package
225
- $applicationUserModelId = $package.PackageFamilyName + "!" + $manifest.package.applications.application.id
226
-
227
- add-type -TypeDefinition $code
228
- $appActivator = new-object StoreAppRunner.ApplicationActivationManager
229
- if ($argv.Count -gt 0) {
230
- $args = [system.String]::Join(" ", $argv)
231
- }
232
-
233
- try {
234
- $appActivator.ActivateApplication($applicationUserModelId,$args,[StoreAppRunner.ActivateOptions]::None,[ref]0) | Out-Null
235
- } catch {
236
- $log = Get-EventLog 'Application' -EntryType Error -Message "*$ID*" -Newest 1
237
- if ($log -ne $null) {
238
- Write-Error $log.Message
239
- }
240
- }
241
- }
242
-
243
-
244
- function Map-PackageNameToPackage {
245
- param([Parameter(Mandatory=$true)] [string]$DependenciesPath)
246
- $mapP2N = @{};
247
- [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.Zipfile') | Out-Null;
248
- foreach ($package in (gci $DependenciesPath)) {
249
- $archive = [System.IO.Compression.Zipfile]::OpenRead($package.FullName);
250
- $packageManifestReader = New-Object System.IO.StreamReader($archive.GetEntry('AppxManifest.xml').Open());
251
- $manifest = [xml]($packageManifestReader.ReadToEnd());
252
- $mapP2N[$manifest.Package.Identity.Name] = $package;
253
- }
254
- return $mapP2N;
255
- }
256
-
257
- function Install-AppDependencies {
258
- param(
259
- [Parameter(Mandatory=$true)] [string]$AppxManifestPath,
260
- [Parameter(Mandatory=$true)] [string]$AppPackagePath,
261
- [Parameter(Mandatory=$true)] [string]$Architecture
262
- )
263
-
264
- $xml=[xml] (gc $AppxManifestPath);
265
- $packageNamesToInstall = $xml.Package.Dependencies.PackageDependency |
266
- Where-Object {
267
- $installed = Get-AppxPackage $_.Name | Where-Object -Property Architecture -EQ -Value $Architecture;
268
- $installed -eq $null -or $installed.Version -lt $_.MinVersion
269
- } |
270
- % { $_.Name };
271
- $map = Map-PackageNameToPackage $AppPackagePath\Dependencies\$Architecture
272
- $packagePaths = $packageNamesToInstall | % { $map[$_] }
273
- $packagePaths | % { Add-AppxPackage -Path $_ }
274
- }
1
+ <#
2
+ Licensed to the Apache Software Foundation (ASF) under one
3
+ or more contributor license agreements. See the NOTICE file
4
+ distributed with this work for additional information
5
+ regarding copyright ownership. The ASF licenses this file
6
+ to you under the Apache License, Version 2.0 (the
7
+ "License"); you may not use this file except in compliance
8
+ with the License. You may obtain a copy of the License at
9
+
10
+ http://www.apache.org/licenses/LICENSE-2.0
11
+
12
+ Unless required by applicable law or agreed to in writing,
13
+ software distributed under the License is distributed on an
14
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
+ KIND, either express or implied. See the License for the
16
+ specific language governing permissions and limitations
17
+ under the License.
18
+ #>
19
+
20
+ # SDL CE.10116 SECURITY FIX: Removed PowerShell injection vulnerabilities
21
+ # - Replaced Invoke-Expression with direct cmdlet invocation
22
+ # - Implemented parameterized ScriptBlock pattern for elevated execution
23
+ # - Added input validation for package IDs and paths
24
+ # Date: October 14, 2025
25
+
26
+ $code = @"
27
+ using System;
28
+ using System.Runtime.CompilerServices;
29
+ using System.Runtime.InteropServices;
30
+ namespace StoreAppRunner
31
+ {
32
+ public enum ActivateOptions
33
+ {
34
+ None = 0,
35
+ DesignMode = 0x1,
36
+ NoErrorUI = 0x2,
37
+ NoSplashScreen = 0x4
38
+ }
39
+
40
+ [ComImport]
41
+ [Guid("2e941141-7f97-4756-ba1d-9decde894a3d")]
42
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
43
+ public interface IApplicationActivationManager
44
+ {
45
+ IntPtr ActivateApplication([In] String appUserModelId, [In] String arguments, [In] ActivateOptions options, [Out] out UInt32 processId);
46
+ IntPtr ActivateForFile([In] String appUserModelId, [In] IntPtr itemArray, [In] String verb, [Out] out UInt32 processId);
47
+ IntPtr ActivateForProtocol([In] String appUserModelId, [In] IntPtr itemArray, [Out] out UInt32 processId);
48
+ }
49
+ [ComImport]
50
+ [Guid("45BA127D-10A8-46EA-8AB7-56EA9078943C")]
51
+ public class ApplicationActivationManager : IApplicationActivationManager
52
+ {
53
+ [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
54
+ public extern IntPtr ActivateApplication([In] String appUserModelId, [In] String arguments, [In] ActivateOptions options, [Out] out UInt32 processId);
55
+ [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
56
+ public extern IntPtr ActivateForFile([In] String appUserModelId, [In] IntPtr itemArray, [In] String verb, [Out] out UInt32 processId);
57
+ [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
58
+ public extern IntPtr ActivateForProtocol([In] String appUserModelId, [In] IntPtr itemArray, [Out] out UInt32 processId);
59
+ }
60
+ }
61
+ "@
62
+
63
+ #region Security Helper Functions
64
+
65
+ <#
66
+ .SYNOPSIS
67
+ Validates package identifier format to prevent injection attacks.
68
+ .DESCRIPTION
69
+ Ensures package ID contains only safe characters and matches expected format.
70
+ SDL CE.10116 compliance - prevents PowerShell injection via package names.
71
+ #>
72
+ function Validate-PackageIdentifier {
73
+ param(
74
+ [Parameter(Mandatory=$true)]
75
+ [string]$PackageId
76
+ )
77
+
78
+ # Valid format: alphanumeric, dots, hyphens, underscores only
79
+ if ($PackageId -notmatch '^[a-zA-Z0-9\.\-_]+$') {
80
+ throw "Invalid package identifier format. Only alphanumeric characters, dots, hyphens, and underscores are allowed."
81
+ }
82
+
83
+ # Prevent common injection patterns
84
+ $dangerousPatterns = @(';', '|', '&', '$', '`', '<', '>', "`n", "`r", '(', ')', '{', '}')
85
+ foreach ($pattern in $dangerousPatterns) {
86
+ if ($PackageId.Contains($pattern)) {
87
+ throw "Package identifier contains forbidden characters: $pattern"
88
+ }
89
+ }
90
+
91
+ return $true
92
+ }
93
+
94
+ <#
95
+ .SYNOPSIS
96
+ Validates and canonicalizes script path to prevent path traversal attacks.
97
+ .DESCRIPTION
98
+ Ensures path is a valid .ps1 file and resolves to canonical path.
99
+ SDL CE.10116 compliance - prevents path injection attacks.
100
+ #>
101
+ function Validate-ScriptPath {
102
+ param(
103
+ [Parameter(Mandatory=$true)]
104
+ [string]$Path
105
+ )
106
+
107
+ # Check file exists
108
+ if (!(Test-Path $Path -PathType Leaf)) {
109
+ throw "Script path does not exist: $Path"
110
+ }
111
+
112
+ # Check .ps1 extension
113
+ if ([System.IO.Path]::GetExtension($Path) -ne '.ps1') {
114
+ throw "Path must reference a PowerShell script (.ps1)"
115
+ }
116
+
117
+ # Get canonical path (prevents ../ traversal)
118
+ $canonicalPath = [System.IO.Path]::GetFullPath($Path)
119
+
120
+ return $canonicalPath
121
+ }
122
+
123
+ <#
124
+ .SYNOPSIS
125
+ Executes a ScriptBlock with optional elevation using parameterized approach.
126
+ .DESCRIPTION
127
+ SDL CE.10116 compliant - uses ScriptBlock with ArgumentList instead of string concatenation.
128
+ Prevents PowerShell injection attacks by properly isolating parameters.
129
+ #>
130
+ function Invoke-ElevatedScriptBlock {
131
+ param(
132
+ [Parameter(Mandatory=$true)]
133
+ [ScriptBlock]$ScriptBlock,
134
+
135
+ [Parameter(Mandatory=$false)]
136
+ [object[]]$ArgumentList = @()
137
+ )
138
+
139
+ if (!(IsElevated)) {
140
+ # Serialize ScriptBlock and arguments for elevated execution
141
+ $encodedCommand = [Convert]::ToBase64String(
142
+ [System.Text.Encoding]::Unicode.GetBytes($ScriptBlock.ToString())
143
+ )
144
+
145
+ $encodedArgs = [Convert]::ToBase64String(
146
+ [System.Text.Encoding]::Unicode.GetBytes(
147
+ ($ArgumentList | ConvertTo-Json -Compress -Depth 10)
148
+ )
149
+ )
150
+
151
+ # Create secure argument list (no string interpolation)
152
+ $startArgs = @(
153
+ '-NoProfile',
154
+ '-NonInteractive',
155
+ '-Command',
156
+ "& ([ScriptBlock]::Create([System.Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('$encodedCommand')))) @(ConvertFrom-Json ([System.Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('$encodedArgs'))))"
157
+ )
158
+
159
+ $process = Start-Process PowerShell -ArgumentList $startArgs `
160
+ -Verb RunAs -Wait -PassThru -WindowStyle Hidden -ErrorAction Stop
161
+
162
+ if ($process.ExitCode -ne 0) {
163
+ throw "Elevated command failed with exit code $($process.ExitCode)"
164
+ }
165
+ }
166
+ else {
167
+ # Already elevated, execute directly with splatting
168
+ & $ScriptBlock @ArgumentList
169
+ }
170
+ }
171
+
172
+ #endregion
173
+
174
+ #region Core Functions
175
+
176
+ <#
177
+ .SYNOPSIS
178
+ Uninstalls an AppX package by package identifier.
179
+ .DESCRIPTION
180
+ SDL CE.10116 FIX: Replaced Invoke-Expression with direct Remove-AppxPackage cmdlet.
181
+ Uses parameterized ScriptBlock for elevated execution.
182
+ #>
183
+ function Uninstall-App {
184
+ param(
185
+ [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
186
+ [string] $ID <# package.appxmanifest//Identity@name #>
187
+ )
188
+
189
+ # SDL FIX: Validate package ID to prevent injection
190
+ Validate-PackageIdentifier -PackageId $ID | Out-Null
191
+
192
+ $package = Get-AppxPackage $ID
193
+
194
+ if($package) {
195
+ $pfn = $package.PackageFullName
196
+
197
+ # SDL FIX: Direct cmdlet invocation instead of Invoke-Expression
198
+ try {
199
+ Remove-AppxPackage $pfn -ErrorAction Stop
200
+ } catch {
201
+ # SDL FIX: Use parameterized ScriptBlock for elevation
202
+ $scriptBlock = {
203
+ param($PackageFullName)
204
+ Remove-AppxPackage $PackageFullName -ErrorAction Stop
205
+ }
206
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock -ArgumentList @($pfn)
207
+ }
208
+ }
209
+ }
210
+
211
+ #
212
+ # Checks whether the machine is missing a valid developer license.
213
+ #
214
+ function CheckIfNeedDeveloperLicense
215
+ {
216
+ $Result = $true
217
+ try
218
+ {
219
+ $Result = (Get-WindowsDeveloperLicense | Where-Object { $_.IsValid }).Count -eq 0
220
+ }
221
+ catch {}
222
+
223
+ return $Result
224
+ }
225
+
226
+ function IsElevated {
227
+ return [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-32-544");
228
+ }
229
+
230
+ <#
231
+ .SYNOPSIS
232
+ Enables developer mode by setting registry keys.
233
+ .DESCRIPTION
234
+ SDL CE.10116 FIX: Replaced Invoke-Expression-MayElevate with direct cmdlet calls
235
+ and parameterized ScriptBlock for elevation.
236
+ #>
237
+ function EnableDevmode {
238
+ $RegistryKeyPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock"
239
+
240
+ # Create registry key if it doesn't exist
241
+ if (-not(Test-Path -Path $RegistryKeyPath)) {
242
+ if (!(IsElevated)) {
243
+ $scriptBlock = {
244
+ param($Path)
245
+ New-Item -Path $Path -ItemType Directory -Force | Out-Null
246
+ }
247
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock -ArgumentList @($RegistryKeyPath)
248
+ }
249
+ else {
250
+ New-Item -Path $RegistryKeyPath -ItemType Directory -Force | Out-Null
251
+ }
252
+ }
253
+
254
+ # SDL FIX: Direct cmdlet invocation for AllowDevelopmentWithoutDevLicense
255
+ $value = Get-ItemProperty -Path $RegistryKeyPath -Name AllowDevelopmentWithoutDevLicense -ErrorAction SilentlyContinue
256
+ if (($value -eq $null) -or ($value.AllowDevelopmentWithoutDevLicense -ne 1)) {
257
+ if (!(IsElevated)) {
258
+ $scriptBlock = {
259
+ param($Path, $Name, $Value)
260
+ Set-ItemProperty -Path $Path -Name $Name -Value $Value -ErrorAction Stop
261
+ }
262
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock `
263
+ -ArgumentList @($RegistryKeyPath, 'AllowDevelopmentWithoutDevLicense', 1)
264
+ }
265
+ else {
266
+ Set-ItemProperty -Path $RegistryKeyPath -Name AllowDevelopmentWithoutDevLicense -Value 1 -ErrorAction Stop
267
+ }
268
+ }
269
+
270
+ # SDL FIX: Direct cmdlet invocation for AllowAllTrustedApps
271
+ $value = Get-ItemProperty -Path $RegistryKeyPath -Name AllowAllTrustedApps -ErrorAction SilentlyContinue
272
+ if (($value -eq $null) -or ($value.AllowAllTrustedApps -ne 1)) {
273
+ if (!(IsElevated)) {
274
+ $scriptBlock = {
275
+ param($Path, $Name, $Value)
276
+ Set-ItemProperty -Path $Path -Name $Name -Value $Value -ErrorAction Stop
277
+ }
278
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock `
279
+ -ArgumentList @($RegistryKeyPath, 'AllowAllTrustedApps', 1)
280
+ }
281
+ else {
282
+ Set-ItemProperty -Path $RegistryKeyPath -Name AllowAllTrustedApps -Value 1 -ErrorAction Stop
283
+ }
284
+ }
285
+ }
286
+
287
+ #
288
+ # Checks whether the package certificate must be installed on the machine.
289
+ #
290
+ function CheckIfNeedInstallCertificate
291
+ {
292
+ param(
293
+ [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
294
+ [string] $ScriptDir <# Full path to the dir where Add-AppDevPackage.ps1 is stored #>
295
+ )
296
+
297
+ $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.appx") | Where-Object { $_.Mode -NotMatch "d" }
298
+ if ($PackagePath -eq $null)
299
+ {
300
+ $PackagePath = Get-ChildItem (Join-Path $ScriptDir "*.msix") | Where-Object { $_.Mode -NotMatch "d" }
301
+ }
302
+
303
+ $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.appxbundle") | Where-Object { $_.Mode -NotMatch "d" }
304
+ if ($BundlePath -eq $null)
305
+ {
306
+ $BundlePath = Get-ChildItem (Join-Path $ScriptDir "*.msixbundle") | Where-Object { $_.Mode -NotMatch "d" }
307
+ }
308
+
309
+ # There must be exactly 1 package/bundle
310
+ if (($PackagePath.Count + $BundlePath.Count) -lt 1)
311
+ {
312
+ Throw "The app package has not been found at dir $ScriptDir"
313
+ }
314
+ if (($PackagePath.Count + $BundlePath.Count) -gt 1)
315
+ {
316
+ Throw "To many app packages have been found at dir $ScriptDir"
317
+ }
318
+
319
+ if ($PackagePath.Count -ne 1) # there is *.appxbundle
320
+ {
321
+ $PackagePath = $BundlePath
322
+ }
323
+
324
+ $PackageSignature = (Get-AuthenticodeSignature $PackagePath)
325
+ $Valid = ($PackageSignature -and $PackageSignature.Status -eq "Valid")
326
+ return (-not $Valid)
327
+ }
328
+
329
+ <#
330
+ .SYNOPSIS
331
+ Installs an app package using Add-AppDevPackage.ps1 script.
332
+ .DESCRIPTION
333
+ SDL CE.10116 FIX: Replaced Invoke-Expression with call operator (&) and
334
+ parameterized ScriptBlock for elevated execution.
335
+ #>
336
+ function Install-App {
337
+ param(
338
+ [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
339
+ [string] $Path, <# Full path to Add-AppDevPackage.ps1 #>
340
+ [switch] $Force = $false
341
+ )
342
+
343
+ # SDL FIX: Validate script path
344
+ $Path = Validate-ScriptPath -Path $Path
345
+
346
+ $needInstallCertificate = CheckIfNeedInstallCertificate (Join-Path $Path "..")
347
+
348
+ if (!$Force -and ((CheckIfNeedDeveloperLicense) -or ($needInstallCertificate)))
349
+ {
350
+ # SDL FIX: Use call operator (&) instead of Invoke-Expression
351
+ # No user input in path (validated above), so safe to execute
352
+ & $Path
353
+ }
354
+ else
355
+ {
356
+ # SDL FIX: Use parameterized ScriptBlock for elevation
357
+ if (!(IsElevated)) {
358
+ $scriptBlock = {
359
+ param($ScriptPath)
360
+ & $ScriptPath -Force
361
+ }
362
+ Invoke-ElevatedScriptBlock -ScriptBlock $scriptBlock -ArgumentList @($Path)
363
+ }
364
+ else {
365
+ & $Path -Force
366
+ }
367
+ }
368
+ }
369
+
370
+ function Install-AppFromDirectory {
371
+ param(
372
+ [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
373
+ [string] $Path <# Full path to actual AppxManifest.xml #>
374
+ )
375
+
376
+ Add-AppxPackage -Path $Path -Register -ForceApplicationShutdown
377
+ }
378
+
379
+ function Install-AppFromAppx {
380
+ param(
381
+ [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
382
+ [string] $Path <# Full path to actual .appx #>
383
+ )
384
+
385
+ Add-AppxPackage -Path $Path -ForceApplicationShutdown
386
+ }
387
+
388
+ function Start-Locally {
389
+ param(
390
+ [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
391
+ [string] $ID, <# package.appxmanifest//Identity@name #>
392
+
393
+ [Parameter(Mandatory=$false, Position=1, ValueFromPipelineByPropertyName=$true)]
394
+ [string[]] $argv
395
+ )
396
+
397
+ # SDL FIX: Validate package ID
398
+ Validate-PackageIdentifier -PackageId $ID | Out-Null
399
+
400
+ $package = Get-AppxPackage $ID
401
+ $manifest = Get-appxpackagemanifest $package
402
+ $applicationUserModelId = $package.PackageFamilyName + "!" + $manifest.package.applications.application.id
403
+
404
+ add-type -TypeDefinition $code
405
+ $appActivator = new-object StoreAppRunner.ApplicationActivationManager
406
+ if ($argv.Count -gt 0) {
407
+ $args = [system.String]::Join(" ", $argv)
408
+ }
409
+
410
+ try {
411
+ $appActivator.ActivateApplication($applicationUserModelId,$args,[StoreAppRunner.ActivateOptions]::None,[ref]0) | Out-Null
412
+ } catch {
413
+ $log = Get-EventLog 'Application' -EntryType Error -Message "*$ID*" -Newest 1
414
+ if ($log -ne $null) {
415
+ Write-Error $log.Message
416
+ }
417
+ }
418
+ }
419
+
420
+ function Map-PackageNameToPackage {
421
+ param([Parameter(Mandatory=$true)] [string]$DependenciesPath)
422
+ $mapP2N = @{};
423
+ [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.Zipfile') | Out-Null;
424
+ foreach ($package in (gci $DependenciesPath)) {
425
+ $archive = [System.IO.Compression.Zipfile]::OpenRead($package.FullName);
426
+ $packageManifestReader = New-Object System.IO.StreamReader($archive.GetEntry('AppxManifest.xml').Open());
427
+ $manifest = [xml]($packageManifestReader.ReadToEnd());
428
+ $mapP2N[$manifest.Package.Identity.Name] = $package;
429
+ }
430
+ return $mapP2N;
431
+ }
432
+
433
+ function Install-AppDependencies {
434
+ param(
435
+ [Parameter(Mandatory=$true)] [string]$AppxManifestPath,
436
+ [Parameter(Mandatory=$true)] [string]$AppPackagePath,
437
+ [Parameter(Mandatory=$true)] [string]$Architecture
438
+ )
439
+
440
+ $xml=[xml] (gc $AppxManifestPath);
441
+ $packageNamesToInstall = $xml.Package.Dependencies.PackageDependency |
442
+ Where-Object {
443
+ $installed = Get-AppxPackage $_.Name | Where-Object -Property Architecture -EQ -Value $Architecture;
444
+ $installed -eq $null -or $installed.Version -lt $_.MinVersion
445
+ } |
446
+ % { $_.Name };
447
+ $map = Map-PackageNameToPackage $AppPackagePath\Dependencies\$Architecture
448
+ $packagePaths = $packageNamesToInstall | % { $map[$_] }
449
+ $packagePaths | % { Add-AppxPackage -Path $_ }
450
+ }
451
+
452
+ #endregion
453
+
454
+ # Export functions
455
+ Export-ModuleMember -Function @(
456
+ 'Uninstall-App',
457
+ 'EnableDevmode',
458
+ 'CheckIfNeedDeveloperLicense',
459
+ 'CheckIfNeedInstallCertificate',
460
+ 'Install-App',
461
+ 'Install-AppFromDirectory',
462
+ 'Install-AppFromAppx',
463
+ 'Start-Locally',
464
+ 'Install-AppDependencies'
465
+ )