mirror of
https://github.com/aphrody-labs/PowerShell.git
synced 2026-10-17 12:45:47 +00:00
Add mapped files for all PackageManagement assemblies
This commit is contained in:
1 parent
d8a7ca9f70
commit
5361c16aaf
327 files changed
+75903
No files matched your search
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell.Internal {
|
||||
internal static class Constants {
|
||||
internal const string ScriptStackTrace = "MSG:ScriptStackTrace";
|
||||
internal const string ProviderNameUnknown = "(unknown)";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell {
|
||||
public class Dependency {
|
||||
public string ProviderName {get; set;}
|
||||
public string PackageName {get; set;}
|
||||
public string Version {get; set;}
|
||||
public string Source {get; set;}
|
||||
public string AppliesTo {get; set;}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Internal;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
|
||||
public class DynamicOption : Yieldable {
|
||||
public DynamicOption(OptionCategory category, string name, OptionType expectedType, bool isRequired, IEnumerable<object> permittedValues) {
|
||||
Name = name;
|
||||
ExpectedType = expectedType;
|
||||
IsRequired = isRequired;
|
||||
PermittedValues = permittedValues;
|
||||
}
|
||||
|
||||
public DynamicOption(string name, OptionType expectedType, bool isRequired, IEnumerable<object> permittedValues) {
|
||||
Name = name;
|
||||
ExpectedType = expectedType;
|
||||
IsRequired = isRequired;
|
||||
PermittedValues = permittedValues;
|
||||
}
|
||||
|
||||
|
||||
public DynamicOption(OptionCategory category,string name, OptionType expectedType, bool isRequired) : this(category, name , expectedType, isRequired, null) {
|
||||
}
|
||||
|
||||
public DynamicOption(string name, OptionType expectedType, bool isRequired)
|
||||
: this(name, expectedType, isRequired, null) {
|
||||
}
|
||||
|
||||
|
||||
public DynamicOption() {
|
||||
}
|
||||
|
||||
public string Name {get; set;}
|
||||
public OptionType ExpectedType {get; set;}
|
||||
public bool IsRequired {get; set;}
|
||||
public IEnumerable<object> PermittedValues {get; set;}
|
||||
|
||||
public override bool YieldResult(PsRequest r) {
|
||||
if (r == null) {
|
||||
throw new ArgumentNullException("r");
|
||||
}
|
||||
return r.YieldDynamicOption(Name, ExpectedType.ToString(), IsRequired) && PermittedValues.WhereNotNull().Select(each => each.ToString()).ToArray().All(v => r.YieldKeyValuePair(Name, v));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
|
||||
public class Entity {
|
||||
public string Name {get; set;}
|
||||
public string RegId {get; set;}
|
||||
public string Role {get; set;}
|
||||
|
||||
public IEnumerable<string> Roles {
|
||||
get {
|
||||
return (string.IsNullOrWhiteSpace(Role) ? "unknown" : Role).Split(new[] {' '}, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
set
|
||||
{
|
||||
var values = value == null ? new string[0] : value.ToArray();
|
||||
Role = ( values.Length == 0) ? "unknown" : value.JoinWith(" ");
|
||||
}
|
||||
}
|
||||
|
||||
public string Thumbprint {get; set;}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell {
|
||||
public enum OptionCategory {
|
||||
Package = 0,
|
||||
Provider = 1,
|
||||
Source = 2,
|
||||
Install = 3
|
||||
}
|
||||
|
||||
public enum OptionType {
|
||||
String = 0,
|
||||
StringArray = 1,
|
||||
Int = 2,
|
||||
Switch = 3,
|
||||
Folder = 4,
|
||||
File = 5,
|
||||
Path = 6,
|
||||
Uri = 7,
|
||||
SecureString = 8
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Internal;
|
||||
|
||||
public class Feature : Yieldable {
|
||||
private KeyValuePair<string, string[]> _pair;
|
||||
|
||||
public Feature(string name) : this(name, new string[0]) {
|
||||
}
|
||||
|
||||
public Feature(string name, string value) : this(name, new[] {value}) {
|
||||
}
|
||||
|
||||
public Feature(string name, string[] values) {
|
||||
_pair = new KeyValuePair<string, string[]>(name, values);
|
||||
}
|
||||
|
||||
public override bool YieldResult(PsRequest r) {
|
||||
if (r == null) {
|
||||
throw new ArgumentNullException("r");
|
||||
}
|
||||
if (_pair.Value.Length == 0) {
|
||||
return r.YieldKeyValuePair(_pair.Key, null);
|
||||
}
|
||||
return _pair.Value.All(each => r.YieldKeyValuePair(_pair.Key, each));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell {
|
||||
public class Link {
|
||||
public string HRef {get; set;}
|
||||
public string Relationship {get; set;}
|
||||
public string MediaType {get; set;}
|
||||
public string Ownership {get; set;}
|
||||
public string Use {get; set;}
|
||||
public string AppliesToMedia {get; set;}
|
||||
public string Artifact {get; set;}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell {
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Internal;
|
||||
|
||||
public class PackageSource : Yieldable {
|
||||
public PackageSource(string name, string location, bool isTrusted, bool isRegistered, bool isValidated) {
|
||||
Name = name;
|
||||
Location = location;
|
||||
IsTrusted = isTrusted;
|
||||
IsRegistered = isRegistered;
|
||||
IsValidated = isValidated;
|
||||
}
|
||||
|
||||
public PackageSource(string name, string location, bool isTrusted, bool isRegistered, bool isValidated, Hashtable details)
|
||||
: this(name, location, isTrusted, isRegistered, isValidated) {
|
||||
_details = details;
|
||||
}
|
||||
|
||||
|
||||
public PackageSource(string name, string location, bool isTrusted, bool isRegistered, Hashtable details)
|
||||
: this(name, location, isTrusted, isRegistered,false) {
|
||||
_details = details;
|
||||
}
|
||||
|
||||
public string Name {get; set;}
|
||||
public string Location {get; set;}
|
||||
public bool IsTrusted {get; set;}
|
||||
public bool IsRegistered { get; set; }
|
||||
|
||||
public bool IsValidated {get; set;}
|
||||
public override bool YieldResult(PsRequest r) {
|
||||
if (r == null) {
|
||||
throw new ArgumentNullException("r");
|
||||
}
|
||||
|
||||
return r.YieldPackageSource(Name, Location, IsTrusted, IsRegistered,IsValidated) && YieldDetails(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using Microsoft.PackageManagement.Internal.Utility.Platform;
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell.Internal {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Platform;
|
||||
|
||||
internal static class PowerShellExtensions {
|
||||
internal static PowerShell Clear(this PowerShell powershell) {
|
||||
if (powershell != null) {
|
||||
powershell.WaitForReady();
|
||||
powershell.Commands = new PSCommand();
|
||||
}
|
||||
return powershell;
|
||||
}
|
||||
|
||||
internal static PSModuleInfo ImportModule(this PowerShell powershell, string name, bool force = false) {
|
||||
if (powershell != null) {
|
||||
powershell.Clear().AddCommand("Import-Module");
|
||||
powershell.AddParameter("Name", name);
|
||||
powershell.AddParameter("PassThru");
|
||||
|
||||
if (force) {
|
||||
powershell.AddParameter("Force");
|
||||
}
|
||||
return powershell.Invoke<PSModuleInfo>().ToArray().FirstOrDefault();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static IEnumerable<PSModuleInfo> TestModuleManifest(this PowerShell powershell, string path) {
|
||||
if (powershell != null) {
|
||||
return powershell
|
||||
.Clear()
|
||||
.AddCommand("Test-ModuleManifest")
|
||||
.AddParameter("Path", path)
|
||||
.Invoke<PSModuleInfo>().ToArray();
|
||||
}
|
||||
return Enumerable.Empty<PSModuleInfo>();
|
||||
}
|
||||
|
||||
internal static IEnumerable<PSModuleInfo> GetModule(this PowerShell powershell, string moduleName)
|
||||
{
|
||||
if ((powershell != null) && (!string.IsNullOrWhiteSpace(moduleName)))
|
||||
{
|
||||
return powershell
|
||||
.Clear()
|
||||
.AddCommand("Get-Module")
|
||||
.AddParameter("Name", moduleName)
|
||||
.AddParameter("ListAvailable")
|
||||
.Invoke<PSModuleInfo>();
|
||||
}
|
||||
return Enumerable.Empty<PSModuleInfo>();
|
||||
}
|
||||
|
||||
internal static PowerShell SetVariable(this PowerShell powershell, string variable, object value) {
|
||||
if (powershell != null) {
|
||||
powershell
|
||||
.Clear()
|
||||
.AddCommand("Set-Variable")
|
||||
.AddParameter("Name", variable)
|
||||
.AddParameter("Value", value)
|
||||
.Invoke();
|
||||
}
|
||||
return powershell;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the last output to the user. This will be null if the operation did not succeed.
|
||||
/// outputAction is the action that will be performed whenever an object is outputted to the powershell pipeline
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="powershell"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="outputAction"></param>
|
||||
/// <param name="errorAction"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
internal static T InvokeFunction<T>(this PowerShell powershell, string command,
|
||||
EventHandler<DataAddedEventArgs> outputAction, EventHandler<DataAddedEventArgs> errorAction, params object[] args) {
|
||||
|
||||
if (powershell != null) {
|
||||
powershell.Clear().AddCommand(command);
|
||||
foreach (var arg in args) {
|
||||
powershell.AddArgument(arg);
|
||||
}
|
||||
#if DEBUG
|
||||
NativeMethods.OutputDebugString("[Cmdlet:debugging] -- InvokeFunction ({0}, {1})".format(command, args.Select( each => (each ?? "<NULL>").ToString()).JoinWithComma(), powershell.InvocationStateInfo.Reason));
|
||||
#endif
|
||||
|
||||
var input = new PSDataCollection<PSObject>();
|
||||
input.Complete();
|
||||
|
||||
var output = new PSDataCollection<PSObject>();
|
||||
|
||||
if (outputAction != null)
|
||||
{
|
||||
output.DataAdded += outputAction;
|
||||
}
|
||||
|
||||
if (errorAction != null)
|
||||
{
|
||||
powershell.Streams.Error.DataAdded += errorAction;
|
||||
}
|
||||
|
||||
powershell.Invoke(null, output, new PSInvocationSettings());
|
||||
|
||||
if (output.Count == 0)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
// return the last output to the user
|
||||
PSObject last = output.Last();
|
||||
|
||||
if (last != null)
|
||||
{
|
||||
// convert last to T
|
||||
return (T)last.ImmediateBaseObject;
|
||||
}
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
internal static PowerShell WaitForReady(this PowerShell powershell) {
|
||||
try {
|
||||
if (powershell != null) {
|
||||
switch (powershell.InvocationStateInfo.State) {
|
||||
case PSInvocationState.Stopping:
|
||||
while (powershell.InvocationStateInfo.State == PSInvocationState.Stopping) {
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
break;
|
||||
|
||||
case PSInvocationState.Running:
|
||||
powershell.Stop();
|
||||
while (powershell.InvocationStateInfo.State == PSInvocationState.Stopping) {
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
break;
|
||||
|
||||
case PSInvocationState.Failed:
|
||||
break;
|
||||
case PSInvocationState.Completed:
|
||||
break;
|
||||
|
||||
case PSInvocationState.Stopped:
|
||||
break;
|
||||
|
||||
case PSInvocationState.NotStarted:
|
||||
break;
|
||||
case PSInvocationState.Disconnected:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.Dump();
|
||||
}
|
||||
return powershell;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,830 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell.Internal {
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Versions;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Collections;
|
||||
using System.Globalization;
|
||||
using Implementation;
|
||||
using PackageManagement.Internal;
|
||||
using PackageManagement.Internal.Implementation;
|
||||
using PackageManagement.Internal.Providers;
|
||||
using PackageManagement.Internal.Utility.Plugin;
|
||||
using ErrorCategory = System.Management.Automation.ErrorCategory;
|
||||
using ProviderOption = PackageManagement.Internal.Implementation.PackageManagementService.ProviderOption;
|
||||
|
||||
internal class ProviderItem {
|
||||
internal PSModuleInfo ModuleInfo;
|
||||
internal string ProviderPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A MetaProvider class that loads Providers implemented as a PowerShell Module.
|
||||
/// It connects the functions in the PowerShell module to the expected functions that the
|
||||
/// interface expects.
|
||||
/// </summary>
|
||||
public class PowerShellMetaProvider : IDisposable {
|
||||
private static readonly HashSet<string> _exclusionList = new HashSet<string> {
|
||||
"AppBackgroundTask",
|
||||
"AppLocker",
|
||||
"Appx",
|
||||
"AssignedAccess",
|
||||
"BitLocker",
|
||||
"BitsTransfer",
|
||||
"BranchCache",
|
||||
"CimCmdlets",
|
||||
"Defender",
|
||||
"DirectAccessClientComponents",
|
||||
"Dism",
|
||||
"DnsClient",
|
||||
"Hyper-V",
|
||||
"International",
|
||||
"iSCSI",
|
||||
"ISE",
|
||||
"Kds",
|
||||
"Microsoft.PowerShell.Diagnostics",
|
||||
"Microsoft.PowerShell.Host",
|
||||
"Microsoft.PowerShell.Management",
|
||||
"Microsoft.PowerShell.Security",
|
||||
"Microsoft.PowerShell.Utility",
|
||||
"Microsoft.WSMan.Management",
|
||||
"MMAgent",
|
||||
"MsDtc",
|
||||
"NetAdapter",
|
||||
"NetConnection",
|
||||
"NetEventPacketCapture",
|
||||
"NetLbfo",
|
||||
"NetNat",
|
||||
"NetQos",
|
||||
"NetSecurity",
|
||||
"NetSwitchTeam",
|
||||
"NetTCPIP",
|
||||
"NetWNV",
|
||||
"NetworkConnectivityStatus",
|
||||
"NetworkTransition",
|
||||
"PcsvDevice",
|
||||
"PKI",
|
||||
"PrintManagement",
|
||||
"PSDiagnostics",
|
||||
"PSScheduledJob",
|
||||
"PSWorkflow",
|
||||
"PSWorkflowUtility",
|
||||
"ScheduledTasks",
|
||||
"SecureBoot",
|
||||
"SmbShare",
|
||||
"SmbWitness",
|
||||
"StartScreen",
|
||||
"Storage",
|
||||
"TLS",
|
||||
"TroubleshootingPack",
|
||||
"TrustedPlatformModule",
|
||||
"VpnClient",
|
||||
"Wdac",
|
||||
"WindowsDeveloperLicense",
|
||||
"WindowsErrorReporting",
|
||||
"WindowsSearch",
|
||||
"PackageManagement", // dont' search ourselves.
|
||||
"OneGet", // dont' search ourselves.
|
||||
"OneGet-Edge" // dont' search ourselves.
|
||||
};
|
||||
|
||||
private static string _baseFolder;
|
||||
private static string _powershellProviderFunctionsPath;
|
||||
|
||||
//The reason of using 'object' instead of' PowerShellPackageProvider' is that PowerShellPackageProvider is a provider
|
||||
//that is not visiable to the PackageManagment.
|
||||
private readonly IDictionary<string, object> _availableProviders = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly IDictionary<string, List<ProviderItem>> _psProviderCacheTable = new Dictionary<string, List<ProviderItem>>(StringComparer.OrdinalIgnoreCase);
|
||||
internal const string PowerShellGet = "PowerShellGet";
|
||||
private static readonly PowerShell _powershell = PowerShell.Create();
|
||||
private static bool _initialized = false;
|
||||
|
||||
public PowerShellMetaProvider() {
|
||||
// _packageProviders.BlockingEnumerator = true;
|
||||
}
|
||||
|
||||
internal static string BaseFolder {
|
||||
get {
|
||||
if (_baseFolder == null) {
|
||||
#if CORECLR
|
||||
_baseFolder = Path.GetDirectoryName(Path.GetFullPath(typeof(PowerShellMetaProvider).GetTypeInfo().Assembly.ManifestModule.FullyQualifiedName));
|
||||
#else
|
||||
_baseFolder = Path.GetDirectoryName(Path.GetFullPath(Assembly.GetExecutingAssembly().Location));
|
||||
#endif
|
||||
if (_baseFolder == null || !Directory.Exists(_baseFolder)) {
|
||||
throw new Exception(Resources.Messages.CantFindBasePowerShellModuleFolder);
|
||||
}
|
||||
}
|
||||
return _baseFolder;
|
||||
}
|
||||
}
|
||||
|
||||
static PowerShellMetaProvider() {
|
||||
try {
|
||||
EnsurePowerShellInitialized();
|
||||
} catch {
|
||||
//we capture the exceptions here so that we won't fail to load the metaprovider assembly
|
||||
//exceptions can happen when execution-policy is set to restrict, for example.
|
||||
}
|
||||
}
|
||||
|
||||
static void EnsurePowerShellInitialized() {
|
||||
if (!_initialized) {
|
||||
_powershell.ImportModule(PowerShellProviderFunctions);
|
||||
_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static string PowerShellProviderFunctions {
|
||||
get {
|
||||
if (_powershellProviderFunctionsPath == null) {
|
||||
// try the etc directory
|
||||
_powershellProviderFunctionsPath = Path.Combine(BaseFolder, "etc", "PackageProviderFunctions.psm1");
|
||||
if (!File.Exists(_powershellProviderFunctionsPath)) {
|
||||
// fall back to the same directory.
|
||||
_powershellProviderFunctionsPath = Path.Combine(BaseFolder, "PackageProviderFunctions.psm1");
|
||||
if (!File.Exists(_powershellProviderFunctionsPath)) {
|
||||
// oh-oh, no powershell functions file.
|
||||
throw new Exception(String.Format(CultureInfo.CurrentCulture, Resources.Messages.UnableToFindPowerShellFunctionsFile, _powershellProviderFunctionsPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
return _powershellProviderFunctionsPath;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> ProviderNames {
|
||||
get {
|
||||
//return _packageProviders.Select(each => each.GetPackageProviderName());;
|
||||
return _availableProviders.Keys;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddToTable(string name, ProviderItem provider) {
|
||||
//try to find if the provider is in the table already
|
||||
|
||||
if (_psProviderCacheTable.ContainsKey(name)) {
|
||||
var list = _psProviderCacheTable[name];
|
||||
|
||||
var index = list.FindIndex(each => (each.ModuleInfo.Version == provider.ModuleInfo.Version) && (each.ProviderPath.EqualsIgnoreCase(provider.ProviderPath)));
|
||||
|
||||
if (index != -1) {
|
||||
list[index] = provider;
|
||||
|
||||
} else {
|
||||
_psProviderCacheTable[name].Add(provider);
|
||||
}
|
||||
} else {
|
||||
var entry = new List<ProviderItem> {
|
||||
provider
|
||||
};
|
||||
_psProviderCacheTable.Add(name, entry);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The name of this MetaProvider class
|
||||
/// </summary>
|
||||
public string MetaProviderName {
|
||||
get {
|
||||
return "PowerShell";
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public string GetProviderPath(string providername) {
|
||||
return _availableProviders.Keys.Where(each => each.EqualsIgnoreCase(providername))
|
||||
.Select(each => ((PowerShellPackageProvider)_availableProviders[each]).ModulePath).FirstOrDefault();
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string,PSModuleInfo>> ScanPrivateDataForProviders(PsRequest request, string baseFolder, Hashtable privateData, PSModuleInfo moduleInfo) {
|
||||
var providers = privateData.GetStringCollection("PackageManagementProviders").ReEnumerable();
|
||||
if (providers.Any()) {
|
||||
// found a module that is advertizing one or more Providers.
|
||||
|
||||
foreach (var provider in providers) {
|
||||
var fullPath = provider;
|
||||
try {
|
||||
if (!Path.IsPathRooted(provider)) {
|
||||
fullPath = Path.GetFullPath(Path.Combine(baseFolder, provider));
|
||||
}
|
||||
} catch {
|
||||
// got an error from the path.
|
||||
continue;
|
||||
}
|
||||
if (Directory.Exists(fullPath) || File.Exists(fullPath)) {
|
||||
// looks like we have something that could definitely be a
|
||||
// a module path.
|
||||
var result = new KeyValuePair<string, PSModuleInfo>(fullPath, moduleInfo);
|
||||
AddToPowerShellProviderCacheTable(result);
|
||||
yield return result;
|
||||
} else {
|
||||
request.Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.FileNotFound, fullPath));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
request.Debug(string.Format(Resources.Messages.PackageManagementProvidersNotFound, baseFolder));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, PSModuleInfo>> GetPackageManagementModules(PsRequest request, PSModuleInfo module, Version requiredVersion, Version minimumVersion, Version maximumVersion) {
|
||||
// skip modules that we know don't contain any PM modules
|
||||
if (!_exclusionList.Contains(module.Name)) {
|
||||
var privateData = module.PrivateData as Hashtable;
|
||||
if (privateData != null) {
|
||||
if (requiredVersion != null) {
|
||||
if ((FourPartVersion)module.Version == (FourPartVersion)requiredVersion) {
|
||||
return ScanPrivateDataForProviders(request, Path.GetDirectoryName(module.Path), privateData, module).ToArray();
|
||||
} else {
|
||||
return Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>();
|
||||
}
|
||||
}
|
||||
|
||||
if ((minimumVersion != null) && ((FourPartVersion)module.Version < (FourPartVersion)minimumVersion)) {
|
||||
return Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>();
|
||||
}
|
||||
|
||||
if ((maximumVersion != null) && ((FourPartVersion)module.Version > (FourPartVersion)maximumVersion)) {
|
||||
return Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>();
|
||||
}
|
||||
|
||||
return ScanPrivateDataForProviders(request, Path.GetDirectoryName(module.Path), privateData, module).ToArray();
|
||||
}
|
||||
}
|
||||
return Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>();
|
||||
}
|
||||
|
||||
private void AddToPowerShellProviderCacheTable(KeyValuePair<string, PSModuleInfo> moduleInfo) {
|
||||
|
||||
//some times when PrivateData in a provider's .psd1 meta file contains multiple providers (not recommanded way),
|
||||
//they all reside under the same module path. So we extract each file name and add to the table as dictionary key
|
||||
//to indicate they are actaully different providers.
|
||||
if (moduleInfo.Key != null) {
|
||||
var name = Path.GetFileNameWithoutExtension(moduleInfo.Key);
|
||||
if (string.IsNullOrWhiteSpace(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// for the case where provider is a dll, we enforce that provider name must be the same as module name
|
||||
// so the name we add to the hash table will be the name of the module.
|
||||
// (for the case where provider is not a dll, we still allow multiple provider names for a module)
|
||||
if (string.Equals(Path.GetExtension(moduleInfo.Key), ".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
name = moduleInfo.Value.Name;
|
||||
}
|
||||
|
||||
AddToTable(name,
|
||||
new ProviderItem {
|
||||
ModuleInfo = moduleInfo.Value,
|
||||
ProviderPath = moduleInfo.Key,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static PackageManagementService PackageManagementService {
|
||||
get {
|
||||
return PackageManager.Instance as PackageManagementService;
|
||||
}
|
||||
}
|
||||
|
||||
//key = path, value = PSModuleInfo
|
||||
private IEnumerable<KeyValuePair<string, PSModuleInfo>> ScanForModules(
|
||||
PsRequest request,
|
||||
Version requiredVersion,
|
||||
Version minimumVersion,
|
||||
Version maximumVersion,
|
||||
ProviderOption providerOption = ProviderOption.LatestVersion) {
|
||||
|
||||
// two places we search for modules
|
||||
// 1. in this assembly's folder, look for all psd1 and psm1 files.
|
||||
//
|
||||
// 2. modules in the PSMODULEPATH
|
||||
//
|
||||
// Import each one of those, and check to see if they have a PackageManagementProviders section in their private data
|
||||
|
||||
var allAvailableModules = _powershell
|
||||
.Clear()
|
||||
.AddCommand("Get-Module")
|
||||
.AddParameter("ListAvailable")
|
||||
.Invoke<PSModuleInfo>();
|
||||
|
||||
return allAvailableModules.WhereNotNull()
|
||||
.SelectMany(each => GetPackageManagementModules(request, each, requiredVersion, minimumVersion, maximumVersion));
|
||||
}
|
||||
|
||||
private IEnumerable<KeyValuePair<string, PSModuleInfo>> ScanForPowerShellGetModule(PsRequest request)
|
||||
{
|
||||
var psget = _powershell.GetModule("PowerShellGet").FirstOrDefault();
|
||||
return psget != null ? GetPackageManagementModules(request, psget, null, null, null) : Enumerable.Empty<KeyValuePair<string, PSModuleInfo>>();
|
||||
}
|
||||
|
||||
private IEnumerable<string> AlternativeModuleScan(
|
||||
PsRequest request,
|
||||
Version requiredVersion,
|
||||
Version minimumVersion,
|
||||
Version maximumVersion,
|
||||
ProviderOption providerOption = ProviderOption.LatestVersion) {
|
||||
|
||||
var psModulePath = Environment.GetEnvironmentVariable("PSModulePath") ?? "";
|
||||
|
||||
IEnumerable<string> paths = psModulePath.Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
// add assumed paths just in case the environment variable isn't really set.
|
||||
try {
|
||||
#if CORECLR
|
||||
paths = paths.ConcatSingleItem(Path.Combine(Environment.GetEnvironmentVariable("windir"), "system32", @"WindowsPowerShell\v1.0\Modules"));
|
||||
#else
|
||||
paths = paths.ConcatSingleItem(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), @"WindowsPowerShell\v1.0\Modules"));
|
||||
#endif
|
||||
} catch {
|
||||
// skip the folder if it's not valid
|
||||
}
|
||||
try {
|
||||
#if CORECLR
|
||||
paths = paths.ConcatSingleItem(Path.Combine(Environment.GetEnvironmentVariable("userprofile"), "documents", @"WindowsPowerShell\Modules"));
|
||||
#else
|
||||
paths = paths.ConcatSingleItem(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), @"WindowsPowerShell\Modules"));
|
||||
#endif
|
||||
} catch {
|
||||
// skip the folder if it's not valid
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(BaseFolder) && BaseFolder.DirectoryExists()) {
|
||||
paths = paths.ConcatSingleItem(BaseFolder);
|
||||
}
|
||||
|
||||
var moduleFolders = paths.Distinct(new PathEqualityComparer(PathCompareOption.Full)).Where(each => each.DirectoryExists()).SelectMany(each => Directory.EnumerateDirectories(each).Where(dir => !_exclusionList.Contains(Path.GetFileName(dir))));
|
||||
|
||||
foreach (var module in moduleFolders) {
|
||||
|
||||
var moduleManifest = Path.Combine(module, Path.GetFileName(module) + ".psd1");
|
||||
if (File.Exists(moduleManifest)) {
|
||||
//The version check is defered in the GetPackageManagementModules() because we do not know the version without looking into the content.
|
||||
yield return moduleManifest;
|
||||
}
|
||||
|
||||
//The following are the cases where there are multiple modules installed on the system. The file folder is the module version.
|
||||
var selectedVersions = Directory.EnumerateDirectories(module).Select(dir => new {
|
||||
folder = dir,
|
||||
ver = (FourPartVersion)Path.GetFileName(dir)
|
||||
}).Where(each => each.ver > 0L);
|
||||
|
||||
if (requiredVersion != null) {
|
||||
var version = selectedVersions.Where(each => each.ver == (FourPartVersion)requiredVersion).Select(each => each.folder).FirstOrDefault();
|
||||
if (version != null) {
|
||||
var file = Path.Combine(version, Path.GetFileName(Path.GetFileName(module)) + ".psd1");
|
||||
if (File.Exists(file)) {
|
||||
yield return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (minimumVersion != null) {
|
||||
selectedVersions = selectedVersions.Where(each => each.ver >= (FourPartVersion)minimumVersion);
|
||||
|
||||
}
|
||||
if (maximumVersion != null) {
|
||||
selectedVersions = selectedVersions.Where(each => each.ver <= (FourPartVersion)maximumVersion);
|
||||
}
|
||||
|
||||
var results = (providerOption == PackageManagementService.ProviderOption.AllProvider) ?
|
||||
selectedVersions.Select(version => Path.Combine(version.folder, Path.GetFileName(Path.GetFileName(module)) + ".psd1")).Where(File.Exists) :
|
||||
new[] {
|
||||
selectedVersions.OrderByDescending(each => each.ver)
|
||||
.Select(version => Path.Combine(version.folder, Path.GetFileName(Path.GetFileName(module)) + ".psd1"))
|
||||
.FirstOrDefault(File.Exists)
|
||||
};
|
||||
|
||||
foreach (var result in results.WhereNotNull()) {
|
||||
yield return result;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object CreateProvider(string name) {
|
||||
|
||||
if (_availableProviders.ContainsKey(name)) {
|
||||
var provider = _availableProviders[name];
|
||||
|
||||
if (provider != null) {
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
|
||||
// it's possible that this is a path passed in. Let's see if it's a provider.
|
||||
if (!string.IsNullOrEmpty(name) && name.FileExists()) {
|
||||
// MUST DO: load provider from filepath.
|
||||
}
|
||||
// create the instance
|
||||
throw new Exception("No provider by name '{0}' registered.".format(name));
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
_availableProviders.Clear();
|
||||
_psProviderCacheTable.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private PowerShellPackageProvider Create(PsRequest request, string modulePath, string requiredVersion, bool force, bool logWarning) {
|
||||
var ps = PowerShell.Create();
|
||||
try {
|
||||
// load the powershell provider functions into this runspace.
|
||||
if (ps.ImportModule(PowerShellProviderFunctions, false) != null) {
|
||||
var result = ps.ImportModule(modulePath, force);
|
||||
if (result != null) {
|
||||
try {
|
||||
return new PowerShellPackageProvider(ps, result, requiredVersion);
|
||||
} catch (Exception e) {
|
||||
e.Dump();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// something didn't go well.
|
||||
// skip it.
|
||||
e.Dump();
|
||||
if (logWarning) {
|
||||
request.Warning(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// didn't import correctly.
|
||||
ps.Dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void InitializeProvider(PsRequest request) {
|
||||
if (request == null) {
|
||||
throw new ArgumentNullException("request");
|
||||
}
|
||||
|
||||
request.Debug("Initializing PowerShell MetaProvider");
|
||||
|
||||
//During the initialization, we load the PowerShellGet only to speeding up a little bit
|
||||
var psModules = ScanForPowerShellGetModule(request).WhereNotNull();
|
||||
|
||||
foreach (var psModule in psModules) {
|
||||
//Check if the PowerShellGet provider exists
|
||||
if ((psModule.Key != null) && (psModule.Value != null)) {
|
||||
//load the PowerShellGet
|
||||
AnalyzeModule(request, psModule.Key, psModule.Value.Version ?? new Version(0, 0), false, true, psModule.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (_availableProviders.ContainsKey(PowerShellGet))
|
||||
{
|
||||
request.Debug("Loaded PowerShell Provider: PowerShellGet");
|
||||
}
|
||||
else
|
||||
{
|
||||
//if we can not load PowerShellGet, we do not fail the initialization
|
||||
request.Verbose(string.Format(CultureInfo.CurrentCulture, Resources.Messages.ModuleNotFound, PowerShellGet));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void AddToPackageProviderCacheTable(PackageProvider provider)
|
||||
{
|
||||
PackageManagementService.AddToProviderCacheTable(provider.ProviderName, provider);
|
||||
}
|
||||
|
||||
|
||||
public void RefreshProviders(PsRequest request, string providerName, Version requiredVersion, Version minimumVersion, Version maximumVersion, bool logWarning) {
|
||||
//find and load the latest versions of the providers if only providerName exists, e.g., get-pp -name or import-pp -name
|
||||
//find and load the particular provider if both providerName and version are provided
|
||||
_psProviderCacheTable.Clear();
|
||||
|
||||
EnsurePowerShellInitialized();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(providerName)) {
|
||||
//Get the list of available providers
|
||||
var modules = ScanForModules(request, requiredVersion, minimumVersion, maximumVersion, ProviderOption.AllProvider).ReEnumerable();
|
||||
|
||||
var tasks = modules.AsyncForEach(modulePath => AnalyzeModule(request, modulePath.Key, modulePath.Value.Version ?? new Version(0, 0), false, logWarning, modulePath.Value));
|
||||
tasks.WaitAll();
|
||||
} else {
|
||||
//find all providers but only load the lastest if no name nor version exists, e.g. get-pp -list
|
||||
|
||||
//Scan for the all available providers
|
||||
var results = ScanForModules(request, null, null, null, ProviderOption.AllProvider).ToArray();
|
||||
|
||||
if (!_psProviderCacheTable.Any()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var list in _psProviderCacheTable.Values.WhereNotNull()) {
|
||||
var psInfo = list.OrderByDescending(each => each.ModuleInfo.Version).ToArray();
|
||||
if (!psInfo.Any()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PackageProvider pkgProvider = null;
|
||||
for (var index = 0; index < psInfo.Length; index++) {
|
||||
var providerItem = psInfo[index];
|
||||
if (providerItem == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// if the provider is a dll, we will just provide a default provider, assuming the module name will be the name of the provider and add to the cache table (if it is not already loaded)
|
||||
if (string.Equals(Path.GetExtension(providerItem.ProviderPath), ".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// check whether it is already loaded or not
|
||||
var loadedProvider = PackageManagementService.PackageProviders.FirstOrDefault(item => string.Equals(item.ProviderPath, providerItem.ProviderPath, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
// only provide default provider if it is not loaded
|
||||
if (loadedProvider == null)
|
||||
{
|
||||
// here moduleinfo.providercategory is the module name.
|
||||
// we are applying the guideline that module name is the same as provider name so we use that as the provider name
|
||||
AddToPackageProviderCacheTable(new PackageProvider(new DefaultPackageProvider(providerItem.ModuleInfo.Name, providerItem.ModuleInfo.Version.ToString()))
|
||||
{
|
||||
ProviderPath = providerItem.ProviderPath,
|
||||
Version = providerItem.ModuleInfo.Version,
|
||||
IsLoaded = false
|
||||
});
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//load the provider that has the latest version
|
||||
if (pkgProvider == null) {
|
||||
// analyze the module
|
||||
pkgProvider = AnalyzeModule(request, providerItem.ProviderPath, providerItem.ModuleInfo.Version, false, logWarning, providerItem.ModuleInfo);
|
||||
} else {
|
||||
//the rest of providers under the same module will just create a provider object for the output but not loaded
|
||||
var packageProvider = new PackageProvider(new DefaultPackageProvider(pkgProvider.ProviderName, providerItem.ModuleInfo.Version.ToString()))
|
||||
{
|
||||
ProviderPath = providerItem.ProviderPath,
|
||||
Version = providerItem.ModuleInfo.Version,
|
||||
IsLoaded = false
|
||||
};
|
||||
AddToPackageProviderCacheTable(packageProvider);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_psProviderCacheTable.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<PackageProvider> FindMatchedProvidersFromInternalCacheTable(PsRequest request, string providerPath) {
|
||||
//Search from the internal table to see if we can the matched provider
|
||||
|
||||
var providers = PackageManagementService.ProviderCacheTable
|
||||
.Select(each => each.Value).Select(list => list
|
||||
.Where(each => each.ProviderPath.EqualsIgnoreCase(providerPath) && each.IsLoaded)
|
||||
.Select(each => each));
|
||||
|
||||
return providers.SelectMany(list => {
|
||||
var packageProviders = list as PackageProvider[] ?? list.ToArray();
|
||||
return packageProviders;
|
||||
});
|
||||
}
|
||||
|
||||
public IEnumerable<object> LoadAvailableProvider(PsRequest request, string modulePath, Version requiredVersion, bool force) {
|
||||
if (request == null) {
|
||||
throw new ArgumentNullException("request");
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(modulePath)) {
|
||||
throw new ArgumentNullException("modulePath");
|
||||
}
|
||||
|
||||
EnsurePowerShellInitialized();
|
||||
|
||||
//Check if it is already in the cache table
|
||||
var providersAlreadyImported = FindMatchedProvidersFromInternalCacheTable(request, modulePath).ToArray();
|
||||
|
||||
if (providersAlreadyImported.Any() && !force) {
|
||||
return providersAlreadyImported;
|
||||
}
|
||||
|
||||
//Trying to load it from the path directly
|
||||
var pkgProvider = AnalyzeModule(request, modulePath, requiredVersion ?? new Version(0, 0), force);
|
||||
if (pkgProvider != null) {
|
||||
return new[] { pkgProvider }.WhereNotNull();
|
||||
}
|
||||
|
||||
request.Error(PackageManagement.Internal.Constants.Messages.FailedToImportProvider,
|
||||
ErrorCategory.InvalidOperation.ToString(), PowerShellGet, string.Format(CultureInfo.CurrentCulture, Resources.Messages.FailedToImportProvider, modulePath));
|
||||
return Enumerable.Empty<PackageProvider>();
|
||||
}
|
||||
|
||||
private PackageProvider AnalyzeModule(PsRequest request, string modulePath, Version requiredVersion, bool force, bool logWarning =true, PSModuleInfo psModuleInfo = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(modulePath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
request.Debug("Attempting to load PowerShell Provider Module [{0}]", modulePath);
|
||||
|
||||
if (string.Equals(Path.GetExtension(modulePath), ".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (psModuleInfo != null)
|
||||
{
|
||||
// fake provider and returns it
|
||||
var result = new PackageProvider(new DefaultPackageProvider(psModuleInfo.Name, psModuleInfo.Version.ToString()))
|
||||
{
|
||||
ProviderPath = modulePath,
|
||||
Version = psModuleInfo.Version,
|
||||
IsLoaded = false
|
||||
};
|
||||
|
||||
AddToPackageProviderCacheTable(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
// psmoduleinfo is only null when this function is called in loadavailableprovider
|
||||
// but in that case we want to load the provider directly anyway so we can do this
|
||||
// if the path is a .dll then we ask packagemanagement to load it for us
|
||||
// it will also register the dll
|
||||
PackageManagementService.LoadProviderAssembly(request, modulePath, true);
|
||||
|
||||
// now let's checked whether we can find it in the list of loaded providers
|
||||
foreach (var loadedProvider in PackageManagementService.PackageProviders)
|
||||
{
|
||||
// the one loaded should have the same path
|
||||
if (string.Equals(loadedProvider.ProviderPath, modulePath, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return loadedProvider;
|
||||
}
|
||||
}
|
||||
|
||||
// if we reached here then we have failed to load the provider :(
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
string requiredVersionString = requiredVersion.ToString();
|
||||
var provider = Create(request, modulePath, requiredVersionString, force, logWarning);
|
||||
if (provider != null) {
|
||||
var providerName = provider.GetPackageProviderName();
|
||||
if (!string.IsNullOrWhiteSpace(providerName)) {
|
||||
request.Debug(string.Format(CultureInfo.CurrentCulture, Resources.Messages.SuccessfullyLoadedModule, modulePath));
|
||||
// looks good to me, let's add this to the list of moduels this meta provider can create.
|
||||
|
||||
var packageProvider = new PackageProvider(provider.As<IPackageProvider>()) {
|
||||
IsLoaded = true,
|
||||
Version = provider.GetProviderVersion(),
|
||||
ProviderPath = modulePath
|
||||
};
|
||||
|
||||
// take out powershell get
|
||||
var psgetprovider = PackageManagementService.PackageProviders.FirstOrDefault(pv => string.Equals(pv.ProviderName, PowerShellGet, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (psModuleInfo != null)
|
||||
{
|
||||
// add swidtag information using moduleinfo
|
||||
// however, this won't give us as much information yet
|
||||
// we may have to fill this up later
|
||||
ProvideSwidTagInformation(packageProvider, psModuleInfo);
|
||||
}
|
||||
|
||||
AddToPackageProviderCacheTable(packageProvider);
|
||||
_availableProviders.AddOrSet(providerName, provider);
|
||||
|
||||
return packageProvider;
|
||||
} else {
|
||||
provider.Dispose();
|
||||
provider = null;
|
||||
request.Debug(string.Format(CultureInfo.CurrentCulture, Resources.Messages.ProviderNameIsNullOrEmpty, modulePath));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If we cannot use psget to get swidtag information, we will try to fill in some of the information
|
||||
/// </summary>
|
||||
/// <param name="packageProvider"></param>
|
||||
/// <param name="psModuleInfo"></param>
|
||||
private void ProvideSwidTagInformation(PackageProvider packageProvider, PSModuleInfo psModuleInfo)
|
||||
{
|
||||
if (packageProvider == null || psModuleInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
packageProvider.VersionScheme = "MultiPartNumeric";
|
||||
|
||||
Microsoft.PackageManagement.Internal.Packaging.SoftwareMetadata softwareMetadata = new Microsoft.PackageManagement.Internal.Packaging.SoftwareMetadata();
|
||||
bool changed = false;
|
||||
|
||||
var type = psModuleInfo.GetType();
|
||||
|
||||
// introduced in ps 2.0
|
||||
if (!string.IsNullOrWhiteSpace(psModuleInfo.Description))
|
||||
{
|
||||
softwareMetadata.Description = psModuleInfo.Description;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// introduced in ps 3.0
|
||||
if (!string.IsNullOrWhiteSpace(psModuleInfo.Copyright))
|
||||
{
|
||||
softwareMetadata.AddAttribute("copyright", psModuleInfo.Copyright);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// tags is introduced in ps 5.0
|
||||
var tagsProperty = type.GetProperty("Tags");
|
||||
bool isV5 = tagsProperty != null;
|
||||
|
||||
if (isV5)
|
||||
{
|
||||
// introduced in ps 5.0
|
||||
var tags = tagsProperty.GetValue(psModuleInfo);
|
||||
|
||||
// check that we have something in tags
|
||||
if (tags is IEnumerable<string> && (tags as IEnumerable<string>).Any())
|
||||
{
|
||||
softwareMetadata.AddAttribute("tags", string.Join(" ", (tags as IEnumerable<string>).Distinct()));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
var releaseNotes = type.GetProperty("ReleaseNotes").GetValue(psModuleInfo);
|
||||
|
||||
// check that we have something in releasenotes
|
||||
if (releaseNotes is string && !string.IsNullOrWhiteSpace(type.GetProperty("ReleaseNotes").GetValue(psModuleInfo) as string))
|
||||
{
|
||||
softwareMetadata.AddAttribute("tags", string.Join(" ", (tags as IEnumerable<string>).Distinct()));
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
packageProvider.AddElement(softwareMetadata);
|
||||
}
|
||||
|
||||
if (isV5)
|
||||
{
|
||||
var iconUri = type.GetProperty("IconUri").GetValue(psModuleInfo);
|
||||
|
||||
// introduced in ps 5.0
|
||||
if (iconUri is Uri)
|
||||
{
|
||||
packageProvider.AddLink(iconUri as Uri, "icon");
|
||||
}
|
||||
|
||||
var licenseUri = type.GetProperty("LicenseUri").GetValue(psModuleInfo);
|
||||
|
||||
// introduced in ps 5.0
|
||||
if (licenseUri is Uri)
|
||||
{
|
||||
packageProvider.AddLink(licenseUri as Uri, "license");
|
||||
}
|
||||
|
||||
var projectUri = type.GetProperty("ProjectUri").GetValue(psModuleInfo);
|
||||
|
||||
// introduced in ps 5.0
|
||||
if (projectUri is Uri)
|
||||
{
|
||||
packageProvider.AddLink(projectUri as Uri, "project");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// introduced in ps 3.0
|
||||
if (!string.IsNullOrWhiteSpace(psModuleInfo.Author))
|
||||
{
|
||||
packageProvider.AddEntity(psModuleInfo.Author, null, "author");
|
||||
}
|
||||
|
||||
// introduced in ps 3.0
|
||||
if (!string.IsNullOrWhiteSpace(psModuleInfo.CompanyName))
|
||||
{
|
||||
packageProvider.AddEntity(psModuleInfo.CompanyName, null, "owner");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell.Internal {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
|
||||
using Packaging;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Versions;
|
||||
using Microsoft.PackageManagement.Internal.Api;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Collections;
|
||||
|
||||
public class PowerShellPackageProvider : PowerShellProviderBase {
|
||||
private static int _findId = 1;
|
||||
private readonly Lazy<Dictionary<int, List<string, string, string, string>>> _findByNameBatches = new Lazy<Dictionary<int, List<string, string, string, string>>>(() => new Dictionary<int, List<string, string, string, string>>());
|
||||
private readonly Lazy<Dictionary<int, List<string>>> _findByFileBatches = new Lazy<Dictionary<int, List<string>>>(() => new Dictionary<int, List<string>>());
|
||||
private readonly Lazy<Dictionary<int, List<Uri>>> _findByUriBatches = new Lazy<Dictionary<int, List<Uri>>>(() => new Dictionary<int, List<Uri>>());
|
||||
private string _version;
|
||||
|
||||
public PowerShellPackageProvider(PowerShell ps, PSModuleInfo module, string version) : base(ps, module) {
|
||||
_version = version;
|
||||
}
|
||||
|
||||
private bool IsFirstParameterType<T>(string function) {
|
||||
var method = GetMethod(function);
|
||||
if (method == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return method.Parameters.Values.First().ParameterType == typeof (T);
|
||||
}
|
||||
|
||||
public bool IsMethodImplemented(string methodName) {
|
||||
if (methodName == null) {
|
||||
throw new ArgumentNullException("methodName");
|
||||
}
|
||||
|
||||
if (methodName.EqualsIgnoreCase("startfind") || methodName.EqualsIgnoreCase("completeFind") || methodName.EqualsIgnoreCase("GetProviderVersion")) {
|
||||
return true;
|
||||
}
|
||||
#if DEEP_DEBUG
|
||||
var r = GetMethod(methodName) != null;
|
||||
if (!r) {
|
||||
Debug.WriteLine(" -> '{0}' Not Found In PowerShell Module '{1}'".format(methodName, _module.Name));
|
||||
}
|
||||
return r;
|
||||
#else
|
||||
return GetMethod(methodName) != null;
|
||||
#endif
|
||||
}
|
||||
|
||||
private object Call(string function, IRequest requestObject, params object[] args) {
|
||||
return PsRequest.New(requestObject, this, function).CallPowerShell(args);
|
||||
}
|
||||
|
||||
#region implement PackageProvider-interface
|
||||
|
||||
public void AddPackageSource(string name, string location, bool trusted, IRequest requestObject) {
|
||||
Call("AddPackageSource", requestObject, name, location, trusted);
|
||||
}
|
||||
public void FindPackage(string name, string requiredVersion, string minimumVersion, string maximumVersion, int id, IRequest requestObject) {
|
||||
// special case.
|
||||
// if FindPackage is implemented taking an array of strings
|
||||
// and the id > 0 then we need to hold onto the collection until
|
||||
// CompleteFind is called.
|
||||
|
||||
// if it expects multiples...
|
||||
if (IsFirstParameterType<string[]>("FindPackage")) {
|
||||
if (id > 0) {
|
||||
_findByNameBatches.Value.GetOrAdd(id, () => new List<string, string, string, string>()).Add(name, requiredVersion, minimumVersion, maximumVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
// not passed in as a set.
|
||||
Call("FindPackage", requestObject, new string[] {
|
||||
name
|
||||
}, requiredVersion, minimumVersion, maximumVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise, it has to take them one at a time and yield them anyway.
|
||||
Call("FindPackage",requestObject, name, requiredVersion, minimumVersion, maximumVersion);
|
||||
}
|
||||
public void FindPackageByFile(string file, int id, IRequest requestObject) {
|
||||
// special case.
|
||||
// if FindPackageByFile is implemented taking an array of strings
|
||||
// and the id > 0 then we need to hold onto the collection until
|
||||
// CompleteFind is called.
|
||||
|
||||
// if it expects multiples...
|
||||
if (IsFirstParameterType<string[]>("FindPackageByFile")) {
|
||||
if (id > 0) {
|
||||
_findByFileBatches.Value.GetOrAdd(id, () => new List<string>()).Add(file);
|
||||
return;
|
||||
}
|
||||
// not passed in as a set.
|
||||
Call("FindPackageByFile",requestObject, new string[] {
|
||||
file
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Call("FindPackageByFile", requestObject, file);
|
||||
return;
|
||||
}
|
||||
public void FindPackageByUri(Uri uri, int id, IRequest requestObject) {
|
||||
// special case.
|
||||
// if FindPackageByUri is implemented taking an array of strings
|
||||
// and the id > 0 then we need to hold onto the collection until
|
||||
// CompleteFind is called.
|
||||
|
||||
// if it expects multiples...
|
||||
if (IsFirstParameterType<string[]>("FindPackageByUri")) {
|
||||
if (id > 0) {
|
||||
_findByUriBatches.Value.GetOrAdd(id, () => new List<Uri>()).Add(uri);
|
||||
return;
|
||||
}
|
||||
// not passed in as a set.
|
||||
Call("FindPackageByUri",requestObject, new Uri[] {
|
||||
uri
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
Call("FindPackageByUri",requestObject, uri);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the packages that are installed
|
||||
/// </summary>
|
||||
/// <param name="name">the package name to match. Empty or null means match everything</param>
|
||||
/// <param name="requiredVersion">the specific version asked for. If this parameter is specified (ie, not null or empty string) then the minimum and maximum values are ignored</param>
|
||||
/// <param name="minimumVersion">the minimum version of packages to return . If the <code>requiredVersion</code> parameter is specified (ie, not null or empty string) this should be ignored</param>
|
||||
/// <param name="maximumVersion">the maximum version of packages to return . If the <code>requiredVersion</code> parameter is specified (ie, not null or empty string) this should be ignored</param>
|
||||
/// <param name="requestObject">
|
||||
/// An object passed in from the CORE that contains functions that can be used to interact with
|
||||
/// the CORE and HOST
|
||||
/// </param>
|
||||
public void GetInstalledPackages(string name, string requiredVersion, string minimumVersion, string maximumVersion, IRequest requestObject) {
|
||||
Call("GetInstalledPackages",requestObject, name,requiredVersion,minimumVersion,maximumVersion);
|
||||
}
|
||||
|
||||
public void GetDynamicOptions(string category, IRequest requestObject) {
|
||||
OptionCategory cat;
|
||||
if (Enum.TryParse(category ?? "", true, out cat)) {
|
||||
// if this version of the plugin doesn't support that category
|
||||
// there's no point in trying to get options from that type.
|
||||
Call("GetDynamicOptions", requestObject, cat);
|
||||
}
|
||||
}
|
||||
|
||||
private string _providerName;
|
||||
/// <summary>
|
||||
/// Returns the name of the Provider.
|
||||
/// </summary>
|
||||
/// <required />
|
||||
/// <returns>the name of the package provider</returns>
|
||||
public string GetPackageProviderName() {
|
||||
return _providerName ?? (_providerName = (string)CallPowerShellWithoutRequest("GetPackageProviderName"));
|
||||
}
|
||||
public void ResolvePackageSources(IRequest requestObject) {
|
||||
Call("ResolvePackageSources", requestObject);
|
||||
}
|
||||
|
||||
public void InitializeProvider(IRequest requestObject) {
|
||||
Call("InitializeProvider", requestObject);
|
||||
}
|
||||
|
||||
public string GetProviderVersion() {
|
||||
var result= (string)CallPowerShellWithoutRequest("GetProviderVersion");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(result)) {
|
||||
|
||||
if (!string.IsNullOrEmpty(_version)) {
|
||||
return _version;
|
||||
}
|
||||
|
||||
if (_module.Version != new Version(0, 0, 0, 0)) {
|
||||
result = _module.Version.ToString();
|
||||
} else {
|
||||
try
|
||||
{
|
||||
// use the latest date as a version number
|
||||
return (FourPartVersion) _module.FileList.Max(each => new FileInfo(each).LastWriteTime);
|
||||
} catch {
|
||||
// I give up.
|
||||
return "0.0.0.1";
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public void InstallPackage(string fastPath, IRequest requestObject) {
|
||||
Call("InstallPackage", requestObject, fastPath);
|
||||
}
|
||||
public void RemovePackageSource(string name, IRequest requestObject) {
|
||||
Call("RemovePackageSource", requestObject, name);
|
||||
}
|
||||
public void UninstallPackage(string fastPath, IRequest requestObject) {
|
||||
Call("UninstallPackage", requestObject, fastPath);
|
||||
}
|
||||
public void GetFeatures(IRequest requestObject) {
|
||||
Call("GetFeatures", requestObject);
|
||||
}
|
||||
|
||||
// --- operations on a package ---------------------------------------------------------------------------------------------------
|
||||
public void DownloadPackage(string fastPath, string location, IRequest requestObject) {
|
||||
Call("DownloadPackage", requestObject, fastPath, location);
|
||||
}
|
||||
|
||||
public void GetPackageDetails(string fastPath, IRequest requestObject) {
|
||||
Call("GetPackageDetails", requestObject, fastPath);
|
||||
}
|
||||
public int StartFind(IRequest requestObject) {
|
||||
lock (this) {
|
||||
return ++_findId;
|
||||
}
|
||||
}
|
||||
public void CompleteFind(int id, IRequest requestObject) {
|
||||
if (id < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_findByNameBatches.IsValueCreated) {
|
||||
var nameBatch = _findByNameBatches.Value.TryPullValue(id);
|
||||
if (nameBatch != null) {
|
||||
if (IsFirstParameterType<string[]>("FindPackage")) {
|
||||
// it takes a batch at a time.
|
||||
|
||||
var names = nameBatch.Select(each => each.Item1).ToArray();
|
||||
var p1 = nameBatch[0];
|
||||
|
||||
Call("FindPackage", requestObject,names, p1.Item2, p1.Item3, p1.Item4);
|
||||
} else {
|
||||
foreach (var each in nameBatch) {
|
||||
Call("FindPackage",requestObject, each.Item1, each.Item2, each.Item3, each.Item4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_findByFileBatches.IsValueCreated) {
|
||||
var fileBatch = _findByFileBatches.Value.TryPullValue(id);
|
||||
if (fileBatch != null) {
|
||||
if (IsFirstParameterType<string[]>("FindPackageByFile")) {
|
||||
// it takes a batch at a time.
|
||||
Call("FindPackageByFile", requestObject, new object[] {
|
||||
fileBatch.ToArray()
|
||||
});
|
||||
} else {
|
||||
foreach (var each in fileBatch) {
|
||||
Call("FindPackageByFile",requestObject, each);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_findByUriBatches.IsValueCreated) {
|
||||
var uriBatch = _findByUriBatches.Value.TryPullValue(id);
|
||||
if (uriBatch != null) {
|
||||
if (IsFirstParameterType<string[]>("FindPackageByUri")) {
|
||||
// it takes a batch at a time.
|
||||
Call("FindPackageByUri",requestObject, new object[] {uriBatch.ToArray()});
|
||||
} else {
|
||||
foreach (var each in uriBatch) {
|
||||
Call("FindPackageByUri",requestObject, each);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,293 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using Microsoft.PackageManagement.Internal.Utility.Platform;
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell.Internal {
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Threading;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Platform;
|
||||
using Messages = Microsoft.PackageManagement.MetaProvider.PowerShell.Resources.Messages;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
public class PowerShellProviderBase : IDisposable {
|
||||
private object _lock = new Object();
|
||||
protected PSModuleInfo _module;
|
||||
private PowerShell _powershell;
|
||||
private ManualResetEvent _reentrancyLock = new ManualResetEvent(true);
|
||||
private readonly Dictionary<string, CommandInfo> _allCommands = new Dictionary<string, CommandInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Dictionary<string, CommandInfo> _methods = new Dictionary<string, CommandInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public PowerShellProviderBase(PowerShell ps, PSModuleInfo module) {
|
||||
if (module == null) {
|
||||
throw new ArgumentNullException("module");
|
||||
}
|
||||
|
||||
_powershell = ps;
|
||||
_module = module;
|
||||
|
||||
// combine all the cmdinfos we care about
|
||||
// but normalize the keys as we go (remove any '-' '_' chars)
|
||||
foreach (var k in _module.ExportedAliases.Keys) {
|
||||
_allCommands.AddOrSet(k.Replace("-", "").Replace("_", ""), _module.ExportedAliases[k]);
|
||||
}
|
||||
foreach (var k in _module.ExportedCmdlets.Keys) {
|
||||
_allCommands.AddOrSet(k.Replace("-", "").Replace("_", ""), _module.ExportedCmdlets[k]);
|
||||
}
|
||||
foreach (var k in _module.ExportedFunctions.Keys) {
|
||||
_allCommands.AddOrSet(k.Replace("-", "").Replace("_", ""), _module.ExportedFunctions[k]);
|
||||
}
|
||||
}
|
||||
|
||||
public string ModulePath {
|
||||
get {
|
||||
return _module.Path;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing) {
|
||||
if (disposing) {
|
||||
if (_powershell != null) {
|
||||
_powershell.Dispose();
|
||||
_powershell = null;
|
||||
}
|
||||
|
||||
if (_reentrancyLock != null) {
|
||||
_reentrancyLock.Dispose();
|
||||
_reentrancyLock = null;
|
||||
}
|
||||
|
||||
_module = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal CommandInfo GetMethod(string methodName) {
|
||||
return _methods.GetOrAdd(methodName, () => {
|
||||
if (_allCommands.ContainsKey(methodName)) {
|
||||
return _allCommands[methodName];
|
||||
}
|
||||
|
||||
// try simple plurals to single
|
||||
if (methodName.EndsWith("s", StringComparison.OrdinalIgnoreCase)) {
|
||||
var meth = methodName.Substring(0, methodName.Length - 1);
|
||||
if (_allCommands.ContainsKey(meth)) {
|
||||
return _allCommands[meth];
|
||||
}
|
||||
}
|
||||
|
||||
// try words like Dependencies to Dependency
|
||||
if (methodName.EndsWith("cies", StringComparison.OrdinalIgnoreCase)) {
|
||||
var meth = methodName.Substring(0, methodName.Length - 4) + "cy";
|
||||
if (_allCommands.ContainsKey(meth)) {
|
||||
return _allCommands[meth];
|
||||
}
|
||||
}
|
||||
|
||||
// try IsFoo to Test-IsFoo
|
||||
if (methodName.IndexOf("Is", StringComparison.OrdinalIgnoreCase) == 0) {
|
||||
var meth = "test" + methodName;
|
||||
if (_allCommands.ContainsKey(meth)) {
|
||||
return _allCommands[meth];
|
||||
}
|
||||
}
|
||||
|
||||
if (methodName.IndexOf("add", StringComparison.OrdinalIgnoreCase) == 0) {
|
||||
// try it with 'register' instead
|
||||
var result = GetMethod("register" + methodName.Substring(3));
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (methodName.IndexOf("remove", StringComparison.OrdinalIgnoreCase) == 0) {
|
||||
// try it with 'register' instead
|
||||
var result = GetMethod("unregister" + methodName.Substring(6));
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// can't find one, return null.
|
||||
return null;
|
||||
});
|
||||
|
||||
// hmm, it is possible to get the parameter types to match better when binding.
|
||||
// module.ExportedFunctions.FirstOrDefault().Value.Parameters.Values.First().ParameterType
|
||||
}
|
||||
|
||||
internal object CallPowerShellWithoutRequest(string method, params object[] args) {
|
||||
var cmdInfo = GetMethod(method);
|
||||
if (cmdInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var result = _powershell.InvokeFunction<object>(cmdInfo.Name, null, null, args);
|
||||
if (result == null) {
|
||||
// failure!
|
||||
throw new Exception(Messages.PowershellScriptFunctionReturnsNull.format(_module.Name, method));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// lock is on this instance only
|
||||
|
||||
internal void ReportErrors(PsRequest request, IEnumerable<ErrorRecord> errors) {
|
||||
foreach (var error in errors) {
|
||||
request.Error(error.FullyQualifiedErrorId, error.CategoryInfo.Category.ToString(), error.TargetObject == null ? null : error.TargetObject.ToString(), error.ErrorDetails == null ? error.Exception.Message : error.ErrorDetails.Message);
|
||||
if (!string.IsNullOrWhiteSpace(error.Exception.StackTrace)) {
|
||||
// give a debug hint if we have a script stack trace. How nice of us.
|
||||
// the exception stack trace gives better stack than the script stack trace
|
||||
request.Debug(Constants.ScriptStackTrace, error.Exception.StackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IAsyncResult _stopResult;
|
||||
private object _stopLock = new object();
|
||||
|
||||
internal void CancelRequest() {
|
||||
if (!_reentrancyLock.WaitOne(0)) {
|
||||
// it's running right now.
|
||||
#if DEBUG
|
||||
NativeMethods.OutputDebugString("[Cmdlet:debugging] -- Stopping powershell script.");
|
||||
#endif
|
||||
lock (_stopLock) {
|
||||
if (_stopResult == null) {
|
||||
_stopResult = _powershell.BeginStop(ar => { }, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object CallPowerShell(PsRequest request, params object[] args) {
|
||||
// the lock ensures that we're not re-entrant into the same powershell runspace
|
||||
lock (_lock) {
|
||||
if (!_reentrancyLock.WaitOne(0)) {
|
||||
// this lock is set to false, meaning we're still in a call **ON THIS THREAD**
|
||||
// this is bad karma -- powershell won't let us call into the runspace again
|
||||
// we're going to throw an error here because this indicates that the currently
|
||||
// running powershell call is calling back into PM, and it has called back
|
||||
// into this provider. That's just bad bad bad.
|
||||
throw new Exception("Re-entrancy Violation in powershell module");
|
||||
}
|
||||
|
||||
try {
|
||||
// otherwise, this is the first time we've been here during this call.
|
||||
_reentrancyLock.Reset();
|
||||
|
||||
_powershell.SetVariable("request", request);
|
||||
_powershell.Streams.ClearStreams();
|
||||
|
||||
object finalValue = null;
|
||||
ConcurrentBag<ErrorRecord> errors = new ConcurrentBag<ErrorRecord>();
|
||||
|
||||
request.Debug("INVOKING PowerShell Fn {0} with args {1} that has length {2}", request.CommandInfo.Name, String.Join(", ", args), args.Length);
|
||||
|
||||
var result = _powershell.InvokeFunction<object>(request.CommandInfo.Name,
|
||||
(sender, e) => output_DataAdded(sender, e, request, ref finalValue),
|
||||
(sender, e) => error_DataAdded(sender, e, request, errors),
|
||||
args);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
// result is null but it does not mean that the call fails because the command may return nothing
|
||||
request.Debug(Messages.PowershellScriptFunctionReturnsNull.format(_module.Name, request.CommandInfo.Name));
|
||||
}
|
||||
|
||||
if (errors.Count > 0)
|
||||
{
|
||||
// report the error if there are any
|
||||
ReportErrors(request, errors);
|
||||
_powershell.Streams.Error.Clear();
|
||||
}
|
||||
|
||||
return finalValue;
|
||||
} catch (CmdletInvocationException cie) {
|
||||
var error = cie.ErrorRecord;
|
||||
request.Error(error.FullyQualifiedErrorId, error.CategoryInfo.Category.ToString(), error.TargetObject == null ? null : error.TargetObject.ToString(), error.ErrorDetails == null ? error.Exception.Message : error.ErrorDetails.Message);
|
||||
} finally {
|
||||
lock (_stopLock) {
|
||||
if (_stopResult != null){
|
||||
_powershell.EndStop(_stopResult);
|
||||
_stopResult = null;
|
||||
}
|
||||
}
|
||||
_powershell.Clear();
|
||||
_powershell.SetVariable("request", null);
|
||||
// it's ok if someone else calls into this module now.
|
||||
request.Debug("Done calling powershell", request.CommandInfo.Name, _module.Name);
|
||||
_reentrancyLock.Set();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void error_DataAdded(object sender, DataAddedEventArgs e, PsRequest request, ConcurrentBag<ErrorRecord> errors)
|
||||
{
|
||||
PSDataCollection<ErrorRecord> errorStream = sender as PSDataCollection<ErrorRecord>;
|
||||
|
||||
if (errorStream == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var error = errorStream[e.Index];
|
||||
|
||||
if (error != null)
|
||||
{
|
||||
// add the error so we can report them later
|
||||
errors.Add(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void output_DataAdded(object sender, DataAddedEventArgs e, PsRequest request, ref object finalValue)
|
||||
{
|
||||
PSDataCollection<PSObject> outputstream = sender as PSDataCollection<PSObject>;
|
||||
|
||||
if (outputstream == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PSObject psObject = outputstream[e.Index];
|
||||
if (psObject != null)
|
||||
{
|
||||
var value = psObject.ImmediateBaseObject;
|
||||
var y = value as Yieldable;
|
||||
if (y != null)
|
||||
{
|
||||
// yield it to stream the result gradually
|
||||
y.YieldResult(request);
|
||||
}
|
||||
else
|
||||
{
|
||||
finalValue = value;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
|
||||
[assembly: AssemblyTitle("Microsoft.PackageManagement.MetaProvider.PowerShell")]
|
||||
[assembly: AssemblyDescription("PackageManagement Powershell MetaProvider")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Microsoft")]
|
||||
[assembly: AssemblyProduct("Microsoft.PackageManagement.MetaProvider.PowerShell")]
|
||||
[assembly: AssemblyCopyright("Copyright Microsoft © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: InternalsVisibleTo("Microsoft.PackageManagement.Test")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
|
||||
[assembly: Guid("8a16b9f4-f12a-42ab-a396-3c966b896722")]
|
||||
@@ -0,0 +1,213 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
|
||||
using Microsoft.PackageManagement.Internal.Utility.Plugin;
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell.Internal {
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Management.Automation;
|
||||
using System.Security;
|
||||
using Microsoft.PackageManagement.Internal.Api;
|
||||
using Microsoft.PackageManagement.Internal.Implementation;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Async;
|
||||
|
||||
using Messages = Microsoft.PackageManagement.MetaProvider.PowerShell.Resources.Messages;
|
||||
|
||||
public abstract class PsRequest : Request {
|
||||
internal CommandInfo CommandInfo;
|
||||
private PowerShellProviderBase _provider;
|
||||
|
||||
internal bool IsMethodImplemented {
|
||||
get {
|
||||
return CommandInfo != null;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> PackageSources {
|
||||
get {
|
||||
var ps = Sources;
|
||||
if (ps == null) {
|
||||
return new string[] {
|
||||
};
|
||||
}
|
||||
return ps.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
internal IRequest Extend(params object[] objects) {
|
||||
return objects.ConcatSingleItem(this).As<IRequest>();
|
||||
}
|
||||
|
||||
internal string GetMessageStringInternal(string messageText) {
|
||||
return Messages.ResourceManager.GetString(messageText);
|
||||
}
|
||||
|
||||
public PSCredential Credential {
|
||||
get
|
||||
{
|
||||
if (CredentialUsername != null && CredentialPassword != null) {
|
||||
return new PSCredential(CredentialUsername, CredentialPassword);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Hashtable _options;
|
||||
|
||||
public Hashtable Options {
|
||||
get {
|
||||
if (_options == null) {
|
||||
_options = new Hashtable();
|
||||
//quick and dirty, grab all four sets and merge them.
|
||||
var keys = OptionKeys ?? new string[0];
|
||||
foreach (var k in keys) {
|
||||
if (_options.ContainsKey(k)) {
|
||||
continue;
|
||||
}
|
||||
var values = GetOptionValues(k).ToArray();
|
||||
if (values.Length == 1) {
|
||||
if (values[0].IsTrue()) {
|
||||
_options.Add(k, true);
|
||||
} else if (values[0].IndexOf("SECURESTRING:", StringComparison.OrdinalIgnoreCase) == 0) {
|
||||
#if !CORECLR
|
||||
_options.Add(k, values[0].Substring(13).FromProtectedString("salt"));
|
||||
#endif
|
||||
} else {
|
||||
_options.Add(k, values[0]);
|
||||
}
|
||||
} else {
|
||||
_options.Add(k, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
return _options;
|
||||
}
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Design", "CA1026:DefaultParametersShouldNotBeUsed", Justification = "This is required for the PowerShell Providers.")]
|
||||
public object CloneRequest(Hashtable options = null, ArrayList sources = null, PSCredential credential = null) {
|
||||
var srcs = (sources ?? new ArrayList()).ToArray().Select(each => each.ToString()).ToArray();
|
||||
|
||||
options = options ?? new Hashtable();
|
||||
|
||||
var lst = new Dictionary<string, string[]>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var k in options.Keys) {
|
||||
if (k != null) {
|
||||
var obj = options[k];
|
||||
|
||||
string[] val = null;
|
||||
|
||||
if (obj is string) {
|
||||
val = new[] {obj as string};
|
||||
} else {
|
||||
// otherwise, try to cast it to a collection of string-like-things
|
||||
var collection = obj as IEnumerable;
|
||||
if (collection != null) {
|
||||
val = collection.Cast<object>().Select(each => each.ToString()).ToArray();
|
||||
} else {
|
||||
// meh. ToString, and goodnight.
|
||||
val = new[] {obj.ToString()};
|
||||
}
|
||||
}
|
||||
|
||||
lst.Add(k.ToString(), val);
|
||||
}
|
||||
}
|
||||
|
||||
return Extend(new {
|
||||
GetOptionKeys = new Func<IEnumerable<string>>(() => {return lst.Keys.ToArray();}),
|
||||
GetOptionValues = new Func<string, IEnumerable<string>>((key) => {
|
||||
if (lst.ContainsKey(key)) {
|
||||
return lst[key];
|
||||
}
|
||||
return new string[0];
|
||||
}),
|
||||
GetSources = new Func<IEnumerable<string>>(() => {return srcs;}),
|
||||
GetCredentialUsername = new Func<string>(() => {return credential != null ? credential.UserName : null;}),
|
||||
GetCredentialPassword = new Func<SecureString>(() => {return credential != null ? credential.Password: null;}),
|
||||
ShouldContinueWithUntrustedPackageSource = new Func<string, string, bool>((pkgName, pkgSource) => {
|
||||
// chained providers provide locations, and don't rely on 'trusted' flags from the upstream provider.
|
||||
return true;
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
public object CallPowerShell(params object[] args) {
|
||||
if (IsMethodImplemented) {
|
||||
return _provider.CallPowerShell(this, args);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static PsRequest New(Object requestObject, PowerShellProviderBase provider, string methodName) {
|
||||
if (requestObject is IAsyncAction) {
|
||||
((IAsyncAction)(requestObject)).OnCancel += provider.CancelRequest;
|
||||
((IAsyncAction)(requestObject)).OnAbort += provider.CancelRequest;
|
||||
}
|
||||
var req = requestObject.As<PsRequest>();
|
||||
|
||||
req.CommandInfo = provider.GetMethod(methodName);
|
||||
if (req.CommandInfo == null) {
|
||||
req.Debug("METHOD_NOT_IMPLEMENTED", methodName);
|
||||
}
|
||||
req._provider = provider;
|
||||
|
||||
if (req.Options == null) {
|
||||
req.Debug("req.Options is null");
|
||||
|
||||
} else {
|
||||
|
||||
req.Debug("Calling New() : MethodName = '{0}'", methodName);
|
||||
|
||||
foreach(string key in req.Options.Keys)
|
||||
{
|
||||
req.Debug(String.Format(CultureInfo.CurrentCulture, "{0}: {1}", key, req.Options[key]));
|
||||
}
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
public object SelectProvider(string providerName) {
|
||||
return PackageManagementService.SelectProviders(providerName, Extend()).FirstOrDefault(each => each.Name.EqualsIgnoreCase(providerName));
|
||||
}
|
||||
|
||||
public IEnumerable<object> SelectProviders(string providerName) {
|
||||
return PackageManagementService.SelectProviders(providerName, Extend());
|
||||
}
|
||||
|
||||
|
||||
public object Services {
|
||||
get {
|
||||
return ProviderServices;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<object> FindPackageByCanonicalId(string packageId, object requestObject) {
|
||||
return ProviderServices.FindPackageByCanonicalId(packageId, (requestObject ?? new object()) .As<IRequest>());
|
||||
}
|
||||
|
||||
public bool RequirePackageProvider(string packageProviderName, string minimumVersion) {
|
||||
var pp = (_provider as PowerShellPackageProvider);
|
||||
return PackageManagementService.RequirePackageProvider(pp == null ? Constants.ProviderNameUnknown : pp.GetPackageProviderName(), packageProviderName, minimumVersion, Extend());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell {
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using Internal;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
|
||||
public class SoftwareIdentity : Yieldable {
|
||||
public SoftwareIdentity() {
|
||||
}
|
||||
|
||||
public SoftwareIdentity(string fastPackageReference, string name, string version, string versionScheme, string source, string summary, string searchKey, string fullPath, string filename) {
|
||||
FastPackageReference = fastPackageReference;
|
||||
Name = name;
|
||||
Version = version;
|
||||
VersionScheme = versionScheme;
|
||||
Source = source;
|
||||
Summary = summary;
|
||||
SearchKey = searchKey;
|
||||
FullPath = fullPath;
|
||||
Filename = filename;
|
||||
}
|
||||
|
||||
public SoftwareIdentity(string fastPackageReference, string name, string version, string versionScheme, string source, string summary, string searchKey, string fullPath, string filename, Hashtable details, ArrayList entities, ArrayList links, bool fromTrustedSource)
|
||||
: this(fastPackageReference, name, version, versionScheme, source, summary, searchKey,fullPath, filename) {
|
||||
_details = details;
|
||||
_entities = entities;
|
||||
_links = links;
|
||||
FromTrustedSource = fromTrustedSource;
|
||||
}
|
||||
|
||||
public SoftwareIdentity(string fastPackageReference, string name, string version, string versionScheme, string source, string summary, string searchKey, string fullPath, string filename, Hashtable details, ArrayList entities, ArrayList links, bool fromTrustedSource, ArrayList dependencies)
|
||||
: this(fastPackageReference, name, version, versionScheme, source, summary, searchKey, fullPath, filename) {
|
||||
_details = details;
|
||||
_entities = entities;
|
||||
_links = links;
|
||||
FromTrustedSource = fromTrustedSource;
|
||||
_dependencies = dependencies;
|
||||
}
|
||||
|
||||
public SoftwareIdentity(string fastPackageReference, string name, string version, string versionScheme, string source, string summary, string searchKey, string fullPath, string filename, Hashtable details, ArrayList entities, ArrayList links, bool fromTrustedSource, ArrayList dependencies, string tagId, string xmlLang)
|
||||
: this(fastPackageReference, name, version, versionScheme, source, summary, searchKey, fullPath, filename)
|
||||
{
|
||||
_details = details;
|
||||
_entities = entities;
|
||||
_links = links;
|
||||
FromTrustedSource = fromTrustedSource;
|
||||
_dependencies = dependencies;
|
||||
_tagId = tagId;
|
||||
_xmlLang = xmlLang;
|
||||
}
|
||||
|
||||
public SoftwareIdentity(string fastPackageReference, string name, string version, string versionScheme, string source, string summary, string searchKey, string fullPath, string filename, Hashtable details, ArrayList entities, ArrayList links, bool fromTrustedSource, ArrayList dependencies, string tagId, string xmlLang, string destinationPath)
|
||||
: this(fastPackageReference, name, version, versionScheme, source, summary, searchKey, fullPath, filename)
|
||||
{
|
||||
_details = details;
|
||||
_entities = entities;
|
||||
_links = links;
|
||||
FromTrustedSource = fromTrustedSource;
|
||||
_dependencies = dependencies;
|
||||
_tagId = tagId;
|
||||
_xmlLang = xmlLang;
|
||||
_destinationPath = destinationPath;
|
||||
}
|
||||
|
||||
public SoftwareIdentity(string xmlSwidTag, bool commitImmediately)
|
||||
{
|
||||
_xmlSwidTag = xmlSwidTag;
|
||||
_commitImmediately = commitImmediately;
|
||||
}
|
||||
|
||||
|
||||
public string FastPackageReference {get; set;}
|
||||
public string Name {get; set;}
|
||||
public string Version {get; set;}
|
||||
public string VersionScheme {get; set;}
|
||||
public string Source {get; set;}
|
||||
public string Summary {get; set;}
|
||||
|
||||
public string FullPath { get; set; }
|
||||
public string Filename { get; set; }
|
||||
|
||||
public string SearchKey {get; set;}
|
||||
|
||||
public bool FromTrustedSource {get; set;}
|
||||
|
||||
public override bool YieldResult(PsRequest r) {
|
||||
if (r == null) {
|
||||
throw new ArgumentNullException("r");
|
||||
}
|
||||
|
||||
// if we get an xml swidtag string, use that
|
||||
if (!string.IsNullOrWhiteSpace(_xmlSwidTag))
|
||||
{
|
||||
return r.YieldSoftwareIdentityXml(_xmlSwidTag, _commitImmediately) != null;
|
||||
}
|
||||
|
||||
bool result = r.YieldSoftwareIdentity(FastPackageReference, Name, Version, VersionScheme, Summary, Source, SearchKey, FullPath, Filename) != null && YieldTagId(r) && YieldXmlLang(r)
|
||||
&& YieldDetails(r) && YieldEntities(r) && YieldLinks(r) && YieldDependencies(r) && r.AddMetadata(FastPackageReference, "FromTrustedSource", FromTrustedSource.ToString()) != null;
|
||||
|
||||
// check whether we have destination
|
||||
if (!string.IsNullOrWhiteSpace(_destinationPath))
|
||||
{
|
||||
var payload = r.AddPayload();
|
||||
|
||||
// could not add the payload, return false
|
||||
if (string.IsNullOrWhiteSpace(payload))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (r.AddDirectory(payload, System.IO.Path.GetFileName(_destinationPath), System.IO.Path.GetDirectoryName(_destinationPath), null, true) == null)
|
||||
{
|
||||
// cannot add directory
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ArrayList _links;
|
||||
private ArrayList _entities;
|
||||
private ArrayList _dependencies;
|
||||
private string _destinationPath;
|
||||
private string _tagId;
|
||||
private string _xmlLang;
|
||||
private string _xmlSwidTag;
|
||||
private bool _commitImmediately;
|
||||
|
||||
protected virtual bool YieldTagId(PsRequest r)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_tagId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return r.AddTagId(_tagId) != null;
|
||||
}
|
||||
|
||||
protected virtual bool YieldXmlLang(PsRequest r)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_xmlLang))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return r.AddCulture(_xmlLang) != null;
|
||||
}
|
||||
protected override bool YieldDetails(PsRequest r) {
|
||||
if (_details != null && _details.Count > 0) {
|
||||
// we need to send this back as a set of key/path & value pairs.
|
||||
return _details.Flatten().All(kvp => r.AddMetadata(FastPackageReference,kvp.Key, kvp.Value) != null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool YieldLinks(PsRequest r) {
|
||||
if( _links != null ) {
|
||||
return _links.OfType<Link>().All(link => r.AddLink(new Uri(link.HRef), link.Relationship, link.MediaType, link.Ownership, link.Use, link.AppliesToMedia, link.Artifact) != null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual bool YieldDependencies(PsRequest r) {
|
||||
if (_dependencies != null) {
|
||||
return _dependencies.OfType<Dependency>().All(dep => r.AddDependency(dep.ProviderName, dep.PackageName, dep.Version, dep.Source, dep.AppliesTo ) != null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected virtual bool YieldEntities(PsRequest r) {
|
||||
if (_links != null) {
|
||||
return _entities.OfType<Entity>().All(entity => r.AddEntity(entity.Name, entity.RegId, entity.Role, entity.Thumbprint) != null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
namespace Microsoft.PackageManagement.MetaProvider.PowerShell.Internal {
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using Microsoft.PackageManagement.Internal.Utility.Extensions;
|
||||
|
||||
public abstract class Yieldable {
|
||||
protected Hashtable _details;
|
||||
|
||||
public Hashtable Details {
|
||||
get {
|
||||
return _details ?? (_details = new Hashtable());
|
||||
}
|
||||
internal set {
|
||||
_details = value;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract bool YieldResult(PsRequest r);
|
||||
|
||||
protected virtual bool YieldDetails(PsRequest r) {
|
||||
if (_details != null && _details.Count > 0) {
|
||||
// we need to send this back as a set of key/path & value pairs.
|
||||
return _details.Flatten().All(kvp => r.YieldKeyValuePair(kvp.Key, kvp.Value));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<SoftwareIdentity
|
||||
name="PowerShell MetaProvider for PackageManagement"
|
||||
version="1.0.0.0" versionScheme="multipartnumeric"
|
||||
media="(windows) and (PackageManagement) and (min-PackageManagement.api:2) and (PowerShell) and (min-PowerShell:3.0)"
|
||||
xmlns="http://standards.iso.org/iso/19770/-2/2015/schema.xsd">
|
||||
|
||||
</SoftwareIdentity>
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="DuplicateProviderName" xml:space="preserve">
|
||||
<value>Fail to import the provider '{0}' because the provider with the same name also exists from path '{1}'.</value>
|
||||
<comment>{0} provider path {1} provider path</comment>
|
||||
</data>
|
||||
<data name="FailedToImportProvider" xml:space="preserve">
|
||||
<value>Import-PackageProvider '{0}' failed.</value>
|
||||
<comment>0-provider name or path</comment>
|
||||
</data>
|
||||
<data name="FileNotFound" xml:space="preserve">
|
||||
<value>File '{0}' not found.</value>
|
||||
<comment>{0} module path</comment>
|
||||
</data>
|
||||
<data name="ImportModuleFailed" xml:space="preserve">
|
||||
<value>Import-Module failed: '{0}'.</value>
|
||||
<comment>0- module name or path</comment>
|
||||
</data>
|
||||
<data name="ModuleAlreadyLoaded" xml:space="preserve">
|
||||
<value>The module '{0}' is already loaded.</value>
|
||||
<comment>{0} - module name</comment>
|
||||
</data>
|
||||
<data name="ModuleNotFound" xml:space="preserve">
|
||||
<value>Cannot find provider '{0}' under the specified path.</value>
|
||||
</data>
|
||||
<data name="PackageManagementProvidersNotFound" xml:space="preserve">
|
||||
<value>'PackageManagementProviders' key is not found in the .psd1 file under '{0}'.</value>
|
||||
<comment>{0} file path.</comment>
|
||||
</data>
|
||||
<data name="PowershellScriptFunctionReturnsNull" xml:space="preserve">
|
||||
<value>PowerShell Script '{0}' Function '{1}' returns null.</value>
|
||||
<comment>{0} script name, {1} function name</comment>
|
||||
</data>
|
||||
<data name="ProvideNameMismatch" xml:space="preserve">
|
||||
<value>Unable to find provider '{0}'. Please check if the ProviderName is set to '{1}' in '{2}'. </value>
|
||||
<comment>{0} provider name, {1} provider path, {2} provider name</comment>
|
||||
</data>
|
||||
<data name="ProviderNameIsNullOrEmpty" xml:space="preserve">
|
||||
<value>Name of the provider '{0}' is null, empty or not implemented by the provider.</value>
|
||||
<comment>0-provider name</comment>
|
||||
</data>
|
||||
<data name="RootModuleAndPackageManagementProviderNameNotMatch" xml:space="preserve">
|
||||
<value>Root module {0} does not match the packagemanagementprovider name {1}.</value>
|
||||
</data>
|
||||
<data name="ScriptStackTrace" xml:space="preserve">
|
||||
<value>Script failure at : {0}</value>
|
||||
<comment>{0} script location</comment>
|
||||
</data>
|
||||
<data name="SuccessfullyLoadedModule" xml:space="preserve">
|
||||
<value>Loaded PowerShell package provider: '[{0}]'.</value>
|
||||
</data>
|
||||
<data name="UnableToFindModuleProvider" xml:space="preserve">
|
||||
<value>Unable to find package provider '{0}' under the specified path.</value>
|
||||
<comment>{0} module name</comment>
|
||||
</data>
|
||||
<data name="UnableToFindPowerShellFunctionsFile" xml:space="preserve">
|
||||
<value>Unable to find 'PackageProviderFunctions.psm1' at '{0}'</value>
|
||||
</data>
|
||||
<data name="UnableToLoadModule" xml:space="preserve">
|
||||
<value>Cannot load module '{0}' because no valid provider found under the specified path.</value>
|
||||
</data>
|
||||
<data name="CantFindBasePowerShellModuleFolder" xml:space="preserve">
|
||||
<value>Cannot find base Powershell module folder.</value>
|
||||
</data>
|
||||
</root>
|
||||
Reference in new issue
Block a user