├── .gitattributes ├── .gitignore ├── Appx-Backup.ps1 └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | 254 | # ========================= 255 | # Operating System Files 256 | # ========================= 257 | 258 | # OSX 259 | # ========================= 260 | 261 | .DS_Store 262 | .AppleDouble 263 | .LSOverride 264 | 265 | # Thumbnails 266 | ._* 267 | 268 | # Files that might appear in the root of a volume 269 | .DocumentRevisions-V100 270 | .fseventsd 271 | .Spotlight-V100 272 | .TemporaryItems 273 | .Trashes 274 | .VolumeIcon.icns 275 | 276 | # Directories potentially created on remote AFP share 277 | .AppleDB 278 | .AppleDesktop 279 | Network Trash Folder 280 | Temporary Items 281 | .apdisk 282 | 283 | # Windows 284 | # ========================= 285 | 286 | # Windows image file caches 287 | Thumbs.db 288 | ehthumbs.db 289 | 290 | # Folder config file 291 | Desktop.ini 292 | 293 | # Recycle Bin used on file shares 294 | $RECYCLE.BIN/ 295 | 296 | # Windows Installer files 297 | *.cab 298 | *.msi 299 | *.msm 300 | *.msp 301 | 302 | # Windows shortcuts 303 | *.lnk 304 | -------------------------------------------------------------------------------- /Appx-Backup.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | param ( 3 | [Parameter(Mandatory=$True)] 4 | [string] $WSAppPath, 5 | 6 | [Parameter(Mandatory=$True)] 7 | [string] $WSAppOutputPath, 8 | 9 | [Parameter(Mandatory=$True)] 10 | [string] $WSTools 11 | ) 12 | 13 | function Run-Process { 14 | Param ($p, $a) 15 | $pinfo = New-Object System.Diagnostics.ProcessStartInfo 16 | $pinfo.FileName = $p 17 | $pinfo.Arguments = $a 18 | $pinfo.RedirectStandardError = $true 19 | $pinfo.RedirectStandardOutput = $true 20 | $pinfo.UseShellExecute = $false 21 | $p = New-Object System.Diagnostics.Process 22 | $p.StartInfo = $pinfo 23 | $p.Start() | Out-Null 24 | $output = $p.StandardOutput.ReadToEnd() 25 | $output += $p.StandardError.ReadToEnd() 26 | $p.WaitForExit() 27 | return $output 28 | } 29 | 30 | # find tools 31 | $FileExists = Test-Path "$WSTools\MakeAppx.exe" 32 | if ($FileExists -eq $False) { 33 | Write-Output "ERROR: MakeAppx.exe not found in WSTools path." 34 | Exit 35 | } 36 | $FileExists = Test-Path "$WSTools\MakeCert.exe" 37 | if ($FileExists -eq $False) { 38 | Write-Output "ERROR: MakeCert.exe not found in WSTools path." 39 | Exit 40 | } 41 | $FileExists = Test-Path "$WSTools\Pvk2Pfx.exe" 42 | if ($FileExists -eq $False) { 43 | Write-Output "ERROR: Pvk2Pfx.exe not found in WSTools path." 44 | Exit 45 | } 46 | $FileExists = Test-Path "$WSTools\SignTool.exe" 47 | if ($FileExists -eq $False) { 48 | Write-Output "ERROR: SignTool.exe not found in WSTools path." 49 | Exit 50 | } 51 | 52 | $WSAppXmlFile="AppxManifest.xml" 53 | 54 | # read manifest 55 | Write-Output "Reading ""$WSAppPath\$WSAppXmlFile""" 56 | $FileExists = Test-Path "$WSAppPath\$WSAppXmlFile" 57 | if ($FileExists -eq $False) { 58 | Write-Output "ERROR: Windows Store manifest not found." 59 | Exit 60 | } 61 | [xml]$manifest = Get-Content "$WSAppPath\$WSAppXmlFile" 62 | $WSAppName = $manifest.Package.Identity.Name 63 | $WSAppPublisher = $manifest.Package.Identity.Publisher 64 | Write-Output " App Name : $WSAppName" 65 | Write-Output " Publisher: $WSAppPublisher" 66 | 67 | # prepare 68 | $WSAppFileName = gi $WSAppPath | select basename 69 | $WSAppFileName = $WSAppFileName.BaseName 70 | 71 | Write-Output "Creating ""$WSAppOutputPath\$WSAppFileName.appx""." 72 | if (Test-Path "$WSAppOutputPath\$WSAppFileName.appx") { 73 | Remove-Item "$WSAppOutputPath\$WSAppFileName.appx" 74 | } 75 | $proc = "$WSTools\MakeAppx.exe" 76 | $args = "pack /d ""$WSAppPath"" /p ""$WSAppOutputPath\$WSAppFileName.appx"" /l" 77 | $output = Run-Process $proc $args 78 | if ($output -inotlike "*succeeded*") { 79 | Write-Output " ERROR: Appx creation failed!" 80 | Write-Output " proc = $proc" 81 | Write-Output " args = $args" 82 | Write-Output (" " + $output) 83 | Exit 84 | } 85 | Write-Output " Done." 86 | 87 | Write-Output "Creating self-signed certificates." 88 | Write-Output " Click NONE in the 'Create Private Key Passsword' pop-up." 89 | if (Test-Path "$WSAppOutputPath\$WSAppFileName.pvk") { 90 | Remove-Item "$WSAppOutputPath\$WSAppFileName.pvk" 91 | } 92 | if (Test-Path "$WSAppOutputPath\$WSAppFileName.cer") { 93 | Remove-Item "$WSAppOutputPath\$WSAppFileName.cer" 94 | } 95 | $proc = "$WSTools\MakeCert.exe" 96 | $args = "-n ""$WSAppPublisher"" -r -a sha256 -len 2048 -cy end -h 0 -eku 1.3.6.1.5.5.7.3.3 -b 01/01/2000 -sv ""$WSAppOutputPath\$WSAppFileName.pvk"" ""$WSAppOutputPath\$WSAppFileName.cer""" 97 | $output = Run-Process $proc $args 98 | if ($output -inotlike "*succeeded*") { 99 | Write-Output "ERROR: Certificate creation failed!" 100 | Write-Output "proc = $proc" 101 | Write-Output "args = $args" 102 | Write-Output (" " + $output) 103 | Exit 104 | } 105 | Write-Output " Done." 106 | 107 | Write-Output "Converting certificate to pfx." 108 | if (Test-Path "$WSAppOutputPath\$WSAppFileName.pfx") { 109 | Remove-Item "$WSAppOutputPath\$WSAppFileName.pfx" 110 | } 111 | $proc = "$WSTools\Pvk2Pfx.exe" 112 | $args = "-pvk ""$WSAppOutputPath\$WSAppFileName.pvk"" -spc ""$WSAppOutputPath\$WSAppFileName.cer"" -pfx ""$WSAppOutputPath\$WSAppFileName.pfx""" 113 | $output = Run-Process $proc $args 114 | if ($output.Length -gt 0) { 115 | Write-Output " ERROR: Certificate conversion to pfx failed!" 116 | Write-Output " proc = $proc" 117 | Write-Output " args = $args" 118 | Write-Output (" " + $output) 119 | Exit 120 | } 121 | Write-Output " Done." 122 | 123 | Write-Output "Signing the package." 124 | $proc = "$WSTools\SignTool.exe" 125 | $args = "sign -fd SHA256 -a -f ""$WSAppOutputPath\$WSAppFileName.pfx"" ""$WSAppOutputPath\$WSAppFileName.appx""" 126 | $output = Run-Process $proc $args 127 | if ($output -inotlike "*successfully signed*") { 128 | Write-Output "ERROR: Package signing failed!" 129 | Write-Output $output.Length 130 | Write-Output "proc = $proc" 131 | Write-Output "args = $args" 132 | Write-Output (" " + $output) 133 | Exit 134 | } 135 | Write-Output " Done." 136 | 137 | Remove-Item "$WSAppOutputPath\$WSAppFileName.pvk" 138 | Remove-Item "$WSAppOutputPath\$WSAppFileName.pfx" 139 | 140 | Write-Output "Success!" 141 | Write-Output " App Package: ""$WSAppOutputPath\$WSAppFileName.appx""" 142 | Write-Output " Certificate: ""$WSAppOutputPath\$WSAppFileName.cer""" 143 | Write-Output "Install the '.cer' file to [Local Computer\Trusted Root Certification Authorities] before you install the App Package." 144 | Exit 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Appx-Backup 2 | PowerShell script to backup an installed Windows Store App to an installable Appx file. 3 | 4 | This small script allows you to make a backup of installed Windows Store apps. This particularly important if you have installed apps that are no longer available from the Winddows Store. If you ever need to use the Recovery options to Reset your Windows 10 installation, you will not be able to reinstall those apps that are no longer available in the Windows store. An example of this is Disney's Wreck It Ralph. I had to reset one of my PC's and found that even though the game showed up in my Windows Store account, if I tried to install it, Windows Store tells me that it is no longer available. 5 | 6 | Fortunately I had another computer with the game installed and and I found this way to make an installable Appx file and be able to reinstall it manually into the computer that I Reset to Factory. 7 | 8 | You will need to have some tools installed for this to work. These tools are part of Microsoft Visual Studio Community 2015. It's kind of a big download just to be able to do this. If anyone knows of a smaller download, please let me know and I'll update these instructions. Visual Studio installed these tools by default in the 'C:\Program Files (x86)\Windows Kits\10\bin\x86' folder. 9 | 10 | Example Usage (open a Powershell prompt): 11 | ```powershell 12 | PS C:\temp> .\Appx-Backup.ps1 -WSAppPath "C:\Program Files\WindowsApps\Disney.Wreck-itRalph_1.0.0.12_x86__6rarf9sa4v8jt" -WSAppOutputPath "C:\Temp" -WSTools "C:\Program Files (x86)\Windows Kits\10\bin\x86" 13 | Reading "C:\Program Files\WindowsApps\Disney.Wreck-itRalph_1.0.0.12_x86__6rarf9sa4v8jt\AppxManifest.xml" 14 | App Name : Disney.Wreck-itRalph 15 | Publisher: CN=58DECE39-D5D0-4293-AAA0-9AF8484F12E2 16 | Creating "C:\Temp\Disney.Wreck-itRalph_1.0.0.12_x86__6rarf9sa4v8jt.appx". 17 | Done. 18 | Creating self-signed certificates. 19 | Click NONE in the 'Create Private Key Passsword' pop-up. 20 | Done. 21 | Converting certificate to pfx. 22 | Done. 23 | Signing the package. 24 | Done. 25 | Success! 26 | App Package: "C:\Temp\Disney.Wreck-itRalph_1.0.0.12_x86__6rarf9sa4v8jt.appx" 27 | Certificate: "C:\Temp\Disney.Wreck-itRalph_1.0.0.12_x86__6rarf9sa4v8jt.cer" 28 | Install the '.cer' file to [Local Computer\Trusted Root Certification Authorities] before you install the App Package. 29 | PS C:\temp> 30 | ``` 31 | NOTE: Although this can save the installable program, it cannot save anyuser information such as saved games or other user data. And if the app requires network support from the publisher that is also discontinued, then it's not likely that the reinstalled app will work. YMMV. 32 | 33 | Also, this does not sign the app with the publisher's actual key or counter-sign it with the Windows Store key. It signs it with a custom self-signed key. To reinstall your app, you will need first install the *.cer file into your Trusted Root Certificates Store. Just double clicn on the *.cer file and manually add it to the correct store. This requires administrator privileges. Once that is done, you can install the app with the PowerShell command Add-AppxPackage. 34 | 35 | --------------------------------------------------------------------------------