public static PSCredential GetRepositoryCredentialFromSecretManagement( string repositoryName, PSCredentialInfo repositoryCredentialInfo, PSCmdlet cmdletPassedIn) { if (!IsSecretManagementVaultAccessible(repositoryName, repositoryCredentialInfo, cmdletPassedIn)) { cmdletPassedIn.ThrowTerminatingError( new ErrorRecord( new PSInvalidOperationException($"Cannot access Microsoft.PowerShell.SecretManagement vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication."), "RepositoryCredentialSecretManagementInaccessibleVault", ErrorCategory.ResourceUnavailable, cmdletPassedIn)); return(null); } var results = PowerShellInvoker.InvokeScriptWithHost <object>( cmdlet: cmdletPassedIn, script: @" param ( [string] $VaultName, [string] $SecretName ) $module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru if ($null -eq $module) { return } & $module ""Get-Secret"" -Name $SecretName -Vault $VaultName ", args: new object[] { repositoryCredentialInfo.VaultName, repositoryCredentialInfo.SecretName }, out Exception terminatingError); var secretValue = (results.Count == 1) ? results[0] : null; if (secretValue == null) { cmdletPassedIn.ThrowTerminatingError( new ErrorRecord( new PSInvalidOperationException( message: $"Microsoft.PowerShell.SecretManagement\\Get-Secret encountered an error while reading secret \"{repositoryCredentialInfo.SecretName}\" from vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.", innerException: terminatingError), "RepositoryCredentialCannotGetSecretFromVault", ErrorCategory.InvalidOperation, cmdletPassedIn)); } if (secretValue is PSCredential secretCredential) { return(secretCredential); } cmdletPassedIn.ThrowTerminatingError( new ErrorRecord( new PSNotSupportedException($"Secret \"{repositoryCredentialInfo.SecretName}\" from vault \"{repositoryCredentialInfo.VaultName}\" has an invalid type. The only supported type is PSCredential."), "RepositoryCredentialInvalidSecretType", ErrorCategory.InvalidType, cmdletPassedIn)); return(null); }
public PSRepositoryInfo(string name, Uri uri, int priority, bool trusted, PSCredentialInfo credentialInfo) { Name = name; Uri = uri; Priority = priority; Trusted = trusted; CredentialInfo = credentialInfo; }
/// <summary> /// Removes a repository from the XML /// Returns: void /// </summary> /// <param name="sectionName"></param> public static List <PSRepositoryInfo> Remove(string[] repoNames, out string[] errorList) { List <PSRepositoryInfo> removedRepos = new List <PSRepositoryInfo>(); List <string> tempErrorList = new List <string>(); XDocument doc; try { // Open file doc = LoadXDocument(FullRepositoryPath); } catch (Exception e) { throw new PSInvalidOperationException(String.Format("Loading repository store failed: {0}", e.Message)); } // Get root of XDocument (XElement) var root = doc.Root; foreach (string repo in repoNames) { XElement node = FindRepositoryElement(doc, repo); if (node == null) { tempErrorList.Add(String.Format("Unable to find repository '{0}'. Use Get-PSResourceRepository to see all available repositories.", repo)); continue; } PSCredentialInfo repoCredentialInfo = null; if (node.Attribute("VaultName") != null & node.Attribute("SecretName") != null) { repoCredentialInfo = new PSCredentialInfo(node.Attribute("VaultName").Value, node.Attribute("SecretName").Value); } removedRepos.Add( new PSRepositoryInfo(repo, new Uri(node.Attribute("Uri").Value), Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), repoCredentialInfo)); // Remove item from file node.Remove(); } // Close the file root.Save(FullRepositoryPath); errorList = tempErrorList.ToArray(); return(removedRepos); }
public static void SaveRepositoryCredentialToSecretManagementVault( string repositoryName, PSCredentialInfo repositoryCredentialInfo, PSCmdlet cmdletPassedIn) { if (!IsSecretManagementVaultAccessible(repositoryName, repositoryCredentialInfo, cmdletPassedIn)) { cmdletPassedIn.ThrowTerminatingError( new ErrorRecord( new PSInvalidOperationException($"Cannot access Microsoft.PowerShell.SecretManagement vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication."), "RepositoryCredentialSecretManagementInaccessibleVault", ErrorCategory.ResourceUnavailable, cmdletPassedIn)); return; } PowerShellInvoker.InvokeScriptWithHost( cmdlet: cmdletPassedIn, script: @" param ( [string] $VaultName, [string] $SecretName, [object] $SecretValue ) $module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru if ($null -eq $module) { return } & $module ""Set-Secret"" -Name $SecretName -Vault $VaultName -Secret $SecretValue ", args: new object[] { repositoryCredentialInfo.VaultName, repositoryCredentialInfo.SecretName, repositoryCredentialInfo.Credential }, out Exception terminatingError); if (terminatingError != null) { cmdletPassedIn.ThrowTerminatingError( new ErrorRecord( new PSInvalidOperationException( message: $"Microsoft.PowerShell.SecretManagement\\Set-Secret encountered an error while adding secret \"{repositoryCredentialInfo.SecretName}\" to vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.", innerException: terminatingError), "RepositoryCredentialCannotAddSecretToVault", ErrorCategory.InvalidOperation, cmdletPassedIn)); } }
public static bool IsSecretManagementVaultAccessible( string repositoryName, PSCredentialInfo repositoryCredentialInfo, PSCmdlet cmdletPassedIn) { var results = PowerShellInvoker.InvokeScriptWithHost <bool>( cmdlet: cmdletPassedIn, script: @" param ( [string] $VaultName ) $module = Microsoft.PowerShell.Core\Import-Module -Name Microsoft.PowerShell.SecretManagement -PassThru if ($null -eq $module) { return } & $module ""Test-SecretVault"" -Name $VaultName ", args: new object[] { repositoryCredentialInfo.VaultName }, out Exception terminatingError); if (terminatingError != null) { cmdletPassedIn.ThrowTerminatingError( new ErrorRecord( new PSInvalidOperationException( message: $"Microsoft.PowerShell.SecretManagement\\Test-SecretVault encountered an error while validating the vault \"{repositoryCredentialInfo.VaultName}\" for PSResourceRepository ({repositoryName}) authentication.", innerException: terminatingError), "RepositoryCredentialSecretManagementInvalidVault", ErrorCategory.InvalidOperation, cmdletPassedIn)); } bool result = (results.Count > 0) ? results[0] : false; return(result); }
/// <summary> /// Add a repository to the store /// Returns: PSRepositoryInfo containing information about the repository just added to the repository store /// </summary> /// <param name="sectionName"></param> public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo) { try { // Open file XDocument doc = LoadXDocument(FullRepositoryPath); if (FindRepositoryElement(doc, repoName) != null) { throw new PSInvalidOperationException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); } // Else, keep going // Get root of XDocument (XElement) var root = doc.Root; // Create new element XElement newElement = new XElement( "Repository", new XAttribute("Name", repoName), new XAttribute("Uri", repoUri), new XAttribute("Priority", repoPriority), new XAttribute("Trusted", repoTrusted) ); if (repoCredentialInfo != null) { newElement.Add(new XAttribute(PSCredentialInfo.VaultNameAttribute, repoCredentialInfo.VaultName)); newElement.Add(new XAttribute(PSCredentialInfo.SecretNameAttribute, repoCredentialInfo.SecretName)); } root.Add(newElement); // Close the file root.Save(FullRepositoryPath); } catch (Exception e) { throw new PSInvalidOperationException(String.Format("Adding to repository store failed: {0}", e.Message)); } return(new PSRepositoryInfo(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo)); }
public static List <PSRepositoryInfo> Read(string[] repoNames, out string[] errorList) { List <string> tempErrorList = new List <string>(); var foundRepos = new List <PSRepositoryInfo>(); XDocument doc; try { // Open file doc = LoadXDocument(FullRepositoryPath); } catch (Exception e) { throw new PSInvalidOperationException(String.Format("Loading repository store failed: {0}", e.Message)); } if (repoNames == null || !repoNames.Any() || string.Equals(repoNames[0], "*") || repoNames[0] == null) { // Name array or single value is null so we will list all repositories registered // iterate through the doc foreach (XElement repo in doc.Descendants("Repository")) { if (!Uri.TryCreate(repo.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) { tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repo.Attribute("Name").Value)); continue; } PSCredentialInfo thisCredentialInfo; string credentialInfoErrorMessage = $"Repository {repo.Attribute("Name").Value} has invalid CredentialInfo. {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute} should both be present and non-empty"; // both keys are present if (repo.Attribute(PSCredentialInfo.VaultNameAttribute) != null && repo.Attribute(PSCredentialInfo.SecretNameAttribute) != null) { try { // both values are non-empty // = valid credentialInfo thisCredentialInfo = new PSCredentialInfo(repo.Attribute(PSCredentialInfo.VaultNameAttribute).Value, repo.Attribute(PSCredentialInfo.SecretNameAttribute).Value); } catch (Exception) { thisCredentialInfo = null; tempErrorList.Add(credentialInfoErrorMessage); continue; } } // both keys are missing else if (repo.Attribute(PSCredentialInfo.VaultNameAttribute) == null && repo.Attribute(PSCredentialInfo.SecretNameAttribute) == null) { // = valid credentialInfo thisCredentialInfo = null; } // one of the keys is missing else { thisCredentialInfo = null; tempErrorList.Add(credentialInfoErrorMessage); continue; } PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(repo.Attribute("Name").Value, thisUri, Int32.Parse(repo.Attribute("Priority").Value), Boolean.Parse(repo.Attribute("Trusted").Value), thisCredentialInfo); foundRepos.Add(currentRepoItem); } } else { foreach (string repo in repoNames) { bool repoMatch = false; WildcardPattern nameWildCardPattern = new WildcardPattern(repo, WildcardOptions.IgnoreCase); foreach (var node in doc.Descendants("Repository").Where(e => nameWildCardPattern.IsMatch(e.Attribute("Name").Value))) { repoMatch = true; if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) { //debug statement tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", node.Attribute("Name").Value)); continue; } PSCredentialInfo thisCredentialInfo; string credentialInfoErrorMessage = $"Repository {node.Attribute("Name").Value} has invalid CredentialInfo. {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute} should both be present and non-empty"; // both keys are present if (node.Attribute(PSCredentialInfo.VaultNameAttribute) != null && node.Attribute(PSCredentialInfo.SecretNameAttribute) != null) { try { // both values are non-empty // = valid credentialInfo thisCredentialInfo = new PSCredentialInfo(node.Attribute(PSCredentialInfo.VaultNameAttribute).Value, node.Attribute(PSCredentialInfo.SecretNameAttribute).Value); } catch (Exception) { thisCredentialInfo = null; tempErrorList.Add(credentialInfoErrorMessage); continue; } } // both keys are missing else if (node.Attribute(PSCredentialInfo.VaultNameAttribute) == null && node.Attribute(PSCredentialInfo.SecretNameAttribute) == null) { // = valid credentialInfo thisCredentialInfo = null; } // one of the keys is missing else { thisCredentialInfo = null; tempErrorList.Add(credentialInfoErrorMessage); continue; } PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(node.Attribute("Name").Value, thisUri, Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), thisCredentialInfo); foundRepos.Add(currentRepoItem); } if (!repo.Contains("*") && !repoMatch) { tempErrorList.Add(String.Format("Unable to find repository with Name '{0}'. Use Get-PSResourceRepository to see all available repositories.", repo)); } } } errorList = tempErrorList.ToArray(); // Sort by priority, then by repo name var reposToReturn = foundRepos.OrderBy(x => x.Priority).ThenBy(x => x.Name); return(reposToReturn.ToList()); }
/// <summary> /// Updates a repository name, Uri, priority, installation policy, or credential information /// Returns: void /// </summary> public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPriority, bool?repoTrusted, PSCredentialInfo repoCredentialInfo) { PSRepositoryInfo updatedRepo; try { // Open file XDocument doc = LoadXDocument(FullRepositoryPath); XElement node = FindRepositoryElement(doc, repoName); if (node == null) { throw new ArgumentException("Cannot find the repository because it does not exist. Try registering the repository using 'Register-PSResourceRepository'"); } // Else, keep going // Get root of XDocument (XElement) var root = doc.Root; // A null Uri value passed in signifies the Uri was not attempted to be set. // So only set Uri attribute if non-null value passed in for repoUri if (repoUri != null) { node.Attribute("Uri").Value = repoUri.AbsoluteUri; } // A negative Priority value passed in signifies the Priority value was not attempted to be set. // So only set Priority attribute if non-null value passed in for repoPriority if (repoPriority >= 0) { node.Attribute("Priority").Value = repoPriority.ToString(); } // A null Trusted value passed in signifies the Trusted value was not attempted to be set. // So only set Trusted attribute if non-null value passed in for repoTrusted. if (repoTrusted != null) { node.Attribute("Trusted").Value = repoTrusted.ToString(); } // A null CredentialInfo value passed in signifies that CredentialInfo was not attempted to be set. // Set VaultName and SecretName attributes if non-null value passed in for repoCredentialInfo if (repoCredentialInfo != null) { if (node.Attribute(PSCredentialInfo.VaultNameAttribute) == null) { node.Add(new XAttribute(PSCredentialInfo.VaultNameAttribute, repoCredentialInfo.VaultName)); } else { node.Attribute(PSCredentialInfo.VaultNameAttribute).Value = repoCredentialInfo.VaultName; } if (node.Attribute(PSCredentialInfo.SecretNameAttribute) == null) { node.Add(new XAttribute(PSCredentialInfo.SecretNameAttribute, repoCredentialInfo.SecretName)); } else { node.Attribute(PSCredentialInfo.SecretNameAttribute).Value = repoCredentialInfo.SecretName; } } // Create Uri from node Uri attribute to create PSRepositoryInfo item to return. if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out Uri thisUri)) { throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repoName)); } // Create CredentialInfo based on new values or whether it was empty to begin with PSCredentialInfo thisCredentialInfo = null; if (node.Attribute(PSCredentialInfo.VaultNameAttribute)?.Value != null && node.Attribute(PSCredentialInfo.SecretNameAttribute)?.Value != null) { thisCredentialInfo = new PSCredentialInfo( node.Attribute(PSCredentialInfo.VaultNameAttribute).Value, node.Attribute(PSCredentialInfo.SecretNameAttribute).Value); } updatedRepo = new PSRepositoryInfo(repoName, thisUri, Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), thisCredentialInfo); // Close the file root.Save(FullRepositoryPath); } catch (Exception e) { throw new PSInvalidOperationException(String.Format("Updating to repository store failed: {0}", e.Message)); } return(updatedRepo); }
public static PSRepositoryInfo AddToRepositoryStore(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force, PSCmdlet cmdletPassedIn, out string errorMsg) { errorMsg = string.Empty; // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition repoName = repoName.Trim(' '); if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) { throw new ArgumentException("Name cannot be null/empty, contain asterisk or be just whitespace"); } if (repoUri == null || !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) { errorMsg = "Invalid Uri, must be one of the following Uri schemes: HTTPS, HTTP, FTP, File Based"; return(null); } if (repoCredentialInfo != null) { bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, cmdletPassedIn); if (repoCredentialInfo.Credential != null) { if (!isSecretManagementModuleAvailable) { errorMsg = $"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."; return(null); } else { Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, cmdletPassedIn); } } if (!isSecretManagementModuleAvailable) { cmdletPassedIn.WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); } } if (!cmdletPassedIn.ShouldProcess(repoName, "Register repository to repository store")) { return(null); } if (!string.IsNullOrEmpty(errorMsg)) { return(null); } var repo = RepositorySettings.Add(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo, force); return(repo); }
public static PSRepositoryInfo AddRepository(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force, PSCmdlet cmdletPassedIn, out string errorMsg) { errorMsg = String.Empty; if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase)) { errorMsg = "Cannot register PSGallery with -Name parameter. Try: Register-PSResourceRepository -PSGallery"; return(null); } return(AddToRepositoryStore(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo, force, cmdletPassedIn, out errorMsg)); }
public static List <PSRepositoryInfo> Read(string[] repoNames, out string[] errorList) { List <string> tempErrorList = new List <string>(); var foundRepos = new List <PSRepositoryInfo>(); XDocument doc; try { // Open file doc = LoadXDocument(FullRepositoryPath); } catch (Exception e) { throw new PSInvalidOperationException(String.Format("Loading repository store failed: {0}", e.Message)); } if (repoNames == null || repoNames.Length == 0 || string.Equals(repoNames[0], "*") || repoNames[0] == null) { // Name array or single value is null so we will list all repositories registered // iterate through the doc foreach (XElement repo in doc.Descendants("Repository")) { if (repo.Attribute("Name") == null) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Name' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } if (repo.Attribute("Priority") == null) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } if (repo.Attribute("Trusted") == null) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } bool urlAttributeExists = repo.Attribute("Url") != null; bool uriAttributeExists = repo.Attribute("Uri") != null; // case: neither Url nor Uri attributes exist if (!urlAttributeExists && !uriAttributeExists) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Url' or equivalent 'Uri' attribute (it must contain one), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } Uri thisUrl = null; // case: either attribute Uri or Url exists // TODO: do we only allow both to exist, across repositories? (i.e if a file has Uri attribute for one repo and Url attribute for another --> is that invalid?) if (urlAttributeExists) { if (!Uri.TryCreate(repo.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) { tempErrorList.Add(String.Format("Unable to read incorrectly formatted Url for repo {0}", repo.Attribute("Name").Value)); continue; } } else if (uriAttributeExists) { if (!Uri.TryCreate(repo.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) { tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", repo.Attribute("Name").Value)); continue; } } PSCredentialInfo thisCredentialInfo; string credentialInfoErrorMessage = $"Repository {repo.Attribute("Name").Value} has invalid CredentialInfo. {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute} should both be present and non-empty"; // both keys are present if (repo.Attribute(PSCredentialInfo.VaultNameAttribute) != null && repo.Attribute(PSCredentialInfo.SecretNameAttribute) != null) { try { // both values are non-empty // = valid credentialInfo thisCredentialInfo = new PSCredentialInfo(repo.Attribute(PSCredentialInfo.VaultNameAttribute).Value, repo.Attribute(PSCredentialInfo.SecretNameAttribute).Value); } catch (Exception) { thisCredentialInfo = null; tempErrorList.Add(credentialInfoErrorMessage); continue; } } // both keys are missing else if (repo.Attribute(PSCredentialInfo.VaultNameAttribute) == null && repo.Attribute(PSCredentialInfo.SecretNameAttribute) == null) { // = valid credentialInfo thisCredentialInfo = null; } // one of the keys is missing else { thisCredentialInfo = null; tempErrorList.Add(credentialInfoErrorMessage); continue; } PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(repo.Attribute("Name").Value, thisUrl, Int32.Parse(repo.Attribute("Priority").Value), Boolean.Parse(repo.Attribute("Trusted").Value), thisCredentialInfo); foundRepos.Add(currentRepoItem); } } else { foreach (string repo in repoNames) { bool repoMatch = false; WildcardPattern nameWildCardPattern = new WildcardPattern(repo, WildcardOptions.IgnoreCase); foreach (var node in doc.Descendants("Repository").Where(e => e.Attribute("Name") != null && nameWildCardPattern.IsMatch(e.Attribute("Name").Value))) { if (node.Attribute("Priority") == null) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } if (node.Attribute("Trusted") == null) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } repoMatch = true; bool urlAttributeExists = node.Attribute("Url") != null; bool uriAttributeExists = node.Attribute("Uri") != null; // case: neither Url nor Uri attributes exist if (!urlAttributeExists && !uriAttributeExists) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Url' or equivalent 'Uri' attribute (it must contain one), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } Uri thisUrl = null; // case: either attribute Uri or Url exists // TODO: do we only allow both to exist, across repositories? (i.e if a file has Uri attribute for one repo and Url attribute for another --> is that invalid?) if (urlAttributeExists) { if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) { tempErrorList.Add(String.Format("Unable to read incorrectly formatted Url for repo {0}", node.Attribute("Name").Value)); continue; } } else if (uriAttributeExists) { if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) { tempErrorList.Add(String.Format("Unable to read incorrectly formatted Uri for repo {0}", node.Attribute("Name").Value)); continue; } } PSCredentialInfo thisCredentialInfo; string credentialInfoErrorMessage = $"Repository {node.Attribute("Name").Value} has invalid CredentialInfo. {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute} should both be present and non-empty"; // both keys are present if (node.Attribute(PSCredentialInfo.VaultNameAttribute) != null && node.Attribute(PSCredentialInfo.SecretNameAttribute) != null) { try { // both values are non-empty // = valid credentialInfo thisCredentialInfo = new PSCredentialInfo(node.Attribute(PSCredentialInfo.VaultNameAttribute).Value, node.Attribute(PSCredentialInfo.SecretNameAttribute).Value); } catch (Exception) { thisCredentialInfo = null; tempErrorList.Add(credentialInfoErrorMessage); continue; } } // both keys are missing else if (node.Attribute(PSCredentialInfo.VaultNameAttribute) == null && node.Attribute(PSCredentialInfo.SecretNameAttribute) == null) { // = valid credentialInfo thisCredentialInfo = null; } // one of the keys is missing else { thisCredentialInfo = null; tempErrorList.Add(credentialInfoErrorMessage); continue; } PSRepositoryInfo currentRepoItem = new PSRepositoryInfo(node.Attribute("Name").Value, thisUrl, Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), thisCredentialInfo); foundRepos.Add(currentRepoItem); } if (!repo.Contains("*") && !repoMatch) { tempErrorList.Add(String.Format("Unable to find repository with Name '{0}'. Use Get-PSResourceRepository to see all available repositories.", repo)); } } } errorList = tempErrorList.ToArray(); // Sort by priority, then by repo name var reposToReturn = foundRepos.OrderBy(x => x.Priority).ThenBy(x => x.Name); return(reposToReturn.ToList()); }
/// <summary> /// Removes a repository from the XML /// Returns: void /// </summary> /// <param name="sectionName"></param> public static List <PSRepositoryInfo> Remove(string[] repoNames, out string[] errorList) { List <PSRepositoryInfo> removedRepos = new List <PSRepositoryInfo>(); List <string> tempErrorList = new List <string>(); XDocument doc; try { // Open file doc = LoadXDocument(FullRepositoryPath); } catch (Exception e) { throw new PSInvalidOperationException(String.Format("Loading repository store failed: {0}", e.Message)); } // Get root of XDocument (XElement) var root = doc.Root; foreach (string repo in repoNames) { XElement node = FindRepositoryElement(doc, repo); if (node == null) { tempErrorList.Add(String.Format("Unable to find repository '{0}'. Use Get-PSResourceRepository to see all available repositories.", repo)); continue; } PSCredentialInfo repoCredentialInfo = null; if (node.Attribute("VaultName") != null & node.Attribute("SecretName") != null) { repoCredentialInfo = new PSCredentialInfo(node.Attribute("VaultName").Value, node.Attribute("SecretName").Value); } if (node.Attribute("Priority") == null) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Priority' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } if (node.Attribute("Trusted") == null) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } // determine if repo had Url or Uri (less likely) attribute bool urlAttributeExists = node.Attribute("Url") != null; bool uriAttributeExists = node.Attribute("Uri") != null; if (!urlAttributeExists && !uriAttributeExists) { tempErrorList.Add(String.Format("Repository element does not contain neccessary 'Url' or equivalent 'Uri' attribute (it must contain one per Repository), in file located at path: {0}. Fix this in your file and run again.", FullRepositoryPath)); continue; } string attributeUrlUriName = urlAttributeExists ? "Url" : "Uri"; removedRepos.Add( new PSRepositoryInfo(repo, new Uri(node.Attribute(attributeUrlUriName).Value), Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), repoCredentialInfo)); // Remove item from file node.Remove(); } // Close the file root.Save(FullRepositoryPath); errorList = tempErrorList.ToArray(); return(removedRepos); }
/// <summary> /// Updates a repository name, Uri, priority, installation policy, or credential information /// Returns: void /// </summary> public static PSRepositoryInfo Update(string repoName, Uri repoUri, int repoPriority, bool?repoTrusted, PSCredentialInfo repoCredentialInfo, PSCmdlet cmdletPassedIn, out string errorMsg) { errorMsg = string.Empty; PSRepositoryInfo updatedRepo; try { // Open file XDocument doc = LoadXDocument(FullRepositoryPath); XElement node = FindRepositoryElement(doc, repoName); if (node == null) { bool repoIsTrusted = !(repoTrusted == null || repoTrusted == false); repoPriority = repoPriority < 0 ? DefaultPriority : repoPriority; return(AddToRepositoryStore(repoName, repoUri, repoPriority, repoIsTrusted, repoCredentialInfo, force: true, cmdletPassedIn, out errorMsg)); } // Check that repository node we are attempting to update has all required attributes: Name, Url (or Uri), Priority, Trusted. // Name attribute is already checked for in FindRepositoryElement() if (node.Attribute("Priority") == null) { errorMsg = $"Repository element does not contain neccessary 'Priority' attribute, in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; return(null); } if (node.Attribute("Trusted") == null) { errorMsg = $"Repository element does not contain neccessary 'Trusted' attribute, in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; return(null); } bool urlAttributeExists = node.Attribute("Url") != null; bool uriAttributeExists = node.Attribute("Uri") != null; if (!urlAttributeExists && !uriAttributeExists) { errorMsg = $"Repository element does not contain neccessary 'Url' attribute (or alternatively 'Uri' attribute), in file located at path: {FullRepositoryPath}. Fix this in your file and run again."; return(null); } // Else, keep going // Get root of XDocument (XElement) var root = doc.Root; // A null Uri (or Url) value passed in signifies the Uri was not attempted to be set. // So only set Uri attribute if non-null value passed in for repoUri // determine if existing repository node (which we wish to update) had Url or Uri attribute Uri thisUrl = null; if (repoUri != null) { if (!Uri.TryCreate(repoUri.AbsoluteUri, UriKind.Absolute, out thisUrl)) { throw new PSInvalidOperationException(String.Format("Unable to read incorrectly formatted Url for repo {0}", repoName)); } if (urlAttributeExists) { node.Attribute("Url").Value = thisUrl.AbsoluteUri; } else { node.Attribute("Uri").Value = thisUrl.AbsoluteUri; } } else { if (urlAttributeExists) { if (!Uri.TryCreate(node.Attribute("Url").Value, UriKind.Absolute, out thisUrl)) { throw new PSInvalidOperationException(String.Format("The 'Url' for repository {0} is invalid and the repository cannot be used. Please update the Url field or remove the repository entry.", repoName)); } } else { if (!Uri.TryCreate(node.Attribute("Uri").Value, UriKind.Absolute, out thisUrl)) { throw new PSInvalidOperationException(String.Format("The 'Url' for repository {0} is invalid and the repository cannot be used. Please update the Url field or remove the repository entry.", repoName)); } } } // A negative Priority value passed in signifies the Priority value was not attempted to be set. // So only set Priority attribute if non-null value passed in for repoPriority if (repoPriority >= 0) { node.Attribute("Priority").Value = repoPriority.ToString(); } // A null Trusted value passed in signifies the Trusted value was not attempted to be set. // So only set Trusted attribute if non-null value passed in for repoTrusted. if (repoTrusted != null) { node.Attribute("Trusted").Value = repoTrusted.ToString(); } // A null CredentialInfo value passed in signifies that CredentialInfo was not attempted to be set. // Set VaultName and SecretName attributes if non-null value passed in for repoCredentialInfo if (repoCredentialInfo != null) { if (node.Attribute(PSCredentialInfo.VaultNameAttribute) == null) { node.Add(new XAttribute(PSCredentialInfo.VaultNameAttribute, repoCredentialInfo.VaultName)); } else { node.Attribute(PSCredentialInfo.VaultNameAttribute).Value = repoCredentialInfo.VaultName; } if (node.Attribute(PSCredentialInfo.SecretNameAttribute) == null) { node.Add(new XAttribute(PSCredentialInfo.SecretNameAttribute, repoCredentialInfo.SecretName)); } else { node.Attribute(PSCredentialInfo.SecretNameAttribute).Value = repoCredentialInfo.SecretName; } } // Create CredentialInfo based on new values or whether it was empty to begin with PSCredentialInfo thisCredentialInfo = null; if (node.Attribute(PSCredentialInfo.VaultNameAttribute)?.Value != null && node.Attribute(PSCredentialInfo.SecretNameAttribute)?.Value != null) { thisCredentialInfo = new PSCredentialInfo( node.Attribute(PSCredentialInfo.VaultNameAttribute).Value, node.Attribute(PSCredentialInfo.SecretNameAttribute).Value); } updatedRepo = new PSRepositoryInfo(repoName, thisUrl, Int32.Parse(node.Attribute("Priority").Value), Boolean.Parse(node.Attribute("Trusted").Value), thisCredentialInfo); // Close the file root.Save(FullRepositoryPath); } catch (Exception e) { throw new PSInvalidOperationException(String.Format("Updating to repository store failed: {0}", e.Message)); } return(updatedRepo); }
/// <summary> /// Add a repository to the store /// Returns: PSRepositoryInfo containing information about the repository just added to the repository store /// </summary> /// <param name="sectionName"></param> public static PSRepositoryInfo Add(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, PSCredentialInfo repoCredentialInfo, bool force) { try { // Open file XDocument doc = LoadXDocument(FullRepositoryPath); if (FindRepositoryElement(doc, repoName) != null) { if (!force) { throw new PSInvalidOperationException(String.Format("The PSResource Repository '{0}' already exists.", repoName)); } // Delete the existing repository before overwriting it (otherwire multiple repos with the same name will be added) List <PSRepositoryInfo> removedRepositories = RepositorySettings.Remove(new string[] { repoName }, out string[] errorList); // Need to load the document again because of changes after removing doc = LoadXDocument(FullRepositoryPath); if (errorList.Count() > 0) { throw new PSInvalidOperationException($"The PSResource Repository '{repoName}' cannot be overwritten: ${errorList.FirstOrDefault()}"); } } // Else, keep going // Get root of XDocument (XElement) var root = doc.Root; // Create new element XElement newElement = new XElement( "Repository", new XAttribute("Name", repoName), new XAttribute("Url", repoUri), new XAttribute("Priority", repoPriority), new XAttribute("Trusted", repoTrusted) ); if (repoCredentialInfo != null) { newElement.Add(new XAttribute(PSCredentialInfo.VaultNameAttribute, repoCredentialInfo.VaultName)); newElement.Add(new XAttribute(PSCredentialInfo.SecretNameAttribute, repoCredentialInfo.SecretName)); } root.Add(newElement); // Close the file root.Save(FullRepositoryPath); } catch (Exception e) { throw new PSInvalidOperationException(String.Format("Adding to repository store failed: {0}", e.Message)); } return(new PSRepositoryInfo(repoName, repoUri, repoPriority, repoTrusted, repoCredentialInfo)); }
public static PSRepositoryInfo UpdateRepositoryStore(string repoName, Uri repoUri, int repoPriority, bool repoTrusted, bool isSet, int defaultPriority, PSCredentialInfo repoCredentialInfo, PSCmdlet cmdletPassedIn, out string errorMsg) { errorMsg = string.Empty; if (repoUri != null && !(repoUri.Scheme == System.Uri.UriSchemeHttp || repoUri.Scheme == System.Uri.UriSchemeHttps || repoUri.Scheme == System.Uri.UriSchemeFtp || repoUri.Scheme == System.Uri.UriSchemeFile)) { errorMsg = "Invalid Uri, Uri must be one of the following schemes: HTTPS, HTTP, FTP, File Based"; return(null); } // check repoName can't contain * or just be whitespace // remove trailing and leading whitespaces, and if Name is just whitespace Name should become null now and be caught by following condition repoName = repoName.Trim(); if (String.IsNullOrEmpty(repoName) || repoName.Contains("*")) { errorMsg = "Name cannot be null or empty, or contain wildcards"; return(null); } // check PSGallery Uri is not trying to be set if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoUri != null) { errorMsg = "The PSGallery repository has a predefined Uri. Setting the -Uri parameter for this repository is not allowed. Please run 'Register-PSResourceRepository -PSGallery' to register the PowerShell Gallery."; return(null); } // check PSGallery CredentialInfo is not trying to be set if (repoName.Equals("PSGallery", StringComparison.OrdinalIgnoreCase) && repoCredentialInfo != null) { errorMsg = "Setting the -CredentialInfo parameter for PSGallery is not allowed. Run 'Register-PSResourceRepository -PSGallery' to register the PowerShell Gallery."; return(null); } // determine trusted value to pass in (true/false if set, null otherwise, hence the nullable bool variable) bool?_trustedNullable = isSet ? new bool?(repoTrusted) : new bool?(); if (repoCredentialInfo != null) { bool isSecretManagementModuleAvailable = Utils.IsSecretManagementModuleAvailable(repoName, cmdletPassedIn); if (repoCredentialInfo.Credential != null) { if (!isSecretManagementModuleAvailable) { errorMsg = $"Microsoft.PowerShell.SecretManagement module is not found, but is required for saving PSResourceRepository {repoName}'s Credential in a vault."; return(null); } else { Utils.SaveRepositoryCredentialToSecretManagementVault(repoName, repoCredentialInfo, cmdletPassedIn); } } if (!isSecretManagementModuleAvailable) { cmdletPassedIn.WriteWarning($"Microsoft.PowerShell.SecretManagement module cannot be found. Make sure it is installed before performing PSResource operations in order to successfully authenticate to PSResourceRepository \"{repoName}\" with its CredentialInfo."); } } // determine if either 1 of 4 values are attempting to be set: Uri, Priority, Trusted, CredentialInfo. // if none are (i.e only Name parameter was provided, write error) if (repoUri == null && repoPriority == defaultPriority && _trustedNullable == null && repoCredentialInfo == null) { errorMsg = "Must set Uri, Priority, Trusted or CredentialInfo parameter"; return(null); } if (!cmdletPassedIn.ShouldProcess(repoName, "Set repository's value(s) in repository store")) { return(null); } if (!string.IsNullOrEmpty(errorMsg)) { return(null); } return(Update(repoName, repoUri, repoPriority, _trustedNullable, repoCredentialInfo, cmdletPassedIn, out errorMsg)); }
public static bool TryCreateValidPSCredentialInfo( PSObject credentialInfoCandidate, PSCmdlet cmdletPassedIn, out PSCredentialInfo repoCredentialInfo, out ErrorRecord errorRecord) { repoCredentialInfo = null; errorRecord = null; try { if (!string.IsNullOrEmpty((string)credentialInfoCandidate.Properties[PSCredentialInfo.VaultNameAttribute]?.Value) && !string.IsNullOrEmpty((string)credentialInfoCandidate.Properties[PSCredentialInfo.SecretNameAttribute]?.Value)) { PSCredential credential = null; if (credentialInfoCandidate.Properties[PSCredentialInfo.CredentialAttribute] != null) { try { credential = (PSCredential)credentialInfoCandidate.Properties[PSCredentialInfo.CredentialAttribute].Value; } catch (Exception e) { errorRecord = new ErrorRecord( new PSArgumentException($"Invalid CredentialInfo {PSCredentialInfo.CredentialAttribute}", e), "InvalidCredentialInfo", ErrorCategory.InvalidArgument, cmdletPassedIn); return(false); } } repoCredentialInfo = new PSCredentialInfo( (string)credentialInfoCandidate.Properties[PSCredentialInfo.VaultNameAttribute].Value, (string)credentialInfoCandidate.Properties[PSCredentialInfo.SecretNameAttribute].Value, credential ); return(true); } else { errorRecord = new ErrorRecord( new PSArgumentException($"Invalid CredentialInfo, must include non-empty {PSCredentialInfo.VaultNameAttribute} and {PSCredentialInfo.SecretNameAttribute}, and optionally a {PSCredentialInfo.CredentialAttribute}"), "InvalidCredentialInfo", ErrorCategory.InvalidArgument, cmdletPassedIn); return(false); } } catch (Exception e) { errorRecord = new ErrorRecord( new PSArgumentException("Invalid CredentialInfo values", e), "InvalidCredentialInfo", ErrorCategory.InvalidArgument, cmdletPassedIn); return(false); } }