List installed windows Xbox game locations - windows

I want to be able to list the currently installed windows xbox store apps, and at least what hard drive they are installed to, though the installed size would also be helpful.
As an example, I've installed Astroneer to my D:\ drive. I can see the installation location:
# Astroneer folder
D:\WindowsApps\SystemEraSoftworks.29415440E1269_1.21.128.0_x64__ftk5pbg2rayv2\
# Other game package types can install to an MSIXVC file, e.g.
D:\WindowsApps\MSIXVC\130F32F8-4ABB-49E2-9200-3C4FCE2271C8
I can see the appx package, but its InstallLocation points to a junction point within the default appx volume instead:
Get-AppxPackage -Name "SystemEraSoftworks*"
Name : SystemEraSoftworks.29415440E1269
Publisher : CN=115C80E5-07B4-4D9C-8912-5562D4A1828D
Architecture : X64
ResourceId :
Version : 1.21.128.0
PackageFullName : SystemEraSoftworks.29415440E1269_1.21.128.0_x64__ftk5pbg2rayv2
InstallLocation : C:\Program Files\WindowsApps\SystemEraSoftworks.29415440E1269_1.21.128.0_x64__ftk5pbg2rayv2
The appx manifest doesn't contain any information about which drive the app is installed on.
I searched through the registry a bit, but only found references to the C:\ path, or using relative paths like:
Get-ItemProperty 'hklm:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModel\StateRepository\Cache\Activation\Data\18a' -Name 'Executable'
Executable : Astro\Binaries\UWP64\Astro-UWP64-Shipping.exe

I found I could parse the junction points with Get-Item and check the install folders for xbox config files:
# List all windows store packages. May want to include -AllUsers?
Get-AppxPackage |
# Filter out unwanted packages
Where {!$_.IsFramework -and !$_.NonRemovable -and $_.SignatureKind -eq 'Store'} |
Select Name, #{l='InstallLocation';e={
# Return the junction target instead of the local install folder
If ((Get-Item $_.InstallLocation).LinkType -eq 'Junction') {
(Get-Item $_.InstallLocation).Target
}
Else { $_.InstallLocation }
}} |
# Filter to Xbox games
Where { Test-Path "$($_.InstallLocation)\MicrosoftGame.config" }
# Outputs:
Name InstallLocation
---- ---------------
KalypsoMediaGroup.Tropico6Win C:\Program Files\WindowsApps\KalypsoMediaGroup.Tropico6Win_15.3.553.0_x64__e60j8nnj33ga6
WarnerBros.Interactive.e172091a-6630-4ff3-959f-830 F:\WindowsApps\WarnerBros.Interactive.e172091a-6630-4ff3-959f-830_1.279.9438.0_x64__ktmk1xygcecda
SystemEraSoftworks.29415440E1269 D:\WindowsApps\SystemEraSoftworks.29415440E1269_1.21.128.0_x64__ftk5pbg2rayv2
I'm not sure if I can find the package installation sizes anywhere though, although they are listed in the xbox app.

Related

Find with winget.exe all packages and save the package ID and package Name with powershell

