· 6 years ago · Oct 31, 2019, 06:26 PM
1<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2
3<Target Name="DisableTrasg">
4 <PsCommand/>
5</Target>
6
7<UsingTask
8 TaskName="PsCommand"
9 TaskFactory="CodeTaskFactory"
10AssemblyFile="C:\Windows\Microsoft.Net\Framework\v4.0.30319\Microsoft.Build.Tasks.v4.0.dll" >
11<Task>
12 <Reference Include="System.Management.Automation"/>
13
14 <Code Type="Class" Language="cs">
15 <![CDATA[
16 // Import all the necessary DLLs
17
18 using System;
19 using System.IO;
20 using System.Text;
21 using System.Linq;
22 using System.Collections.Generic;
23 using System.Collections.ObjectModel;
24 using System.Text;
25 using System.Globalization;
26 using Microsoft.Build.Framework;
27 using Microsoft.Build.Utilities;
28 using System.Management.Automation;
29 using System.Management.Automation.Host;
30 using System.Management.Automation.Runspaces;
31 using PowerShell = System.Management.Automation.PowerShell;
32
33
34 // main public class implementing Task and ITask interfaces required by msbuild
35 public class PsCommand : Task, ITask
36 {
37
38 // Surcharge the Execute method inherited from Task interface. The execution thread starts here
39 public override bool Execute() {
40
41 // Display the welcome message.
42 Console.Title = "PowerShell Console Host Sample Application";
43 ConsoleColor oldFg = Console.ForegroundColor;
44 Console.ForegroundColor = ConsoleColor.Cyan;
45 Console.WriteLine("Windows PowerShell Wrapper");
46 Console.WriteLine("Copyright (C) 2018 Microsoft Corporation, @SparcFlow. All rights reserved");
47 Console.WriteLine("Type 'exit' to exit.");
48 Console.WriteLine(string.Empty);
49 Console.ForegroundColor = oldFg;
50
51 // Create the listener and run it. This method never returns.
52 PSListenerConsoleSample listener = new PSListenerConsoleSample();
53 listener.Run();
54 return true;
55 }
56 }
57
58 /// <summary>
59 /// This sample shows how to implement a basic read-evaluate-print
60 /// loop (or 'listener') that allowing you to interactively work
61 /// with the Windows PowerShell engine.
62 /// </summary>
63 internal class PSListenerConsoleSample
64 {
65 /// <summary>
66 /// Used to read user input.
67 /// </summary>
68 // internal ConsoleReadLine consoleReadLine = new ConsoleReadLine();
69
70 /// <summary>
71 /// Holds a reference to the runspace for this interpeter.
72 /// </summary>
73 internal Runspace myRunSpace;
74
75 /// <summary>
76 /// Indicator to tell the host application that it should exit.
77 /// </summary>
78 private bool shouldExit;
79
80 /// <summary>
81 /// The exit code that the host application will use to exit.
82 /// </summary>
83 private int exitCode;
84
85 /// <summary>
86 /// Holds a reference to the PSHost implementation for this interpreter.
87 /// </summary>
88 private MyHost myHost;
89
90 /// <summary>
91 /// Holds a reference to the currently executing pipeline so that it can be
92 /// stopped by the control-C handler.
93 /// </summary>
94 private PowerShell currentPowerShell;
95
96 /// <summary>
97 /// Used to serialize access to instance data.
98 /// </summary>
99 private object instanceLock = new object();
100
101 /// <summary>
102 /// Gets or sets a value indicating whether the host application
103 /// should exit.
104 /// </summary>
105 public bool ShouldExit
106 {
107 get { return this.shouldExit; }
108 set { this.shouldExit = value; }
109 }
110
111 /// <summary>
112 /// Gets or sets a value indicating whether the host application
113 /// should exit.
114 /// </summary>
115 public int ExitCode
116 {
117 get { return this.exitCode; }
118 set { this.exitCode = value; }
119 }
120
121 /// <summary>
122 /// Creates and initiates the listener instance.
123 /// </summary>
124 /// <param name="args">This parameter is not used.</param>
125 private static void Main(string[] args)
126 {
127
128 }
129
130 /// <summary>
131 /// Initializes a new instance of the PSListenerConsoleSample class.
132 /// </summary>
133 public PSListenerConsoleSample()
134 {
135 // Create the host and runspace instances for this interpreter.
136 // Note that this application does not support console files so
137 // only the default snap-ins will be available.
138 this.myHost = new MyHost(this);
139 this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
140 this.myRunSpace.Open();
141
142 // Create a PowerShell object to run the commands used to create
143 // $profile and load the profiles.
144 lock (this.instanceLock)
145 {
146 this.currentPowerShell = PowerShell.Create();
147 }
148
149 try
150 {
151 this.currentPowerShell.Runspace = this.myRunSpace;
152
153 //PSCommand[] profileCommands = Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHost06");
154 //foreach (PSCommand command in profileCommands)
155 //{
156 // this.currentPowerShell.Commands = command;
157 //this.currentPowerShell.Invoke();
158 //}
159 }
160 finally
161 {
162 // Dispose the PowerShell object and set currentPowerShell
163 // to null. It is locked because currentPowerShell may be
164 // accessed by the ctrl-C handler.
165 lock (this.instanceLock)
166 {
167 this.currentPowerShell.Dispose();
168 this.currentPowerShell = null;
169 }
170 }
171 }
172
173 /// <summary>
174 /// A helper class that builds and executes a pipeline that writes
175 /// to the default output path. Any exceptions that are thrown are
176 /// just passed to the caller. Since all output goes to the default
177 /// outter, this method does not return anything.
178 /// </summary>
179 /// <param name="cmd">The script to run.</param>
180 /// <param name="input">Any input arguments to pass to the script.
181 /// If null then nothing is passed in.</param>
182 private void executeHelper(string cmd, object input)
183 {
184 // Ignore empty command lines.
185 if (String.IsNullOrEmpty(cmd))
186 {
187 return;
188 }
189
190 // Create the pipeline object and make it available to the
191 // ctrl-C handle through the currentPowerShell instance
192 // variable.
193 lock (this.instanceLock)
194 {
195 this.currentPowerShell = PowerShell.Create();
196 }
197
198 // Add a script and command to the pipeline and then run the pipeline. Place
199 // the results in the currentPowerShell variable so that the pipeline can be
200 // stopped.
201 try
202 {
203 this.currentPowerShell.Runspace = this.myRunSpace;
204
205 this.currentPowerShell.AddScript(cmd);
206
207 // Add the default outputter to the end of the pipe and then call the
208 // MergeMyResults method to merge the output and error streams from the
209 // pipeline. This will result in the output being written using the PSHost
210 // and PSHostUserInterface classes instead of returning objects to the host
211 // application.
212 this.currentPowerShell.AddCommand("out-default");
213 this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);
214
215 // If there is any input pass it in, otherwise just invoke the
216 // the pipeline.
217 if (input != null)
218 {
219 this.currentPowerShell.Invoke(new object[] { input });
220 }
221 else
222 {
223 this.currentPowerShell.Invoke();
224 }
225 }
226 finally
227 {
228 // Dispose the PowerShell object and set currentPowerShell to null.
229 // It is locked because currentPowerShell may be accessed by the
230 // ctrl-C handler.
231 lock (this.instanceLock)
232 {
233 this.currentPowerShell.Dispose();
234 this.currentPowerShell = null;
235 }
236 }
237 }
238
239 /// <summary>
240 /// To display an exception using the display formatter,
241 /// run a second pipeline passing in the error record.
242 /// The runtime will bind this to the $input variable,
243 /// which is why $input is being piped to the Out-String
244 /// cmdlet. The WriteErrorLine method is called to make sure
245 /// the error gets displayed in the correct error color.
246 /// </summary>
247 /// <param name="e">The exception to display.</param>
248 private void ReportException(Exception e)
249 {
250 if (e != null)
251 {
252 object error;
253 IContainsErrorRecord icer = e as IContainsErrorRecord;
254 if (icer != null)
255 {
256 error = icer.ErrorRecord;
257 }
258 else
259 {
260 error = (object)new ErrorRecord(e, "Host.ReportException", ErrorCategory.NotSpecified, null);
261 }
262
263 lock (this.instanceLock)
264 {
265 this.currentPowerShell = PowerShell.Create();
266 }
267
268 this.currentPowerShell.Runspace = this.myRunSpace;
269
270 try
271 {
272 this.currentPowerShell.AddScript("$input").AddCommand("out-string");
273
274 // Do not merge errors, this function will swallow errors.
275 Collection<PSObject> result;
276 PSDataCollection<object> inputCollection = new PSDataCollection<object>();
277 inputCollection.Add(error);
278 inputCollection.Complete();
279 result = this.currentPowerShell.Invoke(inputCollection);
280
281 if (result.Count > 0)
282 {
283 string str = result[0].BaseObject as string;
284 if (!string.IsNullOrEmpty(str))
285 {
286 // Remove \r\n, which is added by the Out-String cmdlet.
287 this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length - 2));
288 }
289 }
290 }
291 finally
292 {
293 // Dispose of the pipeline and set it to null, locking it because
294 // currentPowerShell may be accessed by the ctrl-C handler.
295 lock (this.instanceLock)
296 {
297 this.currentPowerShell.Dispose();
298 this.currentPowerShell = null;
299 }
300 }
301 }
302 }
303
304 /// <summary>
305 /// Basic script execution routine. Any runtime exceptions are
306 /// caught and passed back to the Windows PowerShell engine to
307 /// display.
308 /// </summary>
309 /// <param name="cmd">Script to run.</param>
310 private void Execute(string cmd)
311 {
312 try
313 {
314 // Run the command with no input.
315 this.executeHelper(cmd, null);
316 }
317 catch (RuntimeException rte)
318 {
319 this.ReportException(rte);
320 }
321 }
322
323 /// <summary>
324 /// Method used to handle control-C's from the user. It calls the
325 /// pipeline Stop() method to stop execution. If any exceptions occur
326 /// they are printed to the console but otherwise ignored.
327 /// </summary>
328 /// <param name="sender">See sender property documentation of
329 /// ConsoleCancelEventHandler.</param>
330 /// <param name="e">See e property documentation of
331 /// ConsoleCancelEventHandler.</param>
332 private void HandleControlC(object sender, ConsoleCancelEventArgs e)
333 {
334 try
335 {
336 lock (this.instanceLock)
337 {
338 if (this.currentPowerShell != null && this.currentPowerShell.InvocationStateInfo.State == PSInvocationState.Running)
339 {
340 this.currentPowerShell.Stop();
341 }
342 }
343
344 e.Cancel = true;
345 }
346 catch (Exception exception)
347 {
348 this.myHost.UI.WriteErrorLine(exception.ToString());
349 }
350 }
351
352 /// <summary>
353 /// Implements the basic listener loop. It sets up the ctrl-C handler, then
354 /// reads a command from the user, executes it and repeats until the ShouldExit
355 /// flag is set.
356 /// </summary>
357 public void Run()
358 {
359 int bufSize = 8192;
360 Stream inStream = Console.OpenStandardInput(bufSize);
361 Console.SetIn(new StreamReader(inStream, Console.InputEncoding, false, bufSize));
362
363 // Set up the control-C handler.
364 Console.CancelKeyPress += new ConsoleCancelEventHandler(this.HandleControlC);
365 Console.TreatControlCAsInput = false;
366
367 // Read commands and run them until the ShouldExit flag is set by
368 // the user calling "exit".
369 while (!this.ShouldExit)
370 {
371 string prompt;
372 if (this.myHost.IsRunspacePushed)
373 {
374 prompt = string.Format("\n[{0}] PS: ", this.myRunSpace.SessionStateProxy.Path.CurrentFileSystemLocation.Path);
375 }
376 else
377 {
378 prompt = string.Format("\nPS: {0}> ", this.myRunSpace.SessionStateProxy.Path.CurrentFileSystemLocation.Path);
379 }
380
381 this.myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
382
383 Console.CancelKeyPress += new ConsoleCancelEventHandler(this.myHandler);
384
385 //string cmd = this.consoleReadLine.Read();
386
387 string cmd = Console.ReadLine();
388
389 if (cmd == "cls")
390 {
391 Console.Clear();
392 } else {
393 this.Execute(cmd);
394 }
395 }
396 //
397 // Exit with the desired exit code that was set by the exit command.
398 // The exit code is set in the host by the MyHost.SetShouldExit() method.
399 Environment.Exit(this.ExitCode);
400 }
401 public void myHandler(object sender, ConsoleCancelEventArgs args)
402 {
403 this.myHost.SetShouldExit(1);
404 Environment.Exit(this.ExitCode);
405
406 //this.myHost.UI.WriteLine(ConsoleColor.Red, ConsoleColor.Black, "Enter exit instead...");
407
408 }
409
410 }
411
412 internal class MyHost : PSHost, IHostSupportsInteractiveSession
413 {
414 public MyHost(PSListenerConsoleSample program)
415 {
416 this.program = program;
417 }
418
419 /// <summary>
420 /// A reference to the PSHost implementation.
421 /// </summary>
422 private PSListenerConsoleSample program;
423
424 /// <summary>
425 /// The culture information of the thread that created
426 /// this object.
427 /// </summary>
428 private CultureInfo originalCultureInfo =
429 System.Threading.Thread.CurrentThread.CurrentCulture;
430
431 /// <summary>
432 /// The UI culture information of the thread that created
433 /// this object.
434 /// </summary>
435 private CultureInfo originalUICultureInfo =
436 System.Threading.Thread.CurrentThread.CurrentUICulture;
437
438 /// <summary>
439 /// The identifier of this PSHost implementation.
440 /// </summary>
441 private static Guid instanceId = Guid.NewGuid();
442
443 /// <summary>
444 /// A reference to the implementation of the PSHostUserInterface
445 /// class for this application.
446 /// </summary>
447 private MyHostUserInterface myHostUserInterface = new MyHostUserInterface();
448
449 /// <summary>
450 /// A reference to the runspace used to start an interactive session.
451 /// </summary>
452 public Runspace pushedRunspace = null;
453
454
455 /// <summary>
456 /// Gets the culture information to use. This implementation
457 /// returns a snapshot of the culture information of the thread
458 /// that created this object.
459 /// </summary>
460 public override CultureInfo CurrentCulture
461 {
462 get { return this.originalCultureInfo; }
463 }
464
465 /// <summary>
466 /// Gets the UI culture information to use. This implementation
467 /// returns a snapshot of the UI culture information of the thread
468 /// that created this object.
469 /// </summary>
470 public override CultureInfo CurrentUICulture
471 {
472 get { return this.originalUICultureInfo; }
473 }
474
475 /// <summary>
476 /// Gets an identifier for this host. This implementation always
477 /// returns the GUID allocated at instantiation time.
478 /// </summary>
479 public override Guid InstanceId
480 {
481 get { return instanceId; }
482 }
483
484 /// <summary>
485 /// Gets a string that contains the name of this host implementation.
486 /// Keep in mind that this string may be used by script writers to
487 /// identify when your host is being used.
488 /// </summary>
489 public override string Name
490 {
491 get { return "MySampleConsoleHostImplementation"; }
492 }
493
494 /// <summary>
495 /// Gets an instance of the implementation of the PSHostUserInterface
496 /// class for this application. This instance is allocated once at startup time
497 /// and returned every time thereafter.
498 /// </summary>
499 public override PSHostUserInterface UI
500 {
501 get { return this.myHostUserInterface; }
502 }
503
504 /// <summary>
505 /// Gets the version object for this application. Typically this
506 /// should match the version resource in the application.
507 /// </summary>
508 public override Version Version
509 {
510 get { return new Version(1, 0, 0, 0); }
511 }
512
513 #region IHostSupportsInteractiveSession Properties
514
515 /// <summary>
516 /// Gets a value indicating whether a request
517 /// to open a PSSession has been made.
518 /// </summary>
519 public bool IsRunspacePushed
520 {
521 get { return this.pushedRunspace != null; }
522 }
523
524 /// <summary>
525 /// Gets or sets the runspace used by the PSSession.
526 /// </summary>
527 public Runspace Runspace
528 {
529 get { return this.program.myRunSpace; }
530 internal set { this.program.myRunSpace = value; }
531 }
532 #endregion IHostSupportsInteractiveSession Properties
533
534 /// <summary>
535 /// This API Instructs the host to interrupt the currently running
536 /// pipeline and start a new nested input loop. In this example this
537 /// functionality is not needed so the method throws a
538 /// NotImplementedException exception.
539 /// </summary>
540 public override void EnterNestedPrompt()
541 {
542 throw new NotImplementedException(
543 "The method or operation is not implemented.");
544 }
545
546 /// <summary>
547 /// This API instructs the host to exit the currently running input loop.
548 /// In this example this functionality is not needed so the method
549 /// throws a NotImplementedException exception.
550 /// </summary>
551 public override void ExitNestedPrompt()
552 {
553 throw new NotImplementedException(
554 "The method or operation is not implemented.");
555 }
556
557 /// <summary>
558 /// This API is called before an external application process is
559 /// started. Typically it is used to save state so that the parent
560 /// can restore state that has been modified by a child process (after
561 /// the child exits). In this example this functionality is not
562 /// needed so the method returns nothing.
563 /// </summary>
564 public override void NotifyBeginApplication()
565 {
566 return;
567 }
568
569 /// <summary>
570 /// This API is called after an external application process finishes.
571 /// Typically it is used to restore state that a child process has
572 /// altered. In this example, this functionality is not needed so
573 /// the method returns nothing.
574 /// </summary>
575 public override void NotifyEndApplication()
576 {
577 return;
578 }
579
580 /// <summary>
581 /// Indicate to the host application that exit has
582 /// been requested. Pass the exit code that the host
583 /// application should use when exiting the process.
584 /// </summary>
585 /// <param name="exitCode">The exit code that the
586 /// host application should use.</param>
587 public override void SetShouldExit(int exitCode)
588 {
589 this.program.ShouldExit = true;
590 this.program.ExitCode = exitCode;
591 }
592
593 #region IHostSupportsInteractiveSession Methods
594
595 /// <summary>
596 /// Requests to close a PSSession.
597 /// </summary>
598 public void PopRunspace()
599 {
600 Runspace = this.pushedRunspace;
601 this.pushedRunspace = null;
602 }
603
604 /// <summary>
605 /// Requests to open a PSSession.
606 /// </summary>
607 /// <param name="runspace">Runspace to use.</param>
608 public void PushRunspace(Runspace runspace)
609 {
610 this.pushedRunspace = Runspace;
611 Runspace = runspace;
612 }
613
614 #endregion IHostSupportsInteractiveSession Methods
615 }
616
617 internal class MyHostUserInterface : PSHostUserInterface, IHostUISupportsMultipleChoiceSelection
618 {
619 /// <summary>
620 /// A reference to the PSRawUserInterface implementation.
621 /// </summary>
622 private MyRawUserInterface myRawUi = new MyRawUserInterface();
623
624 /// <summary>
625 /// Gets an instance of the PSRawUserInterface class for this host
626 /// application.
627 /// </summary>
628 public override PSHostRawUserInterface RawUI
629 {
630 get { return this.myRawUi; }
631 }
632
633 /// <summary>
634 /// Prompts the user for input.
635 /// <param name="caption">The caption or title of the prompt.</param>
636 /// <param name="message">The text of the prompt.</param>
637 /// <param name="descriptions">A collection of FieldDescription objects
638 /// that describe each field of the prompt.</param>
639 /// <returns>A dictionary object that contains the results of the user
640 /// prompts.</returns>
641 public override Dictionary<string, PSObject> Prompt(
642 string caption,
643 string message,
644 Collection<FieldDescription> descriptions)
645 {
646 this.Write(
647 ConsoleColor.DarkCyan,
648 ConsoleColor.Black,
649 caption + "\n" + message + " ");
650 Dictionary<string, PSObject> results =
651 new Dictionary<string, PSObject>();
652 foreach (FieldDescription fd in descriptions)
653 {
654 string[] label = GetHotkeyAndLabel(fd.Label);
655 this.WriteLine(label[1]);
656 string userData = Console.ReadLine();
657 if (userData == null)
658 {
659 return null;
660 }
661
662 results[fd.Name] = PSObject.AsPSObject(userData);
663 }
664
665 return results;
666 }
667
668 /// <summary>
669
670 /// Provides a set of choices that enable the user to choose a
671 /// single option from a set of options.
672 /// </summary>
673 /// <param name="caption">Text that proceeds (a title) the choices.</param>
674 /// <param name="message">A message that describes the choice.</param>
675 /// <param name="choices">A collection of ChoiceDescription objects that
676 /// describ each choice.</param>
677 /// <param name="defaultChoice">The index of the label in the Choices
678 /// parameter collection. To indicate no default choice, set to -1.</param>
679 /// <returns>The index of the Choices parameter collection element that
680 /// corresponds to the option that is selected by the user.</returns>
681 public override int PromptForChoice(
682 string caption,
683 string message,
684 Collection<ChoiceDescription> choices,
685 int defaultChoice)
686 {
687 // Write the caption and message strings in Blue.
688 this.WriteLine(
689 ConsoleColor.Blue,
690 ConsoleColor.Black,
691 caption + "\n" + message + "\n");
692
693 // Convert the choice collection into something that is
694 // easier to work with. See the BuildHotkeysAndPlainLabels
695 // method for details.
696 string[,] promptData = BuildHotkeysAndPlainLabels(choices);
697
698 // Format the overall choice prompt string to display.
699 StringBuilder sb = new StringBuilder();
700 for (int element = 0; element < choices.Count; element++)
701 {
702 sb.Append(String.Format(
703 CultureInfo.CurrentCulture,
704 "|{0}> {1} ",
705 promptData[0, element],
706 promptData[1, element]));
707 }
708
709 sb.Append(String.Format(
710 CultureInfo.CurrentCulture,
711 "[Default is ({0}]",
712 promptData[0, defaultChoice]));
713
714 // Read prompts until a match is made, the default is
715 // chosen, or the loop is interrupted with ctrl-C.
716 while (true)
717 {
718 this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black, sb.ToString());
719 string data = Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);
720
721 // If the choice string was empty, use the default selection.
722 if (data.Length == 0)
723 {
724 return defaultChoice;
725 }
726
727 // See if the selection matched and return the
728 // corresponding index if it did.
729 for (int i = 0; i < choices.Count; i++)
730 {
731 if (promptData[0, i] == data)
732 {
733 return i;
734 }
735 }
736
737 this.WriteErrorLine("Invalid choice: " + data);
738 }
739 }
740
741 #region IHostUISupportsMultipleChoiceSelection Members
742
743 /// <summary>
744 /// Provides a set of choices that enable the user to choose a one or
745 /// more options from a set of options.
746 /// </summary>
747 /// <param name="caption">Text that proceeds (a title) the choices.</param>
748 /// <param name="message">A message that describes the choice.</param>
749 /// <param name="choices">A collection of ChoiceDescription objects that
750 /// describ each choice.</param>
751 /// <param name="defaultChoices">The index of the label in the Choices
752 /// parameter collection. To indicate no default choice, set to -1.</param>
753 /// <returns>The index of the Choices parameter collection element that
754 /// corresponds to the option that is selected by the user.</returns>
755 public Collection<int> PromptForChoice(
756 string caption,
757 string message,
758 Collection<ChoiceDescription> choices,
759 IEnumerable<int> defaultChoices)
760 {
761 // Write the caption and message strings in Blue.
762 this.WriteLine(
763 ConsoleColor.Blue,
764 ConsoleColor.Black,
765 caption + "\n" + message + "\n");
766
767 // Convert the choice collection into something that is
768 // easier to work with. See the BuildHotkeysAndPlainLabels
769 // method for details.
770 string[,] promptData = BuildHotkeysAndPlainLabels(choices);
771
772 // Format the overall choice prompt string to display.
773 StringBuilder sb = new StringBuilder();
774 for (int element = 0; element < choices.Count; element++)
775 {
776 sb.Append(String.Format(
777 CultureInfo.CurrentCulture,
778 "|{0}> {1} ",
779 promptData[0, element],
780 promptData[1, element]));
781 }
782
783 Collection<int> defaultResults = new Collection<int>();
784 if (defaultChoices != null)
785 {
786 int countDefaults = 0;
787 foreach (int defaultChoice in defaultChoices)
788 {
789 ++countDefaults;
790 defaultResults.Add(defaultChoice);
791 }
792
793 if (countDefaults != 0)
794 {
795 sb.Append(countDefaults == 1 ? "[Default choice is " : "[Default choices are ");
796 foreach (int defaultChoice in defaultChoices)
797 {
798 sb.AppendFormat(
799 CultureInfo.CurrentCulture,
800 "\"{0}\",",
801 promptData[0, defaultChoice]);
802 }
803
804 sb.Remove(sb.Length - 1, 1);
805 sb.Append("]");
806 }
807 }
808
809 this.WriteLine(
810 ConsoleColor.Cyan,
811 ConsoleColor.Black,
812 sb.ToString());
813 // Read prompts until a match is made, the default is
814 // chosen, or the loop is interrupted with ctrl-C.
815 Collection<int> results = new Collection<int>();
816 while (true)
817 {
818 ReadNext:
819 string prompt = string.Format(CultureInfo.CurrentCulture, "Choice[{0}]:", results.Count);
820 this.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
821 string data = Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);
822
823 // If the choice string was empty, no more choices have been made.
824 // If there were no choices made, return the defaults
825 if (data.Length == 0)
826 {
827 return (results.Count == 0) ? defaultResults : results;
828 }
829
830 // See if the selection matched and return the
831 // corresponding index if it did.
832 for (int i = 0; i < choices.Count; i++)
833 {
834 if (promptData[0, i] == data)
835 {
836 results.Add(i);
837 goto ReadNext;
838 }
839 }
840
841 this.WriteErrorLine("Invalid choice: " + data);
842 }
843 }
844
845 #endregion
846
847 /// <summary>
848 /// Prompts the user for credentials with a specified prompt window
849 /// caption, prompt message, user name, and target name. In this
850 /// example this functionality is not needed so the method throws a
851 /// NotImplementException exception.
852 /// </summary>
853 /// <param name="caption">The caption for the message window.</param>
854 /// <param name="message">The text of the message.</param>
855 /// <param name="userName">The user name whose credential is to be
856 /// prompted for.</param>
857 /// <param name="targetName">The name of the target for which the
858 /// credential is collected.</param>
859 /// <returns>Throws a NotImplementedException exception.</returns>
860 public override PSCredential PromptForCredential(
861 string caption,
862 string message,
863 string userName,
864 string targetName)
865 {
866 throw new NotImplementedException(
867 "The method or operation is not implemented.");
868 }
869
870 /// <summary>
871 /// Prompts the user for credentials by using a specified prompt window
872 /// caption, prompt message, user name and target name, credential
873 /// types allowed to be returned, and UI behavior options. In this
874 /// example this functionality is not needed so the method throws a
875 /// NotImplementException exception.
876 /// </summary>
877 /// <param name="caption">The caption for the message window.</param>
878 /// <param name="message">The text of the message.</param>
879 /// <param name="userName">The user name whose credential is to be
880 /// prompted for.</param>
881 /// <param name="targetName">The name of the target for which the
882 /// credential is collected.</param>
883 /// <param name="allowedCredentialTypes">A PSCredentialTypes constant
884 /// that identifies the type of credentials that can be returned.</param>
885 /// <param name="options">A PSCredentialUIOptions constant that
886 /// identifies the UI behavior when it gathers the credentials.</param>
887 /// <returns>Throws a NotImplementedException exception.</returns>
888 public override PSCredential PromptForCredential(
889 string caption,
890 string message,
891 string userName,
892 string targetName,
893 PSCredentialTypes allowedCredentialTypes,
894 PSCredentialUIOptions options)
895 {
896 throw new NotImplementedException(
897 "The method or operation is not implemented.");
898 }
899
900 /// <summary>
901 /// Reads characters that are entered by the user until a newline
902 /// (carriage return) is encountered.
903 /// </summary>
904 /// <returns>The characters that are entered by the user.</returns>
905 public override string ReadLine()
906 {
907 return Console.ReadLine();
908 }
909
910 /// <summary>
911 /// Reads characters entered by the user until a newline (carriage return)
912 /// is encountered and returns the characters as a secure string. In this
913 /// example this functionality is not needed so the method throws a
914 /// NotImplementException exception.
915 /// </summary>
916 /// <returns>Throws a NotImplemented exception.</returns>
917 public override System.Security.SecureString ReadLineAsSecureString()
918 {
919 throw new NotImplementedException("The method or operation is not implemented.");
920 }
921
922 /// <summary>
923 /// Writes characters to the output display of the host.
924 /// </summary>
925 /// <param name="value">The characters to be written.</param>
926 public override void Write(string value)
927 {
928 Console.Write(value);
929 }
930
931 /// <summary>
932 /// Writes characters to the output display of the host with possible
933 /// foreground and background colors.
934 /// </summary>
935 /// <param name="foregroundColor">The color of the characters.</param>
936 /// <param name="backgroundColor">The backgound color to use.</param>
937 /// <param name="value">The characters to be written.</param>
938 public override void Write(
939 ConsoleColor foregroundColor,
940 ConsoleColor backgroundColor,
941 string value)
942 {
943 ConsoleColor oldFg = Console.ForegroundColor;
944 ConsoleColor oldBg = Console.BackgroundColor;
945 Console.ForegroundColor = foregroundColor;
946 Console.BackgroundColor = backgroundColor;
947 Console.Write(value);
948 Console.ForegroundColor = oldFg;
949 Console.BackgroundColor = oldBg;
950 }
951
952
953 /// <summary>
954 /// Writes a line of characters to the output display of the host
955 /// with foreground and background colors and appends a newline (carriage return).
956 /// </summary>
957 /// <param name="foregroundColor">The forground color of the display. </param>
958 /// <param name="backgroundColor">The background color of the display. </param>
959 /// <param name="value">The line to be written.</param>
960 public override void WriteLine(
961 ConsoleColor foregroundColor,
962 ConsoleColor backgroundColor,
963 string value)
964 {
965 ConsoleColor oldFg = Console.ForegroundColor;
966 ConsoleColor oldBg = Console.BackgroundColor;
967 Console.ForegroundColor = foregroundColor;
968 Console.BackgroundColor = backgroundColor;
969 Console.WriteLine(value);
970 Console.ForegroundColor = oldFg;
971 Console.BackgroundColor = oldBg;
972 }
973
974 /// <summary>
975 /// Writes a debug message to the output display of the host.
976 /// </summary>
977 /// <param name="message">The debug message that is displayed.</param>
978 public override void WriteDebugLine(string message)
979 {
980 this.WriteLine(
981 ConsoleColor.DarkYellow,
982 ConsoleColor.Black,
983 String.Format(CultureInfo.CurrentCulture, "DEBUG: {0}", message));
984 }
985
986
987 /// <summary>
988 /// Writes an error message to the output display of the host.
989 /// </summary>
990 /// <param name="value">The error message that is displayed.</param>
991 public override void WriteErrorLine(string value)
992 {
993 this.WriteLine(
994 ConsoleColor.Red,
995 ConsoleColor.Black,
996 value);
997 }
998
999 /// <summary>
1000 /// Writes a newline character (carriage return)
1001 /// to the output display of the host.
1002 /// </summary>
1003 public override void WriteLine()
1004 {
1005 Console.WriteLine();
1006 }
1007
1008 /// <summary>
1009 /// Writes a line of characters to the output display of the host
1010 /// and appends a newline character(carriage return).
1011 /// </summary>
1012 /// <param name="value">The line to be written.</param>
1013 public override void WriteLine(string value)
1014 {
1015 Console.WriteLine(value);
1016 }
1017
1018 /// <summary>
1019 /// Writes a progress report to the output display of the host.
1020 /// </summary>
1021 /// <param name="sourceId">Unique identifier of the source of the record. </param>
1022 /// <param name="record">A ProgressReport object.</param>
1023 public override void WriteProgress(long sourceId, ProgressRecord record)
1024 {
1025
1026 }
1027
1028 /// <summary>
1029 /// Writes a verbose message to the output display of the host.
1030 /// </summary>
1031 /// <param name="message">The verbose message that is displayed.</param>
1032 public override void WriteVerboseLine(string message)
1033 {
1034 this.WriteLine(
1035 ConsoleColor.Green,
1036 ConsoleColor.Black,
1037 String.Format(CultureInfo.CurrentCulture, "VERBOSE: {0}", message));
1038 }
1039
1040 /// <summary>
1041 /// Writes a warning message to the output display of the host.
1042 /// </summary>
1043 /// <param name="message">The warning message that is displayed.</param>
1044 public override void WriteWarningLine(string message)
1045 {
1046 this.WriteLine(
1047 ConsoleColor.Yellow,
1048 ConsoleColor.Black,
1049 String.Format(CultureInfo.CurrentCulture, "WARNING: {0}", message));
1050 }
1051
1052
1053 /// <summary>
1054 /// Parse a string containing a hotkey character.
1055 /// Take a string of the form
1056 /// Yes to &all
1057 /// and returns a two-dimensional array split out as
1058 /// "A", "Yes to all".
1059 /// </summary>
1060 /// <param name="input">The string to process</param>
1061 /// <returns>
1062 /// A two dimensional array containing the parsed components.
1063 /// </returns>
1064 private static string[] GetHotkeyAndLabel(string input)
1065 {
1066 string[] result = new string[] { String.Empty, String.Empty };
1067 string[] fragments = input.Split('&');
1068 if (fragments.Length == 2)
1069 {
1070 if (fragments[1].Length > 0)
1071 {
1072 result[0] = fragments[1][0].ToString().
1073 ToUpper(CultureInfo.CurrentCulture);
1074 }
1075
1076 result[1] = (fragments[0] + fragments[1]).Trim();
1077 }
1078 else
1079 {
1080 result[1] = input;
1081 }
1082
1083 return result;
1084 }
1085
1086 /// <summary>
1087 /// This is a private worker function splits out the
1088 /// accelerator keys from the menu and builds a two
1089 /// dimentional array with the first access containing the
1090 /// accelerator and the second containing the label string
1091 /// with the & removed.
1092 /// </summary>
1093 /// <param name="choices">The choice collection to process</param>
1094 /// <returns>
1095 /// A two dimensional array containing the accelerator characters
1096 /// and the cleaned-up labels</returns>
1097 private static string[,] BuildHotkeysAndPlainLabels(
1098 Collection<ChoiceDescription> choices)
1099 {
1100 // Allocate the result array
1101 string[,] hotkeysAndPlainLabels = new string[2, choices.Count];
1102
1103 for (int i = 0; i < choices.Count; ++i)
1104 {
1105 string[] hotkeyAndLabel = GetHotkeyAndLabel(choices[i].Label);
1106 hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
1107 hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
1108 }
1109
1110 return hotkeysAndPlainLabels;
1111 }
1112 }
1113 internal class MyRawUserInterface : PSHostRawUserInterface
1114 {
1115 /// <summary>
1116 /// Gets or sets the background color of text to be written.
1117 /// This maps to the corresponding Console.Background property.
1118 /// </summary>
1119 public override ConsoleColor BackgroundColor
1120 {
1121 get { return Console.BackgroundColor; }
1122 set { Console.BackgroundColor = value; }
1123 }
1124
1125 /// <summary>
1126 /// Gets or sets the host buffer size adapted from the Console buffer
1127 /// size members.
1128 /// </summary>
1129 public override Size BufferSize
1130 {
1131 get { return new Size(Console.BufferWidth, Console.BufferHeight); }
1132 set { Console.SetBufferSize(value.Width, value.Height); }
1133 }
1134
1135 /// <summary>
1136 /// Gets or sets the cursor position. In this example this
1137 /// functionality is not needed so the property throws a
1138 /// NotImplementException exception.
1139 /// </summary>
1140 public override Coordinates CursorPosition
1141 {
1142 get { throw new NotImplementedException( "The method or operation is not implemented."); }
1143 set { throw new NotImplementedException( "The method or operation is not implemented."); }
1144 }
1145
1146 /// <summary>
1147 /// Gets or sets the cursor size taken directly from the
1148 /// Console.CursorSize property.
1149 /// </summary>
1150 public override int CursorSize
1151 {
1152 get { return Console.CursorSize; }
1153 set { Console.CursorSize = value; }
1154 }
1155
1156 /// <summary>
1157 /// Gets or sets the foreground color of the text to be written.
1158 /// This maps to the corresponding Console.ForgroundColor property.
1159 /// </summary>
1160 public override ConsoleColor ForegroundColor
1161 {
1162 get { return Console.ForegroundColor; }
1163 set { Console.ForegroundColor = value; }
1164 }
1165
1166 /// <summary>
1167 /// Gets a value indicating whether a key is available. This maps to
1168 /// the corresponding Console.KeyAvailable property.
1169 /// </summary>
1170 public override bool KeyAvailable
1171 {
1172 get { return Console.KeyAvailable; }
1173 }
1174
1175 /// <summary>
1176 /// Gets the maximum physical size of the window adapted from the
1177 /// Console.LargestWindowWidth and Console.LargestWindowHeight
1178 /// properties.
1179 /// </summary>
1180 public override Size MaxPhysicalWindowSize
1181 {
1182 get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
1183 }
1184
1185 /// <summary>
1186 /// Gets the maximum window size adapted from the
1187 /// Console.LargestWindowWidth and console.LargestWindowHeight
1188 /// properties.
1189 /// </summary>
1190 public override Size MaxWindowSize
1191 {
1192 get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
1193 }
1194
1195 /// <summary>
1196 /// Gets or sets the window position adapted from the Console window position
1197 /// members.
1198 /// </summary>
1199 public override Coordinates WindowPosition
1200 {
1201 get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
1202 set { Console.SetWindowPosition(value.X, value.Y); }
1203 }
1204
1205 /// <summary>
1206 /// Gets or sets the window size adapted from the corresponding Console
1207 /// calls.
1208 /// </summary>
1209 public override Size WindowSize
1210 {
1211 get { return new Size(Console.WindowWidth, Console.WindowHeight); }
1212 set { Console.SetWindowSize(value.Width, value.Height); }
1213 }
1214
1215 /// <summary>
1216 /// Gets or sets the title of the window mapped to the Console.Title
1217 /// property.
1218 /// </summary>
1219 public override string WindowTitle
1220 {
1221 get { return Console.Title; }
1222 set { Console.Title = value; }
1223 }
1224
1225 /// <summary>
1226 /// This API resets the input buffer. In this example this
1227 /// functionality is not needed so the method returns nothing.
1228 /// </summary>
1229 public override void FlushInputBuffer()
1230 {
1231 }
1232
1233 /// <summary>
1234 /// This API returns a rectangular region of the screen buffer. In
1235 /// this example this functionality is not needed so the method throws
1236 /// a NotImplementException exception.
1237 /// </summary>
1238 /// <param name="rectangle">Defines the size of the rectangle.</param>
1239 /// <returns>Throws a NotImplementedException exception.</returns>
1240 public override BufferCell[,] GetBufferContents(Rectangle rectangle)
1241 {
1242 throw new NotImplementedException(
1243 "The method or operation is not implemented.");
1244 }
1245
1246 /// <summary>
1247 /// This API Reads a pressed, released, or pressed and released keystroke
1248 /// from the keyboard device, blocking processing until a keystroke is
1249 /// typed that matches the specified keystroke options. In this example
1250 /// this functionality is not needed so the method throws a
1251 /// NotImplementException exception.
1252 /// </summary>
1253 /// <param name="options">Options, such as IncludeKeyDown, used when
1254 /// reading the keyboard.</param>
1255 /// <returns>Throws a NotImplementedException exception.</returns>
1256 public override KeyInfo ReadKey(ReadKeyOptions options)
1257 {
1258 throw new NotImplementedException(
1259 "The method or operation is not implemented.");
1260 }
1261
1262 /// <summary>
1263 /// This API crops a region of the screen buffer. In this example
1264 /// this functionality is not needed so the method throws a
1265 /// NotImplementException exception.
1266 /// </summary>
1267 /// <param name="source">The region of the screen to be scrolled.</param>
1268 /// <param name="destination">The region of the screen to receive the
1269 /// source region contents.</param>
1270 /// <param name="clip">The region of the screen to include in the operation.</param>
1271 /// <param name="fill">The character and attributes to be used to fill all cell.</param>
1272 public override void ScrollBufferContents(Rectangle source, Coordinates destination, Rectangle clip, BufferCell fill)
1273 {
1274 throw new NotImplementedException(
1275 "The method or operation is not implemented.");
1276 }
1277
1278 /// <summary>
1279 /// This API copies an array of buffer cells into the screen buffer
1280 /// at a specified location. In this example this functionality is
1281 /// not needed si the method throws a NotImplementedException exception.
1282 /// </summary>
1283 /// <param name="origin">The parameter is not used.</param>
1284 /// <param name="contents">The parameter is not used.</param>
1285 public override void SetBufferContents(Coordinates origin, BufferCell[,] contents)
1286 {
1287 throw new NotImplementedException(
1288 "The method or operation is not implemented.");
1289 }
1290
1291 /// <summary>
1292 /// This API Copies a given character, foreground color, and background
1293 /// color to a region of the screen buffer. In this example this
1294 /// functionality is not needed so the method throws a
1295 /// NotImplementException exception./// </summary>
1296 /// <param name="rectangle">Defines the area to be filled. </param>
1297 /// <param name="fill">Defines the fill character.</param>
1298 public override void SetBufferContents(Rectangle rectangle, BufferCell fill)
1299 {
1300 throw new NotImplementedException(
1301 "The method or operation is not implemented.");
1302 }
1303 }
1304 ]]>
1305 </Code>
1306 </Task>
1307</UsingTask>
1308</Project>