[APORTE] [PowerShell] Automated AppX Package Installer

Páginas: (1/1)

Eleкtro:

El siguiente script desarrollado en Powershell, buscará archivos de paquetes AppX (*.appx, *.appxbundle, *.msixbundle) dentro del directorio actual (sin recursividad), imprimirá información sobre el paquete, imprimirá un mensaje en caso de que el paquete ya esté instalado, e instalará el paquete en caso de que no esté instalado, manejando posibles errores durante instalación.

Es una herramienta muy útil en particular para quien (como yo) tenga completamente capada la Microsoft Store y sus funcionalidades en el sistema operativo, y necesite una forma de poder instalar paquetes de aplicaciones (*.appx, *.appxbundle, *.msixbundle) descargadas de forma local desde la Microsoft Store.




Código
--
# --------------------------------------------- #
--
# Automated AppX Package Installer - by Elektro #
--
# --------------------------------------------- #
--
 
--
# This script will find any AppX package files within the current directory (without recursion),
--
# print info about the package, print a message in case of the package is already installed,
--
# and install the package in case of it is not installed, handling errors during installation.
--
 
--
# ---------------------------------------------------------------------
--
 
--
# Takes a string argument that points to an AppX package name or file,
--
# then it uses a regular expression to match the package string pattern
--
# and returns a custom object with the Name, Version, Architecture,
--
# PublisherId and other properties.
--
#
--
# Parameters:
--
#   -PackageString: A string that points to the file name
--
#                   or full path of an AppX package file.
--
#
--
# Returns:
--
#   A PSCustomObject object with these properties defined:
--
#     [String] Name
--
#     [String] Version
--
#     [String] Architecture
--
#     [String] PublisherId
--
#     [String] FullName
--
function Get-AppXPackageInfo {
--
   param (
--
       [Parameter(Mandatory=$true)] [string]$PackageString
--
   )
--
 
--
   #$dirname = [System.IO.Path]::GetDirectoryName($PackageString)
--
   #if ([string]::IsNullOrEmpty($dirname)) {
--
   #    $dirname = $PWD
--
   #}
--
 
--
   $filename = [System.IO.Path]::GetFileName($PackageString) -replace "(?i)\.appxbundle$", "" -replace "(?i)\.msixbundle$", "" -replace "(?i)\.appx$", ""
--
 
--
   $regex = '^(?<Name>.+?)_(?<Version>.+?)_(?<Architecture>.+?)_(?<chars>~)?_(?<PublisherId>.+)$'
--
   $match = $filename -match $regex
--
 
--
   if (!$match) {
--
       throw "Unable to parse the string package: '$PackageString'"
--
   }
--
 
--
   [string]$packageName         = $matches['Name']
--
   [string]$packageVersion      = $matches['Version']
--
   [string]$packageArchitecture = $matches['Architecture']
--
   [string]$packagePublisherId  = $matches['PublisherId']
--
   [string]$chars               = $matches['chars']
--
   [string]$packageFullName     = "${packageName}_${packageVersion}_${packageArchitecture}_${chars}_${packagePublisherId}"
--
   #[string]$packageFullPath    = [System.IO.Path]::Combine($dirname, "$filename.Appx")
--
 
--
   [PSCustomObject]@{
--
       Name = $packageName
--
       Version = $packageVersion
--
       Architecture = $packageArchitecture
--
       PublisherId = $packagePublisherId
--
       FullName = $packageFullName
--
       #FullPath = $packageFullPath
--
   }
--
}
--
 
--
# Determines whether an Appx package matching the specified
--
# name, version and architecture is installed in the system.
--
#
--
# Parameters:
--
#   -Name........: The package name.
--
#   -Version.....: The package version.
--
#   -Architecture: The package architecture ("x86", "x64").
--
#
--
# Returns:
--
#   $true if the AppX package is installed in the system,
--
#   $false otherwise.
--
function IsAppxPackageInstalled() {
--
   param (
--
       [Parameter(Mandatory=$true)] [string]$name,
--
       [Parameter(Mandatory=$true)] [string]$version,
--
       [Parameter(Mandatory=$true)] [string]$architecture
--
   )
--
 
--
   if ($architecture -eq "neutral") {
--
       $architecture = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture
--
   }
--
 
--
   $packages = Get-AppxPackage "$($name)*" -ErrorAction Stop | Where-Object {
--
       $_.Name.ToLower()              -eq $name.ToLower()         -and
--
       $_.Version.ToLower()           -eq $version.ToLower()      -and
--
       "$($_.Architecture)".ToLower() -eq $architecture.ToLower()
--
   }
--
   return ($packages.Count -gt 0)
--
}
--
 
