PowerShellGet/PSModule.psm1
######################################################################################### # # Copyright (c) Microsoft Corporation. All rights reserved. # # PowerShellGet Module # ######################################################################################### Microsoft.PowerShell.Core\Set-StrictMode -Version Latest #region script variables $script:IsInbox = $PSHOME.EndsWith('\WindowsPowerShell\v1.0', [System.StringComparison]::OrdinalIgnoreCase) $script:IsWindows = (-not (Get-Variable -Name IsWindows -ErrorAction Ignore)) -or $IsWindows $script:IsLinux = (Get-Variable -Name IsLinux -ErrorAction Ignore) -and $IsLinux $script:IsMacOS = (Get-Variable -Name IsMacOS -ErrorAction Ignore) -and $IsMacOS $script:IsCoreCLR = $PSVersionTable.ContainsKey('PSEdition') -and $PSVersionTable.PSEdition -eq 'Core' $script:IsNanoServer = & { if (!$script:IsWindows) { return $false } $serverLevelsPath = 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Server\ServerLevels\' if (Test-Path -Path $serverLevelsPath) { $NanoItem = Get-ItemProperty -Name NanoServer -Path $serverLevelsPath -ErrorAction Ignore if ($NanoItem -and ($NanoItem.NanoServer -eq 1)) { return $true } } return $false } if($script:IsInbox) { $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell" } elseif($script:IsCoreCLR){ if($script:IsWindows) { $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath 'PowerShell' } else { $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Split-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('SHARED_MODULES')) -Parent } } try { $script:MyDocumentsFolderPath = [Environment]::GetFolderPath("MyDocuments") } catch { $script:MyDocumentsFolderPath = $null } if($script:IsInbox) { $script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath) { Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath "WindowsPowerShell" } else { Microsoft.PowerShell.Management\Join-Path -Path $env:USERPROFILE -ChildPath "Documents\WindowsPowerShell" } } elseif($script:IsCoreCLR) { if($script:IsWindows) { $script:MyDocumentsPSPath = if($script:MyDocumentsFolderPath) { Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsFolderPath -ChildPath 'PowerShell' } else { Microsoft.PowerShell.Management\Join-Path -Path $HOME -ChildPath "Documents\PowerShell" } } else { $script:MyDocumentsPSPath = Microsoft.PowerShell.Management\Split-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('USER_MODULES')) -Parent } } $script:ProgramFilesModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath 'Modules' $script:MyDocumentsModulesPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath 'Modules' $script:ProgramFilesScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesPSPath -ChildPath 'Scripts' $script:MyDocumentsScriptsPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsPSPath -ChildPath 'Scripts' $script:TempPath = [System.IO.Path]::GetTempPath() $script:PSGetItemInfoFileName = "PSGetModuleInfo.xml" if($script:IsWindows) { $script:PSGetProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramData -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' $script:PSGetAppLocalPath = Microsoft.PowerShell.Management\Join-Path -Path $env:LOCALAPPDATA -ChildPath 'Microsoft\Windows\PowerShell\PowerShellGet\' } else { $script:PSGetProgramDataPath = Microsoft.PowerShell.Management\Join-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('CONFIG')) -ChildPath 'PowerShellGet' $script:PSGetAppLocalPath = Microsoft.PowerShell.Management\Join-Path -Path ([System.Management.Automation.Platform]::SelectProductNameForDirectory('CACHE')) -ChildPath 'PowerShellGet' } $script:PSGetModuleSourcesFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath "PSRepositories.xml" $script:PSGetModuleSources = $null $script:PSGetInstalledModules = $null $script:PSGetSettingsFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath "PowerShellGetSettings.xml" $script:PSGetSettings = $null $script:MyDocumentsInstalledScriptInfosPath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsScriptsPath -ChildPath 'InstalledScriptInfos' $script:ProgramFilesInstalledScriptInfosPath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesScriptsPath -ChildPath 'InstalledScriptInfos' $script:IsRunningAsElevated = $true $script:IsRunningAsElevatedTested = $false $script:InstalledScriptInfoFileName = 'InstalledScriptInfo.xml' $script:PSGetInstalledScripts = $null # Public PSGallery module source name and location $Script:PSGalleryModuleSource="PSGallery" $Script:PSGallerySourceUri = 'https://go.microsoft.com/fwlink/?LinkID=397631&clcid=0x409' $Script:PSGalleryPublishUri = 'https://go.microsoft.com/fwlink/?LinkID=397527&clcid=0x409' $Script:PSGalleryScriptSourceUri = 'https://go.microsoft.com/fwlink/?LinkID=622995&clcid=0x409' # PSGallery V3 Source $Script:PSGalleryV3SourceUri = 'https://go.microsoft.com/fwlink/?LinkId=528403&clcid=0x409' $Script:PSGalleryV2ApiAvailable = $true $Script:PSGalleryV3ApiAvailable = $false $Script:PSGalleryApiChecked = $false $Script:ResponseUri = "ResponseUri" $Script:StatusCode = "StatusCode" $Script:Exception = "Exception" $script:PSModuleProviderName = 'PowerShellGet' $script:PackageManagementProviderParam = "PackageManagementProvider" $script:PublishLocation = "PublishLocation" $script:ScriptSourceLocation = 'ScriptSourceLocation' $script:ScriptPublishLocation = 'ScriptPublishLocation' $script:Proxy = 'Proxy' $script:ProxyCredential = 'ProxyCredential' $script:Credential = 'Credential' $script:VSTSAuthenticatedFeedsDocUrl = 'https://go.microsoft.com/fwlink/?LinkID=698608' $script:Prerelease = "Prerelease" $script:NuGetProviderName = "NuGet" $script:NuGetProviderVersion = [Version]'2.8.5.201' $script:SupportsPSModulesFeatureName="supports-powershell-modules" $script:FastPackRefHashtable = @{} $script:NuGetBinaryProgramDataPath=if($script:IsWindows) {"$env:ProgramFiles\PackageManagement\ProviderAssemblies"} $script:NuGetBinaryLocalAppDataPath=if($script:IsWindows) {"$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies"} # go fwlink for 'https://nuget.org/nuget.exe' $script:NuGetClientSourceURL = 'https://go.microsoft.com/fwlink/?LinkID=690216&clcid=0x409' $script:NuGetExeName = 'NuGet.exe' $script:NuGetExePath = $null $script:NuGetProvider = $null $script:DotnetCommandName = 'dotnet' $script:MinimumDotnetCommandVersion = [Version]'2.0.0' $script:DotnetInstallUrl = 'https://aka.ms/dotnet-install-script' $script:DotnetCommandPath = $null # PowerShellGetFormatVersion will be incremented when we change the .nupkg format structure. # PowerShellGetFormatVersion is in the form of Major.Minor. # Minor is incremented for the backward compatible format change. # Major is incremented for the breaking change. $script:PSGetRequireLicenseAcceptanceFormatVersion = [Version]'2.0' $script:CurrentPSGetFormatVersion = $script:PSGetRequireLicenseAcceptanceFormatVersion $script:PSGetFormatVersion = "PowerShellGetFormatVersion" $script:SupportedPSGetFormatVersionMajors = @("1","2") $script:ModuleReferences = 'Module References' $script:AllVersions = "AllVersions" $script:AllowPrereleaseVersions = "AllowPrereleaseVersions" $script:Filter = "Filter" $script:IncludeValidSet = @('DscResource','Cmdlet','Function','Workflow','RoleCapability') $script:DscResource = "PSDscResource" $script:Command = "PSCommand" $script:Cmdlet = "PSCmdlet" $script:Function = "PSFunction" $script:Workflow = "PSWorkflow" $script:RoleCapability = 'PSRoleCapability' $script:Includes = "PSIncludes" $script:Tag = "Tag" $script:NotSpecified= '_NotSpecified_' $script:PSGetModuleName = 'PowerShellGet' $script:FindByCanonicalId = 'FindByCanonicalId' $script:InstalledLocation = 'InstalledLocation' $script:PSArtifactType = 'Type' $script:PSArtifactTypeModule = 'Module' $script:PSArtifactTypeScript = 'Script' $script:All = 'All' $script:Name = 'Name' $script:Version = 'Version' $script:Guid = 'Guid' $script:Path = 'Path' $script:ScriptBase = 'ScriptBase' $script:Description = 'Description' $script:Author = 'Author' $script:CompanyName = 'CompanyName' $script:Copyright = 'Copyright' $script:Tags = 'Tags' $script:LicenseUri = 'LicenseUri' $script:ProjectUri = 'ProjectUri' $script:IconUri = 'IconUri' $script:RequiredModules = 'RequiredModules' $script:ExternalModuleDependencies = 'ExternalModuleDependencies' $script:ReleaseNotes = 'ReleaseNotes' $script:RequiredScripts = 'RequiredScripts' $script:ExternalScriptDependencies = 'ExternalScriptDependencies' $script:DefinedCommands = 'DefinedCommands' $script:DefinedFunctions = 'DefinedFunctions' $script:DefinedWorkflows = 'DefinedWorkflows' $script:TextInfo = (Get-Culture).TextInfo $script:PrivateData = 'PrivateData' $script:PSScriptInfoProperties = @($script:Name $script:Version, $script:Guid, $script:Path, $script:ScriptBase, $script:Description, $script:Author, $script:CompanyName, $script:Copyright, $script:Tags, $script:ReleaseNotes, $script:RequiredModules, $script:ExternalModuleDependencies, $script:RequiredScripts, $script:ExternalScriptDependencies, $script:LicenseUri, $script:ProjectUri, $script:IconUri, $script:DefinedCommands, $script:DefinedFunctions, $script:DefinedWorkflows, $script:PrivateData ) $script:SystemEnvironmentKey = 'HKLM:\System\CurrentControlSet\Control\Session Manager\Environment' $script:UserEnvironmentKey = 'HKCU:\Environment' $script:SystemEnvironmentVariableMaximumLength = 1024 $script:UserEnvironmentVariableMaximumLength = 255 $script:EnvironmentVariableTarget = @{ Process = 0; User = 1; Machine = 2 } # Wildcard pattern matching configuration. $script:wildcardOptions = [System.Management.Automation.WildcardOptions]::CultureInvariant -bor ` [System.Management.Automation.WildcardOptions]::IgnoreCase $script:DynamicOptionTypeMap = @{ 0 = [string]; # String 1 = [string[]]; # StringArray 2 = [int]; # Int 3 = [switch]; # Switch 4 = [string]; # Folder 5 = [string]; # File 6 = [string]; # Path 7 = [Uri]; # Uri 8 = [SecureString]; #SecureString } #endregion script variables #region Module message resolvers $script:PackageManagementMessageResolverScriptBlock = { param($i, $Message) return (PackageManagementMessageResolver -MsgId $i, -Message $Message) } $script:PackageManagementSaveModuleMessageResolverScriptBlock = { param($i, $Message) $PackageTarget = $LocalizedData.InstallModulewhatIfMessage $QuerySaveUntrustedPackage = $LocalizedData.QuerySaveUntrustedPackage switch ($i) { 'ActionInstallPackage' { return "Save-Module" } 'QueryInstallUntrustedPackage' {return $QuerySaveUntrustedPackage} 'TargetPackage' { return $PackageTarget } Default { $Message = $Message -creplace "Install", "Download" $Message = $Message -creplace "install", "download" return (PackageManagementMessageResolver -MsgId $i, -Message $Message) } } } $script:PackageManagementInstallModuleMessageResolverScriptBlock = { param($i, $Message) $PackageTarget = $LocalizedData.InstallModulewhatIfMessage switch ($i) { 'ActionInstallPackage' { return "Install-Module" } 'TargetPackage' { return $PackageTarget } Default { return (PackageManagementMessageResolver -MsgId $i, -Message $Message) } } } $script:PackageManagementUnInstallModuleMessageResolverScriptBlock = { param($i, $Message) $PackageTarget = $LocalizedData.InstallModulewhatIfMessage switch ($i) { 'ActionUninstallPackage' { return "Uninstall-Module" } 'TargetPackageVersion' { return $PackageTarget } Default { return (PackageManagementMessageResolver -MsgId $i, -Message $Message) } } } $script:PackageManagementUpdateModuleMessageResolverScriptBlock = { param($i, $Message) $PackageTarget = ($LocalizedData.UpdateModulewhatIfMessage -replace "__OLDVERSION__",$($psgetItemInfo.Version)) switch ($i) { 'ActionInstallPackage' { return "Update-Module" } 'TargetPackage' { return $PackageTarget } Default { return (PackageManagementMessageResolver -MsgId $i, -Message $Message) } } } function PackageManagementMessageResolver($MsgID, $Message) { $NoMatchFound = $LocalizedData.NoMatchFound $SourceNotFound = $LocalizedData.SourceNotFound $ModuleIsNotTrusted = $LocalizedData.ModuleIsNotTrusted $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedPackage switch ($MsgID) { 'NoMatchFound' { return $NoMatchFound } 'SourceNotFound' { return $SourceNotFound } 'CaptionPackageNotTrusted' { return $ModuleIsNotTrusted } 'CaptionSourceNotTrusted' { return $RepositoryIsNotTrusted } 'QueryInstallUntrustedPackage' {return $QueryInstallUntrustedPackage} Default { if($Message) { $tempMessage = $Message -creplace "PackageSource", "PSRepository" $tempMessage = $tempMessage -creplace "packagesource", "psrepository" $tempMessage = $tempMessage -creplace "Package", "Module" $tempMessage = $tempMessage -creplace "package", "module" $tempMessage = $tempMessage -creplace "Sources", "Repositories" $tempMessage = $tempMessage -creplace "sources", "repositories" $tempMessage = $tempMessage -creplace "Source", "Repository" $tempMessage = $tempMessage -creplace "source", "repository" return $tempMessage } } } } #endregion Module message resolvers #region Script message resolvers $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets = { param($i, $Message) return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) } $script:PackageManagementSaveScriptMessageResolverScriptBlock = { param($i, $Message) $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage $QuerySaveUntrustedPackage = $LocalizedData.QuerySaveUntrustedScriptPackage switch ($i) { 'ActionInstallPackage' { return "Save-Script" } 'QueryInstallUntrustedPackage' {return $QuerySaveUntrustedPackage} 'TargetPackage' { return $PackageTarget } Default { $Message = $Message -creplace "Install", "Download" $Message = $Message -creplace "install", "download" return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) } } } $script:PackageManagementInstallScriptMessageResolverScriptBlock = { param($i, $Message) $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage switch ($i) { 'ActionInstallPackage' { return "Install-Script" } 'TargetPackage' { return $PackageTarget } Default { return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) } } } $script:PackageManagementUnInstallScriptMessageResolverScriptBlock = { param($i, $Message) $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage switch ($i) { 'ActionUninstallPackage' { return "Uninstall-Script" } 'TargetPackageVersion' { return $PackageTarget } Default { return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) } } } $script:PackageManagementUpdateScriptMessageResolverScriptBlock = { param($i, $Message) $PackageTarget = ($LocalizedData.UpdateScriptwhatIfMessage -replace "__OLDVERSION__",$($psgetItemInfo.Version)) switch ($i) { 'ActionInstallPackage' { return "Update-Script" } 'TargetPackage' { return $PackageTarget } Default { return (PackageManagementMessageResolverForScripts -MsgId $i, -Message $Message) } } } function PackageManagementMessageResolverForScripts($MsgID, $Message) { $NoMatchFound = $LocalizedData.NoMatchFoundForScriptName $SourceNotFound = $LocalizedData.SourceNotFound $ScriptIsNotTrusted = $LocalizedData.ScriptIsNotTrusted $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedScriptPackage switch ($MsgID) { 'NoMatchFound' { return $NoMatchFound } 'SourceNotFound' { return $SourceNotFound } 'CaptionPackageNotTrusted' { return $ScriptIsNotTrusted } 'CaptionSourceNotTrusted' { return $RepositoryIsNotTrusted } 'QueryInstallUntrustedPackage' {return $QueryInstallUntrustedPackage} Default { if($Message) { $tempMessage = $Message -creplace "PackageSource", "PSRepository" $tempMessage = $tempMessage -creplace "packagesource", "psrepository" $tempMessage = $tempMessage -creplace "Package", "Script" $tempMessage = $tempMessage -creplace "package", "script" $tempMessage = $tempMessage -creplace "Sources", "Repositories" $tempMessage = $tempMessage -creplace "sources", "repositories" $tempMessage = $tempMessage -creplace "Source", "Repository" $tempMessage = $tempMessage -creplace "source", "repository" return $tempMessage } } } } #endregion Script message resolvers Microsoft.PowerShell.Utility\Import-LocalizedData LocalizedData -filename PSGet.Resource.psd1 #region Add .Net type for Telemetry APIs and WebProxy # Check and add InternalWebProxy type if( -not ('Microsoft.PowerShell.Commands.PowerShellGet.InternalWebProxy' -as [Type])) { $RequiredAssembliesForInternalWebProxy = @( [System.Net.IWebProxy].Assembly.FullName, [System.Uri].Assembly.FullName ) $InternalWebProxySource = @' using System; using System.Net; namespace Microsoft.PowerShell.Commands.PowerShellGet { /// <summary> /// Used by Ping-Endpoint function to supply webproxy to HttpClient /// We cannot use System.Net.WebProxy because this is not available on CoreClr /// </summary> public class InternalWebProxy : IWebProxy { Uri _proxyUri; ICredentials _credentials; public InternalWebProxy(Uri uri, ICredentials credentials) { Credentials = credentials; _proxyUri = uri; } /// <summary> /// Credentials used by WebProxy /// </summary> public ICredentials Credentials { get { return _credentials; } set { _credentials = value; } } public Uri GetProxy(Uri destination) { return _proxyUri; } public bool IsBypassed(Uri host) { return false; } } } '@ try { $AddType_prams = @{ TypeDefinition = $InternalWebProxySource Language = 'CSharp' ErrorAction = 'SilentlyContinue' } if (-not $script:IsCoreCLR -or $script:IsNanoServer) { $AddType_prams['ReferencedAssemblies'] = $RequiredAssembliesForInternalWebProxy } Add-Type @AddType_prams } catch { Write-Warning -Message "InternalWebProxy: $_" } } # Check and add Telemetry type if(('Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI' -as [Type]) -and -not ('Microsoft.PowerShell.Commands.PowerShellGet.Telemetry' -as [Type])) { $RequiredAssembliesForTelemetry = @( [System.Management.Automation.PSCmdlet].Assembly.FullName ) $TelemetrySource = @' using System; using System.Management.Automation; namespace Microsoft.PowerShell.Commands.PowerShellGet { public static class Telemetry { public static void TraceMessageArtifactsNotFound(string[] artifactsNotFound, string operationName) { Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { ArtifactsNotFound = artifactsNotFound }); } public static void TraceMessageNonPSGalleryRegistration(string sourceLocationType, string sourceLocationHash, string installationPolicy, string packageManagementProvider, string publishLocationHash, string scriptSourceLocationHash, string scriptPublishLocationHash, string operationName) { Microsoft.PowerShell.Telemetry.Internal.TelemetryAPI.TraceMessage(operationName, new { SourceLocationType = sourceLocationType, SourceLocationHash = sourceLocationHash, InstallationPolicy = installationPolicy, PackageManagementProvider = packageManagementProvider, PublishLocationHash = publishLocationHash, ScriptSourceLocationHash = scriptSourceLocationHash, ScriptPublishLocationHash = scriptPublishLocationHash }); } } } '@ try { $AddType_prams = @{ TypeDefinition = $TelemetrySource Language = 'CSharp' ErrorAction = 'SilentlyContinue' } $AddType_prams['ReferencedAssemblies'] = $RequiredAssembliesForTelemetry Add-Type @AddType_prams } catch { Write-Warning -Message "Telemetry: $_" } } # Turn ON Telemetry if the infrastructure is present on the machine $script:TelemetryEnabled = $false if('Microsoft.PowerShell.Commands.PowerShellGet.Telemetry' -as [Type]) { $telemetryMethods = ([Microsoft.PowerShell.Commands.PowerShellGet.Telemetry] | Get-Member -Static).Name if ($telemetryMethods.Contains("TraceMessageArtifactsNotFound") -and $telemetryMethods.Contains("TraceMessageNonPSGalleryRegistration")) { $script:TelemetryEnabled = $true } } # Check and add Win32Helpers type $script:IsSafeX509ChainHandleAvailable = ($null -ne ('Microsoft.Win32.SafeHandles.SafeX509ChainHandle' -as [Type])) if($script:IsWindows -and -not ('Microsoft.PowerShell.Commands.PowerShellGet.Win32Helpers' -as [Type])) { $RequiredAssembliesForWin32Helpers = @() if($script:IsSafeX509ChainHandleAvailable) { # It is not possible to define a single internal SafeHandle class in PowerShellGet namespace for all the supported versions of .Net Framework including .Net Core. # SafeHandleZeroOrMinusOneIsInvalid is not a public class on .Net Core, # therefore SafeX509ChainHandle will be used if it is available otherwise InternalSafeX509ChainHandle is defined below. # # ChainContext is not available on .Net Core, we must have to use SafeX509ChainHandle on .Net Core. # $SafeX509ChainHandleClassName = 'SafeX509ChainHandle' $RequiredAssembliesForWin32Helpers += [Microsoft.Win32.SafeHandles.SafeX509ChainHandle].Assembly.FullName } else { # SafeX509ChainHandle is not available on .Net Framework 4.5 or older versions, # therefore InternalSafeX509ChainHandle is defined below. # $SafeX509ChainHandleClassName = 'InternalSafeX509ChainHandle' } $Win32HelpersSource = @" using System; using System.Net; using Microsoft.Win32.SafeHandles; using System.Security.Cryptography; using System.Runtime.InteropServices; using System.Runtime.ConstrainedExecution; using System.Runtime.Versioning; using System.Security; namespace Microsoft.PowerShell.Commands.PowerShellGet { [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] public struct CERT_CHAIN_POLICY_PARA { public CERT_CHAIN_POLICY_PARA(int size) { cbSize = (uint) size; dwFlags = 0; pvExtraPolicyPara = IntPtr.Zero; } public uint cbSize; public uint dwFlags; public IntPtr pvExtraPolicyPara; } [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] public struct CERT_CHAIN_POLICY_STATUS { public CERT_CHAIN_POLICY_STATUS(int size) { cbSize = (uint) size; dwError = 0; lChainIndex = IntPtr.Zero; lElementIndex = IntPtr.Zero; pvExtraPolicyStatus = IntPtr.Zero; } public uint cbSize; public uint dwError; public IntPtr lChainIndex; public IntPtr lElementIndex; public IntPtr pvExtraPolicyStatus; } // Internal SafeHandleZeroOrMinusOneIsInvalid class to remove the dependency on .Net Framework 4.6. public abstract class InternalSafeHandleZeroOrMinusOneIsInvalid : SafeHandle { protected InternalSafeHandleZeroOrMinusOneIsInvalid(bool ownsHandle) : base(IntPtr.Zero, ownsHandle) { } public override bool IsInvalid { get { return handle == IntPtr.Zero || handle == new IntPtr(-1); } } } // Internal SafeX509ChainHandle class to remove the dependency on .Net Framework 4.6. [SecurityCritical] public sealed class InternalSafeX509ChainHandle : InternalSafeHandleZeroOrMinusOneIsInvalid { private InternalSafeX509ChainHandle () : base(true) {} internal InternalSafeX509ChainHandle (IntPtr handle) : base (true) { SetHandle(handle); } internal static InternalSafeX509ChainHandle InvalidHandle { get { return new InternalSafeX509ChainHandle(IntPtr.Zero); } } [SecurityCritical] override protected bool ReleaseHandle() { CertFreeCertificateChain(handle); return true; } [DllImport("Crypt32.dll", SetLastError=true)] $(if(-not $script:IsCoreCLR) { ' [SuppressUnmanagedCodeSecurity, ResourceExposure(ResourceScope.None), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] ' }) private static extern void CertFreeCertificateChain(IntPtr handle); } public class Win32Helpers { [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public extern static bool CertVerifyCertificateChainPolicy( [In] IntPtr pszPolicyOID, [In] $SafeX509ChainHandleClassName pChainContext, [In] ref CERT_CHAIN_POLICY_PARA pPolicyPara, [In,Out] ref CERT_CHAIN_POLICY_STATUS pPolicyStatus); [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern $SafeX509ChainHandleClassName CertDuplicateCertificateChain( [In] IntPtr pChainContext); $(if($script:IsSafeX509ChainHandleAvailable) { @" [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] $(if(-not $script:IsCoreCLR) { ' [ResourceExposure(ResourceScope.None)] ' }) public static extern SafeX509ChainHandle CertDuplicateCertificateChain( [In] SafeX509ChainHandle pChainContext); "@ }) public static bool IsMicrosoftCertificate([In] $SafeX509ChainHandleClassName pChainContext) { //------------------------------------------------------------------------- // CERT_CHAIN_POLICY_MICROSOFT_ROOT // // Checks if the last element of the first simple chain contains a // Microsoft root public key. If it doesn't contain a Microsoft root // public key, dwError is set to CERT_E_UNTRUSTEDROOT. // // pPolicyPara is optional. However, // MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG can be set in // the dwFlags in pPolicyPara to also check for the Microsoft Test Roots. // // MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG can be set // in the dwFlags in pPolicyPara to check for the Microsoft root for // application signing instead of the Microsoft product root. This flag // explicitly checks for the application root only and cannot be combined // with the test root flag. // // MICROSOFT_ROOT_CERT_CHAIN_POLICY_DISABLE_FLIGHT_ROOT_FLAG can be set // in the dwFlags in pPolicyPara to always disable the Flight root. // // pvExtraPolicyPara and pvExtraPolicyStatus aren't used and must be set // to NULL. //-------------------------------------------------------------------------- const uint MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG = 0x00010000; const uint MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG = 0x00020000; //const uint MICROSOFT_ROOT_CERT_CHAIN_POLICY_DISABLE_FLIGHT_ROOT_FLAG = 0x00040000; CERT_CHAIN_POLICY_PARA PolicyPara = new CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_PARA))); CERT_CHAIN_POLICY_STATUS PolicyStatus = new CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_STATUS))); int CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7; PolicyPara.dwFlags = (uint) MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG; bool isMicrosoftRoot = false; if(CertVerifyCertificateChainPolicy(new IntPtr(CERT_CHAIN_POLICY_MICROSOFT_ROOT), pChainContext, ref PolicyPara, ref PolicyStatus)) { isMicrosoftRoot = (PolicyStatus.dwError == 0); } // Also check for the Microsoft root for application signing if the Microsoft product root verification is unsuccessful. if(!isMicrosoftRoot) { // Some Microsoft modules can be signed with Microsoft Application Root instead of Microsoft Product Root, // So we need to use the MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG for the certificate verification. // MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG can not be used // with MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG, // so additional CertVerifyCertificateChainPolicy call is required to verify the given certificate is in Microsoft Application Root. // CERT_CHAIN_POLICY_PARA PolicyPara2 = new CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_PARA))); CERT_CHAIN_POLICY_STATUS PolicyStatus2 = new CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_STATUS))); PolicyPara2.dwFlags = (uint) MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG; if(CertVerifyCertificateChainPolicy(new IntPtr(CERT_CHAIN_POLICY_MICROSOFT_ROOT), pChainContext, ref PolicyPara2, ref PolicyStatus2)) { isMicrosoftRoot = (PolicyStatus2.dwError == 0); } } return isMicrosoftRoot; } } } "@ try { $AddType_prams = @{ TypeDefinition = $Win32HelpersSource Language = 'CSharp' ErrorAction = 'SilentlyContinue' } if ((-not $script:IsCoreCLR -or $script:IsNanoServer) -and $RequiredAssembliesForWin32Helpers) { $AddType_prams['ReferencedAssemblies'] = $RequiredAssembliesForWin32Helpers } Add-Type @AddType_prams } catch { Write-Warning -Message "Win32Helpers: $_" } } #endregion #region *-Module cmdlets function Publish-Module { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(SupportsShouldProcess=$true, PositionalBinding=$false, HelpUri='https://go.microsoft.com/fwlink/?LinkID=398575', DefaultParameterSetName="ModuleNameParameterSet")] Param ( [Parameter(Mandatory=$true, ParameterSetName="ModuleNameParameterSet", ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter(Mandatory=$true, ParameterSetName="ModulePathParameterSet", ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(ParameterSetName="ModuleNameParameterSet")] [ValidateNotNullOrEmpty()] [string] $RequiredVersion, [Parameter()] [ValidateNotNullOrEmpty()] [string] $NuGetApiKey, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Repository = $Script:PSGalleryModuleSource, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [ValidateSet("2.0")] [Version] $FormatVersion, [Parameter()] [string[]] $ReleaseNotes, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Tags, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $LicenseUri, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $IconUri, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $ProjectUri, [Parameter()] [switch] $Force, [Parameter(ParameterSetName="ModuleNameParameterSet")] [switch] $AllowPrerelease ) Begin { Get-PSGalleryApiAvailability -Repository $Repository if($LicenseUri -and -not (Test-WebUri -uri $LicenseUri)) { $message = $LocalizedData.InvalidWebUri -f ($LicenseUri, "LicenseUri") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $LicenseUri } if($IconUri -and -not (Test-WebUri -uri $IconUri)) { $message = $LocalizedData.InvalidWebUri -f ($IconUri, "IconUri") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $IconUri } if($ProjectUri -and -not (Test-WebUri -uri $ProjectUri)) { $message = $LocalizedData.InvalidWebUri -f ($ProjectUri, "ProjectUri") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ProjectUri } Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe -Force:$Force } Process { if($Repository -eq $Script:PSGalleryModuleSource) { $moduleSource = Get-PSRepository -Name $Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue if(-not $moduleSource) { $message = $LocalizedData.PSGalleryNotFound -f ($Repository) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'PSGalleryNotFound' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Repository return } } else { $ev = $null $moduleSource = Get-PSRepository -Name $Repository -ErrorVariable ev if($ev) { return } } $DestinationLocation = $moduleSource.PublishLocation if(-not $DestinationLocation -or (-not (Microsoft.PowerShell.Management\Test-Path $DestinationLocation) -and -not (Test-WebUri -uri $DestinationLocation))) { $message = $LocalizedData.PSGalleryPublishLocationIsMissing -f ($Repository, $Repository) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PSGalleryPublishLocationIsMissing" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Repository } $message = $LocalizedData.PublishLocation -f ($DestinationLocation) Write-Verbose -Message $message if(-not $NuGetApiKey.Trim()) { if(Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) { $NuGetApiKey = "$(Get-Random)" } else { $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } } $providerName = Get-ProviderName -PSCustomObject $moduleSource if($providerName -ne $script:NuGetProviderName) { $message = $LocalizedData.PublishModuleSupportsOnlyNuGetBasedPublishLocations -f ($moduleSource.PublishLocation, $Repository, $Repository) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PublishModuleSupportsOnlyNuGetBasedPublishLocations" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Repository } $moduleName = $null if($Name) { if ($RequiredVersion) { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $reqResult = ValidateAndGet-VersionPrereleaseStrings -Version $RequiredVersion -CallerPSCmdlet $PSCmdlet if (-not $reqResult) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $reqVersion = $reqResult["Version"] $reqPrerelease = $reqResult["Prerelease"] } else { $reqVersion = $null $reqPrerelease = $null } # Find the module to be published locally, search by name and RequiredVersion $module = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false | Microsoft.PowerShell.Core\Where-Object { $modInfoPrerelease = $null if ($_.PrivateData -and $_.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable" -and $_.PrivateData["PSData"] -and $_.PrivateData.PSData.GetType().ToString() -eq "System.Collections.Hashtable" -and $_.PrivateData.PSData["Prerelease"]) { $modInfoPrerelease = $_.PrivateData.PSData.Prerelease } (-not $RequiredVersion) -or ( ($reqVersion -eq $_.Version) -and ($reqPrerelease -match $modInfoPrerelease) ) } if(-not $module) { if($RequiredVersion) { $message = $LocalizedData.ModuleWithRequiredVersionNotAvailableLocally -f ($Name, $RequiredVersion) } else { $message = $LocalizedData.ModuleNotAvailableLocally -f ($Name) } ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "ModuleNotAvailableLocallyToPublish" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Name } elseif($module.GetType().ToString() -ne "System.Management.Automation.PSModuleInfo") { $message = $LocalizedData.AmbiguousModuleName -f ($Name) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "AmbiguousModuleNameToPublish" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Name } $moduleName = $module.Name $Path = $module.ModuleBase } else { $resolvedPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $resolvedPath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $resolvedPath -PathType Container)) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage ($LocalizedData.PathIsNotADirectory -f ($Path)) ` -ErrorId "PathIsNotADirectory" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Path return } $moduleName = Microsoft.PowerShell.Management\Split-Path -Path $resolvedPath -Leaf $modulePathWithVersion = $false # if the Leaf of the $resolvedPath is a version, use its parent folder name as the module name [Version]$ModuleVersion = $null if([System.Version]::TryParse($moduleName, ([ref]$ModuleVersion))) { $moduleName = Microsoft.PowerShell.Management\Split-Path -Path (Microsoft.PowerShell.Management\Split-Path $resolvedPath -Parent) -Leaf $modulePathWithVersion = $true } $manifestPath = Join-PathUtility -Path $resolvedPath -ChildPath "$moduleName.psd1" -PathType File $module = $null if(Microsoft.PowerShell.Management\Test-Path -Path $manifestPath -PathType Leaf) { $ev = $null $module = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath ` -ErrorVariable ev ` -Verbose:$VerbosePreference if($ev) { # Above Test-ModuleManifest cmdlet should write an errors to the Errors stream and Console. return } } elseif(-not $modulePathWithVersion -and ($PSVersionTable.PSVersion -ge '5.0.0')) { $module = Microsoft.PowerShell.Core\Get-Module -Name $resolvedPath -ListAvailable -ErrorAction SilentlyContinue -Verbose:$false } if(-not $module) { $message = $LocalizedData.InvalidModulePathToPublish -f ($Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'InvalidModulePathToPublish' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Path } elseif($module.GetType().ToString() -ne "System.Management.Automation.PSModuleInfo") { $message = $LocalizedData.AmbiguousModulePath -f ($Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'AmbiguousModulePathToPublish' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Path } if($module -and (-not $module.Path.EndsWith('.psd1', [System.StringComparison]::OrdinalIgnoreCase))) { $message = $LocalizedData.InvalidModuleToPublish -f ($module.Name) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "InvalidModuleToPublish" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $module.Name } $moduleName = $module.Name $Path = $module.ModuleBase } $message = $LocalizedData.PublishModuleLocation -f ($moduleName, $Path) Write-Verbose -Message $message #If users are providing tags using -Tags while running PS 5.0, will show warning messages if($Tags) { $message = $LocalizedData.TagsShouldBeIncludedInManifestFile -f ($moduleName, $Path) Write-Warning $message } if($ReleaseNotes) { $message = $LocalizedData.ReleaseNotesShouldBeIncludedInManifestFile -f ($moduleName, $Path) Write-Warning $message } if($LicenseUri) { $message = $LocalizedData.LicenseUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) Write-Warning $message } if($IconUri) { $message = $LocalizedData.IconUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) Write-Warning $message } if($ProjectUri) { $message = $LocalizedData.ProjectUriShouldBeIncludedInManifestFile -f ($moduleName, $Path) Write-Warning $message } # Copy the source module to temp location to publish $tempModulePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath ` -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)\$moduleName" if ($FormatVersion -eq "1.0") { $tempModulePathForFormatVersion = Microsoft.PowerShell.Management\Join-Path $tempModulePath "Content\Deployment\$script:ModuleReferences\$moduleName" } else { $tempModulePathForFormatVersion = $tempModulePath } $null = Microsoft.PowerShell.Management\New-Item -Path $tempModulePathForFormatVersion -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false Microsoft.PowerShell.Management\Copy-Item -Path "$Path\*" -Destination $tempModulePathForFormatVersion -Force -Recurse -Confirm:$false -WhatIf:$false try { $manifestPath = Join-PathUtility -Path $tempModulePathForFormatVersion -ChildPath "$moduleName.psd1" -PathType File if(-not (Microsoft.PowerShell.Management\Test-Path $manifestPath)) { $message = $LocalizedData.InvalidModuleToPublish -f ($moduleName) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "InvalidModuleToPublish" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $moduleName } $ev = $null $moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath ` -ErrorVariable ev ` -Verbose:$VerbosePreference if($ev) { # Above Test-ModuleManifest cmdlet should write an errors to the Errors stream and Console. return } if(-not $moduleInfo -or -not $moduleInfo.Author -or -not $moduleInfo.Description) { $message = $LocalizedData.MissingRequiredManifestKeys -f ($moduleName) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "MissingRequiredModuleManifestKeys" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $moduleName } # Validate Prerelease string $moduleInfoPrerelease = $null if ($moduleInfo.PrivateData -and $moduleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable" -and $moduleInfo.PrivateData["PSData"] -and $moduleInfo.PrivateData.PSData.GetType().ToString() -eq "System.Collections.Hashtable" -and $moduleInfo.PrivateData.PSData["Prerelease"]) { $moduleInfoPrerelease = $moduleInfo.PrivateData.PSData.Prerelease } $result = ValidateAndGet-VersionPrereleaseStrings -Version $moduleInfo.Version -Prerelease $moduleInfoPrerelease -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $moduleInfoVersion = $result["Version"] $moduleInfoPrerelease = $result["Prerelease"] $moduleInfoFullVersion = $result["FullVersion"] $FindParameters = @{ Name = $moduleName Repository = $Repository Tag = 'PSScript' AllowPrerelease = $true Verbose = $VerbosePreference ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' Debug = $DebugPreference } if($Credential) { $FindParameters[$script:Credential] = $Credential } # Check if the specified module name is already used for a script on the specified repository # Use Find-Script to check if that name is already used as scriptname $scriptPSGetItemInfo = Find-Script @FindParameters | Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleName} | Microsoft.PowerShell.Utility\Select-Object -Last 1 -ErrorAction Ignore if($scriptPSGetItemInfo) { $message = $LocalizedData.SpecifiedNameIsAlearyUsed -f ($moduleName, $Repository, 'Find-Script') ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "SpecifiedNameIsAlearyUsed" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $moduleName } $null = $FindParameters.Remove('Tag') $currentPSGetItemInfo = Find-Module @FindParameters | Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $moduleInfo.Name} | Microsoft.PowerShell.Utility\Select-Object -Last 1 -ErrorAction Ignore if($currentPSGetItemInfo) { $result = ValidateAndGet-VersionPrereleaseStrings -Version $currentPSGetItemInfo.Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $currentPSGetItemVersion = $result["Version"] $currentPSGetItemPrereleaseString = $result["Prerelease"] $currentPSGetItemFullVersion = $result["FullVersion"] if($currentPSGetItemVersion -eq $moduleInfoVersion) { # Compare Prerelease strings if (-not $currentPSGetItemPrereleaseString -and -not $moduleInfoPrerelease) { $message = $LocalizedData.ModuleVersionIsAlreadyAvailableInTheGallery -f ($moduleInfo.Name, $moduleInfoFullVersion, $currentPSGetItemFullVersion, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'ModuleVersionIsAlreadyAvailableInTheGallery' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } elseif (-not $Force -and (-not $currentPSGetItemPrereleaseString -and $moduleInfoPrerelease)) { # User is trying to publish a new Prerelease version AFTER publishing the stable version. $message = $LocalizedData.ModuleVersionShouldBeGreaterThanGalleryVersion -f ($moduleInfo.Name, $moduleInfoFullVersion, $currentPSGetItemFullVersion, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "ModuleVersionShouldBeGreaterThanGalleryVersion" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } # elseif ($currentPSGetItemPrereleaseString -and -not $moduleInfoPrerelease) --> allow publish # User is attempting to publish a stable version after publishing a Prerelease version (allowed). elseif ($currentPSGetItemPrereleaseString -and $moduleInfoPrerelease) { if ($currentPSGetItemPrereleaseString -eq $moduleInfoPrerelease) { $message = $LocalizedData.ModuleVersionIsAlreadyAvailableInTheGallery -f ($moduleInfo.Name, $moduleInfoFullVersion, $currentPSGetItemFullVersion, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'ModuleVersionIsAlreadyAvailableInTheGallery' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } elseif (-not $Force -and ($currentPSGetItemPrereleaseString -gt $moduleInfoPrerelease)) { $message = $LocalizedData.ModuleVersionShouldBeGreaterThanGalleryVersion -f ($moduleInfo.Name, $moduleInfoFullVersion, $currentPSGetItemFullVersion, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "ModuleVersionShouldBeGreaterThanGalleryVersion" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } # elseif ($currentPSGetItemPrereleaseString -lt $moduleInfoPrerelease) --> allow publish } } elseif(-not $Force -and ($currentPSGetItemVersion -gt $moduleInfoVersion)) { $message = $LocalizedData.ModuleVersionShouldBeGreaterThanGalleryVersion -f ($moduleInfo.Name, $moduleInfoVersion, $currentPSGetItemFullVersion, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "ModuleVersionShouldBeGreaterThanGalleryVersion" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } # else ($currentPSGetItemVersion -lt $moduleInfoVersion) --> allow publish } $shouldProcessMessage = $LocalizedData.PublishModulewhatIfMessage -f ($moduleInfo.Version, $moduleInfo.Name) if($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Module")) { $PublishPSArtifactUtility_Params = @{ PSModuleInfo=$moduleInfo ManifestPath=$manifestPath NugetApiKey=$NuGetApiKey Destination=$DestinationLocation Repository=$Repository NugetPackageRoot=$tempModulePath FormatVersion=$FormatVersion ReleaseNotes=$($ReleaseNotes -join "`r`n") Tags=$Tags LicenseUri=$LicenseUri IconUri=$IconUri ProjectUri=$ProjectUri Verbose=$VerbosePreference WarningAction=$WarningPreference ErrorAction=$ErrorActionPreference Debug=$DebugPreference } if ($PSBoundParameters.Containskey('Credential')) { $PublishPSArtifactUtility_Params.Add('Credential',$Credential) } Publish-PSArtifactUtility @PublishPSArtifactUtility_Params } } finally { Microsoft.PowerShell.Management\Remove-Item $tempModulePath -Force -Recurse -ErrorAction Ignore -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } } } function Find-Module { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri='https://go.microsoft.com/fwlink/?LinkID=398574')] [outputtype("PSCustomObject[]")] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $RequiredVersion, [Parameter()] [switch] $AllVersions, [Parameter()] [switch] $IncludeDependencies, [Parameter()] [ValidateNotNull()] [string] $Filter, [Parameter()] [ValidateNotNull()] [string[]] $Tag, [Parameter()] [ValidateNotNull()] [ValidateSet('DscResource','Cmdlet','Function','RoleCapability')] [string[]] $Includes, [Parameter()] [ValidateNotNull()] [string[]] $DscResource, [Parameter()] [ValidateNotNull()] [string[]] $RoleCapability, [Parameter()] [ValidateNotNull()] [string[]] $Command, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Repository, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [switch] $AllowPrerelease ) Begin { Get-PSGalleryApiAvailability -Repository $Repository Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential } Process { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllVersions:$AllVersions ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule $null = $PSBoundParameters.Remove("AllowPrerelease") if($PSBoundParameters.ContainsKey("Repository")) { $PSBoundParameters["Source"] = $Repository $null = $PSBoundParameters.Remove("Repository") $ev = $null $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false if($ev) { return } } $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock $modulesFoundInPSGallery = @() # No Telemetry must be performed if PSGallery is not in the supplied list of Repositories $isRepositoryNullOrPSGallerySpecified = $false if ($Repository -and ($Repository -Contains $Script:PSGalleryModuleSource)) { $isRepositoryNullOrPSGallerySpecified = $true } elseif(-not $Repository) { $psgalleryRepo = Get-PSRepository -Name $Script:PSGalleryModuleSource ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if($psgalleryRepo) { $isRepositoryNullOrPSGallerySpecified = $true } } PackageManagement\Find-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { $psgetItemInfo = New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule if ($AllVersions -and -not $AllowPrerelease) { # If AllVersions is specified but not AllowPrerelease, we should only return stable release versions. # PackageManagement returns ALL versions (including prerelease) when AllVersions is specified, regardless of the value of AllowPrerelease. # Filtering results returned from PackageManagement based on flags. if ($psgetItemInfo.AdditionalMetadata -and $psgetItemInfo.AdditionalMetadata.IsPrerelease -eq 'false') { $psgetItemInfo } } else { $psgetItemInfo } if ($psgetItemInfo -and $isRepositoryNullOrPSGallerySpecified -and $script:TelemetryEnabled -and ($psgetItemInfo.Repository -eq $Script:PSGalleryModuleSource)) { $modulesFoundInPSGallery += $psgetItemInfo.Name } } # Perform Telemetry if Repository is not supplied or Repository contains PSGallery # We are only interested in finding modules not in PSGallery if ($isRepositoryNullOrPSGallerySpecified) { Log-ArtifactNotFoundInPSGallery -SearchedName $Name -FoundName $modulesFoundInPSGallery -operationName 'PSGET_FIND_MODULE' } } } function Save-Module { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet', HelpUri='https://go.microsoft.com/fwlink/?LinkId=531351', SupportsShouldProcess=$true)] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='NameAndPathParameterSet')] [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='InputOjectAndPathParameterSet')] [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='InputOjectAndLiteralPathParameterSet')] [ValidateNotNull()] [PSCustomObject[]] $InputObject, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNullOrEmpty()] [string[]] $Repository, [Parameter(Mandatory=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndPathParameterSet')] [string] $Path, [Parameter(Mandatory=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [Parameter(Mandatory=$true, ParameterSetName='InputOjectAndLiteralPathParameterSet')] [string] $LiteralPath, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [switch] $Force, [Parameter(ParameterSetName='NameAndPathParameterSet')] [Parameter(ParameterSetName='NameAndLiteralPathParameterSet')] [switch] $AllowPrerelease, [Parameter()] [switch] $AcceptLicense ) Begin { Get-PSGalleryApiAvailability -Repository $Repository Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential # Module names already tried in the current pipeline for InputObject parameterset $moduleNamesInPipeline = @() } Process { $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementSaveModuleMessageResolverScriptBlock $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule $null = $PSBoundParameters.Remove("AllowPrerelease") # When -Force is specified, Path will be created if not available. if(-not $Force) { if($Path) { $destinationPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-path $destinationPath)) { $errorMessage = ($LocalizedData.PathNotFound -f $Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $Path ` -ErrorCategory InvalidArgument } $PSBoundParameters['Path'] = $destinationPath } else { $destinationPath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $destinationPath)) { $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $LiteralPath ` -ErrorCategory InvalidArgument } $PSBoundParameters['LiteralPath'] = $destinationPath } } if($Name) { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -TestWildcardsInName ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } if($PSBoundParameters.ContainsKey("Repository")) { $PSBoundParameters["Source"] = $Repository $null = $PSBoundParameters.Remove("Repository") $ev = $null $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false if($ev) { return } } $parameters = $PSBoundParameters $null = PackageManagement\Save-Package @PSBoundParameters } elseif($InputObject) {x $null = $PSBoundParameters.Remove("InputObject") foreach($inputValue in $InputObject) { if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -and ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` -ErrorId "InvalidInputObjectValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $inputValue } if( ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -or ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -or ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -or ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) { $psgetModuleInfo = $inputValue.PSGetModuleInfo } else { $psgetModuleInfo = $inputValue } # Skip the module name if it is already tried in the current pipeline if($moduleNamesInPipeline -contains $psgetModuleInfo.Name) { continue } $moduleNamesInPipeline += $psgetModuleInfo.Name if ($psgetModuleInfo.PowerShellGetFormatVersion -and ($script:SupportedPSGetFormatVersionMajors -notcontains $psgetModuleInfo.PowerShellGetFormatVersion.Major)) { $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgetModuleInfo.Name, $psgetModuleInfo.PowerShellGetFormatVersion, $psgetModuleInfo.Name) Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation continue } $PSBoundParameters["Name"] = $psgetModuleInfo.Name $PSBoundParameters["RequiredVersion"] = $psgetModuleInfo.Version $PSBoundParameters['Source'] = $psgetModuleInfo.Repository $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psgetModuleInfo) $null = PackageManagement\Save-Package @PSBoundParameters } } } } function Install-Module { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(DefaultParameterSetName='NameParameterSet', HelpUri='https://go.microsoft.com/fwlink/?LinkID=398573', SupportsShouldProcess=$true)] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='InputObject')] [ValidateNotNull()] [PSCustomObject[]] $InputObject, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [string[]] $Repository, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [ValidateSet("CurrentUser","AllUsers")] [string] $Scope = "AllUsers", [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter()] [switch] $AllowClobber, [Parameter()] [switch] $SkipPublisherCheck, [Parameter()] [switch] $Force, [Parameter(ParameterSetName='NameParameterSet')] [switch] $AllowPrerelease, [Parameter()] [switch] $AcceptLicense ) Begin { Get-PSGalleryApiAvailability -Repository $Repository if(-not (Test-RunningAsElevated) -and ($Scope -ne "CurrentUser")) { # Throw an error when Install-Module is used as a non-admin user and '-Scope CurrentUser' is not specified $message = $LocalizedData.InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential # Module names already tried in the current pipeline for InputObject parameterset $moduleNamesInPipeline = @() $YesToAll = $false $NoToAll = $false $SourceSGrantedTrust = @() $SourcesDeniedTrust = @() } Process { $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedPackage $PackageTarget = $LocalizedData.InstallModulewhatIfMessage $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementInstallModuleMessageResolverScriptBlock $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule $PSBoundParameters['Scope'] = $Scope $PSBoundParameters[$script:AllowPrereleaseVersions] = $AllowPrerelease $null = $PSBoundParameters.Remove("AllowPrerelease") if($PSCmdlet.ParameterSetName -eq "NameParameterSet") { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -TestWildcardsInName ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } if($PSBoundParameters.ContainsKey("Repository")) { $PSBoundParameters["Source"] = $Repository $null = $PSBoundParameters.Remove("Repository") $ev = $null $null = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false if($ev) { return } } $null = PackageManagement\Install-Package @PSBoundParameters } elseif($PSCmdlet.ParameterSetName -eq "InputObject") { $null = $PSBoundParameters.Remove("InputObject") foreach($inputValue in $InputObject) { if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -and ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -and ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` -ErrorId "InvalidInputObjectValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $inputValue } if( ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetDscResourceInfo") -or ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetCommandInfo") -or ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetCommandInfo") -or ($inputValue.PSTypeNames -contains "Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo") -or ($inputValue.PSTypeNames -contains "Deserialized.Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo")) { $psgetModuleInfo = $inputValue.PSGetModuleInfo } else { $psgetModuleInfo = $inputValue } # Skip the module name if it is already tried in the current pipeline if($moduleNamesInPipeline -contains $psgetModuleInfo.Name) { continue } $moduleNamesInPipeline += $psgetModuleInfo.Name if ($psgetModuleInfo.PowerShellGetFormatVersion -and ($script:SupportedPSGetFormatVersionMajors -notcontains $psgetModuleInfo.PowerShellGetFormatVersion.Major)) { $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgetModuleInfo.Name, $psgetModuleInfo.PowerShellGetFormatVersion, $psgetModuleInfo.Name) Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation continue } $PSBoundParameters["Name"] = $psgetModuleInfo.Name $PSBoundParameters["RequiredVersion"] = $psgetModuleInfo.Version $PSBoundParameters[$script:AllowPrereleaseVersions] = $psgetModuleInfo.AdditionalMetadata.IsPrerelease -eq "true" $PSBoundParameters['Source'] = $psgetModuleInfo.Repository $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psgetModuleInfo) #Check if module is already installed $InstalledModuleInfo = Test-ModuleInstalled -Name $psgetModuleInfo.Name -RequiredVersion $psgetModuleInfo.Version if(-not $Force -and $InstalledModuleInfo -ne $null) { $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase) Write-Verbose -Message $message } else { $source = $psgetModuleInfo.Repository $installationPolicy = (Get-PSRepository -Name $source).InstallationPolicy $ShouldProcessMessage = $PackageTarget -f ($psgetModuleInfo.Name, $psgetModuleInfo.Version) if($psCmdlet.ShouldProcess($ShouldProcessMessage)) { if($installationPolicy.Equals("Untrusted", [StringComparison]::OrdinalIgnoreCase)) { if(-not($YesToAll -or $NoToAll -or $SourceSGrantedTrust.Contains($source) -or $sourcesDeniedTrust.Contains($source) -or $Force)) { $message = $QueryInstallUntrustedPackage -f ($psgetModuleInfo.Name, $psgetModuleInfo.RepositorySourceLocation) if($PSVersionTable.PSVersion -ge '5.0.0') { $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted",$true, [ref]$YesToAll, [ref]$NoToAll) } else { $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted", [ref]$YesToAll, [ref]$NoToAll) } if($sourceTrusted) { $SourceSGrantedTrust+=$source } else { $SourcesDeniedTrust+=$source } } } if($installationPolicy.Equals("trusted", [StringComparison]::OrdinalIgnoreCase) -or $SourceSGrantedTrust.Contains($source) -or $YesToAll -or $Force) { $PSBoundParameters["Force"] = $true $null = PackageManagement\Install-Package @PSBoundParameters } } } } } } } function Update-Module { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(SupportsShouldProcess=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkID=398576')] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [String[]] $Name, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter()] [Switch] $Force, [Parameter()] [Switch] $AllowPrerelease, [Parameter()] [switch] $AcceptLicense ) Begin { Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential # Module names already tried in the current pipeline $moduleNamesInPipeline = @() } Process { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $GetPackageParameters = @{} $GetPackageParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule $GetPackageParameters["Provider"] = $script:PSModuleProviderName $GetPackageParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock $GetPackageParameters['ErrorAction'] = 'SilentlyContinue' $GetPackageParameters['WarningAction'] = 'SilentlyContinue' $PSBoundParameters[$script:AllowPrereleaseVersions] = $AllowPrerelease $null = $PSBoundParameters.Remove("AllowPrerelease") $PSGetItemInfos = @() if($Name) { foreach($moduleName in $Name) { $GetPackageParameters['Name'] = $moduleName $installedPackages = PackageManagement\Get-Package @GetPackageParameters if(-not $installedPackages -and -not (Test-WildcardPattern -Name $moduleName)) { $availableModules = Get-Module -ListAvailable $moduleName -Verbose:$false | Microsoft.PowerShell.Utility\Select-Object -Unique -ErrorAction Ignore if(-not $availableModules) { $message = $LocalizedData.ModuleNotInstalledOnThisMachine -f ($moduleName) Write-Error -Message $message -ErrorId 'ModuleNotInstalledOnThisMachine' -Category InvalidOperation -TargetObject $moduleName } else { $message = $LocalizedData.ModuleNotInstalledUsingPowerShellGet -f ($moduleName) Write-Error -Message $message -ErrorId 'ModuleNotInstalledUsingInstallModuleCmdlet' -Category InvalidOperation -TargetObject $moduleName } continue } $installedPackages | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} | Microsoft.PowerShell.Core\ForEach-Object { if(-not (Test-RunningAsElevated) -and $_.InstalledLocation.StartsWith($script:programFilesModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) { if(-not (Test-WildcardPattern -Name $moduleName)) { $message = $LocalizedData.AdminPrivilegesRequiredForUpdate -f ($_.Name, $_.InstalledLocation) Write-Error -Message $message -ErrorId "AdminPrivilegesAreRequiredForUpdate" -Category InvalidOperation -TargetObject $moduleName } continue } $PSGetItemInfos += $_ } } } else { $PSGetItemInfos = PackageManagement\Get-Package @GetPackageParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} | Microsoft.PowerShell.Core\Where-Object { (Test-RunningAsElevated) -or $_.InstalledLocation.StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase) } } $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule foreach($psgetItemInfo in $PSGetItemInfos) { # Skip the module name if it is already tried in the current pipeline if($moduleNamesInPipeline -contains $psgetItemInfo.Name) { continue } $moduleNamesInPipeline += $psgetItemInfo.Name $message = $LocalizedData.CheckingForModuleUpdate -f ($psgetItemInfo.Name) Write-Verbose -Message $message $providerName = Get-ProviderName -PSCustomObject $psgetItemInfo if(-not $providerName) { $providerName = $script:NuGetProviderName } $PSBoundParameters["MessageResolver"] = $script:PackageManagementUpdateModuleMessageResolverScriptBlock $PSBoundParameters["Name"] = $psgetItemInfo.Name $PSBoundParameters['Source'] = $psgetItemInfo.Repository Get-PSGalleryApiAvailability -Repository (Get-SourceName -Location $psgetItemInfo.RepositorySourceLocation) $PSBoundParameters["PackageManagementProvider"] = $providerName $PSBoundParameters["InstallUpdate"] = $true if($psgetItemInfo.InstalledLocation.ToString().StartsWith($script:MyDocumentsModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) { $PSBoundParameters["Scope"] = "CurrentUser" } else { $PSBoundParameters['Scope'] = 'AllUsers' } $sid = PackageManagement\Install-Package @PSBoundParameters } } } function Uninstall-Module { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(DefaultParameterSetName='NameParameterSet', SupportsShouldProcess=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkId=526864')] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=0, ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [String[]] $Name, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='InputObject')] [ValidateNotNull()] [PSCustomObject[]] $InputObject, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ParameterSetName='NameParameterSet')] [switch] $AllVersions, [Parameter()] [Switch] $Force, [Parameter(ParameterSetName='NameParameterSet')] [switch] $AllowPrerelease ) Process { $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementUnInstallModuleMessageResolverScriptBlock $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule if($PSCmdlet.ParameterSetName -eq "InputObject") { $null = $PSBoundParameters.Remove("InputObject") foreach($inputValue in $InputObject) { if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` -ErrorId "InvalidInputObjectValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $inputValue } $PSBoundParameters["Name"] = $inputValue.Name $PSBoundParameters["RequiredVersion"] = $inputValue.Version $null = PackageManagement\Uninstall-Package @PSBoundParameters } } else { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -TestWildcardsInName ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllVersions:$AllVersions ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $null = PackageManagement\Uninstall-Package @PSBoundParameters } } } function Get-InstalledModule { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri='https://go.microsoft.com/fwlink/?LinkId=526863')] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [String[]] $Name, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MaximumVersion, [Parameter()] [switch] $AllVersions, [Parameter()] [switch] $AllowPrerelease ) Process { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllVersions:$AllVersions ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeModule $PSBoundParameters[$script:AllowPrereleaseVersions] = $AllowPrerelease $null = $PSBoundParameters.Remove("AllowPrerelease") PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeModule} } } #endregion *-Module cmdlets #region Find-DscResource cmdlet function Find-DscResource { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri = 'https://go.microsoft.com/fwlink/?LinkId=517196')] [outputtype('PSCustomObject[]')] Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter()] [ValidateNotNullOrEmpty()] [string] $ModuleName, [Parameter()] [ValidateNotNull()] [string] $MinimumVersion, [Parameter()] [ValidateNotNull()] [string] $MaximumVersion, [Parameter()] [ValidateNotNull()] [string] $RequiredVersion, [Parameter()] [switch] $AllVersions, [Parameter()] [switch] $AllowPrerelease, [Parameter()] [ValidateNotNull()] [string[]] $Tag, [Parameter()] [ValidateNotNull()] [string] $Filter, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Repository ) Process { $PSBoundParameters['Includes'] = 'DscResource' if($PSBoundParameters.ContainsKey('Name')) { $PSBoundParameters['DscResource'] = $Name $null = $PSBoundParameters.Remove('Name') } if($PSBoundParameters.ContainsKey('ModuleName')) { $PSBoundParameters['Name'] = $ModuleName $null = $PSBoundParameters.Remove('ModuleName') } PowerShellGet\Find-Module @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { $psgetModuleInfo = $_ $psgetModuleInfo.Includes.DscResource | Microsoft.PowerShell.Core\ForEach-Object { if($Name -and ($Name -notcontains $_)) { return } $psgetDscResourceInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $_ Version = $psgetModuleInfo.Version ModuleName = $psgetModuleInfo.Name Repository = $psgetModuleInfo.Repository PSGetModuleInfo = $psgetModuleInfo }) $psgetDscResourceInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetDscResourceInfo') $psgetDscResourceInfo } } } } #endregion Find-DscResource cmdlet #region Find-Command cmdlet function Find-Command { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri = 'https://go.microsoft.com/fwlink/?LinkId=733636')] [outputtype('PSCustomObject[]')] Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter()] [ValidateNotNullOrEmpty()] [string] $ModuleName, [Parameter()] [ValidateNotNull()] [string] $MinimumVersion, [Parameter()] [ValidateNotNull()] [string] $MaximumVersion, [Parameter()] [ValidateNotNull()] [string] $RequiredVersion, [Parameter()] [switch] $AllVersions, [Parameter()] [switch] $AllowPrerelease, [Parameter()] [ValidateNotNull()] [string[]] $Tag, [Parameter()] [ValidateNotNull()] [string] $Filter, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Repository ) Process { if($PSBoundParameters.ContainsKey('Name')) { $PSBoundParameters['Command'] = $Name $null = $PSBoundParameters.Remove('Name') } else { $PSBoundParameters['Includes'] = @('Cmdlet','Function') } if($PSBoundParameters.ContainsKey('ModuleName')) { $PSBoundParameters['Name'] = $ModuleName $null = $PSBoundParameters.Remove('ModuleName') } PowerShellGet\Find-Module @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { $psgetModuleInfo = $_ $psgetModuleInfo.Includes.Command | Microsoft.PowerShell.Core\ForEach-Object { if(($_ -eq "*") -or ($Name -and ($Name -notcontains $_))) { return } $psgetCommandInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $_ Version = $psgetModuleInfo.Version ModuleName = $psgetModuleInfo.Name Repository = $psgetModuleInfo.Repository PSGetModuleInfo = $psgetModuleInfo }) $psgetCommandInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetCommandInfo') $psgetCommandInfo } } } } #endregion Find-Command cmdlet #region Find-RoleCapability cmdlet function Find-RoleCapability { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri = 'https://go.microsoft.com/fwlink/?LinkId=718029')] [outputtype('PSCustomObject[]')] Param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter()] [ValidateNotNullOrEmpty()] [string] $ModuleName, [Parameter()] [ValidateNotNull()] [string] $MinimumVersion, [Parameter()] [ValidateNotNull()] [string] $MaximumVersion, [Parameter()] [ValidateNotNull()] [string] $RequiredVersion, [Parameter()] [switch] $AllVersions, [Parameter()] [switch] $AllowPrerelease, [Parameter()] [ValidateNotNull()] [string[]] $Tag, [Parameter()] [ValidateNotNull()] [string] $Filter, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Repository ) Process { $PSBoundParameters['Includes'] = 'RoleCapability' if($PSBoundParameters.ContainsKey('Name')) { $PSBoundParameters['RoleCapability'] = $Name $null = $PSBoundParameters.Remove('Name') } if($PSBoundParameters.ContainsKey('ModuleName')) { $PSBoundParameters['Name'] = $ModuleName $null = $PSBoundParameters.Remove('ModuleName') } PowerShellGet\Find-Module @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { $psgetModuleInfo = $_ $psgetModuleInfo.Includes.RoleCapability | Microsoft.PowerShell.Core\ForEach-Object { if($Name -and ($Name -notcontains $_)) { return } $psgetRoleCapabilityInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $_ Version = $psgetModuleInfo.Version ModuleName = $psgetModuleInfo.Name Repository = $psgetModuleInfo.Repository PSGetModuleInfo = $psgetModuleInfo }) $psgetRoleCapabilityInfo.PSTypeNames.Insert(0, 'Microsoft.PowerShell.Commands.PSGetRoleCapabilityInfo') $psgetRoleCapabilityInfo } } } } #endregion Find-RoleCapability cmdlet #region *-Script cmdlets function Publish-Script { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(SupportsShouldProcess=$true, PositionalBinding=$false, DefaultParameterSetName='PathParameterSet', HelpUri='https://go.microsoft.com/fwlink/?LinkId=619788')] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='PathParameterSet')] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='LiteralPathParameterSet')] [ValidateNotNullOrEmpty()] [string] $LiteralPath, [Parameter()] [ValidateNotNullOrEmpty()] [string] $NuGetApiKey, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Repository = $Script:PSGalleryModuleSource, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [switch] $Force ) Begin { Get-PSGalleryApiAvailability -Repository $Repository Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe -Force:$Force } Process { $scriptFilePath = $null if($Path) { $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) { $errorMessage = ($LocalizedData.PathNotFound -f $Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $Path ` -ErrorCategory InvalidArgument } } else { $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) { $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $LiteralPath ` -ErrorCategory InvalidArgument } } if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) { $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "InvalidScriptFilePath" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $scriptFilePath ` -ErrorCategory InvalidArgument return } if($Repository -eq $Script:PSGalleryModuleSource) { $repo = Get-PSRepository -Name $Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue if(-not $repo) { $message = $LocalizedData.PSGalleryNotFound -f ($Repository) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'PSGalleryNotFound' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Repository return } } else { $ev = $null $repo = Get-PSRepository -Name $Repository -ErrorVariable ev # Checking for the $repo object as well as terminating errors are not captured into ev on downlevel PowerShell versions. if($ev -or (-not $repo)) { return } } $DestinationLocation = $null if(Get-Member -InputObject $repo -Name $script:ScriptPublishLocation) { $DestinationLocation = $repo.ScriptPublishLocation } if(-not $DestinationLocation -or (-not (Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) -and -not (Test-WebUri -uri $DestinationLocation))) { $message = $LocalizedData.PSRepositoryScriptPublishLocationIsMissing -f ($Repository, $Repository) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PSRepositoryScriptPublishLocationIsMissing" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Repository } $message = $LocalizedData.PublishLocation -f ($DestinationLocation) Write-Verbose -Message $message if(-not $NuGetApiKey.Trim()) { if(Microsoft.PowerShell.Management\Test-Path -Path $DestinationLocation) { $NuGetApiKey = "$(Get-Random)" } else { $message = $LocalizedData.NuGetApiKeyIsRequiredForNuGetBasedGalleryService -f ($Repository, $DestinationLocation) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "NuGetApiKeyIsRequiredForNuGetBasedGalleryService" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } } $providerName = Get-ProviderName -PSCustomObject $repo if($providerName -ne $script:NuGetProviderName) { $message = $LocalizedData.PublishScriptSupportsOnlyNuGetBasedPublishLocations -f ($DestinationLocation, $Repository, $Repository) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PublishScriptSupportsOnlyNuGetBasedPublishLocations" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Repository } if($Path) { $PSScriptInfo = Test-ScriptFileInfo -Path $scriptFilePath } else { $PSScriptInfo = Test-ScriptFileInfo -LiteralPath $scriptFilePath } if(-not $PSScriptInfo) { # Test-ScriptFileInfo throws the actual error return } $scriptName = $PSScriptInfo.Name $result = ValidateAndGet-VersionPrereleaseStrings -Version $PSScriptInfo.Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $scriptVersion = $result["Version"] $scriptPrerelease = $result["Prerelease"] $scriptFullVersion = $result["FullVersion"] # Copy the source script file to temp location to publish $tempScriptPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath "$(Get-Random)" | Microsoft.PowerShell.Management\Join-Path -ChildPath $scriptName $null = Microsoft.PowerShell.Management\New-Item -Path $tempScriptPath -ItemType Directory -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false if($Path) { Microsoft.PowerShell.Management\Copy-Item -Path $scriptFilePath -Destination $tempScriptPath -Force -Recurse -Confirm:$false -WhatIf:$false } else { Microsoft.PowerShell.Management\Copy-Item -LiteralPath $scriptFilePath -Destination $tempScriptPath -Force -Recurse -Confirm:$false -WhatIf:$false } try { $FindParameters = @{ Name = $scriptName Repository = $Repository Tag = 'PSModule' AllowPrerelease = $true Verbose = $VerbosePreference ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' Debug = $DebugPreference } if($Credential) { $FindParameters[$script:Credential] = $Credential } # Check if the specified script name is already used for a module on the specified repository # Use Find-Module to check if that name is already used as module name $modulePSGetItemInfo = Find-Module @FindParameters | Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} | Microsoft.PowerShell.Utility\Select-Object -Last 1 -ErrorAction Ignore if($modulePSGetItemInfo) { $message = $LocalizedData.SpecifiedNameIsAlearyUsed -f ($scriptName, $Repository, 'Find-Module') ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "SpecifiedNameIsAlearyUsed" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $scriptName } $null = $FindParameters.Remove('Tag') $currentPSGetItemInfo = $null $currentPSGetItemInfo = Find-Script @FindParameters | Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} | Microsoft.PowerShell.Utility\Select-Object -Last 1 -ErrorAction Ignore if($currentPSGetItemInfo) { $result = ValidateAndGet-VersionPrereleaseStrings -Version $currentPSGetItemInfo.Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $galleryScriptVersion = $result["Version"] $galleryScriptPrerelease = $result["Prerelease"] $galleryScriptFullVersion = $result["FullVersion"] if($galleryScriptFullVersion -eq $scriptFullVersion) { $message = $LocalizedData.ScriptVersionIsAlreadyAvailableInTheGallery -f ($scriptName, $scriptFullVersion, $galleryScriptFullVersion, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId 'ScriptVersionIsAlreadyAvailableInTheGallery' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } if ($galleryScriptVersion -eq $scriptVersion -and -not $Force) { # Prerelease strings will not both be null, otherwise would have terminated already above if (-not $Force -and (-not $galleryScriptPrerelease -and $scriptPrerelease)) { # User is trying to publish a new Prerelease version AFTER publishing the stable version. $message = $LocalizedData.ScriptPrereleaseStringShouldBeGreaterThanGalleryPrereleaseString -f ($scriptName, $scriptVersion, $scriptPrerelease, $galleryScriptPrerelease, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "ScriptPrereleaseStringShouldBeGreaterThanGalleryPrereleaseString" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } # elseif ($galleryScriptPrerelease -and -not $scriptPrerelease) --> allow publish # User is attempting to publish a stable version after publishing a prerelease version (allowed). elseif($galleryScriptPrerelease -and $scriptPrerelease) { # if ($galleryScriptPrerelease -eq $scriptPrerelease) --> not reachable, would have terminated already above. if (-not $Force -and ($galleryScriptPrerelease -gt $scriptPrerelease)) { # User is trying to publish a lower prerelease version. $message = $LocalizedData.ScriptPrereleaseStringShouldBeGreaterThanGalleryPrereleaseString -f ($scriptName, $scriptVersion, $scriptPrerelease, $galleryScriptPrerelease, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "ScriptPrereleaseStringShouldBeGreaterThanGalleryPrereleaseString" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } # elseif ($galleryScriptPrerelease -lt $scriptPrerelease) --> allow publish # User is trying to publish a newer prerelease version (allowed) } } elseif (-not $Force -and ($galleryScriptVersion -gt $scriptVersion)) { $message = $LocalizedData.ScriptVersionShouldBeGreaterThanGalleryVersion -f ($scriptName, $scriptVersion, $galleryScriptVersion, $currentPSGetItemInfo.RepositorySourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "ScriptVersionShouldBeGreaterThanGalleryVersion" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } # else ($galleryScriptVersion -lt $scriptVersion) --> allow publish # User is trying to publish a newer stable version (allowed) } $shouldProcessMessage = $LocalizedData.PublishScriptwhatIfMessage -f ($PSScriptInfo.Version, $scriptName) if($Force -or $PSCmdlet.ShouldProcess($shouldProcessMessage, "Publish-Script")) { $PublishPSArtifactUtility_Params = @{ PSScriptInfo=$PSScriptInfo NugetApiKey=$NuGetApiKey Destination=$DestinationLocation Repository=$Repository NugetPackageRoot=$tempScriptPath Verbose=$VerbosePreference WarningAction=$WarningPreference ErrorAction=$ErrorActionPreference Debug=$DebugPreference } if ($PSBoundParameters.ContainsKey('Credential')) { $PublishPSArtifactUtility_Params.Add('Credential',$Credential) } Publish-PSArtifactUtility @PublishPSArtifactUtility_Params } } finally { Microsoft.PowerShell.Management\Remove-Item $tempScriptPath -Force -Recurse -ErrorAction Ignore -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } } } function Find-Script { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri='https://go.microsoft.com/fwlink/?LinkId=619785')] [outputtype("PSCustomObject[]")] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $RequiredVersion, [Parameter()] [switch] $AllVersions, [Parameter()] [switch] $IncludeDependencies, [Parameter()] [ValidateNotNull()] [string] $Filter, [Parameter()] [ValidateNotNull()] [string[]] $Tag, [Parameter()] [ValidateNotNull()] [ValidateSet('Function','Workflow')] [string[]] $Includes, [Parameter()] [ValidateNotNull()] [string[]] $Command, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Repository, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [switch] $AllowPrerelease ) Begin { Get-PSGalleryApiAvailability -Repository $Repository Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential } Process { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllVersions:$AllVersions ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $PSBoundParameters['Provider'] = $script:PSModuleProviderName $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript $null = $PSBoundParameters.Remove("AllowPrerelease") if($PSBoundParameters.ContainsKey("Repository")) { $PSBoundParameters["Source"] = $Repository $null = $PSBoundParameters.Remove("Repository") $ev = $null $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false if($ev) { return } $RepositoriesWithoutScriptSourceLocation = $false foreach($repo in $repositories) { if(-not $repo.ScriptSourceLocation) { $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) Write-Error -Message $message ` -ErrorId 'ScriptSourceLocationIsMissing' ` -Category InvalidArgument ` -TargetObject $repo.Name ` -Exception 'System.ArgumentException' $RepositoriesWithoutScriptSourceLocation = $true } } if($RepositoriesWithoutScriptSourceLocation) { return } } $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets $scriptsFoundInPSGallery = @() # No Telemetry must be performed if PSGallery is not in the supplied list of Repositories $isRepositoryNullOrPSGallerySpecified = $false if ($Repository -and ($Repository -Contains $Script:PSGalleryModuleSource)) { $isRepositoryNullOrPSGallerySpecified = $true } elseif(-not $Repository) { $psgalleryRepo = Get-PSRepository -Name $Script:PSGalleryModuleSource ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue # And check for IsDefault? if($psgalleryRepo) { $isRepositoryNullOrPSGallerySpecified = $true } } PackageManagement\Find-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object { $psgetItemInfo = New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeScript if ($AllVersions -and -not $AllowPrerelease) { # If AllVersions is specified but not AllowPrerelease, we should only return stable release versions. # PackageManagement returns ALL versions (including prerelease) when AllVersions is specified, regardless of the value of AllowPrerelease. # Filtering results returned from PackageManagement based on flags. if ($psgetItemInfo.AdditionalMetadata -and $psgetItemInfo.AdditionalMetadata.IsPrerelease -eq $false) { $psgetItemInfo } } else { $psgetItemInfo } if ($psgetItemInfo -and $isRepositoryNullOrPSGallerySpecified -and $script:TelemetryEnabled -and ($psgetItemInfo.Repository -eq $Script:PSGalleryModuleSource)) { $scriptsFoundInPSGallery += $psgetItemInfo.Name } } # Perform Telemetry if Repository is not supplied or Repository contains PSGallery # We are only interested in finding artifacts not in PSGallery if ($isRepositoryNullOrPSGallerySpecified) { Log-ArtifactNotFoundInPSGallery -SearchedName $Name -FoundName $scriptsFoundInPSGallery -operationName PSGET_FIND_SCRIPT } } } function Save-Script { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(DefaultParameterSetName='NameAndPathParameterSet', HelpUri='https://go.microsoft.com/fwlink/?LinkId=619786', SupportsShouldProcess=$true)] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='NameAndPathParameterSet')] [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='InputOjectAndPathParameterSet')] [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='InputOjectAndLiteralPathParameterSet')] [ValidateNotNull()] [PSCustomObject[]] $InputObject, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [ValidateNotNullOrEmpty()] [string[]] $Repository, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndPathParameterSet')] [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='InputOjectAndPathParameterSet')] [string] $Path, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='NameAndLiteralPathParameterSet')] [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='InputOjectAndLiteralPathParameterSet')] [string] $LiteralPath, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [switch] $Force, [Parameter(ParameterSetName='NameAndPathParameterSet')] [Parameter(ParameterSetName='NameAndLiteralPathParameterSet')] [switch] $AllowPrerelease, [Parameter()] [switch] $AcceptLicense ) Begin { Get-PSGalleryApiAvailability -Repository $Repository Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential # Script names already tried in the current pipeline for InputObject parameterset $scriptNamesInPipeline = @() } Process { $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementSaveScriptMessageResolverScriptBlock $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript $PSBoundParameters[$script:AllowPrereleaseVersions] = $AllowPrerelease $null = $PSBoundParameters.Remove("AllowPrerelease") # When -Force is specified, Path will be created if not available. if(-not $Force) { if($Path) { $destinationPath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-path $destinationPath)) { $errorMessage = ($LocalizedData.PathNotFound -f $Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $Path ` -ErrorCategory InvalidArgument } $PSBoundParameters['Path'] = $destinationPath } else { $destinationPath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $destinationPath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $destinationPath)) { $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $LiteralPath ` -ErrorCategory InvalidArgument } $PSBoundParameters['LiteralPath'] = $destinationPath } } if($Name) { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -TestWildcardsInName ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } if($PSBoundParameters.ContainsKey("Repository")) { $PSBoundParameters["Source"] = $Repository $null = $PSBoundParameters.Remove("Repository") $ev = $null $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false if($ev) { return } $RepositoriesWithoutScriptSourceLocation = $false foreach($repo in $repositories) { if(-not $repo.ScriptSourceLocation) { $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) Write-Error -Message $message ` -ErrorId 'ScriptSourceLocationIsMissing' ` -Category InvalidArgument ` -TargetObject $repo.Name ` -Exception 'System.ArgumentException' $RepositoriesWithoutScriptSourceLocation = $true } } if($RepositoriesWithoutScriptSourceLocation) { return } } $null = PackageManagement\Save-Package @PSBoundParameters } elseif($InputObject) { $null = $PSBoundParameters.Remove("InputObject") foreach($inputValue in $InputObject) { if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` -ErrorId "InvalidInputObjectValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $inputValue } $psRepositoryItemInfo = $inputValue # Skip the script name if it is already tried in the current pipeline if($scriptNamesInPipeline -contains $psRepositoryItemInfo.Name) { continue } $scriptNamesInPipeline += $psRepositoryItemInfo.Name if ($psRepositoryItemInfo.PowerShellGetFormatVersion -and ($script:SupportedPSGetFormatVersionMajors -notcontains $psRepositoryItemInfo.PowerShellGetFormatVersion.Major)) { $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.PowerShellGetFormatVersion, $psRepositoryItemInfo.Name) Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation continue } $PSBoundParameters["Name"] = $psRepositoryItemInfo.Name $PSBoundParameters["RequiredVersion"] = $psRepositoryItemInfo.Version $PSBoundParameters['Source'] = $psRepositoryItemInfo.Repository $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psRepositoryItemInfo) $null = PackageManagement\Save-Package @PSBoundParameters } } } } function Install-Script { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(DefaultParameterSetName='NameParameterSet', HelpUri='https://go.microsoft.com/fwlink/?LinkId=619784', SupportsShouldProcess=$true)] Param ( [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [string[]] $Name, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='InputObject')] [ValidateNotNull()] [PSCustomObject[]] $InputObject, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [string[]] $Repository, [Parameter()] [ValidateSet("CurrentUser","AllUsers")] [string] $Scope = 'AllUsers', [Parameter()] [Switch] $NoPathUpdate, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [switch] $Force, [Parameter(ParameterSetName='NameParameterSet')] [switch] $AllowPrerelease, [Parameter()] [switch] $AcceptLicense ) Begin { Get-PSGalleryApiAvailability -Repository $Repository if(-not (Test-RunningAsElevated) -and ($Scope -ne "CurrentUser")) { # Throw an error when Install-Script is used as a non-admin user and '-Scope CurrentUser' is not specified $AdminPrivilegeErrorMessage = $LocalizedData.InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) $AdminPrivilegeErrorId = 'InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser' ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $AdminPrivilegeErrorMessage ` -ErrorId $AdminPrivilegeErrorId ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } # Check and add the scope path to PATH environment variable if($Scope -eq 'AllUsers') { $scopePath = $script:ProgramFilesScriptsPath } else { $scopePath = $script:MyDocumentsScriptsPath } ValidateAndSet-PATHVariableIfUserAccepts -Scope $Scope ` -ScopePath $scopePath ` -NoPathUpdate:$NoPathUpdate ` -Force:$Force Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential # Script names already tried in the current pipeline for InputObject parameterset $scriptNamesInPipeline = @() $YesToAll = $false $NoToAll = $false $SourceSGrantedTrust = @() $SourcesDeniedTrust = @() } Process { $RepositoryIsNotTrusted = $LocalizedData.RepositoryIsNotTrusted $QueryInstallUntrustedPackage = $LocalizedData.QueryInstallUntrustedScriptPackage $PackageTarget = $LocalizedData.InstallScriptwhatIfMessage $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementInstallScriptMessageResolverScriptBlock $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript $PSBoundParameters['Scope'] = $Scope $PSBoundParameters[$script:AllowPrereleaseVersions] = $AllowPrerelease $null = $PSBoundParameters.Remove("AllowPrerelease") if($PSCmdlet.ParameterSetName -eq "NameParameterSet") { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -TestWildcardsInName ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } if($PSBoundParameters.ContainsKey("Repository")) { $PSBoundParameters["Source"] = $Repository $null = $PSBoundParameters.Remove("Repository") $ev = $null $repositories = Get-PSRepository -Name $Repository -ErrorVariable ev -verbose:$false if($ev) { return } $RepositoriesWithoutScriptSourceLocation = $false foreach($repo in $repositories) { if(-not $repo.ScriptSourceLocation) { $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($repo.Name) Write-Error -Message $message ` -ErrorId 'ScriptSourceLocationIsMissing' ` -Category InvalidArgument ` -TargetObject $repo.Name ` -Exception 'System.ArgumentException' $RepositoriesWithoutScriptSourceLocation = $true } } if($RepositoriesWithoutScriptSourceLocation) { return } } if(-not $Force) { foreach($scriptName in $Name) { # Throw an error if there is a command with the same name and -force is not specified. $cmd = Microsoft.PowerShell.Core\Get-Command -Name $scriptName ` -ErrorAction Ignore ` -WarningAction SilentlyContinue if($cmd) { # Check if this script was already installed, may be with -Force $InstalledScriptInfo = Test-ScriptInstalled -Name $scriptName ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if(-not $InstalledScriptInfo) { $message = $LocalizedData.CommandAlreadyAvailable -f ($scriptName) Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation # return if only single name is specified if($scriptName -eq $Name) { return } } } } } $null = PackageManagement\Install-Package @PSBoundParameters } elseif($PSCmdlet.ParameterSetName -eq "InputObject") { $null = $PSBoundParameters.Remove("InputObject") foreach($inputValue in $InputObject) { if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` -ErrorId "InvalidInputObjectValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $inputValue } $psRepositoryItemInfo = $inputValue # Skip the script name if it is already tried in the current pipeline if($scriptNamesInPipeline -contains $psRepositoryItemInfo.Name) { continue } $scriptNamesInPipeline += $psRepositoryItemInfo.Name if ($psRepositoryItemInfo.PowerShellGetFormatVersion -and ($script:SupportedPSGetFormatVersionMajors -notcontains $psRepositoryItemInfo.PowerShellGetFormatVersion.Major)) { $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.PowerShellGetFormatVersion, $psRepositoryItemInfo.Name) Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation continue } $PSBoundParameters["Name"] = $psRepositoryItemInfo.Name $PSBoundParameters["RequiredVersion"] = $psRepositoryItemInfo.Version $PSBoundParameters['Source'] = $psRepositoryItemInfo.Repository $PSBoundParameters["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $psRepositoryItemInfo) $InstalledScriptInfo = Test-ScriptInstalled -Name $psRepositoryItemInfo.Name if(-not $Force -and $InstalledScriptInfo) { $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptInfo.Version, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase) Write-Verbose -Message $message } else { # Throw an error if there is a command with the same name and -force is not specified. if(-not $Force) { $cmd = Microsoft.PowerShell.Core\Get-Command -Name $psRepositoryItemInfo.Name ` -ErrorAction Ignore ` -WarningAction SilentlyContinue if($cmd) { $message = $LocalizedData.CommandAlreadyAvailable -f ($psRepositoryItemInfo.Name) Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation continue } } $source = $psRepositoryItemInfo.Repository $installationPolicy = (Get-PSRepository -Name $source).InstallationPolicy $ShouldProcessMessage = $PackageTarget -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.Version) if($psCmdlet.ShouldProcess($ShouldProcessMessage)) { if($installationPolicy.Equals("Untrusted", [StringComparison]::OrdinalIgnoreCase)) { if(-not($YesToAll -or $NoToAll -or $SourceSGrantedTrust.Contains($source) -or $sourcesDeniedTrust.Contains($source) -or $Force)) { $message = $QueryInstallUntrustedPackage -f ($psRepositoryItemInfo.Name, $psRepositoryItemInfo.RepositorySourceLocation) if($PSVersionTable.PSVersion -ge '5.0.0') { $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted",$true, [ref]$YesToAll, [ref]$NoToAll) } else { $sourceTrusted = $psCmdlet.ShouldContinue("$message", "$RepositoryIsNotTrusted", [ref]$YesToAll, [ref]$NoToAll) } if($sourceTrusted) { $SourcesGrantedTrust+=$source } else { $SourcesDeniedTrust+=$source } } } } if($installationPolicy.Equals("trusted", [StringComparison]::OrdinalIgnoreCase) -or $SourcesGrantedTrust.Contains($source) -or $YesToAll -or $Force) { $PSBoundParameters["Force"] = $true $null = PackageManagement\Install-Package @PSBoundParameters } } } } } } function Update-Script { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(SupportsShouldProcess=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkId=619787')] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [String[]] $Name, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MaximumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [Switch] $Force, [Parameter()] [Switch] $AllowPrerelease, [Parameter()] [switch] $AcceptLicense ) Begin { Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential # Script names already tried in the current pipeline $scriptNamesInPipeline = @() } Process { $scriptFilePathsToUpdate = @() $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } if($Name) { foreach($scriptName in $Name) { $availableScriptPaths = Get-AvailableScriptFilePath -Name $scriptName -Verbose:$false if(-not $availableScriptPaths -and -not (Test-WildcardPattern -Name $scriptName)) { $message = $LocalizedData.ScriptNotInstalledOnThisMachine -f ($scriptName, $script:MyDocumentsScriptsPath, $script:ProgramFilesScriptsPath) Write-Error -Message $message -ErrorId "ScriptNotInstalledOnThisMachine" -Category InvalidOperation -TargetObject $scriptName continue } foreach($scriptFilePath in $availableScriptPaths) { $installedScriptFilePath = Get-InstalledScriptFilePath -Name ([System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath)) | Microsoft.PowerShell.Core\Where-Object {$_ -eq $scriptFilePath } # Check if this script got installed with PowerShellGet and user has required permissions if ($installedScriptFilePath) { if(-not (Test-RunningAsElevated) -and $installedScriptFilePath.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) { if(-not (Test-WildcardPattern -Name $scriptName)) { $message = $LocalizedData.AdminPrivilegesRequiredForScriptUpdate -f ($scriptName, $installedScriptFilePath) Write-Error -Message $message -ErrorId "AdminPrivilegesAreRequiredForUpdate" -Category InvalidOperation -TargetObject $scriptName } continue } $scriptFilePathsToUpdate += $installedScriptFilePath } else { if(-not (Test-WildcardPattern -Name $scriptName)) { $message = $LocalizedData.ScriptNotInstalledUsingPowerShellGet -f ($scriptName) Write-Error -Message $message -ErrorId "ScriptNotInstalledUsingPowerShellGet" -Category InvalidOperation -TargetObject $scriptName } continue } } } } else { $isRunningAsElevated = Test-RunningAsElevated $installedScriptFilePaths = Get-InstalledScriptFilePath if($isRunningAsElevated) { $scriptFilePathsToUpdate = $installedScriptFilePaths } else { # Update the scripts installed under $scriptFilePathsToUpdate = $installedScriptFilePaths | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)} } } $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript $PSBoundParameters["InstallUpdate"] = $true foreach($scriptFilePath in $scriptFilePathsToUpdate) { $scriptName = [System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath) $installedScriptInfoFilePath = $null $installedScriptInfoFileName = "$($scriptName)_$script:InstalledScriptInfoFileName" if($scriptFilePath.ToString().StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) { $PSBoundParameters["Scope"] = "CurrentUser" $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` -ChildPath $installedScriptInfoFileName } elseif($scriptFilePath.ToString().StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) { $PSBoundParameters["Scope"] = "AllUsers" $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` -ChildPath $installedScriptInfoFileName } $psgetItemInfo = $null if($installedScriptInfoFilePath -and (Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf)) { $psgetItemInfo = DeSerialize-PSObject -Path $installedScriptInfoFilePath } # Skip the script name if it is already tried in the current pipeline if(-not $psgetItemInfo -or ($scriptNamesInPipeline -contains $psgetItemInfo.Name)) { continue } $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $psgetItemInfo.InstalledLocation ` -ChildPath "$($psgetItemInfo.Name).ps1" # Remove the InstalledScriptInfo.xml file if the actual script file was manually uninstalled by the user if(-not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) { Microsoft.PowerShell.Management\Remove-Item -Path $installedScriptInfoFilePath -Force -ErrorAction SilentlyContinue continue } $scriptNamesInPipeline += $psgetItemInfo.Name $message = $LocalizedData.CheckingForScriptUpdate -f ($psgetItemInfo.Name) Write-Verbose -Message $message $providerName = Get-ProviderName -PSCustomObject $psgetItemInfo if(-not $providerName) { $providerName = $script:NuGetProviderName } $PSBoundParameters["MessageResolver"] = $script:PackageManagementUpdateScriptMessageResolverScriptBlock $PSBoundParameters["PackageManagementProvider"] = $providerName $PSBoundParameters["Name"] = $psgetItemInfo.Name $PSBoundParameters['Source'] = $psgetItemInfo.Repository $PSBoundParameters[$script:AllowPrereleaseVersions] = $AllowPrerelease $null = $PSBoundParameters.Remove("AllowPrerelease") Get-PSGalleryApiAvailability -Repository (Get-SourceName -Location $psgetItemInfo.RepositorySourceLocation) $sid = PackageManagement\Install-Package @PSBoundParameters } } } function Uninstall-Script { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(DefaultParameterSetName='NameParameterSet', SupportsShouldProcess=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkId=619789')] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=0, ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [String[]] $Name, [Parameter(Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0, ParameterSetName='InputObject')] [ValidateNotNull()] [PSCustomObject[]] $InputObject, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [ValidateNotNull()] [string] $MaximumVersion, [Parameter()] [Switch] $Force, [Parameter(ParameterSetName='NameParameterSet')] [Switch] $AllowPrerelease ) Process { $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementUnInstallScriptMessageResolverScriptBlock $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript $PSBoundParameters[$script:AllowPrereleaseVersions] = $AllowPrerelease $null = $PSBoundParameters.Remove("AllowPrerelease") if($PSCmdlet.ParameterSetName -eq "InputObject") { $null = $PSBoundParameters.Remove("InputObject") foreach($inputValue in $InputObject) { if (($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and ($inputValue.PSTypeNames -notcontains "Deserialized.Microsoft.PowerShell.Commands.PSRepositoryItemInfo")) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.InvalidInputObjectValue ` -ErrorId "InvalidInputObjectValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $inputValue } $PSBoundParameters["Name"] = $inputValue.Name $PSBoundParameters["RequiredVersion"] = $inputValue.Version $null = PackageManagement\Uninstall-Package @PSBoundParameters } } else { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -TestWildcardsInName ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $null = PackageManagement\Uninstall-Package @PSBoundParameters } } } function Get-InstalledScript { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri='https://go.microsoft.com/fwlink/?LinkId=619790')] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Position=0)] [ValidateNotNullOrEmpty()] [String[]] $Name, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MinimumVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $RequiredVersion, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNull()] [string] $MaximumVersion, [Parameter()] [Switch] $AllowPrerelease ) Process { $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet ` -Name $Name ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion ` -RequiredVersion $RequiredVersion ` -AllowPrerelease:$AllowPrerelease if(-not $ValidationResult) { # Validate-VersionParameters throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlockForScriptCmdlets $PSBoundParameters[$script:PSArtifactType] = $script:PSArtifactTypeScript $PSBoundParameters[$script:AllowPrereleaseVersions] = $AllowPrerelease $null = $PSBoundParameters.Remove("AllowPrerelease") PackageManagement\Get-Package @PSBoundParameters | Microsoft.PowerShell.Core\ForEach-Object {New-PSGetItemInfo -SoftwareIdentity $_ -Type $script:PSArtifactTypeScript} } } #endregion *-Script cmdlets #region *-PSRepository cmdlets function Register-PSRepository { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(DefaultParameterSetName='NameParameterSet', HelpUri='https://go.microsoft.com/fwlink/?LinkID=517129')] Param ( [Parameter(Mandatory=$true, Position=0, ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter(Mandatory=$true, Position=1, ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [Uri] $SourceLocation, [Parameter(ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [Uri] $PublishLocation, [Parameter(ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [Uri] $ScriptSourceLocation, [Parameter(ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [Uri] $ScriptPublishLocation, [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName='NameParameterSet')] [PSCredential] $Credential, [Parameter(Mandatory=$true, ParameterSetName='PSGalleryParameterSet')] [Switch] $Default, [Parameter()] [ValidateSet('Trusted','Untrusted')] [string] $InstallationPolicy = 'Untrusted', [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter(ParameterSetName='NameParameterSet')] [ValidateNotNullOrEmpty()] [string] $PackageManagementProvider ) DynamicParam { if (Get-Variable -Name SourceLocation -ErrorAction SilentlyContinue) { Set-Variable -Name selectedProviderName -value $null -Scope 1 if(Get-Variable -Name PackageManagementProvider -ErrorAction SilentlyContinue) { $selectedProviderName = $PackageManagementProvider $null = Get-DynamicParameters -Location $SourceLocation -PackageManagementProvider ([REF]$selectedProviderName) } else { $dynamicParameters = Get-DynamicParameters -Location $SourceLocation -PackageManagementProvider ([REF]$selectedProviderName) Set-Variable -Name PackageManagementProvider -Value $selectedProviderName -Scope 1 $null = $dynamicParameters } } } Begin { Get-PSGalleryApiAvailability -Repository $Name Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential if($PackageManagementProvider) { $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Name -ne $script:PSModuleProviderName -and $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } if (-not $providers -or $providers.Name -notcontains $PackageManagementProvider) { $possibleProviderNames = $script:NuGetProviderName if($providers) { $possibleProviderNames = ($providers.Name -join ',') } $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($PackageManagementProvider, $possibleProviderNames, $script:NuGetProviderName) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidPackageManagementProviderValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $PackageManagementProvider return } } } Process { if($PSCmdlet.ParameterSetName -eq 'PSGalleryParameterSet') { if(-not $Default) { return } $PSBoundParameters['Name'] = $Script:PSGalleryModuleSource $null = $PSBoundParameters.Remove('Default') } else { if($Name -eq $Script:PSGalleryModuleSource) { $message = $LocalizedData.UseDefaultParameterSetOnRegisterPSRepository ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'UseDefaultParameterSetOnRegisterPSRepository' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Name return } # Ping and resolve the specified location $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) ` -LocationParameterName 'SourceLocation' ` -Credential $Credential ` -Proxy $Proxy ` -ProxyCredential $ProxyCredential ` -CallerPSCmdlet $PSCmdlet if(-not $SourceLocation) { # Above Resolve-Location function throws an error when it is not able to resolve a location return } $providerName = $null if($PackageManagementProvider) { $providerName = $PackageManagementProvider } elseif($selectedProviderName) { $providerName = $selectedProviderName } else { $providerName = Get-PackageManagementProviderName -Location $SourceLocation } if($providerName) { $PSBoundParameters[$script:PackageManagementProviderParam] = $providerName } if($PublishLocation) { $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation } if($ScriptPublishLocation) { $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation } if($ScriptSourceLocation) { $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation } $PSBoundParameters["Location"] = Get-LocationString -LocationUri $SourceLocation $null = $PSBoundParameters.Remove("SourceLocation") } if($InstallationPolicy -eq "Trusted") { $PSBoundParameters['Trusted'] = $true } $null = $PSBoundParameters.Remove("InstallationPolicy") $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock $null = PackageManagement\Register-PackageSource @PSBoundParameters } } function Set-PSRepository { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(PositionalBinding=$false, HelpUri='https://go.microsoft.com/fwlink/?LinkID=517128')] Param ( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter(Position=1)] [ValidateNotNullOrEmpty()] [Uri] $SourceLocation, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $PublishLocation, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $ScriptSourceLocation, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $ScriptPublishLocation, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $Credential, [Parameter()] [ValidateSet('Trusted','Untrusted')] [string] $InstallationPolicy, [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [Uri] $Proxy, [Parameter(ValueFromPipelineByPropertyName=$true)] [PSCredential] $ProxyCredential, [Parameter()] [ValidateNotNullOrEmpty()] [string] $PackageManagementProvider ) DynamicParam { if (Get-Variable -Name Name -ErrorAction SilentlyContinue) { $moduleSource = Get-PSRepository -Name $Name -ErrorAction SilentlyContinue -WarningAction SilentlyContinue if($moduleSource) { $providerName = (Get-ProviderName -PSCustomObject $moduleSource) $loc = $moduleSource.SourceLocation if(Get-Variable -Name SourceLocation -ErrorAction SilentlyContinue) { $loc = $SourceLocation } if(Get-Variable -Name PackageManagementProvider -ErrorAction SilentlyContinue) { $providerName = $PackageManagementProvider } $null = Get-DynamicParameters -Location $loc -PackageManagementProvider ([REF]$providerName) } } } Begin { Get-PSGalleryApiAvailability -Repository $Name Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -Proxy $Proxy -ProxyCredential $ProxyCredential if($PackageManagementProvider) { $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Name -ne $script:PSModuleProviderName -and $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } if (-not $providers -or $providers.Name -notcontains $PackageManagementProvider) { $possibleProviderNames = $script:NuGetProviderName if($providers) { $possibleProviderNames = ($providers.Name -join ',') } $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($PackageManagementProvider, $possibleProviderNames, $script:NuGetProviderName) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidPackageManagementProviderValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $PackageManagementProvider return } } } Process { # Ping and resolve the specified location if($SourceLocation) { # Ping and resolve the specified location $SourceLocation = Resolve-Location -Location (Get-LocationString -LocationUri $SourceLocation) ` -LocationParameterName 'SourceLocation' ` -Credential $Credential ` -Proxy $Proxy ` -ProxyCredential $ProxyCredential ` -CallerPSCmdlet $PSCmdlet if(-not $SourceLocation) { # Above Resolve-Location function throws an error when it is not able to resolve a location return } } $ModuleSource = Get-PSRepository -Name $Name -ErrorAction SilentlyContinue -WarningAction SilentlyContinue if(-not $ModuleSource) { $message = $LocalizedData.RepositoryNotFound -f ($Name) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "RepositoryNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $Name } if (-not $PackageManagementProvider) { $PackageManagementProvider = (Get-ProviderName -PSCustomObject $ModuleSource) } $Trusted = $ModuleSource.Trusted if($InstallationPolicy) { if($InstallationPolicy -eq "Trusted") { $Trusted = $true } else { $Trusted = $false } $null = $PSBoundParameters.Remove("InstallationPolicy") } if($PublishLocation) { $PSBoundParameters[$script:PublishLocation] = Get-LocationString -LocationUri $PublishLocation } if($ScriptPublishLocation) { $PSBoundParameters[$script:ScriptPublishLocation] = Get-LocationString -LocationUri $ScriptPublishLocation } if($ScriptSourceLocation) { $PSBoundParameters[$script:ScriptSourceLocation] = Get-LocationString -LocationUri $ScriptSourceLocation } if($SourceLocation) { $PSBoundParameters["NewLocation"] = Get-LocationString -LocationUri $SourceLocation $null = $PSBoundParameters.Remove("SourceLocation") } $PSBoundParameters[$script:PackageManagementProviderParam] = $PackageManagementProvider $PSBoundParameters.Add("Trusted", $Trusted) $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock $null = PackageManagement\Set-PackageSource @PSBoundParameters } } function Unregister-PSRepository { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri='https://go.microsoft.com/fwlink/?LinkID=517130')] Param ( [Parameter(ValueFromPipelineByPropertyName=$true, Mandatory=$true)] [ValidateNotNullOrEmpty()] [string[]] $Name ) Begin { Get-PSGalleryApiAvailability -Repository $Name } Process { $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock $null = $PSBoundParameters.Remove("Name") foreach ($moduleSourceName in $Name) { # Check if $moduleSourceName contains any wildcards if(Test-WildcardPattern $moduleSourceName) { $message = $LocalizedData.RepositoryNameContainsWildCards -f ($moduleSourceName) Write-Error -Message $message -ErrorId "RepositoryNameContainsWildCards" -Category InvalidOperation continue } $PSBoundParameters["Source"] = $moduleSourceName $null = PackageManagement\Unregister-PackageSource @PSBoundParameters } } } function Get-PSRepository { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(HelpUri='https://go.microsoft.com/fwlink/?LinkID=517127')] Param ( [Parameter(ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [string[]] $Name ) Begin { Get-PSGalleryApiAvailability -Repository $Name } Process { $PSBoundParameters["Provider"] = $script:PSModuleProviderName $PSBoundParameters["MessageResolver"] = $script:PackageManagementMessageResolverScriptBlock if($Name) { foreach($sourceName in $Name) { $PSBoundParameters["Name"] = $sourceName $packageSources = PackageManagement\Get-PackageSource @PSBoundParameters $packageSources | Microsoft.PowerShell.Core\ForEach-Object { New-ModuleSourceFromPackageSource -PackageSource $_ } } } else { $packageSources = PackageManagement\Get-PackageSource @PSBoundParameters $packageSources | Microsoft.PowerShell.Core\ForEach-Object { New-ModuleSourceFromPackageSource -PackageSource $_ } } } } #endregion *-PSRepository cmdlets #region *-ScriptFileInfo cmdlets # Below is the sample PSScriptInfo in a script file. <#PSScriptInfo .VERSION 1.0 .GUID 544238e3-1751-4065-9227-be105ff11636 .AUTHOR manikb .COMPANYNAME Microsoft Corporation .COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved. .TAGS Tag1 Tag2 Tag3 .LICENSEURI https://contoso.com/License .PROJECTURI https://contoso.com/ .ICONURI https://contoso.com/Icon .EXTERNALMODULEDEPENDENCIES ExternalModule1 .REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript .EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript .RELEASENOTES contoso script now supports following features Feature 1 Feature 2 Feature 3 Feature 4 Feature 5 .PRIVATEDATA Contoso private data #> <# #Requires -Module statements #> <# .DESCRIPTION Description goes here. #> function Test-ScriptFileInfo { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(PositionalBinding=$false, DefaultParameterSetName='PathParameterSet', HelpUri='https://go.microsoft.com/fwlink/?LinkId=619791')] Param ( [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true, ParameterSetName='PathParameterSet')] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Mandatory=$true, ValueFromPipelineByPropertyName=$true, ParameterSetName='LiteralPathParameterSet')] [ValidateNotNullOrEmpty()] [string] $LiteralPath ) Process { $scriptFilePath = $null if($Path) { $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) { $errorMessage = ($LocalizedData.PathNotFound -f $Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $Path ` -ErrorCategory InvalidArgument return } } else { $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) { $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $LiteralPath ` -ErrorCategory InvalidArgument return } } if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) { $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "InvalidScriptFilePath" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $scriptFilePath ` -ErrorCategory InvalidArgument return } $PSScriptInfo = New-PSScriptInfoObject -Path $scriptFilePath [System.Management.Automation.Language.Token[]]$tokens = $null; [System.Management.Automation.Language.ParseError[]]$errors = $null; $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptFilePath, ([ref]$tokens), ([ref]$errors)) $notSupportedOnNanoErrorIds = @('WorkflowNotSupportedInPowerShellCore', 'ConfigurationNotSupportedInPowerShellCore') $errorsAfterSkippingOneCoreErrors = $errors | Microsoft.PowerShell.Core\Where-Object { $notSupportedOnNanoErrorIds -notcontains $_.ErrorId} if($errorsAfterSkippingOneCoreErrors) { $errorMessage = ($LocalizedData.ScriptParseError -f $scriptFilePath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "ScriptParseError" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $errorsAfterSkippingOneCoreErrors ` -ErrorCategory InvalidArgument return } if($ast) { # Get the block/group comment beginning with <#PSScriptInfo $CommentTokens = $tokens | Microsoft.PowerShell.Core\Where-Object {$_.Kind -eq 'Comment'} $psscriptInfoComments = $CommentTokens | Microsoft.PowerShell.Core\Where-Object { $_.Extent.Text -match "<#PSScriptInfo" } | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $psscriptInfoComments) { $errorMessage = ($LocalizedData.MissingPSScriptInfo -f $scriptFilePath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "MissingPSScriptInfo" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $scriptFilePath ` -ErrorCategory InvalidArgument return } # $psscriptInfoComments.Text will have the multiline PSScriptInfo comment, # split them into multiple lines to parse for the PSScriptInfo metadata properties. $commentLines = [System.Text.RegularExpressions.Regex]::Split($psscriptInfoComments.Text, "[\r\n]") $KeyName = $null $Value = "" # PSScriptInfo comment will be in following format: <#PSScriptInfo .VERSION 1.0 .GUID 544238e3-1751-4065-9227-be105ff11636 .AUTHOR manikb .COMPANYNAME Microsoft Corporation .COPYRIGHT (c) 2015 Microsoft Corporation. All rights reserved. .TAGS Tag1 Tag2 Tag3 .LICENSEURI https://contoso.com/License .PROJECTURI https://contoso.com/ .ICONURI https://contoso.com/Icon .EXTERNALMODULEDEPENDENCIES ExternalModule1 .REQUIREDSCRIPTS Start-WFContosoServer,Stop-ContosoServerScript .EXTERNALSCRIPTDEPENDENCIES Stop-ContosoServerScript .RELEASENOTES contoso script now supports following features Feature 1 Feature 2 Feature 3 Feature 4 Feature 5 #> # If comment line count is not more than two, it doesn't have the any metadata property # First line is <#PSScriptInfo # Last line #> # if($commentLines.Count -gt 2) { for($i = 1; $i -lt ($commentLines.count - 1); $i++) { $line = $commentLines[$i] if(-not $line) { continue } # A line is starting with . conveys a new metadata property # __NEWLINE__ is used for replacing the value lines while adding the value to $PSScriptInfo object # if($line.trim().StartsWith('.')) { $parts = $line.trim() -split '[.\s+]',3 | Microsoft.PowerShell.Core\Where-Object {$_} if($KeyName -and $Value) { if($keyName -eq $script:ReleaseNotes) { $Value = $Value.Trim() -split '__NEWLINE__' } elseif($keyName -eq $script:DESCRIPTION) { $Value = $Value -split '__NEWLINE__' $Value = ($Value -join "`r`n").Trim() } else { $Value = $Value -split '__NEWLINE__' | Microsoft.PowerShell.Core\Where-Object { $_ } if($Value -and $Value.GetType().ToString() -eq "System.String") { $Value = $Value.Trim() } } ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` -PropertyName $KeyName ` -PropertyValue $Value ` -CallerPSCmdlet $PSCmdlet } $KeyName = $null $Value = "" if($parts.GetType().ToString() -eq "System.String") { $KeyName = $parts } else { $KeyName = $parts[0]; $Value = $parts[1] } } else { if($Value) { # __NEWLINE__ is used for replacing the value lines while adding the value to $PSScriptInfo object $Value += '__NEWLINE__' } $Value += $line } } if($KeyName -and $Value) { if($keyName -eq $script:ReleaseNotes) { $Value = $Value.Trim() -split '__NEWLINE__' } elseif($keyName -eq $script:DESCRIPTION) { $Value = $Value -split '__NEWLINE__' $Value = ($Value -join "`r`n").Trim() } else { $Value = $Value -split '__NEWLINE__' | Microsoft.PowerShell.Core\Where-Object { $_ } if($Value -and $Value.GetType().ToString() -eq "System.String") { $Value = $Value.Trim() } } ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` -PropertyName $KeyName ` -PropertyValue $Value ` -CallerPSCmdlet $PSCmdlet $KeyName = $null $Value = "" } } $helpContent = $ast.GetHelpContent() if($helpContent -and $helpContent.Description) { ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` -PropertyName $script:DESCRIPTION ` -PropertyValue $helpContent.Description.Trim() ` -CallerPSCmdlet $PSCmdlet } # Handle RequiredModules if((Microsoft.PowerShell.Utility\Get-Member -InputObject $ast -Name 'ScriptRequirements') -and $ast.ScriptRequirements -and (Microsoft.PowerShell.Utility\Get-Member -InputObject $ast.ScriptRequirements -Name 'RequiredModules') -and $ast.ScriptRequirements.RequiredModules) { ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` -PropertyName $script:RequiredModules ` -PropertyValue $ast.ScriptRequirements.RequiredModules ` -CallerPSCmdlet $PSCmdlet } # Get all defined functions and populate DefinedCommands, DefinedFunctions and DefinedWorkflows $allCommands = $ast.FindAll({param($i) return ($i.GetType().Name -eq 'FunctionDefinitionAst')}, $true) if($allCommands) { $allCommandNames = $allCommands | ForEach-Object {$_.Name} | Select-Object -Unique -ErrorAction Ignore ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` -PropertyName $script:DefinedCommands ` -PropertyValue $allCommandNames ` -CallerPSCmdlet $PSCmdlet $allFunctionNames = $allCommands | Where-Object {-not $_.IsWorkflow} | ForEach-Object {$_.Name} | Select-Object -Unique -ErrorAction Ignore ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` -PropertyName $script:DefinedFunctions ` -PropertyValue $allFunctionNames ` -CallerPSCmdlet $PSCmdlet $allWorkflowNames = $allCommands | Where-Object {$_.IsWorkflow} | ForEach-Object {$_.Name} | Select-Object -Unique -ErrorAction Ignore ValidateAndAdd-PSScriptInfoEntry -PSScriptInfo $PSScriptInfo ` -PropertyName $script:DefinedWorkflows ` -PropertyValue $allWorkflowNames ` -CallerPSCmdlet $PSCmdlet } } # Ensure that the script file has the required metadata properties. if(-not $PSScriptInfo.Version -or -not $PSScriptInfo.Guid -or -not $PSScriptInfo.Author -or -not $PSScriptInfo.Description) { $errorMessage = ($LocalizedData.MissingRequiredPSScriptInfoProperties -f $scriptFilePath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "MissingRequiredPSScriptInfoProperties" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $Path ` -ErrorCategory InvalidArgument return } if ($PSScriptInfo.Version -match '-') { $result = ValidateAndGet-VersionPrereleaseStrings -Version $PSScriptInfo.Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } } $PSScriptInfo = Get-OrderedPSScriptInfoObject -PSScriptInfo $PSScriptInfo return $PSScriptInfo } } function New-ScriptFileInfo { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(PositionalBinding=$false, SupportsShouldProcess=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkId=619792')] Param ( [Parameter(Mandatory=$false, Position=0, ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Version, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Author, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Description, [Parameter()] [ValidateNotNullOrEmpty()] [Guid] $Guid, [Parameter()] [ValidateNotNullOrEmpty()] [string] $CompanyName, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Copyright, [Parameter()] [ValidateNotNullOrEmpty()] [Object[]] $RequiredModules, [Parameter()] [ValidateNotNullOrEmpty()] [String[]] $ExternalModuleDependencies, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $RequiredScripts, [Parameter()] [ValidateNotNullOrEmpty()] [String[]] $ExternalScriptDependencies, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Tags, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $ProjectUri, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $LicenseUri, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $IconUri, [Parameter()] [string[]] $ReleaseNotes, [Parameter()] [ValidateNotNullOrEmpty()] [string] $PrivateData, [Parameter()] [switch] $PassThru, [Parameter()] [switch] $Force ) Process { if($Path) { if(-not $Path.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) { $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $Path) ThrowError -ExceptionName 'System.ArgumentException' ` -ExceptionMessage $errorMessage ` -ErrorId 'InvalidScriptFilePath' ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $Path ` -ErrorCategory InvalidArgument return } if(-not $Force -and (Microsoft.PowerShell.Management\Test-Path -Path $Path)) { $errorMessage = ($LocalizedData.ScriptFileExist -f $Path) ThrowError -ExceptionName 'System.ArgumentException' ` -ExceptionMessage $errorMessage ` -ErrorId 'ScriptFileExist' ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $Path ` -ErrorCategory InvalidArgument return } } elseif(-not $PassThru) { ThrowError -ExceptionName 'System.ArgumentException' ` -ExceptionMessage $LocalizedData.MissingTheRequiredPathOrPassThruParameter ` -ErrorId 'MissingTheRequiredPathOrPassThruParameter' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } if(-not $Version) { $Version = '1.0' } else { $result = ValidateAndGet-VersionPrereleaseStrings -Version $Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } } if(-not $Author) { if($script:IsWindows) { $Author = (Get-EnvironmentVariable -Name 'USERNAME' -Target $script:EnvironmentVariableTarget.Process -ErrorAction SilentlyContinue) } else { $Author = $env:USER } } if(-not $Guid) { $Guid = [System.Guid]::NewGuid() } $params = @{ Version = $Version Author = $Author Guid = $Guid CompanyName = $CompanyName Copyright = $Copyright ExternalModuleDependencies = $ExternalModuleDependencies RequiredScripts = $RequiredScripts ExternalScriptDependencies = $ExternalScriptDependencies Tags = $Tags ProjectUri = $ProjectUri LicenseUri = $LicenseUri IconUri = $IconUri ReleaseNotes = $ReleaseNotes PrivateData = $PrivateData } if(-not (Validate-ScriptFileInfoParameters -parameters $params)) { return } if("$Description" -match '<#' -or "$Description" -match '#>') { $message = $LocalizedData.InvalidParameterValue -f ($Description, 'Description') Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument return } $PSScriptInfoString = Get-PSScriptInfoString @params $requiresStrings = Get-RequiresString -RequiredModules $RequiredModules $ScriptCommentHelpInfoString = Get-ScriptCommentHelpInfoString -Description $Description $ScriptMetadataString = $PSScriptInfoString $ScriptMetadataString += "`r`n" if("$requiresStrings".Trim()) { $ScriptMetadataString += "`r`n" $ScriptMetadataString += $requiresStrings -join "`r`n" $ScriptMetadataString += "`r`n" } $ScriptMetadataString += "`r`n" $ScriptMetadataString += $ScriptCommentHelpInfoString $ScriptMetadataString += "Param()`r`n`r`n" $tempScriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath "$(Get-Random).ps1" try { Microsoft.PowerShell.Management\Set-Content -Value $ScriptMetadataString -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath if(-not $scriptInfo) { # Above Test-ScriptFileInfo cmdlet writes the errors return } if($Path -and ($Force -or $PSCmdlet.ShouldProcess($Path, ($LocalizedData.NewScriptFileInfowhatIfMessage -f $Path) ))) { Microsoft.PowerShell.Management\Copy-Item -Path $tempScriptFilePath -Destination $Path -Force -WhatIf:$false -Confirm:$false } if($PassThru) { Write-Output -InputObject $ScriptMetadataString } } finally { Microsoft.PowerShell.Management\Remove-Item -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue } } } function Update-ScriptFileInfo { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(PositionalBinding=$false, DefaultParameterSetName='PathParameterSet', SupportsShouldProcess=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkId=619793')] Param ( [Parameter(Mandatory=$true, Position=0, ParameterSetName='PathParameterSet', ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter(Mandatory=$true, Position=0, ParameterSetName='LiteralPathParameterSet', ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [string] $LiteralPath, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Version, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Author, [Parameter()] [ValidateNotNullOrEmpty()] [Guid] $Guid, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Description, [Parameter()] [ValidateNotNullOrEmpty()] [string] $CompanyName, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Copyright, [Parameter()] [ValidateNotNullOrEmpty()] [Object[]] $RequiredModules, [Parameter()] [ValidateNotNullOrEmpty()] [String[]] $ExternalModuleDependencies, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $RequiredScripts, [Parameter()] [ValidateNotNullOrEmpty()] [String[]] $ExternalScriptDependencies, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Tags, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $ProjectUri, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $LicenseUri, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $IconUri, [Parameter()] [string[]] $ReleaseNotes, [Parameter()] [ValidateNotNullOrEmpty()] [string] $PrivateData, [Parameter()] [switch] $PassThru, [Parameter()] [switch] $Force ) Process { # Resolve the script path $scriptFilePath = $null if($Path) { $scriptFilePath = Resolve-PathHelper -Path $Path -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) { $errorMessage = ($LocalizedData.PathNotFound -f $Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $Path ` -ErrorCategory InvalidArgument } } else { $scriptFilePath = Resolve-PathHelper -Path $LiteralPath -IsLiteralPath -CallerPSCmdlet $PSCmdlet | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $scriptFilePath -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $scriptFilePath -PathType Leaf)) { $errorMessage = ($LocalizedData.PathNotFound -f $LiteralPath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $LiteralPath ` -ErrorCategory InvalidArgument } } if(-not $scriptFilePath.EndsWith('.ps1', [System.StringComparison]::OrdinalIgnoreCase)) { $errorMessage = ($LocalizedData.InvalidScriptFilePath -f $scriptFilePath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "InvalidScriptFilePath" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $scriptFilePath ` -ErrorCategory InvalidArgument return } # Obtain script info $psscriptInfo = $null try { $psscriptInfo = Test-ScriptFileInfo -LiteralPath $scriptFilePath } catch { if(-not $Force) { throw $_ return } } if(-not $psscriptInfo) { if(-not $Description) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.DescriptionParameterIsMissingForAddingTheScriptFileInfo ` -ErrorId 'DescriptionParameterIsMissingForAddingTheScriptFileInfo' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } if(-not $Version) { $Version = '1.0' } else { $result = ValidateAndGet-VersionPrereleaseStrings -Version $Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } } if(-not $Author) { if($script:IsWindows) { $Author = (Get-EnvironmentVariable -Name 'USERNAME' -Target $script:EnvironmentVariableTarget.Process -ErrorAction SilentlyContinue) } else { $Author = $env:USER } } if(-not $Guid) { $Guid = [System.Guid]::NewGuid() } } else { # Use existing values if any of the parameters are not specified during Update-ScriptFileInfo if(-not $Version -and $psscriptInfo.Version) { $Version = $psscriptInfo.Version } if(-not $Guid -and $psscriptInfo.Guid) { $Guid = $psscriptInfo.Guid } if(-not $Author -and $psscriptInfo.Author) { $Author = $psscriptInfo.Author } if(-not $CompanyName -and $psscriptInfo.CompanyName) { $CompanyName = $psscriptInfo.CompanyName } if(-not $Copyright -and $psscriptInfo.Copyright) { $Copyright = $psscriptInfo.Copyright } if(-not $RequiredModules -and $psscriptInfo.RequiredModules) { $RequiredModules = $psscriptInfo.RequiredModules } if(-not $ExternalModuleDependencies -and $psscriptInfo.ExternalModuleDependencies) { $ExternalModuleDependencies = $psscriptInfo.ExternalModuleDependencies } if(-not $RequiredScripts -and $psscriptInfo.RequiredScripts) { $RequiredScripts = $psscriptInfo.RequiredScripts } if(-not $ExternalScriptDependencies -and $psscriptInfo.ExternalScriptDependencies) { $ExternalScriptDependencies = $psscriptInfo.ExternalScriptDependencies } if(-not $Tags -and $psscriptInfo.Tags) { $Tags = $psscriptInfo.Tags } if(-not $ProjectUri -and $psscriptInfo.ProjectUri) { $ProjectUri = $psscriptInfo.ProjectUri } if(-not $LicenseUri -and $psscriptInfo.LicenseUri) { $LicenseUri = $psscriptInfo.LicenseUri } if(-not $IconUri -and $psscriptInfo.IconUri) { $IconUri = $psscriptInfo.IconUri } if(-not $ReleaseNotes -and $psscriptInfo.ReleaseNotes) { $ReleaseNotes = $psscriptInfo.ReleaseNotes } } $params = @{ Version = $Version Author = $Author Guid = $Guid CompanyName = $CompanyName Copyright = $Copyright ExternalModuleDependencies = $ExternalModuleDependencies RequiredScripts = $RequiredScripts ExternalScriptDependencies = $ExternalScriptDependencies Tags = $Tags ProjectUri = $ProjectUri LicenseUri = $LicenseUri IconUri = $IconUri ReleaseNotes = $ReleaseNotes PrivateData = $PrivateData } # Ensure no fields contain '<#' or '#>' (would break comment section) if(-not (Validate-ScriptFileInfoParameters -parameters $params)) { return } if("$Description" -match '<#' -or "$Description" -match '#>') { $message = $LocalizedData.InvalidParameterValue -f ($Description, 'Description') Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument return } $PSScriptInfoString = Get-PSScriptInfoString @params $requiresStrings = "" $requiresStrings = Get-RequiresString -RequiredModules $RequiredModules $DescriptionValue = if($Description) {$Description} else {$psscriptInfo.Description} $ScriptCommentHelpInfoString = Get-ScriptCommentHelpInfoString -Description $DescriptionValue $ScriptMetadataString = $PSScriptInfoString $ScriptMetadataString += "`r`n" if("$requiresStrings".Trim()) { $ScriptMetadataString += "`r`n" $ScriptMetadataString += $requiresStrings -join "`r`n" $ScriptMetadataString += "`r`n" } $ScriptMetadataString += "`r`n" $ScriptMetadataString += $ScriptCommentHelpInfoString $ScriptMetadataString += "`r`nParam()`r`n`r`n" if(-not $ScriptMetadataString) { return } $tempScriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath "$(Get-Random).ps1" try { # First create a new script file with new script metadata to ensure that updated values are valid. Microsoft.PowerShell.Management\Set-Content -Value $ScriptMetadataString -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath if(-not $scriptInfo) { # Above Test-ScriptFileInfo cmdlet writes the error return } $scriptFileContents = Microsoft.PowerShell.Management\Get-Content -LiteralPath $scriptFilePath # If -Force is specified and script file doesnt have a valid PSScriptInfo # Prepend the PSScriptInfo and Check if the Test-ScriptFileInfo returns a valid script info without any errors if($Force -and -not $psscriptInfo) { # Add the script file contents to the temp file with script metadata Microsoft.PowerShell.Management\Set-Content -LiteralPath $tempScriptFilePath ` -Value $ScriptMetadataString,$scriptFileContents ` -Force ` -WhatIf:$false ` -Confirm:$false $tempScriptInfo = $null try { $tempScriptInfo = Test-ScriptFileInfo -LiteralPath $tempScriptFilePath } catch { $errorMessage = ($LocalizedData.UnableToAddPSScriptInfo -f $scriptFilePath) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $errorMessage ` -ErrorId 'UnableToAddPSScriptInfo' ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $scriptFilePath ` -ErrorCategory InvalidOperation return } } else { [System.Management.Automation.Language.Token[]]$tokens = $null; [System.Management.Automation.Language.ParseError[]]$errors = $null; $ast = [System.Management.Automation.Language.Parser]::ParseFile($scriptFilePath, ([ref]$tokens), ([ref]$errors)) # Update PSScriptInfo and #Requires $CommentTokens = $tokens | Microsoft.PowerShell.Core\Where-Object {$_.Kind -eq 'Comment'} $psscriptInfoComments = $CommentTokens | Microsoft.PowerShell.Core\Where-Object { $_.Extent.Text -match "<#PSScriptInfo" } | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $psscriptInfoComments) { $errorMessage = ($LocalizedData.MissingPSScriptInfo -f $scriptFilePath) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $errorMessage ` -ErrorId "MissingPSScriptInfo" ` -CallerPSCmdlet $PSCmdlet ` -ExceptionObject $scriptFilePath ` -ErrorCategory InvalidArgument return } # Ensure that metadata is replaced at the correct location and should not corrupt the existing script file. # Remove the lines between below lines and add the new PSScriptInfo and new #Requires statements # ($psscriptInfoComments.Extent.StartLineNumber - 1) # ($psscriptInfoComments.Extent.EndLineNumber - 1) $tempContents = @() $IsNewPScriptInfoAdded = $false for($i = 0; $i -lt $scriptFileContents.Count; $i++) { $line = $scriptFileContents[$i] if(($i -ge ($psscriptInfoComments.Extent.StartLineNumber - 1)) -and ($i -le ($psscriptInfoComments.Extent.EndLineNumber - 1))) { if(-not $IsNewPScriptInfoAdded) { $PSScriptInfoString = $PSScriptInfoString.TrimStart() $requiresStrings = $requiresStrings.TrimEnd() $tempContents += "$PSScriptInfoString `r`n`r`n$($requiresStrings -join "`r`n")" $IsNewPScriptInfoAdded = $true } } elseif($line -notmatch "\s*#Requires\s+-Module") { # Add the existing lines if they are not part of PSScriptInfo comment or not containing #Requires -Module statements. $tempContents += $line } } Microsoft.PowerShell.Management\Set-Content -Value $tempContents -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath if(-not $scriptInfo) { # Above Test-ScriptFileInfo cmdlet writes the error return } # Now update the Description value if a new is specified. if($Description) { $tempContents = @() $IsDescriptionAdded = $false $IsDescriptionBeginFound = $false $scriptFileContents = Microsoft.PowerShell.Management\Get-Content -Path $tempScriptFilePath for($i = 0; $i -lt $scriptFileContents.Count; $i++) { $line = $scriptFileContents[$i] if(-not $IsDescriptionAdded) { if(-not $IsDescriptionBeginFound) { if($line.Trim().StartsWith(".DESCRIPTION", [System.StringComparison]::OrdinalIgnoreCase)) { $IsDescriptionBeginFound = $true } else { $tempContents += $line } } else { # Description begin has found # Skip the old description lines until description end is found if($line.Trim().StartsWith("#>", [System.StringComparison]::OrdinalIgnoreCase) -or $line.Trim().StartsWith(".", [System.StringComparison]::OrdinalIgnoreCase)) { $tempContents += ".DESCRIPTION `r`n$($Description -join "`r`n")`r`n" $IsDescriptionAdded = $true $tempContents += $line } } } else { $tempContents += $line } } Microsoft.PowerShell.Management\Set-Content -Value $tempContents -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false $scriptInfo = Test-ScriptFileInfo -Path $tempScriptFilePath if(-not $scriptInfo) { # Above Test-ScriptFileInfo cmdlet writes the error return } } } if($Force -or $PSCmdlet.ShouldProcess($scriptFilePath, ($LocalizedData.UpdateScriptFileInfowhatIfMessage -f $Path) )) { Microsoft.PowerShell.Management\Copy-Item -Path $tempScriptFilePath -Destination $scriptFilePath -Force -WhatIf:$false -Confirm:$false if($PassThru) { $ScriptMetadataString } } } finally { Microsoft.PowerShell.Management\Remove-Item -Path $tempScriptFilePath -Force -WhatIf:$false -Confirm:$false -ErrorAction SilentlyContinue -WarningAction SilentlyContinue } } } function Get-RequiresString { [CmdletBinding()] Param ( [Parameter()] [Object[]] $RequiredModules ) Process { if($RequiredModules) { $RequiredModuleStrings = @() foreach($requiredModuleObject in $RequiredModules) { if($requiredModuleObject.GetType().ToString() -eq 'System.Collections.Hashtable') { if(($requiredModuleObject.Keys.Count -eq 1) -and (Microsoft.PowerShell.Utility\Get-Member -InputObject $requiredModuleObject -Name 'ModuleName')) { $RequiredModuleStrings += $requiredModuleObject['ModuleName'].ToString() } else { $moduleSpec = New-Object Microsoft.PowerShell.Commands.ModuleSpecification -ArgumentList $requiredModuleObject if (-not (Microsoft.PowerShell.Utility\Get-Variable -Name moduleSpec -ErrorAction SilentlyContinue)) { return } $keyvalueStrings = $requiredModuleObject.Keys | Microsoft.PowerShell.Core\ForEach-Object {"$_ = '$( $requiredModuleObject[$_])'"} $RequiredModuleStrings += "@{$($keyvalueStrings -join '; ')}" } } elseif(($PSVersionTable.PSVersion -eq '3.0.0') -and ($requiredModuleObject.GetType().ToString() -eq 'Microsoft.PowerShell.Commands.ModuleSpecification')) { # ModuleSpecification.ToString() is not implemented on PowerShell 3.0. $optionalString = " " if($requiredModuleObject.Version) { $optionalString += "ModuleVersion = '$($requiredModuleObject.Version.ToString())'; " } if($requiredModuleObject.Guid) { $optionalString += "Guid = '$($requiredModuleObject.Guid.ToString())'; " } if($optionalString.Trim()) { $moduleSpecString = "@{ ModuleName = '$($requiredModuleObject.Name.ToString())';$optionalString}" } else { $moduleSpecString = $requiredModuleObject.Name.ToString() } $RequiredModuleStrings += $moduleSpecString } else { $RequiredModuleStrings += $requiredModuleObject.ToString() } } $hashRequiresStrings = $RequiredModuleStrings | Microsoft.PowerShell.Core\ForEach-Object { "#Requires -Module $_" } return $hashRequiresStrings } else { return "" } } } function Get-PSScriptInfoString { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Version, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Guid] $Guid, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Author, [Parameter()] [String] $CompanyName, [Parameter()] [string] $Copyright, [Parameter()] [String[]] $ExternalModuleDependencies, [Parameter()] [string[]] $RequiredScripts, [Parameter()] [String[]] $ExternalScriptDependencies, [Parameter()] [string[]] $Tags, [Parameter()] [Uri] $ProjectUri, [Parameter()] [Uri] $LicenseUri, [Parameter()] [Uri] $IconUri, [Parameter()] [string[]] $ReleaseNotes, [Parameter()] [string] $PrivateData ) Process { $PSScriptInfoString = @" <#PSScriptInfo .VERSION $Version .GUID $Guid .AUTHOR $Author .COMPANYNAME $CompanyName .COPYRIGHT $Copyright .TAGS $Tags .LICENSEURI $LicenseUri .PROJECTURI $ProjectUri .ICONURI $IconUri .EXTERNALMODULEDEPENDENCIES $($ExternalModuleDependencies -join ',') .REQUIREDSCRIPTS $($RequiredScripts -join ',') .EXTERNALSCRIPTDEPENDENCIES $($ExternalScriptDependencies -join ',') .RELEASENOTES $($ReleaseNotes -join "`r`n") .PRIVATEDATA $PrivateData #> "@ return $PSScriptInfoString } } function Validate-ScriptFileInfoParameters { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [PSCustomObject] $Parameters ) $hasErrors = $false $Parameters.Keys | ForEach-Object { $parameterName = $_ $parameterValue = $($Parameters[$parameterName]) if("$parameterValue" -match '<#' -or "$parameterValue" -match '#>') { $message = $LocalizedData.InvalidParameterValue -f ($parameterValue, $parameterName) Write-Error -Message $message -ErrorId 'InvalidParameterValue' -Category InvalidArgument $hasErrors = $true } } return (-not $hasErrors) } function Get-ScriptCommentHelpInfoString { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Description, [Parameter()] [string] $Synopsis, [Parameter()] [string[]] $Example, [Parameter()] [string[]] $Inputs, [Parameter()] [string[]] $Outputs, [Parameter()] [string[]] $Notes, [Parameter()] [string[]] $Link, [Parameter()] [string] $Component, [Parameter()] [string] $Role, [Parameter()] [string] $Functionality ) Process { $ScriptCommentHelpInfoString = "<# `r`n`r`n.DESCRIPTION `r`n $Description `r`n`r`n" if("$Synopsis".Trim()) { $ScriptCommentHelpInfoString += ".SYNOPSIS `r`n$Synopsis `r`n`r`n" } if("$Example".Trim()) { $Example | ForEach-Object { if($_) { $ScriptCommentHelpInfoString += ".EXAMPLE `r`n$_ `r`n`r`n" } } } if("$Inputs".Trim()) { $Inputs | ForEach-Object { if($_) { $ScriptCommentHelpInfoString += ".INPUTS `r`n$_ `r`n`r`n" } } } if("$Outputs".Trim()) { $Outputs | ForEach-Object { if($_) { $ScriptCommentHelpInfoString += ".OUTPUTS `r`n$_ `r`n`r`n" } } } if("$Notes".Trim()) { $ScriptCommentHelpInfoString += ".NOTES `r`n$($Notes -join "`r`n") `r`n`r`n" } if("$Link".Trim()) { $Link | ForEach-Object { if($_) { $ScriptCommentHelpInfoString += ".LINK `r`n$_ `r`n`r`n" } } } if("$Component".Trim()) { $ScriptCommentHelpInfoString += ".COMPONENT `r`n$($Component -join "`r`n") `r`n`r`n" } if("$Role".Trim()) { $ScriptCommentHelpInfoString += ".ROLE `r`n$($Role -join "`r`n") `r`n`r`n" } if("$Functionality".Trim()) { $ScriptCommentHelpInfoString += ".FUNCTIONALITY `r`n$($Functionality -join "`r`n") `r`n`r`n" } $ScriptCommentHelpInfoString += "#> `r`n" return $ScriptCommentHelpInfoString } } #endregion *-ScriptFileInfo cmdlets #region Utility functions function Get-ManifestHashTable { param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Path, [Parameter()] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet ) $Lines = $null try { $Lines = Get-Content -Path $Path -Force } catch { if($CallerPSCmdlet) { $CallerPSCmdlet.ThrowTerminatingError($_.Exception.ErrorRecord) } } if(-not $Lines) { return } $scriptBlock = [ScriptBlock]::Create( $Lines -join "`n" ) $allowedVariables = [System.Collections.Generic.List[String]] @('PSEdition', 'PSScriptRoot') $allowedCommands = [System.Collections.Generic.List[String]] @() $allowEnvironmentVariables = $false try { $scriptBlock.CheckRestrictedLanguage($allowedCommands, $allowedVariables, $allowEnvironmentVariables) } catch { if($CallerPSCmdlet) { $CallerPSCmdlet.ThrowTerminatingError($_.Exception.ErrorRecord) } return } return $scriptBlock.InvokeReturnAsIs() } function Get-ParametersHashtable { param( $Proxy, $ProxyCredential ) $ParametersHashtable = @{} if($Proxy) { $ParametersHashtable[$script:Proxy] = $Proxy } if($ProxyCredential) { $ParametersHashtable[$script:ProxyCredential] = $ProxyCredential } return $ParametersHashtable } function ToUpper { param([string]$str) return $script:TextInfo.ToUpper($str) } function Resolve-PathHelper { param ( [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $path, [Parameter()] [switch] $isLiteralPath, [Parameter()] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $callerPSCmdlet ) $resolvedPaths =@() foreach($currentPath in $path) { try { if($isLiteralPath) { $currentResolvedPaths = Microsoft.PowerShell.Management\Resolve-Path -LiteralPath $currentPath -ErrorAction Stop } else { $currentResolvedPaths = Microsoft.PowerShell.Management\Resolve-Path -Path $currentPath -ErrorAction Stop } } catch { $errorMessage = ($LocalizedData.PathNotFound -f $currentPath) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $errorMessage ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $callerPSCmdlet ` -ErrorCategory InvalidOperation } foreach($currentResolvedPath in $currentResolvedPaths) { $resolvedPaths += $currentResolvedPath.ProviderPath } } $resolvedPaths } function Check-PSGalleryApiAvailability { param ( [Parameter()] [ValidateNotNullOrEmpty()] [string] $PSGalleryV2ApiUri, [Parameter()] [ValidateNotNullOrEmpty()] [string] $PSGalleryV3ApiUri ) # check internet availability first $connected = $false $microsoftDomain = 'www.microsoft.com' if((-not $script:IsCoreCLR) -and (Get-Command Microsoft.PowerShell.Management\Test-Connection -ErrorAction Ignore)) { $connected = Microsoft.PowerShell.Management\Test-Connection -ComputerName $microsoftDomain -Count 1 -Quiet } elseif(Get-Command NetTCPIP\Test-Connection -ErrorAction Ignore) { $connected = NetTCPIP\Test-NetConnection -ComputerName $microsoftDomain -InformationLevel Quiet } else { $connected = [System.Net.NetworkInformation.NetworkInterface]::GetIsNetworkAvailable() } if ( -not $connected) { return } $statusCode_v2 = $null $resolvedUri_v2 = $null $statusCode_v3 = $null $resolvedUri_v3 = $null # ping V2 $res_v2 = Ping-Endpoint -Endpoint $PSGalleryV2ApiUri if ($res_v2.ContainsKey($Script:ResponseUri)) { $resolvedUri_v2 = $res_v2[$Script:ResponseUri] } if ($res_v2.ContainsKey($Script:StatusCode)) { $statusCode_v2 = $res_v2[$Script:StatusCode] } # ping V3 $res_v3 = Ping-Endpoint -Endpoint $PSGalleryV3ApiUri if ($res_v3.ContainsKey($Script:ResponseUri)) { $resolvedUri_v3 = $res_v3[$Script:ResponseUri] } if ($res_v3.ContainsKey($Script:StatusCode)) { $statusCode_v3 = $res_v3[$Script:StatusCode] } $Script:PSGalleryV2ApiAvailable = (($statusCode_v2 -eq 200) -and ($resolvedUri_v2)) $Script:PSGalleryV3ApiAvailable = (($statusCode_v3 -eq 200) -and ($resolvedUri_v3)) $Script:PSGalleryApiChecked = $true } function Get-PSGalleryApiAvailability { param ( [Parameter()] [string[]] $Repository ) # skip if repository is null or not PSGallery if ( -not $Repository) { return } if ($Repository -notcontains $Script:PSGalleryModuleSource ) { return } # run check only once if( -not $Script:PSGalleryApiChecked) { $null = Check-PSGalleryApiAvailability -PSGalleryV2ApiUri $Script:PSGallerySourceUri -PSGalleryV3ApiUri $Script:PSGalleryV3SourceUri } if ( -not $Script:PSGalleryV2ApiAvailable ) { if ($Script:PSGalleryV3ApiAvailable) { ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $LocalizedData.PSGalleryApiV2Discontinued ` -ErrorId "PSGalleryApiV2Discontinued" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } else { # both APIs are down, throw error ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $LocalizedData.PowerShellGalleryUnavailable ` -ErrorId "PowerShellGalleryUnavailable" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } } else { if ($Script:PSGalleryV3ApiAvailable) { Write-Warning -Message $LocalizedData.PSGalleryApiV2Deprecated return } } # if V2 is available and V3 is not available, do nothing } function HttpClientApisAvailable { $HttpClientApisAvailable = $false try { [System.Net.Http.HttpClient] $HttpClientApisAvailable = $true } catch { } return $HttpClientApisAvailable } function Ping-Endpoint { [CmdletBinding()] param ( [Parameter()] [ValidateNotNullOrEmpty()] [string] $Endpoint, [Parameter()] $Credential, [Parameter()] $Proxy, [Parameter()] $ProxyCredential, [Parameter()] [switch] $AllowAutoRedirect = $true ) $results = @{} $WebProxy = $null if($Proxy -and ('Microsoft.PowerShell.Commands.PowerShellGet.InternalWebProxy' -as [Type])) { $ProxyNetworkCredential = $null if($ProxyCredential) { $ProxyNetworkCredential = $ProxyCredential.GetNetworkCredential() } $WebProxy = New-Object Microsoft.PowerShell.Commands.PowerShellGet.InternalWebProxy -ArgumentList $Proxy,$ProxyNetworkCredential } if(HttpClientApisAvailable) { $response = $null try { $handler = New-Object System.Net.Http.HttpClientHandler if($Credential) { $handler.Credentials = $Credential.GetNetworkCredential() } else { $handler.UseDefaultCredentials = $true } if($WebProxy) { $handler.Proxy = $WebProxy } $httpClient = New-Object System.Net.Http.HttpClient -ArgumentList $handler $response = $httpclient.GetAsync($endpoint) } catch { } if ($response -ne $null -and $response.result -ne $null) { $results.Add($Script:ResponseUri,$response.Result.RequestMessage.RequestUri.AbsoluteUri.ToString()) $results.Add($Script:StatusCode,$response.result.StatusCode.value__) } } else { $iss = [System.Management.Automation.Runspaces.InitialSessionState]::Create() $iss.types.clear() $iss.formats.clear() $iss.LanguageMode = "FullLanguage" $WebRequestcmd = @' param($Credential, $WebProxy) try {{ $request = [System.Net.WebRequest]::Create("{0}") $request.Method = 'GET' $request.Timeout = 30000 if($Credential) {{ $request.Credentials = $Credential.GetNetworkCredential() }} else {{ $request.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials }} $request.AllowAutoRedirect = ${1} if($WebProxy) {{ $request.Proxy = $WebProxy }} $response = [System.Net.HttpWebResponse]$request.GetResponse() if($response.StatusCode.value__ -eq 302) {{ $response.Headers["Location"].ToString() }} else {{ $response }} $response.Close() }} catch [System.Net.WebException] {{ "Error:System.Net.WebException" }} '@ -f $EndPoint, $AllowAutoRedirect $ps = [powershell]::Create($iss).AddScript($WebRequestcmd) if($WebProxy) { $null = $ps.AddParameter('WebProxy', $WebProxy) } if($Credential) { $null = $ps.AddParameter('Credential', $Credential) } $response = $ps.Invoke() $ps.dispose() if ($response -ne "Error:System.Net.WebException") { if($AllowAutoRedirect) { $results.Add($Script:ResponseUri,$response.ResponseUri.ToString()) $results.Add($Script:StatusCode,$response.StatusCode.value__) } else { $results.Add($Script:ResponseUri,[String]$response) } } } return $results } function Validate-VersionParameters { [CmdletBinding()] Param( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet, [Parameter()] [String[]] $Name, [Parameter()] [string] $MinimumVersion, [Parameter()] [string] $RequiredVersion, [Parameter()] [string] $MaximumVersion, [Parameter()] [Switch] $AllVersions, [Parameter()] [Switch] $AllowPrerelease, [Parameter()] [Switch] $TestWildcardsInName ) if ($MinimumVersion) { $minResult = ValidateAndGet-VersionPrereleaseStrings -Version $MinimumVersion -CallerPSCmdlet $PSCmdlet # ValidateAndGet-VersionPrereleaseStrings will throw error if issue is found } if ($MaximumVersion) { $maxResult = ValidateAndGet-VersionPrereleaseStrings -Version $MaximumVersion -CallerPSCmdlet $PSCmdlet # ValidateAndGet-VersionPrereleaseStrings will throw error if issue is found } if ($RequiredVersion) { $reqResult = ValidateAndGet-VersionPrereleaseStrings -Version $RequiredVersion -CallerPSCmdlet $PSCmdlet # ValidateAndGet-VersionPrereleaseStrings will throw error if issue is found } if($TestWildcardsInName -and $Name -and (Test-WildcardPattern -Name "$Name")) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage ($LocalizedData.NameShouldNotContainWildcardCharacters -f "$($Name -join ',')") ` -ErrorId 'NameShouldNotContainWildcardCharacters' ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Name } elseif($AllVersions -and ($RequiredVersion -or $MinimumVersion -or $MaximumVersion)) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.AllVersionsCannotBeUsedWithOtherVersionParameters ` -ErrorId 'AllVersionsCannotBeUsedWithOtherVersionParameters' ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument } elseif($RequiredVersion -and ($MinimumVersion -or $MaximumVersion)) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether ` -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument } elseif($MinimumVersion -and $MaximumVersion -and ($MinimumVersion -gt $MaximumVersion)) { $Message = $LocalizedData.MinimumVersionIsGreaterThanMaximumVersion -f ($MinimumVersion, $MaximumVersion) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $Message ` -ErrorId "MinimumVersionIsGreaterThanMaximumVersion" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument } elseif( (($MinimumVersion -match '-') -or ($MaximumVersion -match '-') -or ($RequiredVersion -match '-')) -and -not $AllowPrerelease) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.AllowPrereleaseRequiredToUsePrereleaseStringInVersion ` -ErrorId "AllowPrereleaseRequiredToUsePrereleaseStringInVersion" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument } elseif($AllVersions -or $AllowPrerelease -or $RequiredVersion -or $MinimumVersion -or $MaximumVersion) { if(-not $Name -or $Name.Count -ne 1 -or (Test-WildcardPattern -Name $Name[0])) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSingleName ` -ErrorId "VersionParametersAreAllowedOnlyWithSingleName" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument } } return $true } function ValidateAndSet-PATHVariableIfUserAccepts { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [string] $Scope, [Parameter(Mandatory=$true)] [string] $ScopePath, [Parameter()] [Switch] $NoPathUpdate, [Parameter()] [Switch] $Force, [Parameter()] $Request ) if(-not $script:IsWindows) { return } Set-PSGetSettingsVariable # Check and add the scope path to PATH environment variable if USER accepts the prompt. if($Scope -eq 'AllUsers') { $envVariableTarget = $script:EnvironmentVariableTarget.Machine $scriptPATHPromptQuery=$LocalizedData.ScriptPATHPromptQuery -f $ScopePath $scopeSpecificKey = 'AllUsersScope_AllowPATHChangeForScripts' } else { $envVariableTarget = $script:EnvironmentVariableTarget.User $scriptPATHPromptQuery=$LocalizedData.ScriptPATHPromptQuery -f $ScopePath $scopeSpecificKey = 'CurrentUserScope_AllowPATHChangeForScripts' } $AlreadyPromptedForScope = $script:PSGetSettings.Contains($scopeSpecificKey) Write-Debug "Already prompted for the current scope:$AlreadyPromptedForScope" if(-not $AlreadyPromptedForScope) { # Read the file contents once again to ensure that it was not set in another PowerShell Session Set-PSGetSettingsVariable -Force $AlreadyPromptedForScope = $script:PSGetSettings.Contains($scopeSpecificKey) Write-Debug "After reading contents of PowerShellGetSettings.xml file, the Already prompted for the current scope:$AlreadyPromptedForScope" if($AlreadyPromptedForScope) { return } $userResponse = $false if(-not $NoPathUpdate) { $scopePathEndingWithBackSlash = "$scopePath\" # Check and add the $scopePath to $env:Path value if( (($env:PATH -split ';') -notcontains $scopePath) -and (($env:PATH -split ';') -notcontains $scopePathEndingWithBackSlash)) { if($Force) { $userResponse = $true } else { $scriptPATHPromptCaption = $LocalizedData.ScriptPATHPromptCaption if($Request) { $userResponse = $Request.ShouldContinue($scriptPATHPromptQuery, $scriptPATHPromptCaption) } else { $userResponse = $PSCmdlet.ShouldContinue($scriptPATHPromptQuery, $scriptPATHPromptCaption) } } if($userResponse) { $currentPATHValue = Get-EnvironmentVariable -Name 'PATH' -Target $envVariableTarget if((($currentPATHValue -split ';') -notcontains $scopePath) -and (($currentPATHValue -split ';') -notcontains $scopePathEndingWithBackSlash)) { # To ensure that the installed script is immediately usable, # we need to add the scope path to the PATH enviroment variable. Set-EnvironmentVariable -Name 'PATH' ` -Value "$currentPATHValue;$scopePath" ` -Target $envVariableTarget Write-Verbose ($LocalizedData.AddedScopePathToPATHVariable -f ($scopePath,$Scope)) } # Process specific PATH # Check and add the $scopePath to $env:Path value of current process # so that installed scripts can be used in the current process. $target = $script:EnvironmentVariableTarget.Process $currentPATHValue = Get-EnvironmentVariable -Name 'PATH' -Target $target if((($currentPATHValue -split ';') -notcontains $scopePath) -and (($currentPATHValue -split ';') -notcontains $scopePathEndingWithBackSlash)) { # To ensure that the installed script is immediately usable, # we need to add the scope path to the PATH enviroment variable. Set-EnvironmentVariable -Name 'PATH' ` -Value "$currentPATHValue;$scopePath" ` -Target $target Write-Verbose ($LocalizedData.AddedScopePathToProcessSpecificPATHVariable -f ($scopePath,$Scope)) } } } } # Add user's response to the PowerShellGet.settings file $script:PSGetSettings[$scopeSpecificKey] = $userResponse Save-PSGetSettings } } function Save-PSGetSettings { if($script:PSGetSettings) { if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:PSGetAppLocalPath)) { $null = Microsoft.PowerShell.Management\New-Item -Path $script:PSGetAppLocalPath ` -ItemType Directory ` -Force ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false ` -WhatIf:$false } Microsoft.PowerShell.Utility\Out-File -FilePath $script:PSGetSettingsFilePath -Force ` -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:PSGetSettings)) Write-Debug "In Save-PSGetSettings, persisted the $script:PSGetSettingsFilePath file" } } function Set-PSGetSettingsVariable { [CmdletBinding()] param([switch]$Force) if(-not $script:PSGetSettings -or $Force) { if(Microsoft.PowerShell.Management\Test-Path -Path $script:PSGetSettingsFilePath) { $script:PSGetSettings = DeSerialize-PSObject -Path $script:PSGetSettingsFilePath } else { $script:PSGetSettings = [ordered]@{} } } } function Set-PSGalleryRepository { [CmdletBinding()] param( [Parameter()] [switch] $Trusted, [Parameter()] $Proxy, [Parameter()] $ProxyCredential ) $psgalleryLocation = Resolve-Location -Location $Script:PSGallerySourceUri ` -LocationParameterName 'SourceLocation' ` -Proxy $Proxy ` -ProxyCredential $ProxyCredential ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue $scriptSourceLocation = Resolve-Location -Location $Script:PSGalleryScriptSourceUri ` -LocationParameterName 'ScriptSourceLocation' ` -Proxy $Proxy ` -ProxyCredential $ProxyCredential ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if($psgalleryLocation) { $result = Ping-Endpoint -Endpoint $Script:PSGalleryPublishUri -AllowAutoRedirect:$false -Proxy $Proxy -ProxyCredential $ProxyCredential if ($result.ContainsKey($Script:ResponseUri) -and $result[$Script:ResponseUri]) { $script:PSGalleryPublishUri = $result[$Script:ResponseUri] } $repository = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $Script:PSGalleryModuleSource SourceLocation = $psgalleryLocation PublishLocation = $Script:PSGalleryPublishUri ScriptSourceLocation = $scriptSourceLocation ScriptPublishLocation = $Script:PSGalleryPublishUri Trusted=$Trusted Registered=$true InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'} PackageManagementProvider=$script:NuGetProviderName ProviderOptions = @{} }) $repository.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") $script:PSGetModuleSources[$Script:PSGalleryModuleSource] = $repository Save-ModuleSources return $repository } } function Set-ModuleSourcesVariable { [CmdletBinding()] param( [switch] $Force, $Proxy, $ProxyCredential ) if(-not $script:PSGetModuleSources -or $Force) { $isPersistRequired = $false if(Microsoft.PowerShell.Management\Test-Path $script:PSGetModuleSourcesFilePath) { $script:PSGetModuleSources = DeSerialize-PSObject -Path $script:PSGetModuleSourcesFilePath } else { $script:PSGetModuleSources = [ordered]@{} if(-not $script:PSGetModuleSources.Contains($Script:PSGalleryModuleSource)) { $null = Set-PSGalleryRepository -Proxy $Proxy -ProxyCredential $ProxyCredential } } # Already registered repositories may not have the ScriptSourceLocation property, try to populate it from the existing SourceLocation # Also populate the PublishLocation and ScriptPublishLocation from the SourceLocation if PublishLocation is empty/null. # $script:PSGetModuleSources.Keys | Microsoft.PowerShell.Core\ForEach-Object { $moduleSource = $script:PSGetModuleSources[$_] if(-not (Get-Member -InputObject $moduleSource -Name $script:ScriptSourceLocation)) { $scriptSourceLocation = Get-ScriptSourceLocation -Location $moduleSource.SourceLocation -Proxy $Proxy -ProxyCredential $ProxyCredential Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] ` -MemberType NoteProperty ` -Name $script:ScriptSourceLocation ` -Value $scriptSourceLocation if(Get-Member -InputObject $moduleSource -Name $script:PublishLocation) { if(-not $moduleSource.PublishLocation) { $script:PSGetModuleSources[$_].PublishLocation = Get-PublishLocation -Location $moduleSource.SourceLocation } Microsoft.PowerShell.Utility\Add-Member -InputObject $script:PSGetModuleSources[$_] ` -MemberType NoteProperty ` -Name $script:ScriptPublishLocation ` -Value $moduleSource.PublishLocation } $isPersistRequired = $true } } if($isPersistRequired) { Save-ModuleSources } } } function Get-PackageManagementProviderName { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Uri] $Location ) $PackageManagementProviderName = $null $loc = Get-LocationString -LocationUri $Location $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } foreach($provider in $providers) { # Skip the PowerShellGet provider if($provider.ProviderName -eq $script:PSModuleProviderName) { continue } $packageSource = Get-PackageSource -Location $loc -Provider $provider.ProviderName -ErrorAction SilentlyContinue if($packageSource) { $PackageManagementProviderName = $provider.ProviderName break } } return $PackageManagementProviderName } function Get-ProviderName { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [PSCustomObject] $PSCustomObject ) $providerName = $script:NuGetProviderName if((Get-Member -InputObject $PSCustomObject -Name PackageManagementProvider)) { $providerName = $PSCustomObject.PackageManagementProvider } return $providerName } function Get-DynamicParameters { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Uri] $Location, [Parameter(Mandatory=$true)] [REF] $PackageManagementProvider ) $paramDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary $dynamicOptions = $null $loc = Get-LocationString -LocationUri $Location if(-not $loc) { return $paramDictionary } # Ping and resolve the specified location $loc = Resolve-Location -Location $loc ` -LocationParameterName 'Location' ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if(-not $loc) { return $paramDictionary } $providers = PackageManagement\Get-PackageProvider | Where-Object { $_.Features.ContainsKey($script:SupportsPSModulesFeatureName) } if ($PackageManagementProvider.Value) { # Skip the PowerShellGet provider if($PackageManagementProvider.Value -ne $script:PSModuleProviderName) { $SelectedProvider = $providers | Where-Object {$_.ProviderName -eq $PackageManagementProvider.Value} if($SelectedProvider) { $res = Get-PackageSource -Location $loc -Provider $PackageManagementProvider.Value -ErrorAction SilentlyContinue if($res) { $dynamicOptions = $SelectedProvider.DynamicOptions } } } } else { $PackageManagementProvider.Value = Get-PackageManagementProviderName -Location $Location if($PackageManagementProvider.Value) { $provider = $providers | Where-Object {$_.ProviderName -eq $PackageManagementProvider.Value} $dynamicOptions = $provider.DynamicOptions } } foreach ($option in $dynamicOptions) { # Skip the Destination parameter if( $option.IsRequired -and ($option.Name -eq "Destination") ) { continue } $paramAttribute = New-Object System.Management.Automation.ParameterAttribute $paramAttribute.Mandatory = $option.IsRequired $message = $LocalizedData.DynamicParameterHelpMessage -f ($option.Name, $PackageManagementProvider.Value, $loc, $option.Name) $paramAttribute.HelpMessage = $message $attributeCollection = new-object System.Collections.ObjectModel.Collection[System.Attribute] $attributeCollection.Add($paramAttribute) $ageParam = New-Object System.Management.Automation.RuntimeDefinedParameter($option.Name, $script:DynamicOptionTypeMap[$option.Type.value__], $attributeCollection) $paramDictionary.Add($option.Name, $ageParam) } return $paramDictionary } function New-PSGetItemInfo { param ( [Parameter(Mandatory=$true)] $SoftwareIdentity, [Parameter()] $PackageManagementProviderName, [Parameter()] [string] $SourceLocation, [Parameter(Mandatory=$true)] [string] $Type, [Parameter()] [string] $InstalledLocation, [Parameter()] [System.DateTime] $InstalledDate, [Parameter()] [System.DateTime] $UpdatedDate ) foreach($swid in $SoftwareIdentity) { if($SourceLocation) { $sourceName = (Get-SourceName -Location $SourceLocation) } else { # First get the source name from the Metadata # if not exists, get the source name from $swid.Source # otherwise default to $swid.Source $sourceName = (Get-First $swid.Metadata["SourceName"]) if(-not $sourceName) { $sourceName = (Get-SourceName -Location $swid.Source) } if(-not $sourceName) { $sourceName = $swid.Source } $SourceLocation = Get-SourceLocation -SourceName $sourceName } $published = (Get-First $swid.Metadata["published"]) $PublishedDate = New-Object System.DateTime $InstalledDateString = (Get-First $swid.Metadata['installeddate']) if(-not $InstalledDate -and $InstalledDateString) { $InstalledDate = New-Object System.DateTime if(-not (([System.DateTime]::TryParse($InstalledDateString, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None, ([ref]$InstalledDate))) -or ([System.DateTime]::TryParse($InstalledDateString, ([ref]$InstalledDate))))) { $InstalledDate = $null } } $UpdatedDateString = (Get-First $swid.Metadata['updateddate']) if(-not $UpdatedDate -and $UpdatedDateString) { $UpdatedDate = New-Object System.DateTime if(-not (([System.DateTime]::TryParse($UpdatedDateString, [System.Globalization.DateTimeFormatInfo]::InvariantInfo, [System.Globalization.DateTimeStyles]::None, ([ref]$UpdatedDate))) -or ([System.DateTime]::TryParse($UpdatedDateString, ([ref]$UpdatedDate))))) { $UpdatedDate = $null } } $tags = (Get-First $swid.Metadata["tags"]) -split " " $userTags = @() $exportedDscResources = @() $exportedRoleCapabilities = @() $exportedCmdlets = @() $exportedFunctions = @() $exportedWorkflows = @() $exportedCommands = @() $exportedRoleCapabilities += (Get-First $swid.Metadata['RoleCapabilities']) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } $exportedDscResources += (Get-First $swid.Metadata["DscResources"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } $exportedCmdlets += (Get-First $swid.Metadata["Cmdlets"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } $exportedFunctions += (Get-First $swid.Metadata["Functions"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } $exportedWorkflows += (Get-First $swid.Metadata["Workflows"]) -split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } $exportedCommands += $exportedCmdlets + $exportedFunctions + $exportedWorkflows $PSGetFormatVersion = $null ForEach($tag in $tags) { if(-not $tag.Trim()) { continue } $parts = $tag -split "_",2 if($parts.Count -ne 2) { $userTags += $tag continue } Switch($parts[0]) { $script:Command { $exportedCommands += $parts[1]; break } $script:DscResource { $exportedDscResources += $parts[1]; break } $script:Cmdlet { $exportedCmdlets += $parts[1]; break } $script:Function { $exportedFunctions += $parts[1]; break } $script:Workflow { $exportedWorkflows += $parts[1]; break } $script:RoleCapability { $exportedRoleCapabilities += $parts[1]; break } $script:PSGetFormatVersion { $PSGetFormatVersion = $parts[1]; break } $script:Includes { break } Default { $userTags += $tag; break } } } $ArtifactDependencies = @() Foreach ($dependencyString in $swid.Dependencies) { [Uri]$packageId = $null if([Uri]::TryCreate($dependencyString, [System.UriKind]::Absolute, ([ref]$packageId))) { $segments = $packageId.Segments $Version = $null $DependencyName = $null if ($segments) { $DependencyName = [Uri]::UnescapeDataString($segments[0].Trim('/', '\')) $Version = if($segments.Count -gt 1){[Uri]::UnescapeDataString($segments[1])} } $dep = [ordered]@{ Name=$DependencyName } if($Version) { # Required/exact version is represented in NuGet as "[2.0]" if ($Version -match "\[+[0-9.]+\]") { $dep["RequiredVersion"] = $Version.Trim('[', ']') } elseif ($Version -match "\[+[0-9., ]+\]") { # Minimum and Maximum version range is represented in NuGet as "[1.0, 2.0]" $versionRange = $Version.Trim('[', ']') -split ',' | Microsoft.PowerShell.Core\Where-Object {$_} if($versionRange -and $versionRange.count -eq 2) { $dep["MinimumVersion"] = $versionRange[0].Trim() $dep["MaximumVersion"] = $versionRange[1].Trim() } } elseif ($Version -match "\(+[0-9., ]+\]") { # Maximum version is represented in NuGet as "(, 2.0]" $maximumVersion = $Version.Trim('(', ']') -split ',' | Microsoft.PowerShell.Core\Where-Object {$_} if($maximumVersion) { $dep["MaximumVersion"] = $maximumVersion.Trim() } } else { $dep['MinimumVersion'] = $Version } } $dep["CanonicalId"]=$dependencyString $ArtifactDependencies += $dep } } $additionalMetadata = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{}) foreach ( $key in $swid.Metadata.Keys.LocalName) { Microsoft.PowerShell.Utility\Add-Member -InputObject $additionalMetadata ` -MemberType NoteProperty ` -Name $key ` -Value (Get-First $swid.Metadata[$key]) } if (-not (Get-Member -InputObject $additionalMetadata -Name "IsPrerelease") ) { if ($swid.Version -match '-') { Microsoft.PowerShell.Utility\Add-Member -InputObject $additionalMetadata ` -MemberType NoteProperty ` -Name 'IsPrerelease' ` -Value $true } else { Microsoft.PowerShell.Utility\Add-Member -InputObject $additionalMetadata ` -MemberType NoteProperty ` -Name 'IsPrerelease' ` -Value $false } } if(Get-Member -InputObject $additionalMetadata -Name 'ItemType') { $Type = $additionalMetadata.'ItemType' } elseif($userTags -contains 'PSModule') { $Type = $script:PSArtifactTypeModule } elseif($userTags -contains 'PSScript') { $Type = $script:PSArtifactTypeScript } $PSGetItemInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $swid.Name Version = $swid.Version Type = $Type Description = (Get-First $swid.Metadata["description"]) Author = (Get-EntityName -SoftwareIdentity $swid -Role "author") CompanyName = (Get-EntityName -SoftwareIdentity $swid -Role "owner") Copyright = (Get-First $swid.Metadata["copyright"]) PublishedDate = if([System.DateTime]::TryParse($published, ([ref]$PublishedDate))){$PublishedDate}; InstalledDate = $InstalledDate; UpdatedDate = $UpdatedDate; LicenseUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "license") ProjectUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "project") IconUri = (Get-UrlFromSwid -SoftwareIdentity $swid -UrlName "icon") Tags = $userTags Includes = @{ DscResource = $exportedDscResources Command = $exportedCommands Cmdlet = $exportedCmdlets Function = $exportedFunctions Workflow = $exportedWorkflows RoleCapability = $exportedRoleCapabilities } PowerShellGetFormatVersion=[Version]$PSGetFormatVersion ReleaseNotes = (Get-First $swid.Metadata["releaseNotes"]) Dependencies = $ArtifactDependencies RepositorySourceLocation = $SourceLocation Repository = $sourceName PackageManagementProvider = if($PackageManagementProviderName) { $PackageManagementProviderName } else { (Get-First $swid.Metadata["PackageManagementProvider"]) } AdditionalMetadata = $additionalMetadata }) if(-not $InstalledLocation) { $InstalledLocation = (Get-First $swid.Metadata[$script:InstalledLocation]) } if($InstalledLocation) { Microsoft.PowerShell.Utility\Add-Member -InputObject $PSGetItemInfo -MemberType NoteProperty -Name $script:InstalledLocation -Value $InstalledLocation } $PSGetItemInfo.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") $PSGetItemInfo } } function Get-SourceName { [CmdletBinding()] [OutputType("string")] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Location ) Set-ModuleSourcesVariable foreach($psModuleSource in $script:PSGetModuleSources.Values) { if(($psModuleSource.Name -eq $Location) -or ($psModuleSource.SourceLocation -eq $Location) -or ((Get-Member -InputObject $psModuleSource -Name $script:ScriptSourceLocation) -and ($psModuleSource.ScriptSourceLocation -eq $Location))) { return $psModuleSource.Name } } } function Get-SourceLocation { [CmdletBinding()] [OutputType("string")] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $SourceName ) Set-ModuleSourcesVariable if($script:PSGetModuleSources.Contains($SourceName)) { return $script:PSGetModuleSources[$SourceName].SourceLocation } else { return $SourceName } } function Get-UrlFromSwid { param ( [Parameter(Mandatory=$true)] $SoftwareIdentity, [Parameter(Mandatory=$true)] $UrlName ) foreach($link in $SoftwareIdentity.Links) { if( $link.Relationship -eq $UrlName) { return $link.HRef } } return $null } function Get-EntityName { param ( [Parameter(Mandatory=$true)] $SoftwareIdentity, [Parameter(Mandatory=$true)] $Role ) foreach( $entity in $SoftwareIdentity.Entities ) { if( $entity.Role -eq $Role) { $entity.Name } } } function Install-NuGetClientBinaries { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet, [parameter()] [switch] $BootstrapNuGetExe, [Parameter()] $Proxy, [Parameter()] $ProxyCredential, [parameter()] [switch] $Force ) if ($script:NuGetProvider -and (-not $BootstrapNuGetExe -or (($script:NuGetExePath -and (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath)) -or ($script:DotnetCommandPath -and (Microsoft.PowerShell.Management\Test-Path -Path $script:DotnetCommandPath))))) { return } $bootstrapNuGetProvider = (-not $script:NuGetProvider) if($bootstrapNuGetProvider) { # Bootstrap the NuGet provider only if it is not available. # By default PackageManagement loads the latest version of the NuGet provider. $nugetProvider = PackageManagement\Get-PackageProvider -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq $script:NuGetProviderName -and $_.Version -ge $script:NuGetProviderVersion } if($nugetProvider) { $script:NuGetProvider = $nugetProvider $bootstrapNuGetProvider = $false } else { # User might have installed it in an another console or in the same process, check available NuGet providers and import the required provider. $availableNugetProviders = PackageManagement\Get-PackageProvider -Name $script:NuGetProviderName ` -ListAvailable ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq $script:NuGetProviderName -and $_.Version -ge $script:NuGetProviderVersion } if($availableNugetProviders) { # Force import ensures that nuget provider with minimum version got loaded. $null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName ` -MinimumVersion $script:NuGetProviderVersion ` -Force $nugetProvider = PackageManagement\Get-PackageProvider -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object { $_.Name -eq $script:NuGetProviderName -and $_.Version -ge $script:NuGetProviderVersion } if($nugetProvider) { $script:NuGetProvider = $nugetProvider $bootstrapNuGetProvider = $false } } } } if($script:IsWindows -and -not $script:IsNanoServer) { if($BootstrapNuGetExe -and (-not $script:NuGetExePath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath))) { $programDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetProgramDataPath -ChildPath $script:NuGetExeName $applocalDataExePath = Microsoft.PowerShell.Management\Join-Path -Path $script:PSGetAppLocalPath -ChildPath $script:NuGetExeName # Check if NuGet.exe is available under one of the predefined PowerShellGet locations under ProgramData or LocalAppData if(Microsoft.PowerShell.Management\Test-Path -Path $programDataExePath) { $script:NuGetExePath = $programDataExePath $BootstrapNuGetExe = $false } elseif(Microsoft.PowerShell.Management\Test-Path -Path $applocalDataExePath) { $script:NuGetExePath = $applocalDataExePath $BootstrapNuGetExe = $false } else { # Using Get-Command cmdlet, get the location of NuGet.exe if it is available under $env:PATH. # NuGet.exe does not work if it is under $env:WINDIR, so skip it from the Get-Command results. $nugetCmd = Microsoft.PowerShell.Core\Get-Command -Name $script:NuGetExeName ` -ErrorAction Ignore ` -WarningAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object { $_.Path -and ((Microsoft.PowerShell.Management\Split-Path -Path $_.Path -Leaf) -eq $script:NuGetExeName) -and (-not $_.Path.StartsWith($env:windir, [System.StringComparison]::OrdinalIgnoreCase)) } | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if($nugetCmd -and $nugetCmd.Path) { $script:NuGetExePath = $nugetCmd.Path $BootstrapNuGetExe = $false } } } else { # No need to bootstrap the NuGet.exe when $BootstrapNuGetExe is false or NuGet.exe path is already assigned. $BootstrapNuGetExe = $false } } if($BootstrapNuGetExe) { $DotnetCmd = Microsoft.PowerShell.Core\Get-Command -Name $script:DotnetCommandName -ErrorAction Ignore -WarningAction SilentlyContinue | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if ($DotnetCmd -and $DotnetCmd.Path) { $script:DotnetCommandPath = $DotnetCmd.Path $BootstrapNuGetExe = $false } else { if($script:IsWindows) { $DotnetCommandPath = Microsoft.PowerShell.Management\Join-Path -Path $env:LocalAppData -ChildPath Microsoft | Microsoft.PowerShell.Management\Join-Path -ChildPath dotnet | Microsoft.PowerShell.Management\Join-Path -ChildPath dotnet.exe if($DotnetCommandPath -and -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $DotnetCommandPath -PathType Leaf)) { $DotnetCommandPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath dotnet | Microsoft.PowerShell.Management\Join-Path -ChildPath dotnet.exe } } else { $DotnetCommandPath = '/usr/local/bin/dotnet' } if($DotnetCommandPath -and (Microsoft.PowerShell.Management\Test-Path -LiteralPath $DotnetCommandPath -PathType Leaf)) { $DotnetCommandVersion,$null = (& $DotnetCommandPath '--version') -split '-',2 if($DotnetCommandVersion -and ($script:MinimumDotnetCommandVersion -le $DotnetCommandVersion)) { $script:DotnetCommandPath = $DotnetCommandPath $BootstrapNuGetExe = $false } } } } # On non-Windows, dotnet should be installed by the user, throw an error if dotnet is not found using above logic. if ($BootstrapNuGetExe -and (-not $script:IsWindows -or $script:IsNanoServer)) { $ThrowError_params = @{ ExceptionName = 'System.InvalidOperationException' ExceptionMessage = ($LocalizedData.CouldNotFindDotnetCommand -f $script:MinimumDotnetCommandVersion, $script:DotnetInstallUrl) ErrorId = 'CouldNotFindDotnetCommand' CallerPSCmdlet = $CallerPSCmdlet ErrorCategory = 'InvalidOperation' } ThrowError @ThrowError_params return } if(-not $bootstrapNuGetProvider -and -not $BootstrapNuGetExe) { return } # We should prompt only once for bootstrapping the NuGet provider and/or NuGet.exe # Should continue message for bootstrapping only NuGet provider $shouldContinueQueryMessage = $LocalizedData.InstallNuGetProviderShouldContinueQuery -f @($script:NuGetProviderVersion,$script:NuGetBinaryProgramDataPath,$script:NuGetBinaryLocalAppDataPath) $shouldContinueCaption = $LocalizedData.InstallNuGetProviderShouldContinueCaption # Should continue message for bootstrapping both NuGet provider and NuGet.exe if($bootstrapNuGetProvider -and $BootstrapNuGetExe) { $shouldContinueQueryMessage = $LocalizedData.InstallNuGetBinariesShouldContinueQuery2 -f @($script:NuGetProviderVersion,$script:NuGetBinaryProgramDataPath,$script:NuGetBinaryLocalAppDataPath, $script:PSGetProgramDataPath, $script:PSGetAppLocalPath) $shouldContinueCaption = $LocalizedData.InstallNuGetBinariesShouldContinueCaption2 } elseif($BootstrapNuGetExe) { # Should continue message for bootstrapping only NuGet.exe $shouldContinueQueryMessage = $LocalizedData.InstallNuGetExeShouldContinueQuery -f ($script:PSGetProgramDataPath, $script:PSGetAppLocalPath) $shouldContinueCaption = $LocalizedData.InstallNuGetExeShouldContinueCaption } $AdditionalParams = Get-ParametersHashtable -Proxy $Proxy -ProxyCredential $ProxyCredential if($Force -or $psCmdlet.ShouldContinue($shouldContinueQueryMessage, $shouldContinueCaption)) { if($bootstrapNuGetProvider) { Write-Verbose -Message $LocalizedData.DownloadingNugetProvider $scope = 'CurrentUser' if(Test-RunningAsElevated) { $scope = 'AllUsers' } # Bootstrap the NuGet provider $null = PackageManagement\Install-PackageProvider -Name $script:NuGetProviderName ` -MinimumVersion $script:NuGetProviderVersion ` -Scope $scope ` -Force @AdditionalParams # Force import ensures that nuget provider with minimum version got loaded. $null = PackageManagement\Import-PackageProvider -Name $script:NuGetProviderName ` -MinimumVersion $script:NuGetProviderVersion ` -Force $nugetProvider = PackageManagement\Get-PackageProvider -Name $script:NuGetProviderName if ($nugetProvider) { $script:NuGetProvider = $nugetProvider } } if($BootstrapNuGetExe -and $script:IsWindows) { Write-Verbose -Message $LocalizedData.DownloadingNugetExe $nugetExeBasePath = $script:PSGetAppLocalPath # if the current process is running with elevated privileges, # install NuGet.exe to $script:PSGetProgramDataPath if(Test-RunningAsElevated) { $nugetExeBasePath = $script:PSGetProgramDataPath } if(-not (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeBasePath)) { $null = Microsoft.PowerShell.Management\New-Item -Path $nugetExeBasePath ` -ItemType Directory -Force ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false -WhatIf:$false } $nugetExeFilePath = Microsoft.PowerShell.Management\Join-Path -Path $nugetExeBasePath -ChildPath $script:NuGetExeName # Download the NuGet.exe from https://nuget.org/NuGet.exe $null = Microsoft.PowerShell.Utility\Invoke-WebRequest -Uri $script:NuGetClientSourceURL ` -OutFile $nugetExeFilePath ` @AdditionalParams if (Microsoft.PowerShell.Management\Test-Path -Path $nugetExeFilePath) { $script:NuGetExePath = $nugetExeFilePath } } } $message = $null $errorId = $null $failedToBootstrapNuGetProvider = $false $failedToBootstrapNuGetExe = $false if($bootstrapNuGetProvider -and -not $script:NuGetProvider) { $failedToBootstrapNuGetProvider = $true $message = $LocalizedData.CouldNotInstallNuGetProvider -f @($script:NuGetProviderVersion) $errorId = 'CouldNotInstallNuGetProvider' } if($BootstrapNuGetExe -and (-not $script:NuGetExePath -or -not (Microsoft.PowerShell.Management\Test-Path -Path $script:NuGetExePath))) { $failedToBootstrapNuGetExe = $true $message = $LocalizedData.CouldNotInstallNuGetExe -f @($script:MinimumDotnetCommandVersion) $errorId = 'CouldNotInstallNuGetExe' } # Change the error id and message if both NuGet provider and NuGet.exe are not installed. if($failedToBootstrapNuGetProvider -and $failedToBootstrapNuGetExe) { $message = $LocalizedData.CouldNotInstallNuGetBinaries2 -f @($script:NuGetProviderVersion) $errorId = 'CouldNotInstallNuGetBinaries' } # Throw the error message if one of the above conditions are met if($message -and $errorId) { ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId $errorId ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } } # Check if current user is running with elevated privileges function Test-RunningAsElevated { [CmdletBinding()] [OutputType([bool])] Param() if(-not $script:IsRunningAsElevatedTested -and $script:IsRunningAsElevated) { if($script:IsWindows) { $wid=[System.Security.Principal.WindowsIdentity]::GetCurrent() $prp=new-object System.Security.Principal.WindowsPrincipal($wid) $adm=[System.Security.Principal.WindowsBuiltInRole]::Administrator $script:IsRunningAsElevated = $prp.IsInRole($adm) } elseif($script:IsCoreCLR) { # Permission models on *nix can be very complex, to the point that you could never possibly guess without simply trying what you need to try; # This is totally different from Windows where you can know what you can or cannot do with/without admin rights. $script:IsRunningAsElevated = $true } $script:IsRunningAsElevatedTested = $true } return $script:IsRunningAsElevated } function Get-EscapedString { [CmdletBinding()] [OutputType([String])] Param ( [Parameter()] [string] $ElementValue ) return [System.Security.SecurityElement]::Escape($ElementValue) } function ValidateAndGet-ScriptDependencies { param( [Parameter(Mandatory=$true)] [string] $Repository, [Parameter(Mandatory=$true)] [PSCustomObject] $DependentScriptInfo, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet, [Parameter()] [PSCredential] $Credential ) $DependenciesDetails = @() # Validate dependent modules $RequiredModuleSpecification = $DependentScriptInfo.RequiredModules if($RequiredModuleSpecification) { ForEach($moduleSpecification in $RequiredModuleSpecification) { $ModuleName = $moduleSpecification.Name $FindModuleArguments = @{ Repository = $Repository Verbose = $VerbosePreference ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' Debug = $DebugPreference } if ($PSBoundParameters.ContainsKey('Credential')) { $FindModuleArguments.Add('Credential',$Credential) } if($DependentScriptInfo.ExternalModuleDependencies -contains $ModuleName) { Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) continue } $FindModuleArguments['Name'] = $ModuleName $ReqModuleInfo = @{} $ReqModuleInfo['Name'] = $ModuleName if($moduleSpecification.Version) { $FindModuleArguments['MinimumVersion'] = $moduleSpecification.Version $ReqModuleInfo['MinimumVersion'] = $moduleSpecification.Version } elseif((Get-Member -InputObject $moduleSpecification -Name RequiredVersion) -and $moduleSpecification.RequiredVersion) { $FindModuleArguments['RequiredVersion'] = $moduleSpecification.RequiredVersion $ReqModuleInfo['RequiredVersion'] = $moduleSpecification.RequiredVersion } if((Get-Member -InputObject $moduleSpecification -Name MaximumVersion) -and $moduleSpecification.MaximumVersion) { # * can be specified in the MaximumVersion of a ModuleSpecification to convey that maximum possible value of that version part. # like 1.0.0.* --> 1.0.0.99999999 # replace * with 99999999, PowerShell core takes care validating the * to be the last character in the version string. $maximumVersion = $moduleSpecification.MaximumVersion -replace '\*','99999999' $FindModuleArguments['MaximumVersion'] = $maximumVersion $ReqModuleInfo['MaximumVersion'] = $maximumVersion } $psgetItemInfo = Find-Module @FindModuleArguments | Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | Microsoft.PowerShell.Utility\Select-Object -Last 1 -ErrorAction Ignore if(-not $psgetItemInfo) { $message = $LocalizedData.UnableToResolveScriptDependency -f ('module', $ModuleName, $DependentScriptInfo.Name, $Repository, 'ExternalModuleDependencies') ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } $DependenciesDetails += $ReqModuleInfo } } # Validate dependent scrips $RequiredScripts = $DependentScriptInfo.RequiredScripts if($RequiredScripts) { ForEach($requiredScript in $RequiredScripts) { $FindScriptArguments = @{ Repository = $Repository Verbose = $VerbosePreference ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' Debug = $DebugPreference } $ReqScriptInfo = @{} if ($PSBoundParameters.ContainsKey('Credential')) { $FindScriptArguments.Add('Credential',$Credential) } if (-not ($requiredScript -match '^(?<ScriptName>[^:]+)(:(?<Version>[^:\s]+))?$')) { $message = $LocalizedData.FailedToParseRequiredScripts -f ($requiredScript) ThrowError ` -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "FailedToParseRequiredScripts" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } $scriptName = $Matches['ScriptName'] if ($DependentScriptInfo.ExternalScriptDependencies -contains $scriptName) { Write-Verbose -Message ($LocalizedData.SkippedScriptDependency -f $scriptName) continue } if ($Matches.Keys -Contains 'Version') { $ReqScriptInfo = ValidateAndGet-NuspecVersionString -Version $Matches['Version'] if($ReqScriptInfo.Keys -Contains 'RequiredVersion') { $FindScriptArguments['RequiredVersion'] = $ReqScriptInfo['RequiredVersion'] } elseif($ReqScriptInfo.Keys -Contains 'MinimumVersion') { $FindScriptArguments['MinimumVersion'] = $ReqScriptInfo['MinimumVersion'] } if($ReqScriptInfo.Keys -Contains 'MaximumVersion') { $FindScriptArguments['MaximumVersion'] = $ReqScriptInfo['MaximumVersion'] } } $ReqScriptInfo['Name'] = $scriptName $FindScriptArguments['Name'] = $scriptName $psgetItemInfo = Find-Script @FindScriptArguments | Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $scriptName} | Microsoft.PowerShell.Utility\Select-Object -Last 1 -ErrorAction Ignore if(-not $psgetItemInfo) { $message = $LocalizedData.UnableToResolveScriptDependency -f ('script', $scriptName, $DependentScriptInfo.Name, $Repository, 'ExternalScriptDependencies') ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } $DependenciesDetails += $ReqScriptInfo } } return $DependenciesDetails } function ValidateAndGet-NuspecVersionString { param( [Parameter(Mandatory=$true)] [string] $Version ) $versionPattern = '^((?<MinRule>[\[\(])?((?<MinVersion>[^:\(\[\)\]\,]+))?((?<Comma>[\,])?(?<MaxVersion>[^:\(\[\)\]\,]+)?)?(?<MaxRule>[\]\)])?)$' $VersionInfo = @{} if ( -not ($Version -match $versionPattern)) { $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ('Invalid Version format', $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } if ($Matches.Keys -Contains 'MinRule' -xor $Matches.Keys -Contains 'MaxRule') { $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ('Minimum and Maximum inclusive/exclusive condition mismatch', $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } if (-not ($Matches.Keys -Contains 'MinVersion' -or $Matches.Keys -Contains 'MaxVersion')) { $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ('No version.', $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } if ((-not ($Matches.Keys -Contains 'MinRule' -and $Matches.Keys -Contains 'MaxRule')) -and $Matches.Keys -Contains 'Comma') { $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ('Invalid version format', $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } if ($Matches.Keys -Contains 'MaxRule' -and -not ($Matches['MaxRule'] -eq ']') ) { $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ('Maximum version condition should be inclusive', $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } if ($Matches.Keys -Contains 'MinVersion' -and $Matches.Keys -Contains 'MaxVersion') { if ($Matches.Keys -Contains 'MinRule' -and $Matches.Keys -Contains 'MaxRule') { if ($Matches['MinRule'] -eq '[') { $VersionInfo['MinimumVersion'] = $Matches['MinVersion'] $VersionInfo['MaximumVersion'] = $Matches['MaxVersion'] } else { $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ('Minimum version condition should be inclusive', $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } } else { $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ('Minimum and Maximum inclusive/exclusive condition mismatch', $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } return $VersionInfo } if ($Matches.Keys -Contains 'MinVersion') { if ($Matches.Keys -Contains 'MinRule' -and $Matches.Keys -Contains 'MaxRule') { if (($Matches['MinRule'] -eq '[') -and ($Matches['MaxRule'] -eq ']')) { $VersionInfo['RequiredVersion'] = $Matches['MinVersion'] return $VersionInfo } } else { $VersionInfo['MinimumVersion'] = $Matches['MinVersion'] return $VersionInfo } $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ("Minimum and Maximum version rules should be inclusive for 'RequiredVersion'", $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } if ($Matches.Keys -Contains 'MaxVersion') { $VersionInfo['MaximumVersion'] = $Matches['MaxVersion'] return $VersionInfo } $message = $LocalizedData.FailedToParseRequiredScriptsVersion -f ("Failed to parse version string", $Version, $LocalizedData.RequiredScriptVersoinFormat) Write-Verbose $message ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveScriptDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } function ValidateAndGet-RequiredModuleDetails { param( [Parameter()] $ModuleManifestRequiredModules, [Parameter()] [PSModuleInfo[]] $RequiredPSModuleInfos, [Parameter(Mandatory=$true)] [string] $Repository, [Parameter(Mandatory=$true)] [PSModuleInfo] $DependentModuleInfo, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet, [Parameter(Mandatory = $false)] [pscredential] $Credential ) $RequiredModuleDetails = @() if(-not $RequiredPSModuleInfos) { return $RequiredModuleDetails } if($ModuleManifestRequiredModules) { ForEach($RequiredModule in $ModuleManifestRequiredModules) { $ModuleName = $null $VersionString = $null $ReqModuleInfo = @{} $FindModuleArguments = @{ Repository = $Repository Verbose = $VerbosePreference ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' Debug = $DebugPreference } if ($PSBoundParameters.ContainsKey('Credential')) { $FindModuleArguments.Add('Credential',$Credential) } # ModuleSpecification case if($RequiredModule.GetType().ToString() -eq 'System.Collections.Hashtable') { $ModuleName = $RequiredModule.ModuleName # Version format in NuSpec: # "[2.0]" --> (== 2.0) Required Version # "2.0" --> (>= 2.0) Minimum Version if($RequiredModule.Keys -Contains "RequiredVersion") { $FindModuleArguments['RequiredVersion'] = $RequiredModule.RequiredVersion $ReqModuleInfo['RequiredVersion'] = $RequiredModule.RequiredVersion } elseif($RequiredModule.Keys -Contains "ModuleVersion") { $FindModuleArguments['MinimumVersion'] = $RequiredModule.ModuleVersion $ReqModuleInfo['MinimumVersion'] = $RequiredModule.ModuleVersion } if($RequiredModule.Keys -Contains 'MaximumVersion' -and $RequiredModule.MaximumVersion) { # * can be specified in the MaximumVersion of a ModuleSpecification to convey that maximum possible value of that version part. # like 1.0.0.* --> 1.0.0.99999999 # replace * with 99999999, PowerShell core takes care validating the * to be the last character in the version string. $maximumVersion = $RequiredModule.MaximumVersion -replace '\*','99999999' $FindModuleArguments['MaximumVersion'] = $maximumVersion $ReqModuleInfo['MaximumVersion'] = $maximumVersion } } else { # Just module name was specified $ModuleName = $RequiredModule.ToString() } if((Get-ExternalModuleDependencies -PSModuleInfo $DependentModuleInfo) -contains $ModuleName) { Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) continue } # Skip this module name if it's name is not in $RequiredPSModuleInfos. # This is required when a ModuleName is part of the NestedModules list of the actual module. # $ModuleName is packaged as part of the actual module When $RequiredPSModuleInfos doesn't contain it's name. if($RequiredPSModuleInfos.Name -notcontains $ModuleName) { continue } $ReqModuleInfo['Name'] = $ModuleName # Add the dependency only if the module is available on the gallery # Otherwise Module installation will fail as all required modules need to be available on # the same Repository $FindModuleArguments['Name'] = $ModuleName $psgetItemInfo = Find-Module @FindModuleArguments | Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | Microsoft.PowerShell.Utility\Select-Object -Last 1 -ErrorAction Ignore if(-not $psgetItemInfo) { $message = $LocalizedData.UnableToResolveModuleDependency -f ($ModuleName, $DependentModuleInfo.Name, $Repository, $ModuleName, $Repository, $ModuleName, $ModuleName) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveModuleDependency" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation } $RequiredModuleDetails += $ReqModuleInfo } } else { # If Import-LocalizedData cmdlet was failed to read the .psd1 contents # use provided $RequiredPSModuleInfos (PSModuleInfo.RequiredModules or PSModuleInfo.NestedModules of the actual dependent module) $FindModuleArguments = @{ Repository = $Repository Verbose = $VerbosePreference ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' Debug = $DebugPreference } if ($PSBoundParameters.ContainsKey('Credential')) { $FindModuleArguments.Add('Credential',$Credential) } ForEach($RequiredModuleInfo in $RequiredPSModuleInfos) { $ModuleName = $requiredModuleInfo.Name if((Get-ExternalModuleDependencies -PSModuleInfo $DependentModuleInfo) -contains $ModuleName) { Write-Verbose -Message ($LocalizedData.SkippedModuleDependency -f $ModuleName) continue } $FindModuleArguments['Name'] = $ModuleName $FindModuleArguments['MinimumVersion'] = $requiredModuleInfo.Version $psgetItemInfo = Find-Module @FindModuleArguments | Microsoft.PowerShell.Core\Where-Object {$_.Name -eq $ModuleName} | Microsoft.PowerShell.Utility\Select-Object -Last 1 -ErrorAction Ignore if(-not $psgetItemInfo) { $message = $LocalizedData.UnableToResolveModuleDependency -f ($ModuleName, $DependentModuleInfo.Name, $Repository, $ModuleName, $Repository, $ModuleName, $ModuleName) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "UnableToResolveModuleDependency" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } $RequiredModuleDetails += @{ Name=$_.Name MinimumVersion=$_.Version } } } return $RequiredModuleDetails } function Get-ExternalModuleDependencies { Param ( [Parameter(Mandatory=$true)] [PSModuleInfo] $PSModuleInfo ) if($PSModuleInfo.PrivateData -and ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and $PSModuleInfo.PrivateData["PSData"] -and ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") -and $PSModuleInfo.PrivateData.PSData['ExternalModuleDependencies'] -and ($PSModuleInfo.PrivateData.PSData['ExternalModuleDependencies'].GetType().ToString() -eq "System.Object[]") ) { return $PSModuleInfo.PrivateData.PSData.ExternalModuleDependencies } } function Get-ModuleDependencies { Param ( [Parameter(Mandatory=$true)] [PSModuleInfo] $PSModuleInfo, [Parameter(Mandatory=$true)] [string] $Repository, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet, [Parameter(Mandatory=$false)] [pscredential] $Credential ) $DependentModuleDetails = @() if($PSModuleInfo.RequiredModules -or $PSModuleInfo.NestedModules) { # PSModuleInfo.RequiredModules doesn't provide the RequiredVersion info from the ModuleSpecification # Reading the contents of module manifest file # to get the RequiredVersion details. $ModuleManifestHashTable = Get-ManifestHashTable -Path $PSModuleInfo.Path if($PSModuleInfo.RequiredModules) { $ModuleManifestRequiredModules = $null if($ModuleManifestHashTable) { $ModuleManifestRequiredModules = $ModuleManifestHashTable.RequiredModules } $ValidateAndGetRequiredModuleDetails_Params = @{ ModuleManifestRequiredModules=$ModuleManifestRequiredModules RequiredPSModuleInfos=$PSModuleInfo.RequiredModules Repository=$Repository DependentModuleInfo=$PSModuleInfo CallerPSCmdlet=$CallerPSCmdlet Verbose=$VerbosePreference Debug=$DebugPreference } if ($PSBoundParameters.ContainsKey('Credential')) { $ValidateAndGetRequiredModuleDetails_Params.Add('Credential',$Credential) } $DependentModuleDetails += ValidateAndGet-RequiredModuleDetails @ValidateAndGetRequiredModuleDetails_Params } if($PSModuleInfo.NestedModules) { $ModuleManifestRequiredModules = $null if($ModuleManifestHashTable) { $ModuleManifestRequiredModules = $ModuleManifestHashTable.NestedModules } # A nested module is be considered as a dependency # 1) whose module base is not under the specified module base OR # 2) whose module base is under the specified module base and it's path doesn't exists # $RequiredPSModuleInfos = $PSModuleInfo.NestedModules | Microsoft.PowerShell.Core\Where-Object { -not $_.ModuleBase.StartsWith($PSModuleInfo.ModuleBase, [System.StringComparison]::OrdinalIgnoreCase) -or -not $_.Path -or -not (Microsoft.PowerShell.Management\Test-Path -LiteralPath $_.Path) } $ValidateAndGetRequiredModuleDetails_Params = @{ ModuleManifestRequiredModules=$ModuleManifestRequiredModules RequiredPSModuleInfos=$RequiredPSModuleInfos Repository=$Repository DependentModuleInfo=$PSModuleInfo CallerPSCmdlet=$CallerPSCmdlet Verbose=$VerbosePreference Debug=$DebugPreference } if ($PSBoundParameters.ContainsKey('Credential')) { $ValidateAndGetRequiredModuleDetails_Params.Add('Credential',$Credential) } $DependentModuleDetails += ValidateAndGet-RequiredModuleDetails @ValidateAndGetRequiredModuleDetails_Params } } return $DependentModuleDetails } function Publish-PSArtifactUtility { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true, ParameterSetName='PublishModule')] [ValidateNotNullOrEmpty()] [PSModuleInfo] $PSModuleInfo, [Parameter(Mandatory=$true, ParameterSetName='PublishScript')] [ValidateNotNullOrEmpty()] [PSCustomObject] $PSScriptInfo, [Parameter(Mandatory=$true, ParameterSetName='PublishModule')] [ValidateNotNullOrEmpty()] [string] $ManifestPath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Destination, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Repository, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $NugetApiKey, [Parameter(Mandatory=$false)] [pscredential] $Credential, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $NugetPackageRoot, [Parameter(ParameterSetName='PublishModule')] [Version] $FormatVersion, [Parameter(ParameterSetName='PublishModule')] [string] $ReleaseNotes, [Parameter(ParameterSetName='PublishModule')] [string[]] $Tags, [Parameter(ParameterSetName='PublishModule')] [Uri] $LicenseUri, [Parameter(ParameterSetName='PublishModule')] [Uri] $IconUri, [Parameter(ParameterSetName='PublishModule')] [Uri] $ProjectUri ) Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet -BootstrapNuGetExe $PSArtifactType = $script:PSArtifactTypeModule $Name = $null $Description = $null $Version = "" $Author = $null $CompanyName = $null $Copyright = $null $requireLicenseAcceptance = "false" if($PSModuleInfo) { $Name = $PSModuleInfo.Name $Description = $PSModuleInfo.Description $Version = $PSModuleInfo.Version $Author = $PSModuleInfo.Author $CompanyName = $PSModuleInfo.CompanyName $Copyright = $PSModuleInfo.Copyright if($PSModuleInfo.PrivateData -and ($PSModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable") -and $PSModuleInfo.PrivateData["PSData"] -and ($PSModuleInfo.PrivateData["PSData"].GetType().ToString() -eq "System.Collections.Hashtable") ) { if( -not $Tags -and $PSModuleInfo.PrivateData.PSData["Tags"]) { $Tags = $PSModuleInfo.PrivateData.PSData.Tags } if( -not $ReleaseNotes -and $PSModuleInfo.PrivateData.PSData["ReleaseNotes"]) { $ReleaseNotes = $PSModuleInfo.PrivateData.PSData.ReleaseNotes } if( -not $LicenseUri -and $PSModuleInfo.PrivateData.PSData["LicenseUri"]) { $LicenseUri = $PSModuleInfo.PrivateData.PSData.LicenseUri } if( -not $IconUri -and $PSModuleInfo.PrivateData.PSData["IconUri"]) { $IconUri = $PSModuleInfo.PrivateData.PSData.IconUri } if( -not $ProjectUri -and $PSModuleInfo.PrivateData.PSData["ProjectUri"]) { $ProjectUri = $PSModuleInfo.PrivateData.PSData.ProjectUri } if ($PSModuleInfo.PrivateData.PSData["Prerelease"]) { $psmoduleInfoPrereleaseString = $PSModuleInfo.PrivateData.PSData.Prerelease if ($psmoduleInfoPrereleaseString -and $psmoduleInfoPrereleaseString.StartsWith("-")) { $Version = [string]$Version + $psmoduleInfoPrereleaseString } else { $Version = [string]$Version + "-" + $psmoduleInfoPrereleaseString } } if($PSModuleInfo.PrivateData.PSData["RequireLicenseAcceptance"]) { $requireLicenseAcceptance = $PSModuleInfo.PrivateData.PSData.requireLicenseAcceptance.ToString().ToLower() if($requireLicenseAcceptance -eq "true") { if($FormatVersion -and ($FormatVersion.Major -lt $script:PSGetRequireLicenseAcceptanceFormatVersion.Major)) { $message = $LocalizedData.requireLicenseAcceptanceNotSupported -f($FormatVersion) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "requireLicenseAcceptanceNotSupported" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidData } if(-not $LicenseUri) { $message = $LocalizedData.LicenseUriNotSpecified ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "LicenseUriNotSpecified" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidData } $LicenseFilePath = Join-PathUtility -Path $NugetPackageRoot -ChildPath 'License.txt' -PathType File if(-not $LicenseFilePath -or -not (Test-Path -Path $LicenseFilePath -PathType Leaf)) { $message = $LocalizedData.LicenseTxtNotFound ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "LicenseTxtNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidData } if((Get-Content -LiteralPath $LicenseFilePath) -eq $null) { $message = $LocalizedData.LicenseTxtEmpty ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "LicenseTxtEmpty" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidData } #RequireLicenseAcceptance is true, License uri and license.txt exist. Bump Up the FormatVersion if(-not $FormatVersion) { $FormatVersion = $script:CurrentPSGetFormatVersion } } elseif($requireLicenseAcceptance -ne "false") { $InvalidValueForRequireLicenseAcceptance = $LocalizedData.InvalidValueBoolean -f ($requireLicenseAcceptance, "requireLicenseAcceptance") Write-Warning -Message $InvalidValueForRequireLicenseAcceptance } } } } else { $PSArtifactType = $script:PSArtifactTypeScript $Name = $PSScriptInfo.Name $Description = $PSScriptInfo.Description $Version = $PSScriptInfo.Version $Author = $PSScriptInfo.Author $CompanyName = $PSScriptInfo.CompanyName $Copyright = $PSScriptInfo.Copyright if($PSScriptInfo.'Tags') { $Tags = $PSScriptInfo.Tags } if($PSScriptInfo.'ReleaseNotes') { $ReleaseNotes = $PSScriptInfo.ReleaseNotes } if($PSScriptInfo.'LicenseUri') { $LicenseUri = $PSScriptInfo.LicenseUri } if($PSScriptInfo.'IconUri') { $IconUri = $PSScriptInfo.IconUri } if($PSScriptInfo.'ProjectUri') { $ProjectUri = $PSScriptInfo.ProjectUri } } # Add PSModule and PSGet format version tags if(-not $Tags) { $Tags = @() } if($FormatVersion) { $Tags += "$($script:PSGetFormatVersion)_$FormatVersion" } $DependentModuleDetails = @() if($PSScriptInfo) { $Tags += "PSScript" if($PSScriptInfo.DefinedCommands) { if($PSScriptInfo.DefinedFunctions) { $Tags += "$($script:Includes)_Function" $Tags += $PSScriptInfo.DefinedFunctions | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } } if($PSScriptInfo.DefinedWorkflows) { $Tags += "$($script:Includes)_Workflow" $Tags += $PSScriptInfo.DefinedWorkflows | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Workflow)_$_" } } $Tags += $PSScriptInfo.DefinedCommands | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } } # Populate the dependencies elements from RequiredModules and RequiredScripts # $ValidateAndGetScriptDependencies_Params = @{ Repository=$Repository DependentScriptInfo=$PSScriptInfo CallerPSCmdlet=$PSCmdlet Verbose=$VerbosePreference Debug=$DebugPreference } if ($PSBoundParameters.ContainsKey('Credential')) { $ValidateAndGetScriptDependencies_Params.Add('Credential',$Credential) } $DependentModuleDetails += ValidateAndGet-ScriptDependencies @ValidateAndGetScriptDependencies_Params } else { $Tags += "PSModule" $ModuleManifestHashTable = Get-ManifestHashTable -Path $ManifestPath if($PSModuleInfo.ExportedCommands.Count) { if($PSModuleInfo.ExportedCmdlets.Count) { $Tags += "$($script:Includes)_Cmdlet" $Tags += $PSModuleInfo.ExportedCmdlets.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Cmdlet)_$_" } #if CmdletsToExport field in manifest file is "*", we suggest the user to include all those cmdlets for best practice if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('CmdletsToExport') -and ($ModuleManifestHashTable.CmdletsToExport -eq "*")) { $WarningMessage = $LocalizedData.ShouldIncludeCmdletsToExport -f ($ManifestPath) Write-Warning -Message $WarningMessage } } if($PSModuleInfo.ExportedFunctions.Count) { $Tags += "$($script:Includes)_Function" $Tags += $PSModuleInfo.ExportedFunctions.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Function)_$_" } if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey('FunctionsToExport') -and ($ModuleManifestHashTable.FunctionsToExport -eq "*")) { $WarningMessage = $LocalizedData.ShouldIncludeFunctionsToExport -f ($ManifestPath) Write-Warning -Message $WarningMessage } } $Tags += $PSModuleInfo.ExportedCommands.Keys | Microsoft.PowerShell.Core\ForEach-Object { "$($script:Command)_$_" } } $dscResourceNames = Get-ExportedDscResources -PSModuleInfo $PSModuleInfo if($dscResourceNames) { $Tags += "$($script:Includes)_DscResource" $Tags += $dscResourceNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:DscResource)_$_" } #If DscResourcesToExport is commented out or "*" is used, we will write-warning if($ModuleManifestHashTable -and ($ModuleManifestHashTable.ContainsKey("DscResourcesToExport") -and $ModuleManifestHashTable.DscResourcesToExport -eq "*") -or -not $ModuleManifestHashTable.ContainsKey("DscResourcesToExport")) { $WarningMessage = $LocalizedData.ShouldIncludeDscResourcesToExport -f ($ManifestPath) Write-Warning -Message $WarningMessage } } $RoleCapabilityNames = Get-AvailableRoleCapabilityName -PSModuleInfo $PSModuleInfo if($RoleCapabilityNames) { $Tags += "$($script:Includes)_RoleCapability" $Tags += $RoleCapabilityNames | Microsoft.PowerShell.Core\ForEach-Object { "$($script:RoleCapability)_$_" } } # Populate the module dependencies elements from RequiredModules and # NestedModules properties of the current PSModuleInfo $GetModuleDependencies_Params = @{ PSModuleInfo=$PSModuleInfo Repository=$Repository CallerPSCmdlet=$PSCmdlet Verbose=$VerbosePreference Debug=$DebugPreference } if ($PSBoundParameters.ContainsKey('Credential')) { $GetModuleDependencies_Params.Add('Credential',$Credential) } $DependentModuleDetails = Get-ModuleDependencies @GetModuleDependencies_Params } $dependencies = @() ForEach($Dependency in $DependentModuleDetails) { $ModuleName = $Dependency.Name $VersionString = $null # Version format in NuSpec: # "[2.0]" --> (== 2.0) Required Version # "2.0" --> (>= 2.0) Minimum Version # # When only MaximumVersion is specified in the ModuleSpecification # (,1.0] = x <= 1.0 # # When both Minimum and Maximum versions are specified in the ModuleSpecification # [1.0,2.0] = 1.0 <= x <= 2.0 if($Dependency.Keys -Contains "RequiredVersion") { $VersionString = "[$($Dependency.RequiredVersion)]" } elseif($Dependency.Keys -Contains 'MinimumVersion' -and $Dependency.Keys -Contains 'MaximumVersion') { $VersionString = "[$($Dependency.MinimumVersion),$($Dependency.MaximumVersion)]" } elseif($Dependency.Keys -Contains 'MaximumVersion') { $VersionString = "(,$($Dependency.MaximumVersion)]" } elseif($Dependency.Keys -Contains 'MinimumVersion') { $VersionString = "$($Dependency.MinimumVersion)" } if ([System.string]::IsNullOrWhiteSpace($VersionString)) { $dependencies += "<dependency id='$($ModuleName)'/>" } else { $dependencies += "<dependency id='$($ModuleName)' version='$($VersionString)' />" } } # Populate the nuspec elements $nuspec = @" <?xml version="1.0"?> <package > <metadata> <id>$(Get-EscapedString -ElementValue "$Name")</id> <version>$($Version)</version> <authors>$(Get-EscapedString -ElementValue "$Author")</authors> <owners>$(Get-EscapedString -ElementValue "$CompanyName")</owners> <description>$(Get-EscapedString -ElementValue "$Description")</description> <releaseNotes>$(Get-EscapedString -ElementValue "$ReleaseNotes")</releaseNotes> <requireLicenseAcceptance>$($requireLicenseAcceptance.ToString())</requireLicenseAcceptance> <copyright>$(Get-EscapedString -ElementValue "$Copyright")</copyright> <tags>$(if($Tags){ Get-EscapedString -ElementValue ($Tags -join ' ')})</tags> $(if($LicenseUri){ "<licenseUrl>$(Get-EscapedString -ElementValue "$LicenseUri")</licenseUrl>" }) $(if($ProjectUri){ "<projectUrl>$(Get-EscapedString -ElementValue "$ProjectUri")</projectUrl>" }) $(if($IconUri){ "<iconUrl>$(Get-EscapedString -ElementValue "$IconUri")</iconUrl>" }) <dependencies> $dependencies </dependencies> </metadata> </package> "@ # When packaging we must build something. # So, we are building an empty assembly called NotUsed, and discarding it. $CsprojContent = @" <Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <AssemblyName>NotUsed</AssemblyName> <Description>Temp project used for creating nupkg file.</Description> <NuspecFile>$Name.nuspec</NuspecFile> <NuspecBasePath>$NugetPackageRoot</NuspecBasePath> <TargetFramework>netcoreapp2.0</TargetFramework> </PropertyGroup> </Project> "@ $NupkgPath = Microsoft.PowerShell.Management\Join-Path -Path $NugetPackageRoot -ChildPath "$Name.$Version.nupkg" $csprojBasePath = $null if($script:DotnetCommandPath) { $csprojBasePath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath ([System.Guid]::NewGuid()) $null = Microsoft.PowerShell.Management\New-Item -Path $csprojBasePath -ItemType Directory -Force -WhatIf:$false -Confirm:$false $NuspecPath = Microsoft.PowerShell.Management\Join-Path -Path $csprojBasePath -ChildPath "$Name.nuspec" $CsprojFilePath = Microsoft.PowerShell.Management\Join-Path -Path $csprojBasePath -ChildPath "$Name.csproj" } else { $NuspecPath = Microsoft.PowerShell.Management\Join-Path -Path $NugetPackageRoot -ChildPath "$Name.nuspec" } $tempErrorFile = $null $tempOutputFile = $null try { # Remove existing nuspec and nupkg files if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf)) { Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf)) { Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } Microsoft.PowerShell.Management\Set-Content -Value $nuspec -Path $NuspecPath -Force -Confirm:$false -WhatIf:$false # Create .nupkg file if($script:DotnetCommandPath) { Microsoft.PowerShell.Management\Set-Content -Value $CsprojContent -Path $CsprojFilePath -Force -Confirm:$false -WhatIf:$false $arguments = @('pack') $arguments += $csprojBasePath $arguments += @('--output',$NugetPackageRoot) $arguments += "/p:StagingPath=$NugetPackageRoot" $output = & $script:DotnetCommandPath $arguments Write-Debug -Message "dotnet pack output: $output" } elseif($script:NuGetExePath) { $output = & $script:NuGetExePath pack $NuspecPath -OutputDirectory $NugetPackageRoot } if(-not (Test-Path -Path $NupkgPath -PathType Leaf)) { $SemanticVersionString = Get-NormalizedVersionString -Version $Version $NupkgPath = Join-PathUtility -Path $NugetPackageRoot -ChildPath "$Name.$($SemanticVersionString).nupkg" -PathType File } if($LASTEXITCODE -or -not $NupkgPath -or -not (Test-Path -Path $NupkgPath -PathType Leaf)) { if($PSArtifactType -eq $script:PSArtifactTypeModule) { $message = $LocalizedData.FailedToCreateCompressedModule -f ($output) $errorId = "FailedToCreateCompressedModule" } else { $message = $LocalizedData.FailedToCreateCompressedScript -f ($output) $errorId = "FailedToCreateCompressedScript" } Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation return } # Publish the .nupkg to gallery $tempErrorFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishError.txt" $tempOutputFile = Microsoft.PowerShell.Management\Join-Path -Path $nugetPackageRoot -ChildPath "TempPublishOutput.txt" $errorMsg = $null $StartProcess_params = @{ RedirectStandardError = $tempErrorFile RedirectStandardOutput = $tempOutputFile NoNewWindow = $true Wait = $true } if($script:DotnetCommandPath) { $StartProcess_params['FilePath'] = $script:DotnetCommandPath $ArgumentList = @('nuget') $ArgumentList += 'push' $ArgumentList += "`"$NupkgPath`"" $ArgumentList += @('--source', "`"$($Destination.TrimEnd('\'))`"") $ArgumentList += @('--api-key', "`"$NugetApiKey`"") } elseif($script:NuGetExePath) { $StartProcess_params['FilePath'] = $script:NuGetExePath $ArgumentList = @('push') $ArgumentList += "`"$NupkgPath`"" $ArgumentList += @('-source', "`"$($Destination.TrimEnd('\'))`"") $ArgumentList += @('-apikey', "`"$NugetApiKey`"") $ArgumentList += '-NonInteractive' } $StartProcess_params['ArgumentList'] = $ArgumentList if($script:IsCoreCLR -and -not $script:IsNanoServer) { $StartProcess_params['WhatIf'] = $false $StartProcess_params['Confirm'] = $false } Microsoft.PowerShell.Management\Start-Process @StartProcess_params if(Test-Path -Path $tempErrorFile -PathType Leaf) { $errorMsg = Microsoft.PowerShell.Management\Get-Content -Path $tempErrorFile -Raw } if($errorMsg) { if(($NugetApiKey -eq 'VSTS') -and ($errorMsg -match 'Cannot prompt for input in non-interactive mode.') ) { $errorMsg = $LocalizedData.RegisterVSTSFeedAsNuGetPackageSource -f ($Destination, $script:VSTSAuthenticatedFeedsDocUrl) } if($PSArtifactType -eq $script:PSArtifactTypeModule) { $message = $LocalizedData.FailedToPublish -f ($Name,$errorMsg) $errorId = "FailedToPublishTheModule" } else { $message = $LocalizedData.FailedToPublishScript -f ($Name,$errorMsg) $errorId = "FailedToPublishTheScript" } Write-Error -Message $message -ErrorId $errorId -Category InvalidOperation } else { if($PSArtifactType -eq $script:PSArtifactTypeModule) { $message = $LocalizedData.PublishedSuccessfully -f ($Name, $Destination, $Name) } else { $message = $LocalizedData.PublishedScriptSuccessfully -f ($Name, $Destination, $Name) } Write-Verbose -Message $message } } finally { if($NupkgPath -and (Test-Path -Path $NupkgPath -PathType Leaf)) { Microsoft.PowerShell.Management\Remove-Item $NupkgPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } if($NuspecPath -and (Test-Path -Path $NuspecPath -PathType Leaf)) { Microsoft.PowerShell.Management\Remove-Item $NuspecPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } if($tempErrorFile -and (Test-Path -Path $tempErrorFile -PathType Leaf)) { Microsoft.PowerShell.Management\Remove-Item $tempErrorFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } if($tempOutputFile -and (Test-Path -Path $tempOutputFile -PathType Leaf)) { Microsoft.PowerShell.Management\Remove-Item $tempOutputFile -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } if($csprojBasePath -and (Test-Path -Path $csprojBasePath -PathType Container)) { Microsoft.PowerShell.Management\Remove-Item -Path $csprojBasePath -Recurse -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } } } function ValidateAndAdd-PSScriptInfoEntry { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [PSCustomObject] $PSScriptInfo, [Parameter(Mandatory=$true)] [string] $PropertyName, [Parameter()] $PropertyValue, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet ) $Value = $PropertyValue $KeyName = $PropertyName # return if $KeyName value is not null in $PSScriptInfo if(-not $value -or -not $KeyName -or (Get-Member -InputObject $PSScriptInfo -Name $KeyName) -and $PSScriptInfo."$KeyName") { return } switch($PropertyName) { # Validate the property value and also use proper key name as users can specify the property name in any case. $script:Version { $KeyName = $script:Version $result = ValidateAndGet-VersionPrereleaseStrings -Version $Value -CallerPSCmdlet $CallerPSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $Version = $result["Version"] $Prerelease = $result["Prerelease"] $fullVersion = $result["FullVersion"] $Value = if ($Prerelease) { $fullVersion } else { $Version } break } $script:Author { $KeyName = $script:Author } $script:Guid { $KeyName = $script:Guid [Guid]$guid = [System.Guid]::Empty if([System.Guid]::TryParse($Value, ([ref]$guid))) { $Value = $guid } else { $message = $LocalizedData.InvalidGuid -f ($Value) ThrowError -ExceptionName 'System.ArgumentException' ` -ExceptionMessage $message ` -ErrorId 'InvalidGuid' ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Value return } break } $script:Description { $KeyName = $script:Description } $script:CompanyName { $KeyName = $script:CompanyName } $script:Copyright { $KeyName = $script:Copyright } $script:Tags { $KeyName = $script:Tags $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} break } $script:LicenseUri { $KeyName = $script:LicenseUri if(-not (Test-WebUri -Uri $Value)) { $message = $LocalizedData.InvalidWebUri -f ($LicenseUri, "LicenseUri") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Value return } $Value = [Uri]$Value } $script:ProjectUri { $KeyName = $script:ProjectUri if(-not (Test-WebUri -Uri $Value)) { $message = $LocalizedData.InvalidWebUri -f ($ProjectUri, "ProjectUri") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Value return } $Value = [Uri]$Value } $script:IconUri { $KeyName = $script:IconUri if(-not (Test-WebUri -Uri $Value)) { $message = $LocalizedData.InvalidWebUri -f ($IconUri, "IconUri") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Value return } $Value = [Uri]$Value } $script:ExternalModuleDependencies { $KeyName = $script:ExternalModuleDependencies $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} } $script:ReleaseNotes { $KeyName = $script:ReleaseNotes } $script:RequiredModules { $KeyName = $script:RequiredModules } $script:RequiredScripts { $KeyName = $script:RequiredScripts $Value = $Value -split ',(?=[^\[^\(]\w(?!\w+[\)\]]))|\s' | Microsoft.PowerShell.Core\Where-Object {$_} } $script:ExternalScriptDependencies { $KeyName = $script:ExternalScriptDependencies $Value = $Value -split '[,\s+]' | Microsoft.PowerShell.Core\Where-Object {$_} } $script:DefinedCommands { $KeyName = $script:DefinedCommands } $script:DefinedFunctions { $KeyName = $script:DefinedFunctions } $script:DefinedWorkflows { $KeyName = $script:DefinedWorkflows } $script:PrivateData { $KeyName = $script:PrivateData } } Microsoft.PowerShell.Utility\Add-Member -InputObject $PSScriptInfo ` -MemberType NoteProperty ` -Name $KeyName ` -Value $Value ` -Force } function Get-ExportedDscResources { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSModuleInfo] $PSModuleInfo ) $dscResources = @() if(-not $script:IsCoreCLR -and (Get-Command -Name Get-DscResource -Module PSDesiredStateConfiguration -ErrorAction Ignore)) { $OldPSModulePath = $env:PSModulePath try { $env:PSModulePath = Join-Path -Path $PSHOME -ChildPath "Modules" $env:PSModulePath = "$env:PSModulePath;$(Split-Path -Path $PSModuleInfo.ModuleBase -Parent)" $dscResources = PSDesiredStateConfiguration\Get-DscResource -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Microsoft.PowerShell.Core\ForEach-Object { if($_.Module -and ($_.Module.Name -eq $PSModuleInfo.Name)) { $_.Name } } } finally { $env:PSModulePath = $OldPSModulePath } } else { $dscResourcesDir = Join-PathUtility -Path $PSModuleInfo.ModuleBase -ChildPath "DscResources" -PathType Directory if(Microsoft.PowerShell.Management\Test-Path $dscResourcesDir) { $dscResources = Microsoft.PowerShell.Management\Get-ChildItem -Path $dscResourcesDir -Directory -Name } } return $dscResources } function Get-AvailableRoleCapabilityName { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [PSModuleInfo] $PSModuleInfo ) $RoleCapabilityNames = @() $RoleCapabilitiesDir = Join-PathUtility -Path $PSModuleInfo.ModuleBase -ChildPath 'RoleCapabilities' -PathType Directory if(Microsoft.PowerShell.Management\Test-Path -Path $RoleCapabilitiesDir -PathType Container) { $RoleCapabilityNames = Microsoft.PowerShell.Management\Get-ChildItem -Path $RoleCapabilitiesDir ` -Name -Filter *.psrc | ForEach-Object {[System.IO.Path]::GetFileNameWithoutExtension($_)} } return $RoleCapabilityNames } function Get-LocationString { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter()] [Uri] $LocationUri ) $LocationString = $null if($LocationUri) { if($LocationUri.Scheme -eq 'file') { $LocationString = $LocationUri.OriginalString } elseif($LocationUri.AbsoluteUri) { $LocationString = $LocationUri.AbsoluteUri } else { $LocationString = $LocationUri.ToString() } } return $LocationString } <# .DESCRIPTION Utility to get the case-sensitive path, if exists. Otherwise, returns the output of Join-Path cmdlet. This is required for getting the case-sensitive paths on non-Windows platforms. #> function Join-PathUtility { param ( [Parameter(Mandatory = $true)] [string] $Path, [Parameter(Mandatory = $false)] [string] $ChildPath, [Parameter(Mandatory = $true)] [string] [ValidateSet('File', 'Directory', 'Any')] $PathType = 'Any' ) $JoinedPath = Microsoft.PowerShell.Management\Join-Path -Path $Path -ChildPath $ChildPath if(Microsoft.PowerShell.Management\Test-Path -Path $Path -PathType Container) { $GetChildItem_params = @{ Path = $Path ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' } if($PathType -eq 'File') { $GetChildItem_params['File'] = $true } elseif($PathType -eq 'Directory') { $GetChildItem_params['Directory'] = $true } $FoundPath = Microsoft.PowerShell.Management\Get-ChildItem @GetChildItem_params | Where-Object {$_.Name -eq $ChildPath} | ForEach-Object {$_.FullName} | Select-Object -First 1 -ErrorAction SilentlyContinue if($FoundPath) { $JoinedPath = $FoundPath } } return $JoinedPath } <# .DESCRIPTION Latest versions of nuget.exe and dotnet command generate the .nupkg file name with semantic version format for the modules/scripts with two part version. For example: package 1.0 --> package.1.0.0.nupkg #> function Get-NormalizedVersionString { param ( [Parameter(Mandatory = $true)] [string] $Version ) [Version]$ParsedVersion = $null if ([System.Version]::TryParse($Version, [ref]$ParsedVersion)) { $Build = $ParsedVersion.Build if ($Build -eq -1) { $Build = 0 } return "$($ParsedVersion.Major).$($ParsedVersion.Minor).$Build" } return $Version } #endregion Utility functions #region PowerShellGet Provider APIs Implementation function Get-PackageProviderName { return $script:PSModuleProviderName } function Get-Feature { Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-Feature')) Write-Output -InputObject (New-Feature $script:SupportsPSModulesFeatureName ) } function Initialize-Provider { Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Initialize-Provider')) } function Get-DynamicOptions { param ( [Microsoft.PackageManagement.MetaProvider.PowerShell.OptionCategory] $category ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Get-DynamicOptions')) Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:PackageManagementProviderParam -ExpectedType String -IsRequired $false) switch($category) { Package { Write-Output -InputObject (New-DynamicOption -Category $category ` -Name $script:PSArtifactType ` -ExpectedType String ` -IsRequired $false ` -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All)) Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Filter -ExpectedType String -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:Tag -ExpectedType StringArray -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name Includes -ExpectedType StringArray -IsRequired $false -PermittedValues $script:IncludeValidSet) Write-Output -InputObject (New-DynamicOption -Category $category -Name DscResource -ExpectedType StringArray -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name RoleCapability -ExpectedType StringArray -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name 'AllowPrereleaseVersions' -ExpectedType Switch -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name Command -ExpectedType StringArray -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name 'AcceptLicense' -ExpectedType Switch -IsRequired $false) } Source { Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:PublishLocation -ExpectedType String -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:ScriptSourceLocation -ExpectedType String -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name $script:ScriptPublishLocation -ExpectedType String -IsRequired $false) } Install { Write-Output -InputObject (New-DynamicOption -Category $category ` -Name $script:PSArtifactType ` -ExpectedType String ` -IsRequired $false ` -PermittedValues @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript, $script:All)) Write-Output -InputObject (New-DynamicOption -Category $category -Name "Scope" -ExpectedType String -IsRequired $false -PermittedValues @("CurrentUser","AllUsers")) Write-Output -InputObject (New-DynamicOption -Category $category -Name 'AllowClobber' -ExpectedType Switch -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name 'SkipPublisherCheck' -ExpectedType Switch -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name "InstallUpdate" -ExpectedType Switch -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name 'NoPathUpdate' -ExpectedType Switch -IsRequired $false) Write-Output -InputObject (New-DynamicOption -Category $category -Name 'AllowPrereleaseVersions' -ExpectedType Switch -IsRequired $false) } } } function Add-PackageSource { [CmdletBinding()] param ( [string] $Name, [string] $Location, [bool] $Trusted ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Add-PackageSource')) if(-not $Name) { return } $Credential = $request.Credential $IsNewModuleSource = $false $Options = $request.Options foreach( $o in $Options.Keys ) { Write-Debug ( "OPTION: {0} => {1}" -f ($o, $Options[$o]) ) } $Proxy = $null if($Options.ContainsKey($script:Proxy)) { $Proxy = $Options[$script:Proxy] if(-not (Test-WebUri -Uri $Proxy)) { $message = $LocalizedData.InvalidWebUri -f ($Proxy, $script:Proxy) ThrowError -ExceptionName 'System.ArgumentException' ` -ExceptionMessage $message ` -ErrorId 'InvalidWebUri' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Proxy } } $ProxyCredential = $null if($Options.ContainsKey($script:ProxyCredential)) { $ProxyCredential = $Options[$script:ProxyCredential] } Set-ModuleSourcesVariable -Force -Proxy $Proxy -ProxyCredential $ProxyCredential if($Options.ContainsKey('IsNewModuleSource')) { $IsNewModuleSource = $Options['IsNewModuleSource'] if($IsNewModuleSource.GetType().ToString() -eq 'System.String') { if($IsNewModuleSource -eq 'false') { $IsNewModuleSource = $false } elseif($IsNewModuleSource -eq 'true') { $IsNewModuleSource = $true } } } $IsUpdatePackageSource = $false if($Options.ContainsKey('IsUpdatePackageSource')) { $IsUpdatePackageSource = $Options['IsUpdatePackageSource'] if($IsUpdatePackageSource.GetType().ToString() -eq 'System.String') { if($IsUpdatePackageSource -eq 'false') { $IsUpdatePackageSource = $false } elseif($IsUpdatePackageSource -eq 'true') { $IsUpdatePackageSource = $true } } } $PublishLocation = $null if($Options.ContainsKey($script:PublishLocation)) { if($Name -eq $Script:PSGalleryModuleSource) { $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('PublishLocation') ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'ParameterIsNotAllowedWithPSGallery' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $PublishLocation } $PublishLocation = $Options[$script:PublishLocation] if(-not (Microsoft.PowerShell.Management\Test-Path $PublishLocation) -and -not (Test-WebUri -uri $PublishLocation)) { $PublishLocationUri = [Uri]$PublishLocation if($PublishLocationUri.Scheme -eq 'file') { $message = $LocalizedData.PathNotFound -f ($PublishLocation) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $PublishLocation } else { $message = $LocalizedData.InvalidWebUri -f ($PublishLocation, "PublishLocation") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $PublishLocation } } } $ScriptSourceLocation = $null if($Options.ContainsKey($script:ScriptSourceLocation)) { if($Name -eq $Script:PSGalleryModuleSource) { $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('ScriptSourceLocation') ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'ParameterIsNotAllowedWithPSGallery' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ScriptSourceLocation } $ScriptSourceLocation = $Options[$script:ScriptSourceLocation] if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptSourceLocation) -and -not (Test-WebUri -uri $ScriptSourceLocation)) { $ScriptSourceLocationUri = [Uri]$ScriptSourceLocation if($ScriptSourceLocationUri.Scheme -eq 'file') { $message = $LocalizedData.PathNotFound -f ($ScriptSourceLocation) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ScriptSourceLocation } else { $message = $LocalizedData.InvalidWebUri -f ($ScriptSourceLocation, "ScriptSourceLocation") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ScriptSourceLocation } } } $ScriptPublishLocation = $null if($Options.ContainsKey($script:ScriptPublishLocation)) { if($Name -eq $Script:PSGalleryModuleSource) { $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('ScriptPublishLocation') ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'ParameterIsNotAllowedWithPSGallery' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ScriptPublishLocation } $ScriptPublishLocation = $Options[$script:ScriptPublishLocation] if(-not (Microsoft.PowerShell.Management\Test-Path $ScriptPublishLocation) -and -not (Test-WebUri -uri $ScriptPublishLocation)) { $ScriptPublishLocationUri = [Uri]$ScriptPublishLocation if($ScriptPublishLocationUri.Scheme -eq 'file') { $message = $LocalizedData.PathNotFound -f ($ScriptPublishLocation) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ScriptPublishLocation } else { $message = $LocalizedData.InvalidWebUri -f ($ScriptPublishLocation, "ScriptPublishLocation") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ScriptPublishLocation } } } $currentSourceObject = $null # Check if Name is already registered if($script:PSGetModuleSources.Contains($Name)) { $currentSourceObject = $script:PSGetModuleSources[$Name] } # Location is not allowed for PSGallery source # However OneGet passes Location value during Set-PackageSource cmdlet, # that's why ensuring that Location value is same as the current SourceLocation # if(($Name -eq $Script:PSGalleryModuleSource) -and $Location -and ((-not $IsUpdatePackageSource) -or ($currentSourceObject -and $currentSourceObject.SourceLocation -ne $Location))) { $message = $LocalizedData.ParameterIsNotAllowedWithPSGallery -f ('Location, NewLocation or SourceLocation') ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'ParameterIsNotAllowedWithPSGallery' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Location } if($Name -eq $Script:PSGalleryModuleSource) { # Add or update the PSGallery repository $repository = Set-PSGalleryRepository -Trusted:$Trusted if($repository) { # return the package source object. Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $repository) } return } if($Location) { # Ping and resolve the specified location $Location = Resolve-Location -Location $Location ` -LocationParameterName 'Location' ` -Credential $Credential ` -Proxy $Proxy ` -ProxyCredential $ProxyCredential ` -CallerPSCmdlet $PSCmdlet } if(-not $Location) { # Above Resolve-Location function throws an error when it is not able to resolve a location return } if(-not (Microsoft.PowerShell.Management\Test-Path -Path $Location) -and -not (Test-WebUri -uri $Location) ) { $LocationUri = [Uri]$Location if($LocationUri.Scheme -eq 'file') { $message = $LocalizedData.PathNotFound -f ($Location) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Location } else { $message = $LocalizedData.InvalidWebUri -f ($Location, "Location") ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Location } } if(Test-WildcardPattern $Name) { $message = $LocalizedData.RepositoryNameContainsWildCards -f ($Name) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "RepositoryNameContainsWildCards" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Name } $LocationString = Get-ValidModuleLocation -LocationString $Location -ParameterName "Location" -Proxy $Proxy -ProxyCredential $ProxyCredential -Credential $Credential # Check if Location is already registered with another Name $existingSourceName = Get-SourceName -Location $LocationString if($existingSourceName -and ($Name -ne $existingSourceName) -and -not $IsNewModuleSource) { $message = $LocalizedData.RepositoryAlreadyRegistered -f ($existingSourceName, $Location, $Name) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "RepositoryAlreadyRegistered" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } if(-not $PublishLocation -and $currentSourceObject -and $currentSourceObject.PublishLocation) { $PublishLocation = $currentSourceObject.PublishLocation } if((-not $ScriptPublishLocation) -and $currentSourceObject -and (Get-Member -InputObject $currentSourceObject -Name $script:ScriptPublishLocation) -and $currentSourceObject.ScriptPublishLocation) { $ScriptPublishLocation = $currentSourceObject.ScriptPublishLocation } if((-not $ScriptSourceLocation) -and $currentSourceObject -and (Get-Member -InputObject $currentSourceObject -Name $script:ScriptSourceLocation) -and $currentSourceObject.ScriptSourceLocation) { $ScriptSourceLocation = $currentSourceObject.ScriptSourceLocation } $IsProviderSpecified = $false; if ($Options.ContainsKey($script:PackageManagementProviderParam)) { $SpecifiedProviderName = $Options[$script:PackageManagementProviderParam] $IsProviderSpecified = $true Write-Verbose ($LocalizedData.SpecifiedProviderName -f $SpecifiedProviderName) if ($SpecifiedProviderName -eq $script:PSModuleProviderName) { $message = $LocalizedData.InvalidPackageManagementProviderValue -f ($SpecifiedProviderName, $script:NuGetProviderName, $script:NuGetProviderName) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidPackageManagementProviderValue" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $SpecifiedProviderName return } } else { $SpecifiedProviderName = $script:NuGetProviderName Write-Verbose ($LocalizedData.ProviderNameNotSpecified -f $SpecifiedProviderName) } $packageSource = $null $selProviders = $request.SelectProvider($SpecifiedProviderName) if(-not $selProviders -and $IsProviderSpecified) { $message = $LocalizedData.SpecifiedProviderNotAvailable -f $SpecifiedProviderName ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "SpecifiedProviderNotAvailable" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $SpecifiedProviderName } # Try with user specified provider or NuGet provider foreach($SelectedProvider in $selProviders) { if($request.IsCanceled) { return } if($SelectedProvider -and $SelectedProvider.Features.ContainsKey($script:SupportsPSModulesFeatureName)) { $NewRequest = $request.CloneRequest( $null, @($LocationString), $request.Credential ) $packageSource = $SelectedProvider.ResolvePackageSources( $NewRequest ) } else { $message = $LocalizedData.SpecifiedProviderDoesnotSupportPSModules -f $SelectedProvider.ProviderName ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "SpecifiedProviderDoesnotSupportPSModules" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $SelectedProvider.ProviderName } if($packageSource) { break } } # Poll other package provider when NuGet provider doesn't resolves the specified location if(-not $packageSource -and -not $IsProviderSpecified) { Write-Verbose ($LocalizedData.PollingPackageManagementProvidersForLocation -f $LocationString) $moduleProviders = $request.SelectProvidersWithFeature($script:SupportsPSModulesFeatureName) foreach($provider in $moduleProviders) { if($request.IsCanceled) { return } # Skip already tried $SpecifiedProviderName and PowerShellGet provider if($provider.ProviderName -eq $SpecifiedProviderName -or $provider.ProviderName -eq $script:PSModuleProviderName) { continue } Write-Verbose ($LocalizedData.PollingSingleProviderForLocation -f ($LocationString, $provider.ProviderName)) $NewRequest = $request.CloneRequest( @{}, @($LocationString), $request.Credential ) $packageSource = $provider.ResolvePackageSources($NewRequest) if($packageSource) { Write-Verbose ($LocalizedData.FoundProviderForLocation -f ($provider.ProviderName, $Location)) $SelectedProvider = $provider break } } } if(-not $packageSource) { $message = $LocalizedData.SpecifiedLocationCannotBeRegistered -f $Location ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "SpecifiedLocationCannotBeRegistered" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $Location } $ProviderOptions = @{} $SelectedProvider.DynamicOptions | Microsoft.PowerShell.Core\ForEach-Object { if($options.ContainsKey($_.Name) ) { $ProviderOptions[$_.Name] = $options[$_.Name] } } # Keep the existing provider options if not specified in Set-PSRepository if($currentSourceObject) { $currentSourceObject.ProviderOptions.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { if (-not $ProviderOptions.ContainsKey($_.Key) ) { $ProviderOptions[$_.Key] = $_.Value } } } if(-not $PublishLocation) { $PublishLocation = Get-PublishLocation -Location $LocationString } # Use the PublishLocation for the scripts when ScriptPublishLocation is not specified by the user if(-not $ScriptPublishLocation) { $ScriptPublishLocation = $PublishLocation # ScriptPublishLocation and PublishLocation should be equal in case of SMB Share or Local directory paths if($Options.ContainsKey($script:ScriptPublishLocation) -and (Microsoft.PowerShell.Management\Test-Path -Path $ScriptPublishLocation)) { if($ScriptPublishLocation -ne $PublishLocation) { $message = $LocalizedData.PublishLocationPathsForModulesAndScriptsShouldBeEqual -f ($LocationString, $ScriptSourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "PublishLocationPathsForModulesAndScriptsShouldBeEqual" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $Location } } } if(-not $ScriptSourceLocation) { $ScriptSourceLocation = Get-ScriptSourceLocation -Location $LocationString -Proxy $Proxy -ProxyCredential $ProxyCredential -Credential $Credential } elseif($Options.ContainsKey($script:ScriptSourceLocation)) { # ScriptSourceLocation and SourceLocation cannot be same for they are URLs # Both should be equal in case of SMB Share or Local directory paths if(Microsoft.PowerShell.Management\Test-Path -Path $ScriptSourceLocation) { if($ScriptSourceLocation -ne $LocationString) { $message = $LocalizedData.SourceLocationPathsForModulesAndScriptsShouldBeEqual -f ($LocationString, $ScriptSourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "SourceLocationPathsForModulesAndScriptsShouldBeEqual" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $Location } } else { if($ScriptSourceLocation -eq $LocationString -and -not ($LocationString.EndsWith('/nuget/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('/nuget/v2/', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('/nuget', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('/nuget/', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('index.json', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('index.json/', [System.StringComparison]::OrdinalIgnoreCase)) ) { $message = $LocalizedData.SourceLocationUrisForModulesAndScriptsShouldBeDifferent -f ($LocationString, $ScriptSourceLocation) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "SourceLocationUrisForModulesAndScriptsShouldBeDifferent" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $Location } } } # no error so we can safely remove the source if($script:PSGetModuleSources.Contains($Name)) { $null = $script:PSGetModuleSources.Remove($Name) } # Add new module source $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $Name SourceLocation = $LocationString PublishLocation = $PublishLocation ScriptSourceLocation = $ScriptSourceLocation ScriptPublishLocation = $ScriptPublishLocation Trusted=$Trusted Registered= (-not $IsNewModuleSource) InstallationPolicy = if($Trusted) {'Trusted'} else {'Untrusted'} PackageManagementProvider = $SelectedProvider.ProviderName ProviderOptions = $ProviderOptions }) #region telemetry - Capture non-PSGallery registrations as telemetry events if ($script:TelemetryEnabled) { Log-NonPSGalleryRegistration -sourceLocation $moduleSource.SourceLocation ` -installationPolicy $moduleSource.InstallationPolicy ` -packageManagementProvider $moduleSource.PackageManagementProvider ` -publishLocation $moduleSource.PublishLocation ` -scriptSourceLocation $moduleSource.ScriptSourceLocation ` -scriptPublishLocation $moduleSource.ScriptPublishLocation ` -operationName PSGET_NONPSGALLERY_REGISTRATION ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue } #endregion $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") # Persist the repositories only when Register-PSRepository cmdlet is used if(-not $IsNewModuleSource) { $script:PSGetModuleSources.Add($Name, $moduleSource) $message = $LocalizedData.RepositoryRegistered -f ($Name, $LocationString) Write-Verbose $message # Persist the module sources Save-ModuleSources } # return the package source object. Write-Output -InputObject (New-PackageSourceFromModuleSource -ModuleSource $moduleSource) } function Resolve-PackageSource { Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Resolve-PackageSource')) Set-ModuleSourcesVariable $SourceName = $request.PackageSources if(-not $SourceName) { $SourceName = "*" } foreach($moduleSourceName in $SourceName) { if($request.IsCanceled) { return } $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $moduleSourceName,$script:wildcardOptions $moduleSourceFound = $false $script:PSGetModuleSources.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object {$wildcardPattern.IsMatch($_.Key)} | Microsoft.PowerShell.Core\ForEach-Object { $moduleSource = $script:PSGetModuleSources[$_.Key] $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource Write-Output -InputObject $packageSource $moduleSourceFound = $true } if(-not $moduleSourceFound) { $sourceName = Get-SourceName -Location $moduleSourceName if($sourceName) { $moduleSource = $script:PSGetModuleSources[$sourceName] $packageSource = New-PackageSourceFromModuleSource -ModuleSource $moduleSource Write-Output -InputObject $packageSource } elseif( -not (Test-WildcardPattern $moduleSourceName)) { $message = $LocalizedData.RepositoryNotFound -f ($moduleSourceName) Write-Error -Message $message -ErrorId "RepositoryNotFound" -Category InvalidOperation -TargetObject $moduleSourceName } } } } function Remove-PackageSource { param ( [string] $Name ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Remove-PackageSource')) Set-ModuleSourcesVariable -Force $ModuleSourcesToBeRemoved = @() foreach ($moduleSourceName in $Name) { if($request.IsCanceled) { return } # Check if $Name contains any wildcards if(Test-WildcardPattern $moduleSourceName) { $message = $LocalizedData.RepositoryNameContainsWildCards -f ($moduleSourceName) Write-Error -Message $message -ErrorId "RepositoryNameContainsWildCards" -Category InvalidOperation -TargetObject $moduleSourceName continue } # Check if the specified module source name is in the registered module sources if(-not $script:PSGetModuleSources.Contains($moduleSourceName)) { $message = $LocalizedData.RepositoryNotFound -f ($moduleSourceName) Write-Error -Message $message -ErrorId "RepositoryNotFound" -Category InvalidOperation -TargetObject $moduleSourceName continue } $ModuleSourcesToBeRemoved += $moduleSourceName $message = $LocalizedData.RepositoryUnregistered -f ($moduleSourceName) Write-Verbose $message } # Remove the module source $ModuleSourcesToBeRemoved | Microsoft.PowerShell.Core\ForEach-Object { $null = $script:PSGetModuleSources.Remove($_) } # Persist the module sources Save-ModuleSources } function Find-Package { [CmdletBinding()] param ( [string[]] $names, [string] $requiredVersion, [string] $minimumVersion, [string] $maximumVersion ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Find-Package')) Set-ModuleSourcesVariable if($RequiredVersion -and $MinimumVersion) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.VersionRangeAndRequiredVersionCannotBeSpecifiedTogether ` -ErrorId "VersionRangeAndRequiredVersionCannotBeSpecifiedTogether" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } if($RequiredVersion -or $MinimumVersion) { if(-not $names -or $names.Count -ne 1 -or (Test-WildcardPattern -Name $names[0])) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.VersionParametersAreAllowedOnlyWithSingleName ` -ErrorId "VersionParametersAreAllowedOnlyWithSingleName" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } } $options = $request.Options foreach( $o in $options.Keys ) { Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) ) } # When using -Name, we don't send PSGet-specific properties to the server - we will filter it ourselves $postFilter = New-Object -TypeName System.Collections.Hashtable if($options.ContainsKey("Name")) { if($options.ContainsKey("Includes")) { $postFilter["Includes"] = $options["Includes"] $null = $options.Remove("Includes") } if($options.ContainsKey("DscResource")) { $postFilter["DscResource"] = $options["DscResource"] $null = $options.Remove("DscResource") } if($options.ContainsKey('RoleCapability')) { $postFilter['RoleCapability'] = $options['RoleCapability'] $null = $options.Remove('RoleCapability') } if($options.ContainsKey("Command")) { $postFilter["Command"] = $options["Command"] $null = $options.Remove("Command") } } $LocationOGPHashtable = [ordered]@{} if($options -and $options.ContainsKey('Source')) { $SourceNames = $($options['Source']) Write-Verbose ($LocalizedData.SpecifiedSourceName -f ($SourceNames)) foreach($sourceName in $SourceNames) { if($script:PSGetModuleSources.Contains($sourceName)) { $ModuleSource = $script:PSGetModuleSources[$sourceName] $LocationOGPHashtable[$ModuleSource.SourceLocation] = (Get-ProviderName -PSCustomObject $ModuleSource) } else { $sourceByLocation = Get-SourceName -Location $sourceName if ($sourceByLocation) { $ModuleSource = $script:PSGetModuleSources[$sourceByLocation] $LocationOGPHashtable[$ModuleSource.SourceLocation] = (Get-ProviderName -PSCustomObject $ModuleSource) } else { $message = $LocalizedData.RepositoryNotFound -f ($sourceName) Write-Error -Message $message ` -ErrorId 'RepositoryNotFound' ` -Category InvalidArgument ` -TargetObject $sourceName } } } } elseif($options -and $options.ContainsKey($script:PackageManagementProviderParam) -and $options.ContainsKey('Location')) { $Location = $options['Location'] $PackageManagementProvider = $options['PackageManagementProvider'] Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($Location, $PackageManagementProvider)) $LocationOGPHashtable[$Location] = $PackageManagementProvider } else { Write-Verbose $LocalizedData.NoSourceNameIsSpecified $script:PSGetModuleSources.Values | Microsoft.PowerShell.Core\ForEach-Object { $LocationOGPHashtable[$_.SourceLocation] = (Get-ProviderName -PSCustomObject $_) } } $artifactTypes = $script:PSArtifactTypeModule if($options.ContainsKey($script:PSArtifactType)) { $artifactTypes = $options[$script:PSArtifactType] } if($artifactTypes -eq $script:All) { $artifactTypes = @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript) } $providerOptions = @{} if($options.ContainsKey($script:AllVersions)) { $providerOptions[$script:AllVersions] = $options[$script:AllVersions] } if ($options.Contains($script:AllowPrereleaseVersions)) { $providerOptions[$script:AllowPrereleaseVersions] = $options[$script:AllowPrereleaseVersions] } if($options.ContainsKey($script:Filter)) { $Filter = $options[$script:Filter] $providerOptions['Contains'] = $Filter } if($options.ContainsKey($script:Tag)) { $userSpecifiedTags = $options[$script:Tag] | Microsoft.PowerShell.Utility\Select-Object -Unique -ErrorAction Ignore } else { $userSpecifiedTags = @($script:NotSpecified) } $specifiedDscResources = @() if($options.ContainsKey('DscResource')) { $specifiedDscResources = $options['DscResource'] | Microsoft.PowerShell.Utility\Select-Object -Unique -ErrorAction Ignore | Microsoft.PowerShell.Core\ForEach-Object {"$($script:DscResource)_$_"} } $specifiedRoleCapabilities = @() if($options.ContainsKey('RoleCapability')) { $specifiedRoleCapabilities = $options['RoleCapability'] | Microsoft.PowerShell.Utility\Select-Object -Unique -ErrorAction Ignore | Microsoft.PowerShell.Core\ForEach-Object {"$($script:RoleCapability)_$_"} } $specifiedCommands = @() if($options.ContainsKey('Command')) { $specifiedCommands = $options['Command'] | Microsoft.PowerShell.Utility\Select-Object -Unique -ErrorAction Ignore | Microsoft.PowerShell.Core\ForEach-Object {"$($script:Command)_$_"} } $specifiedIncludes = @() if($options.ContainsKey('Includes')) { $includes = $options['Includes'] | Microsoft.PowerShell.Utility\Select-Object -Unique -ErrorAction Ignore | Microsoft.PowerShell.Core\ForEach-Object {"$($script:Includes)_$_"} # Add PSIncludes_DscResource to $specifiedIncludes iff -DscResource names are not specified # Add PSIncludes_RoleCapability to $specifiedIncludes iff -RoleCapability names are not specified # Add PSIncludes_Cmdlet or PSIncludes_Function to $specifiedIncludes iff -Command names are not specified # otherwise $script:NotSpecified will be added to $specifiedIncludes if($includes) { if(-not $specifiedDscResources -and ($includes -contains "$($script:Includes)_DscResource") ) { $specifiedIncludes += "$($script:Includes)_DscResource" } if(-not $specifiedRoleCapabilities -and ($includes -contains "$($script:Includes)_RoleCapability") ) { $specifiedIncludes += "$($script:Includes)_RoleCapability" } if(-not $specifiedCommands) { if($includes -contains "$($script:Includes)_Cmdlet") { $specifiedIncludes += "$($script:Includes)_Cmdlet" } if($includes -contains "$($script:Includes)_Function") { $specifiedIncludes += "$($script:Includes)_Function" } if($includes -contains "$($script:Includes)_Workflow") { $specifiedIncludes += "$($script:Includes)_Workflow" } } } } if(-not $specifiedDscResources) { $specifiedDscResources += $script:NotSpecified } if(-not $specifiedRoleCapabilities) { $specifiedRoleCapabilities += $script:NotSpecified } if(-not $specifiedCommands) { $specifiedCommands += $script:NotSpecified } if(-not $specifiedIncludes) { $specifiedIncludes += $script:NotSpecified } $providerSearchTags = @{} foreach($tag in $userSpecifiedTags) { foreach($include in $specifiedIncludes) { foreach($command in $specifiedCommands) { foreach($resource in $specifiedDscResources) { foreach($roleCapability in $specifiedRoleCapabilities) { $providerTags = @() if($resource -ne $script:NotSpecified) { $providerTags += $resource } if($roleCapability -ne $script:NotSpecified) { $providerTags += $roleCapability } if($command -ne $script:NotSpecified) { $providerTags += $command } if($include -ne $script:NotSpecified) { $providerTags += $include } if($tag -ne $script:NotSpecified) { $providerTags += $tag } if($providerTags) { $providerSearchTags["$tag $resource $roleCapability $command $include"] = $providerTags } } } } } } $InstallationPolicy = "Untrusted" if($options.ContainsKey('InstallationPolicy')) { $InstallationPolicy = $options['InstallationPolicy'] } $streamedResults = @() foreach($artifactType in $artifactTypes) { foreach($kvPair in $LocationOGPHashtable.GetEnumerator()) { if($request.IsCanceled) { return } $Location = $kvPair.Key if($artifactType -eq $script:PSArtifactTypeScript) { $sourceName = Get-SourceName -Location $Location if($SourceName) { $ModuleSource = $script:PSGetModuleSources[$SourceName] # Skip source if no ScriptSourceLocation is available. if(-not $ModuleSource.ScriptSourceLocation) { if($options.ContainsKey('Source')) { $message = $LocalizedData.ScriptSourceLocationIsMissing -f ($ModuleSource.Name) Write-Error -Message $message ` -ErrorId 'ScriptSourceLocationIsMissing' ` -Category InvalidArgument ` -TargetObject $ModuleSource.Name } continue } $Location = $ModuleSource.ScriptSourceLocation } } $ProviderName = $kvPair.Value Write-Verbose ($LocalizedData.GettingPackageManagementProviderObject -f ($ProviderName)) $provider = $request.SelectProvider($ProviderName) if(-not $provider) { Write-Error -Message ($LocalizedData.PackageManagementProviderIsNotAvailable -f $ProviderName) Continue } Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($Location, $provider.ProviderName)) if($providerSearchTags.Values.Count) { $tagList = $providerSearchTags.Values } else { $tagList = @($script:NotSpecified) } $namesParameterEmpty = ($names.Count -eq 1) -and ($names[0] -eq '') foreach($providerTag in $tagList) { if($request.IsCanceled) { return } $FilterOnTag = @() if($providerTag -ne $script:NotSpecified) { $FilterOnTag = $providerTag } if(Microsoft.PowerShell.Management\Test-Path -Path $Location) { if($artifactType -eq $script:PSArtifactTypeScript) { $FilterOnTag += 'PSScript' } elseif($artifactType -eq $script:PSArtifactTypeModule) { $FilterOnTag += 'PSModule' } } if($FilterOnTag) { $providerOptions["FilterOnTag"] = $FilterOnTag } elseif($providerOptions.ContainsKey('FilterOnTag')) { $null = $providerOptions.Remove('FilterOnTag') } if($request.Options.ContainsKey($script:FindByCanonicalId)) { $providerOptions[$script:FindByCanonicalId] = $request.Options[$script:FindByCanonicalId] } $providerOptions["Headers"] = 'PSGalleryClientVersion=1.1' $NewRequest = $request.CloneRequest( $providerOptions, @($Location), $request.Credential ) $pkgs = $provider.FindPackages($names, $requiredVersion, $minimumVersion, $maximumVersion, $NewRequest ) foreach($pkg in $pkgs) { if($request.IsCanceled) { return } # $pkg.Name has to match any of the supplied names, using PowerShell wildcards if ($namesParameterEmpty -or ($names | % { if ($pkg.Name -like $_){return $true; break} } -End {return $false})) { $includePackage = $true # If -Name was provided, we need to post-filter # Filtering has AND semantics between different parameters and OR within a parameter (each parameter is potentially an array) if($options.ContainsKey("Name") -and $postFilter.Count -gt 0) { if ($pkg.Metadata["DscResources"].Count -gt 0) { $pkgDscResources = $pkg.Metadata["DscResources"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } } else { $pkgDscResources = $pkg.Metadata["tags"] -Split " " ` | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:DscResource, [System.StringComparison]::OrdinalIgnoreCase) } ` | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:DscResource.Length + 1) } } if ($pkg.Metadata['RoleCapabilities'].Count -gt 0) { $pkgRoleCapabilities = $pkg.Metadata['RoleCapabilities'] -Split ' ' | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } } else { $pkgRoleCapabilities = $pkg.Metadata["tags"] -Split ' ' ` | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:RoleCapability, [System.StringComparison]::OrdinalIgnoreCase) } ` | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:RoleCapability.Length + 1) } } if ($pkg.Metadata["Functions"].Count -gt 0) { $pkgFunctions = $pkg.Metadata["Functions"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } } else { $pkgFunctions = $pkg.Metadata["tags"] -Split " " ` | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Function, [System.StringComparison]::OrdinalIgnoreCase) } ` | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Function.Length + 1) } } if ($pkg.Metadata["Cmdlets"].Count -gt 0) { $pkgCmdlets = $pkg.Metadata["Cmdlets"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } } else { $pkgCmdlets = $pkg.Metadata["tags"] -Split " " ` | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Cmdlet, [System.StringComparison]::OrdinalIgnoreCase) } ` | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Cmdlet.Length + 1) } } if ($pkg.Metadata["Workflows"].Count -gt 0) { $pkgWorkflows = $pkg.Metadata["Workflows"] -Split " " | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } } else { $pkgWorkflows = $pkg.Metadata["tags"] -Split " " ` | Microsoft.PowerShell.Core\Where-Object { $_.Trim() } ` | Microsoft.PowerShell.Core\Where-Object { $_.StartsWith($script:Workflow, [System.StringComparison]::OrdinalIgnoreCase) } ` | Microsoft.PowerShell.Core\ForEach-Object { $_.Substring($script:Workflow.Length + 1) } } foreach ($key in $postFilter.Keys) { switch ($key) { "DscResource" { $values = $postFilter[$key] $includePackage = $false foreach ($value in $values) { $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions $pkgDscResources | Microsoft.PowerShell.Core\ForEach-Object { if ($wildcardPattern.IsMatch($_)) { $includePackage = $true break } } } if (-not $includePackage) { break } } 'RoleCapability' { $values = $postFilter[$key] $includePackage = $false foreach ($value in $values) { $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions $pkgRoleCapabilities | Microsoft.PowerShell.Core\ForEach-Object { if ($wildcardPattern.IsMatch($_)) { $includePackage = $true break } } } if (-not $includePackage) { break } } "Command" { $values = $postFilter[$key] $includePackage = $false foreach ($value in $values) { $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $value,$script:wildcardOptions $pkgFunctions | Microsoft.PowerShell.Core\ForEach-Object { if ($wildcardPattern.IsMatch($_)) { $includePackage = $true break } } $pkgCmdlets | Microsoft.PowerShell.Core\ForEach-Object { if ($wildcardPattern.IsMatch($_)) { $includePackage = $true break } } $pkgWorkflows | Microsoft.PowerShell.Core\ForEach-Object { if ($wildcardPattern.IsMatch($_)) { $includePackage = $true break } } } if (-not $includePackage) { break } } "Includes" { $values = $postFilter[$key] $includePackage = $false foreach ($value in $values) { switch ($value) { "Cmdlet" { if ($pkgCmdlets ) { $includePackage = $true } } "Function" { if ($pkgFunctions ) { $includePackage = $true } } "DscResource" { if ($pkgDscResources ) { $includePackage = $true } } "RoleCapability" { if ($pkgRoleCapabilities ) { $includePackage = $true } } "Workflow" { if ($pkgWorkflows ) { $includePackage = $true } } } } if (-not $includePackage) { break } } } } } if ($includePackage) { $fastPackageReference = New-FastPackageReference -ProviderName $provider.ProviderName ` -PackageName $pkg.Name ` -Version $pkg.Version ` -Source $Location ` -ArtifactType $artifactType if($streamedResults -notcontains $fastPackageReference) { $streamedResults += $fastPackageReference $FromTrustedSource = $false $ModuleSourceName = Get-SourceName -Location $Location if($ModuleSourceName) { $FromTrustedSource = $script:PSGetModuleSources[$ModuleSourceName].Trusted } elseif($InstallationPolicy -eq "Trusted") { $FromTrustedSource = $true } $sid = New-SoftwareIdentityFromPackage -Package $pkg ` -PackageManagementProviderName $provider.ProviderName ` -SourceLocation $Location ` -IsFromTrustedSource:$FromTrustedSource ` -Type $artifactType ` -request $request $script:FastPackRefHashtable[$fastPackageReference] = $pkg Write-Output -InputObject $sid } } } } } } } } function Download-Package { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $FastPackageReference, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Location ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Download-Package')) Install-PackageUtility -FastPackageReference $FastPackageReference -Request $Request -Location $Location } function Install-Package { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $FastPackageReference ) Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Install-Package')) Install-PackageUtility -FastPackageReference $FastPackageReference -Request $Request } function Install-PackageUtility { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $FastPackageReference, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Location, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] $request ) Set-ModuleSourcesVariable Write-Debug ($LocalizedData.ProviderApiDebugMessage -f ('Install-PackageUtility')) Write-Debug ($LocalizedData.FastPackageReference -f $fastPackageReference) $Force = $false $SkipPublisherCheck = $false $AllowClobber = $false $Debug = $false $MinimumVersion = "" $RequiredVersion = "" $IsSavePackage = $false $Scope = $null $NoPathUpdate = $false $AcceptLicense = $false # take the fastPackageReference and get the package object again. $parts = $fastPackageReference -Split '[|]' if( $parts.Length -eq 5 ) { $providerName = $parts[0] $packageName = $parts[1] $version = $parts[2] $sourceLocation= $parts[3] $artifactType = $parts[4] $result = ValidateAndGet-VersionPrereleaseStrings -Version $version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $galleryItemVersion = $result["Version"] $galleryItemPrerelease = $result["Prerelease"] $galleryItemFullVersion = $result["FullVersion"] # The default destination location for Modules and Scripts is ProgramFiles path $scriptDestination = $script:ProgramFilesScriptsPath $moduleDestination = $script:programFilesModulesPath $Scope = 'AllUsers' if($artifactType -eq $script:PSArtifactTypeScript) { $AdminPrivilegeErrorMessage = $LocalizedData.InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) $AdminPrivilegeErrorId = 'InstallScriptNeedsCurrentUserScopeParameterForNonAdminUser' } else { $AdminPrivilegeErrorMessage = $LocalizedData.InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser -f @($script:programFilesModulesPath, $script:MyDocumentsModulesPath) $AdminPrivilegeErrorId = 'InstallModuleNeedsCurrentUserScopeParameterForNonAdminUser' } $installUpdate = $false $options = $request.Options if($options) { foreach( $o in $options.Keys ) { Write-Debug ("OPTION: {0} => {1}" -f ($o, $request.Options[$o]) ) } if($options.ContainsKey('Scope')) { $Scope = $options['Scope'] Write-Verbose ($LocalizedData.SpecifiedInstallationScope -f $Scope) if($Scope -eq "CurrentUser") { $scriptDestination = $script:MyDocumentsScriptsPath $moduleDestination = $script:MyDocumentsModulesPath } elseif($Scope -eq "AllUsers") { $scriptDestination = $script:ProgramFilesScriptsPath $moduleDestination = $script:programFilesModulesPath if(-not (Test-RunningAsElevated)) { # Throw an error when Install-Module/Script is used as a non-admin user and '-Scope CurrentUser' is not specified ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $AdminPrivilegeErrorMessage ` -ErrorId $AdminPrivilegeErrorId ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } } } elseif($Location) { $IsSavePackage = $true $Scope = $null $moduleDestination = $Location $scriptDestination = $Location } # if no scope and no destination path and not elevated, then raise an error elseif(-not (Test-RunningAsElevated)) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $AdminPrivilegeErrorMessage ` -ErrorId $AdminPrivilegeErrorId ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } if($options.ContainsKey('SkipPublisherCheck')) { $SkipPublisherCheck = $options['SkipPublisherCheck'] if($SkipPublisherCheck.GetType().ToString() -eq 'System.String') { if($SkipPublisherCheck -eq 'true') { $SkipPublisherCheck = $true } else { $SkipPublisherCheck = $false } } } if($options.ContainsKey('AllowClobber')) { $AllowClobber = $options['AllowClobber'] if($AllowClobber.GetType().ToString() -eq 'System.String') { if($AllowClobber -eq 'false') { $AllowClobber = $false } elseif($AllowClobber -eq 'true') { $AllowClobber = $true } } } if($options.ContainsKey('Force')) { $Force = $options['Force'] if($Force.GetType().ToString() -eq 'System.String') { if($Force -eq 'false') { $Force = $false } elseif($Force -eq 'true') { $Force = $true } } } if($options.ContainsKey('AcceptLicense')) { $AcceptLicense = $options['AcceptLicense'] if($AcceptLicense.GetType().ToString() -eq 'System.String') { if($AcceptLicense -eq 'false') { $AcceptLicense = $false } elseif($AcceptLicense -eq 'true') { $AcceptLicense = $true } } } if($options.ContainsKey('Debug')) { $Debug = $options['Debug'] if($Debug.GetType().ToString() -eq 'System.String') { if($Debug -eq 'false') { $Debug = $false } elseif($Debug -eq 'true') { $Debug = $true } } } if($options.ContainsKey('NoPathUpdate')) { $NoPathUpdate = $options['NoPathUpdate'] if($NoPathUpdate.GetType().ToString() -eq 'System.String') { if($NoPathUpdate -eq 'false') { $NoPathUpdate = $false } elseif($NoPathUpdate -eq 'true') { $NoPathUpdate = $true } } } if($options.ContainsKey('MinimumVersion')) { $MinimumVersion = $options['MinimumVersion'] } if($options.ContainsKey('RequiredVersion')) { $RequiredVersion = $options['RequiredVersion'] } if($options.ContainsKey('InstallUpdate')) { $installUpdate = $options['InstallUpdate'] if($installUpdate.GetType().ToString() -eq 'System.String') { if($installUpdate -eq 'false') { $installUpdate = $false } elseif($installUpdate -eq 'true') { $installUpdate = $true } } } if($Scope -and ($artifactType -eq $script:PSArtifactTypeScript) -and (-not $installUpdate)) { ValidateAndSet-PATHVariableIfUserAccepts -Scope $Scope ` -ScopePath $scriptDestination ` -Request $request ` -NoPathUpdate:$NoPathUpdate ` -Force:$Force } if($artifactType -eq $script:PSArtifactTypeModule) { $message = $LocalizedData.ModuleDestination -f @($moduleDestination) } else { $message = $LocalizedData.ScriptDestination -f @($scriptDestination, $moduleDestination) } Write-Verbose $message } Write-Debug "ArtifactType is $artifactType" if($artifactType -eq $script:PSArtifactTypeModule) { # Test if module is already installed $InstalledModuleInfo = if(-not $IsSavePackage){ Test-ModuleInstalled -Name $packageName -RequiredVersion $RequiredVersion } if(-not $Force -and $InstalledModuleInfo) { $installedModPrerelease = $null if ((Get-Member -InputObject $InstalledModuleInfo -Name PrivateData -ErrorAction SilentlyContinue) -and ` $InstalledModuleInfo.PrivateData -and ` $InstalledModuleInfo.PrivateData.GetType().ToString() -eq "System.Collections.Hashtable" -and ` ($InstalledModuleInfo.PrivateData.ContainsKey('PSData')) -and ` $InstalledModuleInfo.PrivateData.PSData.GetType().ToString() -eq "System.Collections.Hashtable" -and ` ($InstalledModuleInfo.PrivateData.PSData.ContainsKey('Prerelease'))) { $installedModPrerelease = $InstalledModuleInfo.PrivateData.PSData.Prerelease } $result = ValidateAndGet-VersionPrereleaseStrings -Version $InstalledModuleInfo.Version -Prerelease $installedModPrerelease -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $installedModuleVersion = $result["Version"] $installedModulePrerelease = $result["Prerelease"] $installedModuleFullVersion = $result["FullVersion"] if($RequiredVersion -and (Test-ModuleSxSVersionSupport)) { # Check if the module with the required version is already installed otherwise proceed to install/update. if($InstalledModuleInfo) { $message = $LocalizedData.ModuleWithRequiredVersionAlreadyInstalled -f ($InstalledModuleInfo.Version, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $InstalledModuleInfo.Version) Write-Error -Message $message -ErrorId "ModuleWithRequiredVersionAlreadyInstalled" -Category InvalidOperation return } } else { if(-not $installUpdate) { if ($MinimumVersion) { $result = ValidateAndGet-VersionPrereleaseStrings -Version $MinimumVersion -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $minVersion = $result["Version"] $minPrerelease = $result["Prerelease"] $minFullVersion = $result["FullVersion"] } else { $minVersion = $null $minPrerelease = $null $minFullVersion = $null } if( (-not $MinimumVersion -and ($galleryItemFullVersion -ne $InstalledModuleFullVersion)) -or ($MinimumVersion -and (Compare-PrereleaseVersions -FirstItemVersion $installedModuleVersion ` -FirstItemPrerelease $installedModulePrerelease ` -SecondItemVersion $minVersion ` -SecondItemPrerelease $minPrerelease))) { if($PSVersionTable.PSVersion -ge '5.0.0') { $message = $LocalizedData.ModuleAlreadyInstalledSxS -f ($InstalledModuleFullVersion, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $galleryItemFullVersion, $InstalledModuleFullVersion, $galleryItemFullVersion) } else { $message = $LocalizedData.ModuleAlreadyInstalled -f ($InstalledModuleFullVersion, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase, $InstalledModuleFullVersion, $galleryItemFullVersion) } Write-Error -Message $message -ErrorId "ModuleAlreadyInstalled" -Category InvalidOperation } else { $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleFullVersion, $InstalledModuleInfo.Name, $InstalledModuleInfo.ModuleBase) Write-Verbose $message } return } else { if (Compare-PrereleaseVersions -FirstItemVersion $installedModuleVersion ` -FirstItemPrerelease $installedModulePrerelease ` -SecondItemVersion $galleryItemVersion.ToString() ` -SecondItemPrerelease $galleryItemPrerelease) { $message = $LocalizedData.FoundModuleUpdate -f ($InstalledModuleInfo.Name, $galleryItemFullVersion) Write-Verbose $message } else { $message = $LocalizedData.NoUpdateAvailable -f ($InstalledModuleInfo.Name) Write-Verbose $message return } } } } } if($artifactType -eq $script:PSArtifactTypeScript) { # Test if script is already installed $InstalledScriptInfo = if(-not $IsSavePackage){ Test-ScriptInstalled -Name $packageName } Write-Debug "InstalledScriptInfo is $InstalledScriptInfo" if(-not $Force -and $InstalledScriptInfo) { $result = ValidateAndGet-VersionPrereleaseStrings -Version $InstalledScriptInfo.Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $installedScriptInfoVersion = $result["Version"] $installedScriptInfoPrerelease = $result["Prerelease"] $installedScriptFullVersion = $result["FullVersion"] if(-not $installUpdate) { if ($MinimumVersion) { $result = ValidateAndGet-VersionPrereleaseStrings -Version $MinimumVersion -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $minVersion = $result["Version"] $minPrerelease = $result["Prerelease"] $minFullVersion = $result["FullVersion"] } else { $minVersion = $null $minPrerelease = $null $minFullVersion = $null } if( (-not $MinimumVersion -and ($galleryItemFullVersion -ne $installedScriptFullVersion)) -or ($MinimumVersion -and (Compare-PrereleaseVersions -FirstItemVersion $installedScriptInfoVersion ` -FirstItemPrerelease $installedScriptInfoPrerelease ` -SecondItemVersion $minVersion ` -SecondItemPrerelease $minPrerelease) )) { $message = $LocalizedData.ScriptAlreadyInstalled -f ($installedScriptFullVersion, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase, $installedScriptFullVersion, $galleryItemFullVersion) Write-Error -Message $message -ErrorId "ScriptAlreadyInstalled" -Category InvalidOperation } else { $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($installedScriptFullVersion, $InstalledScriptInfo.Name, $InstalledScriptInfo.ScriptBase) Write-Verbose $message } return } else { if (Compare-PrereleaseVersions -FirstItemVersion $installedScriptInfoVersion.ToString() ` -FirstItemPrerelease $installedScriptInfoPrerelease ` -SecondItemVersion $galleryItemVersion.ToString() ` -SecondItemPrerelease $galleryItemPrerelease) { $message = $LocalizedData.FoundScriptUpdate -f ($InstalledScriptInfo.Name, $version) Write-Verbose $message } else { $message = $LocalizedData.NoScriptUpdateAvailable -f ($InstalledScriptInfo.Name) Write-Verbose $message return } } } # Throw an error if there is a command with the same name and -force is not specified. if(-not $installUpdate -and -not $IsSavePackage -and -not $Force) { $cmd = Microsoft.PowerShell.Core\Get-Command -Name $packageName ` -ErrorAction Ignore ` -WarningAction SilentlyContinue if($cmd) { $message = $LocalizedData.CommandAlreadyAvailable -f ($packageName) Write-Error -Message $message -ErrorId CommandAlreadyAvailableWitScriptName -Category InvalidOperation return } } } # create a temp folder and download the module $tempDestination = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)" $null = Microsoft.PowerShell.Management\New-Item -Path $tempDestination -ItemType Directory -Force -Confirm:$false -WhatIf:$false try { $provider = $request.SelectProvider($providerName) if(-not $provider) { Write-Error -Message ($LocalizedData.PackageManagementProviderIsNotAvailable -f $providerName) return } if($request.IsCanceled) { return } Write-Verbose ($LocalizedData.SpecifiedLocationAndOGP -f ($provider.ProviderName, $providerName)) $InstalledItemsList = $null $pkg = $script:FastPackRefHashtable[$fastPackageReference] # If an item has dependencies, prepare the list of installed items and # pass it to the NuGet provider to not download the already installed items. if($pkg.Dependencies.count -and -not $IsSavePackage -and -not $Force) { $InstalledItemsList = Microsoft.PowerShell.Core\Get-Module -ListAvailable | Microsoft.PowerShell.Core\ForEach-Object {"$($_.Name)!#!$($_.Version)".ToLower()} if($artifactType -eq $script:PSArtifactTypeScript) { $InstalledItemsList += $script:PSGetInstalledScripts.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { "$($_.Value.PSGetItemInfo.Name)!#!$($_.Value.PSGetItemInfo.Version)".ToLower() } } $InstalledItemsList | Select-Object -Unique -ErrorAction Ignore if($Debug) { $InstalledItemsList | Microsoft.PowerShell.Core\ForEach-Object { Write-Debug -Message "Locally available Item: $_"} } } $ProviderOptions = @{ Destination=$tempDestination; ExcludeVersion=$true } if($InstalledItemsList) { $ProviderOptions['InstalledPackages'] = $InstalledItemsList } $newRequest = $request.CloneRequest( $ProviderOptions, @($SourceLocation), $request.Credential ) if($artifactType -eq $script:PSArtifactTypeModule) { $message = $LocalizedData.DownloadingModuleFromGallery -f ($packageName, $galleryItemFullVersion, $sourceLocation) } else { $message = $LocalizedData.DownloadingScriptFromGallery -f ($packageName, $galleryItemFullVersion, $sourceLocation) } Write-Verbose $message $installedPkgs = $provider.InstallPackage($script:FastPackRefHashtable[$fastPackageReference], $newRequest) $YesToAll = $false $NoToAll = $false foreach($pkg in $installedPkgs) { if($request.IsCanceled) { return } $result = ValidateAndGet-VersionPrereleaseStrings -Version $pkg.Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $pkgVersion = $result["Version"] $pkgPrerelease = $result["Prerelease"] $pkgFullVersion = $result["FullVersion"] $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $moduleDestination -ChildPath $pkg.Name # Side-by-Side module version is available on PowerShell 5.0 or later versions only # By default, PowerShell module versions will be installed/updated Side-by-Side. if(Test-ModuleSxSVersionSupport) { $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $destinationModulePath -ChildPath $pkgVersion } $destinationscriptPath = $scriptDestination # Get actual artifact type from the package $packageType = $script:PSArtifactTypeModule $installLocation = $destinationModulePath $tempPackagePath = Microsoft.PowerShell.Management\Join-Path -Path $tempDestination -ChildPath $pkg.Name if(Microsoft.PowerShell.Management\Test-Path -Path $tempPackagePath) { $packageFiles = Microsoft.PowerShell.Management\Get-ChildItem -Path $tempPackagePath -Recurse -Exclude "*.nupkg","*.nuspec" if($packageFiles -and $packageFiles.GetType().ToString() -eq 'System.IO.FileInfo' -and $packageFiles.Name -eq "$($pkg.Name).ps1") { $packageType = $script:PSArtifactTypeScript $installLocation = $destinationscriptPath } } $AdditionalParams = @{} if(-not $IsSavePackage) { # During the install operation: # InstalledDate should be the current Get-Date value # UpdatedDate should be null # # During the update operation: # InstalledDate should be from the previous version's InstalledDate otherwise current Get-Date value # UpdatedDate should be the current Get-Date value # $InstalledDate = Microsoft.PowerShell.Utility\Get-Date if($installUpdate) { $AdditionalParams['UpdatedDate'] = Microsoft.PowerShell.Utility\Get-Date $InstalledItemDetails = $null if($packageType -eq $script:PSArtifactTypeModule) { $InstalledItemDetails = Get-InstalledModuleDetails -Name $pkg.Name | Select-Object -Last 1 -ErrorAction Ignore } elseif($packageType -eq $script:PSArtifactTypeScript) { $InstalledItemDetails = Get-InstalledScriptDetails -Name $pkg.Name | Select-Object -Last 1 -ErrorAction Ignore } if($InstalledItemDetails -and $InstalledItemDetails.PSGetItemInfo -and (Get-Member -InputObject $InstalledItemDetails.PSGetItemInfo -Name 'InstalledDate') -and $InstalledItemDetails.PSGetItemInfo.InstalledDate) { $InstalledDate = $InstalledItemDetails.PSGetItemInfo.InstalledDate } } $AdditionalParams['InstalledDate'] = $InstalledDate } # construct the PSGetItemInfo from SoftwareIdentity and persist it $psgItemInfo = New-PSGetItemInfo -SoftwareIdentity $pkg ` -PackageManagementProviderName $provider.ProviderName ` -SourceLocation $sourceLocation ` -Type $packageType ` -InstalledLocation $installLocation ` @AdditionalParams if($packageType -eq $script:PSArtifactTypeModule) { if ($psgItemInfo.PowerShellGetFormatVersion -and ($script:SupportedPSGetFormatVersionMajors -notcontains $psgItemInfo.PowerShellGetFormatVersion.Major)) { $message = $LocalizedData.NotSupportedPowerShellGetFormatVersion -f ($psgItemInfo.Name, $psgItemInfo.PowerShellGetFormatVersion, $psgItemInfo.Name) Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation continue } if($psgItemInfo.PowerShellGetFormatVersion -eq "1.0") { $sourceModulePath = Microsoft.PowerShell.Management\Join-Path $tempDestination "$($pkg.Name)\Content\*\$script:ModuleReferences\$($pkg.Name)" } else { $sourceModulePath = Microsoft.PowerShell.Management\Join-Path $tempDestination $pkg.Name } #Prompt if module requires license Acceptance $requireLicenseAcceptance = $false if($psgItemInfo.PowerShellGetFormatVersion -and $psgItemInfo.PowerShellGetFormatVersion -ge $script:PSGetRequireLicenseAcceptanceFormatVersion) { if($psgItemInfo.AdditionalMetadata -and $psgItemInfo.AdditionalMetadata.requireLicenseAcceptance) { $requireLicenseAcceptance = $psgItemInfo.AdditionalMetadata.requireLicenseAcceptance } } if($requireLicenseAcceptance -eq $true) { if($Force -and -not($AcceptLicense)) { $message = $LocalizedData.ForceAcceptLicense -f $pkg.Name ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "ForceAcceptLicense" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } If (-not ($YesToAll -or $NoToAll -or $AcceptLicense)) { $LicenseFilePath = Join-PathUtility -Path $sourceModulePath -ChildPath 'License.txt' -PathType File if(-not(Test-Path -Path $LicenseFilePath -PathType Leaf)) { $message = $LocalizedData.LicenseTxtNotFound ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "LicenseTxtNotFound" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory ObjectNotFound } $FormattedEula = (Get-Content -Path $LicenseFilePath) -Join "`r`n" $message = $FormattedEula + "`r`n" + ($LocalizedData.AcceptanceLicenseQuery -f $pkg.Name) $title = $LocalizedData.AcceptLicense $result = $request.ShouldContinue($message, $title, [ref]$yesToAll, [ref]$NoToAll) if(($result -eq $false) -or ($NoToAll -eq $true)) { Write-Warning -Message $LocalizedData.UserDeclinedLicenseAcceptance return } } } $CurrentModuleInfo = $null # Validate the module if(-not $IsSavePackage) { $CurrentModuleInfo = Test-ValidManifestModule -ModuleBasePath $sourceModulePath ` -InstallLocation $InstallLocation ` -AllowClobber:$AllowClobber ` -SkipPublisherCheck:$SkipPublisherCheck ` -IsUpdateOperation:$installUpdate if(-not $CurrentModuleInfo) { # This Install-Package provider API gets called once per an item/package/SoftwareIdentity. # Return if there is an error instead of continuing further to install the dependencies or current module. # return } } # Test if module is already installed $InstalledModuleInfo2 = if(-not $IsSavePackage){ Test-ModuleInstalled -Name $pkg.Name -RequiredVersion $pkgFullVersion } if($pkg.Name -ne $packageName) { if(-not $Force -and $InstalledModuleInfo2) { $result = ValidateAndGet-VersionPrereleaseStrings -Version $InstalledModuleInfo2.Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $installedModuleVersion = $result["Version"] $installedModulePrerelease = $result["Prerelease"] $installedModuleFullVersion = $result["FullVersion"] if(Test-ModuleSxSVersionSupport) { if($pkgFullVersion -eq $installedModuleFullVersion) { if(-not $installUpdate) { $message = $LocalizedData.ModuleWithRequiredVersionAlreadyInstalled -f ($installedModuleFullVersion, $InstalledModuleInfo2.Name, $InstalledModuleInfo2.ModuleBase, $InstalledModuleFullVersion) } else { $message = $LocalizedData.NoUpdateAvailable -f ($pkg.Name) } Write-Verbose $message Continue } } else { if(-not $installUpdate) { $message = $LocalizedData.ModuleAlreadyInstalledVerbose -f ($InstalledModuleFullVersion, $InstalledModuleInfo2.Name, $InstalledModuleInfo2.ModuleBase) Write-Verbose $message Continue } else { if(Compare-PrereleaseVersions -FirstItemVersion $installedModuleVersion.ToString() ` -FirstItemPrerelease $installedModPrerelease ` -SecondItemVersion $pkgVersion.ToString() ` -SecondItemPrerelease $pkgPrerelease) { $message = $LocalizedData.FoundModuleUpdate -f ($pkg.Name, $pkgFullVersion) Write-Verbose $message } else { $message = $LocalizedData.NoUpdateAvailable -f ($pkg.Name) Write-Verbose $message Continue } } } } if($IsSavePackage) { $DependencyInstallMessage = $LocalizedData.SavingDependencyModule -f ($pkg.Name, $pkgFullVersion, $packageName) } else { $DependencyInstallMessage = $LocalizedData.InstallingDependencyModule -f ($pkg.Name, $pkgFullVersion, $packageName) } Write-Verbose $DependencyInstallMessage } # check if module is in use if($InstalledModuleInfo2) { $moduleInUse = Test-ModuleInUse -ModuleBasePath $InstalledModuleInfo2.ModuleBase ` -ModuleName $InstalledModuleInfo2.Name ` -ModuleVersion $InstalledModuleInfo2.Version ` -Verbose:$VerbosePreference ` -WarningAction $WarningPreference ` -ErrorAction $ErrorActionPreference ` -Debug:$DebugPreference if($moduleInUse) { $message = $LocalizedData.ModuleIsInUse -f ($psgItemInfo.Name) Write-Verbose $message continue } } # Use the actual module version retrieved from the module manifest. if($CurrentModuleInfo -and (Test-ModuleSxSVersionSupport) -and -not $pkgPrerelease) { $destinationModulePath = Microsoft.PowerShell.Management\Join-Path -Path $moduleDestination -ChildPath $pkg.Name | Microsoft.PowerShell.Management\Join-Path -ChildPath $CurrentModuleInfo.Version $installLocation = $destinationModulePath $psgItemInfo.InstalledLocation = $installLocation $psgItemInfo.Version = $CurrentModuleInfo.Version } Copy-Module -SourcePath $sourceModulePath -DestinationPath $destinationModulePath -PSGetItemInfo $psgItemInfo if(-not $IsSavePackage) { # Write warning messages if externally managed module dependencies are not installed. $ExternalModuleDependencies = Get-ExternalModuleDependencies -PSModuleInfo $CurrentModuleInfo foreach($ExternalDependency in $ExternalModuleDependencies) { $depModuleInfo = Test-ModuleInstalled -Name $ExternalDependency if(-not $depModuleInfo) { Write-Warning -Message ($LocalizedData.MissingExternallyManagedModuleDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) } else { Write-Verbose -Message ($LocalizedData.ExternallyManagedModuleDependencyIsInstalled -f $ExternalDependency) } } } if($IsSavePackage) { $message = $LocalizedData.ModuleSavedSuccessfully -f ($psgItemInfo.Name, $installLocation) } else { $message = $LocalizedData.ModuleInstalledSuccessfully -f ($psgItemInfo.Name, $installLocation) } Write-Verbose $message } if($packageType -eq $script:PSArtifactTypeScript) { if ($psgItemInfo.PowerShellGetFormatVersion -and ($script:SupportedPSGetFormatVersionMajors -notcontains $psgItemInfo.PowerShellGetFormatVersion.Major)) { $message = $LocalizedData.NotSupportedPowerShellGetFormatVersionScripts -f ($psgItemInfo.Name, $psgItemInfo.PowerShellGetFormatVersion, $psgItemInfo.Name) Write-Error -Message $message -ErrorId "NotSupportedPowerShellGetFormatVersion" -Category InvalidOperation continue } $sourceScriptPath = Join-PathUtility -Path $tempPackagePath -ChildPath "$($pkg.Name).ps1" -PathType File $currentScriptInfo = $null if(-not $IsSavePackage) { # Validate the script $currentScriptInfo = Test-ScriptFileInfo -Path $sourceScriptPath -ErrorAction SilentlyContinue if(-not $currentScriptInfo) { $message = $LocalizedData.InvalidPowerShellScriptFile -f ($pkg.Name) Write-Error -Message $message -ErrorId "InvalidPowerShellScriptFile" -Category InvalidOperation -TargetObject $pkg.Name continue } # Use the version extracted from the script file. $psgItemInfo.Version = $currentScriptInfo.Version } # Test if script is already installed $InstalledScriptInfo2 = if(-not $IsSavePackage){ Test-ScriptInstalled -Name $pkg.Name } if($pkg.Name -ne $packageName) { if(-not $Force -and $InstalledScriptInfo2) { $result = ValidateAndGet-VersionPrereleaseStrings -Version $InstalledScriptInfo2.Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $installedScriptFullVersion = $result["FullVersion"] if(-not $installUpdate) { $message = $LocalizedData.ScriptAlreadyInstalledVerbose -f ($InstalledScriptFullVersion, $InstalledScriptInfo2.Name, $InstalledScriptInfo2.ScriptBase) Write-Verbose $message Continue } else { if(Compare-PrereleaseVersions -FirstItemVersion $installedScriptInfoVersion.ToString() ` -FirstItemPrerelease $installedScriptInfoPrerelease ` -SecondItemVersion $pkgVersion ` -SecondItemPrerelease $pkgPrerelease) { $message = $LocalizedData.FoundScriptUpdate -f ($pkg.Name, $pkgFullVersion) Write-Verbose $message } else { $message = $LocalizedData.NoScriptUpdateAvailable -f ($pkg.Name) Write-Verbose $message Continue } } } if($IsSavePackage) { $DependencyInstallMessage = $LocalizedData.SavingDependencyScript -f ($pkg.Name, $pkgFullVersion, $packageName) } else { $DependencyInstallMessage = $LocalizedData.InstallingDependencyScript -f ($pkg.Name, $pkgFullVersion, $packageName) } Write-Verbose $DependencyInstallMessage } Write-Debug "SourceScriptPath is $sourceScriptPath and DestinationscriptPath is $destinationscriptPath" Copy-ScriptFile -SourcePath $sourceScriptPath -DestinationPath $destinationscriptPath -PSGetItemInfo $psgItemInfo -Scope $Scope if(-not $IsSavePackage) { # Write warning messages if externally managed module dependencies are not installed. foreach($ExternalDependency in $currentScriptInfo.ExternalModuleDependencies) { $depModuleInfo = Test-ModuleInstalled -Name $ExternalDependency if(-not $depModuleInfo) { Write-Warning -Message ($LocalizedData.ScriptMissingExternallyManagedModuleDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) } else { Write-Verbose -Message ($LocalizedData.ExternallyManagedModuleDependencyIsInstalled -f $ExternalDependency) } } # Write warning messages if externally managed script dependencies are not installed. foreach($ExternalDependency in $currentScriptInfo.ExternalScriptDependencies) { $depScriptInfo = Test-ScriptInstalled -Name $ExternalDependency if(-not $depScriptInfo) { Write-Warning -Message ($LocalizedData.ScriptMissingExternallyManagedScriptDependency -f $ExternalDependency,$pkg.Name,$ExternalDependency) } else { Write-Verbose -Message ($LocalizedData.ScriptExternallyManagedScriptDependencyIsInstalled -f $ExternalDependency) } } } # Remove the old scriptfile if it's path different from the required destination script path when -Force is specified if($Force -and $InstalledScriptInfo2 -and -not $destinationscriptPath.StartsWith($InstalledScriptInfo2.ScriptBase, [System.StringComparison]::OrdinalIgnoreCase)) { Microsoft.PowerShell.Management\Remove-Item -Path $InstalledScriptInfo2.Path ` -Force ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false -WhatIf:$false } if($IsSavePackage) { $message = $LocalizedData.ScriptSavedSuccessfully -f ($psgItemInfo.Name, $installLocation) } else { $message = $LocalizedData.ScriptInstalledSuccessfully -f ($psgItemInfo.Name, $installLocation) } Write-Verbose $message } $sid = New-SoftwareIdentityFromPackage -Package $pkg ` -SourceLocation $sourceLocation ` -PackageManagementProviderName $provider.ProviderName ` -Request $request ` -Type $packageType ` -InstalledLocation $installLocation ` @AdditionalParams Write-Output -InputObject $sid } } finally { Microsoft.PowerShell.Management\Remove-Item $tempDestination -Force -Recurse -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } } } function Uninstall-Package { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $fastPackageReference ) Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Uninstall-Package')) Write-Debug -Message ($LocalizedData.FastPackageReference -f $fastPackageReference) # take the fastPackageReference and get the package object again. $parts = $fastPackageReference -Split '[|]' $Force = $false $options = $request.Options if($options) { foreach( $o in $options.Keys ) { Write-Debug -Message ("OPTION: {0} => {1}" -f ($o, $request.Options[$o]) ) } } if($parts.Length -eq 5) { $providerName = $parts[0] $packageName = $parts[1] $version = $parts[2] $sourceLocation= $parts[3] $artifactType = $parts[4] if($request.IsCanceled) { return } if($options.ContainsKey('Force')) { $Force = $options['Force'] if($Force.GetType().ToString() -eq 'System.String') { if($Force -eq 'false') { $Force = $false } elseif($Force -eq 'true') { $Force = $true } } } if($artifactType -eq $script:PSArtifactTypeModule) { $moduleName = $packageName $InstalledModuleInfo = $script:PSGetInstalledModules["$($moduleName)$($version)"] if(-not $InstalledModuleInfo) { $message = $LocalizedData.ModuleUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet -f $moduleName ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "ModuleUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } $moduleBase = $InstalledModuleInfo.PSGetItemInfo.InstalledLocation if(-not (Test-RunningAsElevated) -and $moduleBase.StartsWith($script:programFilesModulesPath, [System.StringComparison]::OrdinalIgnoreCase)) { $message = $LocalizedData.AdminPrivilegesRequiredForUninstall -f ($moduleName, $moduleBase) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "AdminPrivilegesRequiredForUninstall" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } $dependentModuleScript = { param ([string] $moduleName) Microsoft.PowerShell.Core\Get-Module -ListAvailable | Microsoft.PowerShell.Core\Where-Object { ($moduleName -ne $_.Name) -and ( ($_.RequiredModules -and $_.RequiredModules.Name -contains $moduleName) -or ($_.NestedModules -and $_.NestedModules.Name -contains $moduleName)) } } $dependentModulesJob = Microsoft.PowerShell.Core\Start-Job -ScriptBlock $dependentModuleScript -ArgumentList $moduleName Microsoft.PowerShell.Core\Wait-Job -job $dependentModulesJob $dependentModules = Microsoft.PowerShell.Core\Receive-Job -job $dependentModulesJob -ErrorAction Ignore if(-not $Force -and $dependentModules) { $message = $LocalizedData.UnableToUninstallAsOtherModulesNeedThisModule -f ($moduleName, $version, $moduleBase, $(($dependentModules.Name | Select-Object -Unique -ErrorAction Ignore) -join ','), $moduleName) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "UnableToUninstallAsOtherModulesNeedThisModule" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } $moduleInUse = Test-ModuleInUse -ModuleBasePath $moduleBase ` -ModuleName $InstalledModuleInfo.PSGetItemInfo.Name` -ModuleVersion $InstalledModuleInfo.PSGetItemInfo.Version ` -Verbose:$VerbosePreference ` -WarningAction $WarningPreference ` -ErrorAction $ErrorActionPreference ` -Debug:$DebugPreference if($moduleInUse) { $message = $LocalizedData.ModuleIsInUse -f ($moduleName) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "ModuleIsInUse" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } $ModuleBaseFolderToBeRemoved = $moduleBase # With SxS version support, more than one version of the module can be installed. # - Remove the parent directory of the module version base when only one version is installed # - Don't remove the modulebase when it was installed before SxS version support and # other versions are installed under the module base folder # if(Test-ModuleSxSVersionSupport) { $ModuleBaseWithoutVersion = $moduleBase $IsModuleInstalledAsSxSVersion = $false if($moduleBase.EndsWith("$version", [System.StringComparison]::OrdinalIgnoreCase)) { $IsModuleInstalledAsSxSVersion = $true $ModuleBaseWithoutVersion = Microsoft.PowerShell.Management\Split-Path -Path $moduleBase -Parent } $InstalledVersionsWithSameModuleBase = @() Get-Module -Name $moduleName -ListAvailable | Microsoft.PowerShell.Core\ForEach-Object { if($_.ModuleBase.StartsWith($ModuleBaseWithoutVersion, [System.StringComparison]::OrdinalIgnoreCase)) { $InstalledVersionsWithSameModuleBase += $_.ModuleBase } } # Remove ..\ModuleName directory when only one module is installed with the same ..\ModuleName path # like ..\ModuleName\1.0 or ..\ModuleName if($InstalledVersionsWithSameModuleBase.Count -eq 1) { $ModuleBaseFolderToBeRemoved = $ModuleBaseWithoutVersion } elseif($ModuleBaseWithoutVersion -eq $moduleBase) { # There are version specific folders under the same module base dir # Throw an error saying uninstall other versions then uninstall this current version $message = $LocalizedData.UnableToUninstallModuleVersion -f ($moduleName, $version, $moduleBase) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "UnableToUninstallModuleVersion" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } # Otherwise specified version folder will be removed as current module base is assigned to $ModuleBaseFolderToBeRemoved } Microsoft.PowerShell.Management\Remove-Item -Path $ModuleBaseFolderToBeRemoved ` -Force -Recurse ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false -WhatIf:$false $message = $LocalizedData.ModuleUninstallationSucceeded -f $moduleName, $moduleBase Write-Verbose $message Write-Output -InputObject $InstalledModuleInfo.SoftwareIdentity } elseif($artifactType -eq $script:PSArtifactTypeScript) { $scriptName = $packageName $InstalledScriptInfo = $script:PSGetInstalledScripts["$($scriptName)$($version)"] if(-not $InstalledScriptInfo) { $message = $LocalizedData.ScriptUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet -f $scriptName ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "ScriptUninstallationNotPossibleAsItIsNotInstalledUsingPowerShellGet" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } $scriptBase = $InstalledScriptInfo.PSGetItemInfo.InstalledLocation $installedScriptInfoPath = $script:MyDocumentsInstalledScriptInfosPath if($scriptBase.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) { if(-not (Test-RunningAsElevated)) { $message = $LocalizedData.AdminPrivilegesRequiredForScriptUninstall -f ($scriptName, $scriptBase) ThrowError -ExceptionName "System.InvalidOperationException" ` -ExceptionMessage $message ` -ErrorId "AdminPrivilegesRequiredForUninstall" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } $installedScriptInfoPath = $script:ProgramFilesInstalledScriptInfosPath } # Check if there are any dependent scripts $dependentScriptDetails = $script:PSGetInstalledScripts.Values | Microsoft.PowerShell.Core\Where-Object { $_.PSGetItemInfo.Dependencies -contains $scriptName } $dependentScriptNames = $dependentScriptDetails | Microsoft.PowerShell.Core\ForEach-Object { $_.PSGetItemInfo.Name } if(-not $Force -and $dependentScriptNames) { $message = $LocalizedData.UnableToUninstallAsOtherScriptsNeedThisScript -f ($scriptName, $version, $scriptBase, $(($dependentScriptNames | Select-Object -Unique -ErrorAction Ignore) -join ','), $scriptName) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'UnableToUninstallAsOtherScriptsNeedThisScript' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $scriptBase ` -ChildPath "$($scriptName).ps1" $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $installedScriptInfoPath ` -ChildPath "$($scriptName)_$($script:InstalledScriptInfoFileName)" # Remove the script file and it's corresponding InstalledScriptInfo.xml if(Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf) { Microsoft.PowerShell.Management\Remove-Item -Path $scriptFilePath ` -Force ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false -WhatIf:$false } if(Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf) { Microsoft.PowerShell.Management\Remove-Item -Path $installedScriptInfoFilePath ` -Force ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false -WhatIf:$false } $message = $LocalizedData.ScriptUninstallationSucceeded -f $scriptName, $scriptBase Write-Verbose $message Write-Output -InputObject $InstalledScriptInfo.SoftwareIdentity } } } function Get-InstalledPackage { [CmdletBinding()] param ( [Parameter()] [string] $Name, [Parameter()] [string] $RequiredVersion, [Parameter()] [string] $MinimumVersion, [Parameter()] [string] $MaximumVersion ) Write-Debug -Message ($LocalizedData.ProviderApiDebugMessage -f ('Get-InstalledPackage')) $options = $request.Options foreach( $o in $options.Keys ) { Write-Debug ( "OPTION: {0} => {1}" -f ($o, $options[$o]) ) } $artifactTypes = $script:PSArtifactTypeModule if($options.ContainsKey($script:PSArtifactType)) { $artifactTypes = $options[$script:PSArtifactType] } if($artifactTypes -eq $script:All) { $artifactTypes = @($script:PSArtifactTypeModule,$script:PSArtifactTypeScript) } if($artifactTypes -contains $script:PSArtifactTypeModule) { Get-InstalledModuleDetails -Name $Name ` -RequiredVersion $RequiredVersion ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion | Microsoft.PowerShell.Core\ForEach-Object {$_.SoftwareIdentity} } if($artifactTypes -contains $script:PSArtifactTypeScript) { Get-InstalledScriptDetails -Name $Name ` -RequiredVersion $RequiredVersion ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion | Microsoft.PowerShell.Core\ForEach-Object {$_.SoftwareIdentity} } } #endregion #region Internal Utility functions for the PackageManagement Provider Implementation function Compare-PrereleaseVersions { [CmdletBinding()] param( [ValidateNotNullOrEmpty()] [string] $FirstItemVersion, [string] $FirstItemPrerelease, [ValidateNotNullOrEmpty()] [string] $SecondItemVersion, [string] $SecondItemPrerelease ) <# This function compares one item to another to determine if it has a greater version (and/or prerelease). It returns true if item TWO is GREATER/newer than item ONE, it returns false otherwise. First Order: Compare Versions =========== *** Version is never NULL. Item #1 Comparison Item #2 Version of Values Version Notes about item #2 ------- ---------- ------- ------------------- Value > Value An older release version Value < Value * A newer release version Value == Value Inconclusive, must compare prerelease strings now Second Order: Compare Prereleases ============= *** Prerelease may be NULL, indicates a release version. Item #1 Comparison Item #2 Prerelease of Values Prerelease Notes about item #2 ---------- ----------- ---------- ------------------- NULL == NULL Exact same release version NULL > Value Older (prerelease) version Value < NULL * A newer, release version Value == Value Exact same prerelease (and same version) Value > Value An older prerelease Value < Value * A newer prerelease Item #2 is newer/greater than item #1 in the starred (*) combinations. Those are the conditions tested for below. #> [version]$itemOneVersion = $null # try parsing version string if (-not ( [System.Version]::TryParse($FirstItemVersion.Trim(), [ref]$itemOneVersion) )) { $message = $LocalizedData.InvalidVersion -f ($FirstItemVersion) Write-Error -Message $message -ErrorId "InvalidVersion" -Category InvalidArgument return } [Version]$itemTwoVersion = $null # try parsing version string if (-not ( [System.Version]::TryParse($SecondItemVersion.Trim(), [ref]$itemTwoVersion) )) { $message = $LocalizedData.InvalidVersion -f ($SecondItemVersion) Write-Error -Message $message -ErrorId "InvalidVersion" -Category InvalidArgument return } return (($itemOneVersion -lt $itemTwoVersion) -or ` (($itemOneVersion -eq $itemTwoVersion) -and ` (($FirstItemPrerelease -and -not $SecondItemPrerelease) -or ` ($FirstItemPrerelease -lt $SecondItemPrerelease)))) } function Set-InstalledScriptsVariable { # Initialize list of scripts installed by the PowerShellGet provider $script:PSGetInstalledScripts = [ordered]@{} $scriptPaths = @($script:ProgramFilesInstalledScriptInfosPath, $script:MyDocumentsInstalledScriptInfosPath) foreach ($location in $scriptPaths) { # find all scripts installed using PowerShellGet $scriptInfoFiles = Get-ChildItem -Path $location ` -Filter "*$script:InstalledScriptInfoFileName" ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if($scriptInfoFiles) { foreach ($scriptInfoFile in $scriptInfoFiles) { $psgetItemInfo = DeSerialize-PSObject -Path $scriptInfoFile.FullName $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $psgetItemInfo.InstalledLocation ` -ChildPath "$($psgetItemInfo.Name).ps1" # Remove the InstalledScriptInfo.xml file if the actual script file was manually uninstalled by the user if(-not (Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf)) { Microsoft.PowerShell.Management\Remove-Item -Path $scriptInfoFile.FullName -Force -ErrorAction SilentlyContinue continue } $package = New-SoftwareIdentityFromPSGetItemInfo -PSGetItemInfo $psgetItemInfo if($package) { $script:PSGetInstalledScripts["$($psgetItemInfo.Name)$($psgetItemInfo.Version)"] = @{ SoftwareIdentity = $package PSGetItemInfo = $psgetItemInfo } } } } } } function Get-InstalledScriptDetails { [CmdletBinding()] param ( [Parameter()] [string] $Name, [Parameter()] [string] $RequiredVersion, [Parameter()] [string] $MinimumVersion, [Parameter()] [string] $MaximumVersion ) Set-InstalledScriptsVariable # Keys in $script:PSGetInstalledScripts are "<ScriptName><ScriptVersion>", # first filter the installed scripts using "$Name*" wildcard search # then apply $Name wildcard search to get the script name which meets the specified name with wildcards. # $wildcardPattern = New-Object System.Management.Automation.WildcardPattern "$Name*",$script:wildcardOptions $nameWildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions $script:PSGetInstalledScripts.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { if($wildcardPattern.IsMatch($_.Key)) { $InstalledScriptDetails = $_.Value if(-not $Name -or $nameWildcardPattern.IsMatch($InstalledScriptDetails.PSGetItemInfo.Name)) { if (Test-ItemPrereleaseVersionRequirements -Version $InstalledScriptDetails.PSGetItemInfo.Version ` -RequiredVersion $RequiredVersion ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion) { $InstalledScriptDetails } } } } } function Get-InstalledModuleDetails { [CmdletBinding()] param ( [Parameter()] [string] $Name, [Parameter()] [string] $RequiredVersion, [Parameter()] [string] $MinimumVersion, [Parameter()] [string] $MaximumVersion ) Set-InstalledModulesVariable # Keys in $script:PSGetInstalledModules are "<ModuleName><ModuleVersion>", # first filter the installed modules using "$Name*" wildcard search # then apply $Name wildcard search to get the module name which meets the specified name with wildcards. # $wildcardPattern = New-Object System.Management.Automation.WildcardPattern "$Name*",$script:wildcardOptions $nameWildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions $script:PSGetInstalledModules.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { if($wildcardPattern.IsMatch($_.Key)) { $InstalledModuleDetails = $_.Value if(-not $Name -or $nameWildcardPattern.IsMatch($InstalledModuleDetails.PSGetItemInfo.Name)) { if (Test-ItemPrereleaseVersionRequirements -Version $InstalledModuleDetails.PSGetItemInfo.Version ` -RequiredVersion $RequiredVersion ` -MinimumVersion $MinimumVersion ` -MaximumVersion $MaximumVersion) { $InstalledModuleDetails } } } } } # Returns true if it meets the Required, Minimum, and Maximum version bounds. function Test-ItemPrereleaseVersionRequirements { [CmdletBinding()] param( [ValidateNotNullOrEmpty()] [string] $Version, [string] $RequiredVersion, [string] $MinimumVersion, [string] $MaximumVersion ) $result = ValidateAndGet-VersionPrereleaseStrings -Version $Version -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $psgetitemVersion = $result["Version"] $psgetitemPrerelease = $result["Prerelease"] $psgetitemFullVersion = $result["FullVersion"] if($RequiredVersion) { $reqResult = ValidateAndGet-VersionPrereleaseStrings -Version $RequiredVersion -CallerPSCmdlet $PSCmdlet if (-not $reqResult) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $reqFullVersion = $reqResult["FullVersion"] return ($reqFullVersion -eq $psgetitemFullVersion) } else { $minimumBoundMet = $false if ($MinimumVersion) { $minResult = ValidateAndGet-VersionPrereleaseStrings -Version $MinimumVersion -CallerPSCmdlet $PSCmdlet if (-not $minResult) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $minVersion = $minResult["Version"] $minPrerelease = $minResult["Prerelease"] # minimum bound is met if PSGet item version is greater than or equal to minimum version if (-not (Compare-PrereleaseVersions -FirstItemVersion $psgetitemVersion ` -FirstItemPrerelease $psgetitemPrerelease ` -SecondItemVersion $minVersion ` -SecondItemPrerelease $minPrerelease )) { $minimumBoundMet = $true } } else { $minimumBoundMet = $true } $maximumBoundMet = $false if ($MaximumVersion) { $maxResult = ValidateAndGet-VersionPrereleaseStrings -Version $MaximumVersion -CallerPSCmdlet $PSCmdlet if (-not $maxResult) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $maxVersion = $maxResult["Version"] $maxPrerelease = $maxResult["Prerelease"] # maximum bound is met if PSGet item version is less than or equal to maximum version if (-not (Compare-PrereleaseVersions -FirstItemVersion $maxVersion ` -FirstItemPrerelease $maxPrerelease ` -SecondItemVersion $psgetitemVersion ` -SecondItemPrerelease $psgetitemPrerelease )) { $maximumBoundMet = $true } } else { $maximumBoundMet = $true } return ($minimumBoundMet -and $maximumBoundMet) } } function New-SoftwareIdentityFromPackage { param ( [Parameter(Mandatory=$true)] $Package, [Parameter(Mandatory=$true)] [string] $PackageManagementProviderName, [Parameter(Mandatory=$true)] [string] $SourceLocation, [Parameter()] [switch] $IsFromTrustedSource, [Parameter(Mandatory=$true)] $request, [Parameter(Mandatory=$true)] [string] $Type, [Parameter()] [string] $InstalledLocation, [Parameter()] [System.DateTime] $InstalledDate, [Parameter()] [System.DateTime] $UpdatedDate ) $fastPackageReference = New-FastPackageReference -ProviderName $PackageManagementProviderName ` -PackageName $Package.Name ` -Version $Package.Version ` -Source $SourceLocation ` -ArtifactType $Type $links = New-Object -TypeName System.Collections.ArrayList foreach($lnk in $Package.Links) { if( $lnk.Relationship -eq "icon" -or $lnk.Relationship -eq "license" -or $lnk.Relationship -eq "project" ) { $links.Add( (New-Link -Href $lnk.HRef -RelationShip $lnk.Relationship ) ) } } $entities = New-Object -TypeName System.Collections.ArrayList foreach( $entity in $Package.Entities ) { if( $entity.Role -eq "author" -or $entity.Role -eq "owner" ) { $entities.Add( (New-Entity -Name $entity.Name -Role $entity.Role -RegId $entity.RegId -Thumbprint $entity.Thumbprint) ) } } $deps = (new-Object -TypeName System.Collections.ArrayList) foreach( $dep in $pkg.Dependencies ) { # Add each dependency and say it's from this provider. $newDep = New-Dependency -ProviderName $script:PSModuleProviderName ` -PackageName $request.Services.ParsePackageName($dep) ` -Version $request.Services.ParsePackageVersion($dep) ` -Source $SourceLocation $deps.Add( $newDep ) } $details = New-Object -TypeName System.Collections.Hashtable foreach ( $key in $Package.Metadata.Keys.LocalName) { if (!$details.ContainsKey($key)) { $details.Add($key, (Get-First $Package.Metadata[$key]) ) } } $details.Add( "PackageManagementProvider" , $PackageManagementProviderName ) if($InstalledLocation) { $details.Add( $script:InstalledLocation , $InstalledLocation ) } if($InstalledDate) { $details.Add( 'installeddate' , $InstalledDate.ToString('O', [System.Globalization.DateTimeFormatInfo]::InvariantInfo) ) } if($UpdatedDate) { $details.Add( 'updateddate' , $UpdatedDate.ToString('O', [System.Globalization.DateTimeFormatInfo]::InvariantInfo) ) } # Initialize package source name to the source location $sourceNameForSoftwareIdentity = $SourceLocation $sourceName = (Get-SourceName -Location $SourceLocation) if($sourceName) { $details.Add( "SourceName" , $sourceName ) # Override the source name only if we are able to map source location to source name $sourceNameForSoftwareIdentity = $sourceName } $params = @{FastPackageReference = $fastPackageReference; Name = $Package.Name; Version = $Package.Version; versionScheme = "MultiPartNumeric"; Source = $sourceNameForSoftwareIdentity; Summary = $Package.Summary; SearchKey = $Package.Name; FullPath = $Package.FullPath; FileName = $Package.Name; Details = $details; Entities = $entities; Links = $links; Dependencies = $deps; } if($IsFromTrustedSource) { $params["FromTrustedSource"] = $true } $sid = New-SoftwareIdentity @params return $sid } function New-PackageSourceFromModuleSource { param ( [Parameter(Mandatory=$true)] $ModuleSource ) $ScriptSourceLocation = $null if(Get-Member -InputObject $ModuleSource -Name $script:ScriptSourceLocation) { $ScriptSourceLocation = $ModuleSource.ScriptSourceLocation } $ScriptPublishLocation = $ModuleSource.PublishLocation if(Get-Member -InputObject $ModuleSource -Name $script:ScriptPublishLocation) { $ScriptPublishLocation = $ModuleSource.ScriptPublishLocation } $packageSourceDetails = @{} $packageSourceDetails["InstallationPolicy"] = $ModuleSource.InstallationPolicy $packageSourceDetails["PackageManagementProvider"] = (Get-ProviderName -PSCustomObject $ModuleSource) $packageSourceDetails[$script:PublishLocation] = $ModuleSource.PublishLocation $packageSourceDetails[$script:ScriptSourceLocation] = $ScriptSourceLocation $packageSourceDetails[$script:ScriptPublishLocation] = $ScriptPublishLocation $ModuleSource.ProviderOptions.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { $packageSourceDetails[$_.Key] = $_.Value } # create a new package source $src = New-PackageSource -Name $ModuleSource.Name ` -Location $ModuleSource.SourceLocation ` -Trusted $ModuleSource.Trusted ` -Registered $ModuleSource.Registered ` -Details $packageSourceDetails Write-Verbose ( $LocalizedData.RepositoryDetails -f ($src.Name, $src.Location, $src.IsTrusted, $src.IsRegistered) ) # return the package source object. Write-Output -InputObject $src } function New-ModuleSourceFromPackageSource { param ( [Parameter(Mandatory=$true)] $PackageSource ) $moduleSource = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ Name = $PackageSource.Name SourceLocation = $PackageSource.Location Trusted=$PackageSource.IsTrusted Registered=$PackageSource.IsRegistered InstallationPolicy = $PackageSource.Details['InstallationPolicy'] PackageManagementProvider=$PackageSource.Details['PackageManagementProvider'] PublishLocation=$PackageSource.Details[$script:PublishLocation] ScriptSourceLocation=$PackageSource.Details[$script:ScriptSourceLocation] ScriptPublishLocation=$PackageSource.Details[$script:ScriptPublishLocation] ProviderOptions = @{} }) $PackageSource.Details.GetEnumerator() | Microsoft.PowerShell.Core\ForEach-Object { if($_.Key -ne 'PackageManagementProvider' -and $_.Key -ne $script:PublishLocation -and $_.Key -ne $script:ScriptPublishLocation -and $_.Key -ne $script:ScriptSourceLocation -and $_.Key -ne 'InstallationPolicy') { $moduleSource.ProviderOptions[$_.Key] = $_.Value } } $moduleSource.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSRepository") # return the module source object. Write-Output -InputObject $moduleSource } function New-FastPackageReference { param ( [Parameter(Mandatory=$true)] [string] $ProviderName, [Parameter(Mandatory=$true)] [string] $PackageName, [Parameter(Mandatory=$true)] [string] $Version, [Parameter(Mandatory=$true)] [string] $Source, [Parameter(Mandatory=$true)] [string] $ArtifactType ) return "$ProviderName|$PackageName|$Version|$Source|$ArtifactType" } function Get-First { param ( [Parameter(Mandatory=$true)] $IEnumerator ) foreach($item in $IEnumerator) { return $item } return $null } function Set-InstalledModulesVariable { # Initialize list of modules installed by the PowerShellGet provider $script:PSGetInstalledModules = [ordered]@{} $modulePaths = @($script:ProgramFilesModulesPath, $script:MyDocumentsModulesPath) foreach ($location in $modulePaths) { # find all modules installed using PowerShellGet $GetChildItemParams = @{ Path = $location Recurse = $true Filter = $script:PSGetItemInfoFileName ErrorAction = 'SilentlyContinue' WarningAction = 'SilentlyContinue' } if($script:IsWindows) { $GetChildItemParams['Attributes'] = 'Hidden' } $moduleBases = Get-ChildItem @GetChildItemParams | Foreach-Object { $_.Directory } foreach ($moduleBase in $moduleBases) { $PSGetItemInfoPath = Microsoft.PowerShell.Management\Join-Path $moduleBase.FullName $script:PSGetItemInfoFileName # Check if this module got installed using PSGet, read its contents to create a SoftwareIdentity object if (Microsoft.PowerShell.Management\Test-Path $PSGetItemInfoPath) { $psgetItemInfo = DeSerialize-PSObject -Path $PSGetItemInfoPath # Add InstalledLocation if this module was installed with older version of PowerShellGet if(-not (Get-Member -InputObject $psgetItemInfo -Name $script:InstalledLocation)) { Microsoft.PowerShell.Utility\Add-Member -InputObject $psgetItemInfo ` -MemberType NoteProperty ` -Name $script:InstalledLocation ` -Value $moduleBase.FullName } $package = New-SoftwareIdentityFromPSGetItemInfo -PSGetItemInfo $psgetItemInfo if($package) { $script:PSGetInstalledModules["$($psgetItemInfo.Name)$($psgetItemInfo.Version)"] = @{ SoftwareIdentity = $package PSGetItemInfo = $psgetItemInfo } } } } } } function New-SoftwareIdentityFromPSGetItemInfo { param ( [Parameter(Mandatory=$true)] $PSGetItemInfo ) $SourceLocation = $psgetItemInfo.RepositorySourceLocation if(Get-Member -InputObject $PSGetItemInfo -Name $script:PSArtifactType) { $artifactType = $psgetItemInfo.Type } else { $artifactType = $script:PSArtifactTypeModule } $fastPackageReference = New-FastPackageReference -ProviderName (Get-ProviderName -PSCustomObject $psgetItemInfo) ` -PackageName $psgetItemInfo.Name ` -Version $psgetItemInfo.Version ` -Source $SourceLocation ` -ArtifactType $artifactType $links = New-Object -TypeName System.Collections.ArrayList if($psgetItemInfo.IconUri) { $links.Add( (New-Link -Href $psgetItemInfo.IconUri -RelationShip "icon") ) } if($psgetItemInfo.LicenseUri) { $links.Add( (New-Link -Href $psgetItemInfo.LicenseUri -RelationShip "license") ) } if($psgetItemInfo.ProjectUri) { $links.Add( (New-Link -Href $psgetItemInfo.ProjectUri -RelationShip "project") ) } $entities = New-Object -TypeName System.Collections.ArrayList if($psgetItemInfo.Author -and $psgetItemInfo.Author.ToString()) { $entities.Add( (New-Entity -Name $psgetItemInfo.Author -Role 'author') ) } if($psgetItemInfo.CompanyName -and $psgetItemInfo.CompanyName.ToString()) { $entities.Add( (New-Entity -Name $psgetItemInfo.CompanyName -Role 'owner') ) } $details = @{ description = $psgetItemInfo.Description copyright = $psgetItemInfo.Copyright published = $psgetItemInfo.PublishedDate.ToString() installeddate = $null updateddate = $null tags = $psgetItemInfo.Tags releaseNotes = $psgetItemInfo.ReleaseNotes PackageManagementProvider = (Get-ProviderName -PSCustomObject $psgetItemInfo) } if((Get-Member -InputObject $psgetItemInfo -Name 'InstalledDate') -and $psgetItemInfo.InstalledDate) { $details['installeddate'] = $psgetItemInfo.InstalledDate.ToString('O', [System.Globalization.DateTimeFormatInfo]::InvariantInfo) } if((Get-Member -InputObject $psgetItemInfo -Name 'UpdatedDate') -and $psgetItemInfo.UpdatedDate) { $details['updateddate'] = $psgetItemInfo.UpdatedDate.ToString('O', [System.Globalization.DateTimeFormatInfo]::InvariantInfo) } if(Get-Member -InputObject $psgetItemInfo -Name $script:InstalledLocation) { $details[$script:InstalledLocation] = $psgetItemInfo.InstalledLocation } $details[$script:PSArtifactType] = $artifactType $sourceName = Get-SourceName -Location $SourceLocation if($sourceName) { $details["SourceName"] = $sourceName } $params = @{ FastPackageReference = $fastPackageReference; Name = $psgetItemInfo.Name; Version = $psgetItemInfo.Version; versionScheme = "MultiPartNumeric"; Source = $SourceLocation; Summary = $psgetItemInfo.Description; Details = $details; Entities = $entities; Links = $links } if($sourceName -and $script:PSGetModuleSources[$sourceName].Trusted) { $params["FromTrustedSource"] = $true } $sid = New-SoftwareIdentity @params return $sid } #endregion #region Common functions function Get-EnvironmentVariable { param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Name, [parameter(Mandatory = $true)] [int] $Target ) if ($Target -eq $script:EnvironmentVariableTarget.Process) { return [System.Environment]::GetEnvironmentVariable($Name) } elseif ($Target -eq $script:EnvironmentVariableTarget.Machine) { if ($Name -eq "path") { # if we need the path environment variable, we need it un-expanded, otherwise # when writing it back, we would loose all the variables like %systemroot% in it. # We use the Win32 API directly using DoNotExpandEnvironmentNames # It is unclear whether any code calling this function for %path% needs the expanded version of %path% # There are currently no tests for this code # Microsoft.PowerShell.Management\Get-ItemProperty is passed through to the PowerShell Registry provider # which currently doesn't seem to support anything like: DoNotExpandEnvironmentNames $hklmHive = [Microsoft.Win32.Registry]::LocalMachine $EnvRegKey = $hklmHive.OpenSubKey("SYSTEM\CurrentControlSet\Control\Session Manager\Environment", $FALSE) $itemPropertyValue = $EnvRegKey.GetValue($Name, "", [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) return $itemPropertyValue } else { $itemPropertyValue = Microsoft.PowerShell.Management\Get-ItemProperty -Path $script:SystemEnvironmentKey -Name $Name -ErrorAction SilentlyContinue if($itemPropertyValue) { return $itemPropertyValue.$Name } } } elseif ($Target -eq $script:EnvironmentVariableTarget.User) { $itemPropertyValue = Microsoft.PowerShell.Management\Get-ItemProperty -Path $script:UserEnvironmentKey -Name $Name -ErrorAction SilentlyContinue if($itemPropertyValue) { return $itemPropertyValue.$Name } } } function Set-EnvironmentVariable { param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [String] $Name, [parameter()] [String] $Value, [parameter(Mandatory = $true)] [int] $Target ) if ($Target -eq $script:EnvironmentVariableTarget.Process) { [System.Environment]::SetEnvironmentVariable($Name, $Value) return } elseif ($Target -eq $script:EnvironmentVariableTarget.Machine) { if ($Name.Length -ge $script:SystemEnvironmentVariableMaximumLength) { $message = $LocalizedData.InvalidEnvironmentVariableName -f ($Name, $script:SystemEnvironmentVariableMaximumLength) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'InvalidEnvironmentVariableName' ` -ErrorCategory InvalidArgument ` -ExceptionObject $Name return } $Path = $script:SystemEnvironmentKey } elseif ($Target -eq $script:EnvironmentVariableTarget.User) { if ($Name.Length -ge $script:UserEnvironmentVariableMaximumLength) { $message = $LocalizedData.InvalidEnvironmentVariableName -f ($Name, $script:UserEnvironmentVariableMaximumLength) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId 'InvalidEnvironmentVariableName' ` -ErrorCategory InvalidArgument ` -ExceptionObject $Name return } $Path = $script:UserEnvironmentKey } if (!$Value) { Microsoft.PowerShell.Management\Remove-ItemProperty $Path -Name $Name -ErrorAction SilentlyContinue } else { Microsoft.PowerShell.Management\Set-ItemProperty $Path -Name $Name -Value $Value } # Broadcast the Environment variable changes, so that other processes pick changes to Environment variables without having to reboot or logoff/logon. Send-EnvironmentChangeMessage } # Broadcast the Environment variable changes, so that other processes pick changes to Environment variables without having to reboot or logoff/logon. function Send-EnvironmentChangeMessage { if($Script:IsWindows) { if (-not ('Microsoft.PowerShell.Commands.PowerShellGet.Win32.NativeMethods' -as [type])) { Add-Type -Namespace Microsoft.PowerShell.Commands.PowerShellGet.Win32 ` -Name NativeMethods ` -MemberDefinition @' [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] public static extern IntPtr SendMessageTimeout( IntPtr hWnd, uint Msg, UIntPtr wParam, string lParam, uint fuFlags, uint uTimeout, out UIntPtr lpdwResult); '@ } $HWND_BROADCAST = [System.IntPtr]0xffff $WM_SETTINGCHANGE = 0x1a $result = [System.UIntPtr]::zero $returnValue = [Microsoft.PowerShell.Commands.PowerShellGet.Win32.NativeMethods]::SendMessageTimeout($HWND_BROADCAST, $WM_SETTINGCHANGE, [System.UIntPtr]::Zero, 'Environment', 2, 5000, [ref]$result) if($returnValue) { Write-Verbose -Message $LocalizedData.SentEnvironmentVariableChangeMessage } else { Write-Warning -Message $LocalizedData.UnableToSendEnvironmentVariableChangeMessage } } } function DeSerialize-PSObject { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] $Path ) $filecontent = Microsoft.PowerShell.Management\Get-Content -Path $Path [System.Management.Automation.PSSerializer]::Deserialize($filecontent) } function Log-ArtifactNotFoundInPSGallery { [CmdletBinding()] Param ( [Parameter()] [string[]] $SearchedName, [Parameter()] [string[]] $FoundName, [Parameter(Mandatory=$true)] [string] $operationName ) if (-not $script:TelemetryEnabled) { return } if(-not $SearchedName) { return } $SearchedNameNoWildCards = @() # Ignore wild cards foreach ($artifactName in $SearchedName) { if (-not (Test-WildcardPattern $artifactName)) { $SearchedNameNoWildCards += $artifactName } } # Find artifacts searched, but not found in the specified gallery $notFoundArtifacts = @() foreach ($element in $SearchedNameNoWildCards) { if (-not ($FoundName -contains $element)) { $notFoundArtifacts += $element } } # Perform Telemetry only if searched artifacts are not available in specified Gallery if ($notFoundArtifacts) { [Microsoft.PowerShell.Commands.PowerShellGet.Telemetry]::TraceMessageArtifactsNotFound($notFoundArtifacts, $operationName) } } # Function to record non-PSGallery registration for telemetry # Function consumes the type of registration (i.e hosted (http(s)), non-hosted (file/unc)), locations, installation policy, provider and event name function Log-NonPSGalleryRegistration { [CmdletBinding()] Param ( [Parameter()] [string] $sourceLocation, [Parameter()] [string] $installationPolicy, [Parameter()] [string] $packageManagementProvider, [Parameter()] [string] $publishLocation, [Parameter()] [string] $scriptSourceLocation, [Parameter()] [string] $scriptPublishLocation, [Parameter(Mandatory=$true)] [string] $operationName ) if (-not $script:TelemetryEnabled) { return } # Initialize source location type - this can be hosted (http(s)) or not hosted (unc/file) $sourceLocationType = "NON_WEB_HOSTED" if (Test-WebUri -uri $sourceLocation) { $sourceLocationType = "WEB_HOSTED" } # Create a hash of the source location # We cannot log the actual source location, since this might contain PII (Personally identifiable information) data $sourceLocationHash = Get-Hash -locationString $sourceLocation $publishLocationHash = Get-Hash -locationString $publishLocation $scriptSourceLocationHash = Get-Hash -locationString $scriptSourceLocation $scriptPublishLocationHash = Get-Hash -locationString $scriptPublishLocation # Log the telemetry event [Microsoft.PowerShell.Commands.PowerShellGet.Telemetry]::TraceMessageNonPSGalleryRegistration($sourceLocationType, $sourceLocationHash, $installationPolicy, $packageManagementProvider, $publishLocationHash, $scriptSourceLocationHash, $scriptPublishLocationHash, $operationName) } # Returns a SHA1 hash of the specified string function Get-Hash { [CmdletBinding()] Param ( [string] $locationString ) if(-not $locationString) { return "" } $sha1Object = New-Object System.Security.Cryptography.SHA1Managed $stringHash = $sha1Object.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($locationString)); $stringHashInHex = [System.BitConverter]::ToString($stringHash) if ($stringHashInHex) { # Remove all dashes in the hex string return $stringHashInHex.Replace('-', '') } return "" } function Get-ValidModuleLocation { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $LocationString, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $ParameterName, [Parameter()] $Credential, [Parameter()] $Proxy, [Parameter()] $ProxyCredential ) # Get the actual Uri from the Location if(-not (Microsoft.PowerShell.Management\Test-Path $LocationString)) { # Append '/api/v2/' to the $LocationString, return if that URI works. if(($LocationString -notmatch 'LinkID') -and -not ($LocationString.EndsWith('/nuget/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('/nuget/v2/', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('/nuget', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('/nuget/', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('index.json', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('index.json/', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) -and -not ($LocationString.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) ) { $tempLocation = $null if($LocationString.EndsWith('/', [System.StringComparison]::OrdinalIgnoreCase)) { $tempLocation = $LocationString + 'api/v2/' } else { $tempLocation = $LocationString + '/api/v2/' } if($tempLocation) { # Ping and resolve the specified location $tempLocation = Resolve-Location -Location $tempLocation ` -LocationParameterName $ParameterName ` -Credential $Credential ` -Proxy $Proxy ` -ProxyCredential $ProxyCredential ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if($tempLocation) { return $tempLocation } # No error if we can't resolve the URL appended with '/api/v2/' } } # Ping and resolve the specified location $LocationString = Resolve-Location -Location $LocationString ` -LocationParameterName $ParameterName ` -Credential $Credential ` -Proxy $Proxy ` -ProxyCredential $ProxyCredential ` -CallerPSCmdlet $PSCmdlet } return $LocationString } function Save-ModuleSources { if($script:PSGetModuleSources) { if(-not (Microsoft.PowerShell.Management\Test-Path $script:PSGetAppLocalPath)) { $null = Microsoft.PowerShell.Management\New-Item -Path $script:PSGetAppLocalPath ` -ItemType Directory -Force ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false -WhatIf:$false } Microsoft.PowerShell.Utility\Out-File -FilePath $script:PSGetModuleSourcesFilePath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($script:PSGetModuleSources)) } } function Test-ModuleSxSVersionSupport { # Side-by-Side module version is available on PowerShell 5.0 or later versions only # By default, PowerShell module versions will be installed/updated Side-by-Side. $PSVersionTable.PSVersion -ge '5.0.0' } function Test-ModuleInstalled { [CmdletBinding(PositionalBinding=$false)] [OutputType("PSModuleInfo")] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter()] [string] $RequiredVersion ) # Check if module is already installed $availableModule = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false | Microsoft.PowerShell.Core\Where-Object { -not (Test-ModuleSxSVersionSupport) ` -or (-not $RequiredVersion) ` -or ($RequiredVersion.Trim() -eq $_.Version.ToString()) ` -or (Test-ItemPrereleaseVersionRequirements -Version $_.Version -RequiredVersion $RequiredVersion) } | Microsoft.PowerShell.Utility\Select-Object -Unique -First 1 -ErrorAction Ignore return $availableModule } function Test-ScriptInstalled { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Name, [Parameter()] [string] $RequiredVersion ) $scriptInfo = $null $scriptFileName = "$Name.ps1" $scriptPaths = @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) $scriptInfos = @() if ($RequiredVersion) { $reqResult = ValidateAndGet-VersionPrereleaseStrings -Version $RequiredVersion -CallerPSCmdlet $PSCmdlet if (-not $reqResult) { return } $reqFullVersion = $reqResult["FullVersion"] } foreach ($location in $scriptPaths) { $scriptFilePath = Microsoft.PowerShell.Management\Join-Path -Path $location -ChildPath $scriptFileName if(Microsoft.PowerShell.Management\Test-Path -Path $scriptFilePath -PathType Leaf) { $scriptInfo = $null try { $scriptInfo = Test-ScriptFileInfo -Path $scriptFilePath -ErrorAction SilentlyContinue -WarningAction SilentlyContinue } catch { # Ignore any terminating error from the Test-ScriptFileInfo cmdlet, # if it does not contain valid Script metadata Write-Verbose -Message "$_" } if($scriptInfo) { $scriptInfos += $scriptInfo } else { # Since the script file doesn't contain the valid script metadata, # create dummy PSScriptInfo object with 0.0 version $scriptInfo = New-PSScriptInfoObject -Path $scriptFilePath $scriptInfo.$script:Version = [Version]'0.0' $scriptInfos += $scriptInfo } } } $scriptInfo = $scriptInfos | Microsoft.PowerShell.Core\Where-Object { $thisResult = ValidateAndGet-VersionPrereleaseStrings -Version $_.Version -CallerPSCmdlet $PSCmdlet if (-not $thisResult) { return } $thisFullVersion = $thisResult["FullVersion"] (-not $RequiredVersion) -or ($reqFullVersion -eq $thisFullVersion) } | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore return $scriptInfo } function New-PSScriptInfoObject { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [string] $Path ) $PSScriptInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{}) $script:PSScriptInfoProperties | Microsoft.PowerShell.Core\ForEach-Object { Microsoft.PowerShell.Utility\Add-Member -InputObject $PSScriptInfo ` -MemberType NoteProperty ` -Name $_ ` -Value $null } $PSScriptInfo.$script:Name = [System.IO.Path]::GetFileNameWithoutExtension($Path) $PSScriptInfo.$script:Path = $Path $PSScriptInfo.$script:ScriptBase = (Microsoft.PowerShell.Management\Split-Path -Path $Path -Parent) return $PSScriptInfo } function Get-OrderedPSScriptInfoObject { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [PSCustomObject] $PSScriptInfo ) $NewPSScriptInfo = Microsoft.PowerShell.Utility\New-Object PSCustomObject -Property ([ordered]@{ $script:Name = $PSScriptInfo.$script:Name $script:Version = $PSScriptInfo.$script:Version $script:Guid = $PSScriptInfo.$script:Guid $script:Path = $PSScriptInfo.$script:Path $script:ScriptBase = $PSScriptInfo.$script:ScriptBase $script:Description = $PSScriptInfo.$script:Description $script:Author = $PSScriptInfo.$script:Author $script:CompanyName = $PSScriptInfo.$script:CompanyName $script:Copyright = $PSScriptInfo.$script:Copyright $script:Tags = $PSScriptInfo.$script:Tags $script:ReleaseNotes = $PSScriptInfo.$script:ReleaseNotes $script:RequiredModules = $PSScriptInfo.$script:RequiredModules $script:ExternalModuleDependencies = $PSScriptInfo.$script:ExternalModuleDependencies $script:RequiredScripts = $PSScriptInfo.$script:RequiredScripts $script:ExternalScriptDependencies = $PSScriptInfo.$script:ExternalScriptDependencies $script:LicenseUri = $PSScriptInfo.$script:LicenseUri $script:ProjectUri = $PSScriptInfo.$script:ProjectUri $script:IconUri = $PSScriptInfo.$script:IconUri $script:DefinedCommands = $PSScriptInfo.$script:DefinedCommands $script:DefinedFunctions = $PSScriptInfo.$script:DefinedFunctions $script:DefinedWorkflows = $PSScriptInfo.$script:DefinedWorkflows $script:PrivateData = $PSScriptInfo.$script:PrivateData }) $NewPSScriptInfo.PSTypeNames.Insert(0, "Microsoft.PowerShell.Commands.PSScriptInfo") return $NewPSScriptInfo } function Get-AvailableScriptFilePath { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter()] [string] $Name ) $scriptInfo = $null $scriptFileName = '*.ps1' $scriptBasePaths = @($script:ProgramFilesScriptsPath, $script:MyDocumentsScriptsPath) $scriptFilePaths = @() $wildcardPattern = $null if($Name) { if(Test-WildcardPattern -Name $Name) { $wildcardPattern = New-Object System.Management.Automation.WildcardPattern $Name,$script:wildcardOptions } else { $scriptFileName = "$Name.ps1" } } foreach ($location in $scriptBasePaths) { $scriptFiles = Get-ChildItem -Path $location ` -Filter $scriptFileName ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue if($wildcardPattern) { $scriptFiles | Microsoft.PowerShell.Core\ForEach-Object { if($wildcardPattern.IsMatch($_.BaseName)) { $scriptFilePaths += $_.FullName } } } else { $scriptFiles | Microsoft.PowerShell.Core\ForEach-Object { $scriptFilePaths += $_.FullName } } } return $scriptFilePaths } function Get-InstalledScriptFilePath { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter()] [string] $Name ) $installedScriptFilePaths = @() $scriptFilePaths = Get-AvailableScriptFilePath @PSBoundParameters foreach ($scriptFilePath in $scriptFilePaths) { $scriptInfo = Test-ScriptInstalled -Name ([System.IO.Path]::GetFileNameWithoutExtension($scriptFilePath)) if($scriptInfo) { $installedScriptInfoFilePath = $null $installedScriptInfoFileName = "$($scriptInfo.Name)_$script:InstalledScriptInfoFileName" if($scriptInfo.Path.StartsWith($script:ProgramFilesScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) { $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` -ChildPath $installedScriptInfoFileName } elseif($scriptInfo.Path.StartsWith($script:MyDocumentsScriptsPath, [System.StringComparison]::OrdinalIgnoreCase)) { $installedScriptInfoFilePath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` -ChildPath $installedScriptInfoFileName } if($installedScriptInfoFilePath -and (Microsoft.PowerShell.Management\Test-Path -Path $installedScriptInfoFilePath -PathType Leaf)) { $installedScriptFilePaths += $scriptInfo.Path } } } return $installedScriptFilePaths } function Update-ModuleManifest { <# .ExternalHelp PSGet.psm1-help.xml #> [CmdletBinding(SupportsShouldProcess=$true, PositionalBinding=$false, HelpUri='https://go.microsoft.com/fwlink/?LinkId=619311')] Param ( [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)] [ValidateNotNullOrEmpty()] [string] $Path, [ValidateNotNullOrEmpty()] [Object[]] $NestedModules, [ValidateNotNullOrEmpty()] [Guid] $Guid, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Author, [Parameter()] [ValidateNotNullOrEmpty()] [String] $CompanyName, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Copyright, [Parameter()] [ValidateNotNullOrEmpty()] [string] $RootModule, [Parameter()] [ValidateNotNullOrEmpty()] [Version] $ModuleVersion, [Parameter()] [ValidateNotNullOrEmpty()] [string] $Description, [Parameter()] [ValidateNotNullOrEmpty()] [System.Reflection.ProcessorArchitecture] $ProcessorArchitecture, [Parameter()] [ValidateSet('Desktop','Core')] [string[]] $CompatiblePSEditions, [Parameter()] [ValidateNotNullOrEmpty()] [Version] $PowerShellVersion, [Parameter()] [ValidateNotNullOrEmpty()] [Version] $ClrVersion, [Parameter()] [ValidateNotNullOrEmpty()] [Version] $DotNetFrameworkVersion, [Parameter()] [ValidateNotNullOrEmpty()] [String] $PowerShellHostName, [Parameter()] [ValidateNotNullOrEmpty()] [Version] $PowerShellHostVersion, [Parameter()] [ValidateNotNullOrEmpty()] [Object[]] $RequiredModules, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $TypesToProcess, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $FormatsToProcess, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $ScriptsToProcess, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $RequiredAssemblies, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $FileList, [Parameter()] [ValidateNotNullOrEmpty()] [object[]] $ModuleList, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $FunctionsToExport, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $AliasesToExport, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $VariablesToExport, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $CmdletsToExport, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $DscResourcesToExport, [Parameter()] [ValidateNotNullOrEmpty()] [System.Collections.Hashtable] $PrivateData, [Parameter()] [ValidateNotNullOrEmpty()] [string[]] $Tags, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $ProjectUri, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $LicenseUri, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $IconUri, [Parameter()] [string[]] $ReleaseNotes, [Parameter()] [string] $Prerelease, [Parameter()] [ValidateNotNullOrEmpty()] [Uri] $HelpInfoUri, [Parameter()] [switch] $PassThru, [Parameter()] [ValidateNotNullOrEmpty()] [String] $DefaultCommandPrefix, [Parameter()] [ValidateNotNullOrEmpty()] [String[]] $ExternalModuleDependencies, [Parameter()] [ValidateNotNullOrEmpty()] [String[]] $PackageManagementProviders, [Parameter()] [switch] $RequireLicenseAcceptance ) if(-not (Microsoft.PowerShell.Management\Test-Path -Path $Path -PathType Leaf)) { $message = $LocalizedData.UpdateModuleManifestPathCannotFound -f ($Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidModuleManifestFilePath" ` -ExceptionObject $Path ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } $ModuleManifestHashTable = $null try { $ModuleManifestHashTable = Get-ManifestHashTable -Path $Path -CallerPSCmdlet $PSCmdlet } catch { $message = $LocalizedData.TestModuleManifestFail -f ($_.Exception.Message) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidModuleManifestFile" ` -ExceptionObject $Path ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } #Get the original module manifest and migrate all the fields to the new module manifest, including the specified parameter values $moduleInfo = $null try { $moduleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $Path -ErrorAction Stop } catch { # Throw an error only if Test-ModuleManifest did not return the PSModuleInfo object. # This enables the users to use Update-ModuleManifest cmdlet to update the metadata. if(-not $moduleInfo) { $message = $LocalizedData.TestModuleManifestFail -f ($_.Exception.Message) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidModuleManifestFile" ` -ExceptionObject $Path ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } } #Params to pass to New-ModuleManifest module $params = @{} #NestedModules is read-only property if($NestedModules) { $params.Add("NestedModules",$NestedModules) } elseif($moduleInfo.NestedModules) { #Get the original module info from ManifestHashTab if($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("NestedModules")) { $params.Add("NestedModules",$ModuleManifestHashtable.NestedModules) } } #Guid is read-only property if($Guid) { $params.Add("Guid",$Guid) } elseif($moduleInfo.Guid) { $params.Add("Guid",$moduleInfo.Guid) } if($Author) { $params.Add("Author",$Author) } elseif($moduleInfo.Author) { $params.Add("Author",$moduleInfo.Author) } if($CompanyName) { $params.Add("CompanyName",$CompanyName) } elseif($moduleInfo.CompanyName) { $params.Add("CompanyName",$moduleInfo.CompanyName) } if($Copyright) { $params.Add("CopyRight",$Copyright) } elseif($moduleInfo.Copyright) { $params.Add("Copyright",$moduleInfo.Copyright) } if($RootModule) { $params.Add("RootModule",$RootModule) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RootModule") -and $moduleInfo.RootModule) { $params.Add("RootModule",$ModuleManifestHashTable.RootModule) } if($ModuleVersion) { $params.Add("ModuleVersion",$ModuleVersion) } elseif($moduleInfo.Version) { $params.Add("ModuleVersion",$moduleInfo.Version) } if($Description) { $params.Add("Description",$Description) } elseif($moduleInfo.Description) { $params.Add("Description",$moduleInfo.Description) } if($ProcessorArchitecture) { $params.Add("ProcessorArchitecture",$ProcessorArchitecture) } #Check if ProcessorArchitecture has a value and is not 'None' on lower version PS elseif($moduleInfo.ProcessorArchitecture -and $moduleInfo.ProcessorArchitecture -ne 'None') { $params.Add("ProcessorArchitecture",$moduleInfo.ProcessorArchitecture) } if($PowerShellVersion) { $params.Add("PowerShellVersion",$PowerShellVersion) } elseif($moduleinfo.PowerShellVersion) { $params.Add("PowerShellVersion",$moduleinfo.PowerShellVersion) } if($ClrVersion) { $params.Add("ClrVersion",$ClrVersion) } elseif($moduleInfo.ClrVersion) { $params.Add("ClrVersion",$moduleInfo.ClrVersion) } if($DotNetFrameworkVersion) { $params.Add("DotNetFrameworkVersion",$DotNetFrameworkVersion) } elseif($moduleInfo.DotNetFrameworkVersion) { $params.Add("DotNetFrameworkVersion",$moduleInfo.DotNetFrameworkVersion) } if($PowerShellHostName) { $params.Add("PowerShellHostName",$PowerShellHostName) } elseif($moduleInfo.PowerShellHostName) { $params.Add("PowerShellHostName",$moduleInfo.PowerShellHostName) } if($PowerShellHostVersion) { $params.Add("PowerShellHostVersion",$PowerShellHostVersion) } elseif($moduleInfo.PowerShellHostVersion) { $params.Add("PowerShellHostVersion",$moduleInfo.PowerShellHostVersion) } if($RequiredModules) { $params.Add("RequiredModules",$RequiredModules) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RequiredModules") -and $moduleInfo.RequiredModules) { $params.Add("RequiredModules",$ModuleManifestHashtable.RequiredModules) } if($TypesToProcess) { $params.Add("TypesToProcess",$TypesToProcess) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("TypesToProcess") -and $moduleInfo.ExportedTypeFiles) { $params.Add("TypesToProcess",$ModuleManifestHashTable.TypesToProcess) } if($FormatsToProcess) { $params.Add("FormatsToProcess",$FormatsToProcess) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("FormatsToProcess") -and $moduleInfo.ExportedFormatFiles) { $params.Add("FormatsToProcess",$ModuleManifestHashTable.FormatsToProcess) } if($ScriptsToProcess) { $params.Add("ScriptsToProcess",$ScriptstoProcess) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("ScriptsToProcess") -and $moduleInfo.Scripts) { $params.Add("ScriptsToProcess",$ModuleManifestHashTable.ScriptsToProcess) } if($RequiredAssemblies) { $params.Add("RequiredAssemblies",$RequiredAssemblies) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("RequiredAssemblies") -and $moduleInfo.RequiredAssemblies) { $params.Add("RequiredAssemblies",$moduleInfo.RequiredAssemblies) } if($FileList) { $params.Add("FileList",$FileList) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("FileList") -and $moduleInfo.FileList) { $params.Add("FileList",$ModuleManifestHashTable.FileList) } #Make sure every path defined under FileList is within module base $moduleBase = $moduleInfo.ModuleBase foreach($file in $params["FileList"]) { #If path is not root path, append the module base to it and check if the file exists if(-not [System.IO.Path]::IsPathRooted($file)) { $combinedPath = Join-Path $moduleBase -ChildPath $file } else { $combinedPath = $file } if(-not (Microsoft.PowerShell.Management\Test-Path -Type Leaf -LiteralPath $combinedPath)) { $message = $LocalizedData.FilePathInFileListNotWithinModuleBase -f ($file,$moduleBase) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "FilePathInFileListNotWithinModuleBase" ` -ExceptionObject $file ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } } if($ModuleList) { $params.Add("ModuleList",$ModuleList) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("ModuleList") -and $moduleInfo.ModuleList) { $params.Add("ModuleList",$ModuleManifestHashtable.ModuleList) } if($FunctionsToExport) { $params.Add("FunctionsToExport",$FunctionsToExport) } elseif($moduleInfo.ExportedFunctions) { #Since $moduleInfo.ExportedFunctions is a hashtable, we need to take the name of the #functions and make them into a list $params.Add("FunctionsToExport",($moduleInfo.ExportedFunctions.Keys -split ' ')) } if($AliasesToExport) { $params.Add("AliasesToExport",$AliasesToExport) } elseif($moduleInfo.ExportedAliases) { $params.Add("AliasesToExport",($moduleInfo.ExportedAliases.Keys -split ' ')) } if($VariablesToExport) { $params.Add("VariablesToExport",$VariablesToExport) } elseif($moduleInfo.ExportedVariables) { $params.Add("VariablesToExport",($moduleInfo.ExportedVariables.Keys -split ' ')) } if($CmdletsToExport) { $params.Add("CmdletsToExport", $CmdletsToExport) } elseif($moduleInfo.ExportedCmdlets) { $params.Add("CmdletsToExport",($moduleInfo.ExportedCmdlets.Keys -split ' ')) } if($DscResourcesToExport) { #DscResourcesToExport field is not available in PowerShell version lower than 5.0 if (($PSVersionTable.PSVersion -lt '5.0.0') -or ($PowerShellVersion -and $PowerShellVersion -lt '5.0') ` -or (-not $PowerShellVersion -and $moduleInfo.PowerShellVersion -and $moduleInfo.PowerShellVersion -lt '5.0') ` -or (-not $PowerShellVersion -and -not $moduleInfo.PowerShellVersion)) { ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $LocalizedData.ExportedDscResourcesNotSupportedOnLowerPowerShellVersion ` -ErrorId "ExportedDscResourcesNotSupported" ` -ExceptionObject $DscResourcesToExport ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } $params.Add("DscResourcesToExport",$DscResourcesToExport) } elseif(Microsoft.PowerShell.Utility\Get-Member -InputObject $moduleInfo -name "ExportedDscResources") { if($moduleInfo.ExportedDscResources) { $params.Add("DscResourcesToExport",$moduleInfo.ExportedDscResources) } } if($CompatiblePSEditions) { # CompatiblePSEditions field is not available in PowerShell version lower than 5.1 # if (($PSVersionTable.PSVersion -lt '5.1.0') -or ($PowerShellVersion -and $PowerShellVersion -lt '5.1') ` -or (-not $PowerShellVersion -and $moduleInfo.PowerShellVersion -and $moduleInfo.PowerShellVersion -lt '5.1') ` -or (-not $PowerShellVersion -and -not $moduleInfo.PowerShellVersion)) { ThrowError -ExceptionName 'System.ArgumentException' ` -ExceptionMessage $LocalizedData.CompatiblePSEditionsNotSupportedOnLowerPowerShellVersion ` -ErrorId 'CompatiblePSEditionsNotSupported' ` -ExceptionObject $CompatiblePSEditions ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } $params.Add('CompatiblePSEditions', $CompatiblePSEditions) } elseif( (Microsoft.PowerShell.Utility\Get-Member -InputObject $moduleInfo -name 'CompatiblePSEditions') -and $moduleInfo.CompatiblePSEditions) { $params.Add('CompatiblePSEditions', $moduleInfo.CompatiblePSEditions) } if($HelpInfoUri) { $params.Add("HelpInfoUri",$HelpInfoUri) } elseif($moduleInfo.HelpInfoUri) { $params.Add("HelpInfoUri",$moduleInfo.HelpInfoUri) } if($DefaultCommandPrefix) { $params.Add("DefaultCommandPrefix",$DefaultCommandPrefix) } elseif($ModuleManifestHashTable -and $ModuleManifestHashTable.ContainsKey("DefaultCommandPrefix") -and $ModuleManifestHashTable.DefaultCommandPrefix) { $params.Add("DefaultCommandPrefix",$ModuleManifestHashTable.DefaultCommandPrefix) } #Create a temp file within the directory and generate a new temporary manifest with the input $tempPath = Microsoft.PowerShell.Management\Join-Path -Path $moduleInfo.ModuleBase -ChildPath "PSGet_$($moduleInfo.Name).psd1" $params.Add("Path",$tempPath) try { #Terminates if there is error creating new module manifest try{ Microsoft.PowerShell.Core\New-ModuleManifest @params -Confirm:$false -WhatIf:$false } catch { $ErrorMessage = $LocalizedData.UpdatedModuleManifestNotValid -f ($Path, $_.Exception.Message) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $ErrorMessage ` -ErrorId "NewModuleManifestFailure" ` -ExceptionObject $params ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } #Manually update the section in PrivateData since New-ModuleManifest works differently on different PS version $PrivateDataInput = "" $ExistingData = $moduleInfo.PrivateData $Data = @{} if($ExistingData) { foreach($key in $ExistingData.Keys) { if($key -ne "PSData"){ $Data.Add($key,$ExistingData[$key]) } else { $PSData = $ExistingData["PSData"] foreach($entry in $PSData.Keys) { $Data.Add($entry,$PSData[$Entry]) } } } } if($PrivateData) { foreach($key in $PrivateData.Keys) { #if user provides PSData within PrivateData, we will parse through the PSData if($key -ne "PSData") { $Data[$key] = $PrivateData[$Key] } else { $PSData = $ExistingData["PSData"] foreach($entry in $PSData.Keys) { $Data[$entry] = $PSData[$entry] } } } } #Tags is a read-only property if($Tags) { $Data["Tags"] = $Tags } #The following Uris and ReleaseNotes cannot be empty if($ProjectUri) { $Data["ProjectUri"] = $ProjectUri } if($LicenseUri) { $Data["LicenseUri"] = $LicenseUri } if($IconUri) { $Data["IconUri"] = $IconUri } if($RequireLicenseAcceptance) { $Data["RequireLicenseAcceptance"] = $RequireLicenseAcceptance } if($ReleaseNotes) { #If value is provided as an array, we append the string. $Data["ReleaseNotes"] = $($ReleaseNotes -join "`r`n") } if ($Prerelease) { $result = ValidateAndGet-VersionPrereleaseStrings -Version $params["ModuleVersion"] -Prerelease $Prerelease -CallerPSCmdlet $PSCmdlet if (-not $result) { # ValidateAndGet-VersionPrereleaseStrings throws the error. # returning to avoid further execution when different values are specified for -ErrorAction parameter return } $validatedPrerelease = $result["Prerelease"] $Data[$script:Prerelease] = $validatedPrerelease } if($ExternalModuleDependencies) { #ExternalModuleDependencies have to be specified either under $RequiredModules or $NestedModules #Extract all the module names specified in the moduleInfo of NestedModules and RequiredModules $DependentModuleNames = @() foreach($moduleInfo in $params["NestedModules"]) { if($moduleInfo.GetType() -eq [System.Collections.Hashtable]) { $DependentModuleNames += $moduleInfo.ModuleName } } foreach($moduleInfo in $params["RequiredModules"]) { if($moduleInfo.GetType() -eq [System.Collections.Hashtable]) { $DependentModuleNames += $moduleInfo.ModuleName } } foreach($dependency in $ExternalModuleDependencies) { if($params["NestedModules"] -notcontains $dependency -and $params["RequiredModules"] -notContains $dependency -and $DependentModuleNames -notcontains $dependency) { $message = $LocalizedData.ExternalModuleDependenciesNotSpecifiedInRequiredOrNestedModules -f ($dependency) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidExternalModuleDependencies" ` -ExceptionObject $Exception ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } } if($Data.ContainsKey("ExternalModuleDependencies")) { $Data["ExternalModuleDependencies"] = $ExternalModuleDependencies } else { $Data.Add("ExternalModuleDependencies", $ExternalModuleDependencies) } } if($PackageManagementProviders) { #Check if the provided value is within the relative path $ModuleBase = Microsoft.PowerShell.Management\Split-Path $Path -Parent $Files = Microsoft.PowerShell.Management\Get-ChildItem -Path $ModuleBase foreach($provider in $PackageManagementProviders) { if ($Files.Name -notcontains $provider) { $message = $LocalizedData.PackageManagementProvidersNotInModuleBaseFolder -f ($provider,$ModuleBase) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidPackageManagementProviders" ` -ExceptionObject $PackageManagementProviders ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } } $Data["PackageManagementProviders"] = $PackageManagementProviders } $PrivateDataInput = Get-PrivateData -PrivateData $Data #Replace the PrivateData section by first locating the linenumbers of start line and endline. $PrivateDataBegin = Select-String -Path $tempPath -Pattern "PrivateData =" $PrivateDataBeginLine = $PrivateDataBegin.LineNumber $newManifest = Microsoft.PowerShell.Management\Get-Content -Path $tempPath #Look up the endline of PrivateData section by finding the matching brackets since private data could #consist of multiple pairs of brackets. $PrivateDataEndLine=0 if($PrivateDataBegin -match "@{") { $leftBrace = 0 $EndLineOfFile = $newManifest.Length-1 For($i = $PrivateDataBeginLine;$i -lt $EndLineOfFile; $i++) { if($newManifest[$i] -match "{") { $leftBrace ++ } elseif($newManifest[$i] -match "}") { if($leftBrace -gt 0) { $leftBrace -- } else { $PrivateDataEndLine = $i break } } } } try { if($PrivateDataEndLine -ne 0) { #If PrivateData section has more than one line, we will remove the old content and insert the new PrivataData $newManifest | where {$_.readcount -le $PrivateDataBeginLine -or $_.readcount -gt $PrivateDataEndLine+1} ` | ForEach-Object { $_ if($_ -match "PrivateData = ") { $PrivateDataInput } } | Set-Content -Path $tempPath -Confirm:$false -WhatIf:$false } #In lower version, PrivateData is just a single line else { $PrivateDataForDownlevelPS = "PrivateData = @{ `n"+$PrivateDataInput $newManifest | where {$_.readcount -le $PrivateDataBeginLine -or $_.readcount -gt $PrivateDataBeginLine } ` | ForEach-Object { $_ if($_ -match "PrivateData = ") { $PrivateDataForDownlevelPS } } | Set-Content -Path $tempPath -Confirm:$false -WhatIf:$false } #Verify the new module manifest is valid $testModuleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $tempPath ` -Verbose:$VerbosePreference ` } #Catch the exceptions from Test-ModuleManifest catch { $message = $LocalizedData.UpdatedModuleManifestNotValid -f ($Path, $_.Exception.Message) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "UpdateManifestFileFail" ` -ExceptionObject $_.Exception ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument return } $newContent = Microsoft.PowerShell.Management\Get-Content -Path $tempPath try { #Ask for confirmation of the new manifest before replacing the original one if($PSCmdlet.ShouldProcess($Path,$LocalizedData.UpdateManifestContentMessage+$newContent)) { Microsoft.PowerShell.Management\Set-Content -Path $Path -Value $newContent -Confirm:$false -WhatIf:$false } #Return the new content if -PassThru is specified if($PassThru) { return $newContent } } catch { $message = $LocalizedData.ManifestFileReadWritePermissionDenied -f ($Path) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "ManifestFileReadWritePermissionDenied" ` -ExceptionObject $Path ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument } } finally { Microsoft.PowerShell.Management\Remove-Item -LiteralPath $tempPath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } } #Utility function to help form the content string for PrivateData function Get-PrivateData { param ( [System.Collections.Hashtable] $PrivateData ) if($PrivateData.Keys.Count -eq 0) { $content = " PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. # Tags = @() # A URL to the license for this module. # LicenseUri = '' # A URL to the main website for this project. # ProjectUri = '' # A URL to an icon representing this module. # IconUri = '' # ReleaseNotes of this module # ReleaseNotes = '' # Prerelease string of this module # Prerelease = '' # Flag to indicate whether the module requires explicit user acceptance for install/update/save # RequireLicenseAcceptance = $false # External dependent modules of this module # ExternalModuleDependencies = '' } # End of PSData hashtable } # End of PrivateData hashtable" return $content } #Validate each of the property of PSData is of the desired data type $Tags= $PrivateData["Tags"] -join "','" | %{"'$_'"} $LicenseUri = $PrivateData["LicenseUri"]| %{"'$_'"} $ProjectUri = $PrivateData["ProjectUri"] | %{"'$_'"} $IconUri = $PrivateData["IconUri"] | %{"'$_'"} $ReleaseNotesEscape = $PrivateData["ReleaseNotes"] -Replace "'","''" $ReleaseNotes = $ReleaseNotesEscape | %{"'$_'"} $Prerelease = $PrivateData[$script:Prerelease] | %{"'$_'"} $RequireLicenseAcceptance = $PrivateData["RequireLicenseAcceptance"] $ExternalModuleDependencies = $PrivateData["ExternalModuleDependencies"] -join "','" | %{"'$_'"} $DefaultProperties = @("Tags","LicenseUri","ProjectUri","IconUri","ReleaseNotes",$script:Prerelease,"ExternalModuleDependencies","RequireLicenseAcceptance") $ExtraProperties = @() foreach($key in $PrivateData.Keys) { if($DefaultProperties -notcontains $key) { $PropertyString = "#"+"$key"+ " of this module" $PropertyString += "`r`n " if(($PrivateData[$key]).GetType().IsArray) { $PropertyString += $key +" = " +" @(" $PrivateData[$key] | % { $PropertyString += "'" + $_ +"'" + "," } if($PrivateData[$key].Length -ge 1) { #Remove extra , $PropertyString = $PropertyString -Replace ".$" } $PropertyString += ")" } else { $PropertyString += $key +" = " + "'"+$PrivateData[$key]+"'" } $ExtraProperties += ,$PropertyString } } $ExtraPropertiesString = "" $firstProperty = $true foreach($property in $ExtraProperties) { if($firstProperty) { $firstProperty = $false } else { $ExtraPropertiesString += "`r`n`r`n " } $ExtraPropertiesString += $Property } $TagsLine ="# Tags = @()" if($Tags -ne "''") { $TagsLine = "Tags = "+$Tags } $LicenseUriLine = "# LicenseUri = ''" if($LicenseUri -ne "''") { $LicenseUriLine = "LicenseUri = "+$LicenseUri } $ProjectUriLine = "# ProjectUri = ''" if($ProjectUri -ne "''") { $ProjectUriLine = "ProjectUri = " +$ProjectUri } $IconUriLine = "# IconUri = ''" if($IconUri -ne "''") { $IconUriLine = "IconUri = " +$IconUri } $ReleaseNotesLine = "# ReleaseNotes = ''" if($ReleaseNotes -ne "''") { $ReleaseNotesLine = "ReleaseNotes = "+$ReleaseNotes } $PrereleaseLine = "# Prerelease = ''" if ($Prerelease -ne "''") { $PrereleaseLine = "Prerelease = " +$Prerelease } $RequireLicenseAcceptanceLine = "# RequireLicenseAcceptance = `$false" if($RequireLicenseAcceptance) { $RequireLicenseAcceptanceLine = "RequireLicenseAcceptance = `$true" } $ExternalModuleDependenciesLine ="# ExternalModuleDependencies = @()" if($ExternalModuleDependencies -ne "''") { $ExternalModuleDependenciesLine = "ExternalModuleDependencies = @($ExternalModuleDependencies)" } if(-not $ExtraPropertiesString -eq "") { $Content = " ExtraProperties PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. $TagsLine # A URL to the license for this module. $LicenseUriLine # A URL to the main website for this project. $ProjectUriLine # A URL to an icon representing this module. $IconUriLine # ReleaseNotes of this module $ReleaseNotesLine # Prerelease string of this module $PrereleaseLine # Flag to indicate whether the module requires explicit user acceptance for install/update/save $RequireLicenseAcceptanceLine # External dependent modules of this module $ExternalModuleDependenciesLine } # End of PSData hashtable } # End of PrivateData hashtable" #Replace the Extra PrivateData in the block $Content -replace "ExtraProperties", $ExtraPropertiesString } else { $content = " PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. $TagsLine # A URL to the license for this module. $LicenseUriLine # A URL to the main website for this project. $ProjectUriLine # A URL to an icon representing this module. $IconUriLine # ReleaseNotes of this module $ReleaseNotesLine # Prerelease string of this module $PrereleaseLine # Flag to indicate whether the module requires explicit user acceptance for install/update $RequireLicenseAcceptanceLine # External dependent modules of this module $ExternalModuleDependenciesLine } # End of PSData hashtable } # End of PrivateData hashtable" return $content } } # Separates Version from Prerelease string (if needed) and validates each. function ValidateAndGet-VersionPrereleaseStrings { Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $Version, [string] $Prerelease, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet ) # Scripts scenario if ($Version -match '-' -and -not $Prerelease) { $Version,$Prerelease = $Version -split '-',2 } # Remove leading hyphen (if present) and trim whitespace if ($Prerelease -and $Prerelease.StartsWith('-') ) { $Prerelease = $Prerelease -split '-',2 | Select-Object -Skip 1 } if ($Prerelease) { $Prerelease = $Prerelease.Trim() } # only these characters are allowed in a prerelease string $validCharacters = "^[a-zA-Z0-9]+$" $prereleaseStringValid = $Prerelease -match $validCharacters if ($Prerelease -and -not $prereleaseStringValid) { $message = $LocalizedData.InvalidCharactersInPrereleaseString -f $Prerelease ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidCharactersInPrereleaseString" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $Prerelease } # Validate that Version contains exactly 3 parts if ($Prerelease -and -not ($Version.ToString().Split('.').Count -eq 3)) { $message = $LocalizedData.IncorrectVersionPartsCountForPrereleaseStringUsage -f $Version ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "IncorrectVersionPartsCountForPrereleaseStringUsage" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidOperation ` -ExceptionObject $Version } # try parsing version string [Version]$VersionVersion = $null if (-not ( [System.Version]::TryParse($Version, [ref]$VersionVersion) )) { $message = $LocalizedData.InvalidVersion -f ($Version) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidVersion" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Version } $fullVersion = if ($Prerelease) { "$Version-$Prerelease" } else { $Version } $results = @{ Version = $Version Prerelease = $Prerelease FullVersion = $fullVersion } return $results } function Copy-ScriptFile { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $SourcePath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $DestinationPath, [Parameter(Mandatory=$true)] [ValidateNotNull()] [PSCustomObject] $PSGetItemInfo, [Parameter()] [string] $Scope ) $ev = $null $message = $LocalizedData.AdministratorRightsNeededOrSpecifyCurrentUserScope # Copy the script file to destination if(-not (Microsoft.PowerShell.Management\Test-Path -Path $DestinationPath)) { $null = Microsoft.PowerShell.Management\New-Item -Path $DestinationPath ` -ItemType Directory ` -Force ` -ErrorVariable ev ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false ` -WhatIf:$false if($ev) { $script:IsRunningAsElevated = $false ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "AdministratorRightsNeededOrSpecifyCurrentUserScope" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ev } } Microsoft.PowerShell.Management\Copy-Item -Path $SourcePath ` -Destination $DestinationPath ` -Force ` -Confirm:$false ` -WhatIf:$false ` -ErrorVariable ev ` -ErrorAction SilentlyContinue if($ev) { $script:IsRunningAsElevated = $false ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "AdministratorRightsNeededOrSpecifyCurrentUserScope" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ev } if($Scope) { # Create <Name>_InstalledScriptInfo.xml $InstalledScriptInfoFileName = "$($PSGetItemInfo.Name)_$script:InstalledScriptInfoFileName" if($scope -eq 'AllUsers') { $scriptInfopath = Microsoft.PowerShell.Management\Join-Path -Path $script:ProgramFilesInstalledScriptInfosPath ` -ChildPath $InstalledScriptInfoFileName } else { $scriptInfopath = Microsoft.PowerShell.Management\Join-Path -Path $script:MyDocumentsInstalledScriptInfosPath ` -ChildPath $InstalledScriptInfoFileName } Microsoft.PowerShell.Utility\Out-File -FilePath $scriptInfopath ` -Force ` -InputObject ([System.Management.Automation.PSSerializer]::Serialize($PSGetItemInfo)) } } function Copy-Module { [CmdletBinding(PositionalBinding=$false)] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $SourcePath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $DestinationPath, [Parameter(Mandatory=$true)] [ValidateNotNull()] [PSCustomObject] $PSGetItemInfo ) $ev = $null $message = $LocalizedData.AdministratorRightsNeededOrSpecifyCurrentUserScope if(Microsoft.PowerShell.Management\Test-Path $DestinationPath) { Microsoft.PowerShell.Management\Remove-Item -Path $DestinationPath ` -Recurse ` -Force ` -ErrorVariable ev ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false ` -WhatIf:$false if($ev) { $script:IsRunningAsElevated = $false ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "AdministratorRightsNeededOrSpecifyCurrentUserScope" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ev } } # Copy the module to destination $null = Microsoft.PowerShell.Management\New-Item -Path $DestinationPath ` -ItemType Directory ` -Force ` -ErrorVariable ev ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false ` -WhatIf:$false if($ev) { $script:IsRunningAsElevated = $false ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "AdministratorRightsNeededOrSpecifyCurrentUserScope" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ev } Microsoft.PowerShell.Management\Copy-Item -Path "$SourcePath\*" ` -Destination $DestinationPath ` -Force ` -Recurse ` -ErrorVariable ev ` -ErrorAction SilentlyContinue ` -Confirm:$false ` -WhatIf:$false if($ev) { $script:IsRunningAsElevated = $false ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "AdministratorRightsNeededOrSpecifyCurrentUserScope" ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $ev } # Remove the *.nupkg file $NupkgFilePath = Join-PathUtility -Path $DestinationPath -ChildPath "$($PSGetItemInfo.Name).nupkg" -PathType File if(Microsoft.PowerShell.Management\Test-Path -Path $NupkgFilePath -PathType Leaf) { Microsoft.PowerShell.Management\Remove-Item -Path $NupkgFilePath -Force -ErrorAction SilentlyContinue -WarningAction SilentlyContinue -Confirm:$false -WhatIf:$false } # Create PSGetModuleInfo.xml $psgetItemInfopath = Microsoft.PowerShell.Management\Join-Path $DestinationPath $script:PSGetItemInfoFileName Microsoft.PowerShell.Utility\Out-File -FilePath $psgetItemInfopath -Force -InputObject ([System.Management.Automation.PSSerializer]::Serialize($PSGetItemInfo)) [System.IO.File]::SetAttributes($psgetItemInfopath, [System.IO.FileAttributes]::Hidden) } function Test-FileInUse { [CmdletBinding()] [OutputType([bool])] param ( [string] $FilePath ) if(Microsoft.PowerShell.Management\Test-Path -LiteralPath $FilePath -PathType Leaf) { # Attempts to open a file and handles the exception if the file is already open/locked try { $fileInfo = New-Object System.IO.FileInfo $FilePath $fileStream = $fileInfo.Open( [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None ) if ($fileStream) { $fileStream.Close() } } catch { Write-Debug "In Test-FileInUse function, unable to open the $FilePath file in ReadWrite access. $_" return $true } } return $false } function Test-ModuleInUse { [CmdletBinding()] [OutputType([bool])] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $ModuleBasePath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $ModuleName, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $ModuleVersion ) $FileList = Get-ChildItem -Path $ModuleBasePath ` -File ` -Recurse ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue $IsModuleInUse = $false foreach($file in $FileList) { $IsModuleInUse = Test-FileInUse -FilePath $file.FullName if($IsModuleInUse) { break } } if($IsModuleInUse) { $message = $LocalizedData.ModuleVersionInUse -f ($ModuleVersion, $ModuleName) Write-Error -Message $message -ErrorId 'ModuleIsInUse' -Category InvalidOperation return $true } return $false } function Validate-ModuleAuthenticodeSignature { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] $CurrentModuleInfo, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $InstallLocation, [Parameter()] [Switch] $IsUpdateOperation, [Parameter()] [Switch] $SkipPublisherCheck ) # Skip the publisher check when -SkipPublisherCheck is specified and # it is not an update operation. if(-not $IsUpdateOperation -and $SkipPublisherCheck) { $Message = $LocalizedData.SkippingPublisherCheck -f ($CurrentModuleInfo.Version, $CurrentModuleInfo.Name) Write-Verbose -Message $message return $true } $InstalledModuleDetails = $null $InstalledModuleInfo = Test-ModuleInstalled -Name $CurrentModuleInfo.Name if($InstalledModuleInfo) { $InstalledModuleDetails = Get-InstalledModuleAuthenticodeSignature -InstalledModuleInfo $InstalledModuleInfo ` -InstallLocation $InstallLocation } # Validate the catalog signature for the current module being installed. $ev = $null $CurrentModuleDetails = ValidateAndGet-AuthenticodeSignature -ModuleInfo $CurrentModuleInfo -ErrorVariable ev if($ev) { Write-Debug "$ev" return $false } if($InstalledModuleInfo) { $CurrentModuleAuthenticodePublisher = $null $IsCurrentModuleSignedByMicrosoft = $false if($CurrentModuleDetails) { $CurrentModuleAuthenticodePublisher = $CurrentModuleDetails.Publisher $IsCurrentModuleSignedByMicrosoft = $CurrentModuleDetails.IsMicrosoftCertificate $message = $LocalizedData.NewModuleVersionDetailsForPublisherValidation -f ($CurrentModuleInfo.Name, $CurrentModuleInfo.Version, $CurrentModuleDetails.Publisher, $CurrentModuleDetails.IsMicrosoftCertificate) Write-Verbose $message } $InstalledModuleAuthenticodePublisher = $null $IsInstalledModuleSignedByMicrosoft = $false $InstalledModuleVersion = [Version]'0.0' if($InstalledModuleDetails) { $InstalledModuleAuthenticodePublisher = $InstalledModuleDetails.Publisher $IsInstalledModuleSignedByMicrosoft = $InstalledModuleDetails.IsMicrosoftCertificate $InstalledModuleVersion = $InstalledModuleDetails.Version $message = $LocalizedData.SourceModuleDetailsForPublisherValidation -f ($CurrentModuleInfo.Name, $InstalledModuleDetails.Version, $InstalledModuleDetails.ModuleBase, $InstalledModuleDetails.Publisher, $InstalledModuleDetails.IsMicrosoftCertificate) Write-Verbose $message } Write-Debug -Message "Previously-installed module publisher: $InstalledModuleAuthenticodePublisher" Write-Debug -Message "Current module publisher: $CurrentModuleAuthenticodePublisher" Write-Debug -Message "Is previously-installed module signed by Microsoft: $IsInstalledModuleSignedByMicrosoft" Write-Debug -Message "Is current module signed by Microsoft: $IsCurrentModuleSignedByMicrosoft" if($InstalledModuleAuthenticodePublisher) { if(-not $CurrentModuleAuthenticodePublisher) { $Message = $LocalizedData.ModuleIsNotCatalogSigned -f ($CurrentModuleInfo.Version, $CurrentModuleInfo.Name, "$($CurrentModuleInfo.Name).cat", $InstalledModuleAuthenticodePublisher, $InstalledModuleDetails.Version, $InstalledModuleDetails.ModuleBase) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'ModuleIsNotCatalogSigned' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return $false } elseif($InstalledModuleAuthenticodePublisher -eq $CurrentModuleAuthenticodePublisher) { $Message = $LocalizedData.AuthenticodeIssuerMatch -f ($CurrentModuleAuthenticodePublisher, $CurrentModuleInfo.Name, $CurrentModuleInfo.Version, $InstalledModuleAuthenticodePublisher, $InstalledModuleInfo.Name, $InstalledModuleVersion) Write-Verbose -Message $message } elseif($IsInstalledModuleSignedByMicrosoft) { if($IsCurrentModuleSignedByMicrosoft) { $Message = $LocalizedData.PublishersMatch -f ($CurrentModuleAuthenticodePublisher, $CurrentModuleInfo.Name, $CurrentModuleInfo.Version, $InstalledModuleAuthenticodePublisher, $InstalledModuleInfo.Name, $InstalledModuleVersion) Write-Verbose -Message $message } else { $Message = $LocalizedData.PublishersMismatch -f ($InstalledModuleInfo.Name, $InstalledModuleVersion, $CurrentModuleInfo.Name, $CurrentModuleAuthenticodePublisher, $CurrentModuleInfo.Version) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'PublishersMismatch' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return $false } } else { $Message = $LocalizedData.AuthenticodeIssuerMismatch -f ($CurrentModuleAuthenticodePublisher, $CurrentModuleInfo.Name, $CurrentModuleInfo.Version, $InstalledModuleAuthenticodePublisher, $InstalledModuleInfo.Name, $InstalledModuleVersion) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'AuthenticodeIssuerMismatch' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return $false } } } return $true } function Validate-ModuleCommandAlreadyAvailable { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [PSModuleInfo] $CurrentModuleInfo, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $InstallLocation, [Parameter()] [Switch] $AllowClobber, [Parameter()] [Switch] $IsUpdateOperation ) <# Install-Module must generate an error message when there is a conflict. User can specify -AllowClobber to avoid the message. Scenario: A large module could be separated into 2 smaller modules. Reason 1: the consumer might have to change code (aka: import-module) to use the command from the new module. Reason 2: it is too confusing to troubleshoot this problem if the user isn't informed right away. #> # When new module has some commands, no clobber error if # - AllowClobber is specified, or # - Installing to the same module base, or # - Update operation if($CurrentModuleInfo.ExportedCommands.Keys.Count -and -not $AllowClobber -and -not $IsUpdateOperation) { # Remove the version folder on 5.0 to get the actual module base folder without version if(Test-ModuleSxSVersionSupport) { $InstallLocation = Microsoft.PowerShell.Management\Split-Path -Path $InstallLocation } $InstalledModuleInfo = Test-ModuleInstalled -Name $CurrentModuleInfo.Name if(-not $InstalledModuleInfo -or -not $InstalledModuleInfo.ModuleBase.StartsWith($InstallLocation, [System.StringComparison]::OrdinalIgnoreCase)) { # Throw an error if there is a command with the same name from a different source. # Get-Command loads the module if a command is already available. # To avoid that, appending '*' at the end for each name then comparing the results. $CommandNames = $CurrentModuleInfo.ExportedCommands.Values.Name $CommandNamesWithWildcards = $CommandNames | Microsoft.PowerShell.Core\Foreach-Object { "$_*" } $AvailableCommands = Microsoft.PowerShell.Core\Get-Command -Name $CommandNamesWithWildcards ` -ErrorAction Ignore ` -WarningAction SilentlyContinue | Microsoft.PowerShell.Core\Where-Object { ($CommandNames -contains $_.Name) -and ($_.ModuleName -ne $script:PSModuleProviderName) -and ($_.ModuleName -ne $CurrentModuleInfo.Name) } if($AvailableCommands) { $AvailableCommandsList = ($AvailableCommands.Name | Microsoft.PowerShell.Utility\Select-Object -Unique -ErrorAction Ignore) -join "," $message = $LocalizedData.ModuleCommandAlreadyAvailable -f ($AvailableCommandsList, $CurrentModuleInfo.Name) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'CommandAlreadyAvailable' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return $false } } } return $true } function ValidateAndGet-AuthenticodeSignature { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [PSModuleInfo] $ModuleInfo ) $ModuleDetails = $null $AuthenticodeSignature = $null $ModuleName = $ModuleInfo.Name $ModuleBasePath = $ModuleInfo.ModuleBase $ModuleManifestName = "$ModuleName.psd1" $CatalogFileName = "$ModuleName.cat" $CatalogFilePath = Microsoft.PowerShell.Management\Join-Path -Path $ModuleBasePath -ChildPath $CatalogFileName if(Microsoft.PowerShell.Management\Test-Path -Path $CatalogFilePath -PathType Leaf) { $message = $LocalizedData.CatalogFileFound -f ($CatalogFileName, $ModuleName) Write-Verbose -Message $message $AuthenticodeSignature = Microsoft.PowerShell.Security\Get-AuthenticodeSignature -FilePath $CatalogFilePath if(-not $AuthenticodeSignature -or ($AuthenticodeSignature.Status -ne "Valid")) { $message = $LocalizedData.InvalidModuleAuthenticodeSignature -f ($ModuleName, $CatalogFileName) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'InvalidAuthenticodeSignature' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } Write-Verbose -Message ($LocalizedData.ValidAuthenticodeSignature -f @($CatalogFileName, $ModuleName)) if(Get-Command -Name Test-FileCatalog -Module Microsoft.PowerShell.Security -ErrorAction Ignore) { Write-Verbose -Message ($LocalizedData.ValidatingCatalogSignature -f @($ModuleName, $CatalogFileName)) # Skip the PSGetModuleInfo.xml and ModuleName.cat files in the catalog validation $TestFileCatalogResult = Microsoft.PowerShell.Security\Test-FileCatalog -Path $ModuleBasePath ` -CatalogFilePath $CatalogFilePath ` -FilesToSkip $script:PSGetItemInfoFileName,'*.cat','*.nupkg','*.nuspec' ` -Detailed ` -ErrorAction SilentlyContinue if(-not $TestFileCatalogResult -or ($TestFileCatalogResult.Status -ne "Valid") -or ($TestFileCatalogResult.Signature.Status -ne "Valid")) { $message = $LocalizedData.InvalidCatalogSignature -f ($ModuleName, $CatalogFileName) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'InvalidCatalogSignature' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } else { Write-Verbose -Message ($LocalizedData.ValidCatalogSignature -f @($CatalogFileName, $ModuleName)) } } } else { Write-Verbose -Message ($LocalizedData.CatalogFileNotFoundInNewModule -f ($CatalogFileName, $ModuleName)) $message = "Using the '{0}' file for getting the authenticode signature." -f ($ModuleManifestName) Write-Debug -Message $message $AuthenticodeSignature = Microsoft.PowerShell.Security\Get-AuthenticodeSignature -FilePath $ModuleInfo.Path if($AuthenticodeSignature) { if($AuthenticodeSignature.Status -eq "Valid") { Write-Verbose -Message ($LocalizedData.ValidAuthenticodeSignatureInFile -f @($ModuleManifestName, $ModuleName)) } elseif($AuthenticodeSignature.Status -ne "NotSigned") { $message = $LocalizedData.InvalidModuleAuthenticodeSignature -f ($ModuleName, $ModuleManifestName) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'InvalidAuthenticodeSignature' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation return } } } if($AuthenticodeSignature) { $ModuleDetails = @{} $ModuleDetails['AuthenticodeSignature'] = $AuthenticodeSignature $ModuleDetails['Version'] = $ModuleInfo.Version $ModuleDetails['ModuleBase']=$ModuleInfo.ModuleBase $ModuleDetails['IsMicrosoftCertificate'] = Test-MicrosoftCertificate -AuthenticodeSignature $AuthenticodeSignature $ModuleDetails['Publisher'] = Get-AuthenticodePublisher -AuthenticodeSignature $AuthenticodeSignature $message = $LocalizedData.NewModuleVersionDetailsForPublisherValidation -f ($ModuleInfo.Name, $ModuleInfo.Version, $ModuleDetails.Publisher, $ModuleDetails.IsMicrosoftCertificate) Write-Debug $message } return $ModuleDetails } function Get-AuthenticodePublisher { [CmdletBinding()] Param ( [Parameter(Mandatory=$true)] [System.Management.Automation.Signature] $AuthenticodeSignature ) if($AuthenticodeSignature.SignerCertificate) { $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain $null = $chain.Build($AuthenticodeSignature.SignerCertificate) $certStoreLocations = @('cert:\LocalMachine\Root', 'cert:\LocalMachine\AuthRoot', 'cert:\CurrentUser\Root', 'cert:\CurrentUser\AuthRoot') foreach($element in $chain.ChainElements.Certificate) { foreach($certStoreLocation in $certStoreLocations) { $rootCertificateAuthority = Microsoft.PowerShell.Management\Get-ChildItem -Path $certStoreLocation | Microsoft.PowerShell.Core\Where-Object { $_.Subject -eq $element.Subject } if($rootCertificateAuthority) { return $rootCertificateAuthority.Subject } } } } } function Get-InstalledModuleAuthenticodeSignature { [CmdletBinding()] Param( [Parameter(Mandatory=$true)] [PSModuleInfo] $InstalledModuleInfo, [Parameter(Mandatory=$true)] [string] $InstallLocation ) $ModuleName = $InstalledModuleInfo.Name # Priority order for getting the published details of the installed module: # 1. Latest version under the $InstallLocation # 2. Latest available version in $PSModulePath # 3. $InstalledModuleInfo $AvailableModules = Microsoft.PowerShell.Core\Get-Module -ListAvailable ` -Name $ModuleName ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Verbose:$false | Microsoft.PowerShell.Utility\Sort-Object -Property Version -Descending # Remove the version folder on 5.0 to get the actual module base folder without version if(Test-ModuleSxSVersionSupport) { $InstallLocation = Microsoft.PowerShell.Management\Split-Path -Path $InstallLocation } $SourceModule = $AvailableModules | Microsoft.PowerShell.Core\Where-Object { $_.ModuleBase.StartsWith($InstallLocation, [System.StringComparison]::OrdinalIgnoreCase) } | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore if(-not $SourceModule) { $SourceModule = $AvailableModules | Microsoft.PowerShell.Utility\Select-Object -First 1 -ErrorAction Ignore } else { $SourceModule = $InstalledModuleInfo } $SignedFilePath = $SourceModule.Path $CatalogFileName = "$ModuleName.cat" $CatalogFilePath = Microsoft.PowerShell.Management\Join-Path -Path $SourceModule.ModuleBase -ChildPath $CatalogFileName if(Microsoft.PowerShell.Management\Test-Path -Path $CatalogFilePath -PathType Leaf) { $message = $LocalizedData.CatalogFileFound -f ($CatalogFileName, $ModuleName) Write-Debug -Message $message $SignedFilePath = $CatalogFilePath } else { Write-Debug -Message ($LocalizedData.CatalogFileNotFoundInAvailableModule -f ($CatalogFileName, $ModuleName)) } $message = "Using the previously-installed module '{0}' with version '{1}' under '{2}' for getting the publisher details." -f ($SourceModule.Name, $SourceModule.Version, $SourceModule.ModuleBase) Write-Debug -Message $message $message = "Using the '{0}' file for getting the authenticode signature." -f ($SignedFilePath) Write-Debug -Message $message $AuthenticodeSignature = Microsoft.PowerShell.Security\Get-AuthenticodeSignature -FilePath $SignedFilePath $ModuleDetails = $null if($AuthenticodeSignature) { $ModuleDetails = @{} $ModuleDetails['AuthenticodeSignature'] = $AuthenticodeSignature $ModuleDetails['Version'] = $SourceModule.Version $ModuleDetails['ModuleBase']=$SourceModule.ModuleBase $ModuleDetails['IsMicrosoftCertificate'] = Test-MicrosoftCertificate -AuthenticodeSignature $AuthenticodeSignature $ModuleDetails['Publisher'] = Get-AuthenticodePublisher -AuthenticodeSignature $AuthenticodeSignature $message = $LocalizedData.SourceModuleDetailsForPublisherValidation -f ($ModuleName, $SourceModule.Version, $SourceModule.ModuleBase, $ModuleDetails.Publisher, $ModuleDetails.IsMicrosoftCertificate) Write-Debug $message } return $ModuleDetails } function Test-MicrosoftCertificate { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [System.Management.Automation.Signature] $AuthenticodeSignature ) $IsMicrosoftCertificate = $false if($AuthenticodeSignature.SignerCertificate -and ('Microsoft.PowerShell.Commands.PowerShellGet.Win32Helpers' -as [Type])) { $X509Chain = $null $SafeX509ChainHandle = $null try { $X509Chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain $null = $X509Chain.Build($AuthenticodeSignature.SignerCertificate) if($script:IsSafeX509ChainHandleAvailable) { $SafeX509ChainHandle = [Microsoft.PowerShell.Commands.PowerShellGet.Win32Helpers]::CertDuplicateCertificateChain($X509Chain.SafeHandle) } else { $SafeX509ChainHandle = [Microsoft.PowerShell.Commands.PowerShellGet.Win32Helpers]::CertDuplicateCertificateChain($X509Chain.ChainContext) } $IsMicrosoftCertificate = [Microsoft.PowerShell.Commands.PowerShellGet.Win32Helpers]::IsMicrosoftCertificate($SafeX509ChainHandle) } catch { Write-Debug "Exception in Test-MicrosoftCertificate function: $_" } finally { if($SafeX509ChainHandle) { $SafeX509ChainHandle.Dispose() } # On .NET Framework 4.5.2 and earlier versions, # the X509Chain class does not implement the IDisposable interface and # therefore does not have a Dispose method. if($X509Chain -and (Get-Member -InputObject $X509Chain -Name Dispose -ErrorAction SilentlyContinue)) { $X509Chain.Dispose() } } } return $IsMicrosoftCertificate } function Test-ValidManifestModule { [CmdletBinding()] [OutputType([bool])] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $ModuleBasePath, [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [string] $InstallLocation, [Parameter()] [Switch] $SkipPublisherCheck, [Parameter()] [Switch] $AllowClobber, [Parameter()] [Switch] $IsUpdateOperation ) $moduleName = Microsoft.PowerShell.Management\Split-Path $ModuleBasePath -Leaf $manifestPath = Join-PathUtility -Path $ModuleBasePath -ChildPath "$moduleName.psd1" -PathType File $PSModuleInfo = $null if(Microsoft.PowerShell.Management\Test-Path $manifestPath) { $PSModuleInfo = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $manifestPath -ErrorAction SilentlyContinue -WarningAction SilentlyContinue if(-not $PSModuleInfo) { $message = $LocalizedData.InvalidPSModule -f ($moduleName) ThrowError -ExceptionName 'System.InvalidOperationException' ` -ExceptionMessage $message ` -ErrorId 'InvalidManifestModule' ` -CallerPSCmdlet $PSCmdlet ` -ErrorCategory InvalidOperation } elseif($script:IsWindows) { $ValidationResult = Validate-ModuleAuthenticodeSignature -CurrentModuleInfo $PSModuleInfo ` -InstallLocation $InstallLocation ` -IsUpdateOperation:$IsUpdateOperation ` -SkipPublisherCheck:$SkipPublisherCheck if($ValidationResult) { # Checking for the possible command clobbering. $ValidationResult = Validate-ModuleCommandAlreadyAvailable -CurrentModuleInfo $PSModuleInfo ` -InstallLocation $InstallLocation ` -AllowClobber:$AllowClobber ` -IsUpdateOperation:$IsUpdateOperation } if(-not $ValidationResult) { $PSModuleInfo = $null } } } return $PSModuleInfo } function Get-ScriptSourceLocation { [CmdletBinding()] Param ( [Parameter()] [String] $Location, [Parameter()] $Credential, [Parameter()] $Proxy, [Parameter()] $ProxyCredential ) $scriptLocation = $null if($Location) { # For local dir or SMB-share locations, ScriptSourceLocation is SourceLocation. if(Microsoft.PowerShell.Management\Test-Path -Path $Location) { $scriptLocation = $Location } else { $tempScriptLocation = $null if($Location.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) { $tempScriptLocation = $Location + '/items/psscript/' } elseif($Location.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) { $tempScriptLocation = $Location + 'items/psscript/' } if($tempScriptLocation) { # Ping and resolve the specified location $scriptLocation = Resolve-Location -Location $tempScriptLocation ` -LocationParameterName 'ScriptSourceLocation' ` -Credential $Credential ` -Proxy $Proxy ` -ProxyCredential $ProxyCredential ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue } } } return $scriptLocation } function Get-PublishLocation { [CmdletBinding()] Param ( [Parameter()] [String] $Location ) $PublishLocation = $null if($Location) { # For local dir or SMB-share locations, ScriptPublishLocation is PublishLocation. if(Microsoft.PowerShell.Management\Test-Path -Path $Location) { $PublishLocation = $Location } else { $tempPublishLocation = $null if($Location.EndsWith('/api/v2', [System.StringComparison]::OrdinalIgnoreCase)) { $tempPublishLocation = $Location + '/package/' } elseif($Location.EndsWith('/api/v2/', [System.StringComparison]::OrdinalIgnoreCase)) { $tempPublishLocation = $Location + 'package/' } if($tempPublishLocation) { $PublishLocation = $tempPublishLocation } } } return $PublishLocation } function Resolve-Location { [CmdletBinding()] [OutputType([string])] Param ( [Parameter(Mandatory=$true)] [string] $Location, [Parameter(Mandatory=$true)] [string] $LocationParameterName, [Parameter()] $Credential, [Parameter()] $Proxy, [Parameter()] $ProxyCredential, [Parameter()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet ) # Ping and resolve the specified location if(-not (Test-WebUri -uri $Location)) { if(Microsoft.PowerShell.Management\Test-Path -Path $Location) { return $Location } elseif($CallerPSCmdlet) { $message = $LocalizedData.PathNotFound -f ($Location) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "PathNotFound" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Location } } else { $pingResult = Ping-Endpoint -Endpoint $Location -Credential $Credential -Proxy $Proxy -ProxyCredential $ProxyCredential $statusCode = $null $exception = $null $resolvedLocation = $null if($pingResult -and $pingResult.ContainsKey($Script:ResponseUri)) { $resolvedLocation = $pingResult[$Script:ResponseUri] } if($pingResult -and $pingResult.ContainsKey($Script:StatusCode)) { $statusCode = $pingResult[$Script:StatusCode] } Write-Debug -Message "Ping-Endpoint: location=$Location, statuscode=$statusCode, resolvedLocation=$resolvedLocation" if((($statusCode -eq 200) -or ($statusCode -eq 401)) -and $resolvedLocation) { return $resolvedLocation } elseif($CallerPSCmdlet) { $message = $LocalizedData.InvalidWebUri -f ($Location, $LocationParameterName) ThrowError -ExceptionName "System.ArgumentException" ` -ExceptionMessage $message ` -ErrorId "InvalidWebUri" ` -CallerPSCmdlet $CallerPSCmdlet ` -ErrorCategory InvalidArgument ` -ExceptionObject $Location } } } function Test-WebUri { [CmdletBinding()] [OutputType([bool])] Param ( [Parameter(Mandatory=$true)] [ValidateNotNullOrEmpty()] [Uri] $uri ) return ($uri.AbsoluteURI -ne $null) -and ($uri.Scheme -match '[http|https]') } function Test-WildcardPattern { [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory=$true)] [ValidateNotNull()] $Name ) return [System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($Name) } # Utility to throw an errorrecord function ThrowError { param ( [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.Management.Automation.PSCmdlet] $CallerPSCmdlet, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $ExceptionName, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $ExceptionMessage, [System.Object] $ExceptionObject, [parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $ErrorId, [parameter(Mandatory = $true)] [ValidateNotNull()] [System.Management.Automation.ErrorCategory] $ErrorCategory ) $exception = New-Object $ExceptionName $ExceptionMessage; $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $ErrorId, $ErrorCategory, $ExceptionObject $CallerPSCmdlet.ThrowTerminatingError($errorRecord) } #endregion # Create install locations for scripts if they are not already created if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:ProgramFilesInstalledScriptInfosPath) -and (Test-RunningAsElevated)) { $ev = $null $null = Microsoft.PowerShell.Management\New-Item -Path $script:ProgramFilesInstalledScriptInfosPath ` -ItemType Directory ` -Force ` -ErrorVariable ev ` -ErrorAction SilentlyContinue ` -WarningAction SilentlyContinue ` -Confirm:$false ` -WhatIf:$false if($ev) { $script:IsRunningAsElevated = $false } } if(-not (Microsoft.PowerShell.Management\Test-Path -Path $script:MyDocumentsInstalledScriptInfosPath)) { $null = Microsoft.PowerShell.Management\New-Item -Path $script:MyDocumentsInstalledScriptInfosPath ` -ItemType Directory ` -Force ` -Confirm:$false ` -WhatIf:$false } Set-Alias -Name fimo -Value Find-Module Set-Alias -Name inmo -Value Install-Module Set-Alias -Name upmo -Value Update-Module Set-Alias -Name pumo -Value Publish-Module Set-Alias -Name uimo -Value Uninstall-Module Export-ModuleMember -Function Find-Module, ` Save-Module, ` Install-Module, ` Update-Module, ` Publish-Module, ` Uninstall-Module, ` Get-InstalledModule, ` Find-Command, ` Find-DscResource, ` Find-RoleCapability, ` Install-Script, ` Find-Script, ` Save-Script, ` Update-Script, ` Publish-Script, ` Get-InstalledScript, ` Uninstall-Script, ` Test-ScriptFileInfo, ` New-ScriptFileInfo, ` Update-ScriptFileInfo, ` Get-PSRepository, ` Register-PSRepository, ` Unregister-PSRepository, ` Set-PSRepository, ` Find-Package, ` Get-PackageDependencies, ` Download-Package, ` Install-Package, ` Uninstall-Package, ` Get-InstalledPackage, ` Remove-PackageSource, ` Resolve-PackageSource, ` Add-PackageSource, ` Get-DynamicOptions, ` Initialize-Provider, ` Get-Feature, ` Get-PackageProviderName, ` Update-ModuleManifest ` -Alias fimo, ` inmo, ` upmo, ` pumo |