# 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 #change HKLM\Software\Windows NT\CurrentVersion\AppCompatFlags\CompatTS EnableTracing(DWORD) to 1 #if you want to enable tracing $SpewTraceToDesktop = $false Import-LocalizedData -BindingVariable CompatibilityStrings -FileName CL_LocalizationData #Compatibility modes $CompatibilityModes = new-Object System.Collections.Hashtable $CompatibilityModes.Add("Version_WIN8RTM", "WIN8RTM") $CompatibilityModes.Add("Version_WIN7RTM", "WIN7RTM") $CompatibilityModes.Add("Version_WINVISTA2", "VISTASP2") $CompatibilityModes.Add("Version_WINXP3", "WINXPSP3") $CompatibilityModes.Add("Version_MSIAUTO", "MSIAUTO") $CompatibilityModes.Add("Version_UNKNOWN", "WINXPSP3") $CompatibilityModes.Add("Display_256COLOR", "256COLOR") $CompatibilityModes.Add("Display_16BITCOLOR", "16BITCOLOR") $CompatibilityModes.Add("Display_640x480", "640X480") $CompatibilityModes.Add("Display_HIGHDPIAWARE", "HIGHDPIAWARE") $CompatibilityModes.Add("Access_RUNASADMIN", "RUNASADMIN") [string]$RunAsAdminCompatMode = "RUNASADMIN" [string]$MsiAutoCompatMode = "MSIAUTO" [string]$AllVersionModes = "WIN8RTM WIN7RTM VISTASP2 WINXPSP3" [string]$AllDisplayModes = "256COLOR 16BITCOLOR 640X480 HIGHDPIAWARE" [string]$VistaPlusDisplayMode = "HIGHDPIAWARE" [string]$AllTSLayers = "{0} {1} {2} {3}" -f $AllVersionModes, $RunAsAdminCompatMode, $MsiAutoCompatMode, $AllDisplayModes $SupportedModes = new-Object System.Collections.ArrayList $SupportedModes.AddRange($CompatibilityModes.Values) #Compatibility mode strings $CompatibilityModeStrings = new-Object System.Collections.Hashtable $CompatibilityModeStrings.Add("WIN8RTM", $CompatibilityStrings.Version_Choice_WIN8RTM) $CompatibilityModeStrings.Add("WIN7RTM", $CompatibilityStrings.Version_Choice_WIN7RTM) $CompatibilityModeStrings.Add("VISTASP2", $CompatibilityStrings.Version_Choice_WINVISTA2) $CompatibilityModeStrings.Add("WINXPSP3", $CompatibilityStrings.Version_Choice_WINXPSP3) $CompatibilityModeStrings.Add("MSIAUTO", $CompatibilityStrings.Version_Choice_MSIAUTO) $CompatibilityModeStrings.Add("256COLOR", $CompatibilityStrings.Display_Choice_256COLOR) $CompatibilityModeStrings.Add("16BITCOLOR", $CompatibilityStrings.Display_Choice_16BITCOLOR) $CompatibilityModeStrings.Add("640X480", $CompatibilityStrings.Display_Choice_640x480) $CompatibilityModeStrings.Add("HIGHDPIAWARE", $CompatibilityStrings.Display_Choice_HIGHDPIAWARE) [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 '@ $problemChoiceXmlMsi=@' ProblemN_Choice_VERSION ProblemD_Choice_VERSION VersionProblem ProblemN_Choice_DISPLAY ProblemD_Choice_DISPLAY DisplayProblem ProblemN_Choice_UNKNOWN ProblemD_Choice_UNKNOWN UnknownProblem '@ $versionChoiceXml=@' Version_Choice_WIN8RTM VersionD_Choice_ALL Version_WIN8RTM Version_Choice_WIN7RTM VersionD_Choice_ALL Version_WIN7RTM Version_Choice_WINVISTA2 VersionD_Choice_ALL Version_WINVISTA2 Version_Choice_WINXPSP3 VersionD_Choice_ALL Version_WINXP3 Version_Choice_UNKNOWN VersionD_Choice_ALL Version_UNKNOWN '@ $versionChoiceXml64=@' Version_Choice_WIN8RTM VersionD_Choice_ALL Version_WIN8RTM Version_Choice_WIN7RTM VersionD_Choice_ALL Version_WIN7RTM Version_Choice_WINVISTA2 VersionD_Choice_ALL Version_WINVISTA2 Version_Choice_UNKNOWN VersionD_Choice_ALL Version_WINVISTA2 '@ $displayChoiceXml = @' DisplayN_Choice_256COLOR DisplayD_Choice_256COLOR Display_256COLOR DisplayN_Choice_16BITCOLOR DisplayD_Choice_16BITCOLOR Display_16BITCOLOR DisplayN_Choice_640x480 DisplayD_Choice_640x480 Display_640x480 DisplayN_Choice_HIGHDPIAWARE DisplayD_Choice_HIGHDPIAWARE Display_HIGHDPIAWARE 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_APPLIED_FROM_WIZARD = 0x00000010; const uint LAYER_APPLIED_FROM_WIZ_CLOUD = 0x00000020; 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, bool CloudLayer) { uint Flag; if (CloudLayer) { Flag = LAYER_APPLIED_FROM_WIZ_CLOUD; } else { Flag = LAYER_APPLIED_FROM_WIZARD; } foreach (Object layer in LayersToApply) { if ((String)layer != String.Empty) { SetPermLayerState(ExePath, (String)layer, Flag, 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; } [DllImport("pcwutl.dll", EntryPoint="GetLayerFromGenome", CharSet=CharSet.Unicode)] [return : MarshalAs(UnmanagedType.Bool)] public static extern bool GetLayerFromGenome(String ExePath, StringBuilder Layer, out bool IsConfidentVistaPlus); public static Array GetGenomeLayer(String ExePath) { bool IsConfidentVistaPlus = false; StringBuilder resultPath = new StringBuilder(MAX_PATH); Array retArray = Array.CreateInstance(typeof(Object), 2); if (GetLayerFromGenome(ExePath, resultPath, out IsConfidentVistaPlus)) { retArray.SetValue(resultPath.ToString(), 0); } else { retArray.SetValue(String.Empty, 0); } retArray.SetValue(IsConfidentVistaPlus, 1); return retArray; } [DllImport("pcwutl.dll", EntryPoint = "LogPCWDebugEvent", CharSet = CharSet.Unicode)] public static extern void LogPCWDebugEvent(string DebugString, Int64 qwDebugValue); public static void LogDebugEvent(String Message, Int64 DebugValue) { LogPCWDebugEvent(Message, DebugValue); } [DllImport("pcwutl.dll", EntryPoint = "SendSQMForTSRun", CharSet = CharSet.Unicode)] public static extern bool SendSQMForTSRun(uint LaunchedFrom, uint COSResponse, string COSLayers, string AppliedLayers, uint UserAction, uint NotUsed, uint ProblemFixed); public static void SendSqmForSession(uint LaunchedFrom, uint COSResponse, string COSLayers, string AppliedLayers, uint UserAction, uint NotUsed, uint ProblemFixed) { SendSQMForTSRun(LaunchedFrom, COSResponse, COSLayers, AppliedLayers, UserAction, NotUsed, ProblemFixed); LogPCWDebugEvent(String.Format("{0}, {1}, {2}, {3}, {4}, {5}, {6}", LaunchedFrom, COSResponse, COSLayers, AppliedLayers, UserAction, NotUsed, ProblemFixed), 0); } [DllImport("user32.dll", EntryPoint = "MessageBox", CharSet = CharSet.Unicode)] public static extern int MessageBox(uint hwnd, string Message, string Caption, uint Buttons); public static void ShowMessage(string Message) { MessageBox(0, Message, "Debug", 0); } } "@ 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() { #Select the xml appropriate for the binary type, and parse it into a list of choices #as expected by the diag framework $choices = New-Object System.Collections.ArrayList if(([System.IO.Path]::GetExtension($targetPath) -eq ".msi")) { $choiceDoc = [xml] $problemChoiceXmlMsi } 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. Vista or better has a different selection #than XP or earlier if ($isVistaPlus) { $DisplayModes = $VistaPlusDisplayMode } else { $DisplayModes = $AllDisplayModes } if(($DisplayModes.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) { #pull xml nodes from string declared above, parse it into array of dictionary objects $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 for the item $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.Contains($_)) { set-variable compatModeParam $CompatibilityModeStrings[$_] -scope global } if($AllDisplayModes.Contains($_)) { $displayMode = Get-Variable -name displayModeParam -valueOnly -scope global if($displayMode -eq $CompatibilityStrings.Display_Choice_DEFAULT) { $displayMode = [String]::Empty } if (-not($displayMode.Contains($CompatibilityModeStrings[$_]))) { 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 } } } } #alters the contents of $Env:RecommendedLayer based on if the exe is an executable or if it is a Vista+ era app function FilterRecommendedLayers([bool]$isExecutable, [bool]$isVistaPlus) { [string]$tempLayers = "" [string]$PreVistaDisplayMode = "256COLOR 16BITCOLOR 640X480" $Env:RecommendedLayer.Split(' ') | foreach { $Layer = $_ #Executables don't get the MSIAUTO layer if ($isExecutable -and ($Layer -eq "MSIAUTO")) { $Layer = "" } #Vista+ era apps don't get some display layers if ($isVistaPlus -and ($PreVistaDisplayMode.Contains($Layer))) { $Layer = "" } $tempLayers = "{0} {1}" -f $Layer, $tempLayers } $tempLayers = $tempLayers.Trim(' ') if ($tempLayers -eq "") { $Env:RecommendedLayer = "NONE" } else { $Env:RecommendedLayer = $tempLayers } } # This block of code sets up the manual troubleshooting portion. # $werUtilType = Add-Type -TypeDefinition $typeDefinition -PassThru -IgnoreWarnings $targetPath = $werUtilType::EscapePath($targetPath) if($targetPath -eq $null) { throw $CompatibilityStrings.Throw_INVALID_PATH } # Initialize 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 set-variable RecLayerIsCloudLayer $false -scope global set-variable isVistaPlus $false -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 } # This section will show the screen that asks if you want to do the recommended thing or the manual troubleshooting if($isExecutable) { $tsChoice = Get-DiagInput -id IT_AutoTroubleshoot } # if they chose the recommended layer or the app is an MSI, we will pick a recommended layer for them. # recommended layers come from (in order of precedence) # 1. COS recommendation # 2. Genome recommendation # 3. hardcoded value (WIN8RTM) # #Query app genome for genome layer and if the app is known Vista+ $genomeArray = $werUtilType::GetGenomeLayer($targetPath) Set-Variable -name isVistaPlus -value $genomeArray[1] -scope global FilterRecommendedLayers $isExecutable $isVistaPlus if ($Env:RecommendedLayer -eq "NONE") { $Env:RecommendedLayer = $genomeArray[0] if($Env:RecommendedLayer -eq [String]::Empty) { $Env:RecommendedLayer = "WIN8RTM" } } else { Set-Variable -name RecLayerIsCloudLayer $true -scope global } # If they chose the recommended layer, we do some processing to remove applied stuff if(($tsChoice -eq "ts_AUTO") -or -not($isExecutable)) { #For each layer in the recommended layer string (usually one, can be more) #we will add it to the layersToApply. We will remove all the other layers #from the app. if($isExecutable) { $Env:RecommendedLayer.Split(' ') | foreach { if ($AllTSLayers.Contains($_) -and (-not($layersToApply.Contains($_)))) { $layersToApply.Add($_) } } } else { #MSIs also get the RunAsAdmin layer $layersToApply.Add($RunAsAdminCompatMode) $layersToApply.Add("MSIAUTO") } $AllTSLayers.Split(' ') | foreach { if (-not($layersToApply.Contains($_))) { $layersToRemove.Add($_) } } 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) { #If this is a vista era or later application, the only display problem #we attempt to fix will be the high DPI aware issue if ($isVistaPlus) { #No interaction for this; just need to set the layer if(-not($originalCompatMode -match $VistaPlusDisplayMode)) { SetCompatMode $VistaPlusDisplayMode $true } set-Variable solutionSelected $true -scope global } else { GetDisplayLayers($true) } } else { 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 = "{0}\rundll32.exe {0}\pcwutl.dll,LaunchApplication `"{1}`"" -f [System.Environment]::SystemDirectory,$quotedPath #Make the registry entry $werUtilType::ApplyCompatMode($targetPath, $layersToApply, $layersToRemove, $RecLayerIsCloudLayer) 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`";" $title = $CompatibilityStrings.Text_AppName_Title $getDiagCmd+="`"AppName`"=`"$title $appName`";" 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 } } #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 } if ($verifyResponse -eq "Verify_TRYAGAIN") { $autoFix = $false $RecLayerIsCloudLayer = $false } } while($verifyResponse -eq "Verify_TRYAGAIN") #Send SQM about the TS session #Applied Layers in a space separated string $Env:SQMAppliedLayers = "" $layersToApply | foreach { $Env:SQMAppliedLayers = "{0} {1}" -f $_, $Env:SQMAppliedLayers $Env:SQMAppliedLayers = $Env:SQMAppliedLayers.TrimEnd(' ') } #Need to preserve this for SQM #Recommended layer (2) or did they manually troubleshoot (3) ? if ($autoFix) { $Env:SQMUserAction = 2 } else { $Env:SQMUserAction = 3 } #Was the problem solved? if ($verifyResponse -eq "Verify_YES") { #If the user said this fixed their problem, we note it so we can show 'fixed' at the end of the process (in the vf_ script) $Env:AppFixed = $true $Env:SQMProblemSolved = 1 } else { $Env:SQMProblemSolved = 0 } $werUtilType::SendSqmForSession($Env:SQMLaunchMethod, $Env:SQMCOSResponse, $Env:SQMCOSLayers, $Env:SQMAppliedLayers, $Env:SQMUserAction, 0, $Env:SQMProblemSolved) #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, $false) exit } Write-DiagProgress -activity $CompatibilityStrings.Text_Activity_SAVING -status $CompatibilityStrings.Text_Status_GENERATING #Get final state of compat mode $finalCompatMode = $werUtilType::GetExistingCompatMode($targetPath) #Get the applied compatibility modes as user-friendly strings $modesApplied = New-Object System.Collections.ArrayList foreach($layerApplied in $layersToApply) { if ($RunAsAdminCompatMode -eq $layerApplied) { $modesApplied.Add($CompatibilityStrings.Access_Choice_ADMIN) } else { $modesApplied.Add($CompatibilityModeStrings[$layerApplied]) } } #Push the compat mode settings into the diag report $fixesWorked = $false $fixVerified = $CompatibilityStrings.Text_Report_SolutionNo if ($verifyResponse -eq "Verify_YES") { $fixesWorked = $true $fixVerified = $CompatibilityStrings.Text_Report_SolutionYes } $modesApplied.Add($fixVerified) #Add fix verification to modes applied because Update-DiagReport only seems to accept one update $modesApplied | convertto-xml | Update-DiagReport -id compatMode -name $CompatibilityStrings.Text_Report_CompatName -description $CompatibilityStrings.Text_Report_CompatDesc -verbosity Informational #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 $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) } }