--
<#
--
===========================================================================================
--
|                                                                                         |
--
|                                         Main                                            |
--
|                                                                                         |
--
===========================================================================================
--
#>
--
 
--
[System.Console]::Title = "Automated AppX Package Installer - by Elektro"
--
[CultureInfo]::CurrentUICulture = "en-US"
--
 
--
try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { }
--
 
--
# Hides the progress-bar for 'Add-AppxPackage' cmdlet in this script.
--
# Thanks to @Santiago Squarzon for the tip: https://stackoverflow.com/questions/75716867
--
# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.3#progresspreference
--
$ProgressPreference = "Ignore"
--
 
--
Do {
--
   Clear-Host
--
   Write-Output ""
--
   Write-Output " $($host.ui.RawUI.WindowTitle)"
--
   Write-Output " +=====================================================+"
--
   Write-Output " |                                                     |"
--
   Write-Output " | This script will find any AppX package files        |"
--
   Write-Output " | within the current directory (without recursion),   |"
--
   Write-Output " | print info about the package, print a message       |"
--
   Write-Output " | in case of the package is already installed,        |"
--
   Write-Output " | and install the package in case of it is            |"
--
   Write-Output " | not installed, handling errors during installation. |"
--
   Write-Output " |                                                     |"
--
   Write-Output " +=====================================================+"
--
   Write-Output ""
--
   Write-Host " -Continue? (Y/N)"
--
   $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
--
   $char = $key.Character.ToString().ToUpper()
--
   if ($char -ne "Y" -and $char -ne "N") {
--
       [console]::beep(1500, 500)
--
   }
--
} while ($char -ne "Y" -and $char -ne "N")
--
if ($char -eq "N") {Exit(1)} else {Clear-Host}
--
 
--
$appxFiles = Get-ChildItem -Path "$PWD" -Filter "*.appx*"
--
 
--
if ($appxFiles.Count -eq 0) {
--
   Write-Warning "No Appx files were found in the current directory."
--
   Write-Host ""
--
   $LastExitCode = 2
--
} else {
--
   $appxFiles | ForEach-Object {
--
       # The AppX package string. It can be a file name (with or without extension), or a full path.
--
       $packageString = $_.FullName
--
       $packageInfo = Get-AppXPackageInfo -PackageString $packageString
--
       $nameVerArch = "$($packageInfo.Name) v$($packageInfo.Version) ($($packageInfo.Architecture))"
--
       Write-Host "Package Info.:" -ForegroundColor Gray
--
       Write-Host ($packageInfo | Format-List | Out-String).Trim() -ForegroundColor DarkGray
--
       Write-Host ""
--
 
--
       $isInstalled = IsAppxPackageInstalled -Name $packageInfo.Name -Version $packageInfo.Version -Architecture $packageInfo.Architecture
--
       if ($isInstalled) {
--
           Write-Warning "Package $nameVerArch is already installed."
--
           Write-Warning "Installation is not needed."
--
       } else {
--
           Write-Host "Package $nameVerArch is ready to install."
--
           Write-Host "Installing package..."
--
           try {
--
               Add-AppxPackage -Path "$($_.FullName)" -ErrorAction Stop
--
               Write-Host "Package $nameVerArch has been successfully installed." -BackgroundColor Black -ForegroundColor Green
--
           } catch {
--
               Write-Host "Error installing package $nameVerArch" -BackgroundColor Black -ForegroundColor Red
--
               Write-Host ""
--
               Write-Error -Message ($_.Exception | Format-List * -Force | Out-String)
--
               $LastExitCode = 1
--
               Break
--
           }
--
       }
--
       Write-Host ""
--
       $LastExitCode = 0
--
   }
--
}
--
 
