/// <summary> /// Proxy method for substitution of executing Initialize/Reset methods in adapter interface. /// </summary> /// <param name="mcall">The IMethodCallMessage containing method invoking data.</param> /// <param name="helpMessage">The help message from the attribute</param> /// <returns>Always void.</returns> private IMessage InvokeCompact(IMethodCallMessage mcall, string helpMessage) { string path = LookupScript(mcall.MethodName); if (path != null) { TestSite.Log.Add(LogEntryKind.EnterAdapter, "Power Shell adapter: {0}, method: {1}", ProxyType.Name, mcall.MethodName); try { PSParameterBuilder builder = InvokeScript(path, null, helpMessage); //should always return null TestSite.Assert.IsNull(builder, "Compact mode should always return null"); } catch (Exception ex) { TestSite.Log.Add(LogEntryKind.Debug, ex.ToString()); throw; } finally { TestSite.Log.Add(LogEntryKind.ExitAdapter, "Power Shell adapter: {0}, method: {1}", ProxyType.Name, mcall.MethodName); } } else { TestSite.Log.Add(LogEntryKind.Debug, "Power Shell adapter: {0}, method: {1} not found, skipped.", ProxyType.Name, mcall.MethodName); } ReturnMessage mret = new ReturnMessage( null, null, 0, mcall.LogicalCallContext, mcall); return(mret); }
private PSParameterBuilder SetPSVariables( IMethodCallMessage methodCall, Type sessionStateProxy, object proxyInstance, string helpMessage) { //get "SetVariable" method which will set all param as variable. MethodInfo methodSetVariable = sessionStateProxy.GetMethod( "SetVariable", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, new Type[] { typeof(string), typeof(object) }, null ); if (methodSetVariable == null) { throw new InvalidOperationException("Cannot get 'SetVariable' method from SessionStateProxy."); } //set all properties and help message as variable //which can be used in PowerShell script. //set help message as variable methodSetVariable.Invoke(proxyInstance, new object[] { "PtfHelpMessage", helpMessage }); //set all properties as variables foreach (string key in this.TestSite.Properties.AllKeys) { string propName = "PTFProp" + key; methodSetVariable.Invoke( proxyInstance, new object[] { propName, this.TestSite.Properties[key] } ); } if (methodCall != null) { //set all parameters as variables which can be used //by users directly in the PowerShell script PSParameterBuilder builder = new PSParameterBuilder(methodCall); builder.SetAllParametersAsVariables(methodSetVariable, proxyInstance); return(builder); } return(null); }
/// <summary> /// Proxy method for substitution of executing Initialize/Reset methods in adapter interface. /// </summary> /// <param name="targetMethod">The method the caller invoked.</param> /// <param name="helpMessage">The help message from the attribute</param> /// <returns>Always null.</returns> private object ExecuteMethodCompact(MethodInfo targetMethod, string helpMessage) { string path = LookupScript(targetMethod.Name); if (path != null) { TestSite.Log.Add(LogEntryKind.EnterAdapter, "PowerShell adapter: {0}, method: {1}", ProxyType.Name, targetMethod.Name); try { PSParameterBuilder builder = InvokeScript(path, targetMethod, null, helpMessage); //should always return null TestSite.Assert.IsNull(builder, "Compact mode should always return null"); } catch (Exception ex) { TestSite.Log.Add(LogEntryKind.Debug, ex.ToString()); throw; } finally { TestSite.Log.Add(LogEntryKind.ExitAdapter, "Power Shell adapter: {0}, method: {1}", ProxyType.Name, targetMethod.Name); } } else { TestSite.Log.Add(LogEntryKind.Debug, "Power Shell adapter: {0}, method: {1} not found, skipped.", ProxyType.Name, targetMethod.Name); } return(null); }
/// <summary> /// Proxy method for substitution of executing methods in adapter interface. /// </summary> /// <param name="targetMethod">The method the caller invoked.</param> /// <param name="args">The arguments the caller passed to the method.</param> /// <returns>The return value of the ExecuteMethod implementation.</returns> protected override object ExecuteMethod(MethodInfo targetMethod, object[] args) { //get help message from attribute string methodhelp = AdapterProxyHelpers.GetHelpMessage(targetMethod); bool compactMode = ((targetMethod.Name == "Initialize" || targetMethod.Name == "Reset") && AdapterType.IsAdapterTypeFullName(targetMethod.DeclaringType.FullName) ); if (compactMode) { return(ExecuteMethodCompact(targetMethod, methodhelp)); } object retVal = null; object[] outArgs = args; // Check if this is a method from IAdapter. Any IAdapter methods should be ignored. if (!AdapterType.IsAdapterTypeFullName(targetMethod.DeclaringType.FullName) && (targetMethod.DeclaringType.FullName != typeof(IDisposable).FullName) ) { TestSite.Log.Add(LogEntryKind.EnterAdapter, "PowerShell adapter: {0}, method: {1}", ProxyType.Name, targetMethod.Name); try { string path = LookupScript(targetMethod.Name); if (path == null) { TestSite.Assume.Fail( "PowerShell script file ({0}.ps1) can not be found.", targetMethod.Name); } else { PSParameterBuilder builder = InvokeScript(path, targetMethod, args, methodhelp); if (builder != null) { retVal = builder.RetValue; if (builder.OutArguments != null) { int argsIndex = 0; int outArgsIndex = 0; foreach (ParameterInfo pi in targetMethod.GetParameters()) { if (pi.ParameterType.IsByRef) { outArgs[argsIndex] = builder.OutArguments[outArgsIndex++]; } argsIndex++; } } //clear builder builder = null; } } } catch (Exception ex) { TestSite.Log.Add(LogEntryKind.Debug, ex.ToString()); throw; } finally { TestSite.Log.Add(LogEntryKind.ExitAdapter, "PowerShell adapter: {0}, method: {1}", ProxyType.Name, targetMethod.Name); } } return(retVal); }
/// <summary> /// Invokde script by given file path and arguments. /// </summary> /// <param name="path">The file path to the cmd script.</param> /// <param name="targetMethod">The method the caller invoked.</param> /// <param name="args">The argument to be passed to the script.</param> /// <param name="helpMessage">The help message from the attribute.</param> /// <returns>The return value of script executation.</returns> private PSParameterBuilder InvokeScript(string path, MethodInfo targetMethod, object[] args, string helpMessage) { //the patameter builder to handle all parameters PSParameterBuilder builder = null; //use the Dot operation in PowerShell to make all variables can be accessed in whole runspace. string scriptContent = string.Format(". \"{0}\"", Path.GetFullPath(path)); //call static method, and create the instance of runspace type Runspace runspace = RunspaceFactory.CreateRunspace(); //open run space runspace.Open(); //call runspace.CreatePipeline to create an instance of Pipeline Pipeline pipeline = runspace.CreatePipeline(); if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { //set execution policy for Windows in order to load and run local script files pipeline.Commands.AddScript("Set-ExecutionPolicy -Scope Process RemoteSigned"); } pipeline.Commands.AddScript(scriptContent); SessionStateProxy sessionStateProxy = runspace.SessionStateProxy; //set current location to the folder containing the script sessionStateProxy.Path.SetLocation(Path.GetDirectoryName(path)); //set variables which can be used in PowerShell script SetPTFVariables(sessionStateProxy); //set all parameters as variables which can be used //by users directly in the PowerShell script builder = new PSParameterBuilder(targetMethod); builder.SetAllParametersAsVariables(sessionStateProxy, args, helpMessage); try { if (builder != null) { //invoke script and get the return value and out/ref parameters if (builder.HasRetValue) { Collection <PSObject> returnValueCollection = pipeline.Invoke(); //get return value object KeyValuePair <string, object> retValue = GetRetValueFromCollection(returnValueCollection); if (retValue.Value != null) { if (builder.RetType.IsInstanceOfType(retValue.Value)) { builder.RetValue = retValue.Value; } else { throw new InvalidOperationException("The returned type is mismatched"); } } else { builder.RetValue = null; } } else { pipeline.Invoke(); } //get out parameters values builder.GetAllOutParameterValues( sessionStateProxy, targetMethod.GetParameters().Length); } else { pipeline.Invoke(); } //check errors in the error pipeline CheckErrorsInPipeline(pipeline); } catch (RuntimeException ex) { string errorMessage = ex.Message; string traceInfo = ex.ErrorRecord.InvocationInfo.PositionMessage; string ptfAdFailureMessage = string.Format( "Exception thrown in PowerShell Adapter: {0} {1}", errorMessage, traceInfo); throw new InvalidOperationException(ptfAdFailureMessage); } //close runspace and release resources runspace.Close(); return(builder); }
//use reflection to invoke PowerShell script via APIs in System.Management.Automation.dll private PSParameterBuilder InvokeScript(string path, IMethodCallMessage methodCall, string helpMessage) { //the patameter builder to handle all parameters PSParameterBuilder builder = null; Assembly sysMgmtAutoAssembly = null; try { sysMgmtAutoAssembly = Assembly.Load(PSConstant.SystemManagementAutomationAssemblyNameV3); } catch { } // If loading System.Management.Automation, Version=3.0.0.0 failed, try Version=1.0.0.0 if (sysMgmtAutoAssembly == null) { try { sysMgmtAutoAssembly = Assembly.Load(PSConstant.SystemManagementAutomationAssemblyNameV1); } catch { throw new InvalidOperationException("Can not find system management automation assembly from GAC." + "Please make sure your PowerShell installation is valid." + "Or you need to reinstall PowerShell."); } } if (sysMgmtAutoAssembly != null) { //use the Dot operation in PowerShell to make all variables can be accessed in whole runspace. string scriptContent = string.Format(". \"{0}\"", Path.GetFullPath(path)); BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod; //call static method, and create the instance of runspace type Type runspaceFactory = GetPSType(sysMgmtAutoAssembly, "System.Management.Automation.Runspaces.RunspaceFactory"); object runspaceInstance = runspaceFactory.InvokeMember( "CreateRunspace", BindingFlags.InvokeMethod, null, null, null); //open run space Type runspace = GetPSType(sysMgmtAutoAssembly, "System.Management.Automation.Runspaces.Runspace"); runspace.InvokeMember("Open", flag, null, runspaceInstance, null); //call runspace.CreatePipeline to create an instance of Pipeline Type pipeline = GetPSType(sysMgmtAutoAssembly, "System.Management.Automation.Runspaces.Pipeline"); object pipelineInstance = runspace.InvokeMember( "CreatePipeline", flag, null, runspaceInstance, null); //get the Commands property of the pipeline instance object commandsInstance = pipeline.InvokeMember( "Commands", BindingFlags.GetProperty, null, pipelineInstance, null); //add commands to invoke script Type commands = GetPSType(sysMgmtAutoAssembly, "System.Management.Automation.Runspaces.CommandCollection"); commands.InvokeMember( "AddScript", flag, null, commandsInstance, new object[] { scriptContent }); //get "SessionStateProxy" instance from runspace Type sessionStateProxy = GetPSType(sysMgmtAutoAssembly, "System.Management.Automation.Runspaces.SessionStateProxy"); object proxyInstance = runspace.InvokeMember( "SessionStateProxy", BindingFlags.GetProperty, null, runspaceInstance, null); //set variables which can be used in PowerShell script builder = SetPSVariables(methodCall, sessionStateProxy, proxyInstance, helpMessage); try { if (builder != null) { //invoke script and get the return value and out/ref parameters if (builder.HasRetValue) { object returnValueCollection = pipeline.InvokeMember("Invoke", flag, null, pipelineInstance, null); Type psObject = GetPSType(sysMgmtAutoAssembly, "System.Management.Automation.PSObject"); //get return value object KeyValuePair <string, object> retValue = this.GetRetValueFromCollection(returnValueCollection, psObject); if (retValue.Value != null) { if (builder.RetType.IsInstanceOfType(retValue.Value)) { builder.RetValue = retValue.Value; } else { throw new InvalidOperationException("The returned type is mismatched"); } } else { builder.RetValue = null; } } else { pipeline.InvokeMember("Invoke", flag, null, pipelineInstance, null); } //get out parameters values builder.GetAllOutParameterValues( sysMgmtAutoAssembly, sessionStateProxy, proxyInstance, methodCall.MethodBase.GetParameters().Length); } else { pipeline.InvokeMember("Invoke", flag, null, pipelineInstance, null); } //check errors in the error pipeline CheckErrorsInPipeline(sysMgmtAutoAssembly, pipeline, pipelineInstance); } catch (TargetInvocationException ex) { string innerException = string.Empty; string traceInfo = string.Empty; Exception e = ex as Exception; if (null != e.InnerException) { innerException = e.InnerException.Message; traceInfo = GetPSScriptPositionMessage(sysMgmtAutoAssembly, e.InnerException); } string ptfAdFailureMessage = string.Format( "Exception thrown. InnerException: {0} {1}", innerException, traceInfo); throw new InvalidOperationException(ptfAdFailureMessage); } //close runspace and release resources runspace.InvokeMember("Close", flag, null, runspaceInstance, null); } else { throw new InvalidOperationException("Can not find system management automation assembly from GAC." + "Please make sure your PowerShell installation is valid." + "Or you need to reinstall PowerShell."); } return(builder); }
protected override IMessage Invoke(IMethodCallMessage methodCall) { //get help message from attribute string methodhelp = AdapterProxyHelpers.GetHelpMessage(methodCall); bool compactMode = ((methodCall.MethodName == "Initialize" || methodCall.MethodName == "Reset") && AdapterType.IsAdapterTypeFullName(methodCall.MethodBase.DeclaringType.FullName) ); if (compactMode) { return(InvokeCompact(methodCall, methodhelp)); } object retVal = null; object[] outArgs = methodCall.Args; // Check if this is a method from IAdapter. Any IAdapter methods should be ignored. if (!AdapterType.IsAdapterTypeFullName(methodCall.MethodBase.DeclaringType.FullName) && (methodCall.MethodBase.DeclaringType.FullName != typeof(IDisposable).FullName) ) { TestSite.Log.Add(LogEntryKind.EnterAdapter, "Power Shell adapter: {0}, method: {1}", ProxyType.Name, methodCall.MethodName); try { string path = LookupScript(methodCall.MethodName); if (path == null) { TestSite.Assume.Fail( "PowerShell script file ({0}.ps1) can not be found.", methodCall.MethodName); } else { PSParameterBuilder builder = InvokeScript(path, methodCall, methodhelp); if (builder != null) { retVal = builder.RetValue; if (builder.OutArguments != null) { int argsIndex = 0; int outArgsIndex = 0; foreach (ParameterInfo pi in methodCall.MethodBase.GetParameters()) { if (pi.ParameterType.IsByRef) { outArgs[argsIndex] = builder.OutArguments[outArgsIndex++]; } argsIndex++; } } //clear builder builder = null; } } } catch (Exception ex) { TestSite.Log.Add(LogEntryKind.Debug, ex.ToString()); throw; } finally { TestSite.Log.Add(LogEntryKind.ExitAdapter, "Power Shell adapter: {0}, method: {1}", ProxyType.Name, methodCall.MethodName); } } ReturnMessage mret = new ReturnMessage( retVal, (outArgs != null && outArgs.Length > 0) ? outArgs : null, (outArgs != null) ? outArgs.Length : 0, methodCall.LogicalCallContext, methodCall); return(mret); }
private PSParameterBuilder SetPSVariables( IMethodCallMessage methodCall, Type sessionStateProxy, object proxyInstance, string helpMessage) { //get "SetVariable" method which will set all param as variable. MethodInfo methodSetVariable = sessionStateProxy.GetMethod( "SetVariable", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, new Type[] { typeof(string), typeof(object) }, null ); if (methodSetVariable == null) { throw new InvalidOperationException("Cannot get 'SetVariable' method from SessionStateProxy."); } //set all properties and help message as variable //which can be used in PowerShell script. //set help message as variable methodSetVariable.Invoke(proxyInstance, new object[] { "PtfHelpMessage", helpMessage }); //set all properties as variables foreach (string key in this.TestSite.Properties.AllKeys) { string propName = "PTFProp" + key; methodSetVariable.Invoke( proxyInstance, new object[] { propName, this.TestSite.Properties[key] } ); } if (methodCall != null) { //set all parameters as variables which can be used //by users directly in the PowerShell script PSParameterBuilder builder = new PSParameterBuilder(methodCall); builder.SetAllParametersAsVariables(methodSetVariable, proxyInstance); return builder; } return null; }
/// <summary> /// Proxy method for substitution of executing methods in adapter interface. /// </summary> /// <param name="targetMethod">The method the caller invoked.</param> /// <param name="args">The arguments the caller passed to the method.</param> /// <returns>The return value of the ExecuteMethod implementation.</returns> protected override object ExecuteMethod(MethodInfo targetMethod, object[] args) { //get help message from attribute string methodhelp = AdapterProxyHelpers.GetHelpMessage(targetMethod); bool compactMode = ((targetMethod.Name == "Initialize" || targetMethod.Name == "Reset") && AdapterType.IsAdapterTypeFullName(targetMethod.DeclaringType.FullName) ); if (compactMode) { return(ExecuteMethodCompact(targetMethod, methodhelp)); } object retVal = null; object[] outArgs = args; // Check if this is a method from IAdapter. Any IAdapter methods should be ignored. if (!AdapterType.IsAdapterTypeFullName(targetMethod.DeclaringType.FullName) && (targetMethod.DeclaringType.FullName != typeof(IDisposable).FullName) ) { TestSite.Log.Add(LogEntryKind.EnterAdapter, "PowerShell adapter: {0}, method: {1}", ProxyType.Name, targetMethod.Name); try { string path = LookupScript(targetMethod.Name); if (path == null) { TestSite.Assume.Fail( "PowerShell script file ({0}.ps1) can not be found.", targetMethod.Name); } else { int timeout = AdapterProxyHelpers.GetTimeout(targetMethod, int.Parse(TestSite.Properties["AdapterInvokeTimeout"])); Task <PSParameterBuilder> invokeTask = Task.Run <PSParameterBuilder>(() => { TestSite.Log.Add(LogEntryKind.Debug, $"Start to invoke Script {targetMethod.Name}.ps1, timeout: {timeout}"); var invokeResult = InvokeScript(path, targetMethod, args, methodhelp); TestSite.Log.Add(LogEntryKind.Debug, $"Complete execute Script {targetMethod.Name}.ps1"); return(invokeResult); }); TimeSpan waiter = TimeSpan.FromMinutes(timeout); if (invokeTask.Wait(waiter)) { PSParameterBuilder resultBuilder = invokeTask.Result; if (resultBuilder != null) { retVal = resultBuilder.RetValue; if (resultBuilder.OutArguments != null) { int argsIndex = 0; int outArgsIndex = 0; foreach (ParameterInfo pi in targetMethod.GetParameters()) { if (pi.ParameterType.IsByRef) { outArgs[argsIndex] = resultBuilder.OutArguments[outArgsIndex++]; } argsIndex++; } } //clear builder resultBuilder = null; } } else { throw new TimeoutException($"Invoke adapater method timeout after wait {timeout} minutes."); } } } catch (Exception ex) { TestSite.Log.Add(LogEntryKind.Debug, ex.ToString()); throw; } finally { TestSite.Log.Add(LogEntryKind.ExitAdapter, "PowerShell adapter: {0}, method: {1}", ProxyType.Name, targetMethod.Name); } } return(retVal); }