src/GetPSResource.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. using NuGet.Versioning; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Management.Automation; using static System.Environment; using MoreLinq; namespace Microsoft.PowerShell.PowerShellGet.Cmdlets { /// <summary> /// It retrieves a resource that was installEd with Install-PSResource /// Returns a single resource or multiple resource. /// </summary> [Cmdlet(VerbsCommon.Get, "PSResource", SupportsShouldProcess = true, HelpUri = "<add>", RemotingCapability = RemotingCapability.None)] public sealed class GetPSResource : PSCmdlet { /// <summary> /// Specifies the desired name for the resource to look for. /// </summary> [Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "NameParameterSet")] [ValidateNotNullOrEmpty] public string[] Name { get { return _name; } set { _name = value; } } private string[] _name; /// <summary> /// Specifies the version of the resource to include to look for. /// </summary> [Parameter(ParameterSetName = "NameParameterSet")] [ValidateNotNullOrEmpty()] public string Version { get { return _version; } set { _version = value; } } private string _version; /// <summary> /// Specifies the path to look in. /// </summary> [Parameter(ParameterSetName = "NameParameterSet")] [ValidateNotNullOrEmpty()] public string Path { get { return _path; } set { _path = value; } } private string _path; /* /// <summary> /// Specifies to include prerelease versions /// </summary> [Parameter(ParameterSetName = "NameParameterSet")] public SwitchParameter Prerelease { get { return _prerelease; } set { _prerelease = value; } } private SwitchParameter _prerelease; */ public static readonly string OsPlatform = System.Runtime.InteropServices.RuntimeInformation.OSDescription; private string programFilesPath; private string myDocumentsPath; /// <summary> /// </summary> protected override void ProcessRecord() { var dirsToSearch = new List<string>(); if (_path != null) { dirsToSearch.AddRange(Directory.GetDirectories(_path).ToList()); } else { var isWindows = OsPlatform.ToLower().Contains("windows"); // should just check the psmodules path???? // PSModules path var psModulePath = Environment.GetEnvironmentVariable("PSModulePath"); var modulePaths = psModulePath.Split(';'); // if not core var isWindowsPS = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory().ToLower().Contains("windows") ? true : false; if (isWindowsPS) { programFilesPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "WindowsPowerShell"); /// TODO: Come back to this var userENVpath = System.IO.Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "Documents"); myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "WindowsPowerShell"); } else { programFilesPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.ProgramFiles), "PowerShell"); myDocumentsPath = System.IO.Path.Combine(Environment.GetFolderPath(SpecialFolder.MyDocuments), "PowerShell"); } /*** Will search first in PSModulePath, then will search in default paths ***/ // 1) Create a list of either // Of all names try { foreach (var path in modulePaths) { dirsToSearch.AddRange(Directory.GetDirectories(path).ToList()); } } catch { } var pfModulesPath = System.IO.Path.Combine(programFilesPath, "Modules"); if (Directory.Exists(pfModulesPath)) { dirsToSearch.AddRange(Directory.GetDirectories(pfModulesPath).ToList()); } var pfScriptsPath = System.IO.Path.Combine(programFilesPath, "Scripts"); if (Directory.Exists(pfScriptsPath)) { dirsToSearch.AddRange(Directory.GetDirectories(pfScriptsPath).ToList()); } var mdModulesPath = System.IO.Path.Combine(myDocumentsPath, "Modules"); // change programfiles to mydocuments if (Directory.Exists(mdModulesPath)) { dirsToSearch.AddRange(Directory.GetDirectories(mdModulesPath).ToList()); } var mdScriptsPath = System.IO.Path.Combine(myDocumentsPath, "Scripts"); // change programFiles to myDocuments if (Directory.Exists(mdScriptsPath)) { dirsToSearch.AddRange(Directory.GetDirectories(mdScriptsPath).ToList()); } // uniqueify dirsToSearch = dirsToSearch.Distinct().ToList(); } // Or a list of the passed in names if (_name != null && !_name[0].Equals("*")) { var nameLowerCased = new List<string>(); Array.ForEach(_name, n => nameLowerCased.Add(n.ToLower())); dirsToSearch = dirsToSearch.FindAll(p => nameLowerCased.Contains(new DirectoryInfo(p).Name.ToLower())); } // try to parse into a specific NuGet version VersionRange versionRange = null; if (_version != null) { NuGetVersion specificVersion; NuGetVersion.TryParse(_version, out specificVersion); if (specificVersion != null) { // exact version versionRange = new VersionRange(specificVersion, true, specificVersion, true, null, null); } else { // check if version range versionRange = VersionRange.Parse(_version); } } List<string> installedPkgsToReturn = new List<string>(); IEnumerable<string> returnPkgs = null; var versionDirs = new List<string>(); //2) use above list to check // if the version specificed is a version range if (versionRange != null) { foreach (var pkgPath in dirsToSearch) { var versionsDirs = Directory.GetDirectories(pkgPath); foreach (var versionPath in versionsDirs) { NuGetVersion dirAsNugetVersion; var dirInfo = new DirectoryInfo(versionPath); NuGetVersion.TryParse(dirInfo.Name, out dirAsNugetVersion); if (versionRange.Satisfies(dirAsNugetVersion)) { // just search scripts paths if (pkgPath.ToLower().Contains("scripts")) { // TODO check if scripts are installed var scriptXmls = Directory.GetFiles(pkgPath); if (_name == null || _name[0].Equals("*")) { // Add all the script xmls installedPkgsToReturn.AddRange(scriptXmls); } else { // Just add the xmls of the names specified foreach (var name in _name) { var scriptXMLPath = System.IO.Path.Combine(pkgPath, name, "_InstalledScriptInfo"); if (File.Exists(scriptXMLPath)) { installedPkgsToReturn.Add(scriptXMLPath); } } } } else { // modules paths versionsDirs = Directory.GetDirectories(pkgPath); // Check if the pkg path actually has version sub directories. if (versionsDirs.Length != 0) { Array.Sort(versionsDirs, StringComparer.OrdinalIgnoreCase); Array.Reverse(versionsDirs); var pkgXmlFilePath = System.IO.Path.Combine(versionsDirs.First(), "PSGetModuleInfo.xml"); // TODO: check if this xml file exists, if it doesn't check if it exists in a previous version installedPkgsToReturn.Add(pkgXmlFilePath); } } installedPkgsToReturn.Add(versionPath); } } } } else { // THIS SHOULD BE DONE // if no version is specified, just get the latest version foreach (var pkgPath in dirsToSearch) { // just search scripts paths if (pkgPath.ToLower().Contains("scripts")) { // TODO check if scripts are installed var scriptXmls = Directory.GetFiles(pkgPath); if (_name == null || _name[0].Equals("*")) { // Add all the script xmls installedPkgsToReturn.AddRange(scriptXmls); } else { // Just add the xmls of the names specified foreach (var name in _name) { var scriptXMLPath = System.IO.Path.Combine(pkgPath, name, "_InstalledScriptInfo"); if (File.Exists(scriptXMLPath)) { installedPkgsToReturn.Add(scriptXMLPath); } } } } else { // modules paths string[] versionsDirs = new string[0]; versionsDirs = Directory.GetDirectories(pkgPath); // Check if the pkg path actually has version sub directories. if (versionsDirs.Length != 0) { Array.Sort(versionsDirs, StringComparer.OrdinalIgnoreCase); Array.Reverse(versionsDirs); var pkgXmlFilePath = System.IO.Path.Combine(versionsDirs.First(), "PSGetModuleInfo.xml"); // TODO: check if this xml file exists, if it doesn't check if it exists in a previous version installedPkgsToReturn.Add(pkgXmlFilePath); } } } } // Flatten returned pkgs before displaying output returnedPkgsFound.Flatten().ToList()[0] var flattenedPkgs = installedPkgsToReturn.Flatten(); foreach (string xmlFilePath in flattenedPkgs) { // Open xml and read metadata from it if (File.Exists(xmlFilePath)) { ReadOnlyPSMemberInfoCollection<PSPropertyInfo> nameInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> versionInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> additionalMetadataInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> psDataInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> repositoryInfo; ReadOnlyPSMemberInfoCollection<PSPropertyInfo> descriptionversionInfo; var isPrelease = false; using (StreamReader sr = new StreamReader(xmlFilePath)) { string text = sr.ReadToEnd(); var deserializedObj = (PSObject)PSSerializer.Deserialize(text); nameInfo = deserializedObj.Properties.Match("Name"); /* // testing adding prerelease parameter additionalMetadataInfo = deserializedObj.Properties.Match("AdditionalMetadata"); if (additionalMetadataInfo.Any()) { isPrelease = additionalMetadataInfo.FirstOrDefault().Value.ToString().Contains("IsPrerelease=true"); if ((isPrelease == true) && _prerelease) // find a stable version of the pkg {} } */ versionInfo = deserializedObj.Properties.Match("Version"); repositoryInfo = deserializedObj.Properties.Match("Repository"); descriptionversionInfo = deserializedObj.Properties.Match("Description"); }; // if -Prerelease is not passed in as a parameter, don't allow prerelease pkgs to be returned, // we still want all pkgs to be returned if -Prerelease is passed in as a param //if ((_prerelease == false && isPrelease == false) || _prerelease == true) //{ PSObject pkgAsPSObject = new PSObject(); try { pkgAsPSObject.Members.Add(new PSNoteProperty("Name", nameInfo.FirstOrDefault().Value)); // need to fix output pkgAsPSObject.Members.Add(new PSNoteProperty("Version", versionInfo.FirstOrDefault().Value)); pkgAsPSObject.Members.Add(new PSNoteProperty("Repository", repositoryInfo.FirstOrDefault().Value)); pkgAsPSObject.Members.Add(new PSNoteProperty("Description", descriptionversionInfo.FirstOrDefault().Value)); WriteObject(pkgAsPSObject); } catch { } //} } } } } } |