--
Write-Host "Program will terminate now with exit code $LastExitCode. Press any key to exit..."
--
$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
--
Exit($LastExitCode)
--


Eleкtro:

Una captura de pantalla:



Y una pequeña revisión del código:

Código
--
# --------------------------------------------- #
--
# Automated AppX Package Installer - by Elektro #
--
# --------------------------------------------- #
--
 
--
# This script will find any AppX package files within the current directory (without recursion),
--
# print info about the package, print a message in case of the package is already installed,
--
# and install the package in case of it is not installed, handling errors during installation.
--
 
--
# ---------------------------------------------------------------------
--
 
--
# Takes a string argument that points to an AppX package name or file,
--
# then it uses a regular expression to match the package string pattern
--
# and returns a custom object with the Name, Version, Architecture,
--
# PublisherId and other properties.
--
#
--
# Parameters:
--
#   -PackageString: A string that points to the file name
--
#                   or full path of an AppX package file.
--
#
--
# Returns:
--
#   A PSCustomObject object with these properties defined:
--
#     [String] Name
--
#     [String] Version
--
#     [String] Architecture
--
#     [String] PublisherId
--
#     [String] FullName
--
function Get-AppXPackageInfo {
--
   param (
--
       [Parameter(Mandatory=$true)] [string]$PackageString
--
   )
--
 
--
   #$dirname = [System.IO.Path]::GetDirectoryName($PackageString)
--
   #if ([string]::IsNullOrEmpty($dirname)) {
--
   #    $dirname = $PWD
--
   #}
--
 
--
   $filename = [System.IO.Path]::GetFileName($PackageString) -replace "(?i)\.appxbundle$", "" -replace "(?i)\.msixbundle$", "" -replace "(?i)\.appx$", ""
--
   $fileExt  = [System.IO.Path]::GetExtension($PackageString)
--
 
--
   $regex = '^(?<Name>.+?)_(?<Version>.+?)_(?<Architecture>.+?)_(?<chars>~)?_(?<PublisherId>.+)$'
--
   $match = $filename -match $regex
--
 
--
   if (!$match) {
--
       throw "Unable to parse the string package: '$PackageString'"
--
   }
--
 
--
   [string]$packageName         = $matches['Name']
--
   [string]$packageVersion      = $matches['Version']
--
   [string]$packageArchitecture = $matches['Architecture']
--
   [string]$packagePublisherId  = $matches['PublisherId']
--
   [string]$chars               = $matches['chars']
--
   [string]$packageFullName     = "${packageName}_${packageVersion}_${packageArchitecture}_${chars}_${packagePublisherId}$fileExt"
--
   #[string]$packageFullPath    = [System.IO.Path]::Combine($dirname, "$filename$fileExt")
--
 
--
   [PSCustomObject]@{
--
       Name = $packageName
--
       Version = $packageVersion
--
       Architecture = $packageArchitecture
--
       PublisherId = $packagePublisherId
--
       FullName = $packageFullName
--
       #FullPath = $packageFullPath
--
   }
--
}
--
 
--
# Determines whether an Appx package matching the specified
--
# name, version and architecture is installed in the system.
--
#
--
# Parameters:
--
#   -Name........: The package name.
--
#   -Version.....: The package version.
--
#   -Architecture: The package architecture ("x86", "x64").
--
#
--
# Returns:
--
#   $true if the AppX package is installed in the system,
--
#   $false otherwise.
--
function IsAppxPackageInstalled() {
--
   param (
--
       [Parameter(Mandatory=$true)] [string]$name,
--
       [Parameter(Mandatory=$true)] [string]$version,
--
       [Parameter(Mandatory=$true)] [string]$architecture
--
   )
--
 
--
   if ($architecture -match "neutral") {
--
       $architecture = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture
--
   }
--
 
--
   $packages = Get-AppxPackage "$($name)*" -ErrorAction Stop | Where-Object {
--
       $_.Name.ToLower()              -eq $name.ToLower()         -and
--
       $_.Version.ToLower()           -eq $version.ToLower()      -and
--
       "$($_.Architecture)".ToLower() -eq $architecture.ToLower()
--
   }
--
   return ($packages.Count -gt 0)
--
}
--
 
