diff --git a/src/cascadia/CascadiaPackage/ProfileIcons/Powershell_black_64.png b/src/cascadia/CascadiaPackage/ProfileIcons/Powershell_black_64.png
new file mode 100644
index 00000000000..53bbbee10b7
Binary files /dev/null and b/src/cascadia/CascadiaPackage/ProfileIcons/Powershell_black_64.png differ
diff --git a/src/cascadia/TerminalApp/TabManagement.cpp b/src/cascadia/TerminalApp/TabManagement.cpp
index 3b2691df936..150c049e6bd 100644
--- a/src/cascadia/TerminalApp/TabManagement.cpp
+++ b/src/cascadia/TerminalApp/TabManagement.cpp
@@ -77,6 +77,16 @@ namespace winrt::TerminalApp::implementation
}
const auto settings{ TerminalSettings::CreateWithNewTerminalArgs(_settings, newTerminalArgs, *_bindings) };
+ if (profile.Source() == L"Windows.Terminal.InstallPowerShell")
+ {
+ TraceLoggingWrite(
+ g_hTerminalAppProvider,
+ "InstallPowerShellStubInvoked",
+ TraceLoggingDescription("Event emitted when the 'Install Latest PowerShell' stub was invoked"),
+ TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES),
+ TelemetryPrivacyDataTag(PDT_ProductAndServiceUsage));
+ }
+
// Try to handle auto-elevation
if (_maybeElevate(newTerminalArgs, settings, profile))
{
diff --git a/src/cascadia/TerminalSettingsEditor/Extensions.xaml b/src/cascadia/TerminalSettingsEditor/Extensions.xaml
index b7a1296f567..3f5241e1ec9 100644
--- a/src/cascadia/TerminalSettingsEditor/Extensions.xaml
+++ b/src/cascadia/TerminalSettingsEditor/Extensions.xaml
@@ -156,7 +156,8 @@
x:Uid="Extensions_NavigateToProfileButton"
Click="NavigateToProfile_Click"
Style="{StaticResource SettingContainerResetButtonStyle}"
- Tag="{x:Bind Profile.Guid}">
+ Tag="{x:Bind Profile.Guid}"
+ Visibility="{x:Bind mtu:Converters.InvertedBooleanToVisibility(Profile.Deleted)}">
diff --git a/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp
index 9401c0137d3..65595f787f8 100644
--- a/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp
+++ b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp
@@ -31,7 +31,7 @@ std::wstring_view AzureCloudShellGenerator::GetDisplayName() const noexcept
// -
// Return Value:
// - a vector with the Azure Cloud Shell connection profile, if available.
-void AzureCloudShellGenerator::GenerateProfiles(std::vector>& profiles) const
+void AzureCloudShellGenerator::GenerateProfiles(std::vector>& profiles)
{
if (AzureConnection::IsAzureConnectionAvailable())
{
diff --git a/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.h b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.h
index 2f61624bc6f..28b79e93010 100644
--- a/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.h
+++ b/src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.h
@@ -27,6 +27,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model
std::wstring_view GetNamespace() const noexcept override;
std::wstring_view GetDisplayName() const noexcept override;
std::wstring_view GetIcon() const noexcept override { return {}; };
- void GenerateProfiles(std::vector>& profiles) const override;
+ void GenerateProfiles(std::vector>& profiles) override;
};
};
diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
index 97b652a5aaa..8fc99ac9fa2 100644
--- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
+++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
@@ -144,7 +144,7 @@ Model::CascadiaSettings CascadiaSettings::Copy() const
Model::FragmentSettings FragmentSettings::Copy() const
{
- auto fragment{ winrt::make_self(_source, _json, _jsonSource) };
+ auto fragment{ winrt::make_self(_source, _Json, _jsonSource) };
std::vector modifiedProfiles;
modifiedProfiles.reserve(_modifiedProfiles.Size());
diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h
index 88a3133f96f..07cdc42dde4 100644
--- a/src/cascadia/TerminalSettingsModel/CascadiaSettings.h
+++ b/src/cascadia/TerminalSettingsModel/CascadiaSettings.h
@@ -123,7 +123,8 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
void _appendProfile(winrt::com_ptr&& profile, const winrt::guid& guid, ParsedSettings& settings);
void _addUserProfileParent(const winrt::com_ptr& profile);
bool _addOrMergeUserColorScheme(const winrt::com_ptr& colorScheme);
- void _executeGenerator(const IDynamicProfileGenerator& generator);
+ void _executeGenerator(IDynamicProfileGenerator& generator);
+ void _cleanupPowerShellInstaller(bool isPowerShellInstalled);
winrt::com_ptr _registerFragment(const winrt::Microsoft::Terminal::Settings::Model::FragmentSettings& fragment, FragmentScope scope);
std::unordered_set _ignoredNamespaces;
@@ -237,14 +238,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
public:
FragmentProfileEntry(winrt::guid profileGuid, hstring json) :
_profileGuid{ profileGuid },
- _json{ json } {}
+ _Json{ json } {}
winrt::guid ProfileGuid() const noexcept { return _profileGuid; }
- hstring Json() const noexcept { return _json; }
+ WINRT_PROPERTY(hstring, Json);
private:
winrt::guid _profileGuid;
- hstring _json;
};
struct FragmentColorSchemeEntry : FragmentColorSchemeEntryT
@@ -268,7 +268,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
public:
FragmentSettings(hstring source, hstring json, hstring jsonSource) :
_source{ source },
- _json{ json },
+ _Json{ json },
_jsonSource{ jsonSource },
_modifiedProfiles{ winrt::single_threaded_vector() },
_newProfiles{ winrt::single_threaded_vector() },
@@ -277,12 +277,13 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
Model::FragmentSettings Copy() const;
hstring Source() const noexcept { return _source; }
- hstring Json() const noexcept { return _json; }
hstring JsonSource() const noexcept { return _jsonSource; }
Windows::Foundation::Collections::IVector ModifiedProfiles() const noexcept { return _modifiedProfiles; }
Windows::Foundation::Collections::IVector NewProfiles() const noexcept { return _newProfiles; }
Windows::Foundation::Collections::IVector ColorSchemes() const noexcept { return _colorSchemes; }
+ WINRT_PROPERTY(hstring, Json);
+ public:
// views
Windows::Foundation::Collections::IVectorView ModifiedProfilesView() const noexcept { return _modifiedProfiles.GetView(); }
Windows::Foundation::Collections::IVectorView NewProfilesView() const noexcept { return _newProfiles.GetView(); }
@@ -290,7 +291,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
private:
hstring _source;
- hstring _json;
hstring _jsonSource;
Windows::Foundation::Collections::IVector _modifiedProfiles;
Windows::Foundation::Collections::IVector _newProfiles;
diff --git a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp
index 2a2d9af5c09..e47779cce91 100644
--- a/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp
+++ b/src/cascadia/TerminalSettingsModel/CascadiaSettingsSerialization.cpp
@@ -19,6 +19,7 @@
#if TIL_FEATURE_DYNAMICSSHPROFILES_ENABLED
#include "SshHostGenerator.h"
#endif
+#include "PowershellInstallationProfileGenerator.h"
#include "ApplicationState.h"
#include "DefaultTerminal.h"
@@ -178,13 +179,77 @@ SettingsLoader::SettingsLoader(const std::string_view& userJSON, const std::stri
// (meaning profiles specified by the application rather by the user).
void SettingsLoader::GenerateProfiles()
{
- _executeGenerator(PowershellCoreProfileGenerator{});
- _executeGenerator(WslDistroGenerator{});
- _executeGenerator(AzureCloudShellGenerator{});
- _executeGenerator(VisualStudioGenerator{});
+ PowershellCoreProfileGenerator powerShellGenerator{};
+ _executeGenerator(powerShellGenerator);
+
+ WslDistroGenerator wslGenerator{};
+ _executeGenerator(wslGenerator);
+
+ AzureCloudShellGenerator acsGenerator{};
+ _executeGenerator(acsGenerator);
+
+ VisualStudioGenerator vsGenerator{};
+ _executeGenerator(vsGenerator);
+
#if TIL_FEATURE_DYNAMICSSHPROFILES_ENABLED
- _executeGenerator(SshHostGenerator{});
+ SshHostGenerator sshGenerator{};
+ _executeGenerator(sshGenerator);
#endif
+
+ PowershellInstallationProfileGenerator pwshInstallationGenerator{};
+ _executeGenerator(pwshInstallationGenerator);
+
+ _cleanupPowerShellInstaller(!powerShellGenerator.GetPowerShellInstances().empty());
+}
+
+// Retrieve the "Install Latest PowerShell" profile and...
+// - add a comment to the JSON to indicate it's conditionally applied
+// - (if PowerShell is installed) mark it for deletion
+void SettingsLoader::_cleanupPowerShellInstaller(bool isPowerShellInstalled)
+{
+ const hstring pwshInstallerNamespace{ PowershellInstallationProfileGenerator::Namespace };
+ if (extensionPackageMap.contains(pwshInstallerNamespace))
+ {
+ if (const auto& fragExtList = extensionPackageMap[pwshInstallerNamespace]->Fragments(); fragExtList.Size() > 0)
+ {
+ Json::StreamWriterBuilder styledWriter;
+ styledWriter["indentation"] = " ";
+ styledWriter["commentStyle"] = "All";
+
+ auto fragExt = get_self(fragExtList.GetAt(0));
+
+ // We want the comment to be the first thing in the object,
+ // "closeOnExit" is the first property, so target that.
+ auto fragExtJson = _parseJSON(til::u16u8(fragExt->Json()));
+ fragExtJson[JsonKey(ProfilesKey)][0]["closeOnExit"].setComment(til::u16u8(fmt::format(FMT_COMPILE(L"// {}"), RS_(L"PowerShellInstallationProfileJsonComment"))), Json::CommentPlacement::commentBefore);
+ fragExt->Json(hstring{ til::u8u16(Json::writeString(styledWriter, fragExtJson)) });
+
+ if (const auto& profileEntryList = fragExt->NewProfilesView(); profileEntryList.Size() > 0)
+ {
+ auto profileEntry = get_self(profileEntryList.GetAt(0));
+
+ // We want the comment to be the first thing in the object,
+ // "closeOnExit" is the first property, so target that.
+ auto profileJson = _parseJSON(til::u16u8(profileEntry->Json()));
+ profileJson["closeOnExit"].setComment(til::u16u8(fmt::format(FMT_COMPILE(L"// {}"), RS_(L"PowerShellInstallationProfileJsonComment"))), Json::CommentPlacement::commentBefore);
+ profileEntry->Json(hstring{ til::u8u16(Json::writeString(styledWriter, profileJson)) });
+
+ // If PowerShell is installed, mark the installer profile for deletion
+ if (isPowerShellInstalled)
+ {
+ const auto profileGuid = profileEntryList.GetAt(0).ProfileGuid();
+ for (const auto& profile : userSettings.profiles)
+ {
+ if (profile->Guid() == profileGuid)
+ {
+ profile->Deleted(true);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
}
// A new settings.json gets a special treatment:
@@ -993,7 +1058,7 @@ bool SettingsLoader::_addOrMergeUserColorScheme(const winrt::com_ptr> generatedProfiles;
@@ -1590,7 +1655,11 @@ void CascadiaSettings::_resolveNewTabMenuProfiles() const
auto activeProfileCount = gsl::narrow_cast(_activeProfiles.Size());
for (auto profileIndex = 0; profileIndex < activeProfileCount; profileIndex++)
{
- remainingProfilesMap.emplace(profileIndex, _activeProfiles.GetAt(profileIndex));
+ const auto& profile = _activeProfiles.GetAt(profileIndex);
+ if (!profile.Deleted())
+ {
+ remainingProfilesMap.emplace(profileIndex, _activeProfiles.GetAt(profileIndex));
+ }
}
// We keep track of the "remaining profiles" - those that have not yet been resolved
diff --git a/src/cascadia/TerminalSettingsModel/IDynamicProfileGenerator.h b/src/cascadia/TerminalSettingsModel/IDynamicProfileGenerator.h
index 9144bcb3259..5ea68f2e3bd 100644
--- a/src/cascadia/TerminalSettingsModel/IDynamicProfileGenerator.h
+++ b/src/cascadia/TerminalSettingsModel/IDynamicProfileGenerator.h
@@ -32,6 +32,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model
virtual std::wstring_view GetNamespace() const noexcept = 0;
virtual std::wstring_view GetDisplayName() const noexcept = 0;
virtual std::wstring_view GetIcon() const noexcept = 0;
- virtual void GenerateProfiles(std::vector>& profiles) const = 0;
+ virtual void GenerateProfiles(std::vector>& profiles) = 0;
};
};
diff --git a/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj
index adf1610f5e1..9b8937a4a5a 100644
--- a/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj
+++ b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj
@@ -90,6 +90,7 @@
KeyChordSerialization.idl
+
Profile.idl
@@ -167,6 +168,7 @@
KeyChordSerialization.idl
+
Profile.idl
diff --git a/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj.filters b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj.filters
index 3933a242819..be3dd79437f 100644
--- a/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj.filters
+++ b/src/cascadia/TerminalSettingsModel/Microsoft.Terminal.Settings.ModelLib.vcxproj.filters
@@ -15,6 +15,9 @@
profileGeneration
+
+ profileGeneration
+
profileGeneration
@@ -57,6 +60,9 @@
profileGeneration
+
+ profileGeneration
+
profileGeneration
diff --git a/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp
index 196dc7b36a0..8ea4ab35f2a 100644
--- a/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp
+++ b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.cpp
@@ -24,336 +24,301 @@ static constexpr std::wstring_view POWERSHELL_ICON{ L"ms-appx:///ProfileIcons/pw
static constexpr std::wstring_view POWERSHELL_PREVIEW_ICON{ L"ms-appx:///ProfileIcons/pwsh-preview.png" };
static constexpr std::wstring_view POWERSHELL_PREFERRED_PROFILE_NAME{ L"PowerShell" };
-namespace
+using namespace ::Microsoft::Terminal::Settings::Model;
+
+namespace winrt::Microsoft::Terminal::Settings::Model
{
- enum PowerShellFlags
+ DEFINE_ENUM_FLAG_OPERATORS(PowershellCoreProfileGenerator::PowerShellFlags);
+
+ constexpr bool PowershellCoreProfileGenerator::PowerShellInstance::operator<(const PowerShellInstance& second) const
{
- None = 0,
-
- // These flags are used as a sort key, so they encode some native ordering.
- // They are ordered such that the "most important" flags have the largest
- // impact on the sort space. For example, since we want Preview to be very polar
- // we give it the highest flag value.
- // The "ideal" powershell instance has 0 flags (stable, native, Program Files location)
- //
- // With this ordering, the sort space ends up being (for PowerShell 6)
- // (numerically greater values are on the left; this is flipped in the final sort)
- //
- // <-- Less Valued .................................... More Valued -->
- // | All instances of PS 6 | All PS7 |
- // | Preview | Stable | ~~~ |
- // | Non-Native | Native | Non-Native | Native | ~~~ |
- // | Trd | Pack | Trd | Pack | Trd | Pack | Trd | Pack | ~~~ |
- // (where Pack is a stand-in for store, scoop, dotnet, though they have their own orders,
- // and Trd is a stand-in for "Traditional" (Program Files))
- //
- // In short, flags with larger magnitudes are pushed further down (therefore valued less)
-
- // distribution method (choose one)
- Store = 1 << 0, // distributed via the store
- Scoop = 1 << 1, // installed via Scoop
- Dotnet = 1 << 2, // installed as a dotnet global tool
- Traditional = 1 << 3, // installed in traditional Program Files locations
-
- // native architecture (choose one)
- WOWARM = 1 << 4, // non-native (Windows-on-Windows, ARM variety)
- WOWx86 = 1 << 5, // non-native (Windows-on-Windows, x86 variety)
-
- // build type (choose one)
- Preview = 1 << 6, // preview version
- };
- DEFINE_ENUM_FLAG_OPERATORS(PowerShellFlags);
-
- struct PowerShellInstance
+ if (majorVersion != second.majorVersion)
+ {
+ return majorVersion < second.majorVersion;
+ }
+ if (flags != second.flags)
+ {
+ return flags > second.flags; // flags are inverted because "0" is ideal; see above
+ }
+ return executablePath < second.executablePath; // fall back to path sorting
+ }
+
+ // Method Description:
+ // - Generates a name, based on flags, for a powershell instance.
+ // Return value:
+ // - the name
+ std::wstring PowershellCoreProfileGenerator::PowerShellInstance::Name() const
{
- int majorVersion; // 0 = we don't know, sort last.
- PowerShellFlags flags;
- std::filesystem::path executablePath;
+ std::wstringstream namestream;
+ namestream << L"PowerShell";
- constexpr bool operator<(const PowerShellInstance& second) const
+ if (WI_IsFlagSet(flags, PowerShellFlags::Store))
{
- if (majorVersion != second.majorVersion)
+ if (WI_IsFlagSet(flags, PowerShellFlags::Preview))
{
- return majorVersion < second.majorVersion;
+ namestream << L" Preview";
}
- if (flags != second.flags)
- {
- return flags > second.flags; // flags are inverted because "0" is ideal; see above
- }
- return executablePath < second.executablePath; // fall back to path sorting
+ namestream << L" (msix)";
}
-
- // Method Description:
- // - Generates a name, based on flags, for a powershell instance.
- // Return value:
- // - the name
- std::wstring Name() const
+ else if (WI_IsFlagSet(flags, PowerShellFlags::Dotnet))
{
- std::wstringstream namestream;
- namestream << L"PowerShell";
-
- if (WI_IsFlagSet(flags, PowerShellFlags::Store))
+ namestream << L" (dotnet global)";
+ }
+ else if (WI_IsFlagSet(flags, PowerShellFlags::Scoop))
+ {
+ namestream << L" (scoop)";
+ }
+ else
+ {
+ if (majorVersion < 7)
{
- if (WI_IsFlagSet(flags, PowerShellFlags::Preview))
- {
- namestream << L" Preview";
- }
- namestream << L" (msix)";
+ namestream << L" Core";
}
- else if (WI_IsFlagSet(flags, PowerShellFlags::Dotnet))
+ if (majorVersion != 0)
{
- namestream << L" (dotnet global)";
+ namestream << L" " << majorVersion;
}
- else if (WI_IsFlagSet(flags, PowerShellFlags::Scoop))
+ if (WI_IsFlagSet(flags, PowerShellFlags::Preview))
{
- namestream << L" (scoop)";
+ namestream << L" Preview";
}
- else
+ if (WI_IsFlagSet(flags, PowerShellFlags::WOWx86))
{
- if (majorVersion < 7)
- {
- namestream << L" Core";
- }
- if (majorVersion != 0)
- {
- namestream << L" " << majorVersion;
- }
- if (WI_IsFlagSet(flags, PowerShellFlags::Preview))
- {
- namestream << L" Preview";
- }
- if (WI_IsFlagSet(flags, PowerShellFlags::WOWx86))
- {
- namestream << L" (x86)";
- }
- if (WI_IsFlagSet(flags, PowerShellFlags::WOWARM))
- {
- namestream << L" (ARM)";
- }
+ namestream << L" (x86)";
+ }
+ if (WI_IsFlagSet(flags, PowerShellFlags::WOWARM))
+ {
+ namestream << L" (ARM)";
}
- return namestream.str();
}
- };
-}
+ return namestream.str();
+ }
-using namespace ::Microsoft::Terminal::Settings::Model;
-using namespace winrt::Microsoft::Terminal::Settings::Model;
-
-// Function Description:
-// - Finds all powershell instances with the traditional layout under a directory.
-// - The "traditional" directory layout requires that pwsh.exe exist in a versioned directory, as in
-// ROOT\6\pwsh.exe
-// Arguments:
-// - directory: the directory under which to search
-// - flags: flags to apply to all found instances
-// - out: the list into which to accumulate these instances.
-static void _accumulateTraditionalLayoutPowerShellInstancesInDirectory(std::wstring_view directory, PowerShellFlags flags, std::vector& out)
-{
- const std::filesystem::path root{ wil::ExpandEnvironmentStringsW(directory.data()) };
- if (std::filesystem::exists(root))
+ // Function Description:
+ // - Finds all powershell instances with the traditional layout under a directory.
+ // - The "traditional" directory layout requires that pwsh.exe exist in a versioned directory, as in
+ // ROOT\6\pwsh.exe
+ // Arguments:
+ // - directory: the directory under which to search
+ // - flags: flags to apply to all found instances
+ // - out: the list into which to accumulate these instances.
+ static void _accumulateTraditionalLayoutPowerShellInstancesInDirectory(std::wstring_view directory, PowershellCoreProfileGenerator::PowerShellFlags flags, std::vector& out)
{
- for (const auto& versionedDir : std::filesystem::directory_iterator(root))
+ const std::filesystem::path root{ wil::ExpandEnvironmentStringsW(directory.data()) };
+ if (std::filesystem::exists(root))
{
- const auto versionedPath = versionedDir.path();
- const auto executable = versionedPath / PWSH_EXE;
- if (std::filesystem::exists(executable))
+ for (const auto& versionedDir : std::filesystem::directory_iterator(root))
{
- const auto preview = versionedPath.filename().native().find(L"-preview") != std::wstring::npos;
- const auto previewFlag = preview ? PowerShellFlags::Preview : PowerShellFlags::None;
- out.emplace_back(PowerShellInstance{ std::stoi(versionedPath.filename()),
- PowerShellFlags::Traditional | flags | previewFlag,
- executable });
+ const auto versionedPath = versionedDir.path();
+ const auto executable = versionedPath / PWSH_EXE;
+ if (std::filesystem::exists(executable))
+ {
+ const auto preview = versionedPath.filename().native().find(L"-preview") != std::wstring::npos;
+ const auto previewFlag = preview ? PowershellCoreProfileGenerator::PowerShellFlags::Preview : PowershellCoreProfileGenerator::PowerShellFlags::None;
+ out.emplace_back(PowershellCoreProfileGenerator::PowerShellInstance{ std::stoi(versionedPath.filename()),
+ PowershellCoreProfileGenerator::PowerShellFlags::Traditional | flags | previewFlag,
+ executable });
+ }
}
}
}
-}
-// Function Description:
-// - Finds the store package, if one exists, for a given package family name
-// Arguments:
-// - packageFamilyName: the package family name
-// Return Value:
-// - a package, or nullptr.
-static winrt::Windows::ApplicationModel::Package _getStorePackage(const std::wstring_view packageFamilyName) noexcept
-try
-{
- winrt::Windows::Management::Deployment::PackageManager packageManager;
- auto foundPackages = packageManager.FindPackagesForUser(L"", packageFamilyName);
- auto iterator = foundPackages.First();
- if (!iterator.HasCurrent())
+ // Function Description:
+ // - Finds the store package, if one exists, for a given package family name
+ // Arguments:
+ // - packageFamilyName: the package family name
+ // Return Value:
+ // - a package, or nullptr.
+ static winrt::Windows::ApplicationModel::Package _getStorePackage(const std::wstring_view packageFamilyName) noexcept
+ try
{
+ winrt::Windows::Management::Deployment::PackageManager packageManager;
+ auto foundPackages = packageManager.FindPackagesForUser(L"", packageFamilyName);
+ auto iterator = foundPackages.First();
+ if (!iterator.HasCurrent())
+ {
+ return nullptr;
+ }
+ return iterator.Current();
+ }
+ catch (...)
+ {
+ LOG_CAUGHT_EXCEPTION();
return nullptr;
}
- return iterator.Current();
-}
-catch (...)
-{
- LOG_CAUGHT_EXCEPTION();
- return nullptr;
-}
-// Function Description:
-// - Finds all powershell instances that have App Execution Aliases in the standard location
-// Arguments:
-// - out: the list into which to accumulate these instances.
-static void _accumulateStorePowerShellInstances(std::vector& out)
-{
- wil::unique_cotaskmem_string localAppDataFolder;
- if (FAILED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &localAppDataFolder)))
+ // Function Description:
+ // - Finds all powershell instances that have App Execution Aliases in the standard location
+ // Arguments:
+ // - out: the list into which to accumulate these instances.
+ static void _accumulateStorePowerShellInstances(std::vector& out)
{
- return;
- }
+ wil::unique_cotaskmem_string localAppDataFolder;
+ if (FAILED(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &localAppDataFolder)))
+ {
+ return;
+ }
- std::filesystem::path appExecAliasPath{ localAppDataFolder.get() };
- appExecAliasPath /= L"Microsoft";
- appExecAliasPath /= L"WindowsApps";
+ std::filesystem::path appExecAliasPath{ localAppDataFolder.get() };
+ appExecAliasPath /= L"Microsoft";
+ appExecAliasPath /= L"WindowsApps";
- if (std::filesystem::exists(appExecAliasPath))
- {
- // App execution aliases for preview powershell
- const auto previewPath = appExecAliasPath / POWERSHELL_PREVIEW_PFN;
- if (std::filesystem::exists(previewPath))
+ if (std::filesystem::exists(appExecAliasPath))
{
- const auto previewPackage = _getStorePackage(POWERSHELL_PREVIEW_PFN);
- if (previewPackage)
+ // App execution aliases for preview powershell
+ const auto previewPath = appExecAliasPath / POWERSHELL_PREVIEW_PFN;
+ if (std::filesystem::exists(previewPath))
{
- out.emplace_back(PowerShellInstance{
- gsl::narrow_cast(previewPackage.Id().Version().Major),
- PowerShellFlags::Store | PowerShellFlags::Preview,
- previewPath / PWSH_EXE });
+ const auto previewPackage = _getStorePackage(POWERSHELL_PREVIEW_PFN);
+ if (previewPackage)
+ {
+ out.emplace_back(PowershellCoreProfileGenerator::PowerShellInstance{
+ gsl::narrow_cast(previewPackage.Id().Version().Major),
+ PowershellCoreProfileGenerator::PowerShellFlags::Store | PowershellCoreProfileGenerator::PowerShellFlags::Preview,
+ previewPath / PWSH_EXE });
+ }
}
- }
- // App execution aliases for stable powershell
- const auto gaPath = appExecAliasPath / POWERSHELL_PFN;
- if (std::filesystem::exists(gaPath))
- {
- const auto gaPackage = _getStorePackage(POWERSHELL_PFN);
- if (gaPackage)
+ // App execution aliases for stable powershell
+ const auto gaPath = appExecAliasPath / POWERSHELL_PFN;
+ if (std::filesystem::exists(gaPath))
{
- out.emplace_back(PowerShellInstance{
- gaPackage.Id().Version().Major,
- PowerShellFlags::Store,
- gaPath / PWSH_EXE,
- });
+ const auto gaPackage = _getStorePackage(POWERSHELL_PFN);
+ if (gaPackage)
+ {
+ out.emplace_back(PowershellCoreProfileGenerator::PowerShellInstance{
+ gaPackage.Id().Version().Major,
+ PowershellCoreProfileGenerator::PowerShellFlags::Store,
+ gaPath / PWSH_EXE,
+ });
+ }
}
}
}
-}
-// Function Description:
-// - Finds a powershell instance that's just a pwsh.exe in a folder.
-// - This function cannot determine the version number of such a powershell instance.
-// Arguments:
-// - directory: the directory under which to search
-// - flags: flags to apply to all found instances
-// - out: the list into which to accumulate these instances.
-static void _accumulatePwshExeInDirectory(const std::wstring_view directory, const PowerShellFlags flags, std::vector& out)
-{
- const std::filesystem::path root{ wil::ExpandEnvironmentStringsW(directory.data()) };
- const auto pwshPath = root / PWSH_EXE;
- if (std::filesystem::exists(pwshPath))
+ // Function Description:
+ // - Finds a powershell instance that's just a pwsh.exe in a folder.
+ // - This function cannot determine the version number of such a powershell instance.
+ // Arguments:
+ // - directory: the directory under which to search
+ // - flags: flags to apply to all found instances
+ // - out: the list into which to accumulate these instances.
+ static void _accumulatePwshExeInDirectory(const std::wstring_view directory, const PowershellCoreProfileGenerator::PowerShellFlags flags, std::vector& out)
{
- out.emplace_back(PowerShellInstance{ 0 /* we can't tell */, flags, pwshPath });
+ const std::filesystem::path root{ wil::ExpandEnvironmentStringsW(directory.data()) };
+ const auto pwshPath = root / PWSH_EXE;
+ if (std::filesystem::exists(pwshPath))
+ {
+ out.emplace_back(PowershellCoreProfileGenerator::PowerShellInstance{ 0 /* we can't tell */, flags, pwshPath });
+ }
}
-}
-// Function Description:
-// - Builds a comprehensive priority-ordered list of powershell instances.
-// Return value:
-// - a comprehensive priority-ordered list of powershell instances.
-static std::vector _collectPowerShellInstances()
-{
- std::vector versions;
+ // Function Description:
+ // - Builds a comprehensive priority-ordered list of powershell instances.
+ // Return value:
+ // - a comprehensive priority-ordered list of powershell instances.
+ static std::vector _collectPowerShellInstances()
+ {
+ std::vector versions;
- _accumulateTraditionalLayoutPowerShellInstancesInDirectory(L"%ProgramFiles%\\PowerShell", PowerShellFlags::None, versions);
+ _accumulateTraditionalLayoutPowerShellInstancesInDirectory(L"%ProgramFiles%\\PowerShell", PowershellCoreProfileGenerator::PowerShellFlags::None, versions);
#if defined(_M_AMD64) || defined(_M_ARM64) // No point in looking for WOW if we're not somewhere it exists
- _accumulateTraditionalLayoutPowerShellInstancesInDirectory(L"%ProgramFiles(x86)%\\PowerShell", PowerShellFlags::WOWx86, versions);
+ _accumulateTraditionalLayoutPowerShellInstancesInDirectory(L"%ProgramFiles(x86)%\\PowerShell", PowershellCoreProfileGenerator::PowerShellFlags::WOWx86, versions);
#endif
#if defined(_M_ARM64) // no point in looking for WOA if we're not on ARM64
- _accumulateTraditionalLayoutPowerShellInstancesInDirectory(L"%ProgramFiles(Arm)%\\PowerShell", PowerShellFlags::WOWARM, versions);
+ _accumulateTraditionalLayoutPowerShellInstancesInDirectory(L"%ProgramFiles(Arm)%\\PowerShell", PowerShellFlags::WOWARM, versions);
#endif
- _accumulateStorePowerShellInstances(versions);
+ _accumulateStorePowerShellInstances(versions);
- _accumulatePwshExeInDirectory(L"%USERPROFILE%\\.dotnet\\tools", PowerShellFlags::Dotnet, versions);
- _accumulatePwshExeInDirectory(L"%USERPROFILE%\\scoop\\shims", PowerShellFlags::Scoop, versions);
+ _accumulatePwshExeInDirectory(L"%USERPROFILE%\\.dotnet\\tools", PowershellCoreProfileGenerator::PowerShellFlags::Dotnet, versions);
+ _accumulatePwshExeInDirectory(L"%USERPROFILE%\\scoop\\shims", PowershellCoreProfileGenerator::PowerShellFlags::Scoop, versions);
- std::sort(versions.rbegin(), versions.rend()); // sort in reverse (best first)
+ std::sort(versions.rbegin(), versions.rend()); // sort in reverse (best first)
- return versions;
-}
-
-// Legacy GUIDs:
-// - PowerShell Core 574e775e-4f2a-5b96-ac1e-a2962a402336
-static constexpr winrt::guid PowershellCoreGuid{ 0x574e775e, 0x4f2a, 0x5b96, { 0xac, 0x1e, 0xa2, 0x96, 0x2a, 0x40, 0x23, 0x36 } };
+ return versions;
+ }
-std::wstring_view PowershellCoreProfileGenerator::GetNamespace() const noexcept
-{
- return PowershellCoreGeneratorNamespace;
-}
+ // Legacy GUIDs:
+ // - PowerShell Core 574e775e-4f2a-5b96-ac1e-a2962a402336
+ static constexpr winrt::guid PowershellCoreGuid{ 0x574e775e, 0x4f2a, 0x5b96, { 0xac, 0x1e, 0xa2, 0x96, 0x2a, 0x40, 0x23, 0x36 } };
-std::wstring_view PowershellCoreProfileGenerator::GetDisplayName() const noexcept
-{
- return RS_(L"PowershellCoreProfileGeneratorDisplayName");
-}
+ std::wstring_view PowershellCoreProfileGenerator::GetNamespace() const noexcept
+ {
+ return PowershellCoreGeneratorNamespace;
+ }
-std::wstring_view PowershellCoreProfileGenerator::GetIcon() const noexcept
-{
- return POWERSHELL_ICON;
-}
+ std::wstring_view PowershellCoreProfileGenerator::GetDisplayName() const noexcept
+ {
+ return RS_(L"PowershellCoreProfileGeneratorDisplayName");
+ }
-// Method Description:
-// - Checks if pwsh is installed, and if it is, creates a profile to launch it.
-// Arguments:
-// -
-// Return Value:
-// - a vector with the PowerShell Core profile, if available.
-void PowershellCoreProfileGenerator::GenerateProfiles(std::vector>& profiles) const
-{
- const auto psInstances = _collectPowerShellInstances();
- auto first = true;
+ std::wstring_view PowershellCoreProfileGenerator::GetIcon() const noexcept
+ {
+ return POWERSHELL_ICON;
+ }
- for (const auto& psI : psInstances)
+ // Method Description:
+ // - Checks if pwsh is installed, and if it is, creates a profile to launch it.
+ // Arguments:
+ // -
+ // Return Value:
+ // - a vector with the PowerShell Core profile, if available.
+ void PowershellCoreProfileGenerator::GenerateProfiles(std::vector>& profiles)
{
- const auto name = psI.Name();
- auto profile{ CreateDynamicProfile(name) };
-
- const auto& unquotedCommandline = psI.executablePath.native();
- std::wstring quotedCommandline;
- quotedCommandline.reserve(unquotedCommandline.size() + 2);
- quotedCommandline.push_back(L'"');
- quotedCommandline.append(unquotedCommandline);
- quotedCommandline.push_back(L'"');
- profile->Commandline(winrt::hstring{ quotedCommandline });
-
- profile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
- profile->DefaultAppearance().DarkColorSchemeName(L"Campbell");
- profile->DefaultAppearance().LightColorSchemeName(L"Campbell");
- profile->Icon(winrt::hstring{ WI_IsFlagSet(psI.flags, PowerShellFlags::Preview) ? POWERSHELL_PREVIEW_ICON : POWERSHELL_ICON });
-
- if (first)
+ GetPowerShellInstances();
+ auto first = true;
+
+ for (const auto& psI : _powerShellInstances)
{
- // Give the first ("algorithmically best") profile the official, and original, "PowerShell Core" GUID.
- // This will turn the anchored default profile into "PowerShell Core Latest for Native Architecture through Store"
- // (or the closest approximation thereof). It may choose a preview instance as the "best" if it is a higher version.
- profile->Guid(PowershellCoreGuid);
- profile->Name(winrt::hstring{ POWERSHELL_PREFERRED_PROFILE_NAME });
+ const auto name = psI.Name();
+ auto profile{ CreateDynamicProfile(name) };
+
+ const auto& unquotedCommandline = psI.executablePath.native();
+ std::wstring quotedCommandline;
+ quotedCommandline.reserve(unquotedCommandline.size() + 2);
+ quotedCommandline.push_back(L'"');
+ quotedCommandline.append(unquotedCommandline);
+ quotedCommandline.push_back(L'"');
+ profile->Commandline(winrt::hstring{ quotedCommandline });
+
+ profile->StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY });
+ profile->DefaultAppearance().DarkColorSchemeName(L"Campbell");
+ profile->DefaultAppearance().LightColorSchemeName(L"Campbell");
+ profile->Icon(winrt::hstring{ WI_IsFlagSet(psI.flags, PowerShellFlags::Preview) ? POWERSHELL_PREVIEW_ICON : POWERSHELL_ICON });
+
+ if (first)
+ {
+ // Give the first ("algorithmically best") profile the official, and original, "PowerShell Core" GUID.
+ // This will turn the anchored default profile into "PowerShell Core Latest for Native Architecture through Store"
+ // (or the closest approximation thereof). It may choose a preview instance as the "best" if it is a higher version.
+ profile->Guid(PowershellCoreGuid);
+ profile->Name(winrt::hstring{ POWERSHELL_PREFERRED_PROFILE_NAME });
+
+ first = false;
+ }
- first = false;
+ profiles.emplace_back(std::move(profile));
}
+ }
- profiles.emplace_back(std::move(profile));
+ std::vector PowershellCoreProfileGenerator::GetPowerShellInstances() noexcept
+ {
+ if (_powerShellInstances.empty())
+ {
+ _powerShellInstances = _collectPowerShellInstances();
+ }
+ return _powerShellInstances;
}
-}
-// Function Description:
-// - Returns the thing it's named for.
-// Return value:
-// - the thing it says in the name
-const std::wstring_view PowershellCoreProfileGenerator::GetPreferredPowershellProfileName()
-{
- return POWERSHELL_PREFERRED_PROFILE_NAME;
+ // Function Description:
+ // - Returns the thing it's named for.
+ // Return value:
+ // - the thing it says in the name
+ const std::wstring_view PowershellCoreProfileGenerator::GetPreferredPowershellProfileName()
+ {
+ return POWERSHELL_PREFERRED_PROFILE_NAME;
+ }
}
diff --git a/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.h b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.h
index d473292e151..77f2aaa7a02 100644
--- a/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.h
+++ b/src/cascadia/TerminalSettingsModel/PowershellCoreProfileGenerator.h
@@ -25,9 +25,60 @@ namespace winrt::Microsoft::Terminal::Settings::Model
public:
static const std::wstring_view GetPreferredPowershellProfileName();
+ enum PowerShellFlags
+ {
+ None = 0,
+
+ // These flags are used as a sort key, so they encode some native ordering.
+ // They are ordered such that the "most important" flags have the largest
+ // impact on the sort space. For example, since we want Preview to be very polar
+ // we give it the highest flag value.
+ // The "ideal" powershell instance has 0 flags (stable, native, Program Files location)
+ //
+ // With this ordering, the sort space ends up being (for PowerShell 6)
+ // (numerically greater values are on the left; this is flipped in the final sort)
+ //
+ // <-- Less Valued .................................... More Valued -->
+ // | All instances of PS 6 | All PS7 |
+ // | Preview | Stable | ~~~ |
+ // | Non-Native | Native | Non-Native | Native | ~~~ |
+ // | Trd | Pack | Trd | Pack | Trd | Pack | Trd | Pack | ~~~ |
+ // (where Pack is a stand-in for store, scoop, dotnet, though they have their own orders,
+ // and Trd is a stand-in for "Traditional" (Program Files))
+ //
+ // In short, flags with larger magnitudes are pushed further down (therefore valued less)
+
+ // distribution method (choose one)
+ Store = 1 << 0, // distributed via the store
+ Scoop = 1 << 1, // installed via Scoop
+ Dotnet = 1 << 2, // installed as a dotnet global tool
+ Traditional = 1 << 3, // installed in traditional Program Files locations
+
+ // native architecture (choose one)
+ WOWARM = 1 << 4, // non-native (Windows-on-Windows, ARM variety)
+ WOWx86 = 1 << 5, // non-native (Windows-on-Windows, x86 variety)
+
+ // build type (choose one)
+ Preview = 1 << 6, // preview version
+ };
+
+ struct PowerShellInstance
+ {
+ int majorVersion; // 0 = we don't know, sort last.
+ PowerShellFlags flags;
+ std::filesystem::path executablePath;
+
+ constexpr bool operator<(const PowerShellInstance& second) const;
+ std::wstring Name() const;
+ };
+
std::wstring_view GetNamespace() const noexcept override;
std::wstring_view GetDisplayName() const noexcept override;
std::wstring_view GetIcon() const noexcept override;
- void GenerateProfiles(std::vector>& profiles) const override;
+ void GenerateProfiles(std::vector>& profiles) override;
+ std::vector GetPowerShellInstances() noexcept;
+
+ private:
+ std::vector _powerShellInstances;
};
};
diff --git a/src/cascadia/TerminalSettingsModel/PowershellInstallationProfileGenerator.cpp b/src/cascadia/TerminalSettingsModel/PowershellInstallationProfileGenerator.cpp
new file mode 100644
index 00000000000..3ad7e795b19
--- /dev/null
+++ b/src/cascadia/TerminalSettingsModel/PowershellInstallationProfileGenerator.cpp
@@ -0,0 +1,42 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT license.
+
+#include "pch.h"
+
+#include "PowershellInstallationProfileGenerator.h"
+#include "DynamicProfileUtils.h"
+
+#include
+
+static constexpr std::wstring_view POWERSHELL_ICON{ L"ms-appx:///ProfileIcons/pwsh.png" };
+static constexpr std::wstring_view POWERSHELL_ICON_64{ L"ms-appx:///ProfileIcons/Powershell_black_64.png" };
+
+namespace winrt::Microsoft::Terminal::Settings::Model
+{
+ std::wstring_view PowershellInstallationProfileGenerator::Namespace{ L"Windows.Terminal.InstallPowerShell" };
+
+ std::wstring_view PowershellInstallationProfileGenerator::GetNamespace() const noexcept
+ {
+ return Namespace;
+ }
+
+ std::wstring_view PowershellInstallationProfileGenerator::GetDisplayName() const noexcept
+ {
+ return RS_(L"PowerShellInstallationProfileGeneratorDisplayName");
+ }
+
+ std::wstring_view PowershellInstallationProfileGenerator::GetIcon() const noexcept
+ {
+ return POWERSHELL_ICON_64;
+ }
+
+ void PowershellInstallationProfileGenerator::GenerateProfiles(std::vector>& profiles)
+ {
+ auto profile{ CreateDynamicProfile(RS_(L"PowerShellInstallationProfileName")) };
+ profile->Commandline(winrt::hstring{ fmt::format(FMT_COMPILE(L"cmd /k winget install --interactive --id Microsoft.PowerShell & echo. & echo {} & exit"), RS_(L"PowerShellInstallationInstallerGuidance")) });
+ profile->Icon(winrt::hstring{ POWERSHELL_ICON });
+ profile->CloseOnExit(CloseOnExitMode::Never);
+
+ profiles.emplace_back(std::move(profile));
+ }
+}
diff --git a/src/cascadia/TerminalSettingsModel/PowershellInstallationProfileGenerator.h b/src/cascadia/TerminalSettingsModel/PowershellInstallationProfileGenerator.h
new file mode 100644
index 00000000000..6a3fc2fffff
--- /dev/null
+++ b/src/cascadia/TerminalSettingsModel/PowershellInstallationProfileGenerator.h
@@ -0,0 +1,33 @@
+/*++
+Copyright (c) Microsoft Corporation
+Licensed under the MIT license.
+
+Module Name:
+- PowershellInstallationProfileGenerator
+
+Abstract:
+- This is the dynamic profile generator for a PowerShell stub. Checks if pwsh is
+ installed, and if it is NOT installed, creates a profile that installs the
+ latest PowerShell.
+
+Author(s):
+- Carlos Zamora - March 2025
+
+--*/
+
+#pragma once
+
+#include "IDynamicProfileGenerator.h"
+
+namespace winrt::Microsoft::Terminal::Settings::Model
+{
+ class PowershellInstallationProfileGenerator final : public IDynamicProfileGenerator
+ {
+ public:
+ static std::wstring_view Namespace;
+ std::wstring_view GetNamespace() const noexcept override;
+ std::wstring_view GetDisplayName() const noexcept override;
+ std::wstring_view GetIcon() const noexcept override;
+ void GenerateProfiles(std::vector>& profiles) override;
+ };
+};
diff --git a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
index 37d9b2629b4..07758f4967d 100644
--- a/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
+++ b/src/cascadia/TerminalSettingsModel/Resources/en-US/Resources.resw
@@ -748,6 +748,14 @@
PowerShell Profile Generator
The display name of a dynamic profile generator for PowerShell
+
+ PowerShell Installation Generator
+ The display name of a dynamic profile generator that installs the latest PowerShell
+
+
+ Install Latest PowerShell
+ The display name of a profile generated by the PowerShellInstallationProfileGenerator. This profile installs the latest PowerShell.
+
Azure Cloud Shell Profile Generator
The display name of a dynamic profile generator for Azure Cloud Shell
@@ -760,4 +768,11 @@
SSH Host Profile Generator
The display name of a dynamic profile generator for SSH hosts
-
\ No newline at end of file
+
+ Restart Windows Terminal to apply the new profile.
+ Guidance displayed by the installer directing the user to restart the app.
+
+
+ This profile only appears if PowerShell is not installed
+
+
diff --git a/src/cascadia/TerminalSettingsModel/SshHostGenerator.cpp b/src/cascadia/TerminalSettingsModel/SshHostGenerator.cpp
index 2bd52789959..9276ac63520 100644
--- a/src/cascadia/TerminalSettingsModel/SshHostGenerator.cpp
+++ b/src/cascadia/TerminalSettingsModel/SshHostGenerator.cpp
@@ -149,7 +149,7 @@ std::wstring_view SshHostGenerator::GetIcon() const noexcept
// -
// Return Value:
// -
-void SshHostGenerator::GenerateProfiles(std::vector>& profiles) const
+void SshHostGenerator::GenerateProfiles(std::vector>& profiles)
{
std::wstring sshExePath;
if (_tryFindSshExePath(sshExePath))
diff --git a/src/cascadia/TerminalSettingsModel/SshHostGenerator.h b/src/cascadia/TerminalSettingsModel/SshHostGenerator.h
index d83e62535ba..2bce0471612 100644
--- a/src/cascadia/TerminalSettingsModel/SshHostGenerator.h
+++ b/src/cascadia/TerminalSettingsModel/SshHostGenerator.h
@@ -26,7 +26,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model
std::wstring_view GetNamespace() const noexcept override;
std::wstring_view GetDisplayName() const noexcept override;
std::wstring_view GetIcon() const noexcept override;
- void GenerateProfiles(std::vector>& profiles) const override;
+ void GenerateProfiles(std::vector>& profiles) override;
private:
static const std::wregex _configKeyValueRegex;
diff --git a/src/cascadia/TerminalSettingsModel/VisualStudioGenerator.cpp b/src/cascadia/TerminalSettingsModel/VisualStudioGenerator.cpp
index ad09059f9e9..39a40d65bbb 100644
--- a/src/cascadia/TerminalSettingsModel/VisualStudioGenerator.cpp
+++ b/src/cascadia/TerminalSettingsModel/VisualStudioGenerator.cpp
@@ -22,7 +22,7 @@ std::wstring_view VisualStudioGenerator::GetDisplayName() const noexcept
return RS_(L"VisualStudioGeneratorDisplayName");
}
-void VisualStudioGenerator::GenerateProfiles(std::vector>& profiles) const
+void VisualStudioGenerator::GenerateProfiles(std::vector>& profiles)
{
const auto instances = VsSetupConfiguration::QueryInstances();
diff --git a/src/cascadia/TerminalSettingsModel/VisualStudioGenerator.h b/src/cascadia/TerminalSettingsModel/VisualStudioGenerator.h
index 2f5c2274c6c..b256e076f85 100644
--- a/src/cascadia/TerminalSettingsModel/VisualStudioGenerator.h
+++ b/src/cascadia/TerminalSettingsModel/VisualStudioGenerator.h
@@ -30,7 +30,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model
std::wstring_view GetNamespace() const noexcept override;
std::wstring_view GetDisplayName() const noexcept override;
std::wstring_view GetIcon() const noexcept override { return {}; };
- void GenerateProfiles(std::vector>& profiles) const override;
+ void GenerateProfiles(std::vector>& profiles) override;
class IVisualStudioProfileGenerator
{
diff --git a/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp
index f571b08f668..715582fab4d 100644
--- a/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp
+++ b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.cpp
@@ -238,7 +238,7 @@ static bool getWslNames(const wil::unique_hkey& wslRootKey,
// -
// Return Value:
// - A list of WSL profiles.
-void WslDistroGenerator::GenerateProfiles(std::vector>& profiles) const
+void WslDistroGenerator::GenerateProfiles(std::vector>& profiles)
{
auto wslRootKey{ openWslRegKey() };
if (wslRootKey)
diff --git a/src/cascadia/TerminalSettingsModel/WslDistroGenerator.h b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.h
index 123734523fa..77cda13f355 100644
--- a/src/cascadia/TerminalSettingsModel/WslDistroGenerator.h
+++ b/src/cascadia/TerminalSettingsModel/WslDistroGenerator.h
@@ -26,6 +26,6 @@ namespace winrt::Microsoft::Terminal::Settings::Model
std::wstring_view GetNamespace() const noexcept override;
std::wstring_view GetDisplayName() const noexcept override;
std::wstring_view GetIcon() const noexcept override;
- void GenerateProfiles(std::vector>& profiles) const override;
+ void GenerateProfiles(std::vector>& profiles) override;
};
};