Initial Commit
commit
20104565c3
|
|
@ -0,0 +1,484 @@
|
||||||
|
# This script will install the Microsoft Store into Windows Sandbox
|
||||||
|
# It uses the Windows Update API to fetch the necessary installation files directly from Microsoft
|
||||||
|
# Unlike many similar scripts, it uses NO dependencies or third party APIs
|
||||||
|
|
||||||
|
# Author: ThioJoe
|
||||||
|
# Repo Url: https://github.com/ThioJoe/Windows-Sandbox-Tools
|
||||||
|
|
||||||
|
# --- Configuration ---
|
||||||
|
# Category ID for the Microsoft Store app package
|
||||||
|
$storeCategoryId = "64293252-5926-453c-9494-2d4021f1c78d"
|
||||||
|
|
||||||
|
# Flight Ring - Use "Retail" for the public version.
|
||||||
|
# Note: Values other than retail are not properly set up yet in this script
|
||||||
|
$flightRing = "Retail"
|
||||||
|
|
||||||
|
# Other Known options:
|
||||||
|
# "RP" (ReleasePreview Branch)
|
||||||
|
# "WIS" (Beta Branch)
|
||||||
|
# "WIF" (Dev Branch)
|
||||||
|
# Other Possible Options, Untested:
|
||||||
|
# "Canary"
|
||||||
|
# "MSIT" (Internal)
|
||||||
|
|
||||||
|
|
||||||
|
# --- Define Working Directory ---
|
||||||
|
# Get the path to the user's personal Downloads folder in a reliable way
|
||||||
|
$userDownloadsFolder = (New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path
|
||||||
|
|
||||||
|
# Define the subfolder name for all our files
|
||||||
|
$subfolderName = "MSStore Install"
|
||||||
|
|
||||||
|
# Combine them to create the full working directory path
|
||||||
|
$workingDir = Join-Path -Path $userDownloadsFolder -ChildPath $subfolderName
|
||||||
|
|
||||||
|
# Create the directory if it doesn't exist
|
||||||
|
if (-not (Test-Path -Path $workingDir)) {
|
||||||
|
New-Item -Path $workingDir -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "All files (logs, downloads) will be saved to: '$workingDir'" -ForegroundColor Yellow
|
||||||
|
|
||||||
|
# --- XML Templates ---
|
||||||
|
|
||||||
|
# Step 1: GetCookie request body.
|
||||||
|
# See: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wusp/36a5d99a-a3ca-439d-bcc5-7325ff6b91e2
|
||||||
|
$cookieXmlTemplate = @"
|
||||||
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
|
||||||
|
<s:Header>
|
||||||
|
<a:Action s:mustUnderstand="1">http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetCookie</a:Action>
|
||||||
|
<a:MessageID>urn:uuid:$(New-Guid)</a:MessageID>
|
||||||
|
<a:To s:mustUnderstand="1">https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx</a:To>
|
||||||
|
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
||||||
|
<wuws:WindowsUpdateTicketsToken wsu:id="ClientMSA" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wuws="http://schemas.microsoft.com/msus/2014/10/WindowsUpdateAuthorization">
|
||||||
|
<TicketType Name="MSA" Version="1.0" Policy="MBI_SSL"><user></user></TicketType>
|
||||||
|
</wuws:WindowsUpdateTicketsToken>
|
||||||
|
</o:Security>
|
||||||
|
</s:Header>
|
||||||
|
<s:Body><GetCookie xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService" /></s:Body>
|
||||||
|
</s:Envelope>
|
||||||
|
"@
|
||||||
|
|
||||||
|
# Step 2: SyncUpdates request body. Based on intercepted XML request using Microsoft Store.
|
||||||
|
# Info about attributes found here: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wusp/6b654980-ae63-4b0d-9fae-2abb516af894
|
||||||
|
$fileListXmlTemplate = @"
|
||||||
|
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:s="http://www.w3.org/2003/05/soap-envelope">
|
||||||
|
<s:Header>
|
||||||
|
<a:Action s:mustUnderstand="1">http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/SyncUpdates</a:Action>
|
||||||
|
<a:MessageID>urn:uuid:$(New-Guid)</a:MessageID>
|
||||||
|
<a:To s:mustUnderstand="1">https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx</a:To>
|
||||||
|
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
||||||
|
<Timestamp xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
|
||||||
|
<Created>$((Get-Date).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'"))</Created>
|
||||||
|
<Expires>$((Get-Date).AddMinutes(5).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'"))</Expires>
|
||||||
|
</Timestamp>
|
||||||
|
<wuws:WindowsUpdateTicketsToken wsu:id="ClientMSA" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wuws="http://schemas.microsoft.com/msus/2014/10/WindowsUpdateAuthorization">
|
||||||
|
<TicketType Name="MSA" Version="1.0" Policy="MBI_SSL">
|
||||||
|
<user/>
|
||||||
|
</TicketType>
|
||||||
|
</wuws:WindowsUpdateTicketsToken>
|
||||||
|
</o:Security>
|
||||||
|
</s:Header>
|
||||||
|
<s:Body>
|
||||||
|
<SyncUpdates xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
|
||||||
|
<cookie>
|
||||||
|
<Expiration>$((Get-Date).AddYears(10).ToUniversalTime().ToString('u').Replace(' ','T'))</Expiration>
|
||||||
|
<EncryptedData>{0}</EncryptedData>
|
||||||
|
</cookie>
|
||||||
|
<parameters>
|
||||||
|
<ExpressQuery>false</ExpressQuery>
|
||||||
|
<InstalledNonLeafUpdateIDs>
|
||||||
|
<int>1</int><int>2</int><int>3</int><int>11</int><int>19</int><int>2359974</int><int>5169044</int>
|
||||||
|
<int>8788830</int><int>23110993</int><int>23110994</int><int>54341900</int><int>59830006</int><int>59830007</int>
|
||||||
|
<int>59830008</int><int>60484010</int><int>62450018</int><int>62450019</int><int>62450020</int><int>98959022</int>
|
||||||
|
<int>98959023</int><int>98959024</int><int>98959025</int><int>98959026</int><int>104433538</int><int>129905029</int>
|
||||||
|
<int>130040031</int><int>132387090</int><int>132393049</int><int>133399034</int><int>138537048</int><int>140377312</int>
|
||||||
|
<int>143747671</int><int>158941041</int><int>158941042</int><int>158941043</int><int>158941044</int><int>159123858</int>
|
||||||
|
<int>159130928</int><int>164836897</int><int>164847386</int><int>164848327</int><int>164852241</int><int>164852246</int>
|
||||||
|
<int>164852253</int>
|
||||||
|
</InstalledNonLeafUpdateIDs>
|
||||||
|
<SkipSoftwareSync>false</SkipSoftwareSync>
|
||||||
|
<NeedTwoGroupOutOfScopeUpdates>false</NeedTwoGroupOutOfScopeUpdates>
|
||||||
|
<FilterAppCategoryIds>
|
||||||
|
<CategoryIdentifier>
|
||||||
|
<Id>{1}</Id>
|
||||||
|
</CategoryIdentifier>
|
||||||
|
</FilterAppCategoryIds>
|
||||||
|
<TreatAppCategoryIdsAsInstalled>true</TreatAppCategoryIdsAsInstalled>
|
||||||
|
<AlsoPerformRegularSync>false</AlsoPerformRegularSync>
|
||||||
|
<ComputerSpec/>
|
||||||
|
<ExtendedUpdateInfoParameters>
|
||||||
|
<XmlUpdateFragmentTypes>
|
||||||
|
<XmlUpdateFragmentType>Extended</XmlUpdateFragmentType>
|
||||||
|
</XmlUpdateFragmentTypes>
|
||||||
|
<Locales>
|
||||||
|
<string>en-US</string>
|
||||||
|
<string>en</string>
|
||||||
|
</Locales>
|
||||||
|
</ExtendedUpdateInfoParameters>
|
||||||
|
<ClientPreferredLanguages>
|
||||||
|
<string>en-US</string>
|
||||||
|
</ClientPreferredLanguages>
|
||||||
|
<ProductsParameters>
|
||||||
|
<SyncCurrentVersionOnly>false</SyncCurrentVersionOnly>
|
||||||
|
<DeviceAttributes>E:BranchReadinessLevel=CB&CurrentBranch=rs_prerelease&OEMModel=Virtual%20Machine&FlightRing=Retail&AttrDataVer=321&InstallLanguage=en-US&OSUILocale=en-US&InstallationType=Client&FlightingBranchName=&OSSkuId=48&App=WU_STORE&ProcessorManufacturer=GenuineIntel&OEMName_Uncleaned=Microsoft%20Corporation&AppVer=1407.2503.28012.0&OSArchitecture=AMD64&IsFlightingEnabled=1&TelemetryLevel=1&DefaultUserRegion=39070&WuClientVer=1310.2503.26012.0&OSVersion=10.0.26100.3915&DeviceFamily=Windows.Desktop</DeviceAttributes>
|
||||||
|
<CallerAttributes>Interactive=1;IsSeeker=1;</CallerAttributes>
|
||||||
|
<Products/>
|
||||||
|
</ProductsParameters>
|
||||||
|
</parameters>
|
||||||
|
</SyncUpdates>
|
||||||
|
</s:Body>
|
||||||
|
</s:Envelope>
|
||||||
|
"@
|
||||||
|
|
||||||
|
# Step 3: GetExtendedUpdateInfo2 - After getting the list of matched files (app version and dependencies), this lets us get the actual download URLs
|
||||||
|
# See: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-wusp/2f66a682-164f-47ec-968e-e43c0a85dc21
|
||||||
|
$fileUrlXmlTemplate = @"
|
||||||
|
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
|
||||||
|
<s:Header>
|
||||||
|
<a:Action s:mustUnderstand="1">http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService/GetExtendedUpdateInfo2</a:Action>
|
||||||
|
<a:MessageID>urn:uuid:$(New-Guid)</a:MessageID>
|
||||||
|
<a:To s:mustUnderstand="1">https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured</a:To>
|
||||||
|
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
|
||||||
|
<u:Timestamp u:Id="_0" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
|
||||||
|
<u:Created>$((Get-Date).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'"))</u:Created>
|
||||||
|
<u:Expires>$((Get-Date).AddMinutes(5).ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'"))</u:Expires>
|
||||||
|
</u:Timestamp>
|
||||||
|
<wuws:WindowsUpdateTicketsToken wsu:id="ClientMSA" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wuws="http://schemas.microsoft.com/msus/2014/10/WindowsUpdateAuthorization">
|
||||||
|
<TicketType Name="MSA" Version="1.0" Policy="MBI_SSL"><user>{0}</user></TicketType>
|
||||||
|
</wuws:WindowsUpdateTicketsToken>
|
||||||
|
</o:Security>
|
||||||
|
</s:Header>
|
||||||
|
<s:Body>
|
||||||
|
<GetExtendedUpdateInfo2 xmlns="http://www.microsoft.com/SoftwareDistribution/Server/ClientWebService">
|
||||||
|
<updateIDs><UpdateIdentity><UpdateID>{1}</UpdateID><RevisionNumber>{2}</RevisionNumber></UpdateIdentity></updateIDs>
|
||||||
|
<infoTypes><XmlUpdateFragmentType>FileUrl</XmlUpdateFragmentType></infoTypes>
|
||||||
|
<DeviceAttributes>E:BranchReadinessLevel=CB&CurrentBranch=rs_prerelease&OEMModel=Virtual%20Machine&FlightRing={3}&AttrDataVer=321&InstallLanguage=en-US&OSUILocale=en-US&InstallationType=Client&FlightingBranchName=&OSSkuId=48&App=WU_STORE&ProcessorManufacturer=GenuineIntel&OEMName_Uncleaned=Microsoft%20Corporation&AppVer=1407.2503.28012.0&OSArchitecture=AMD64&IsFlightingEnabled=1&TelemetryLevel=1&DefaultUserRegion=39070&WuClientVer=1310.2503.26012.0&OSVersion=10.0.26100.3915&DeviceFamily=Windows.Desktop</DeviceAttributes>
|
||||||
|
</GetExtendedUpdateInfo2>
|
||||||
|
</s:Body>
|
||||||
|
</s:Envelope>
|
||||||
|
"@
|
||||||
|
|
||||||
|
# --- Script Execution ---
|
||||||
|
$headers = @{ "Content-Type" = "application/soap+xml; charset=utf-8" }
|
||||||
|
$baseUri = "https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx"
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Step 1: Get Cookie
|
||||||
|
Write-Host "Step 1: Getting authentication cookie..."
|
||||||
|
$cookieRequestPayload = $cookieXmlTemplate
|
||||||
|
#$cookieRequestPayload | Set-Content -Path (Join-Path $LogDirectory "01_Step1_Request.xml")
|
||||||
|
|
||||||
|
$cookieResponse = Invoke-WebRequest -Uri $baseUri -Method Post -Body $cookieRequestPayload -Headers $headers -UseBasicParsing
|
||||||
|
#$cookieResponse.Content | Set-Content -Path (Join-Path $LogDirectory "01_Step1_Response.xml")
|
||||||
|
Write-Host " -> Saved request and response logs for Step 1."
|
||||||
|
|
||||||
|
$cookieResponseXml = [xml]$cookieResponse.Content
|
||||||
|
$encryptedCookieData = $cookieResponseXml.Envelope.Body.GetCookieResponse.GetCookieResult.EncryptedData
|
||||||
|
Write-Host "Success. Cookie received." -ForegroundColor Green
|
||||||
|
|
||||||
|
# Step 2: Get File List
|
||||||
|
Write-Host "Step 2: Getting file list..."
|
||||||
|
$fileListRequestPayload = $fileListXmlTemplate -f $encryptedCookieData, $storeCategoryId, $flightRing
|
||||||
|
$tempRequestFile = Join-Path $workingDir "02_Step2_Request_AUTOMATED.xml"
|
||||||
|
[System.IO.File]::WriteAllText($tempRequestFile, $fileListRequestPayload, [System.Text.UTF8Encoding]::new($false))
|
||||||
|
|
||||||
|
$fileListResponse = Invoke-WebRequest -Uri $baseUri -Method Post -InFile $tempRequestFile -Headers $headers -UseBasicParsing
|
||||||
|
#$fileListResponse.Content | Set-Content -Path (Join-Path $LogDirectory "02_Step2_Response_SUCCESS.xml")
|
||||||
|
Write-Host " -> Saved request and response logs for Step 2."
|
||||||
|
|
||||||
|
# The response contains XML fragments that are HTML-encoded. We must decode this before treating it as XML.
|
||||||
|
Add-Type -AssemblyName System.Web
|
||||||
|
$decodedContent = [System.Web.HttpUtility]::HtmlDecode($fileListResponse.Content)
|
||||||
|
$fileListResponseXml = [xml]$decodedContent
|
||||||
|
Write-Host "Successfully received and DECODED Step 2 response." -ForegroundColor Green
|
||||||
|
|
||||||
|
$fileIdentityMap = @{}
|
||||||
|
|
||||||
|
# Get the two main lists of updates from the now correctly-decoded response
|
||||||
|
$newUpdates = $fileListResponseXml.Envelope.Body.SyncUpdatesResponse.SyncUpdatesResult.NewUpdates.UpdateInfo
|
||||||
|
$allExtendedUpdates = $fileListResponseXml.Envelope.Body.SyncUpdatesResponse.SyncUpdatesResult.ExtendedUpdateInfo.Updates.Update
|
||||||
|
|
||||||
|
Write-Host "--- Correlating Update Information ---" -ForegroundColor Magenta
|
||||||
|
|
||||||
|
# Filter the 'NewUpdates' list to only include items that are actual downloadable files.
|
||||||
|
# These are identified by the presence of the <SecuredFragment> tag inside their inner XML.
|
||||||
|
$downloadableUpdates = $newUpdates | Where-Object { $_.Xml.Properties.SecuredFragment }
|
||||||
|
|
||||||
|
Write-Host "Found $($downloadableUpdates.Count) potentially downloadable packages." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Now, process each downloadable update
|
||||||
|
foreach ($update in $downloadableUpdates) {
|
||||||
|
$lookupId = $update.ID
|
||||||
|
|
||||||
|
# Find the matching entry in the 'ExtendedUpdateInfo' list using the same numeric ID.
|
||||||
|
$extendedInfo = $allExtendedUpdates | Where-Object { $_.ID -eq $lookupId } | Select-Object -First 1
|
||||||
|
|
||||||
|
if (-not $extendedInfo) {
|
||||||
|
Write-Warning "Could not find matching ExtendedInfo for downloadable update ID $lookupId. Skipping."
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# From the extended info, get the actual package file and ignore the metadata .cab files.
|
||||||
|
$fileNode = $extendedInfo.Xml.Files.File | Where-Object { $_.FileName -and $_.FileName -notlike "Abm_*" } | Select-Object -First 1
|
||||||
|
|
||||||
|
if (-not $fileNode) {
|
||||||
|
Write-Warning "Found matching ExtendedInfo for ID $lookupId, but it contains no valid file node. Skipping."
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# Additional parsing
|
||||||
|
$fileName = $fileNode.FileName
|
||||||
|
$updateGuid = $update.Xml.UpdateIdentity.UpdateID
|
||||||
|
$revNum = $update.Xml.UpdateIdentity.RevisionNumber
|
||||||
|
$fullIdentifier = $fileNode.GetAttribute("InstallerSpecificIdentifier")
|
||||||
|
|
||||||
|
# Define the regex based on the official package identity structure.
|
||||||
|
# <Name>_<Version>_<Architecture>_<ResourceId>_<PublisherId>
|
||||||
|
$regex = "^(?<Name>.+?)_(?<Version>\d+\.\d+\.\d+\.\d+)_(?<Architecture>[a-zA-Z0-9]+)_(?<ResourceId>.*?)_(?<PublisherId>[a-hjkmnp-tv-z0-9]{13})$"
|
||||||
|
|
||||||
|
$packageInfo = [PSCustomObject]@{
|
||||||
|
FullName = $fullIdentifier
|
||||||
|
FileName = $fileName
|
||||||
|
UpdateID = $updateGuid
|
||||||
|
RevisionNumber = $revNum
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fullIdentifier -match $regex) {
|
||||||
|
# If the regex matches, populate the object with the named capture groups
|
||||||
|
$packageInfo | Add-Member -MemberType NoteProperty -Name "PackageName" -Value $matches.Name
|
||||||
|
$packageInfo | Add-Member -MemberType NoteProperty -Name "Version" -Value $matches.Version
|
||||||
|
$packageInfo | Add-Member -MemberType NoteProperty -Name "Architecture" -Value $matches.Architecture
|
||||||
|
$packageInfo | Add-Member -MemberType NoteProperty -Name "ResourceId" -Value $matches.ResourceId
|
||||||
|
$packageInfo | Add-Member -MemberType NoteProperty -Name "PublisherId" -Value $matches.PublisherId
|
||||||
|
} else {
|
||||||
|
# Fallback for any identifiers that don't match the pattern
|
||||||
|
$packageInfo | Add-Member -MemberType NoteProperty -Name "PackageName" -Value "Unknown (Parsing Failed)"
|
||||||
|
$packageInfo | Add-Member -MemberType NoteProperty -Name "Architecture" -Value "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Use the full, unique identifier as the key in the map
|
||||||
|
$fileIdentityMap[$fullIdentifier] = $packageInfo
|
||||||
|
|
||||||
|
Write-Host " -> CORRELATED: '$($packageInfo.PackageName)' ($($packageInfo.Architecture))" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "--- Correlation Complete ---" -ForegroundColor Magenta
|
||||||
|
Write-Host "Found and prepared $($fileIdentityMap.Count) downloadable files." -ForegroundColor Green
|
||||||
|
|
||||||
|
|
||||||
|
# --- Step 3: Filter, Get URLs, and Download ---
|
||||||
|
try {
|
||||||
|
# Get the current system's processor architecture and map it to the script's naming convention
|
||||||
|
$systemArch = switch ($env:PROCESSOR_ARCHITECTURE) {
|
||||||
|
"AMD64" { "x64" }
|
||||||
|
"ARM64" { "arm64" }
|
||||||
|
"x86" { "x86" }
|
||||||
|
default { "unknown" }
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($systemArch -eq "unknown") {
|
||||||
|
throw "Could not determine system architecture from '$($env:PROCESSOR_ARCHITECTURE)'."
|
||||||
|
}
|
||||||
|
Write-Host "Step 3: Filtering packages for your system architecture ('$systemArch')..." -ForegroundColor Magenta
|
||||||
|
|
||||||
|
# --- Filter the packages ---
|
||||||
|
|
||||||
|
# 1. Isolate the Microsoft.WindowsStore packages and find the latest version
|
||||||
|
$latestStorePackage = $fileIdentityMap.Values |
|
||||||
|
Where-Object { $_.PackageName -eq 'Microsoft.WindowsStore' } |
|
||||||
|
Sort-Object { [version]$_.Version } -Descending |
|
||||||
|
Select-Object -First 1
|
||||||
|
|
||||||
|
# 2. Get all other dependencies that match the system architecture (or are neutral)
|
||||||
|
$filteredDependencies = $fileIdentityMap.Values |
|
||||||
|
Where-Object {
|
||||||
|
($_.PackageName -ne 'Microsoft.WindowsStore') -and
|
||||||
|
( ($_.Architecture -eq $systemArch) -or ($_.Architecture -eq 'neutral') )
|
||||||
|
}
|
||||||
|
|
||||||
|
# 3. Combine the lists for the final download queue
|
||||||
|
$packagesToDownload = @()
|
||||||
|
if ($latestStorePackage) {
|
||||||
|
$packagesToDownload += $latestStorePackage
|
||||||
|
Write-Host " -> Found latest Store package: $($latestStorePackage.FullName)" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Warning "Could not find any Microsoft.WindowsStore package."
|
||||||
|
}
|
||||||
|
|
||||||
|
$packagesToDownload += $filteredDependencies
|
||||||
|
Write-Host " -> Found $($filteredDependencies.Count) dependencies for '$systemArch' architecture." -ForegroundColor Green
|
||||||
|
Write-Host "Total files to download: $($packagesToDownload.Count)" -ForegroundColor Cyan
|
||||||
|
Write-Host "------------------------------------------------------------"
|
||||||
|
|
||||||
|
|
||||||
|
# --- Loop through the filtered list, get URLs, and download ---
|
||||||
|
Write-Host "Step 4: Fetching URLs and downloading files..." -ForegroundColor Magenta
|
||||||
|
|
||||||
|
$originalPref = $ProgressPreference
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
|
||||||
|
foreach ($package in $packagesToDownload) {
|
||||||
|
Write-Host "Processing: $($package.FullName)"
|
||||||
|
|
||||||
|
# Get the download URL for this specific package
|
||||||
|
$fileUrlRequestPayload = $fileUrlXmlTemplate -f $encryptedCookieData, $package.UpdateID, $package.RevisionNumber, $flightRing
|
||||||
|
$fileUrlResponse = Invoke-WebRequest -Uri "$baseUri/secured" -Method Post -Body $fileUrlRequestPayload -Headers $headers -UseBasicParsing
|
||||||
|
$fileUrlResponseXml = [xml]$fileUrlResponse.Content
|
||||||
|
|
||||||
|
$fileLocations = $fileUrlResponseXml.Envelope.Body.GetExtendedUpdateInfo2Response.GetExtendedUpdateInfo2Result.FileLocations.FileLocation
|
||||||
|
$baseFileName = [System.IO.Path]::GetFileNameWithoutExtension($package.FileName)
|
||||||
|
$downloadUrl = ($fileLocations | Where-Object { $_.Url -like "*$baseFileName*" }).Url
|
||||||
|
|
||||||
|
if (-not $downloadUrl) {
|
||||||
|
Write-Warning " -> Could not retrieve download URL for $($package.FileName). Skipping."
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download the file
|
||||||
|
# Construct a more descriptive filename using the package's full name and its original extension
|
||||||
|
$fileExtension = [System.IO.Path]::GetExtension($package.FileName)
|
||||||
|
$newFileName = "$($package.FullName)$($fileExtension)"
|
||||||
|
$filePath = Join-Path $workingDir $newFileName
|
||||||
|
|
||||||
|
Write-Host " -> Downloading from: $downloadUrl" -ForegroundColor Gray
|
||||||
|
Write-Host " -> Saving to: $filePath"
|
||||||
|
|
||||||
|
try {
|
||||||
|
Invoke-WebRequest -Uri $downloadUrl -OutFile $filePath -UseBasicParsing
|
||||||
|
Write-Host " -> SUCCESS: Download complete." -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Error " -> FAILED to download $($newFileName). Error: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
$ProgressPreference = $originalPref
|
||||||
|
|
||||||
|
Write-Host "------------------------------------------------------------"
|
||||||
|
Write-Host "Process complete. All files are in the '$downloadDir' folder." -ForegroundColor Green
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Host "An error occurred during the filtering or downloading phase:" -ForegroundColor Red
|
||||||
|
Write-Host $_.Exception.ToString()
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Step 5: Install Downloaded Packages ---
|
||||||
|
Write-Host "------------------------------------------------------------"
|
||||||
|
Write-Host "Step 5: Installing packages..." -ForegroundColor Magenta
|
||||||
|
Write-Host "This step requires Administrator privileges."
|
||||||
|
|
||||||
|
# 1. Check for Administrator rights
|
||||||
|
if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||||
|
Write-Error "Installation failed. Please re-run the script with 'Run as Administrator'."
|
||||||
|
# Add a pause so the user can see the message before the window closes.
|
||||||
|
Read-Host "Press Enter to exit"
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
# 2. Define the installation order for dependencies based on their base names
|
||||||
|
# The order here is critical for dependencies.
|
||||||
|
$dependencyInstallOrder = @(
|
||||||
|
'Microsoft.VCLibs',
|
||||||
|
'Microsoft.NET.Native.Framework',
|
||||||
|
'Microsoft.NET.Native.Runtime',
|
||||||
|
'Microsoft.UI.Xaml'
|
||||||
|
)
|
||||||
|
|
||||||
|
# 3. Get all downloaded package files and separate the main app from dependencies
|
||||||
|
try {
|
||||||
|
$allDownloadedFiles = Get-ChildItem -Path $workingDir -File | Where-Object { $_.Extension -in '.appx', '.msix', '.appxbundle', '.msixbundle' }
|
||||||
|
|
||||||
|
$storePackageFile = $allDownloadedFiles | Where-Object { $_.Name -like 'Microsoft.WindowsStore*' } | Select-Object -First 1
|
||||||
|
$dependencyFiles = $allDownloadedFiles | Where-Object { $_.Name -notlike 'Microsoft.WindowsStore*' }
|
||||||
|
|
||||||
|
if (-not $dependencyFiles -and -not $storePackageFile) {
|
||||||
|
Write-Warning "No package files found in '$downloadDir' to install."
|
||||||
|
return # Exits this part of the script gracefully
|
||||||
|
}
|
||||||
|
|
||||||
|
# 4. Install dependencies in the correct, predefined order
|
||||||
|
Write-Host "Installing dependencies..."
|
||||||
|
foreach ($baseName in $dependencyInstallOrder) {
|
||||||
|
# Find all packages that start with the current base name (e.g., 'Microsoft.VCLibs*')
|
||||||
|
# Sorting by name ensures a consistent order if multiple versions exist
|
||||||
|
$packagesInGroup = $dependencyFiles | Where-Object { $_.Name -like "$baseName*" } | Sort-Object Name
|
||||||
|
|
||||||
|
foreach ($package in $packagesInGroup) {
|
||||||
|
Write-Host " -> Installing $($package.Name)"
|
||||||
|
try {
|
||||||
|
Add-AppxPackage -Path $package.FullName
|
||||||
|
Write-Host " SUCCESS." -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Error " FAILED to install $($package.Name). Error: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# 5. Install the main Microsoft Store package last
|
||||||
|
if ($storePackageFile) {
|
||||||
|
Write-Host "Installing the main application..."
|
||||||
|
Write-Host " -> Installing $($storePackageFile.Name)"
|
||||||
|
try {
|
||||||
|
Add-AppxPackage -Path $storePackageFile.FullName
|
||||||
|
Write-Host " SUCCESS: Microsoft Store has been installed/updated." -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Error " FAILED to install $($storePackageFile.Name). Error: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Warning "Microsoft Store package was not found in the download folder."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "------------------------------------------------------------"
|
||||||
|
Write-Host "Installation process finished." -ForegroundColor Cyan
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Error "A critical error occurred during the installation phase: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Set Region to US so the store will work. Default 'World' region does not work. ---
|
||||||
|
try {
|
||||||
|
# Define the path to the registry key
|
||||||
|
$geoKeyPath = "HKCU:\Control Panel\International\Geo"
|
||||||
|
|
||||||
|
# Check if the 'Geo' key exists. If not, create it.
|
||||||
|
# The -Force switch ensures that parent keys ('International') are also created if they are missing.
|
||||||
|
if (-not (Test-Path $geoKeyPath)) {
|
||||||
|
Write-Host " -> Registry key not found. Creating: $geoKeyPath"
|
||||||
|
New-Item -Path $geoKeyPath -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the 'Nation' value. This is equivalent to: reg add ... /v Nation ...
|
||||||
|
Set-ItemProperty -Path $geoKeyPath -Name "Nation" -Value "244"
|
||||||
|
Write-Host " -> Set 'Nation' value to '244'."
|
||||||
|
|
||||||
|
# Set the 'Name' value. This is equivalent to: reg add ... /v Name ...
|
||||||
|
Set-ItemProperty -Path $geoKeyPath -Name "Name" -Value "US"
|
||||||
|
Write-Host " -> Set 'Name' value to 'US'."
|
||||||
|
|
||||||
|
Write-Host " -> Registry configuration complete." -ForegroundColor Green
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "FAILED to configure registry settings. Error: $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Host "An error occurred:" -ForegroundColor Red
|
||||||
|
if ($_.Exception.Response) {
|
||||||
|
$statusCode = $_.Exception.Response.StatusCode.value__
|
||||||
|
$statusDescription = $_.Exception.Response.StatusDescription
|
||||||
|
$errorLogPath = Join-Path $LogDirectory "ERROR_Response.txt"
|
||||||
|
try {
|
||||||
|
$stream = $_.Exception.Response.GetResponseStream()
|
||||||
|
$reader = New-Object System.IO.StreamReader($stream)
|
||||||
|
$responseBody = $reader.ReadToEnd()
|
||||||
|
#$responseBody | Set-Content -Path $errorLogPath
|
||||||
|
} catch { "Could not read error response body." | Set-Content -Path $errorLogPath }
|
||||||
|
Write-Host "Status Code: $statusCode"
|
||||||
|
Write-Host "Status Description: $statusDescription"
|
||||||
|
Write-Host "Server Response saved to '$errorLogPath'"
|
||||||
|
} else {
|
||||||
|
Write-Host $_.Exception.ToString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
# This script will install Winget from within the Windows Sandbox
|
||||||
|
# It fetches the necessary files and dependencies from Microsoft's winget-cli, and installs them
|
||||||
|
|
||||||
|
# Author: ThioJoe
|
||||||
|
# Repo Url: https://github.com/ThioJoe/Windows-Sandbox-Tools
|
||||||
|
|
||||||
|
|
||||||
|
param(
|
||||||
|
[switch]$removeMsStoreAsSource = $false # If switch is included, it will remove the 'msstore' source after installing winget, which doesn't work with Sandbox, unless the Microsoft Store is also installed
|
||||||
|
)
|
||||||
|
|
||||||
|
function Get-LatestRelease {
|
||||||
|
param(
|
||||||
|
[string]$repoOwner = 'microsoft',
|
||||||
|
[string]$repoName = 'winget-cli'
|
||||||
|
)
|
||||||
|
try {
|
||||||
|
$releasesUrl = "https://api.github.com/repos/$repoOwner/$repoName/releases"
|
||||||
|
$releases = Invoke-RestMethod -Uri $releasesUrl -UseBasicParsing
|
||||||
|
} catch {
|
||||||
|
Write-Error "Failed to fetch releases from GitHub API: $($_.Exception.Message)"
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $releases) { Write-Error "No releases found for $repoOwner/$repoName."; return $null; }
|
||||||
|
|
||||||
|
# Pick the top entry once sorted by published_at descending
|
||||||
|
$latestRelease = $releases | Sort-Object -Property published_at -Descending | Select-Object -First 1
|
||||||
|
return $latestRelease
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-AssetUrl {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
$release,
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$assetName
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($release.assets -and $release.assets.Count -gt 0) {
|
||||||
|
$asset = $release.assets | Where-Object { $_.name -eq $assetName }
|
||||||
|
if ($asset) {
|
||||||
|
return $asset.browser_download_url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Install-WingetDependencies {
|
||||||
|
param([string]$depsFolder)
|
||||||
|
|
||||||
|
# Look for DesktopAppInstaller_Dependencies.json to determine explicit install order
|
||||||
|
$jsonFile = Join-Path $depsFolder "DesktopAppInstaller_Dependencies.json"
|
||||||
|
if (Test-Path $jsonFile) {
|
||||||
|
Write-Host "Installing dependencies based on DesktopAppInstaller_Dependencies.json"
|
||||||
|
$jsonContent = Get-Content $jsonFile -Raw | ConvertFrom-Json
|
||||||
|
$dependencies = $jsonContent.Dependencies
|
||||||
|
|
||||||
|
foreach ($dep in $dependencies) {
|
||||||
|
# For example: "Microsoft.VCLibs.140.00.UWPDesktop" + "14.0.33728.0"
|
||||||
|
$matchingFiles = Get-ChildItem -Path $depsFolder -Filter *.appx -Recurse |
|
||||||
|
Where-Object { $_.Name -like "*$($dep.Name)*" -and $_.Name -like "*$($dep.Version)*" }
|
||||||
|
|
||||||
|
foreach ($file in $matchingFiles) {
|
||||||
|
Write-Host "Installing dependency: $($file.Name)"
|
||||||
|
Add-AppxPackage -Path $file.FullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# If the JSON doesn't exist, install all .appx in the folder
|
||||||
|
Write-Warning "No DesktopAppInstaller_Dependencies.json found, installing all .appx in $depsFolder"
|
||||||
|
foreach ($appxFile in Get-ChildItem $depsFolder -Filter *.appx -Recurse) {
|
||||||
|
Write-Host "Installing: $($appxFile.Name)"
|
||||||
|
Add-AppxPackage -Path $appxFile.FullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prevents progress bar from showing (often speeds downloads)
|
||||||
|
$ProgressPreference = 'SilentlyContinue'
|
||||||
|
|
||||||
|
$downloadPath = Join-Path $env:USERPROFILE "Downloads"
|
||||||
|
$latestRelease = Get-LatestRelease
|
||||||
|
if (-not $latestRelease) { Write-Error "Could not retrieve the latest release. Exiting."; return; }
|
||||||
|
|
||||||
|
$latestTag = $latestRelease.tag_name
|
||||||
|
Write-Host "Latest winget version tag is: $latestTag"
|
||||||
|
|
||||||
|
# Download the MSIX bundle
|
||||||
|
$msixName = "Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
|
||||||
|
$msixUrl = Get-AssetUrl -release $latestRelease -assetName $msixName
|
||||||
|
if (-not $msixUrl) { Write-Error "Could not find $msixName in the latest release assets."; return; }
|
||||||
|
|
||||||
|
Write-Host "Downloading $msixName..."
|
||||||
|
$msixPath = Join-Path $downloadPath $msixName
|
||||||
|
Invoke-WebRequest -Uri $msixUrl -OutFile $msixPath
|
||||||
|
|
||||||
|
# Figure out the OS architecture using environment variable
|
||||||
|
$procArch = $env:PROCESSOR_ARCHITECTURE
|
||||||
|
switch -Wildcard ($procArch) {
|
||||||
|
"AMD64" { $arch = "x64" }
|
||||||
|
"x86" { $arch = "x86" }
|
||||||
|
"*ARM64*" { $arch = "arm64" }
|
||||||
|
"*ARM*" { $arch = "arm" }
|
||||||
|
default {
|
||||||
|
$arch = "x64"
|
||||||
|
Write-Warning "Unrecognized architecture: $procArch. Defaulting to x64."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download the dependencies zip
|
||||||
|
$depsZipName = "DesktopAppInstaller_Dependencies.zip"
|
||||||
|
$depsZipUrl = Get-AssetUrl -release $latestRelease -assetName $depsZipName
|
||||||
|
|
||||||
|
# We'll expand to a base 'Dependencies' folder
|
||||||
|
$topDepsFolder = Join-Path $downloadPath "Dependencies"
|
||||||
|
# Then pick the sub-folder for the architecture
|
||||||
|
$depsFolder = Join-Path $topDepsFolder $arch
|
||||||
|
|
||||||
|
if ($depsZipUrl) {
|
||||||
|
Write-Host "Downloading $depsZipName..."
|
||||||
|
$depsZipPath = Join-Path $downloadPath $depsZipName
|
||||||
|
Invoke-WebRequest -Uri $depsZipUrl -OutFile $depsZipPath
|
||||||
|
|
||||||
|
# Remove existing Dependencies folder and expand the zip
|
||||||
|
if (Test-Path $topDepsFolder) { Remove-Item -Path $topDepsFolder -Recurse -Force }
|
||||||
|
|
||||||
|
Expand-Archive -LiteralPath $depsZipPath -DestinationPath $topDepsFolder -Force
|
||||||
|
}
|
||||||
|
else { Write-Warning "No $depsZipName found in $latestTag, skipping dependency download."; }
|
||||||
|
|
||||||
|
# Restore progress preference
|
||||||
|
$ProgressPreference = 'Continue'
|
||||||
|
|
||||||
|
# If dependencies exist for this architecture, install them
|
||||||
|
if (Test-Path $depsFolder) {
|
||||||
|
Install-WingetDependencies -depsFolder $depsFolder
|
||||||
|
} else {
|
||||||
|
Write-Warning "No architecture-specific dependencies found at $depsFolder"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Finally, install the winget MSIX bundle
|
||||||
|
Write-Host "Installing $msixName..."
|
||||||
|
Add-AppxPackage -Path $msixPath
|
||||||
|
|
||||||
|
# Remove msstore source if set to do so
|
||||||
|
if ($removeMsStoreAsSource.IsPresent) {
|
||||||
|
Write-Host "Attempting to remove 'msstore' source from winget..."
|
||||||
|
try {
|
||||||
|
winget source remove -n msstore --ignore-warnings
|
||||||
|
} catch {
|
||||||
|
Write-Warning "An error occurred while trying to execute 'winget source remove msstore': $($_.Exception.Message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 ThioJoe
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
# Windows-Sandbox-Tools
|
||||||
|
Various useful scripts for use within Windows Sandbox
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
<Configuration>
|
||||||
|
|
||||||
|
<!-- Docs say this may affect ability to copy and paste, but that still seems to work -->
|
||||||
|
<ProtectedClient>Enable</ProtectedClient>
|
||||||
|
|
||||||
|
<Networking>Enable</Networking>
|
||||||
|
<MemoryInMB>12288</MemoryInMB> <!-- Adjust allocated memory as desired. Default is only 4GB -->
|
||||||
|
|
||||||
|
<!-- Options for improved security -->
|
||||||
|
<VideoInput>Disable</VideoInput>
|
||||||
|
<AudioInput>Disable</AudioInput>
|
||||||
|
<PrinterRedirection>Disabled</PrinterRedirection>
|
||||||
|
<vGPU>Disable</vGPU>
|
||||||
|
|
||||||
|
<!-- Enables or disables sharing of the host clipboard with the sandbox. (Disable / Default) -->
|
||||||
|
<ClipboardRedirection>Enable</ClipboardRedirection>
|
||||||
|
|
||||||
|
<!-- Allow read only access to folder on host -->
|
||||||
|
<MappedFolders>
|
||||||
|
<!-- Create a read-only folder mapped to a folder on host -->
|
||||||
|
<MappedFolder>
|
||||||
|
<!-- Update the HostFolder path to the one on your real computer that will be shared with the Sandbox -->
|
||||||
|
<HostFolder>B:\Caches\Sandbox_Share</HostFolder>
|
||||||
|
<SandboxFolder>C:\Users\WDAGUtilityAccount\Desktop\HostShared</SandboxFolder>
|
||||||
|
<ReadOnly>true</ReadOnly>
|
||||||
|
</MappedFolder>
|
||||||
|
</MappedFolders>
|
||||||
|
|
||||||
|
<!-- Run the powershell script from the mapped folder -->
|
||||||
|
<LogonCommand>
|
||||||
|
<Command>powershell -executionpolicy Bypass -command "start powershell {-file C:\Users\WDAGUtilityAccount\Desktop\HostShared\SandboxStartup.ps1}"</Command>
|
||||||
|
<!-- Use this one below instead if you want the powershell window to not close after running the script -->
|
||||||
|
<!-- <Command>powershell -executionpolicy Bypass -command "start powershell {-noexit -file C:\Users\WDAGUtilityAccount\HostShared\SandboxStartup.ps1}"</Command> -->
|
||||||
|
</LogonCommand>
|
||||||
|
|
||||||
|
</Configuration>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Other Settings Examples
|
||||||
|
See: https://learn.microsoft.com/en-us/windows/security/application-security/application-isolation/windows-sandbox/windows-sandbox-configure-using-wsb-file
|
||||||
|
Anything outside <configuration> tags don't apply
|
||||||
|
|
||||||
|
More secure but no clipboard sharing
|
||||||
|
<ProtectedClient>Disable</ProtectedClient>
|
||||||
|
-->
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
<Configuration>
|
||||||
|
|
||||||
|
<Networking>Enable</Networking>
|
||||||
|
|
||||||
|
<LogonCommand>
|
||||||
|
<Command>netsh interface ipv4 set dnsservers "Ethernet" static 8.8.8.8 primary</Command>
|
||||||
|
</LogonCommand>
|
||||||
|
|
||||||
|
</Configuration>
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
# Change context menu to old style
|
||||||
|
reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve
|
||||||
|
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "Start_ShowClassicMode" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
# Show file extensions
|
||||||
|
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "HideFileExt" /t REG_DWORD /d 0 /f
|
||||||
|
|
||||||
|
# Show hidden files
|
||||||
|
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced" /v "Hidden" /t REG_DWORD /d 1 /f
|
||||||
|
|
||||||
|
# ---- Add 'Edit With Notepad' and 'Open Notepad' to context menu -------
|
||||||
|
# Set the path to your specific Notepad executable which you'll put in the shared folder, since notepad isn't included in the sandbox for some reason
|
||||||
|
# Go to C:\Windows on your main computer and copy Notepad.exe, then copy notepad.exe.mui from your main language folder, such as C:\Windows\en-US
|
||||||
|
# Important: Notepad.exe.mui can't simply go next to notepad.exe. You need to actually create the language folder (like en-US) again next to notepad.exe and put it in that. Otherwise notepad won't run.
|
||||||
|
$notepadPath = "C:\Users\WDAGUtilityAccount\Desktop\HostShared\notepad.exe"
|
||||||
|
reg add "HKEY_CLASSES_ROOT\*\shell\Edit with Notepad" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\*\shell\Edit with Notepad" /v "Icon" /t REG_SZ /d "$notepadPath,0" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\*\shell\Edit with Notepad\command" /ve /d "`"$notepadPath`" `"%1`"" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\Notepad" /ve /d "Open Notepad" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\Notepad" /v "Icon" /t REG_SZ /d "$notepadPath,0" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\Notepad\command" /ve /d "`"$notepadPath`"" /f
|
||||||
|
# ---- Add 'Open PowerShell Here' and 'Open CMD Here' to context menu -------
|
||||||
|
$powershellPath = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
|
||||||
|
$cmdPath = "C:\Windows\System32\cmd.exe"
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\MyPowerShell" /ve /d "Open PowerShell Here" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\MyPowerShell" /v "Icon" /t REG_SZ /d "$powershellPath,0" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\MyPowerShell\command" /ve /d "powershell.exe -noexit -command Set-Location -literalPath '%V'" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\Mycmd" /ve /d "Open CMD Here" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\Mycmd" /v "Icon" /t REG_SZ /d "$cmdPath,0" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\Directory\Background\shell\Mycmd\command" /ve /d "cmd.exe /s /k cd /d `"\`"%V`"\`"" /f
|
||||||
|
# ---- Set .txt files to open with Notepad, Create txt option in Context Menu 'New' list
|
||||||
|
cmd /c assoc .txt=txtfile
|
||||||
|
cmd /c ftype txtfile=`"$notepadPath`" "%1"
|
||||||
|
reg add "HKEY_CLASSES_ROOT\txtfile" /ve /d "Text Document" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\.txt\ShellNew" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\.txt\ShellNew" /v "NullFile" /t REG_SZ /d "" /f
|
||||||
|
reg add "HKEY_CLASSES_ROOT\.txt\ShellNew" /v "ItemName" /t REG_SZ /d "New Text Document" /f
|
||||||
|
# -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# Restart Explorer so changes take effect
|
||||||
|
Stop-Process -Name explorer -Force
|
||||||
|
# Open an explorer window to the host-shared folder
|
||||||
|
Start-Process explorer.exe C:\Users\WDAGUtilityAccount\Desktop\HostShared
|
||||||
|
|
||||||
|
# Change execution policy for powershell to allow running scripts
|
||||||
|
Set-ExecutionPolicy -ExecutionPolicy unrestricted -Scope LocalMachine
|
||||||
|
|
||||||
|
# Uncomment to pause after running
|
||||||
|
#Read-Host "Pause"
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Enable Dark Mode for Apps
|
||||||
|
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" -Name "AppsUseLightTheme" -Value 0
|
||||||
|
|
||||||
|
# Enable Dark Mode for System
|
||||||
|
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" -Name "SystemUsesLightTheme" -Value 0
|
||||||
|
|
||||||
|
# Set the Wallpaper
|
||||||
|
$wallpaperPath = "C:\Windows\Web\Wallpaper\Windows\img19.jpg"
|
||||||
|
$code = @'
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
public class Wallpaper {
|
||||||
|
[DllImport("user32.dll", CharSet=CharSet.Auto)]
|
||||||
|
public static extern int SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);
|
||||||
|
}
|
||||||
|
'@
|
||||||
|
|
||||||
|
Add-Type $code
|
||||||
|
$SPI_SETDESKWALLPAPER = 0x0014
|
||||||
|
$UPDATE_INI_FILE = 0x01
|
||||||
|
$SEND_CHANGE = 0x02
|
||||||
|
|
||||||
|
[Wallpaper]::SystemParametersInfo($SPI_SETDESKWALLPAPER, 0, $wallpaperPath, ($UPDATE_INI_FILE -bor $SEND_CHANGE))
|
||||||
|
|
||||||
|
# Restart Explorer to apply changes
|
||||||
|
Write-Host "Restarting Explorer..."
|
||||||
|
Stop-Process -Name explorer -Force
|
||||||
|
Start-Process explorer
|
||||||
|
Write-Host "Dark mode enabled and wallpaper updated successfully! Explorer has been restarted."
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Enable Light Mode for Apps
|
||||||
|
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" -Name "AppsUseLightTheme" -Value 1
|
||||||
|
# Enable Light Mode for System
|
||||||
|
Set-ItemProperty -Path "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize" -Name "SystemUsesLightTheme" -Value 1
|
||||||
|
|
||||||
|
# Restart Explorer to apply changes
|
||||||
|
Write-Host "Restarting Explorer..."
|
||||||
|
Stop-Process -Name explorer -Force
|
||||||
|
Start-Process explorer
|
||||||
|
Write-Host "Light mode enabled! Explorer has been restarted."
|
||||||
Loading…
Reference in New Issue