PowerShell/src/Microsoft.PowerShell.GraphicalHost/commandHelpers/ShowCommandHelper.cs
PowerShell Team c748652c34 Copy all mapped files from [SD:725290]
commit 8cec8f150da7583b7af5efbe2853efee0179750c
2016-07-28 23:23:03 -07:00

1350 lines
54 KiB
C#

//-----------------------------------------------------------------------
// <copyright file="ShowCommandHelper.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <summary>
// Implements ShowCommandHelper
// </summary>
//-----------------------------------------------------------------------
namespace Microsoft.PowerShell.Commands.ShowCommandInternal
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Management.Automation;
using System.Reflection;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using Microsoft.Management.UI;
using Microsoft.Management.UI.Internal;
using Microsoft.Management.UI.Internal.ShowCommand;
using Microsoft.PowerShell.Commands.ShowCommandExtension;
/// <summary>
/// Implements thw WPF window part of the show-command cmdlet
/// </summary>
internal class ShowCommandHelper : IDisposable
{
#region fields
internal const string CommandTypeSegment = " -CommandType Cmdlet, Function, Script, ExternalScript, Workflow";
/// <summary>
/// Method that will return the dialog from ShowAllModulesWindow or ShowCommandWindow.
/// This is necessary because the PlainInvokeAndShowDialog thread starter cannot receive parameters
/// </summary>
private DispatcherOperationCallback methodThatReturnsDialog;
/// <summary>
/// Event set when the window is closed
/// </summary>
private AutoResetEvent windowClosed = new AutoResetEvent(false);
/// <summary>
/// Event set when help is needed
/// </summary>
private AutoResetEvent helpNeeded = new AutoResetEvent(false);
/// <summary>
/// Event set when it is necessary to import a module
/// </summary>
private AutoResetEvent importModuleNeeded = new AutoResetEvent(false);
/// <summary>
/// Event set when the window is loaded
/// </summary>
private AutoResetEvent windowLoaded = new AutoResetEvent(false);
/// <summary>
/// String with the command that needs help set when helpNeeded is set
/// </summary>
private string commandNeedingHelp;
/// <summary>
/// String with the command name that needs to import a module
/// </summary>
private string commandNeedingImportModule;
/// <summary>
/// String with the module name that needs to be imported
/// </summary>
private string parentModuleNeedingImportModule;
/// <summary>
/// String with the selected module at the time a module needs to be imported
/// </summary>
private string selectedModuleNeedingImportModule;
/// <summary>
/// Keeps the window for the implementation of CloseWindow
/// </summary>
private Window window;
/// <summary>
/// host window, if any
/// </summary>
private Window hostWindow;
/// <summary>
/// ViewModel when showing all modules
/// </summary>
private AllModulesViewModel allModulesViewModel;
/// <summary>
/// ViewModel when showing a single command
/// </summary>
private CommandViewModel commandViewModel;
/// <summary>
/// true when the window is closed with cancel
/// </summary>
private bool dialogCanceled = true;
#endregion fields
#region GetSerializedCommand script
private const string ScriptGetSerializedCommand = @"
Function PSGetSerializedShowCommandInfo
{
Function GetParameterType
{
param (
[Type] $parameterType)
$returnParameterType = new-object PSObject
$returnParameterType | Add-Member -MemberType NoteProperty -Name ""FullName"" -Value $parameterType.FullName
$returnParameterType | Add-Member -MemberType NoteProperty -Name ""IsEnum"" -Value $parameterType.IsEnum
$returnParameterType | Add-Member -MemberType NoteProperty -Name ""IsArray"" -Value $parameterType.IsArray
if ($parameterType.IsEnum)
{
$enumValues = [System.Enum]::GetValues($parameterType)
}
else
{
$enumValues = [string[]] @()
}
$returnParameterType | Add-Member -MemberType NoteProperty -Name ""EnumValues"" -Value $enumValues
if ($parameterType.IsArray)
{
$hasFlagAttribute = ($parameterType.GetCustomAttributes([System.FlagsAttribute], $true).Length -gt 0)
# Recurse into array elements.
$elementType = GetParameterType($parameterType.GetElementType())
}
else
{
$hasFlagAttribute = $false
$elementType = $null
}
$returnParameterType | Add-Member -MemberType NoteProperty -Name ""HasFlagAttribute"" -Value $hasFlagAttribute
$returnParameterType | Add-Member -MemberType NoteProperty -Name ""ElementType"" -Value $elementType
if (!($parameterType.IsEnum) -and !($parameterType.IsArray))
{
$implementsDictionary = [System.Collections.IDictionary].IsAssignableFrom($parameterType)
}
else
{
$implementsDictionary = $false
}
$returnParameterType | Add-Member -MemberType NoteProperty -Name ""ImplementsDictionary"" -Value $implementsDictionary
return $returnParameterType
}
Function GetParameterInfo
{
param (
$parameters)
[PSObject[]] $parameterInfos = @()
foreach ($parameter in $parameters)
{
$parameterInfo = new-object PSObject
$parameterInfo | Add-Member -MemberType NoteProperty -Name ""Name"" -Value $parameter.Name
$parameterInfo | Add-Member -MemberType NoteProperty -Name ""IsMandatory"" -Value $parameter.IsMandatory
$parameterInfo | Add-Member -MemberType NoteProperty -Name ""ValueFromPipeline"" -Value $parameter.ValueFromPipeline
$parameterInfo | Add-Member -MemberType NoteProperty -Name ""Position"" -Value $parameter.Position
$parameterInfo | Add-Member -MemberType NoteProperty -Name ""ParameterType"" -Value (GetParameterType($parameter.ParameterType))
$hasParameterSet = $false
[string[]] $validValues = @()
if ($PSVersionTable.PSVersion.Major -gt 2)
{
$validateSetAttributes = $parameter.Attributes | Where {
[ValidateSet].IsAssignableFrom($_.GetType())
}
if (($validateSetAttributes -ne $null) -and ($validateSetAttributes.Count -gt 0))
{
$hasParameterSet = $true
$validValues = $validateSetAttributes[0].ValidValues
}
}
$parameterInfo | Add-Member -MemberType NoteProperty -Name ""HasParameterSet"" -Value $hasParameterSet
$parameterInfo | Add-Member -MemberType NoteProperty -Name ""ValidParamSetValues"" -Value $validValues
$parameterInfos += $parameterInfo
}
return (,$parameterInfos)
}
Function GetParameterSets
{
param (
[System.Management.Automation.CommandInfo] $cmdInfo
)
$parameterSets = $null
try
{
$parameterSets = $cmdInfo.ParameterSets
}
catch [System.InvalidOperationException] { }
catch [System.Management.Automation.PSNotSupportedException] { }
catch [System.Management.Automation.PSNotImplementedException] { }
if (($parameterSets -eq $null) -or ($parameterSets.Count -eq 0))
{
return (,@())
}
[PSObject[]] $returnParameterSets = @()
foreach ($parameterSet in $parameterSets)
{
$parameterSetInfo = new-object PSObject
$parameterSetInfo | Add-Member -MemberType NoteProperty -Name ""Name"" -Value $parameterSet.Name
$parameterSetInfo | Add-Member -MemberType NoteProperty -Name ""IsDefault"" -Value $parameterSet.IsDefault
$parameterSetInfo | Add-Member -MemberType NoteProperty -Name ""Parameters"" -Value (GetParameterInfo($parameterSet.Parameters))
$returnParameterSets += $parameterSetInfo
}
return (,$returnParameterSets)
}
Function GetModuleInfo
{
param (
[System.Management.Automation.CommandInfo] $cmdInfo
)
if ($cmdInfo.ModuleName -ne $null)
{
$moduleName = $cmdInfo.ModuleName
}
else
{
$moduleName = """"
}
$moduleInfo = new-object PSObject
$moduleInfo | Add-Member -MemberType NoteProperty -Name ""Name"" -Value $moduleName
return $moduleInfo
}
Function ConvertToShowCommandInfo
{
param (
[System.Management.Automation.CommandInfo] $cmdInfo
)
$showCommandInfo = new-object PSObject
$showCommandInfo | Add-Member -MemberType NoteProperty -Name ""Name"" -Value $cmdInfo.Name
$showCommandInfo | Add-Member -MemberType NoteProperty -Name ""ModuleName"" -Value $cmdInfo.ModuleName
$showCommandInfo | Add-Member -MemberType NoteProperty -Name ""Module"" -Value (GetModuleInfo($cmdInfo))
$showCommandInfo | Add-Member -MemberType NoteProperty -Name ""CommandType"" -Value $cmdInfo.CommandType
$showCommandInfo | Add-Member -MemberType NoteProperty -Name ""Definition"" -Value $cmdInfo.Definition
$showCommandInfo | Add-Member -MemberType NoteProperty -Name ""ParameterSets"" -Value (GetParameterSets($cmdInfo))
return $showCommandInfo
}
$commandList = @(""Cmdlet"", ""Function"", ""Script"", ""ExternalScript"")
if ($PSVersionTable.PSVersion.Major -gt 2)
{
$commandList += ""Workflow""
}
foreach ($command in @(Get-Command -CommandType $commandList))
{
Write-Output (ConvertToShowCommandInfo($command))
}
}";
#endregion
#region constructor and destructor
/// <summary>
/// Prevents a default instance of the ShowCommandHelper class from being created
/// </summary>
private ShowCommandHelper()
{
}
/// <summary>
/// Finalizes an instance of the ShowCommandHelper class
/// </summary>
~ShowCommandHelper()
{
this.Dispose(false);
}
#endregion constructor and destructor
#region properties called using reflection
/// <summary>
/// Gets the Screen Width
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private static double ScreenWidth
{
get
{
return System.Windows.SystemParameters.PrimaryScreenWidth;
}
}
/// <summary>
/// Gets the Screen Height
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private static double ScreenHeight
{
get
{
return System.Windows.SystemParameters.PrimaryScreenHeight;
}
}
/// <summary>
/// Gets the event set when the show-command window is closed
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private AutoResetEvent WindowClosed
{
get
{
return this.windowClosed;
}
}
/// <summary>
/// Gets the event set when help is needed for a command
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private AutoResetEvent HelpNeeded
{
get
{
return this.helpNeeded;
}
}
/// <summary>
/// Gets the event set when it is necessary to import a module
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private AutoResetEvent ImportModuleNeeded
{
get
{
return this.importModuleNeeded;
}
}
/// <summary>
/// Gets the event set when the window is loaded
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private AutoResetEvent WindowLoaded
{
get
{
return this.windowLoaded;
}
}
/// <summary>
/// Gets the command needing help when HelpNeeded is set
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private string CommandNeedingHelp
{
get
{
return this.commandNeedingHelp;
}
}
/// <summary>
/// Gets the module we want to import
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private string ParentModuleNeedingImportModule
{
get
{
return this.parentModuleNeedingImportModule;
}
}
/// <summary>
/// Gets a value indicating whether there is a host window
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private bool HasHostWindow
{
get
{
return this.hostWindow != null;
}
}
#endregion properties called using reflection
#region public Dispose
/// <summary>
/// Dispose method in IDisposeable
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
#endregion public Dispose
#region internal static methods called using reflection from show-command and directly from ISE
/// <summary>
/// Sets the text in the clipboard
/// </summary>
/// <param name="text">text to set the clipboard to</param>
internal static void SetClipboardText(string text)
{
try
{
Clipboard.SetText(text);
}
catch (System.Runtime.InteropServices.COMException)
{
// This is the recommended way to set clipboard text
System.Threading.Thread.Sleep(0);
try
{
Clipboard.SetText(text);
}
catch (System.Runtime.InteropServices.COMException)
{
}
}
}
/// <summary>
/// Gets the command to be run to get commands and imported modules
/// </summary>
/// <param name="isRemoteRunspace">Boolean flag determining whether Show-Command is queried in the local or remote runspace scenario </param>
/// <param name="isFirstChance">Boolean flag to indicate that it is the second attempt to query Show-Command data </param>
/// <returns>the command to be run to get commands and imported modules</returns>
internal static string GetShowAllModulesCommand(bool isRemoteRunspace = false, bool isFirstChance = true)
{
string scriptBase;
if (isRemoteRunspace)
{
if (isFirstChance)
{
// Return command to run.
scriptBase = "@(Get-Command " + ShowCommandHelper.CommandTypeSegment + @" -ShowCommandInfo)";
}
else
{
// Return script to run.
scriptBase = GetSerializedCommandScript();
}
}
else
{
scriptBase = "@(Get-Command " + ShowCommandHelper.CommandTypeSegment + ")";
}
scriptBase += ShowCommandHelper.GetGetModuleSuffix();
return scriptBase;
}
/// <summary>
/// Retrieves the script for Get-SerializedCommand from local machine
/// </summary>
/// <returns>String representation of the script for Get-SerializedCommand</returns>
private static string GetSerializedCommandScript()
{
return string.Format(CultureInfo.InvariantCulture, "@({0};{1};{2})",
ScriptGetSerializedCommand,
@"PSGetSerializedShowCommandInfo",
@"Remove-Item -Path 'function:\PSGetSerializedShowCommandInfo' -Force");
}
/// <summary>
/// Gets the command to be run to in order to import a module and refresh the command data
/// </summary>
/// <param name="module">module we want to import</param>
/// <param name="isRemoteRunspace">Boolean flag determining whether Show-Command is queried in the local or remote runspace scenario </param>
/// <param name="isFirstChance">Boolean flag to indicate that it is the second attempt to query Show-Command data </param>
/// <returns>the command to be run to in order to import a module and refresh the command data</returns>
internal static string GetImportModuleCommand(string module, bool isRemoteRunspace = false, bool isFirstChance = true)
{
string scriptBase = "Import-Module " + ShowCommandHelper.SingleQuote(module);
if (isRemoteRunspace)
{
if (isFirstChance)
{
scriptBase += ";@(Get-Command " + ShowCommandHelper.CommandTypeSegment + @" -ShowCommandInfo )";
}
else
{
scriptBase += GetSerializedCommandScript();
}
}
else
{
scriptBase += ";@(Get-Command " + ShowCommandHelper.CommandTypeSegment + ")";
}
scriptBase += ShowCommandHelper.GetGetModuleSuffix();
return scriptBase;
}
/// <summary>
/// gets the command to be run in order to show help for a command
/// </summary>
/// <param name="command">command we want to get help from</param>
/// <returns>the command to be run in order to show help for a command</returns>
internal static string GetHelpCommand(string command)
{
return "Get-Help " + ShowCommandHelper.SingleQuote(command);
}
/// <summary>
/// Constructs a dictionary of imported modules based on the module names
/// </summary>
/// <param name="moduleObjects">the imported modules</param>
/// <returns>a dictionary of imported modules based on the module names</returns>
internal static Dictionary<string, ShowCommandModuleInfo> GetImportedModulesDictionary(object[] moduleObjects)
{
Dictionary<string, ShowCommandModuleInfo> returnValue = new Dictionary<string, ShowCommandModuleInfo>(StringComparer.OrdinalIgnoreCase);
foreach (PSObject rawModule in moduleObjects)
{
ShowCommandModuleInfo wrappedModule = null;
PSModuleInfo module = rawModule.BaseObject as PSModuleInfo;
if (module != null)
{
wrappedModule = new ShowCommandModuleInfo(module);
}
else
{
wrappedModule = new ShowCommandModuleInfo(rawModule);
}
// It is probably an issue somewhere else that a module would show up twice in the list, but we want to avoid
// throwing an exception regarding that in returnValue.Add
if(!returnValue.ContainsKey(wrappedModule.Name))
{
returnValue.Add(wrappedModule.Name, wrappedModule);
}
}
return returnValue;
}
/// <summary>
/// Constructs a list of commands out of <paramref name="commandObjects"/>
/// </summary>
/// <param name="commandObjects">the results of a get-command command</param>
/// <returns>a list of commands out of <paramref name="commandObjects"/></returns>
internal static List<ShowCommandCommandInfo> GetCommandList(object[] commandObjects)
{
List<ShowCommandCommandInfo> returnValue = new List<ShowCommandCommandInfo>();
foreach (PSObject rawCommand in commandObjects)
{
CommandInfo command = rawCommand.BaseObject as CommandInfo;
if(command != null)
{
returnValue.Add(new ShowCommandCommandInfo(command));
}
else
{
PSObject obj = rawCommand as PSObject;
if(obj != null)
{
returnValue.Add(new ShowCommandCommandInfo(obj));
}
}
}
return returnValue;
}
/// <summary>
/// Constructs an array of objects out of <paramref name="commandObjects"/>
/// </summary>
/// <param name="commandObjects">The result of a get-command command</param>
/// <returns>An array of objects out of <paramref name="commandObjects"/></returns>
internal static object[] ObjectArrayFromObjectCollection(object commandObjects)
{
object[] objectArray = commandObjects as object[];
if(objectArray == null)
{
objectArray = ((System.Collections.ArrayList)commandObjects).ToArray();
}
return objectArray;
}
/// <summary>
/// Called after a module in <paramref name="oldViewModel"/> is imported to refresh the view model.
/// Gets a new AllModulesViewModel populated with <paramref name="importedModules"/> and <paramref name="commands"/>.
/// The <paramref name="oldViewModel"/> is used to cleanup event listening in the old view model and to copy NoCommonParameters.
/// The new ViewModel will have the command selected according to <paramref name="selectedModuleNeedingImportModule"/>,
/// <paramref name="parentModuleNeedingImportModule"/> and <paramref name="commandNeedingImportModule"/>.
/// </summary>
/// <param name="oldViewModel">the viewModel before the module was imported</param>
/// <param name="importedModules">the list of imported modules</param>
/// <param name="commands">the list of commands</param>
/// <param name="selectedModuleNeedingImportModule">the name of the module that was selected in <paramref name="oldViewModel"/></param>
/// <param name="parentModuleNeedingImportModule">the name of the module that was imported</param>
/// <param name="commandNeedingImportModule">the name of the command that was selected in <paramref name="oldViewModel"/></param>
/// <returns>The new ViewModel based on <paramref name="importedModules"/> and <paramref name="commands"/>.</returns>
internal static AllModulesViewModel GetNewAllModulesViewModel(AllModulesViewModel oldViewModel, Dictionary<string, ShowCommandModuleInfo> importedModules, IEnumerable<ShowCommandCommandInfo> commands, string selectedModuleNeedingImportModule, string parentModuleNeedingImportModule, string commandNeedingImportModule)
{
string oldFilter = null;
if (oldViewModel.SelectedModule != null)
{
// this will allow the old view model to stop listening for events before we
// replace it with a new view model
oldViewModel.SelectedModule.SelectedCommand = null;
oldViewModel.SelectedModule = null;
oldFilter = oldViewModel.CommandNameFilter;
}
AllModulesViewModel returnValue = new AllModulesViewModel(importedModules, commands, oldViewModel.NoCommonParameter);
if (!String.IsNullOrEmpty(oldFilter))
{
returnValue.CommandNameFilter = oldFilter;
}
if (selectedModuleNeedingImportModule == null || parentModuleNeedingImportModule == null)
{
return returnValue;
}
ModuleViewModel moduleToSelect = returnValue.Modules.Find(
new Predicate<ModuleViewModel>(delegate(ModuleViewModel module)
{
return module.Name.Equals(selectedModuleNeedingImportModule, StringComparison.OrdinalIgnoreCase) ? true : false;
}));
if (moduleToSelect == null)
{
return returnValue;
}
returnValue.SelectedModule = moduleToSelect;
CommandViewModel commandToSelect = moduleToSelect.Commands.Find(
new Predicate<CommandViewModel>(delegate(CommandViewModel command)
{
return command.ModuleName.Equals(parentModuleNeedingImportModule, StringComparison.OrdinalIgnoreCase) &&
command.Name.Equals(commandNeedingImportModule, StringComparison.OrdinalIgnoreCase) ? true : false;
}));
if (commandToSelect == null)
{
return returnValue;
}
moduleToSelect.SelectedCommand = commandToSelect;
return returnValue;
}
/// <summary>
/// Gets an error message to be displayed when failed to import a module
/// </summary>
/// <param name="command">command belongiong to the module to import</param>
/// <param name="module">module to import</param>
/// <param name="error">error importing the module</param>
/// <returns>an error message to be displayed when failed to import a module</returns>
internal static string GetImportModuleFailedMessage(string command, string module, string error)
{
return String.Format(
CultureInfo.CurrentUICulture,
ShowCommandResources.ImportModuleFailedFormat,
command,
module,
error);
}
/// <summary>
/// Single quotes <paramref name="str"/>
/// </summary>
/// <param name="str">string to quote</param>
/// <returns><paramref name="str"/> single quoted</returns>
internal static string SingleQuote(string str)
{
if (str == null)
{
str = String.Empty;
}
return "\'" + System.Management.Automation.Language.CodeGeneration.EscapeSingleQuotedStringContent(str) + "\'";
}
#endregion internal static methods called using reflection from show-command and directly from ISE
#region internal static methods used internally in this assembly
/// <summary>
/// Gets the host window, if it is present or null if it is not
/// </summary>
/// <param name="cmdlet">cmdlet calling this method</param>
/// <returns>the host window, if it is present or null if it is not</returns>
internal static Window GetHostWindow(PSCmdlet cmdlet)
{
PSPropertyInfo windowProperty = cmdlet.Host.PrivateData.Properties["Window"];
if (windowProperty == null)
{
return null;
}
try
{
return windowProperty.Value as Window;
}
catch (ExtendedTypeSystemException)
{
return null;
}
}
#endregion internal static methods used internally in this assembly
#region static private methods used only on this file
/// <summary>
/// Gets a property value using reflection
/// </summary>
/// <param name="type">type containing the property</param>
/// <param name="obj">object containing the property (null for a static property)</param>
/// <param name="propertyName">name of property to get</param>
/// <param name="bindingFlags">flags passed to reflection</param>
/// <returns>
/// property value or null if it was not able to retrieve it. This method is not suitable to return a property value that might be null.
/// </returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from a method called using reflection")]
private static object GetPropertyValue(Type type, object obj, string propertyName, BindingFlags bindingFlags)
{
PropertyInfo property = type.GetProperty(propertyName, bindingFlags);
if (property == null)
{
return null;
}
try
{
return property.GetValue(obj, new object[] { });
}
catch (ArgumentException)
{
return null;
}
catch (TargetException)
{
return null;
}
catch (TargetParameterCountException)
{
return null;
}
catch (MethodAccessException)
{
return null;
}
catch (TargetInvocationException)
{
return null;
}
}
/// <summary>
/// Sets a property value using reflection
/// </summary>
/// <param name="type">type containing the property</param>
/// <param name="obj">object containing the property (null for a static property)</param>
/// <param name="propertyName">name of property to set</param>
/// <param name="value">value to set the property with</param>
/// <param name="bindingFlags">flags passed to reflection</param>
/// <returns>true if it was able to set</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from a method called using reflection")]
private static bool SetPropertyValue(Type type, object obj, string propertyName, object value, BindingFlags bindingFlags)
{
PropertyInfo property = type.GetProperty(propertyName, bindingFlags);
if (property == null)
{
return false;
}
try
{
property.SetValue(obj, value, new object[] { });
}
catch (ArgumentException)
{
return false;
}
catch (TargetException)
{
return false;
}
catch (TargetParameterCountException)
{
return false;
}
catch (MethodAccessException)
{
return false;
}
catch (TargetInvocationException)
{
return false;
}
return true;
}
/// <summary>
/// Gets the suffix that adds imported modules to a command
/// </summary>
/// <returns>the suffix that adds imported modules to a command</returns>
private static string GetGetModuleSuffix()
{
return ",@(get-module)";
}
#endregion static private methods used only on this file
#region private methods called using reflection from show-command
/// <summary>
/// Gets the command to be run when calling show-command for a particular command
/// </summary>
/// <param name="commandName">the particular command we are running show-command on</param>
/// <param name="includeAliasAndModules">true if we want to include aliases and retrieve modules</param>
/// <returns>the command to be run when calling show-command for a particular command</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private static string GetShowCommandCommand(string commandName, bool includeAliasAndModules)
{
string quotedCommandName = ShowCommandHelper.SingleQuote(commandName);
return "@(get-command " + quotedCommandName + " " + ShowCommandHelper.CommandTypeSegment +
(includeAliasAndModules ? ",Alias" : String.Empty) + ")" +
(includeAliasAndModules ? ShowCommandHelper.GetGetModuleSuffix() : String.Empty);
}
/// <summary>
/// Gets a CommandViewModel of a CommandInfo
/// </summary>
/// <param name="command">command we want to get a CommandViewModel of</param>
/// <param name="noCommonParameter">true if we do not want common parameters</param>
/// <param name="importedModules">the loaded modules</param>
/// <param name="moduleQualify">True to qualify command with module name in GetScript</param>
/// <returns>a CommandViewModel of a CommandInfo</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private static object GetCommandViewModel(ShowCommandCommandInfo command, bool noCommonParameter, Dictionary<string, ShowCommandModuleInfo> importedModules, bool moduleQualify)
{
CommandViewModel returnValue = CommandViewModel.GetCommandViewModel(new ModuleViewModel(command.ModuleName, importedModules), command, noCommonParameter);
returnValue.ModuleQualifyCommandName = moduleQualify;
return returnValue;
}
/// <summary>
/// Dispatches a message to the window for it to activate
/// </summary>
/// <param name="window">window to be activated</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from ActivateWindow() which is called using reflection")]
private static void ActivateWindow(Window window)
{
window.Dispatcher.Invoke(
new SendOrPostCallback(
delegate(object ignored)
{
window.Activate();
}),
String.Empty);
}
/// <summary>
/// Sets a property in ISE that will allow the command to be run
/// </summary>
/// <param name="command">command to be run</param>
/// <returns>true if it was possible to set the pending ISE command</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private bool SetPendingISECommand(string command)
{
Diagnostics.Assert(this.hostWindow != null, "The caller checks that");
Type internalHostType = this.hostWindow.GetType().Assembly.GetType("Microsoft.Windows.PowerShell.Gui.Internal.PSGInternalHost");
if (internalHostType == null)
{
return false;
}
object current = GetPropertyValue(internalHostType, null, "Current", BindingFlags.Public | BindingFlags.Static);
if (current == null)
{
return false;
}
object powerShellTabs = GetPropertyValue(current.GetType(), current, "PowerShellTabs", BindingFlags.Public | BindingFlags.Instance);
if (powerShellTabs == null)
{
return false;
}
object selectedPowerShellTab = GetPropertyValue(powerShellTabs.GetType(), powerShellTabs, "SelectedPowerShellTab", BindingFlags.Public | BindingFlags.Instance);
if (selectedPowerShellTab == null)
{
return false;
}
return SetPropertyValue(selectedPowerShellTab.GetType(), selectedPowerShellTab, "PendingCommand", command, BindingFlags.NonPublic | BindingFlags.Instance);
}
/// <summary>
/// Shows the window listing cmdlets
/// </summary>
/// <param name="cmdlet">cmdlet calling this method</param>
/// <param name="importedModules">All loaded modules</param>
/// <param name="commands">commands to be listed</param>
/// <param name="noCommonParameter">true if we should not show common parameters</param>
/// <param name="windowWidth">window width</param>
/// <param name="windowHeight">window height</param>
/// <param name="passThrough">true if the GUI should mention ok instead of run</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private void ShowAllModulesWindow(PSCmdlet cmdlet, Dictionary<string, ShowCommandModuleInfo> importedModules, IEnumerable<ShowCommandCommandInfo> commands, bool noCommonParameter, double windowWidth, double windowHeight, bool passThrough)
{
this.methodThatReturnsDialog = new DispatcherOperationCallback(delegate(object ignored)
{
Diagnostics.Assert(commands.GetEnumerator().MoveNext(), "there is always at least one command");
ShowAllModulesWindow allModulesWindow = new ShowAllModulesWindow();
this.allModulesViewModel = new AllModulesViewModel(importedModules, commands, noCommonParameter);
this.SetupButtonEvents(allModulesWindow.Run, allModulesWindow.Copy, allModulesWindow.Cancel, passThrough);
this.SetupWindow(allModulesWindow);
this.SetupViewModel();
CommonHelper.SetStartingPositionAndSize(
allModulesWindow,
ShowCommandSettings.Default.ShowCommandsTop,
ShowCommandSettings.Default.ShowCommandsLeft,
windowWidth != 0.0 && windowWidth > allModulesWindow.MinWidth ? windowWidth : ShowCommandSettings.Default.ShowCommandsWidth,
windowHeight != 0.0 && windowHeight > allModulesWindow.MinHeight ? windowHeight : ShowCommandSettings.Default.ShowCommandsHeight,
allModulesWindow.Width,
allModulesWindow.Height,
ShowCommandSettings.Default.ShowCommandsWindowMaximized);
return allModulesWindow;
});
this.CallShowDialog(cmdlet);
}
/// <summary>
/// Calls ShowsDialog on methodThatReturnsDialog either in a separate thread or dispatched
/// to the hostWindow thread if there is a hostWindow
/// </summary>
/// <param name="cmdlet">cmdlet used to retrieve the host window</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from a method called using reflection")]
private void CallShowDialog(PSCmdlet cmdlet)
{
this.hostWindow = ShowCommandHelper.GetHostWindow(cmdlet);
if (this.hostWindow == null)
{
Thread guiThread = new Thread(new ThreadStart(this.PlainInvokeAndShowDialog));
guiThread.SetApartmentState(ApartmentState.STA);
guiThread.Start();
return;
}
this.hostWindow.Dispatcher.Invoke(
new SendOrPostCallback(
delegate(object ignored)
{
Window childWindow = (Window)this.methodThatReturnsDialog.Invoke(null);
childWindow.Owner = this.hostWindow;
childWindow.Show();
}),
String.Empty);
}
/// <summary>
/// Called from CallMethodThatShowsDialog as the thtead start when there is no host window
/// </summary>
private void PlainInvokeAndShowDialog()
{
((Window)this.methodThatReturnsDialog.Invoke(null)).ShowDialog();
}
/// <summary>
/// Shows the window for the cmdlet
/// </summary>
/// <param name="cmdlet">cmdlet calling this method</param>
/// <param name="commandViewModelObj">command to show in the window</param>
/// <param name="windowWidth">window width</param>
/// <param name="windowHeight">window height</param>
/// <param name="passThrough">true if the GUI should mention ok instead of run</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private void ShowCommandWindow(PSCmdlet cmdlet, object commandViewModelObj, double windowWidth, double windowHeight, bool passThrough)
{
this.methodThatReturnsDialog = new DispatcherOperationCallback(delegate(object ignored)
{
Diagnostics.Assert(commandViewModelObj != null, "verified by caller");
this.commandViewModel = (CommandViewModel)commandViewModelObj;
ShowCommandWindow showCommandWindow = new ShowCommandWindow();
this.commandViewModel.HelpNeeded += new EventHandler<HelpNeededEventArgs>(this.CommandNeedsHelp);
showCommandWindow.DataContext = this.commandViewModel;
this.SetupButtonEvents(showCommandWindow.Run, showCommandWindow.Copy, showCommandWindow.Cancel, passThrough);
this.SetupWindow(showCommandWindow);
CommonHelper.SetStartingPositionAndSize(
showCommandWindow,
ShowCommandSettings.Default.ShowOneCommandTop,
ShowCommandSettings.Default.ShowOneCommandLeft,
windowWidth != 0.0 && windowWidth > showCommandWindow.MinWidth ? windowWidth : ShowCommandSettings.Default.ShowOneCommandWidth,
windowHeight != 0.0 && windowHeight > showCommandWindow.MinHeight ? windowHeight : ShowCommandSettings.Default.ShowOneCommandHeight,
showCommandWindow.Width,
showCommandWindow.Height,
ShowCommandSettings.Default.ShowOneCommandWindowMaximized);
return showCommandWindow;
});
this.CallShowDialog(cmdlet);
}
/// <summary>
/// Called when the module importation is done
/// </summary>
/// <param name="importedModules">all modules currently imported</param>
/// <param name="commands">commands to be displayed</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private void ImportModuleDone(Dictionary<string, ShowCommandModuleInfo> importedModules, IEnumerable<ShowCommandCommandInfo> commands)
{
this.allModulesViewModel.WaitMessageDisplayed = false;
if (this.window != null)
{
this.window.Dispatcher.Invoke(
new SendOrPostCallback(
delegate(object ignored)
{
this.allModulesViewModel = ShowCommandHelper.GetNewAllModulesViewModel(
this.allModulesViewModel,
importedModules,
commands,
this.selectedModuleNeedingImportModule,
this.parentModuleNeedingImportModule,
this.commandNeedingImportModule);
this.SetupViewModel();
}),
String.Empty);
}
}
/// <summary>
/// Called when the module importation has failed
/// </summary>
/// <param name="reason">reason why the module importation failed</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private void ImportModuleFailed(Exception reason)
{
this.allModulesViewModel.WaitMessageDisplayed = false;
if (this.window != null)
{
this.window.Dispatcher.Invoke(
new SendOrPostCallback(
delegate(object ignored)
{
string message = ShowCommandHelper.GetImportModuleFailedMessage(
this.commandNeedingImportModule,
this.parentModuleNeedingImportModule,
reason.Message);
MessageBox.Show(this.window, message, ShowCommandResources.ShowCommandError, MessageBoxButton.OK, MessageBoxImage.Error);
}),
String.Empty);
}
}
/// <summary>
/// Called when the results or get-help are ready in order to display the help window for a command
/// </summary>
/// <param name="getHelpResults">results of a get-help call</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private void DisplayHelp(Collection<PSObject> getHelpResults)
{
if (this.window != null && getHelpResults != null && getHelpResults.Count > 0)
{
this.window.Dispatcher.Invoke(
new SendOrPostCallback(
delegate(object ignored)
{
HelpWindow help = new HelpWindow(getHelpResults[0]);
help.Owner = this.window;
help.Show();
}),
String.Empty);
}
}
/// <summary>
/// Activates this.window
/// </summary>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private void ActivateWindow()
{
if (this.window != null)
{
ShowCommandHelper.ActivateWindow(this.window);
}
}
/// <summary>
/// returns the script to execute if dialog has not been canceled
/// </summary>
/// <returns>the script to execute if dialog has not been canceled</returns>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called using reflection")]
private string GetScript()
{
if (this.dialogCanceled)
{
return null;
}
return this.InternalGetScript();
}
#endregion private methods called using reflection from show-command
#region instance private methods used only on this file
/// <summary>
/// Sets up window settings common between the two flavors of show-command
/// </summary>
/// <param name="commandWindow">the window being displayed</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from ShowAllModulesWindow and ShowCommandWindow which are called with reflection")]
private void SetupWindow(Window commandWindow)
{
this.window = commandWindow;
this.window.Closed += new EventHandler(this.Window_Closed);
this.window.Loaded += new RoutedEventHandler(this.Window_Loaded);
}
/// <summary>
/// Handles the SelectedCommandInSelectedModuleNeedsImportModule event
/// </summary>
/// <param name="sender">event sender</param>
/// <param name="e">event arguments</param>
private void CommandNeedsImportModule(object sender, ImportModuleEventArgs e)
{
this.commandNeedingImportModule = e.CommandName;
this.parentModuleNeedingImportModule = e.ParentModuleName;
this.selectedModuleNeedingImportModule = e.SelectedModuleName;
this.allModulesViewModel.WaitMessageDisplayed = true;
this.ImportModuleNeeded.Set();
}
/// <summary>
/// Handles the SelectedCommandInSelectedModuleNeedsHelp event
/// </summary>
/// <param name="sender">event sender</param>
/// <param name="e">event arguments</param>
private void CommandNeedsHelp(object sender, HelpNeededEventArgs e)
{
this.commandNeedingHelp = e.CommandName;
this.HelpNeeded.Set();
}
/// <summary>
/// Called when the window is closed to set this.dialogCanceled
/// </summary>
/// <param name="sender">event sender</param>
/// <param name="e">event arguments</param>
private void Window_Closed(object sender, EventArgs e)
{
if (this.hostWindow != null)
{
this.hostWindow.Focus();
}
this.window = null;
this.windowClosed.Set();
}
/// <summary>
/// Called when the window is loaded to set this.Window_Loaded
/// </summary>
/// <param name="sender">event sender</param>
/// <param name="e">event arguments</param>
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.window.Loaded -= new RoutedEventHandler(this.Window_Loaded);
this.windowLoaded.Set();
}
/// <summary>
/// Sets up event listening on the buttons
/// </summary>
/// <param name="run">button to run command</param>
/// <param name="copy">button to copy command code</param>
/// <param name="cancel">button to close window</param>
/// <param name="passThrough">true to change the text of Run to OK</param>
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Called from methods called using reflection")]
private void SetupButtonEvents(Button run, Button copy, Button cancel, bool passThrough)
{
if (passThrough)
{
run.Content = ShowCommandResources.ActionButtons_Button_Ok;
}
run.Click += new RoutedEventHandler(this.Buttons_RunClick);
copy.Click += new RoutedEventHandler(this.Buttons_CopyClick);
cancel.Click += new RoutedEventHandler(this.Buttons_CancelClick);
}
/// <summary>
/// Sets up event listening for a new viewModel
/// </summary>
private void SetupViewModel()
{
this.allModulesViewModel.SelectedCommandInSelectedModuleNeedsHelp += new EventHandler<HelpNeededEventArgs>(this.CommandNeedsHelp);
this.allModulesViewModel.SelectedCommandInSelectedModuleNeedsImportModule += new EventHandler<ImportModuleEventArgs>(this.CommandNeedsImportModule);
this.window.DataContext = this.allModulesViewModel;
}
/// <summary>
/// Copies the script into the clipboard
/// </summary>
/// <param name="sender">event sender</param>
/// <param name="e">event arguments</param>
private void Buttons_CopyClick(object sender, RoutedEventArgs e)
{
string script = this.InternalGetScript();
if (script == null)
{
return;
}
this.window.Dispatcher.Invoke(new ThreadStart(delegate { ShowCommandHelper.SetClipboardText(script); }));
}
/// <summary>
/// Sets a succesfull dialog result and then closes the window
/// </summary>
/// <param name="sender">event sender</param>
/// <param name="e">event arguments</param>
private void Buttons_RunClick(object sender, RoutedEventArgs e)
{
this.dialogCanceled = false;
this.CloseWindow();
}
/// <summary>
/// Closes the window
/// </summary>
/// <param name="sender">event sender</param>
/// <param name="e">event arguments</param>
private void Buttons_CancelClick(object sender, RoutedEventArgs e)
{
this.CloseWindow();
}
/// <summary>
/// closes the window
/// </summary>
private void CloseWindow()
{
if (this.window == null)
{
return;
}
this.window.Dispatcher.Invoke(new ThreadStart(delegate
{
// This can happen if ISE is closed while show-command is up
if (this.window != null)
{
this.window.Close();
}
}));
}
/// <summary>
/// Showing a MessageBox when user type a invalidate command name.
/// </summary>
/// <param name="errorString">error message</param>
private void ShowErrorString(string errorString)
{
if (errorString != null && errorString.Trim().Length > 0)
{
MessageBox.Show(
String.Format(
CultureInfo.CurrentUICulture,
Microsoft.Management.UI.Internal.ShowCommandResources.EndProcessingErrorMessage,
errorString),
"Show-Command",
MessageBoxButton.OK,
MessageBoxImage.Error);
}
}
/// <summary>
/// returns the script to execute
/// </summary>
/// <returns>the script to execute</returns>
private string InternalGetScript()
{
if (this.allModulesViewModel != null)
{
return this.allModulesViewModel.GetScript();
}
if (this.commandViewModel == null)
{
return null;
}
return this.commandViewModel.GetScript();
}
/// <summary>
/// Implements IDisposable logic
/// </summary>
/// <param name="isDisposing">true if being called from Dispose</param>
private void Dispose(bool isDisposing)
{
if (isDisposing)
{
this.windowClosed.Dispose();
this.helpNeeded.Dispose();
this.windowLoaded.Dispose();
this.importModuleNeeded.Dispose();
}
}
#endregion instance private methods used only on this file
}
}