private IList<PSModuleInfo> ImportModule_RemotelyViaPsrpSession( ImportModuleOptions importModuleOptions, string moduleName, ModuleSpecification fullyQualifiedName, PSSession psSession) { // // import the module in the remote session first // List<PSObject> remotelyImportedModules; using (var powerShell = System.Management.Automation.PowerShell.Create()) { powerShell.Runspace = psSession.Runspace; powerShell.AddCommand("Import-Module"); powerShell.AddParameter("DisableNameChecking", this.DisableNameChecking); powerShell.AddParameter("PassThru", true); if (fullyQualifiedName != null) { powerShell.AddParameter("FullyQualifiedName", fullyQualifiedName); } else { powerShell.AddParameter("Name", moduleName); if (this.MinimumVersion != null) { powerShell.AddParameter("Version", this.MinimumVersion); } if (this.RequiredVersion != null) { powerShell.AddParameter("RequiredVersion", this.RequiredVersion); } if (this.MaximumVersion != null) { powerShell.AddParameter("MaximumVersion", this.MaximumVersion); } } if (this.ArgumentList != null) { powerShell.AddParameter("ArgumentList", this.ArgumentList); } if (this.BaseForce) { powerShell.AddParameter("Force", true); } string errorMessageTemplate = string.Format( CultureInfo.InvariantCulture, Modules.RemoteDiscoveryRemotePsrpCommandFailed, string.Format(CultureInfo.InvariantCulture, "Import-Module -Name '{0}'", moduleName)); remotelyImportedModules = RemoteDiscoveryHelper.InvokePowerShell( powerShell, this.CancellationToken, this, errorMessageTemplate).ToList(); } List<PSModuleInfo> result = new List<PSModuleInfo>(); foreach (PSObject remotelyImportedModule in remotelyImportedModules) { PSPropertyInfo nameProperty = remotelyImportedModule.Properties["Name"]; if (nameProperty != null) { string remoteModuleName = (string)LanguagePrimitives.ConvertTo( nameProperty.Value, typeof(string), CultureInfo.InvariantCulture); PSPropertyInfo helpInfoProperty = remotelyImportedModule.Properties["HelpInfoUri"]; string remoteHelpInfoUri = null; if (helpInfoProperty != null) { remoteHelpInfoUri = (string)LanguagePrimitives.ConvertTo( helpInfoProperty.Value, typeof(string), CultureInfo.InvariantCulture); } PSPropertyInfo guidProperty = remotelyImportedModule.Properties["Guid"]; Guid remoteModuleGuid = Guid.Empty; if (guidProperty != null) { LanguagePrimitives.TryConvertTo(guidProperty.Value, out remoteModuleGuid); } PSPropertyInfo versionProperty = remotelyImportedModule.Properties["Version"]; Version remoteModuleVersion = null; if (versionProperty != null) { Version tmp; if (LanguagePrimitives.TryConvertTo<Version>(versionProperty.Value, CultureInfo.InvariantCulture, out tmp)) { remoteModuleVersion = tmp; } } PSModuleInfo moduleInfo = ImportModule_RemotelyViaPsrpSession_SinglePreimportedModule( importModuleOptions, remoteModuleName, remoteModuleVersion, psSession); // Set the HelpInfoUri and Guid as necessary, so that Save-Help can work with this module object // to retrieve help files from the remote site. if (moduleInfo != null) { // set the HelpInfoUri if it's needed if (string.IsNullOrEmpty(moduleInfo.HelpInfoUri) && !string.IsNullOrEmpty(remoteHelpInfoUri)) { moduleInfo.SetHelpInfoUri(remoteHelpInfoUri); } // set the Guid if it's needed if (remoteModuleGuid != Guid.Empty) { moduleInfo.SetGuid(remoteModuleGuid); } result.Add(moduleInfo); } } } return result; }
internal void AddRequiredModuleSpecification(ModuleSpecification requiredModuleSpecification) { this._requiredModulesSpecification.Add(requiredModuleSpecification); }
/// <summary> /// Gets a list of modules from the given pattern or ModuleSpecification /// </summary> /// <param name="pattern">pattern to match</param> /// <param name="fullyQualifiedName">ModuleSpecification</param> /// <param name="noErrors">skip errors</param> /// <returns>a list of modules</returns> internal Dictionary<Tuple<string, Version>, UpdatableHelpModuleInfo> GetModuleInfo(string pattern, ModuleSpecification fullyQualifiedName, bool noErrors) { Dictionary<Tuple<string, Version>, UpdatableHelpModuleInfo> modules = GetModuleInfo(Context, pattern, fullyQualifiedName, noErrors); if (modules.Count == 0 && _exceptions.Count == 0 && !noErrors) { var errorMessage = fullyQualifiedName != null ? StringUtil.Format(HelpDisplayStrings.ModuleNotFoundWithFullyQualifiedName, fullyQualifiedName) : StringUtil.Format(HelpDisplayStrings.CannotMatchModulePattern, pattern); ErrorRecord errorRecord = new ErrorRecord(new Exception(errorMessage), "ModuleNotFound", ErrorCategory.InvalidArgument, pattern); WriteError(errorRecord); } return modules; }
/// <summary> /// Resolves using module to a collection of PSModuleInfos. Doesn't throw. /// PSModuleInfo objects are returned in the right order: i.e. if multiply versions of the module /// is presented on the system and user didn't specify version, we will return all of them, but newer one would go first. /// </summary> /// <param name="usingStatementAst">using statement</param> /// <param name="exception">If exception happens, return exception object.</param> /// <param name="wildcardCharactersUsed"> /// True if in the module name uses wildcardCharacter. /// We don't want to resolve any wild-cards in using module. /// </param> /// <param name="isConstant">True if module hashtable contains constant value (it's our requirement).</param> /// <returns>Modules, if can resolve it. null if any problems happens.</returns> private Collection<PSModuleInfo> GetModulesFromUsingModule(UsingStatementAst usingStatementAst, out Exception exception, out bool wildcardCharactersUsed, out bool isConstant) { exception = null; wildcardCharactersUsed = false; isConstant = true; // fullyQualifiedName can be string or hashtable object fullyQualifiedName; if (usingStatementAst.ModuleSpecification != null) { object resultObject; if (!IsConstantValueVisitor.IsConstant(usingStatementAst.ModuleSpecification, out resultObject, forAttribute: false, forRequires: true)) { isConstant = false; return null; } var hashtable = resultObject as System.Collections.Hashtable; var ms = new ModuleSpecification(); exception = ModuleSpecification.ModuleSpecificationInitHelper(ms, hashtable); if (exception != null) { return null; } if (WildcardPattern.ContainsWildcardCharacters(ms.Name)) { wildcardCharactersUsed = true; return null; } fullyQualifiedName = ms; } else { string fullyQualifiedNameStr = usingStatementAst.Name.Value; if (WildcardPattern.ContainsWildcardCharacters(fullyQualifiedNameStr)) { wildcardCharactersUsed = true; return null; } // case 1: relative path. Relative for file in the same folder should include .\ bool isPath = fullyQualifiedNameStr.Contains(@"\"); if (isPath && !LocationGlobber.IsAbsolutePath(fullyQualifiedNameStr)) { string rootPath = Path.GetDirectoryName(_parser._fileName); if (rootPath != null) { fullyQualifiedNameStr = Path.Combine(rootPath, fullyQualifiedNameStr); } } // case 2: Module by name // case 3: Absolute Path // We don't need to do anything for these cases, FullyQualifiedName already handle it. fullyQualifiedName = fullyQualifiedNameStr; } var commandInfo = new CmdletInfo("Get-Module", typeof(GetModuleCommand)); // TODO(sevoroby): we should consider an async call with cancellation here. UsingStatementResolvePowerShell.Commands.Clear(); try { return UsingStatementResolvePowerShell.AddCommand(commandInfo) .AddParameter("FullyQualifiedName", fullyQualifiedName) .AddParameter("ListAvailable", true) .Invoke<PSModuleInfo>(); } catch (Exception e) { exception = e; return null; } }
/// <summary> /// Gets a list of modules from the given pattern /// </summary> /// <param name="context">execution context</param> /// <param name="pattern">pattern to search</param> /// <param name="fullyQualifiedName">Module Specification</param> /// <param name="noErrors">do not generate errors for modules without HelpInfoUri</param> /// <returns>a list of modules</returns> private Dictionary<Tuple<string, Version>, UpdatableHelpModuleInfo> GetModuleInfo(ExecutionContext context, string pattern, ModuleSpecification fullyQualifiedName, bool noErrors) { List<PSModuleInfo> modules = null; string moduleNamePattern = null; if (pattern != null) { moduleNamePattern = pattern; modules = Utils.GetModules(pattern, context); } else if (fullyQualifiedName != null) { moduleNamePattern = fullyQualifiedName.Name; modules = Utils.GetModules(fullyQualifiedName, context); } var helpModules = new Dictionary<Tuple<string, Version>, UpdatableHelpModuleInfo>(); if (modules != null) { foreach (PSModuleInfo module in modules) { ProcessSingleModuleObject(module, context, helpModules, noErrors); } } // Match wildcards WildcardOptions wildcardOptions = WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant; IEnumerable<WildcardPattern> patternList = SessionStateUtilities.CreateWildcardsFromStrings(new string[1] { moduleNamePattern }, wildcardOptions); foreach (KeyValuePair<string, string> name in s_metadataCache) { if (SessionStateUtilities.MatchesAnyWildcardPattern(name.Key, patternList, true)) { // For core snapin, there are no GUIDs. So, we need to construct the HelpInfo slightly differently if (!name.Key.Equals(InitialSessionState.CoreSnapin, StringComparison.OrdinalIgnoreCase)) { var keyTuple = new Tuple<string, Version>(name.Key, new Version("1.0")); if (!helpModules.ContainsKey(keyTuple)) { List<PSModuleInfo> availableModules = Utils.GetModules(name.Key, context); if (null != availableModules) { foreach (PSModuleInfo module in availableModules) { keyTuple = new Tuple<string, Version>(module.Name, module.Version); if (!helpModules.ContainsKey(keyTuple)) { WriteDebug(StringUtil.Format("Found engine module: {0}, {1}.", module.Name, module.Guid)); helpModules.Add(keyTuple, new UpdatableHelpModuleInfo(module.Name, module.Guid, Utils.GetApplicationBase(context.ShellID), s_metadataCache[module.Name])); } } } } } else { var keyTuple2 = new Tuple<string, Version>(name.Key, new Version("1.0")); if (!helpModules.ContainsKey(keyTuple2)) { helpModules.Add(keyTuple2, new UpdatableHelpModuleInfo(name.Key, Guid.Empty, Utils.GetApplicationBase(context.ShellID), name.Value)); } } } } return helpModules; }
/// <summary> /// Processes a ModuleSpecification with potential globbing /// </summary> /// <param name="fullyQualifiedName">ModuleSpecification</param> private void ProcessModuleWithGlobbing(ModuleSpecification fullyQualifiedName) { foreach (KeyValuePair<Tuple<string, Version>, UpdatableHelpModuleInfo> module in GetModuleInfo(null, fullyQualifiedName, false)) { ProcessModule(module.Value); } }
private static string GetModuleVersionStringFromModuleSpecification(ModuleSpecification moduleSpecification) { StringBuilder result = new StringBuilder(); result.Append("(").Append(moduleSpecification.Name); if (moduleSpecification.Version != null) { result.Append(",").Append(moduleSpecification.Version).Append(")"); } else { result.Append(")"); } return result.ToString(); }
/// <summary> /// Load DSC resources from specified module. /// </summary> /// <param name="scriptExtent">Script statement loading the module, can be null</param> /// <param name="moduleSpecifications">Module information, can be null.</param> /// <param name="resourceNames">Name of the resource to be loaded from module</param> /// <param name="errorList">List of errors reported by the method</param> public static void LoadResourcesFromModule(IScriptExtent scriptExtent, ModuleSpecification[] moduleSpecifications, string[] resourceNames, List<ParseError> errorList) { // get all required modules var modules = new Collection<PSModuleInfo>(); if (moduleSpecifications != null) { foreach (var moduleToImport in moduleSpecifications) { bool foundModule = false; var moduleInfos = ModuleCmdletBase.GetModuleIfAvailable(moduleToImport); if (moduleInfos.Count >= 1 && (moduleToImport.Version != null || moduleToImport.Guid != null)) { foreach (var psModuleInfo in moduleInfos) { if ((moduleToImport.Guid.HasValue && moduleToImport.Guid.Equals(psModuleInfo.Guid)) || (moduleToImport.Version != null && moduleToImport.Version.Equals(psModuleInfo.Version))) { modules.Add(psModuleInfo); foundModule = true; break; } } } else if (moduleInfos.Count == 1) { modules.Add(moduleInfos[0]); foundModule = true; } if (!foundModule) { if (moduleInfos.Count > 1) { errorList.Add(new ParseError(scriptExtent, "MultipleModuleEntriesFoundDuringParse", string.Format(CultureInfo.CurrentCulture, ParserStrings.MultipleModuleEntriesFoundDuringParse, moduleToImport.Name))); } else { string moduleString = moduleToImport.Version == null ? moduleToImport.Name : string.Format(CultureInfo.CurrentCulture, "<{0}, {1}>", moduleToImport.Name, moduleToImport.Version); errorList.Add(new ParseError(scriptExtent, "ModuleNotFoundDuringParse", string.Format(CultureInfo.CurrentCulture, ParserStrings.ModuleNotFoundDuringParse, moduleString))); } return; } } } else if (resourceNames != null) { // Lookup the required resources under available PowerShell modules when modulename is not specified using (var powerShell = System.Management.Automation.PowerShell.Create(RunspaceMode.CurrentRunspace)) { powerShell.AddCommand("Get-Module"); powerShell.AddParameter("ListAvailable"); modules = powerShell.Invoke<PSModuleInfo>(); } } // When ModuleName only specified, we need to import all resources from that module var resourcesToImport = new List<string>(); if (resourceNames == null || resourceNames.Length == 0) { resourcesToImport.Add("*"); } else { resourcesToImport.AddRange(resourceNames); } foreach (var moduleInfo in modules) { var dscResourcesPath = Path.Combine(moduleInfo.ModuleBase, "DscResources"); var resourcesFound = new List<String>(); LoadPowerShellClassResourcesFromModule(moduleInfo, moduleInfo, resourcesToImport, resourcesFound, errorList, null, true, scriptExtent); if (Directory.Exists(dscResourcesPath)) { foreach (var resourceToImport in resourcesToImport) { bool foundResources = false; foreach (var resourceDir in Directory.EnumerateDirectories(dscResourcesPath, resourceToImport)) { var resourceName = Path.GetFileName(resourceDir); bool foundCimSchema = false; bool foundScriptSchema = false; string schemaMofFilePath = string.Empty; try { foundCimSchema = ImportCimKeywordsFromModule(moduleInfo, resourceName, out schemaMofFilePath); } catch (FileNotFoundException) { errorList.Add(new ParseError(scriptExtent, "SchemaFileNotFound", string.Format(CultureInfo.CurrentCulture, ParserStrings.SchemaFileNotFound, schemaMofFilePath))); } catch (PSInvalidOperationException e) { errorList.Add(new ParseError(scriptExtent, e.ErrorRecord.FullyQualifiedErrorId, e.Message)); } catch (Exception e) { CommandProcessorBase.CheckForSevereException(e); errorList.Add(new ParseError(scriptExtent, "ExceptionParsingMOFFile", string.Format(CultureInfo.CurrentCulture, ParserStrings.ExceptionParsingMOFFile, schemaMofFilePath, e.Message))); } var schemaScriptFilePath = string.Empty; try { foundScriptSchema = ImportScriptKeywordsFromModule(moduleInfo, resourceName, out schemaScriptFilePath); } catch (FileNotFoundException) { errorList.Add(new ParseError(scriptExtent, "SchemaFileNotFound", string.Format(CultureInfo.CurrentCulture, ParserStrings.SchemaFileNotFound, schemaScriptFilePath))); } catch (Exception e) { // This shouldn't happen so just report the error as is CommandProcessorBase.CheckForSevereException(e); errorList.Add(new ParseError(scriptExtent, "UnexpectedParseError", string.Format(CultureInfo.CurrentCulture, e.ToString()))); } if (foundCimSchema || foundScriptSchema) { foundResources = true; } } // // resourceToImport may be the friendly name of the DSC resource // if (!foundResources) { try { string unused; foundResources = ImportCimKeywordsFromModule(moduleInfo, resourceToImport, out unused); } catch (Exception) { } } // resource name without wildcard (*) should be imported only once if (!resourceToImport.Contains("*") && foundResources) { resourcesFound.Add(resourceToImport); } } } foreach (var resource in resourcesFound) { resourcesToImport.Remove(resource); } if (resourcesToImport.Count == 0) { break; } } if (resourcesToImport.Count > 0) { foreach (var resourceNameToImport in resourcesToImport) { if (!resourceNameToImport.Contains("*")) { errorList.Add(new ParseError(scriptExtent, "DscResourcesNotFoundDuringParsing", string.Format(CultureInfo.CurrentCulture, ParserStrings.DscResourcesNotFoundDuringParsing, resourceNameToImport))); } } } }
// Installs one module // This includes the following steps // 1. Unzip the file // 2. Validate checksum // 3. Validate that the module is a proper DSC module // 4. Install the module private static MiResult ValidateAndInstallOneModule(string downloadLocation, ModuleSpecification moduleSpecification, IEnumerable<string> requiredResources, bool allowModuleOverwrite, out ErrorRecord errorRecord, out UInt32 getActionStatusCode) { Debug.Assert(((requiredResources != null) && requiredResources.Any()), "requiredResources can not be null and should contain one or more required resources"); // DownloadLocation contain .zip file try { string zipFileToSearchFor; if (moduleSpecification.Version == null) { zipFileToSearchFor = moduleSpecification.Name + ".zip"; } else { zipFileToSearchFor = moduleSpecification.Name + "_" + moduleSpecification.Version + ".zip"; } var zipFiles = Directory.GetFiles(downloadLocation, zipFileToSearchFor); if (zipFiles.Length < 1) { errorRecord = GetErrorRecord("DownloadedModulesNotFound", ErrorCategory.InvalidResult, PSinfrastructureStrings.DownloadedModulesNotFound, _pluginModuleName); getActionStatusCode = (int)GetActionStatusCodeTypes.ModuleNotFound; return MiResult.NOT_FOUND; } var dirPath = GetPsProgramFilesModulePath(); var moduleName = String.Empty; var zipFilePath = String.Empty; string moduleToMatch; if (moduleSpecification.Version != null && !string.IsNullOrEmpty(moduleSpecification.Version.ToString())) { moduleToMatch = string.Format(CultureInfo.InvariantCulture, "{0}_{1}.zip", moduleSpecification.Name, moduleSpecification.Version); } else { moduleToMatch = string.Format(CultureInfo.InvariantCulture, "{0}.zip", moduleSpecification.Name); } string zipFile = zipFiles[0]; //extract it in $pshome. var localPath = zipFile.Substring(zipFile.LastIndexOf('\\') + 1); if (string.Compare(localPath, moduleToMatch, StringComparison.OrdinalIgnoreCase) != 0) { getActionStatusCode = (int)GetActionStatusCodeTypes.GetDscModuleCommandFailure; errorRecord = GetErrorRecord("DownloadedModulesNotFound", ErrorCategory.InvalidResult, PSinfrastructureStrings.DownloadedModulesNotFound, _pluginModuleName); return MiResult.NOT_FOUND; } moduleName = moduleSpecification.Name; zipFilePath = zipFile; if (string.IsNullOrEmpty(moduleName)) { getActionStatusCode = (int)GetActionStatusCodeTypes.GetDscModuleCommandFailure; errorRecord = GetErrorRecord("DownloadedModulesNotFound", ErrorCategory.InvalidResult, PSinfrastructureStrings.DownloadedModulesNotFound, _pluginModuleName); return MiResult.NOT_FOUND; } if (!File.Exists(zipFilePath + ".checksum")) { getActionStatusCode = (int)GetActionStatusCodeTypes.ModuleChecksumFileNotFound; errorRecord = GetErrorRecord("ModuleChecksumFileNotExist", ErrorCategory.InvalidResult, PSinfrastructureStrings.ModuleChecksumFileNotExist, _pluginModuleName, zipFilePath); return MiResult.NOT_FOUND; } //compute checksum var statusCode = ValidateModuleWithChecksum(zipFilePath, zipFilePath + ".checksum", out errorRecord, out getActionStatusCode); S_DscCoreR.EventWriteLCMPullModuleChecksumValidationResult(S_DscCoreR.JobGuidString, moduleName, (uint)statusCode); if (statusCode != MiResult.OK) { return statusCode; } var modulePath = dirPath + moduleName; if (Directory.Exists(modulePath) && allowModuleOverwrite == false) { S_DscCoreR.EventWriteLCMPullModuleDirectoryAlreadyExists(S_DscCoreR.JobGuidString, moduleName, modulePath); errorRecord = GetErrorRecord("ModuleDirectoryAlreadyExists", ErrorCategory.ResourceExists, PSinfrastructureStrings.ModuleDirectoryAlreadyExists, moduleName, modulePath); getActionStatusCode = (int)GetActionStatusCodeTypes.ModuleExtractionFailure; statusCode = MiResult.FAILED; return statusCode; } if (Directory.Exists(modulePath) && allowModuleOverwrite) { S_DscCoreR.EventWriteLCMPullModuleDirectoryOverwrite(S_DscCoreR.JobGuidString, moduleName, GetModuleVersionStringFromModuleSpecification(moduleSpecification)); Directory.Move(modulePath, modulePath + "_tmp"); } Directory.CreateDirectory(modulePath); //Validate if module is a valid module. //It is expected that we will get a valid module from the server //hence optimizing for that. try { using (var archive = ZipFile.OpenRead(zipFilePath)) { // Zip file can be in two format. // 1) zip was created at root level and zip content starts with Module folder // 2) zip was created inside the module and top level directly contain the file. It may contain // sub directories and one of them could be same as module name. hence we need to first determine // whether it is type(1) or type(2). var bZipTypeRoot = archive.Entries.All(entry => entry.FullName.StartsWith(moduleName, StringComparison.OrdinalIgnoreCase)); foreach (var entry in archive.Entries) { string fullPath = Path.Combine(bZipTypeRoot ? dirPath : modulePath, entry.FullName); var dirTempIndex = fullPath.LastIndexOf('/'); // This is a directory so we'll create it if necessary. if (dirTempIndex == fullPath.Length - 1) // file is a directory. { if (!Directory.Exists(fullPath)) { Directory.CreateDirectory(fullPath); } } else { entry.ExtractToFile(fullPath, true); } } } } catch (Exception ex) { Directory.Delete(modulePath, true); errorRecord = GetErrorRecord("ModuleExtractionFailed", ex, ErrorCategory.InvalidResult, PSinfrastructureStrings.ModuleExtractionFailed, zipFilePath, _pluginModuleName); getActionStatusCode = (int)GetActionStatusCodeTypes.ModuleExtractionFailure; return MiResult.FAILED; } finally { // The modulePath would have been deleted if there had been any exception. // In that case, restore the old module if any if (!Directory.Exists(modulePath) && Directory.Exists(modulePath + "_tmp")) { Directory.Move(modulePath + "_tmp", modulePath); } // In case of no exception , delete the tmp path else if (Directory.Exists(modulePath + "_tmp")) { Directory.Delete(modulePath + "_tmp"); } } var allResourcesAreValid = MiResult.OK; if ((requiredResources != null) && requiredResources.Any()) { foreach (var resourceName in requiredResources) { //Validate the module var resourceModulePath = Path.Combine(Path.Combine(modulePath, Constants.DscResources), resourceName); var schemaFileName = Path.Combine(resourceModulePath, resourceName + Constants.CimSchemaMofFileExtension); var result = ValidatePsdscModule(resourceModulePath, schemaFileName, out getActionStatusCode, out errorRecord); if (result != MiResult.OK) { allResourcesAreValid = result; break; } } } S_DscCoreR.EventWriteLCMPullModuleContentValidationResult(S_DscCoreR.JobGuidString, moduleName, (uint)allResourcesAreValid); if (allResourcesAreValid == MiResult.OK) { try { if (Directory.Exists(modulePath + "_tmp")) Directory.Delete(modulePath + "_tmp", true); } catch (IOException) { } catch (UnauthorizedAccessException) { } catch (ArgumentException) { } S_DscCoreR.EventWriteLCMPullModuleInstallLocation(S_DscCoreR.JobGuidString, moduleName, modulePath); } else { try { Directory.Delete(modulePath, true); } catch (IOException) { } catch (UnauthorizedAccessException) { } catch (ArgumentException) { } //Move back old module if any if (Directory.Exists(modulePath + "_tmp")) { Directory.Move(modulePath + "_tmp", modulePath); } if (errorRecord == null) { errorRecord = GetErrorRecord("DownloadedModuleInvalid", ErrorCategory.InvalidResult, PSinfrastructureStrings.DownloadedModuleInvalid, zipFilePath, _pluginModuleName); } getActionStatusCode = (int) GetActionStatusCodeTypes.InvalidDownloadedModule; return MiResult.FAILED; } } catch (Exception ex) { getActionStatusCode = (int)GetActionStatusCodeTypes.ModuleExtractionFailure; errorRecord = GetErrorRecord("ModuleExtractionGenericFailure", ex, ErrorCategory.InvalidResult, PSinfrastructureStrings.ModuleExtractionGenericFailure, _pluginModuleName); return MiResult.FAILED; } getActionStatusCode = (int)GetActionStatusCodeTypes.Success; return MiResult.OK; }
// Does the initialization for Get-DscModule. This initialization needs to only happen once for all the modules. // As part of this initialization, the following is done // 1) Download manager is imported // 2) Configuration is parsed to get the list of modules and the download-manager specific properties // 3) For the download manager specific properties, we create PSObjects so we can pass those down to the download manager cmdlets. // 4) We construct a PowerShell that has all the parameters added (except for the Module parameter. This parameter gets added for each module) private static MiResult DoInitializationForGetModule(IntPtr metaConfigHandle, Dictionary<string, Tuple<string, List<string>>> moduleNameVersionTable, string downloadLocation, out string configurationId, out ModuleSpecification[] moduleSpecifications, System.Management.Automation.PowerShell powershell, out PSCommand powershellCommand, out Hashtable arguments, out Collection<PSObject> argumentParameters, out ErrorRecord errorRecord, out UInt32 getActionStatusCode) { configurationId = null; powershellCommand = null; moduleSpecifications = null; argumentParameters = null; arguments = new Hashtable(); // Initialize DownloadManager MiResult statusCode = InitializePlugin(metaConfigHandle, out errorRecord); if (statusCode != MiResult.OK) { getActionStatusCode = (int)GetActionStatusCodeTypes.DownloadManagerInitializationFailure; return statusCode; } //Get parameters for Get-Module cmdlet PSCredential pscredential; statusCode = GetGetModuleParams(metaConfigHandle, out pscredential, arguments, out configurationId, out errorRecord, out getActionStatusCode); if (statusCode != MiResult.OK) { return statusCode; } moduleSpecifications = GetModuleSpecification(moduleNameVersionTable); powershell.Runspace = _pluginRunspace; if (arguments.Count > 0) { argumentParameters = powershell.AddCommand("New-Object").AddParameter("Type", "psobject").AddParameter("Property", arguments).Invoke(); powershell.Commands.Clear(); } powershellCommand = new PSCommand(); powershellCommand.AddCommand(_pluginModuleName + "\\" + DownloadManagerGetModules); powershellCommand.AddParameter(ParamConfigurationId, configurationId); powershellCommand.AddParameter(ParamDestinationPath, downloadLocation); if (pscredential != null) { powershellCommand.AddParameter(ParamCredential, pscredential); } return MiResult.OK; }
// Powershell object passed here will be disposed off by the caller private static MiResult PullOneModule(System.Management.Automation.PowerShell powershell, ModuleSpecification moduleSpecification, string configurationId, string downloadLocation, Hashtable arguments, Collection<PSObject> argumentParameters, out string downloadedModule, out Collection<PSObject> pullOneModuleResult, out ErrorRecord errorRecord, out UInt32 getActionStatusCode) { pullOneModuleResult = null; downloadedModule = null; string moduleVersionString = GetModuleVersionStringFromModuleSpecification(moduleSpecification); try { powershell.AddParameter(ParamModules, moduleSpecification); // Log to ETW Channel:Microsoft-Windows-DSC/Operational S_DscCoreR.EventWriteLCMPullGetModuleAttempt(S_DscCoreR.JobGuidString, _pluginModuleName, configurationId, moduleVersionString); powershell.Streams.Error.Clear(); pullOneModuleResult = arguments.Count > 0 ? powershell.Invoke(argumentParameters) : powershell.Invoke(); if (powershell.Streams.Error.Count > 0) { errorRecord = powershell.Streams.Error[0]; powershell.Dispose(); if( string.Compare(errorRecord.FullyQualifiedErrorId, "WebDownloadManagerUnknownChecksumAlgorithm", StringComparison.OrdinalIgnoreCase) == 0 ) { getActionStatusCode = (int)GetActionStatusCodeTypes.InvalidChecksumAlgorithm; } else { getActionStatusCode = (int)GetActionStatusCodeTypes.GetDscModuleCommandFailure; } return MiResult.FAILED; } } catch (Exception ex) { errorRecord = GetErrorRecord("GetModuleExecutionFailure", ex, ErrorCategory.InvalidType, PSinfrastructureStrings.GetModuleExecutionFailure, _pluginModuleName); getActionStatusCode = (int)GetActionStatusCodeTypes.GetDscModuleCommandFailure; return MiResult.FAILED; } S_DscCoreR.EventWriteLCMPullModuleDownloadLocation(S_DscCoreR.JobGuidString, moduleVersionString, downloadLocation); errorRecord = null; getActionStatusCode = (int)GetActionStatusCodeTypes.Success; return MiResult.OK; }
/// <summary> /// Takes a collection of "module specifications" (string or hashtable) /// and returns the collection as a string that can be inserted into a module manifest. /// </summary> /// <param name="moduleSpecs">The list to quote.</param> /// <param name="streamWriter">Streamwriter to get end of line character from.</param> /// <returns>The quoted list.</returns> private string QuoteModules(IEnumerable moduleSpecs, StreamWriter streamWriter) { StringBuilder result = new StringBuilder(); result.Append("@("); if (moduleSpecs != null) { bool firstModule = true; foreach (object spec in moduleSpecs) { if (spec == null) { continue; } ModuleSpecification moduleSpecification = (ModuleSpecification) LanguagePrimitives.ConvertTo( spec, typeof(ModuleSpecification), CultureInfo.InvariantCulture); if (!firstModule) { result.Append(", "); result.Append(streamWriter.NewLine); result.Append(" "); } firstModule = false; if ((moduleSpecification.Guid == null) && (moduleSpecification.Version == null) && (moduleSpecification.MaximumVersion == null) && (moduleSpecification.RequiredVersion == null)) { result.Append(QuoteName(moduleSpecification.Name)); } else { result.Append("@{"); result.Append("ModuleName = "); result.Append(QuoteName(moduleSpecification.Name)); result.Append("; "); if (moduleSpecification.Guid != null) { result.Append("GUID = "); result.Append(QuoteName(moduleSpecification.Guid.ToString())); result.Append("; "); } if (moduleSpecification.Version != null) { result.Append("ModuleVersion = "); result.Append(QuoteName(moduleSpecification.Version.ToString())); result.Append("; "); } if (moduleSpecification.MaximumVersion != null) { result.Append("MaximumVersion = "); result.Append(QuoteName(moduleSpecification.MaximumVersion)); result.Append("; "); } if (moduleSpecification.RequiredVersion != null) { result.Append("RequiredVersion = "); result.Append(QuoteName(moduleSpecification.RequiredVersion.ToString())); result.Append("; "); } result.Append('}'); } } } result.Append(')'); return(result.ToString()); }
/// <summary> /// Gets a list of modules from the given pattern or ModuleSpecification. /// </summary> /// <param name="pattern">Pattern to match.</param> /// <param name="fullyQualifiedName">ModuleSpecification.</param> /// <param name="noErrors">Skip errors.</param> /// <returns>A list of modules.</returns> internal Dictionary <Tuple <string, Version>, UpdatableHelpModuleInfo> GetModuleInfo(string pattern, ModuleSpecification fullyQualifiedName, bool noErrors) { Dictionary <Tuple <string, Version>, UpdatableHelpModuleInfo> modules = GetModuleInfo(Context, pattern, fullyQualifiedName, noErrors); if (modules.Count == 0 && _exceptions.Count == 0 && !noErrors) { var errorMessage = fullyQualifiedName != null?StringUtil.Format(HelpDisplayStrings.ModuleNotFoundWithFullyQualifiedName, fullyQualifiedName) : StringUtil.Format(HelpDisplayStrings.CannotMatchModulePattern, pattern); ErrorRecord errorRecord = new ErrorRecord(new Exception(errorMessage), "ModuleNotFound", ErrorCategory.InvalidArgument, pattern); WriteError(errorRecord); } return(modules); }
/// <summary> /// Gets a list of modules from the given pattern. /// </summary> /// <param name="context">Execution context.</param> /// <param name="pattern">Pattern to search.</param> /// <param name="fullyQualifiedName">Module Specification.</param> /// <param name="noErrors">Do not generate errors for modules without HelpInfoUri.</param> /// <returns>A list of modules.</returns> private Dictionary <Tuple <string, Version>, UpdatableHelpModuleInfo> GetModuleInfo(ExecutionContext context, string pattern, ModuleSpecification fullyQualifiedName, bool noErrors) { List <PSModuleInfo> modules = null; string moduleNamePattern = null; if (pattern != null) { moduleNamePattern = pattern; modules = Utils.GetModules(pattern, context); } else if (fullyQualifiedName != null) { moduleNamePattern = fullyQualifiedName.Name; modules = Utils.GetModules(fullyQualifiedName, context); } var helpModules = new Dictionary <Tuple <string, Version>, UpdatableHelpModuleInfo>(); if (modules != null) { foreach (PSModuleInfo module in modules) { ProcessSingleModuleObject(module, context, helpModules, noErrors); } } // Match wildcards WildcardOptions wildcardOptions = WildcardOptions.IgnoreCase | WildcardOptions.CultureInvariant; IEnumerable <WildcardPattern> patternList = SessionStateUtilities.CreateWildcardsFromStrings(new string[1] { moduleNamePattern }, wildcardOptions); foreach (KeyValuePair <string, string> name in s_metadataCache) { if (SessionStateUtilities.MatchesAnyWildcardPattern(name.Key, patternList, true)) { // For core snapin, there are no GUIDs. So, we need to construct the HelpInfo slightly differently if (!name.Key.Equals(InitialSessionState.CoreSnapin, StringComparison.OrdinalIgnoreCase)) { var keyTuple = new Tuple <string, Version>(name.Key, new Version("1.0")); if (!helpModules.ContainsKey(keyTuple)) { List <PSModuleInfo> availableModules = Utils.GetModules(name.Key, context); if (availableModules != null) { foreach (PSModuleInfo module in availableModules) { keyTuple = new Tuple <string, Version>(module.Name, module.Version); if (!helpModules.ContainsKey(keyTuple)) { WriteDebug(StringUtil.Format("Found engine module: {0}, {1}.", module.Name, module.Guid)); helpModules.Add(keyTuple, new UpdatableHelpModuleInfo(module.Name, module.Guid, Utils.GetApplicationBase(context.ShellID), s_metadataCache[module.Name])); } } } } } else { var keyTuple2 = new Tuple <string, Version>(name.Key, new Version("1.0")); if (!helpModules.ContainsKey(keyTuple2)) { helpModules.Add(keyTuple2, new UpdatableHelpModuleInfo(name.Key, Guid.Empty, Utils.GetApplicationBase(context.ShellID), name.Value)); } } } } return(helpModules); }
/// <summary> /// Initialize moduleSpecification from hashtable. Return exception object, if hashtable cannot be converted. /// Return null, in the success case. /// </summary> /// <param name="moduleSpecification">object to initialize</param> /// <param name="hashtable">contains info about object to initialize.</param> /// <returns></returns> internal static Exception ModuleSpecificationInitHelper(ModuleSpecification moduleSpecification, Hashtable hashtable) { StringBuilder badKeys = new StringBuilder(); try { foreach (DictionaryEntry entry in hashtable) { if (entry.Key.ToString().Equals("ModuleName", StringComparison.OrdinalIgnoreCase)) { moduleSpecification.Name = LanguagePrimitives.ConvertTo <string>(entry.Value); } else if (entry.Key.ToString().Equals("ModuleVersion", StringComparison.OrdinalIgnoreCase)) { moduleSpecification.Version = LanguagePrimitives.ConvertTo <Version>(entry.Value); } else if (entry.Key.ToString().Equals("RequiredVersion", StringComparison.OrdinalIgnoreCase)) { moduleSpecification.RequiredVersion = LanguagePrimitives.ConvertTo <Version>(entry.Value); } else if (entry.Key.ToString().Equals("MaximumVersion", StringComparison.OrdinalIgnoreCase)) { moduleSpecification.MaximumVersion = LanguagePrimitives.ConvertTo <String>(entry.Value); ModuleCmdletBase.GetMaximumVersion(moduleSpecification.MaximumVersion); } else if (entry.Key.ToString().Equals("GUID", StringComparison.OrdinalIgnoreCase)) { moduleSpecification.Guid = LanguagePrimitives.ConvertTo <Guid?>(entry.Value); } else { if (badKeys.Length > 0) { badKeys.Append(", "); } badKeys.Append("'"); badKeys.Append(entry.Key.ToString()); badKeys.Append("'"); } } } // catch all exceptions here, we are going to report them via return value. // Example of catched exception: one of conversions to Version failed. catch (Exception e) { return(e); } string message; if (badKeys.Length != 0) { message = StringUtil.Format(Modules.InvalidModuleSpecificationMember, "ModuleName, ModuleVersion, RequiredVersion, GUID", badKeys); return(new ArgumentException(message)); } if (string.IsNullOrEmpty(moduleSpecification.Name)) { message = StringUtil.Format(Modules.RequiredModuleMissingModuleName); return(new MissingMemberException(message)); } if (moduleSpecification.RequiredVersion == null && moduleSpecification.Version == null && moduleSpecification.MaximumVersion == null) { message = StringUtil.Format(Modules.RequiredModuleMissingModuleVersion); return(new MissingMemberException(message)); } if (moduleSpecification.RequiredVersion != null && moduleSpecification.Version != null) { message = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, "ModuleVersion", "RequiredVersion"); return(new ArgumentException(message)); } if (moduleSpecification.RequiredVersion != null && moduleSpecification.MaximumVersion != null) { message = StringUtil.Format(SessionStateStrings.GetContent_TailAndHeadCannotCoexist, "MaximumVersion", "RequiredVersion"); return(new ArgumentException(message)); } return(null); }