I would like to use winget to search for all packages and store them in a text file or a variable. Later on I would like to sort them in a list with "Name" and "ID". Unfortunately it seems like you cannot search just for winget package Names and IDs directly using winget.exe
What I have tried so far:
Clear-Host
if (Test-Path -path "$env:temp\download_winget"){
write-host "Folder exists. Continuing..."
}
else{
write-Host "There is no folder called winget_download!`nCreating..."
mkdir "$env:temp\download_winget"
}
$get_winget_packages = winget search . --accept-source-agreements | Out-File "$env:temp\download_winget\winget_packages.txt" -Encoding utf8
(Yes I know, you can also use winget search """")
My Output: (a sample) (using get-content "$env:temp\download_winget\winget_packages.txt")
Name ID Version Ãœbereinstimmung Quelle
-----------------------------------------------------------------------------------------------------------------------
...
...
...
Windows Package Manager Manifest Creator Microsoft.WingetCreate 1.1.2.0 winget
Remote Desktop Services Infrastructure A… Microsoft.WindowsVirtualDesktopAge… 1.0.5739.9800 winget
Windows Terminal Preview Microsoft.WindowsTerminal.Preview 1.16.3463.0 winget
Windows Admin Center Microsoft.WindowsAdminCenter 1.3.53858.0 winget
Windows Assessment and Deployment Kit Microsoft.WindowsADK 10.1.22621.1 winget
...
...
...
As you can see, I displayed with gc "$env:temp\download_winget\winget_packages.txt" the content of the earlier created file. Unfortunately some of the lines are not displayed correctly. For example:
Remote Desktop Services Infrastructure A… Microsoft.WindowsVirtualDesktopAge… 1.0.5739.9800 winget
I did not find any solution to get all winget packages full Name or full ID using winget search .
Even running this directly in PowerShell or CMD, it will display some package Names and ID not fully. Changing the Encoding to utf32, ascii, utf7 or something else wont change anything too.
Is there a workaround to show the correct/full names of all winget packages Name and ID?
I even tried it with a new powershell process with windowstyle maximized:
Start-Process powershell.exe -ArgumentList ("winget search ." , "| Out-File '$env:temp\download_winget\winget_packages_lol.txt' -Encoding utf8") -WindowStyle Maximized
My Output (a sample):
Name ID Version Ãœbereinstimmung Quelle
-----------------------------------------------------------------------------------------------------------------------
BitRecover Windows Live Mail Converter Wizard BitRecover.WindowsLiveMailConver 7.5 winget
or
Name ID Version Ãœbereinstimmung Quelle
-----------------------------------------------------------------------------------------------------------------------
ECLiPSe Constraint Logic Programming System Version  Coninfer.ECLiPSeCLP.7.0 7.0 #63 winget
My next steps would look like this:
$file = gc "$env:temp\download_winget\winget_packages_lol.txt"
$file | sort | Get-Unique | Set-Content "$env:temp\download_winget\winget_packages_lol.txt"
I would also work here with substrings, but as mentioned earlier this can't work if I can't get the full winget packages Name and ID.
What can I do here?
WinGet releases have started including a Microsoft.WinGet.Client powershell module in the "Assets" section.

How to get Paths to all executables from Get-ChildItem

I am currently trying to get a list of all installed applications and would like to build a feature that can launch those.
I'm using these PowerShell commands:
gci HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\* | % { Get-ItemProperty $_.PsPath } | Select DisplayName,InstallLocation
gci HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\* | % { Get-ItemProperty $_.PsPath } | Select DisplayName,InstallLocation
in conjunction with ConvertTo-Json in order to get a good stdout I can work with.
Now, this only gives me the InstallPath without any executables.
Is there any easy way to get the main executable of the applications i nthe list?
Expected Result (Name of the key does not matter):
// ...
{
"DisplayName": "Microsoft Edge",
"InstallLocation": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application",
"LaunchApplication": "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\msedge.exe",
},
{
"DisplayName": "Audacity 2.4.2",
"InstallLocation": "C:\\Program Files (x86)\\Audacity\\",
"LaunchApplication": "C:\\Program Files (x86)\\Audacity\\audacity.exe"
},
// ...
Like others have pointed out in the comments, there isn't a conventional way of getting the executable paths of certain programs.
To answer your indirect question of building an app launch method, we can make use of a few things. Fortunately for us, PowerShell has a Get-StartApps cmdlet that produces an output of the current users installed apps:
Name AppID
---- -----
3D Viewer Microsoft.Microsoft3DViewer_8wekyb3d8bbwe!Microsoft.Microsoft3DViewer
AdGuard AdGuard
Adobe Acrobat DC {6D809377-6AF0-444B-8957-A3773F02200E}\Adobe\Acrobat DC\Acrobat\Acrobat.exe
Battle.net {7C5A40EF-A0FB-4BFC-874A-C0F2E0B9FA8E}\Battle.net\Battle.net Launcher.exe
Blend for Visual Studio 2022 Blend.d58ce8bb
Calculator Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
Calendar microsoft.windowscommunicationsapps_8wekyb3d8bbwe!microsoft.windowslive.calendar
There are 2 properties that are displayed:
Name
AppID.
This becomes important due to the AppID being the value needed for shell: to execute/launch the program. Given the above output of Get-StartApps, you can launch "Adobe Acrobat DC" by passing the AppID to shell:\AppsFolder\"AppID".
Start-Process shell:AppsFolder\"{6D809377-6AF0-444B-8957-A3773F02200E}\Adobe\Acrobat DC\Acrobat\Acrobat.exe"
Using #zett42's approach, we can query your start menu, along with the system start menu folder paths for .lnk's retrieving its target path using the WScript COM object:
$paths = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs","$env:APPDATA\Microsoft\Windows\Start Menu"
Get-ChildItem -Path $paths -Filter "*.lnk" -File -Recurse |
ForEach-Object -Begin {
$WScriptShell = New-Object -ComObject "WScript.Shell"
} -Process {
[PSCustomObject]#{
Name = $_.BaseName
Path = $WScriptShell.CreateShortcut($_.FullName).TargetPath
}
} -End {
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($WScriptShell) #release COM object
}
which will output:
Name Path
---- ----
Adobe Acrobat DC C:\Program Files\Adobe\Acrobat DC\Acrobat\Acrobat.exe
Blend for Visual Studio 2022 C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\Blend.exe
Firefox C:\Program Files\Mozilla Firefox\firefox.exe
Google Chrome C:\Program Files\Google\Chrome\Application\chrome.exe
Microsoft Edge C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe
TechPowerUp GPU-Z C:\Program Files (x86)\GPU-Z\GPU-Z.exe
Not entirely sure this is what you're after, but it may be of help to others.

How to query and add (if not listed) a location to Windows 10 Search Index using PowerShell

I have to re-mount removable drives (which require authentication) each time I boot the computer and Windows Indexing keeps removing the removable drives (perhaps because the removable drives are not available when the computer boots). In an ideal world Windows Indexing would keep these locations and just list them as 'Unavailable' (which it sometimes does). However because it doesn't I am interested in executing a script that queries the Windows Indexing locations and if it does not list the removable drives then add them. At the bottom of this thread I pasted the Batch script that I setup to run at boot (via Start Up folder) to search for a specific folder that is available thereafter mounting one of the removable drives.
I have found several examples of how to do this on Windows 7 (links pasted below) but I can't figure out how to do it in Windows 10. The links provided to the DLL (Microsoft.Search.Interop.dll) no longer resolve.
When searching for the latest Windows Search SDK for Windows 10 I was lead to the Windows SDK here:
https://learn.microsoft.com/en-us/windows/win32/search/-search-developers-guide-entry-page
I installed the C++ related portion of the Windows SDK then searched for Microsoft.Search.Interop.dll but I couldn't find it. Perhaps the DLL has changed?
From How to rebuild Windows Search Index by using PowerShell?
Load DLL containing classes & interfaces
Add-Type -path "C:\Temp\SearchIndexSdk\Microsoft.Search.Interop.dll"
#Provides methods for controlling the Search service. This
interface manages settings and objects that affect the search engine
across catalogs.
https://msdn.microsoft.com/en-us/library/bb231485(v=vs.85).aspx
$sm = New-Object Microsoft.Search.Interop.CSearchManagerClass
#Retrieves a catalog by name and creates a new ISearchCatalogManager
object for that catalog.
$catalog = $sm.GetCatalog("SystemIndex")
#Resets the underlying catalog by rebuilding the databases and performing a full indexing.
#https://msdn.microsoft.com/en-us/library/bb266414(v=vs.85).aspx
$catalog.Reset()
From How to add a location to windows 7/8 search index using batch or vbscript?
#Code copied from "Powershell Tackles Windows Desktop Search" http://powertoe.wordpress.com/2010/05/17/powershell-tackles-windows-desktop-search/
#Microsoft.Search.Interop.dll is needed, download from http://www.microsoft.com/en-us/download/details.aspx?id=7388
#Load the dll
Add-Type -path "D:\Unattend\UserFiles\Tools\Microsoft.Search.Interop.dll"
#Create an instance of CSearchManagerClass
$sm = New-Object Microsoft.Search.Interop.CSearchManagerClass
#Next we connect to the SystemIndex catalog
$catalog = $sm.GetCatalog("SystemIndex")
#Get the interface to the scope rule manager
$crawlman = $catalog.GetCrawlScopeManager()
#add scope
$crawlman.AddUserScopeRule("file:///D:*",$true,$false,$null)
$crawlman.SaveAll()
I would add a comment to the existing threads but I am not able to because I don't have reputation of 50 (dumb rule IMO).
Last... I found this site which lists the DLL along with some code but it hasn't been updated in a long time.
https://github.com/FileMeta/WindowsSearchSample
Thanks in advance!
Batch script that runs at boot:
#echo off
echo Windows Search is being restarted to recognize the Z drive
:while
if EXIST Z:\Watch (
I WANT TO CALL POWERSHELL SCRIPT TO ADD THE LOCATION TO THE INDEX IF NEEDED HERE
sc stop WMPNetworkSvc
ping 127.0.0.1 -n 5 > nul
sc stop WSearch
ping 127.0.0.1 -n 5 > nul
sc start WSearch
ping 127.0.0.1 -n 5 > nul
sc start WMPNetworkSvc
echo Exiting this script in 5 seconds
ping 127.0.0.1 -n 5 > nul
exit
) else (
echo Waiting 60 seconds to check if Z drive is available
ping 127.0.0.1 -n 60 > nul
goto :while
)
When I do a search for Searchdll in what I believe to be the folder where the Windows SDK installed to (C:\Program Files (x86)\Windows Kits\10) I find the following. If I had to guess which DLL is the Windows 10 equivalent of Windows 7's Microsoft.Search.Interop.dll I would guess that it's the 1st one i.e. interop.searchapi.dll.
Add-Type -Path "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\interop.searchapi.dll" does return without error... however $sm = New-Object Microsoft.Search.Interop.CSearchManagerClass returns with error that it cannot find the class in the assembly.
When I cd to "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64" and enter ([appdomain]::currentdomain.GetAssemblies() | Where-Object Location -Match 'interop.searchapi').gettypes() I get the following
When I enter (([appdomain]::currentdomain.GetAssemblies() | Where-Object location -match 'interop.searchapi.dll').gettypes() | Where-Object name -eq 'CSearchManagerClass').getmembers() | Format-Table name, membertype I get
From the list of commands in the previous threads I do see GetCatalog and I presume that the members GetCrawlScopeManager, AddUserScopeRule, Reset, and SaveAll exist.
I don't know how to find the fully qualified class name or I'm doing something else wrong (unknowingly).
When I enter ([appdomain]::currentdomain.GetAssemblies() | Where-Object Location -Match 'interop.searchapi').fullname I get the following
Interop.SearchAPI, Version=10.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
But when I enter $sm = New-Object Interop.SearchAPI.CSearchManagerClass I get an error that it can't find the type Interop.SearchAPI.CSearchManagerClass.

Change Visual studio build path for Ram disk

Currently I have Visual Studio 17 V 15.4.2
Is it possible to set different build path for projects? for example instead of
C:\Users\[UserName]\source\repos\[MyProject]\[bin|obj]
move it on
M:\Users\[UserName]\source\repos\[MyProject]\[bin|obj]
note that project it self is inside C but temporary files are moved somewhere else. I have drive M which is a 16GB ram disk.
Benefits of using RAM disk:(reasons that is tempting me to do this)
faster build times (no real IO)
SSD doesn't wear out with repetitive rebuilds.
projects are inherently cleaned up (which brings following benefits)
share faster, your projects are not filled with unnecessary files so that you can easily share folders with others. (code size is usually less than 1MB but build objects can go beyond 1GB)
fast backups, for same reason your project folders always remain cleaned up and you can backup project much faster. (especially when you have many projects, eg. you would only backup 100MB istead of 10GB)
less chance of creating locked files. (which cause build desync, errors etc) in that case formatting ramdisk is easier than mucking with VS settings or restarting it.
Drawbacks:
you need much more RAM, in my case I have 32GB which I can spare 16GB for it.
if you reset VS or computer you loose compiled objects and you have to rebuild (once)
but benefits of using RAM disk clearly overweight its drawbacks.
Ok, now that I convinced you reasonably why I want this give me paths :)
Fully working solution for "obj" directory
Create EnviromentVariable BUILD_RAMDRIVE which points to your ramdrive.
Create "Directory.Build.props" file inside your solution dir with this content:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BuildRamdrive>$([System.Environment]::GetEnvironmentVariable("BUILD_RAMDRIVE",System.EnvironmentVariableTarget.Machine))</BuildRamdrive>
</PropertyGroup>
<PropertyGroup Condition=" '$(BuildRamdrive)' != '' AND '$(MSBuildProjectFile)' != ''">
<BaseIntermediateOutputPath>$(BuildRamdrive)\Projects\$(SolutionName)\$(MSBuildProjectFile)\obj\</BaseIntermediateOutputPath>
<IntermediateOutputPath>$(BuildRamdrive)\Projects\$(SolutionName)\$(MSBuildProjectFile)\obj\$(Configuration)\</IntermediateOutputPath>
<MSBuildProjectExtensionsPath>$(BuildRamdrive)\Projects\$(SolutionName)\$(MSBuildProjectFile)\obj\</MSBuildProjectExtensionsPath>
</PropertyGroup>
</Project>
Thats all :-)
This MSBuild scripts takes BUILD_RAMDRIVE environment variable from your computer. Then redirect all obj files of all projects inside this solution to $BUILD_RAMDRIVE\Projects\$(SolutionName)\$(MSBuildProjectFile)\obj\ directory
If your computer has no BUILD_RAMDRIVE environment variable it will do nothing.
It is possible to change the project files (at least for .NET applications) which bin- and obj-path should be used. But you need to change this manually on every project. And if you check in these changes it might cause problems for someone else that is trying to build.
Instead you change the bin- and obj-directories to be a symbolic link to a ramdisk. This will not affect your project and solution files (except that git might treat this links as file so you might want to add these to your .gitignore).
I’ve created two Powershell scripts to manage this. I’m running these in the same directory as the solution file. Be aware that the bin- and obj directories will be removed when you are running these.
This script will remove bin- and obj-folders in all directories where these is a csproj-file and replace them with symbolic links:
$ramDiskDrive = "R:"
# Find all project files...
$projectFiles = Get-ChildItem -Filter *.csproj -Recurse
# Get project directories
$projectDirectories = $projectFiles | ForEach-Object { $_.DirectoryName } | Get-Unique
# Create a bin-directory on the RAM-drive
$projectDirectories | ForEach-Object { New-Item -ItemType Directory -Force -Path "$ramDiskDrive$($_.Substring(2))\bin" }
# Remove existing bin-directories
$projectDirectories | ForEach-Object { Remove-Item "$($_)\bin" -Force -Recurse }
# Link bin-directories to ramdisk
$projectDirectories | ForEach-Object { cmd /c mklink /D "$($_)\bin" "$ramDiskDrive$($_.Substring(2))\bin" }
# Create a obj-directory on the RAM-drive
$projectDirectories | ForEach-Object { New-Item -ItemType Directory -Force -Path "$ramDiskDrive$($_.Substring(2))\obj" }
# Remove existing obj-directories
$projectDirectories | ForEach-Object { Remove-Item "$($_)\obj" -Force -Recurse }
# Link obj-directories to ramdisk
$projectDirectories | ForEach-Object { cmd /c mklink /D "$($_)\obj" "$ramDiskDrive$($_.Substring(2))\obj" }
This script will remove the symbolic links:
# Find all project files...
$projectFiles = Get-ChildItem -Filter *.csproj -Recurse
# Get project directories
$projectDirectories = $projectFiles | ForEach-Object { $_.DirectoryName } | Get-Unique
# Unlink bin-directories to ramdisk
$projectDirectories | ForEach-Object { cmd /c rmdir "$($_)\bin" }
# Unlink obj-directories to ramdisk
$projectDirectories | ForEach-Object { cmd /c rmdir "$($_)\obj" }
If you are running the same script twice you will get error messages, but these could be ignored.
All this said, from my experience there is no major difference to use a RAM-disk instead of an SSD-drive. It is faster but not that much as you might expect.

How to get the Dropbox folder in Powershell in Windows

Same question exists for Python here: How can I get the Dropbox folder location programmatically in Python?, or here for OSX: How to get the location of currently logined Dropbox folder
Same thing in Powershell. I need the path of DropBox to copy files to it (building a software and then copying it to dropbox to share with team).
This Dropbox help page tells us where this info is stored, ie, in a json file in the AppData of the user: https://www.dropbox.com/help/4584
function GetDropBoxPathFromInfoJson
{
$DropboxPath = Get-Content "$ENV:LOCALAPPDATA\Dropbox\info.json" -ErrorAction Stop | ConvertFrom-Json | % 'personal' | % 'path'
return $DropboxPath
}
The line above is taken from: https://www.powershellgallery.com/packages/Spizzi.Profile/1.0.0/Content/Functions%5CProfile%5CInstall-ProfileEnvironment.ps1
Note that it doesn't check if you've got a Dropbox business account, or if you have both. It just uses the personal one.
You can then use this base Dropbox folder to build your final path, for example:
$targetPath = Join-Path -Path (GetDropBoxPathFromInfoJson) -ChildPath 'RootDropboxFolder\Subfolder1\Subfolder2'
if (-not (Test-Path -Path $targetPath)) { throw "Path '$targetPath' not found!" }
--
Alternative way is using the host.db file, as shown on this page:
http://bradinscoe.tumblr.com/post/75819881755/get-dropbox-path-in-powershell
$base64path = gc $env:appdata\Dropbox\host.db | select -index 1 # -index 1 is the 2nd line in the file
$dropboxPath = [System.Text.Encoding]::ASCII.GetString([System.Convert]::FromBase64String($base64path)) # convert from base64 to ascii

Resources