AlkanePSF.psm1
Add-Type -AssemblyName System.IO.Compression.FileSystem $script:ApplicationsModel = @() $script:ProcessesModel = @() $fileRedirectionDllName = "FileRedirectionFixup.dll" $regLegacyDllName = "RegLegacyFixups.dll" $envVarDllName = "EnvVarFixup.dll" $dynamicLibraryDllName = "DynamicLibraryFixup.dll" $mfrDllName = "MFRFixup.dll" $traceDllName = "TraceFixup.dll" #******************************************* #******************************************** #function to remove directories with long paths #******************************************* #******************************************** function Remove-LongPathDirectory { Param( [string]$FullPath ) & cmd /c rmdir "$FullPath" /s /q } #******************************************* #******************************************** #function to find an exe in the Windows SDK #******************************************* #******************************************** function Get-WindowsSDKExe { param( [string]$ExeName ) try { $sdkPath = "${env:ProgramFiles(x86)}\Windows Kits\10\Bin\" if (!(test-path $sdkPath)) { write-host "**WARNING** Could not find $sdkPath" -ForegroundColor DarkYellow return } if($env:PROCESSOR_ARCHITECTURE -eq "x86") { $pathToExe = (Get-ChildItem $sdkPath -recurse -include $ExeName -ErrorAction SilentlyContinue | Where-Object FullName -like "*\x86\*" | Select-Object -First 1 -ExpandProperty FullName) } else { $pathToExe = (Get-ChildItem $sdkPath -recurse -include $ExeName -ErrorAction SilentlyContinue | Where-Object FullName -like "*\x64\*" | Select-Object -First 1 -ExpandProperty FullName) } return $pathToExe } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************** #******************************************** #function to install PSF prereqs #******************************************** #******************************************** function Install-AlkanePSFPrerequisite() { param( [bool]$ForceReinstall=$false ) try { #installs #https://developer.microsoft.com/en-gb/windows/downloads/windows-sdk/ #with #Windows SDK Signing Tools for Desktop Apps #Windows SDK for UWP Managed Apps #Windows SDK for UWP C++ Apps #Windows SDK for UWP Apps Localization $makeAppxPath = Get-WindowsSDKExe -ExeName "makeappx.exe" if (($null -eq $makeAppxPath -or $makeAppxPath -eq "") -or $ForceReinstall) { write-host "Installing Windows SDK tools for MSIX." $downloadExePath = "$env:temp\wdksetup.exe" $url = "https://go.microsoft.com/fwlink/?linkid=2083338" if (test-path $downloadExePath) { #remove before downloading write-host "Removing $downloadExePath." remove-item -Path $downloadExePath -Force -Recurse -ErrorAction SilentlyContinue } write-host "Downloading Windows SDK from $url." (New-Object Net.WebClient).DownloadFile($url, $downloadExePath) if (test-path $downloadExePath) { write-host "Installing Windows SDK." $result = (Start-Process -FilePath $downloadExePath -ArgumentList "/features","OptionId.SigningTools","OptionId.UWPManaged","OptionId.UWPCPP","OptionId.UWPLocalized","/quiet","/norestart" -Wait -Passthru).ExitCode if ($result -eq 0) { write-host "Windows SDK installed with exit code $result." } else { write-host "**WARNING** Windows SDK installed with exit code $result." -ForegroundColor DarkYellow } #remove download write-host "Removing $downloadExePath." Remove-Item $downloadExePath -Force -Recurse -ErrorAction SilentlyContinue } else { write-host "**WARNING** Could not download Windows SDK from $url" -ForegroundColor DarkYellow } } else { write-host "Windows SDK already installed." } $nupkg = Get-Package | Where-Object Name -eq "Microsoft.PackageSupportFramework" | Select-Object -ExpandProperty Source if (($null -eq $nupkg) -or $ForceReinstall) { write-host "Installing Microsoft's Package Support Framework." $nuget = get-packagesource | Where-Object ProviderName -eq "Nuget" if ($null -eq $nuget) { Register-PackageSource -Name nuget.org -Location https://www.nuget.org/api/v2 -ProviderName NuGet Install-Package -Name Microsoft.PackageSupportFramework -ProviderName Nuget -Force write-host "Microsoft's Package Support Framework installed." } else { $package = Get-Package | Where-Object Name -eq "Microsoft.PackageSupportFramework" if ($null -eq $package) { Install-Package -Name Microsoft.PackageSupportFramework -ProviderName Nuget -Force write-host "Microsoft's Package Support Framework installed." } else { if ($ForceReinstall) { Install-Package -Name Microsoft.PackageSupportFramework -ProviderName Nuget -Force write-host "Microsoft's Package Support Framework installed." } } } } else { write-host "Microsoft's Package Support Framework already installed." } $tmPsfLocation = "$env:temp\TMPSF" if ((!(test-path $tmPsfLocation)) -or $ForceReinstall) { write-host "Installing Tim Mangan's Package Support Framework." $extractFolder = "$env:temp\TMPSF" $downloadZipPath = "$env:temp\$alkaneTmZipName" $url = "https://github.com/TimMangan/MSIX-PackageSupportFramework/raw/develop/$alkaneTmZipName" if (test-path $downloadZipPath) { #remove before downloading write-host "Removing $downloadZipPath." remove-item -Path $downloadZipPath -Force -Recurse -ErrorAction SilentlyContinue } if (test-path $extractFolder) { #remove before extracting write-host "Removing $extractFolder." Remove-LongPathDirectory $extractFolder } write-host "Downloading Tim Mangan's PSF from $url." #download zip (New-Object Net.WebClient).DownloadFile($url, $downloadZipPath) #if zip downloaded if (test-path $downloadZipPath) { #extract it [IO.Compression.Zipfile]::ExtractToDirectory($downloadZipPath,$extractFolder); #if extracted ok, extract the release folder if (test-path "$extractFolder\ReleasePsf.zip") { [IO.Compression.Zipfile]::ExtractToDirectory("$extractFolder\ReleasePsf.zip",$extractFolder); write-host "Tim Mangen's Package Support Framework installed." } #remove download write-host "Removing $downloadZipPath." Remove-Item $downloadZipPath -Force -Recurse -ErrorAction SilentlyContinue } } else { write-host "Tim Mangan's Package Support Framework already installed." } write-host "Finished installing prerequisites." } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************** #******************************************** #function to extract/stage an MSIX package #******************************************** #******************************************** function New-AlkanePSFStagedPackage { try { if (!(test-path $alkanePathToMSIX)) { write-host "**WARNING** Could not find $alkanePathToMSIX" -ForegroundColor DarkYellow return } $packageName = (get-item $alkanePathToMSIX).BaseName $workFolder = (get-item $alkanePathToMSIX).Directory.FullName $stagingFolder = "$workFolder\$($packageName)_Staged\" write-host "Removing $stagingFolder" if (Test-Path $stagingFolder) { Remove-LongPathDirectory $stagingFolder } write-host "Finding MakeAppx.exe." $makeAppxPath = Get-WindowsSDKExe -ExeName "makeappx.exe" if ($makeAppxPath -ne "") { write-host "Extracting (staging) package to $stagingFolder." $result = (Start-Process -FilePath $makeAppxPath -ArgumentList "unpack","/p","$alkanePathToMSIX","/d","$StagingFolder" -Wait -Passthru).ExitCode if ($result -eq 0) { write-host "Package extracted (staged) to $stagingFolder with exit code $result." } else { write-host "**WARNING** Package extracted (staged) to $stagingFolder with exit code $result." -ForegroundColor DarkYellow } } else { write-host "Cannot find MakeAppx.exe" } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #function to extract AppxManifest.xml from MSIX. #******************************************* #******************************************** function Get-AlkaneAppxManifest { param( [string]$PathToAppx ) try { $zip = [IO.Compression.ZipFile]::OpenRead($alkanePathToMSIX) $zip.Entries | Where-Object {$_.Name -eq 'AppxManifest.xml'} | ForEach-Object { [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $PathToAppx, $true) } $zip.Dispose() } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************** #******************************************** #function to get the name of a filename without the extension #******************************************** #******************************************** function Get-ExeNameNoExtension { param( [string]$PathToEXE ) try { if ($PathToEXE -like "*/*" -or $PathToEXE -like "*\*") { $PathToEXE = $PathToEXE.replace('\','/').split('/')[-1] } if ($PathToEXE -like "*.*") { $PathToEXE = $PathToEXE.split('.')[0] } return $PathToEXE } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #function to get a PSF fixup #******************************************* #******************************************** function Get-AlkanePSFFixup { try { $allFixups = @() foreach ($fixup in $script:ProcessesModel.fixups) { $allFixups += $fixup } return ($allFixups) } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #Function to add a supported Fixup application #******************************************* #******************************************** Function Add-AlkanePSFApplication { param( [string]$FixupApplicationId, [string]$FixupWorkingDirectory, [array]$FixupArguments, [bool]$FixupInPackageContext=$false ) try { if (!(test-path $alkanePathToMSIX)) { write-host "**WARNING** Could not find $alkanePathToMSIX" -ForegroundColor DarkYellow return } #check if we have an 'application' in our dynamic config.json $targetExe = ($script:ApplicationsModel | Where-Object id -eq "$FixupApplicationId").executable if ($null -ne $targetExe -and $targetExe -ne "") { write-host "**WARNING** Application $FixupApplicationId already exists. Will not add again." -ForegroundColor DarkYellow return } $workFolder = (get-item $alkanePathToMSIX).Directory.FullName $packageName = (get-item $alkanePathToMSIX).Basename #Create a subfolder to stage the extraction of the package $stagingFolder = "$workFolder\$($packageName)_Staged\" $appxManifest = "$($stagingFolder)AppxManifest.xml" if (!(test-path $appxManifest)) { write-host "**WARNING** Could not find $appxManifest" -ForegroundColor DarkYellow return } [xml]$appinfo = Get-Content -Path $appxManifest $applications = $appinfo.Package.Applications.Application if ($null -ne $applications) { $exe = $applications | Where-Object id -eq "$FixupApplicationId" | Select-Object -ExpandProperty executable $availableApps = ($applications.id -join " ") if ($null -eq $exe -or $exe -eq "") { write-host "**WARNING** Could not find application ID: $FixupApplicationId in AppxManifest.xml. Available app id's are: $availableApps. Please change the application ID." -ForegroundColor DarkYellow return } else { $script:ApplicationsModel += ,([ordered]@{ 'id' = $FixupApplicationId 'executable' = $exe 'workingDirectory' = $FixupWorkingDirectory 'inPackageContext' = $FixupInPackageContext 'arguments' = (($FixupArguments | ForEach-Object {"`"" + $_ + "`""}) -join " "); }) } } $exe = Get-ExeNameNoExtension $exe $script:ProcessesModel += ,([ordered]@{ 'executable' = $exe }) } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #Function to add file redirection fixup #******************************************* #******************************************** Function Add-AlkanePSFFileRedirectionFixup { param( [string]$FixupApplicationId, [ValidateSet("packageRelative","packageDriveRelative","knownFolders")] [string]$FixupType, [string]$FixupBase, [array]$FixupPatterns, [string]$FixupId ) write-host "Adding File Redirection Fixup for $FixupApplicationId" try { #check if we have an 'application' in our dynamic config.json $targetExe = ($script:ApplicationsModel | Where-Object id -eq "$FixupApplicationId").executable if ($null -eq $targetExe -or $targetExe -eq "") { write-host "**WARNING** Could not find application ID: $FixupApplicationId. Please change the application ID or run: Add-AlkanePSFApplication -FixupApplicationId `"$FixupApplicationId`"." -ForegroundColor DarkYellow return } #extract the process name without the extension $targetExe = Get-ExeNameNoExtension -PathToEXE $targetExe $FileRedirectionFixupModel = [ordered]@{ dll=$fileRedirectionDllName; config=@{ } } #check if fixup has been added previously $fixups = ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups | Where-Object dll -eq $fileRedirectionDllName if ($null -eq $fixups -or $fixups.Count -eq 0) { ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups += @($FileRedirectionFixupModel) } $fixupstype = (($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups | Where-Object dll -eq $fileRedirectionDllName).config.redirectedPaths.$FixupType if ($null -eq $fixupstype -or $fixupstype.Count -eq 0) { ($script:ProcessesModel.fixups | Where-Object dll -eq $fileRedirectionDllName).config.redirectedPaths += @{ $FixupType = $null } } switch ($FixupType) { "packageRelative" { ($script:ProcessesModel.fixups | Where-Object dll -eq $fileRedirectionDllName).config.redirectedPaths.$FixupType += ,@{ base=$FixupBase; patterns=$FixupPatterns; } } "packageDriveRelative" { ($script:ProcessesModel.fixups | Where-Object dll -eq $fileRedirectionDllName).config.redirectedPaths.$FixupType += ,@{ base=$FixupBase; patterns=$FixupPatterns; } } "knownFolders" { ($script:ProcessesModel.fixups | Where-Object dll -eq $fileRedirectionDllName).config.redirectedPaths.$FixupType += ,@{ id=$FixupId; relativePaths = ,@{ base=$FixupBase; patterns=$FixupPatterns; } } } } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #Function to add reg legacy fixup #******************************************* #******************************************** Function Add-AlkanePSFRegLegacyFixup { param( [string]$FixupApplicationId, [ValidateSet("ModifyKeyAccess","FakeDelete")] [string]$FixupType, [ValidateSet("HKCU","HKLM")] [string]$FixupHive, [ValidateSet("FULL2RW","FULL2R","Full2MaxAllowed","RW2R","RW2MaxAllowed")] [string]$FixupAccess, [array]$FixupPatterns ) write-host "Adding Reg Legacy Fixup for $FixupApplicationId" try { #check if we have an 'application' in our dynamic config.json $targetExe = ($script:ApplicationsModel | Where-Object id -eq "$FixupApplicationId").executable if ($null -eq $targetExe -or $targetExe -eq "") { write-host "**WARNING** Could not find application ID: $FixupApplicationId. Please change the application ID or run: Add-AlkanePSFApplication -FixupApplicationId `"$FixupApplicationId`"." -ForegroundColor DarkYellow return } #extract the process name without the extension $targetExe = Get-ExeNameNoExtension -PathToEXE $targetExe $RegLegacyFixupModel = [ordered]@{ dll=$regLegacyDllName; config=@{ } } #check if fixup has been added previously $fixups = ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups | Where-Object dll -eq $regLegacyDllName if ($null -eq $fixups -or $fixups.Count -eq 0) { ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups += @($RegLegacyFixupModel) } switch ($FixupType) { "ModifyKeyAccess" { ($script:ProcessesModel.fixups | Where-Object dll -eq $regLegacyDllName).config.remediation += ,@{ type=$FixupType; hive=$FixupHive; access=$FixupAccess; patterns=$FixupPatterns; } } "FakeDelete" { ($script:ProcessesModel.fixups | Where-Object dll -eq $regLegacyDllName).config.remediation += ,@{ type=$FixupType; hive=$FixupHive; access=$FixupAccess; patterns=$FixupPatterns; } } } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #function to add env var fixup #******************************************* #******************************************** Function Add-AlkanePSFEnvVarFixup { param( [string]$FixupApplicationId, [string]$FixupVarName, [string]$FixupVarValue, [bool]$FixupVarUseRegistry=$true ) write-host "Adding Env Var Fixup for $FixupApplicationId" try { #check if we have an 'application' in our dynamic config.json $targetExe = ($script:ApplicationsModel | Where-Object id -eq "$FixupApplicationId").executable if ($null -eq $targetExe -or $targetExe -eq "") { write-host "**WARNING** Could not find application ID: $FixupApplicationId. Please change the application ID or run: Add-AlkanePSFApplication -FixupApplicationId `"$FixupApplicationId`"." -ForegroundColor DarkYellow return } #extract the process name without the extension $targetExe = Get-ExeNameNoExtension -PathToEXE $targetExe $EnvVarFixupModel = [ordered]@{ dll=$envVarDllName; config=@{ } } #check if fixup has been added previously $fixups = ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups | Where-Object dll -eq $envVarDllName if ($null -eq $fixups -or $fixups.Count -eq 0) { ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups += @($EnvVarFixupModel) } ($script:ProcessesModel.fixups | Where-Object dll -eq $envVarDllName).config.envVars += ,@{ name=$FixupVarName; value=$FixupVarValue; useRegistry=$FixupVarUseRegistry; } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #Function to add dynamic library fixup #******************************************* #******************************************** Function Add-AlkanePSFDynamicLibraryFixup { param( [string]$FixupApplicationId, [string]$FixupDllName, [string]$FixupDllFilepath, [bool]$FixupForcePackageDllUse=$true ) write-host "Adding Dynamic Library Fixup for $FixupApplicationId" try { #check if we have an 'application' in our dynamic config.json $targetExe = ($script:ApplicationsModel | Where-Object id -eq "$FixupApplicationId").executable if ($null -eq $targetExe -or $targetExe -eq "") { write-host "**WARNING** Could not find application ID: $FixupApplicationId. Please change the application ID or run: Add-AlkanePSFApplication -FixupApplicationId `"$FixupApplicationId`"." -ForegroundColor DarkYellow return } #extract the process name without the extension $targetExe = Get-ExeNameNoExtension -PathToEXE $targetExe $DynamicLibraryFixupModel = [ordered]@{ dll=$dynamicLibraryDllName; config=@{ forcePackageDllUse=$FixupForcePackageDllUse; } } #check if fixup has been added previously $fixups = ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups | Where-Object dll -eq $dynamicLibraryDllName if ($null -eq $fixups -or $fixups.Count -eq 0) { ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups += @($DynamicLibraryFixupModel) } ($script:ProcessesModel.fixups | Where-Object dll -eq $dynamicLibraryDllName).config.relativeDllPaths += ,@{ name=$FixupDllName; filepath=$FixupDllFilepath; } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #Function to add MFR fixup #******************************************* #******************************************** Function Add-AlkanePSFMFRFixup { param( [string]$FixupApplicationId, [ValidateSet("OverrideLocalRedirections","OverrideTraditionalRedirections")] [string]$FixupType, [string]$FixupName, [string]$FixupMode, [bool]$FixupIlvAware=$false, [ValidateSet("disableAll","enablePe","default")] [string]$FixupOverrideCOW="default") write-host "Adding MFR Fixup for $FixupApplicationId" try { #check if we have an 'application' in our dynamic config.json $targetExe = ($script:ApplicationsModel | Where-Object id -eq "$FixupApplicationId").executable if ($null -eq $targetExe -or $targetExe -eq "") { write-host "**WARNING** Could not find application ID: $FixupApplicationId. Please change the application ID or run: Add-AlkanePSFApplication -FixupApplicationId `"$FixupApplicationId`"." -ForegroundColor DarkYellow return } #extract the process name without the extension $targetExe = Get-ExeNameNoExtension -PathToEXE $targetExe $MFRFixupModel = [ordered]@{ dll=$mfrDllName; config=@{ overrideCOW=$FixupOverrideCOW; ilvAware=$FixupIlvAware; } } #check if fixup has been added previously $fixups = ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups | Where-Object dll -eq $mfrDllName if ($null -eq $fixups -or $fixups.Count -eq 0) { ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups += @($MFRFixupModel) } switch ($FixupType) { "OverrideLocalRedirections" { ($script:ProcessesModel.fixups | Where-Object dll -eq $mfrDllName).config.overrideLocalRedirections += ,[ordered]@{ name=$FixupName; mode=$FixupMode; } } "OverrideTraditionalRedirections" { ($script:ProcessesModel.fixups | Where-Object dll -eq $mfrDllName).config.overrideTraditionalRedirections += ,[ordered]@{ name=$FixupName; mode=$FixupMode; } } } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #function to add trace fixup #******************************************* #******************************************** Function Add-AlkanePSFTraceFixup { param( [string]$FixupApplicationId, [ValidateSet("printf","eventlog","outputDebugString")] [string]$FixupTraceMethod, [bool]$FixupWaitForDebugger=$false, [bool]$FixupTraceFunctionEntry=$false, [bool]$FixupTraceCallingModule=$true, [bool]$FixupIgnoreDllLoad=$true, [string]$FixupType, [ValidateSet("default","filesystem","registry","processAndThread","dynamicLinkLibrary")] [string]$FixupTraceLevelProperty, [ValidateSet("always","ignoreSuccess","allFailures","unexpectedFailures","ignore")] [string]$FixupTraceLevelValue, [ValidateSet("default","filesystem","registry","processAndThread","dynamicLinkLibrary")] [string]$FixupBreakOnProperty, [ValidateSet("always","ignoreSuccess","allFailures","unexpectedFailures","ignore")] [string]$FixupBreakOnValue ) write-host "Adding Trace Fixup for $FixupApplicationId" try { #check if we have an 'application' in our dynamic config.json $targetExe = ($script:ApplicationsModel | Where-Object id -eq "$FixupApplicationId").executable if ($null -eq $targetExe -or $targetExe -eq "") { write-host "**WARNING** Could not find application ID: $FixupApplicationId. Please change the application ID or run: Add-AlkanePSFApplication -FixupApplicationId `"$FixupApplicationId`"." -ForegroundColor DarkYellow return } #extract the process name without the extension $targetExe = Get-ExeNameNoExtension -PathToEXE $targetExe $TraceFixupModel = [ordered]@{ dll=$traceDllName; config=@{ traceMethod=$FixupTraceMethod waitForDebugger=$FixupWaitForDebugger traceFunctionEntry=$FixupTraceFunctionEntry traceCallingModule=$FixupTraceCallingModule ignoreDllLoad=$FixupIgnoreDllLoad traceLevels=@{ $FixupTraceLevelProperty=$FixupTraceLevelValue } breakOn=@{ $FixupBreakOnProperty=$FixupBreakOnValue } } } #check if fixup has been added previously $fixups = ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups | Where-Object dll -eq $traceDllName if ($null -eq $fixups -or $fixups.Count -eq 0) { ($script:ProcessesModel | Where-Object executable -eq $targetExe).fixups += @($TraceFixupModel) } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #function to add start script #******************************************* #******************************************** Function Add-AlkanePSFStartScript { param( [string]$FixupApplicationId, [string]$FixupScriptPath, [array]$FixupScriptArguments, [bool]$FixupRunInVirtualEnvironment=$true, [bool]$FixupShowWindow=$false, [bool]$FixupStopOnScriptError=$false, [bool]$FixupWaitForScriptToFinish=$true, [int]$FixupTimeout ) write-host "Adding Start Script for $FixupApplicationId" try { $foundApp = $false; foreach ($app in $script:ApplicationsModel) { if ($app.id -eq $FixupApplicationId) { $foundApp = $true $app.startScript = @{ scriptPath=$FixupScriptPath; scriptArguments=(($FixupScriptArguments | ForEach-Object {"`"" + $_ + "`""}) -join " "); runInVirtualEnvironment=$FixupRunInVirtualEnvironment; showWindow=$FixupShowWindow; stopOnScriptError=$FixupStopOnScriptError; waitForScriptToFinish=$FixupWaitForScriptToFinish; timeout=$FixupTimeout; } } } if (!$foundApp) { write-host "**WARNING** Could not find application ID: $FixupApplicationId. Please change the application ID or run: Add-AlkanePSFApplication -FixupApplicationId `"$FixupApplicationId`"." -ForegroundColor DarkYellow } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #function to add end script #******************************************* #******************************************** Function Add-AlkanePSFEndScript { param( [string]$FixupApplicationId, [string]$FixupScriptPath, [array]$FixupScriptArguments, [bool]$FixupRunInVirtualEnvironment=$true, [bool]$FixupShowWindow=$false, [bool]$FixupStopOnScriptError=$false, [bool]$FixupWaitForScriptToFinish=$true, [int]$FixupTimeout ) write-host "Adding End Script for $FixupApplicationId" try { $foundApp = $false; foreach ($app in $script:ApplicationsModel) { if ($app.id -eq $FixupApplicationId) { $foundApp = $true $app.endScript = @{ scriptPath=$FixupScriptPath; scriptArguments=(($FixupScriptArguments | ForEach-Object {"`"" + $_ + "`""}) -join " "); runInVirtualEnvironment=$FixupRunInVirtualEnvironment; showWindow=$FixupShowWindow; stopOnScriptError=$FixupStopOnScriptError; waitForScriptToFinish=$FixupWaitForScriptToFinish; timeout=$FixupTimeout; } } } if (!$foundApp) { write-host "**WARNING** Could not find application ID: $FixupApplicationId. Please change the application ID or run: Add-AlkanePSFApplication -FixupApplicationId `"$FixupApplicationId`"." -ForegroundColor DarkYellow } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #Function to apply fixups by updating AppxManifest.xml and generating config.json #******************************************* #******************************************** function Set-AlkanePSF { param( [ValidateSet("MS","TM")] [string]$FixupPSFType="MS", [bool]$FixupOpenConfigJson=$false ) try { if (!(test-path $alkanePathToMSIX)) { write-host "**WARNING** Could not find $alkanePathToMSIX" -ForegroundColor DarkYellow return } if (!(test-path $alkanePathToCertificate)) { write-host "**WARNING** Could not find $alkanePathToCertificate" -ForegroundColor DarkYellow return } #get name of MSIX without extension $packageName = (get-item $alkanePathToMSIX).Basename $workFolder = (get-item $alkanePathToMSIX).Directory.FullName #Create a subfolder to stage the extraction of the package $stagingFolder = "$workFolder\$($packageName)_Staged" if (!(test-path $stagingFolder)) { write-host "**WARNING** Could not find $stagingFolder" -ForegroundColor DarkYellow return } #set the location of config.json and appxmanifest.xml to the staging folder $configJSON = "$stagingFolder\config.json" $appxManifest = "$stagingFolder\AppxManifest.xml" #locate the bin folder containing PSF DLLs if ($FixupPSFType -eq "MS") { write-host "Using Microsoft's PSF." $nupkg = Get-Package | Where-Object Name -eq "Microsoft.PackageSupportFramework" | Select-Object -ExpandProperty Source $psfLocation = (get-item $nupkg).Directory.FullName + "\bin" } else { write-host "Using Tim Mangan's PSF." $psfLocation = "$env:temp\TMPSF" } #store all fixups $allfixups = Get-AlkanePSFFixup #psfLauncher files $psfLauncherExe = "PsfLauncher$alkaneAppArchitecture.exe" $psfLauncherDll = "PsfRuntime$alkaneAppArchitecture.dll" $psfRunExe = "PsfRunDll$alkaneAppArchitecture.exe" #fixup files $dynamicLibraryFixupDll = "DynamicLibraryFixup$alkaneAppArchitecture.dll" $fileRedirectionFixupDll = "FileRedirectionFixup$alkaneAppArchitecture.dll" $regLegacyFixupDll = "RegLegacyFixups$alkaneAppArchitecture.dll" $envVarFixupDll = "EnvVarFixup$alkaneAppArchitecture.dll" $mfrFixupDll = "MFRFixup$alkaneAppArchitecture.dll" $traceFixupDll = "TraceFixup$alkaneAppArchitecture.dll" #copy psfLauncher Copy-Item -Path "$psfLocation\$psfLauncherExe" -Destination "$stagingFolder" -Force Copy-Item -Path "$psfLocation\$psfLauncherDll" -Destination "$stagingFolder" -Force Copy-Item -Path "$psfLocation\$psfRunExe" -Destination "$stagingFolder" -Force #get a fresh AppxManifest in case we're running this multiple times Get-AlkaneAppxManifest -PathToAppx $appxManifest #Need to make sure manifest publisher is the same as our certificate $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $cert.Import($alkanePathToCertificate,$alkaneCertificatePassword,'DefaultKeySet') $certificateSubject = $cert.Subject #read from manifest [xml]$appinfo = Get-Content -Path $appxManifest $identity = $appinfo.Package.Identity $identity.Publisher = $certificateSubject #get app list for config.json from Appxmanifest $applications = $appinfo.Package.Applications.Application if ($null -ne $applications) { #change executable in manifest to point to the PsfLauncher foreach ($fixupapp in $script:ApplicationsModel) { $foundApp = $false foreach ($manifestapp in $applications){ if ($manifestapp.id -eq $fixupapp.id) { $foundApp = $true $manifestapp.Executable = "$psfLauncherExe" break } } if (!$foundApp) { $availableApps = ($applications.id -join " ") write-host "**WARNING** Could not find application ID: $($fixupapp.id). When using Add-AlkanePSFApplication, your app id must be one of: $availableApps" -ForegroundColor DarkYellow } } #save the appxmanifest.xml $appinfo.Save($appxManifest) } #generate config.json #copy required fixup DLLs, and removed DLLs not required $ApplyDynamicLibraryFixup = $false $ApplyFileRedirectionFixup = $false $ApplyEnvVarFixup = $false $ApplyRegLegacyFixup = $false $ApplyMFRFixup = $false $ApplyTraceFixup = $false foreach($fu in $allfixups) { switch ($fu.dll) { $dynamicLibraryDllName {$fu.dll="$dynamicLibraryFixupDll";$ApplyDynamicLibraryFixup=$true;} $fileRedirectionDllName {$fu.dll="$fileRedirectionFixupDll";$ApplyFileRedirectionFixup=$true;} $envVarDllName {$fu.dll="$envVarFixupDll";$ApplyEnvVarFixup=$true;} $regLegacyDllName {$fu.dll="$regLegacyFixupDll";$ApplyRegLegacyFixup=$true;} $mfrDllName {$fu.dll="$mfrFixupDll";$ApplyMFRFixup=$true;} $traceDllName {$fu.dll="$traceFixupDll";$ApplyTraceFixup=$true;} } } if ($ApplyTraceFixup) { write-host "Adding $stagingFolder\$traceFixupDll." Copy-Item -Path "$psfLocation\$traceFixupDll" -Destination "$stagingFolder" -Force } else { write-host "Removing $stagingFolder\$traceFixupDll." Remove-Item -Path "$stagingFolder\$traceFixupDll" -Force -Recurse -ErrorAction SilentlyContinue } if ($ApplyMFRFixup) { write-host "Adding $stagingFolder\$mfrFixupDll." Copy-Item -Path "$psfLocation\$mfrFixupDll" -Destination "$stagingFolder" -Force } else { write-host "Removing $stagingFolder\$mfrFixupDll." Remove-Item -Path "$stagingFolder\$mfrFixupDll" -Force -Recurse -ErrorAction SilentlyContinue } if ($ApplyFileRedirectionFixup) { write-host "Adding $stagingFolder\$fileRedirectionFixupDll." Copy-Item -Path "$psfLocation\$fileRedirectionFixupDll" -Destination "$stagingFolder" -Force } else { write-host "Removing $stagingFolder\$fileRedirectionFixupDll." Remove-Item -Path "$stagingFolder\$fileRedirectionFixupDll" -Force -Recurse -ErrorAction SilentlyContinue } if ($ApplyRegLegacyFixup) { write-host "Adding $stagingFolder\$regLegacyFixupDll." Copy-Item -Path "$psfLocation\$regLegacyFixupDll" -Destination "$stagingFolder" -Force } else { write-host "Removing $stagingFolder\$regLegacyFixupDll." Remove-Item -Path "$stagingFolder\$regLegacyFixupDll" -Force -Recurse -ErrorAction SilentlyContinue } if ($ApplyEnvVarFixup) { write-host "Adding $stagingFolder\$EnvVarFixupDll." Copy-Item -Path "$psfLocation\$EnvVarFixupDll" -Destination "$stagingFolder" -Force } else { write-host "Removing $stagingFolder\$EnvVarFixupDll." Remove-Item -Path "$stagingFolder\$EnvVarFixupDll" -Force -Recurse -ErrorAction SilentlyContinue } if ($ApplyDynamicLibraryFixup) { write-host "Adding $stagingFolder\$dynamicLibraryFixupDll." Copy-Item -Path "$psfLocation\$dynamicLibraryFixupDll" -Destination "$stagingFolder" -Force } else { write-host "Removing $stagingFolder\$dynamicLibraryFixupDll." Remove-Item -Path "$stagingFolder\$dynamicLibraryFixupDll" -Force -Recurse -ErrorAction SilentlyContinue } $json = @{ 'applications' = $script:ApplicationsModel 'processes' = $script:ProcessesModel } #delete config.json if exists if (test-path $configJSON) { write-host "Removing $configJSON." Remove-Item $configJSON -Force -Recurse -ErrorAction SilentlyContinue } #write config.json $json | ConvertTo-Json -Depth 15 | Out-File -FilePath $configJSON if ($FixupOpenConfigJson) { Start-Process "notepad.exe" -ArgumentList $configJSON } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } #******************************************* #******************************************** #Function to create and sign a new MSIX #******************************************* #******************************************** function New-AlkanePSFMSIX { try { if (!(test-path $alkanePathToMSIX)) { write-host "**WARNING** Could not find $alkanePathToMSIX" -ForegroundColor DarkYellow return } if (!(test-path $alkanePathToCertificate)) { write-host "**WARNING** Could not find $alkanePathToCertificate" -ForegroundColor DarkYellow return } if (test-path $alkanePathToFixedMSIX) { write-host "Removing $alkanePathToFixedMSIX." Remove-Item $alkanePathToFixedMSIX -Force -Recurse -ErrorAction SilentlyContinue } $packageName = (get-item $alkanePathToMSIX).BaseName $workFolder = (get-item $alkanePathToMSIX).Directory.FullName $stagingFolder = "$workFolder\$($packageName)_Staged" write-host "Finding MakeAppx.exe." $makeAppxPath = Get-WindowsSDKExe -ExeName "makeappx.exe" if ($makeAppxPath -ne "") { write-host "Found at $makeAppxPath." write-host "Finding Signtool.exe." $signToolPath = Get-WindowsSDKExe -ExeName "signtool.exe" if ($signToolPath -ne "") { write-host "Found at $signToolPath." write-host "Compiling package to $alkanePathToFixedMSIX." $result = (Start-Process -FilePath $makeAppxPath -ArgumentList "pack","/p","$alkanePathToFixedMSIX","/d","$StagingFolder" -Wait -Passthru).ExitCode if ($result -eq 0) { write-host "Package compiled to $alkanePathToFixedMSIX with exit code $result." } else { write-host "**WARNING** Package compiled to $alkanePathToFixedMSIX with exit code $result." -ForegroundColor DarkYellow } write-host "Signing $alkanePathToFixedMSIX." $result = (Start-Process -FilePath $signToolPath -ArgumentList "sign","/tr","http://timestamp.digicert.com","/v","/fd","sha256","/td","sha256","/f","$alkanePathToCertificate","/p","$alkaneCertificatePassword","$alkanePathToFixedMSIX" -Wait -Passthru).ExitCode if ($result -eq 0) { write-host "Signed $alkanePathToFixedMSIX with exit code $result." } else { write-host "**WARNING** Signed $alkanePathToFixedMSIX with exit code $result." -ForegroundColor DarkYellow } } else { write-host "Cannot find Signtool.exe." } } else { write-host "Cannot find MakeAppx.exe." } } catch { write-host "**ERROR** $($_)" -ForegroundColor Red } } |