/// <summary> /// Create a Proxy Function for the command supplied. /// </summary> /// <param name="commandInfo"></param> /// <param name="debugStrings"></param> /// <returns></returns> internal static FunctionInfo CreateProxyFunction(CommandInfo commandInfo, List <string> debugStrings) { string proxyCommandName = null; string proxyCommand = ProxyCommand.Create(new CommandMetadata(commandInfo)); ScriptBlock proxyScript = ScriptBlock.Create(proxyCommand); ScriptBlockAst proxyScriptAst = (ScriptBlockAst)proxyScript.Ast; string proxyScriptStr = proxyScriptAst.ParamBlock.ToString() + "; return $PSBoundParameters"; proxyScriptStr = proxyScriptStr.Replace("\r\n", string.Empty); debugStrings.Add(proxyScriptStr); if (commandInfo.CommandType == CommandTypes.ExternalScript) { proxyCommandName = commandInfo.Name.Split('\\').LastOrDefault().Replace(".ps1", "IvAllhelper.ps1"); } else { proxyCommandName = commandInfo.Name + "IvAllhelper"; } debugStrings.Add(string.Format("Creating ProxyFunction {0}", proxyCommandName)); try { PSObject proxyFunctionPSObj = ScriptBlock.Create("param($name, $script) New-Item -Path Function:Global:$name -Value $script -Erroraction Stop") .Invoke(proxyCommandName, proxyScriptStr).FirstOrDefault(); debugStrings.Add(string.Format("Created proxy command {0}", proxyCommandName)); return(proxyFunctionPSObj.BaseObject as FunctionInfo); } catch (ActionPreferenceStopException ae) when((ae.ErrorRecord.Exception is PSArgumentException) && ae.ErrorRecord.Exception.Message.EndsWith("already exists.")) { //Todo: throwterminatingerror here debugStrings.Add("ProxyCommand Already Exsits"); string removeProxyFunction = string.Format("Remove-Item -Path Function:{0} -Force", proxyCommandName); ScriptBlock.Create(removeProxyFunction).Invoke(); throw new Exception(string.Format("Proxy function {0} already exists. It is present from a previous failure of Invoke-all, the script tried to remove it. " + "Simply re-run your command to see if it works, if not, please manually remove the function using {1}", proxyCommandName, removeProxyFunction)); } }
/// <summary> /// Run some commands to demonstrate the script capabilities. /// </summary> private void RunCommands() { this.runspace = RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault()); this.runspace.Open(); this.RunScript("$a=0;$a", "Assigning to a variable will work for a default InitialSessionState"); this.runspace.Close(); this.runspace = RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault()); this.runspace.InitialSessionState.LanguageMode = PSLanguageMode.RestrictedLanguage; this.runspace.Open(); this.RunScript("$a=0;$a", "Assigning to a variable will not work in RestrictedLanguage LanguageMode"); this.runspace.Close(); this.runspace = RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault()); this.runspace.InitialSessionState.LanguageMode = PSLanguageMode.NoLanguage; this.runspace.Open(); this.RunScript("10/2", "A script will not work in NoLanguage LanguageMode"); this.runspace.Close(); this.runspace = RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault()); this.runspace.Open(); string scriptComment = "get-childitem with a default InitialSessionState will work since the standard \n" + "PowerShell cmdlets are included in the default InitialSessionState"; this.RunScript("get-childitem", scriptComment); this.runspace.Close(); InitialSessionState defaultSessionState = InitialSessionState.CreateDefault(); defaultSessionState.Commands.Add(new SessionStateAliasEntry("dir2", "get-childitem")); this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState); this.runspace.Open(); this.RunScript("dir2", "An alias, like dir2, can be added to InitialSessionState"); this.runspace.Close(); defaultSessionState = InitialSessionState.CreateDefault(); int commandIndex = GetIndexOfEntry(defaultSessionState.Commands, "get-childitem"); defaultSessionState.Commands.RemoveItem(commandIndex); this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState); this.runspace.Open(); scriptComment = "get-childitem was removed from the list of commands so it\nwill no longer be found"; this.RunScript("get-childitem", scriptComment); this.runspace.Close(); defaultSessionState = InitialSessionState.CreateDefault(); defaultSessionState.Providers.Clear(); this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState); this.runspace.Open(); this.RunScript("get-childitem", "There are no providers so get-childitem will not work"); this.runspace.Close(); // Marks a command as private, and then defines a proxy command // that uses the private command. One reason to define a proxy for a command is // to remove a parameter of the original command. // For a more complete sample of a proxy command, see the Runspace11 sample. defaultSessionState = InitialSessionState.CreateDefault(); commandIndex = GetIndexOfEntry(defaultSessionState.Commands, "get-childitem"); defaultSessionState.Commands[commandIndex].Visibility = SessionStateEntryVisibility.Private; CommandMetadata getChildItemMetadata = new CommandMetadata( typeof(Microsoft.PowerShell.Commands.GetChildItemCommand)); getChildItemMetadata.Parameters.Remove("Recurse"); string getChildItemBody = ProxyCommand.Create(getChildItemMetadata); defaultSessionState.Commands.Add(new SessionStateFunctionEntry("get-childitem2", getChildItemBody)); this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState); this.runspace.Open(); this.RunScript("get-childitem", "get-childitem is private so it will not be available"); scriptComment = "get-childitem2 is is a proxy to get-childitem. \n" + "It works even when get-childitem is private."; this.RunScript("get-childitem2", scriptComment); scriptComment = "This will fail. Unlike get-childitem, get-childitem2 does not have -Recurse"; this.RunScript("get-childitem2 -Recurse", scriptComment); InitialSessionState cleanSessionState = InitialSessionState.Create(); this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState); this.runspace.Open(); scriptComment = "A script will not work because \n" + "InitialSessionState.Create() will have the default LanguageMode of NoLanguage"; this.RunScript("10/2", scriptComment); this.runspace.Close(); cleanSessionState = InitialSessionState.Create(); cleanSessionState.LanguageMode = PSLanguageMode.FullLanguage; this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState); this.runspace.Open(); scriptComment = "get-childitem, standard cmdlets and providers are not present \n" + "in an InitialSessionState returned from InitialSessionState.Create()"; this.RunScript("get-childitem", scriptComment); this.runspace.Close(); cleanSessionState = InitialSessionState.Create(); cleanSessionState.Commands.Add( new SessionStateCmdletEntry( "Get-ChildItem", typeof(Microsoft.PowerShell.Commands.GetChildItemCommand), null)); cleanSessionState.Providers.Add( new SessionStateProviderEntry( "FileSystem", typeof(Microsoft.PowerShell.Commands.FileSystemProvider), null)); cleanSessionState.LanguageMode = PSLanguageMode.FullLanguage; this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState); this.runspace.Open(); scriptComment = "get-childitem and the FileSystem provider were explicitly added\n" + "so get-childitem will work"; this.RunScript("get-childitem", scriptComment); this.runspace.Close(); Console.Write("Done..."); Console.ReadLine(); }
/// <summary> /// This sample uses the ProxyCommand class to create a proxy command that /// calls an existing cmdlet, but restricts the set of available parameters. /// The proxy command is then added to an intial session state that is used to /// create a contrained runspace. This means that the user can access the cmdlet /// through the proxy command. /// </summary> /// <remarks> /// This sample demonstrates the following: /// 1. Creating a CommandMetadata object that describes the metadata of an /// existing cmdlet. /// 2. Modifying the cmdlet metadata to remove a parameter of the cmdlet. /// 3. Adding the cmdlet to an initial session state and making it private. /// 4. Creating a proxy function that calls the existing cmdlet, but exposes /// only a restricted set of parameters. /// 6. Adding the proxy function to the initial session state. /// 7. Calling the private cmdlet and the proxy function to demonstrate the /// constrained runspace. /// </remarks> private static void Main() { // Create a default intial session state. The default inital session state // includes all the elements that are provided by Windows PowerShell. InitialSessionState iss = InitialSessionState.CreateDefault(); // Add the get-proc cmdlet to the initial session state. SessionStateCmdletEntry cmdletEntry = new SessionStateCmdletEntry("get-proc", typeof(GetProcCommand), null); iss.Commands.Add(cmdletEntry); // Make the cmdlet private so that it is not accessable. cmdletEntry.Visibility = SessionStateEntryVisibility.Private; // Set the language mode of the intial session state to NoLanguge to //prevent users from using language features. Only the invocation of // public commands is allowed. iss.LanguageMode = PSLanguageMode.NoLanguage; // Create the proxy command using cmdlet metadata to expose the // get-proc cmdlet. CommandMetadata cmdletMetadata = new CommandMetadata(typeof(GetProcCommand)); // Remove one of the parameters from the command metadata. cmdletMetadata.Parameters.Remove("Name"); // Generate the body of a proxy function that calls the original cmdlet, // but does not have the removed parameter. string bodyOfProxyFunction = ProxyCommand.Create(cmdletMetadata); // Add the proxy function to the initial session state. The name of the proxy // function can be the same as the name of the cmdlet, but to clearly // demonstrate that the original cmdlet is not available a different name is // used for the proxy function. iss.Commands.Add(new SessionStateFunctionEntry("get-procProxy", bodyOfProxyFunction)); // Create the constrained runspace using the intial session state. using (Runspace myRunspace = RunspaceFactory.CreateRunspace(iss)) { myRunspace.Open(); // Call the private cmdlet to demonstrate that it is not available. try { using (PowerShell powershell = PowerShell.Create()) { powershell.Runspace = myRunspace; powershell.AddCommand("get-proc").AddParameter("Name", "*explore*"); powershell.Invoke(); } } catch (CommandNotFoundException e) { System.Console.WriteLine( "Invoking 'get-proc' failed as expected: {0}: {1}", e.GetType().FullName, e.Message); } // Call the proxy function to demonstrate that the -Name parameter is // not available. try { using (PowerShell powershell = PowerShell.Create()) { powershell.Runspace = myRunspace; powershell.AddCommand("get-procProxy").AddParameter("Name", "idle"); powershell.Invoke(); } } catch (ParameterBindingException e) { System.Console.WriteLine( "\nInvoking 'get-procProxy -Name idle' failed as expected: {0}: {1}", e.GetType().FullName, e.Message); } // Call the proxy function to demonstrate that it calls into the // private cmdlet to retrieve the processes. using (PowerShell powershell = PowerShell.Create()) { powershell.Runspace = myRunspace; powershell.AddCommand("get-procProxy"); List <Process> processes = new List <Process>(powershell.Invoke <Process>()); System.Console.WriteLine( "\nInvoking the get-procProxy function called into the get-proc cmdlet and returned {0} processes", processes.Count); } // Close the runspace to release resources. myRunspace.Close(); } System.Console.WriteLine("Hit any key to exit..."); System.Console.ReadKey(); }