X

Using PowerShell to resolve Sysprep problems involving App-X packages

In a previous article here on TechGenix, I talked about how Mark Van Noy, a Technical Lead/Architect at the University of Colorado Boulder in the Greater Denver Area, had been experiencing some problems with trying to deploy App-X packages in Windows images that had been prepared using Sysprep. Mark had wanted to remove some specific App-X apps from his master gold image so that non-business-related apps were not being imaged out to his entire enterprise. A good example, of course, would be Candy Crush Saga, which Windows 10 has provisioned to every Start Menu. Most organizations like Mark’s would, of course, likely want to remove games from Windows 10 like Candy Crush or the Solitaire App-X apps from their images before deploying Windows 10 to their users. In this present article we’re going to examine Mark’s solution to the problem he was facing. The solution that he was able to craft together involved using Windows PowerShell. Let’s now hear how Mark achieved his goal.

The solution

The simple solution is to simply remove the corrupted database and let Windows re-create it based on the actual state of the computer rather than the state the SQLite database thinks it is in. The only catch is that the database resides in %SYSTEMDRIVE%\ProgramData\Microsoft\Windows\AppRepository\, which is a directory owned by Trusted Installer. Even the local Administrator account lacks permissions to take ownership of this directory or change permissions.

The workaround is to script the database removal then have the script run as SYSTEM under Scheduled Tasks. To aid our IT technicians, I created a simple CMD script named Reset-AppX.cmd that uses the command line to create a Scheduled Task as SYSTEM and runs on start:


@ECHO OFF
REM Fail if script is run as ANYONE other than Administrator
IF NOT ‘%username%’ == ‘Administrator’ GOTO AdminError
REM Create a Scheduled Task that fires when the computer starts. The script called by the
REM Scheduled Task handles deleting the Scheduled Task if it is successful.
schtasks /create /RU “SYSTEM” /NP /SC ONSTART /TN Reset-AppX /TR “powershell C:\Powershell\Fix-Sysprep.ps1” /F
GOTO END
:AdminError
ECHO SYSPREP FIX FAILED: Not logged in as Administrator
ECHO ————————————————–
ECHO %username% is not the same as Administrator.
GOTO END
:END


The Scheduled Task then runs a PowerShell script named Fix-Sysprep.ps1 that disables and stops the State-Repository service that protects the directory structure. The script then calls icacls to save the current permissions of the directory structure. Next, the script takes ownership of the database files before renaming them. Then the permissions are restored to the directory, the service is reset to manual, and the State-Repository service is started. As the script finishes it checks to make sure that the database files exist, which verifies that they have been re-created after the rename, and deletes the scheduled task:


# Script to rename the AppX database that can prevent Sysprep from running
# so that Windows will rebuild the AppX databse from scratch the the correct
# information and thus allowing Sysprep to complete successfully.
# Stop the service
Stop-Service -Name “StateRepository” -Force
# Disable the State Repository Service so that the files can be renamed
Set-Service -Name “StateRepository” -StartupType Disabled
# Export the existing permissions
icacls C:\ProgramData\Microsoft\Windows\AppRepository /save AclFile /T
# Take ownership of specific files
takeown /F C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment.srd
takeown /F C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment.srd-shm
takeown /F C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment.srd-wal
takeown /F C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine.srd
takeown /F C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine.srd-shm
takeown /F C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine.srd-wal
# Rename the files
Rename-Item C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment.srd C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment_corrupted.srd -Force
Rename-Item C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment.srd-shm C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment_corrupted.srd-shm -Force
Rename-Item C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment.srd-wal C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment_corrupted.srd-wal -Force
Rename-Item C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine.srd C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine_corrupted.srd -Force
Rename-Item C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine.srd-shm C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine_corrupted.srd-shm -Force
Rename-Item C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine.srd-wal C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine_corrupted.srd-wal -Force
# Import the permissions back
icacls C:\ProgramData\Microsoft\Windows\AppRepository /restore AclFile
# Re-Enable the service
Set-Service -Name “StateRepository” -StartupType Manual
# Re-Start the State Repository Service
Start-Service -Name “StateRepository”
# Try and verify that everything is really working
if (Test-Path C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Deployment_corrupted.srd)
{
if (Test-Path C:\ProgramData\Microsoft\Windows\AppRepository\StateRepository-Machine_corrupted.srd)
{
# If the two database files have been renamed and the service is running again then delete the scheduled task
if ((Get-Service -Name “StateRepository”).Status -eq “Running”)
{
# Delete the scheduled task
schtasks /delete /TN Reset-AppX /F
}
}
}


Note: Microsoft is aware of this problem. I worked with Microsoft on an open ticket with their Premiere support team to come up with this solution. Their team confirmed that this was a problem, our organization was not the only organization to report the problem, and that there were plans to address the issue. It is possible that a fix for this specific problem could be released at any time. The examples used here were taken from a computer running Windows 10 version 1511 on the CBB update branch. I am also including here our Remove-Apps.ps1 script that is a PowerShell script Microsoft signed off on as a legitimate way to remove App-X aps when we first started working with them on this case:

# Remove superflous built-in applications
# Get-AppXProvisionedPackage -Online | Select PackageName
$targets = “*XboxApp*”, “*WindowsStore*”, “*BingFinance*”, “*BingNews*”, “*BingSports*”, “*BingWeather*”, “*WindowsMaps*”, “*ZuneMusic*”, “*ZuneVideo*”, “*Messaging*”
$targets += “*SkypeApp*”, “*MicrosoftOfficeHub*”, “*Sway*”, “*People*”, “*SolitaireCollection*”, “*3DBuilder*”, “*ConnectivityStore*”, “*windowscommunications*”
$targets += “*WindowsCamera*”, “*SoundRecorder*”, “*Alarms*”
$packages = Get-AppXProvisionedPackage -Online
foreach ($package in $packages)
{
foreach ($target in $targets)
{
if ($package.PackageName -like $target)
{
Write-Host “Deprovisioning package: “, $package.DisplayName
Remove-AppXProvisionedPackage -Online -PackageName $package.PackageName
}
}
}
# Get-AppXPackage -AllUsers | Select PackageFullName
# list of application names to remove — USE WILDCARD
$names = “*CandyCrush*”, “*Sway*”, “*3DBuilder*”, “*ZuneVideo*”, “*Advertising*”, “*WindowsMaps*”, “*SolitaireCollection*”, “*XboxApp*”, “*WindowsStore*”
$names += “*BingSports*”, “*BingWeather*”, “*ConnectivityStore*”, “*BingFinance*”, “*BingNews*”, “*ZuneMusic*”, “*Messaging*”, “*People*”, “*Twitter*”
$names += “*SkypeApp*”, “*OfficeHub*”, “*windowscommunications*”, “*WindowsCamera*”, “*SoundRecorder*”, “*Alarms*”
$apps = Get-AppXPackage -AllUsers
foreach ($app in $apps)
{
foreach ($name in $names)
{
if ($app.Name -like $name)
{
Write-Host “Removing app: “, $app.Name
Remove-AppXPackage -Package $app
}
}
}


Additional resources

Interested readers who might like to try out Mark’s solution as described in this article can download all of Mark’s scripts as TXT files in this ZIP archive. Once you’ve download these scripts you can customize them as needed and then use them in your own environment. Be sure to try out any solution like this in a test environment, however, before using it in your production environment.