Werbung

Herkunft

Kurzinformation

Starts a WPF Job to display a UI in the background

Syntax

<# .Synopsis Starts a WPF Job to display a UI in the background .Description Starts a WPF Job to display a UI in the background. You can stop the job with the Stop-Job cmdlet, or by closing the window. You can run scripts within the window with the Update-WPFJob cmdlet Start-WPFJob is used implicitly whenever you use the -AsJob parameter. .Example New-Label "Hello World" -AsJob .Example Start-WPFJob { New-Object Windows.Window -Property @{Content="foo"}} #> param( # The Script Block to run in the Job [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [ScriptBlock] $ScriptBlock, # A dictionary of parameters to pass to the job [Hashtable] $Parameter, # The Command that the Job will display in Get-Job (by default, Start-WPFJob) [String] $Command = "Start-WPFJob", # Additional Context script blocks will be parsed to get the commands # the script block uses, but will not be run. # AdditionalContext is used so that commands referenced in parameters # work in background jobs. [ScriptBlock[]] $AdditionalContext, # The name of the job [String] $Name ) begin { # First, make the job type if it does not exist: if (-not ('WPK.WPFJob' -as [Type])) { Write-Verbose "Compiling WPFJob" Add-Type -IgnoreWarnings -ReferencedAssemblies "WindowsBase", "PresentationCore", "PresentationFramework" @" using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using System.Management.Automation; using System.Management.Automation.Runspaces; using System.Threading; using System.Windows.Threading; using System.ComponentModel; using System.Collections.Generic; using System.Collections; using System.Collections.ObjectModel; namespace WPK { public class WPFJob : Job, INotifyPropertyChanged { Runspace runspace; InitialSessionState initialSessionState; PowerShell powerShellCommand; Dispatcher JobDispatcher; public Window JobWindow; Thread jobThread; Hashtable namedControls; Runspace interopRunspace; Runspace GetWPFCurrentThreadRunspace(InitialSessionState sessionState) { InitialSessionState clone = sessionState.Clone(); clone.ThreadOptions = PSThreadOptions.UseCurrentThread; SessionStateVariableEntry window = new SessionStateVariableEntry("Window", JobWindow, ""); SessionStateVariableEntry namedControls = new SessionStateVariableEntry("NamedControls", this.namedControls, ""); clone.Variables.Add(window); clone.Variables.Add(namedControls); return RunspaceFactory.CreateRunspace(clone); } delegate Collection RunScriptCallback(string script); delegate Collection RunScriptWithParameters(string script, Object parameters); public PSObject[] InvokeScriptInJob(string script, object parameters) { if (this.JobStateInfo.State == JobState.Running) { for (int i = 0; i < 10; i++) { if (JobWindow != null) { break; } Thread.Sleep(50); } if (JobWindow == null) { return null; } return (PSObject[])RunOnUIThread( new DispatcherOperationCallback( delegate { PowerShell psCmd = PowerShell.Create(); if (interopRunspace == null) { interopRunspace = GetWPFCurrentThreadRunspace(this.initialSessionState); interopRunspace.Open(); } psCmd.Runspace = interopRunspace; psCmd.AddScript(script); if (parameters is IDictionary) { psCmd.AddParameters(parameters as IDictionary); } else { if (parameters is IList) { psCmd.AddParameters(parameters as IList); } } Collection results = psCmd.Invoke(); if (psCmd.InvocationStateInfo.Reason != null) { throw psCmd.InvocationStateInfo.Reason; } if (psCmd.Streams.Error.Count > 0) { foreach (ErrorRecord err in psCmd.Streams.Error) { throw err.Exception; } } PSObject[] resultArray = new PSObject[results.Count]; int count = 0; foreach (PSObject r in results) { resultArray[count++] = r; } return resultArray; })); } else { return null; } } object RunOnUIThread(DispatcherOperationCallback dispatcherMethod) { if (Application.Current.Dispatcher.Thread == Thread.CurrentThread) { // This avoids dispatching to the UI thread if we are already in the UI thread. // Without this runing a command like 1/0 was throwing due to nested dispatches. return dispatcherMethod.Invoke(null); } Exception e = null; object returnValue = null; SynchronizationContext sync = new DispatcherSynchronizationContext(JobWindow.Dispatcher); sync.Send( new SendOrPostCallback(delegate(object obj) { try { returnValue = dispatcherMethod.Invoke(obj); } catch (Exception uiException) { e = uiException; } }), null); if (e != null) { throw new System.Reflection.TargetInvocationException(e.Message, e); } return returnValue; } public static InitialSessionState GetSessionStateForCommands(CommandInfo[] commands) { InitialSessionState iss = InitialSessionState.CreateDefault(); Dictionary commandCache = new Dictionary(); foreach (SessionStateCommandEntry ssce in iss.Commands) { commandCache[ssce.Name] = ssce; } iss.ApartmentState = ApartmentState.STA; iss.ThreadOptions = PSThreadOptions.ReuseThread; if (commands.Length == 0) { return iss; } foreach (CommandInfo cmd in commands) { if (cmd.Module != null) { if (cmd.ModuleName == "WPK") { if (cmd is AliasInfo) { SessionStateAliasEntry alias = new SessionStateAliasEntry(cmd.Name, cmd.Definition); iss.Commands.Add(alias); } if (cmd is FunctionInfo) { SessionStateFunctionEntry func = new SessionStateFunctionEntry(cmd.Name, cmd.Definition); iss.Commands.Add(func); } } else { iss.ImportPSModule(new string[] { cmd.ModuleName }); } } else { if (! commandCache.ContainsKey(cmd.Name)) { if (cmd is AliasInfo) { CommandInfo loopCommand = cmd; while (loopCommand is AliasInfo) { SessionStateAliasEntry alias = new SessionStateAliasEntry(loopCommand.Name, loopCommand.Definition); iss.Commands.Add(alias); loopCommand = (loopCommand as AliasInfo).ReferencedCommand; } if (loopCommand is FunctionInfo) { SessionStateFunctionEntry func = new SessionStateFunctionEntry(loopCommand.Name, loopCommand.Definition); iss.Commands.Add(func); } if (loopCommand is CmdletInfo) { CmdletInfo cmdletData = loopCommand as CmdletInfo; SessionStateCmdletEntry cmdlet = new SessionStateCmdletEntry(cmd.Name, cmdletData.ImplementingType, cmdletData.HelpFile); iss.Commands.Add(cmdlet); } } if (cmd is FunctionInfo) { SessionStateFunctionEntry func = new SessionStateFunctionEntry(cmd.Name, cmd.Definition); iss.Commands.Add(func); } if (cmd is CmdletInfo) { CmdletInfo cmdletData = cmd as CmdletInfo; SessionStateCmdletEntry cmdlet = new SessionStateCmdletEntry(cmd.Name, cmdletData.ImplementingType, cmdletData.HelpFile); iss.Commands.Add(cmdlet); } } } } return iss; } public WPFJob(string name, string command, ScriptBlock scriptBlock) : base(command, name) { this.initialSessionState = InitialSessionState.CreateDefault(); Start(scriptBlock, new Hashtable()); } public WPFJob(string name, string command, ScriptBlock scriptBlock, InitialSessionState initalSessionState) : base(command, name) { this.initialSessionState = initalSessionState; Start(scriptBlock, new Hashtable()); } public WPFJob(string name, string command, ScriptBlock scriptBlock, InitialSessionState initalSessionState, Hashtable parameters) : base(command, name) { this.initialSessionState = initalSessionState; Start(scriptBlock, parameters); } /// /// Synchronizes Job State with Background Runspace /// /// /// void powerShellCommand_InvocationStateChanged(object sender, PSInvocationStateChangedEventArgs e) { try { if (e.InvocationStateInfo.State == PSInvocationState.Completed) { runspace.Close(); } if (e.InvocationStateInfo.State == PSInvocationState.Failed) { ErrorRecord err = new ErrorRecord(e.InvocationStateInfo.Reason, "JobFailed", ErrorCategory.OperationStopped, this); Error.Add(err); runspace.Close(); } JobState js = (JobState)Enum.Parse(typeof(JobState), e.InvocationStateInfo.State.ToString(), true); this.SetJobState(js); } catch { } } void Start(ScriptBlock scriptBlock, Hashtable parameters) { SessionStateAssemblyEntry windowsBase = new SessionStateAssemblyEntry(typeof(Dispatcher).Assembly.ToString()); SessionStateAssemblyEntry presentationCore = new SessionStateAssemblyEntry(typeof(UIElement).Assembly.ToString()); SessionStateAssemblyEntry presentationFramework = new SessionStateAssemblyEntry(typeof(Control).Assembly.ToString()); initialSessionState.Assemblies.Add(windowsBase); initialSessionState.Assemblies.Add(presentationCore); initialSessionState.Assemblies.Add(presentationFramework); initialSessionState.Assemblies.Add(presentationFramework); runspace = RunspaceFactory.CreateRunspace(this.initialSessionState); runspace.ThreadOptions = PSThreadOptions.ReuseThread; runspace.ApartmentState = ApartmentState.STA; runspace.Open(); powerShellCommand = PowerShell.Create(); powerShellCommand.Runspace = runspace; jobThread = powerShellCommand.AddScript("[Threading.Thread]::CurrentThread").Invoke()[0]; powerShellCommand.Streams.Error = this.Error; this.Error.DataAdded += new EventHandler(Error_DataAdded); powerShellCommand.Streams.Warning = this.Warning; this.Warning.DataAdded += new EventHandler(Warning_DataAdded); powerShellCommand.Streams.Verbose = this.Verbose; this.Verbose.DataAdded += new EventHandler(Verbose_DataAdded); powerShellCommand.Streams.Debug = this.Debug; this.Debug.DataAdded += new EventHandler(Debug_DataAdded); powerShellCommand.Streams.Progress = this.Progress; this.Progress.DataAdded += new EventHandler(Progress_DataAdded); this.Output.DataAdded += new EventHandler(Output_DataAdded); powerShellCommand.Commands.Clear(); powerShellCommand.Commands.AddScript(scriptBlock.ToString(), false); if (parameters.Count > 0) { powerShellCommand.AddParameters(parameters); } Collection output = powerShellCommand.Invoke(); if (output.Count == 0) { return; } powerShellCommand.Commands.Clear(); powerShellCommand.Commands.AddCommand("Show-Window").AddArgument(output[0]).AddParameter("OutputWindowFirst"); Object var = powerShellCommand.Runspace.SessionStateProxy.GetVariable("NamedControls"); if (var != null && ((var as Hashtable) != null)) { namedControls = var as Hashtable; } JobDispatcher = Dispatcher.FromThread(jobThread); JobDispatcher.UnhandledException += new DispatcherUnhandledExceptionEventHandler(jobDispatcher_UnhandledException); powerShellCommand.InvocationStateChanged += new EventHandler(powerShellCommand_InvocationStateChanged); powerShellCommand.BeginInvoke(null, this.Output); } void jobDispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { ErrorRecord err = new ErrorRecord(e.Exception, "UnhandledException", ErrorCategory.OperationStopped, this); this.Error.Add(err); StopJob(); } void Output_DataAdded(object sender, DataAddedEventArgs e) { PSDataCollection output = sender as PSDataCollection; if (output == null) { return; } if (output[e.Index].BaseObject is Window) { JobWindow = output[e.Index].BaseObject as Window; } if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Output")); } } void Progress_DataAdded(object sender, DataAddedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Progress")); } } void Debug_DataAdded(object sender, DataAddedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Debug")); } } void Verbose_DataAdded(object sender, DataAddedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Verbose")); } } void Warning_DataAdded(object sender, DataAddedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Warning")); } } void Error_DataAdded(object sender, DataAddedEventArgs e) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Error")); } } /// /// If the comamnd is running, the job indicates it has more data /// public override bool HasMoreData { get { if (powerShellCommand.InvocationStateInfo.State == PSInvocationState.Running) { return true; } else { return false; } } } public override string Location { get { if (this.JobStateInfo.State == JobState.Running && (JobWindow != null)) { return (string)RunOnUIThread( new DispatcherOperationCallback( delegate { return "Left: " + JobWindow.Left + " Top: " + JobWindow.Top + " Width: " + JobWindow.ActualWidth + " Height: " + JobWindow.ActualHeight; })); } else { return " "; } } } public override string StatusMessage { get { return string.Empty; } } public override void StopJob() { Dispatcher dispatch = Dispatcher.FromThread(jobThread); if (dispatch != null) { if (!dispatch.HasShutdownStarted) { dispatch.InvokeShutdown(); } } powerShellCommand.Stop(); runspace.Close(); } protected override void Dispose(bool disposing) { if (disposing) { powerShellCommand.Dispose(); runspace.Close(); runspace.Dispose(); } base.Dispose(disposing); } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion } } "@ } } process { $src= @($ScriptBlock) + { Show-Window Get-ChildControl Move-Control Start-Animation Get-Resource Set-Resource } if ($AdditionalContext) { $src += $AdditionalContext } $cmds = $src | Get-ReferencedCommand | Select-Object -Unique if (-not $name) {$name = [GUID]::NewGuid() } $iss = [WPK.WPFJob]::GetSessionStateForCommands($cmds) if ($psBoundParameters.ContainsKey("Parameter") -and $Parameter.Count) { $wpfJob = New-Object WPK.WPFJob ($name, $Command, $ScriptBlock, $Iss, $Parameter) } else { $wpfJob = New-Object WPK.WPFJob ($name, $Command, $ScriptBlock, $Iss) } if ($wpfJob) { $null = $PSCmdlet.JobRepository.Add($wpfJob) $wpfJob } }

Beschreibung

Starts a WPF Job to display a UI in the background.You can stop the job with the Stop-Job cmdlet, or by closing the window.You can run scripts within the window with the Update-WPFJob cmdletStart-WPFJob is used implicitly whenever you use the -AsJob parameter.

Links

Liste aller Commandlets Mehr über die Windows PowerShell

Bücher zur PowerShell

Buchcover Windows PowerShell 5.0 - Das Praxishandbuch (1. Auflage 2016/5. Auflage Gesamtreihe) Windows PowerShell 5.0 - Das Praxishandbuch (1. Auflage 2016/5. Auflage Gesamtreihe)
Autoren: Dr. Holger Schwichtenberg
erschienen 2016, 996 Seiten, 49,99 €
ISBN: 3446446435
Bestellung: Amazon.de oder im Buchhandel über ISBN 3446446435

Schulungen/Seminare

Offene Seminare zur PowerShell
In-House-Seminare zur PowerShell