Skip to content

Commit

Permalink
Merged PR 7676063: Fix platform auto-detect issue on Linux drivers fo…
Browse files Browse the repository at this point in the history
…r PTM Service

1. This change fixes issue with PTM Service on Linux drivers being unable to get platform details from the SUT using WMI (since .NET Core on Linux does not support WMI). Support for PS Remoting over SSH using public/private key authentication is added to allow Linux clients get the platform details over this channel.

2. This change also introduces a work around for an issue with peer dependencies in the build pipeline for PTM Service by adding _--legacy-peer-deps_ to the npm install command. The issue is described [here](https://stackoverflow.com/questions/69259024/how-to-handle-conflicting-peer-dependencies).

## Pull Request Checklist
### General
- [ ] Are all regression test passed?
- [ ] Are there any test cases that will expose unfixed TDIs or Windows bugs?

### New Test Case
- [ ] Have Design Spec and User Guide been updated?
- [ ] Can all the test cases be loaded and executed by PTM & PTMCli?
- [ ] Can the related changes support multiple platform(Windows, Linux, MacOS)?

### SDK Changes
- [ ] Are all related test suites Regression passed?
  • Loading branch information
Bewaji Olumuyiwa committed Aug 11, 2022
1 parent 80b0387 commit 58dbc7c
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 7 deletions.
6 changes: 4 additions & 2 deletions ProtocolTestManager/PTMService/PTMService/PTMService.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
</PropertyGroup>

<PropertyGroup>
Expand All @@ -17,6 +18,7 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.5" />
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.5" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
</ItemGroup>

Expand Down Expand Up @@ -50,12 +52,12 @@
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install --legacy-peer-deps" />
</Target>

<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install --legacy-peer-deps" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />

<!-- Include the newly-built files in the publish output -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Microsoft.Protocols.TestTools.StackSdk.FileAccessService.Smb2;
using Microsoft.Protocols.TestTools.StackSdk.Security.SspiLib;
using Microsoft.Protocols.TestTools.StackSdk.Security.SspiService;
using Microsoft.Protocols.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -1020,12 +1021,26 @@ private void ConnectToClusterShare(

private void FetchPlatformInfo(ref DetectionInfo info)
{
ManagementObjectCollection resultCollection = QueryWmiObject(SUTName, "SELECT * FROM Win32_OperatingSystem", info.userName, info.password);
foreach (ManagementObject result in resultCollection)
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
info.platform = ConvertPlatform(result["Version"].ToString(), result["BuildNumber"].ToString());
logWriter.AddLog(DetectLogLevel.Information, "Platform: " + info.platform);
break;
ManagementObjectCollection resultCollection = QueryWmiObject(SUTName, "SELECT * FROM Win32_OperatingSystem", info.userName, info.password);
foreach (ManagementObject result in resultCollection)
{
info.platform = ConvertPlatform(result["Version"].ToString(), result["BuildNumber"].ToString());
logWriter.AddLog(DetectLogLevel.Information, "Platform: " + info.platform);
break;
}
}
else
{
var session = new PSRemotingSession(SUTName, info.userName);
var results = session.Invoke(@"Get-CimInstance -Namespace ""root\cimv2"" -Query ""SELECT * FROM Win32_OperatingSystem""");
foreach (var result in results)
{
info.platform = ConvertPlatform(result["Version"].ToString(), result["BuildNumber"].ToString());
logWriter.AddLog(DetectLogLevel.Information, "Platform: " + info.platform);
break;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.5" />
<PackageReference Include="System.Management" Version="6.0.0" />
</ItemGroup>

Expand Down
127 changes: 127 additions & 0 deletions TestSuites/FileServer/src/Plugin/FileServerPlugin/PSRemotingSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
using Sma = System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Text;
using System.Threading.Tasks;

using Newtonsoft.Json.Linq;

namespace Microsoft.Protocols.Tools
{
/// <summary>
/// Driver class for hosting a PSRemoting session.
/// </summary>
public class PSRemotingSession
{
private readonly string hostName;
private readonly string userName;
private readonly string keyFilePath;

/// <summary>
/// Creates an instance of <see cref="PSRemotingSession" />
/// </summary>
/// <param name="hostName">The computer name or IP address of the remote host.</param>
/// <param name="userName">The userName for running the session on the remote machine.</param>
/// <param name="keyFilePath">Path to the private key file to use for authenticating. If this parameter is not specified, the sshd service will attempt to use one in the default location.</param>
public PSRemotingSession(string hostName, string userName, string keyFilePath = null)
{
this.hostName = hostName;
this.userName = userName;
this.keyFilePath = keyFilePath;
}

/// <summary>
/// Runs a PowerShell script remotely and returns the result as a JSON array.
/// </summary>
/// <param name="script">The PowerShell script to run.</param>
/// <returns>The result of the script execution.</returns>
/// <exception cref="AggregateException">Thrown if there are any errors returned by the script execution.</exception>
/// <exception cref="InvalidOperationException">Thrown if there is an error connecting to the remote host.</exception>
public JArray Invoke(string script)
{
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
using (Sma.PowerShell powershell = Sma.PowerShell.Create())
{

var command = new PSCommand();
command.AddCommand("New-PSSession");
command.AddParameter("HostName", this.hostName);
command.AddParameter("Username", this.userName);

if(!String.IsNullOrWhiteSpace(this.keyFilePath))
{
command.AddParameter("KeyFilePath", this.keyFilePath);
}

powershell.Commands = command;
runspace.Open();
powershell.Runspace = runspace;
Collection<PSSession> result = powershell.Invoke<PSSession>();

var exceptions = powershell.Streams.Error.Select(e => e.Exception).ToArray();
if(exceptions.Any())
{
throw new AggregateException(exceptions);
}

if (result.Count != 1)
{
throw new InvalidOperationException("Unexpected number of Remote Runspace connections returned.");
}

command = new PSCommand();
command.AddCommand("Set-Variable");
command.AddParameter("Name", "session");
command.AddParameter("Value", result[0]);
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();

command = new PSCommand();
command.AddScript("Enter-PSSession $session");
powershell.Commands = command;
powershell.Runspace = runspace;
powershell.Invoke();

command = new PSCommand();
var scriptBlock = @$"Invoke-Command $session -ScriptBlock {{
{script}
}}";
command.AddScript(scriptBlock);
powershell.Commands = command;
powershell.Runspace = runspace;

Collection<PSObject> results = new Collection<PSObject>();
results = powershell.Invoke();

var resultArray = new JArray();
foreach (PSObject psObject in results)
{
var item = new JObject();
foreach (PSPropertyInfo prop in psObject.Properties)
{
var name = prop.Name;
var value = prop.Value;

if (prop.Value != default(object))
{
item[prop.Name] = JToken.FromObject(prop.Value);
}
}

resultArray.Add(item);
}

return resultArray;
}
}
}
}
}

0 comments on commit 58dbc7c

Please sign in to comment.