# Copyright © 2008, Microsoft Corporation. All rights reserved.
#This is passed from the troubleshooter via 'Add-DiagRootCause'
PARAM($targetPath, $appName)
#RS_ProgramCompatibilityWizard
#rparsons - 05 May 2008
#rfink - 01 Sept 2008 - rewrite to support dynamic choices
#set-psdebug -strict -trace 0
Import-LocalizedData -BindingVariable CompatibilityStrings -FileName CL_LocalizationData
#Compatibility modes
$CompatibilityModes = new-Object System.Collections.Hashtable
$CompatibilityModes.Add("Version_WINVISTA", "VISTARTM")
$CompatibilityModes.Add("Version_WINVISTA1", "VISTASP1")
$CompatibilityModes.Add("Version_WINVISTA2", "VISTASP2")
$CompatibilityModes.Add("Version_WIN2003", "WINSRV03SP1")
$CompatibilityModes.Add("Version_WIN2008SP1", "WINSRV08SP1")
$CompatibilityModes.Add("Version_WINXP", "WINXPSP2")
$CompatibilityModes.Add("Version_WINXP3", "WINXPSP3")
$CompatibilityModes.Add("Version_WIN2000", "WIN2000")
$CompatibilityModes.Add("Version_WINNT4", "NT4SP5")
$CompatibilityModes.Add("Version_WIN98", "WIN98")
$CompatibilityModes.Add("Version_WIN95", "WIN95")
$CompatibilityModes.Add("Version_MSIAUTO", "MSIAUTO")
$CompatibilityModes.Add("Version_UNKNOWN", "WINXPSP2")
$CompatibilityModes.Add("Display_256COLOR", "256COLOR")
$CompatibilityModes.Add("Display_640x480", "640X480")
$CompatibilityModes.Add("Display_DISABLEDWM", "DISABLEDWM")
$CompatibilityModes.Add("Display_HIGHDPIAWARE", "HIGHDPIAWARE")
$CompatibilityModes.Add("Display_DISABLETHEMES", "DISABLETHEMES")
$CompatibilityModes.Add("Access_RUNASADMIN", "RUNASADMIN")
[string]$RunAsAdminCompatMode = "RUNASADMIN"
[string]$MsiAutoCompatMode = "MSIAUTO"
[string]$AllVersionModes = "VISTARTM VISTASP1 VISTASP2 WINSRV08SP1 WINSRV03SP1 WINXPSP2 WINXPSP3 WIN2000 NT4SP5 WIN98 WIN95"
[string]$AllDisplayModes = "256COLOR 640X480 DISABLEDWM HIGHDPIAWARE DISABLETHEMES"
$SupportedModes = new-Object System.Collections.ArrayList
$SupportedModes.AddRange($CompatibilityModes.Values)
#Compatibility mode strings
$CompatibilityModeStrings = new-Object System.Collections.Hashtable
$CompatibilityModeStrings.Add("VISTARTM", $CompatibilityStrings.Version_Choice_WINVISTA)
$CompatibilityModeStrings.Add("VISTASP1", $CompatibilityStrings.Version_Choice_WINVISTA1)
$CompatibilityModeStrings.Add("VISTASP2", $CompatibilityStrings.Version_Choice_WINVISTA2)
$CompatibilityModeStrings.Add("WINSRV03SP1", $CompatibilityStrings.Version_Choice_WIN2003)
$CompatibilityModeStrings.Add("WINSRV08SP1", $CompatibilityStrings.Version_Choice_WIN2008SP1)
$CompatibilityModeStrings.Add("WINXPSP2", $CompatibilityStrings.Version_Choice_WINXPSP2)
$CompatibilityModeStrings.Add("WINXPSP3", $CompatibilityStrings.Version_Choice_WINXPSP3)
$CompatibilityModeStrings.Add("WIN2000", $CompatibilityStrings.Version_Choice_WIN2000)
$CompatibilityModeStrings.Add("NT4SP5", $CompatibilityStrings.Version_Choice_WINNT)
$CompatibilityModeStrings.Add("WIN98", $CompatibilityStrings.Version_Choice_WIN98)
$CompatibilityModeStrings.Add("WIN95", $CompatibilityStrings.Version_Choice_WIN95)
$CompatibilityModeStrings.Add("MSIAUTO", $CompatibilityStrings.Version_Choice_MSIAUTO)
$CompatibilityModeStrings.Add("256COLOR", $CompatibilityStrings.Display_Choice_256COLOR)
$CompatibilityModeStrings.Add("640X480", $CompatibilityStrings.Display_Choice_640x480)
$CompatibilityModeStrings.Add("DISABLEDWM", $CompatibilityStrings.Display_Choice_DISABLEDWM)
$CompatibilityModeStrings.Add("HIGHDPIAWARE", $CompatibilityStrings.Display_Choice_HIGHDPIAWARE)
$CompatibilityModeStrings.Add("DISABLETHEMES", $CompatibilityStrings.Display_Choice_DISABLETHEMES)
[int]$VersionProblem = 1
[int]$DisplayProblem = 2
[int]$RunAsAdminProblem = 4
[int]$problemMask = 0
[string]$spacer = " "
[string]$displaySpacer = ", "
[string]$delimiters = "# "
#Xml constants
[string]$resultSuccess = "Success"
[string]$resultFailure = "Failure"
$problemChoiceXml=@'
ProblemN_Choice_VERSION
ProblemD_Choice_VERSION
VersionProblem
ProblemN_Choice_DISPLAY
ProblemD_Choice_DISPLAY
DisplayProblem
ProblemN_Choice_ACCESS
ProblemD_Choice_ACCESS
RunAsAdminProblem
ProblemN_Choice_UNKNOWN
ProblemD_Choice_UNKNOWN
UnknownProblem
'@
$problemChoiceXml64=@'
ProblemN_Choice_VERSION
ProblemD_Choice_VERSION
VersionProblem
ProblemN_Choice_ACCESS
ProblemD_Choice_ACCESS
RunAsAdminProblem
ProblemN_Choice_UNKNOWN
ProblemD_Choice_UNKNOWN
UnknownProblem
'@
$versionChoiceXml=@'
Version_Choice_WINVISTA
VersionD_Choice_ALL
Version_WINVISTA
Version_Choice_WINVISTA1
VersionD_Choice_ALL
Version_WINVISTA1
Version_Choice_WINVISTA2
VersionD_Choice_ALL
Version_WINVISTA2
Version_Choice_WIN2008SP1
VersionD_Choice_ALL
Version_WIN2008SP1
Version_Choice_WIN2003
VersionD_Choice_ALL
Version_WIN2003
Version_Choice_WINXPSP2
VersionD_Choice_ALL
Version_WINXP
Version_Choice_WINXPSP3
VersionD_Choice_ALL
Version_WINXP3
Version_Choice_WIN2000
VersionD_Choice_ALL
Version_WIN2000
Version_Choice_WINNT
VersionD_Choice_ALL
Version_WINNT4
Version_Choice_WIN98
VersionD_Choice_ALL
Version_WIN98
Version_Choice_WIN95
VersionD_Choice_ALL
Version_WIN95
Version_Choice_UNKNOWN
VersionD_Choice_ALL
Version_UNKNOWN
'@
$versionChoiceXml64=@'
Version_Choice_WINVISTA
VersionD_Choice_ALL
Version_WINVISTA
Version_Choice_WINVISTA1
VersionD_Choice_ALL
Version_WINVISTA1
Version_Choice_WINVISTA2
VersionD_Choice_ALL
Version_WINVISTA2
Version_Choice_WIN2008SP1
VersionD_Choice_ALL
Version_WIN2008SP1
'@
$displayChoiceXml = @'
DisplayN_Choice_256COLOR
DisplayD_Choice_256COLOR
Display_256COLOR
DisplayN_Choice_640x480
DisplayD_Choice_640x480
Display_640x480
DisplayN_Choice_DISABLEDWM
DisplayD_Choice_DISABLEDWM
Display_DISABLEDWM
DisplayN_Choice_HIGHDPIAWARE
DisplayD_Choice_HIGHDPIAWARE
Display_HIGHDPIAWARE
DisplayN_Choice_DISABLETHEMES
DisplayD_Choice_DISABLETHEMES
Display_DISABLETHEMES
DisplayN_Choice_UNKNOWN
DisplayD_Choice_UNKNOWN
Display_UNKNOWN
'@
$typeDefinition = @"
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
public class WerUtil
{
const int MAX_PATH = 260;
const int GPLK_USER = 0x00000001;
const int MAX_LAYER_LENGTH = 256;
const int WCHAR_SIZE = 2;
const uint LAYER_APPLY_TO_SYSTEM_EXES = 0x00000001;
const uint SCS_64BIT_BINARY = 6;
[DllImport("pcwutl.dll", EntryPoint="SendPcwWerReport", CharSet=CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool SendPcwWerReport(String ExePath, bool FixesWorked, String ResultFile, String MatchingInfoFile);
[DllImport("pcwutl.dll", EntryPoint="GetTempFile", CharSet=CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool GetTempFile(String Prefix, StringBuilder ResultFilePath);
public static String GetTempFilePath()
{
StringBuilder resultPath = new StringBuilder(MAX_PATH);
if (GetTempFile("PCW", resultPath))
{
return resultPath.ToString();
}
return String.Empty;
}
[DllImport("pcwutl.dll", EntryPoint="GetMatchingInfo", CharSet=CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool GetMatchingInfo(String ExePath, StringBuilder OutputPath);
public static String GetMatchingFileInfo(String ExePath)
{
StringBuilder resultPath = new StringBuilder(MAX_PATH);
if (GetMatchingInfo(ExePath, resultPath))
{
return resultPath.ToString();
}
return String.Empty;
}
[DllImport("pcwutl.dll", EntryPoint="LogAeEvent", CharSet=CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool LogAeEvent(String ExecutablePath, String CompatibilityLayer, uint ScenarioType, bool FixWorked, String FileIdStr, String ProgramIdStr);
public static String GetMediaType(String ExePath)
{
DriveInfo driveInfo = new DriveInfo(Path.GetPathRoot(ExePath));
return driveInfo.DriveType.ToString();
}
[DllImport("pcwutl.dll", EntryPoint="RetrieveFileAndProgramId", CharSet=CharSet.Unicode)]
public static extern void RetrieveFileAndProgramId(String ExePath, StringBuilder FileId, StringBuilder ProgramId);
public static ArrayList MapFilePathToId(String ExePath)
{
StringBuilder fileId = new StringBuilder(MAX_PATH);
StringBuilder programId = new StringBuilder(MAX_PATH);
RetrieveFileAndProgramId(ExePath, fileId, programId);
ArrayList idInfo = new ArrayList();
idInfo.Add(fileId.ToString());
idInfo.Add(programId.ToString());
return idInfo;
}
[DllImport("apphelp.dll", EntryPoint="SetPermLayerState", CharSet=CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool SetPermLayerState(String wszPath, String wszLayer, uint dwFlags, bool bMachine, bool bEnable);
public static void ApplyCompatMode(String ExePath, ArrayList LayersToApply, ArrayList LayersToRemove)
{
foreach (Object layer in LayersToApply)
{
if ((String)layer != String.Empty)
{
SetPermLayerState(ExePath, (String)layer, LAYER_APPLY_TO_SYSTEM_EXES, false, true);
}
}
foreach (Object layer in LayersToRemove)
{
if ((String)layer != String.Empty)
{
SetPermLayerState(ExePath, (String)layer, 0, false, false);
}
}
}
[DllImport("apphelp.dll", EntryPoint="SdbGetPermLayerKeys", CharSet=CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool SdbGetPermLayerKeys(String pwszPath, StringBuilder pwszLayers, out uint pdwBytes, uint dwFlags);
public static String GetExistingCompatMode(String ExePath)
{
StringBuilder existingLayers = new StringBuilder(MAX_LAYER_LENGTH);
uint existingLayersSize = (uint)existingLayers.Capacity*WCHAR_SIZE;
if (SdbGetPermLayerKeys(ExePath, existingLayers, out existingLayersSize, GPLK_USER))
{
return existingLayers.ToString();
}
return String.Empty;
}
[DllImport("apphelp.dll", EntryPoint="SdbSetPermLayerKeys", CharSet=CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool SdbSetPermLayerKeys(String wszPath, String wszLayers, bool bMachine);
public static void OverwriteCompatMode(String ExePath, String ModeToApply)
{
SdbSetPermLayerKeys(ExePath, ModeToApply, false);
}
public static String EscapePath(String Path)
{
if (Path == null)
{
return null;
}
return Path.Replace("$", "`$");
}
[DllImport("kernel32.dll", EntryPoint="GetBinaryTypeW", CharSet=CharSet.Unicode)]
[return : MarshalAs(UnmanagedType.Bool)]
public static extern bool GetBinaryType(string lpApplicationName, out uint lpBinaryType);
public static bool AppIs64Bit(String AppPath)
{
uint binaryType;
if (GetBinaryType(AppPath, out binaryType))
{
if (binaryType == SCS_64BIT_BINARY)
{
return true;
}
}
return false;
}
}
"@
function set-selected([System.Collections.Hashtable]$choice, [bool]$select)
{
if($select -and -not($choice.ContainsKey("ExtensionPoint")))
{
$choice.Add("ExtensionPoint", "")
}
elseif(-not($select) -and ($choice["ExtensionPoint"] -ne $null))
{
$choice.Remove("ExtensionPoint")
}
}
#Function to mark a compatibility mode for addition/removal
function SetCompatMode([string]$compatMode = $(throw $CompatibilityStrings.Throw_NO_MODE), [bool]$apply)
{
if($apply)
{
if(-not($layersToApply.Contains($compatMode)) -and -not($originalCompatMode -match $compatMode))
{
$layersToApply.Add($compatMode)
}
if($layersToRemove.Contains($compatMode))
{
$layersToRemove.Remove($compatMode)
}
}
else
{
if(-not($layersToRemove.Contains($compatMode)))
{
$layersToRemove.Add($compatMode)
}
if($layersToApply.Contains($compatMode))
{
$layersToApply.Remove($compatMode)
}
}
}
#Function to determine the problem(s) the user is having.
function GetProblemSelection()
{
$choices = New-Object System.Collections.ArrayList
if($appIs64Bit)
{
$choiceDoc = [xml] $problemChoiceXml64
}
else
{
$choiceDoc = [xml] $problemChoiceXml
}
#The following code segment is used multiple times to generate "dynamic choices"
#with default selection based on the layers already stored in the registry.
#Consolidating the code into one function would be preferable, but unfortunately
#this causes problems with the global persistence of the "choices" variable - I'm
#not sure why at the moment.
$choiceDoc.SelectNodes("Choices/Choice") | foreach {
$choice = @{}
foreach ($node in $_.ChildNodes)
{
if($node.InnerXml -ne [string]::Empty)
{
$choice.Add($node.Name, $node.InnerXml)
}
}
#localize the name and description
$key = $choice["Name"]
$choice["Name"] = $CompatibilityStrings.$key
$key = $choice["Description"]
$choice["Description"] = $CompatibilityStrings.$key
$choices += $choice
}
#Determine if a version layer is set
if(($AllVersionModes.Split(' ') | where {$originalCompatMode -match $_}) -ne $null)
{
$choices | where {$_["Value"] -eq "VersionProblem"} | foreach {
set-selected $_ $true
}
}
else
{
$choices | where {$_["Value"] -eq "VersionProblem"} | foreach {
set-selected $_ $false
}
}
#Determine if a display layer is set
if(($AllDisplayModes.Split(' ') | where {$originalCompatMode -match $_}) -ne $null)
{
$choices | where {$_["Value"] -eq "DisplayProblem"} | foreach {
set-selected $_ $true
}
}
else
{
$choices | where {$_["Value"] -eq "DisplayProblem"} | foreach {
set-selected $_ $false
}
}
#Determine if the runasadmin layer is set
if($originalCompatMode -match $RunAsAdminCompatMode)
{
$choices | where {$_["Value"] -eq "RunAsAdminProblem"} | foreach {
set-selected $_ $true
}
}
else
{
$choices | where {$_["Value"] -eq "RunAsAdminProblem"} | foreach {
set-selected $_ $false
}
}
$problemChoices = Get-DiagInput -id IT_ProblemDisplay -choice $choices
$mask = 0
foreach($selection in $problemChoices)
{
if($selection -eq "VersionProblem")
{
$mask = $mask -bor $VersionProblem
}
if($selection -eq "DisplayProblem")
{
$mask = $mask -bor $DisplayProblem
}
if($selection -eq "RunAsAdminProblem")
{
$mask = $mask -bor $RunAsAdminProblem
}
if($selection -eq "UnknownProblem" -and ($problemChoices.Length -eq 1))
{
$mask = $mask -bor $VersionProblem
if(-not($appIs64Bit))
{
$mask = $mask -bor $DisplayProblem
}
$mask = $mask -bor $RunAsAdminProblem
}
}
Set-Variable -name problemMask -value $mask -scope global
}
#Function to determine the user's version choice
#Unlike other problem categories, this is a single selection
function GetVersionLayer([bool]$showInteraction)
{
$choices = New-Object System.Collections.ArrayList
$choiceDoc = $null
if($appIs64Bit)
{
$choiceDoc = [xml] $versionChoiceXml64
}
else
{
$choiceDoc = [xml] $versionChoiceXml
}
$choiceDoc.SelectNodes("Choices/Choice") | foreach {
$choice = @{}
foreach ($node in $_.ChildNodes)
{
if($node.InnerXml -ne [string]::Empty)
{
$choice.Add($node.Name, $node.InnerXml)
}
}
#localize the name and description
$key = $choice["Name"]
$choice["Name"] = $CompatibilityStrings.$key
$key = $choice["Description"]
$choice["Description"] = $CompatibilityStrings.$key
$choices += $choice
}
$choices | where {$originalCompatMode -match $CompatibilityModes[$_["Value"]]} | foreach {
set-selected $_ $true
}
$choices | where {-not($originalCompatMode -match $CompatibilityModes[$_["Value"]])} | foreach {
set-selected $_ $false
}
$versionChoice = $null
if($showInteraction)
{
$versionChoice = Get-DiagInput -id IT_WindowsVersions -choice $choices
if(($versionChoice -ne [String]::Empty) -and ($versionChoice -ne $null))
{
Set-Variable -name solutionSelected -value $true -scope global
SetCompatMode $CompatibilityModes[$versionChoice] $true
}
}
#Make sure unselected choices are not set
foreach($choice in $choices)
{
if($versionChoice -eq $null -or -not($CompatibilityModes[$choice["Value"]] -eq $CompatibilityModes[$versionChoice]) -and ($originalCompatMode -match $CompatibilityModes[$choice["Value"]]))
{
SetCompatMode $CompatibilityModes[$choice["Value"]] $false
}
}
}
#Function to determine the user's display choices
#We allow the user to select multiple symptoms
function GetDisplayLayers([bool]$showInteraction)
{
$choices = New-Object System.Collections.ArrayList
$choiceDoc = [xml] $displayChoiceXml
$choiceDoc.SelectNodes("Choices/Choice") | foreach {
$choice = @{}
foreach ($node in $_.ChildNodes)
{
if($node.InnerXml -ne [string]::Empty)
{
$choice.Add($node.Name, $node.InnerXml)
}
}
#localize the name and description
$key = $choice["Name"]
$choice["Name"] = $CompatibilityStrings.$key
$key = $choice["Description"]
$choice["Description"] = $CompatibilityStrings.$key
$choices += $choice
}
$choices | where {$CompatibilityModes.ContainsKey($_["Value"]) -and ($originalCompatMode -match $CompatibilityModes[$_["Value"]])} | foreach {
set-selected $_ $true
}
$choices | where {-not($CompatibilityModes.ContainsKey($_["Value"]) -and ($originalCompatMode -match $CompatibilityModes[$_["Value"]]))} | foreach {
set-selected $_ $false
}
$displayChoices = New-Object System.Collections.ArrayList
$selectionFound = $false
if($showInteraction)
{
$displayChoices = Get-DiagInput -id IT_DisplayProblems -choice $choices
foreach($selection in $displayChoices)
{
$selectionFound = $true
if(($selection -ne "Display_UNKNOWN") -and ($selection -ne [String]::Empty))
{
Set-Variable -name solutionSelected -value $true -scope global
SetCompatMode $CompatibilityModes[$selection] $true
}
}
}
#Make sure unselected choices are not set
foreach($choice in $choices)
{
$choiceIsSelected = $false
foreach($selectedChoice in $displayChoices)
{
if($selectedChoice -eq $choice["Value"])
{
$choiceIsSelected = $true
break
}
}
if(-not($choiceIsSelected) -and ($originalCompatMode -match $CompatibilityModes[$choice["Value"]]))
{
SetCompatMode $CompatibilityModes[$choice["Value"]] $false
}
}
}
#Function to set the text for the summary page.
function GetSummary()
{
set-variable compatModeParam $CompatibilityStrings.Version_Choice_DEFAULT -scope global
set-variable displayModeParam $CompatibilityStrings.Display_Choice_DEFAULT -scope global
set-variable accessModeParam $CompatibilityStrings.Access_Choice_DEFAULT -scope global
foreach($layer in $layersToApply)
{
if($allVersionModes -match $layer)
{
set-variable compatModeParam $CompatibilityModeStrings[$layer] -scope global
}
if($allDisplayModes -match $layer)
{
$displayMode = Get-Variable -name displayModeParam -valueOnly -scope global
if($displayMode -eq $CompatibilityStrings.Display_Choice_DEFAULT)
{
$displayMode = [String]::Empty
}
if($displayMode -ne [String]::Empty)
{
$displayMode += $displaySpacer
}
$displayMode += $CompatibilityModeStrings[$layer]
Set-Variable -name displayModeParam -value $displayMode -scope global
}
if($RunAsAdminCompatMode -eq $layer)
{
Set-Variable -name accessModeParam -value $CompatibilityStrings.Access_Choice_ADMIN -scope global
}
if($MsiAutoCompatMode -eq $layer)
{
set-variable compatModeParam $CompatibilityModeStrings[$layer] -scope global
}
}
$originalCompatMode.Split($delimiters.ToCharArray()) | foreach {
if(-not($_ -eq [String]::Empty) -and -not($layersToRemove.Contains($_)))
{
if($AllVersionModes -match $_)
{
set-variable compatModeParam $CompatibilityModeStrings[$_] -scope global
}
if($AllDisplayModes -match $_)
{
$displayMode = Get-Variable -name displayModeParam -valueOnly -scope global
if($displayMode -eq $CompatibilityStrings.Display_Choice_DEFAULT)
{
$displayMode = [String]::Empty
}
if($displayMode -ne [String]::Empty)
{
$displayMode += $displaySpacer
}
$displayMode += $CompatibilityModeStrings[$_]
Set-Variable -name displayModeParam -value $displayMode -scope global
}
if($RunAsAdminCompatMode -eq $_)
{
Set-Variable -name accessModeParam -value $CompatibilityStrings.Access_Choice_ADMIN -scope global
}
if($MsiAutoCompatMode -eq $_)
{
set-variable compatModeParam $CompatibilityModeStrings[$_] -scope global
}
}
}
}
$werUtilType = Add-Type -TypeDefinition $typeDefinition -PassThru
$targetPath = $werUtilType::EscapePath($targetPath)
if($targetPath -eq $null)
{
throw $CompatibilityStrings.Throw_INVALID_PATH
}
set-variable verifyResponse "Verify_TRYAGAIN" -scope global
set-variable solutionSelected $false -scope global
set-variable appIs64Bit $false -scope global
set-variable tsChoice "ts_MANUAL" -scope global
$autoFix = $true
$isExecutable = ([System.IO.Path]::GetExtension($targetPath) -eq ".exe")
$layersToApply = New-Object System.Collections.ArrayList
$layersToRemove = New-Object System.Collections.ArrayList
if($werUtilType::AppIs64Bit($targetPath))
{
set-variable appIs64Bit $true -scope global
}
#Show the simple troubleshooting option first for non-64bit apps
if(-not($appIs64Bit) -and ($isExecutable))
{
$tsChoice = Get-DiagInput -id IT_AutoTroubleshoot
}
if(($tsChoice -eq "ts_AUTO") -or -not($isExecutable))
{
#Make sure only WINXPSP2 is set for executables
$AllVersionModes.Split(' ') | foreach {
if($_ -ne "WINXPSP2")
{
$layersToRemove.Add($_)
}
}
$AllDisplayModes.Split(' ') | foreach {
$layersToRemove.Add($_)
}
#MSIs also get the RunAsAdmin layer
if($isExecutable)
{
$layersToRemove.Add($RunAsAdminCompatMode)
$layersToApply.Add("WINXPSP2")
}
else
{
$layersToApply.Add($RunAsAdminCompatMode)
$layersToApply.Add("MSIAUTO")
}
Set-Variable -name solutionSelected -value $true -scope global
}
else
{
$autoFix = $false
}
try
{
#Loop until either the problem is solved or the user gives up
do
{
#Get the original layers string
$originalCompatMode = $werUtilType::GetExistingCompatMode($targetPath)
if(-not($autoFix))
{
#Reset variables
set-variable solutionSelected $false -scope global
set-variable problemMask 0 -scope global
$layersToApply.Clear()
$layersToRemove.Clear()
#Ask the user to identify their symptoms if this is an exe
if($isExecutable)
{
GetProblemSelection
}
#MSIs get the RunAsAdmin layer automatically applied and automatically
#prompt the user to select a version layer
else
{
$mask = $VersionProblem
$mask = $mask -bor $RunAsAdminProblem
set-Variable problemMask $mask -scope global
set-Variable solutionSelected $true -scope global
}
[int]$mask = get-Variable -name problemMask -valueOnly -scope global
if($mask -band $VersionProblem)
{
GetVersionLayer($true)
}
else
{
GetVersionLayer($false)
}
if($mask -band $DisplayProblem)
{
GetDisplayLayers($true)
}
else
{
if(-not($appIs64Bit))
{
GetDisplayLayers($false)
}
}
if($mask -band $RunAsAdminProblem)
{
#No interaction for this; just need to set the layer
if(-not($originalCompatMode -match $RunAsAdminCompatMode))
{
SetCompatMode $RunAsAdminCompatMode $true
}
set-Variable solutionSelected $true -scope global
}
else
{
if($originalCompatMode -match $RunAsAdminCompatMode)
{
SetCompatMode $RunAsAdminCompatMode $false
}
}
}
if($solutionSelected)
{
$quotedPath = "`""+$targetPath+"`""
#Get the command line of the scheduled task we'll run
$schedTaskCmd = "rundll32.exe {0}\pcwutl.dll,CreateAndRunTask -path `"{1}`"" -f [System.Environment]::SystemDirectory,$quotedPath
#Make the registry entry
$werUtilType::ApplyCompatMode($targetPath, $layersToApply, $layersToRemove)
GetSummary
$param1 = Get-Variable -name compatModeParam -valueOnly -scope global
$param2 = Get-Variable -name displayModeParam -valueOnly -scope global
$param3 = Get-Variable -name accessModeParam -valueOnly -scope global
if($isExecutable)
{
$getDiagCmd = "Get-DiagInput -id IT_Summary -parameter @{ `"ExePath`"=`"$schedTaskCmd`";"
if ($param1 -notlike "*None*")
{
$param1 += "`n";
$title = $CompatibilityStrings.Text_Version_Title
$getDiagCmd+="`"CompatMode`"=`"$title $param1`";"
}
else
{
$getDiagCmd+="`"CompatMode`"=`"`";"
}
if ($param2 -notlike "*Normal*")
{
$param2 += "`n";
$title = $CompatibilityStrings.Text_Display_Title
$getDiagCmd+="`"DisplayMode`"=`"$title $param2`";"
$displayWarning = $CompatibilityStrings.Text_Display_Warning
$getDiagCmd+="`"DisplayWarning`"=`"`n$displayWarning `n`";"
}
else
{
$getDiagCmd+="`"DisplayMode`"=`"`";"
$getDiagCmd+="`"DisplayWarning`"=`"`";"
}
if ($param3 -notlike "*Normal*")
{
$title = $CompatibilityStrings.Text_Access_Title
$getDiagCmd+="`"AccessMode`"=`"$title $param3`";"
}
else
{
$getDiagCmd+="`"AccessMode`"=`"`";"
}
$getDiagCmd+="}"
$runResult = Invoke-Expression $getDiagCmd
while($runResult -ne "Run")
{
$getDiagCmd = $getDiagCmd.Replace("IT_Summary ", "IT_Summary_Error ")
$runResult = Invoke-Expression $getDiagCmd
}
}
else
{
$getDiagCmd = "Get-DiagInput -id IT_SummaryMSI -parameter @{ `"ExePath`"=`"$schedTaskCmd`"; `"CompatMode`"=`"$param1`" }"
$runResult = Invoke-Expression $getDiagCmd
while($runResult -ne "Run")
{
$getDiagCmd = $getDiagCmd.Replace("IT_SummaryMSI ", "IT_SummaryMSI_Error ")
$runResult = Invoke-Expression $getDiagCmd
}
}
$autoFix = $false
#Determine if we need to re-run the wizard
if($isExecutable)
{
$verifyResponse = Get-DiagInput -id IT_VerifySolution
}
else
{
$verifyResponse = Get-DiagInput -id IT_MsiVerifySolution
}
Set-Variable -name launchError -value $false -scope global
#Remove applied settings if the user decided the problem wasn't fixed.
if($verifyResponse -ne "Verify_YES")
{
$werUtilType::OverwriteCompatMode($targetPath, $originalCompatMode)
}
}
else
{
$verifyResponse = Get-DiagInput -id IT_NoSolution
}
}
while($verifyResponse -eq "Verify_TRYAGAIN")
#Clear the settings and exit without sending a report.
if($verifyResponse -eq "Verify_UNDO")
{
$layersToApply.Clear()
$layersToRemove.Clear()
$AllVersionModes.Split(' ') | foreach {
$layersToRemove.Add($_)
}
$AllDisplayModes.Split(' ') | foreach {
$layersToRemove.Add($_)
}
$layersToRemove.Add($RunAsAdminCompatMode)
$werUtilType::ApplyCompatMode($targetPath, $layersToApply, $layersToRemove)
exit
}
Write-DiagProgress -activity $CompatibilityStrings.Text_Activity_SAVING -status $CompatibilityStrings.Text_Status_GENERATING
#Get final state of compat mode
$finalCompatMode = $werUtilType::GetExistingCompatMode($targetPath)
#Push the compat mode settings into the diag report
#TODO: Need to have this coming from the localization section (see TS_PrinterDriver.ps1, CL_LocalizationData.psd1)
$finalCompatMode | convertto-xml | Update-DiagReport -id compatMode -name "CompatMode" -description "CompatMode"
$verifyResponse | convertto-xml | Update-DiagReport -id verifySolution -name "UserVerifySolution" -description "User Verification of Solution"
#Generate XML containing wizard results
$resultFile = $werUtilType::GetTempFilePath()
$mediaType = $werUtilType::GetMediaType($targetPath)
$compatResult = $resultFailure
if ($verifyResponse -eq "Verify_YES")
{
$compatResult = $resultSuccess
}
$wizardResultXml = @"
"@
$resultXml = [xml] $wizardResultXml
#Create a new LAYER element for each layer applied
foreach($layerApplied in $layersToApply)
{
$element = $resultXml.CreateElement("LAYER")
$attribute = $resultXml.CreateAttribute("NAME")
$attribute.set_Value($layerApplied)
$element.SetAttributeNode($attribute)
$resultXml.CompatWizardResults.AppendChild($element)
}
$resultXml.save($resultFile)
#Get the matching file information
$matchingInfoFile = $werUtilType::GetMatchingFileInfo($targetPath)
#Send WER report
$fixesWorked = $false
if ($verifyResponse -eq "Verify_YES")
{
$fixesWorked = $true
}
$result = $werUtilType::SendPcwWerReport($targetPath, $fixesWorked, $resultFile, $matchingInfoFile)
#Delete the temporary files
Remove-Item -path $resultFile -erroraction silentlycontinue
Remove-Item -path $matchingInfoFile -erroraction silentlycontinue
#Write event to event log
$fileIdInfo = $werUtilType::MapFilePathToId($targetPath)
$result = $werUtilType::LogAeEvent($targetPath, $finalCompatMode, 203, $fixesWorked, $fileIdInfo[0], $fileIdInfo[1])
}
# Handle cancel event
finally
{
if(($originalCompatMode -ne $null) -and ($verifyResponse -eq "Verify_TRYAGAIN"))
{
$werUtilType::OverwriteCompatMode($targetPath, $originalCompatMode)
}
}