--
<#
--
===========================================================================================
--
|                                                                                         |
--
|                                         Main                                            |
--
|                                                                                         |
--
===========================================================================================
--
#>
--
 
--
[System.Console]::Title = "Automated AppX Package Installer - by Elektro"
--
[CultureInfo]::CurrentUICulture = "en-US"
--
 
--
try { Set-ExecutionPolicy -ExecutionPolicy "Unrestricted" -Scope "Process" } catch { }
--
 
--
# Hides the progress-bar for 'Add-AppxPackage' cmdlet in this script.
--
# Thanks to @Santiago Squarzon for the tip: https://stackoverflow.com/questions/75716867
--
# https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.3#progresspreference
--
$ProgressPreference = "Ignore"
--
 
--
Do {
--
   Clear-Host
--
   Write-Output ""
--
   Write-Output " $($host.ui.RawUI.WindowTitle)"
--
   Write-Output " +=====================================================+"
--
   Write-Output " |                                                     |"
--
   Write-Output " | This script will find any AppX package files        |"
--
   Write-Output " | within the current directory (without recursion),   |"
--
   Write-Output " | print info about the package, print a message       |"
--
   Write-Output " | in case of the package is already installed,        |"
--
   Write-Output " | and install the package in case of it is            |"
--
   Write-Output " | not installed, handling errors during installation. |"
--
   Write-Output " |                                                     |"
--
   Write-Output " +=====================================================+"
--
   Write-Output ""
--
   Write-Host " -Continue? (Y/N)"
--
   $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
--
   $char = $key.Character.ToString().ToUpper()
--
   if ($char -ne "Y" -and $char -ne "N") {
--
       [console]::beep(1500, 500)
--
   }
--
} while ($char -ne "Y" -and $char -ne "N")
--
if ($char -eq "N") {Exit(1)} else {Clear-Host}
--
 
--
$appxFiles = Get-ChildItem -LiteralPath "$PSScriptRoot" -Filter "*.*" -File | Where-Object { $_.Extension -match "appx" -or $_.Extension -match "appxbundle" -or $_.Extension -match "msixbundle"}
--
 
--
if ($appxFiles.Count -eq 0) {
--
   Write-Warning "No Appx files were found in the current directory."
--
   Write-Host ""
--
   $LastExitCode = 2
--
} else {
--
   $appxFiles | ForEach-Object {
--
 
--
       # The AppX package string. It can be a file name (with or without extension), or a full path.
--
       $packageString = $_.FullName
--
       $packageInfo = Get-AppXPackageInfo -PackageString $packageString
--
       $nameVerArch = "$($packageInfo.Name) v$($packageInfo.Version) ($($packageInfo.Architecture))"
--
       Write-Host "Package Info.:" -ForegroundColor Gray
--
       Write-Host ($packageInfo | Format-List | Out-String).Trim() -ForegroundColor DarkGray
--
       Write-Host ""
--
 
--
       $isInstalled = IsAppxPackageInstalled -Name $packageInfo.Name -Version $packageInfo.Version -Architecture $packageInfo.Architecture
--
       if ($isInstalled) {
--
           Write-Warning "Package $nameVerArch is already installed."
--
           Write-Warning "Installation is not required. Ignoring..."
--
       } else {
--
           Write-Host "Package $nameVerArch is ready to install."
--
           Write-Host "Installing package..."
--
           try {
--
               Add-AppxPackage -Path "$($_.FullName)" -ErrorAction Stop
--
               Write-Host "Package $nameVerArch has been successfully installed." -BackgroundColor Black -ForegroundColor Green
--
           } catch {
--
               Write-Host "Error installing package $nameVerArch" -BackgroundColor Black -ForegroundColor Red
--
               Write-Host ""
--
               Write-Error -Message ($_.Exception | Format-List * -Force | Out-String)
--
               $LastExitCode = 1
--
               Break
--
           }
--
       }
--
       Write-Host ""
--
       $LastExitCode = 0
--
   }
--
}
--
 
--
Write-Host "Program will terminate now with exit code $LastExitCode. Press any key to exit..."
--
$key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
--
Exit($LastExitCode)
--


Páginas: (1/1)