2025-11-28 00:35:46 +09:00

234 lines
10 KiB
C#

// <copyright file="HostUtilities.cs" company="Microsoft Corporation">
// Copyright (c) 2009 Microsoft Corporation. All rights reserved.
// </copyright>
// DISCLAIMER OF WARRANTY: The software is licensed “as-is.” You
// bear the risk of using it. Microsoft gives no express warranties,
// guarantees or conditions. You may have additional consumer rights
// under your local laws which this agreement cannot change. To the extent
// permitted under your local laws, Microsoft excludes the implied warranties
// of merchantability, fitness for a particular purpose and non-infringement.
namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using System.Reflection;
using Microsoft.Win32;
/// <summary>
/// Helper functions for setting $profile.
/// </summary>
public class HostUtilities
{
/// <summary>
/// Root registry key for Windows PowerShell.
/// </summary>
internal const string PowerShellRootKeyPath = "Software\\Microsoft\\PowerShell";
/// <summary>
/// Engine registry key.
/// </summary>
internal const string PowerShellEngineKey = "PowerShellEngine";
/// <summary>
/// Registry key used to determine the directory where Windows
/// PowerShell is installed.
/// </summary>
internal const string PowerShellEngineApplicationBase = "ApplicationBase";
/// <summary>
/// Windows PowerShell version registry key.
/// </summary>
internal const string RegistryVersionKey = "1";
/// <summary>
/// Gets a PSObject whose base object is currentUserCurrentHost
/// and with notes for the other 4 parameters.
/// </summary>
/// <param name="allUsersAllHosts">The profile file name for all
/// users and all hosts.</param>
/// <param name="allUsersCurrentHost">The profile file name for
/// all users and current host.</param>
/// <param name="currentUserAllHosts">The profile file name for
/// cuurrent user and all hosts.</param>
/// <param name="currentUserCurrentHost">The profile name for
/// current user and current host.</param>
/// <returns>A PSObject whose base object is currentUserCurrentHost
/// and with notes for the other four parameters.</returns>
internal static PSObject GetDollarProfile(
string allUsersAllHosts,
string allUsersCurrentHost,
string currentUserAllHosts,
string currentUserCurrentHost)
{
PSObject returnValue = new PSObject(currentUserCurrentHost);
returnValue.Properties.Add(new PSNoteProperty("AllUsersAllHosts", allUsersAllHosts));
returnValue.Properties.Add(new PSNoteProperty("AllUsersCurrentHost", allUsersCurrentHost));
returnValue.Properties.Add(new PSNoteProperty("CurrentUserAllHosts", currentUserAllHosts));
returnValue.Properties.Add(new PSNoteProperty("CurrentUserCurrentHost", currentUserCurrentHost));
return returnValue;
}
/// <summary>
/// Gets an array of commands that can be run sequentially to set
/// $profile and run the profile commands.
/// </summary>
/// <param name="shellId">Identifies the host or shell used in
/// the profile file names.</param>
/// <returns></returns>
public static PSCommand[] GetProfileCommands(string shellId)
{
return HostUtilities.GetProfileCommands(shellId, false);
}
/// <summary>
/// Gets an array of commands that can be run sequentially to set
/// $profile and run the profile commands.
/// </summary>
/// <param name="shellId">Identifies the host or shell used in
/// the profile file names.</param>
/// <param name="useTestProfile">Used from test not to overwrite
/// the profile file names from development boxes.</param>
/// <returns>The profile commands.</returns>
internal static PSCommand[] GetProfileCommands(string shellId, bool useTestProfile)
{
List<PSCommand> commands = new List<PSCommand>();
string allUsersAllHosts = HostUtilities.GetFullProfileFileName(null, false, useTestProfile);
string allUsersCurrentHost = HostUtilities.GetFullProfileFileName(shellId, false, useTestProfile);
string currentUserAllHosts = HostUtilities.GetFullProfileFileName(null, true, useTestProfile);
string currentUserCurrentHost = HostUtilities.GetFullProfileFileName(shellId, true, useTestProfile);
PSObject dollarProfile = HostUtilities.GetDollarProfile(allUsersAllHosts, allUsersCurrentHost, currentUserAllHosts, currentUserCurrentHost);
PSCommand command = new PSCommand();
command.AddCommand("set-variable");
command.AddParameter("Name", "profile");
command.AddParameter("Value", dollarProfile);
command.AddParameter("Option", ScopedItemOptions.None);
commands.Add(command);
string[] profilePaths = new string[] { allUsersAllHosts, allUsersCurrentHost, currentUserAllHosts, currentUserCurrentHost };
foreach (string profilePath in profilePaths)
{
if (!System.IO.File.Exists(profilePath))
{
continue;
}
command = new PSCommand();
command.AddCommand(profilePath, false);
commands.Add(command);
}
return commands.ToArray();
}
/// <summary>
/// Used to get all profile file names for the current or all hosts and for the current or all users.
/// </summary>
/// <param name="shellId">null for all hosts, not null for the specified host</param>
/// <param name="forCurrentUser">false for all users, true for the current user.</param>
/// <returns>The profile file name matching the parameters.</returns>
internal static string GetFullProfileFileName(string shellId, bool forCurrentUser)
{
return HostUtilities.GetFullProfileFileName(shellId, forCurrentUser, false);
}
/// <summary>
/// Used to get all profile file names for the current or all hosts and for the current or all users.
/// </summary>
/// <param name="shellId">null for all hosts, not null for the specified host</param>
/// <param name="forCurrentUser">false for all users, true for the current user.</param>
/// <param name="useTestProfile">used from test not to overwrite the profile file names from development boxes</param>
/// <returns>The profile file name matching the parameters.</returns>
internal static string GetFullProfileFileName(string shellId, bool forCurrentUser, bool useTestProfile)
{
string basePath = null;
if (forCurrentUser)
{
basePath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
basePath = System.IO.Path.Combine(basePath, "WindowsPowerShell");
}
else
{
basePath = GetAllUsersFolderPath(shellId);
if (string.IsNullOrEmpty(basePath))
{
return string.Empty;
}
}
string profileName = useTestProfile ? "profile_test.ps1" : "profile.ps1";
if (!string.IsNullOrEmpty(shellId))
{
profileName = shellId + "_" + profileName;
}
string fullPath = basePath = System.IO.Path.Combine(basePath, profileName);
return fullPath;
}
// <summary>
/// Gets the registry key used to install Windows PowerShell.
/// </summary>
/// <param name="shellId">The parameter is not used.</param>
/// <returns>The registry key.</returns>
internal static string GetApplicationBase(string shellId)
{
string engineKeyPath = PowerShellRootKeyPath + "\\" +
RegistryVersionKey + "\\" + PowerShellEngineKey;
using (RegistryKey engineKey = Registry.LocalMachine.OpenSubKey(engineKeyPath))
{
if (engineKey != null)
{
return engineKey.GetValue(PowerShellEngineApplicationBase) as string;
}
}
// The default keys aren't installed, so try and use the entry assembly to
// get the application base. This works for managed apps like minishells...
Assembly assem = Assembly.GetEntryAssembly();
if (assem != null)
{
// For minishells, we just return the executable path.
return Path.GetDirectoryName(assem.Location);
}
// For unmanaged host apps, look for the SMA dll, if it's not GAC'ed then
// use it's location as the application base...
assem = Assembly.GetAssembly(typeof(System.Management.Automation.PSObject));
if (assem != null)
{
// For for other hosts.
return Path.GetDirectoryName(assem.Location);
}
// otherwise, just give up...
return string.Empty;
}
/// <summary>
/// Used internally in GetFullProfileFileName to get the base path for all users profiles.
/// </summary>
/// <param name="shellId">The shellId to use.</param>
/// <returns>the base path for all users profiles.</returns>
private static string GetAllUsersFolderPath(string shellId)
{
string folderPath = string.Empty;
try
{
folderPath = GetApplicationBase(shellId);
}
catch (System.Security.SecurityException)
{
}
return folderPath;
}
}
}