PSModule.psm1


#########################################################################################
#
# Copyright (c) Microsoft Corporation. All rights reserved.
#
# PowerShellGet Module
#
#########################################################################################

Microsoft.PowerShell.Core\Set-StrictMode -Version Latest

#region script variables

# Check if this is nano server. [System.Runtime.Loader.AssemblyLoadContext] is only available on NanoServer
$script:isNanoServer = $null -ne ('System.Runtime.Loader.AssemblyLoadContext' -as [Type])

$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:IsOSX = (Get-Variable -Name IsOSX -ErrorAction Ignore) -and $IsOSX
$script:IsCoreCLR = (Get-Variable -Name IsCoreCLR -ErrorAction Ignore) -and $IsCoreCLR

if($script:IsInbox)
{
    $script:ProgramFilesPSPath = Microsoft.PowerShell.Management\Join-Path -Path $env:ProgramFiles -ChildPath "WindowsPowerShell"
}
else
{
    $script:ProgramFilesPSPath = $PSHome
}

if($script:IsInbox)
{
    try
    {
        $script:MyDocumentsFolderPath = [Environment]::GetFolderPath("MyDocuments")
    }
    catch
    {
        $script:MyDocumentsFolderPath = $null
    }

    $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:IsWindows)
{
    $script:MyDocumentsPSPath = Microsoft.PowerShell.Management\Join-Path -Path $HOME -ChildPath 'Documents\PowerShell'
}
else
{
    $script:MyDocumentsPSPath = Microsoft.PowerShell.Management\Join-Path -Path $HOME -ChildPath ".local/share/powershell"
}

$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 = if($script:IsWindows){ ([System.IO.DirectoryInfo]$env:TEMP).FullName } else { '/tmp' }
$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 = "$HOME/.config/powershell/powershellget" #TODO: Get $env:ProgramData equivalent
    $script:PSGetAppLocalPath = "$HOME/.config/powershell/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: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
# 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: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)
        {
            $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:isNanoServer)
{
        '
        [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:isNanoServer)
    {
    '
        [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 -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()]
        [Version]
        $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
    )

    Begin
    {
        if($script:isNanoServer -or $script:IsCoreCLR) {
            $message = $LocalizedData.PublishPSArtifactUnsupportedOnNano -f "Module"
            ThrowError -ExceptionName "System.InvalidOperationException" `
                        -ExceptionMessage $message `
                        -ErrorId 'PublishModuleIsNotSupportedOnPowerShellCoreEdition' `
                        -CallerPSCmdlet $PSCmdlet `
                        -ExceptionObject $PSCmdlet `
                        -ErrorCategory InvalidOperation
        }

        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)
        {
            $module = Microsoft.PowerShell.Core\Get-Module -ListAvailable -Name $Name -Verbose:$false | 
                          Microsoft.PowerShell.Core\Where-Object {-not $RequiredVersion -or ($RequiredVersion -eq $_.Version)} 

            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
            $ModuleVersion = New-Object System.Version
            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-Path -Path $resolvedPath -ChildPath "$moduleName.psd1"
            $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 = Microsoft.PowerShell.Management\Join-Path $tempModulePathForFormatVersion "$moduleName.psd1"
        
            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
            }

            $FindParameters = @{
                Name = $moduleName
                Repository = $Repository
                Tag = 'PSScript'
                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)
            {
                if($currentPSGetItemInfo.Version -eq $moduleInfo.Version)
                {
                    $message = $LocalizedData.ModuleVersionIsAlreadyAvailableInTheGallery -f ($moduleInfo.Name, $moduleInfo.Version, $currentPSGetItemInfo.Version, $currentPSGetItemInfo.RepositorySourceLocation)
                    ThrowError -ExceptionName 'System.InvalidOperationException' `
                               -ExceptionMessage $message `
                               -ErrorId 'ModuleVersionIsAlreadyAvailableInTheGallery' `
                               -CallerPSCmdlet $PSCmdlet `
                               -ErrorCategory InvalidOperation
                }
                elseif(-not $Force -and ($currentPSGetItemInfo.Version -gt $moduleInfo.Version))
                {
                    $message = $LocalizedData.ModuleVersionShouldBeGreaterThanGalleryVersion -f ($moduleInfo.Name, $moduleInfo.Version, $currentPSGetItemInfo.Version, $currentPSGetItemInfo.RepositorySourceLocation)
                    ThrowError -ExceptionName "System.InvalidOperationException" `
                               -ExceptionMessage $message `
                               -ErrorId "ModuleVersionShouldBeGreaterThanGalleryVersion" `
                               -CallerPSCmdlet $PSCmdlet `
                               -ErrorCategory InvalidOperation
                }
            }

            $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()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $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
    )

    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

        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
                
        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 
                                                        
            $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()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameAndPathParameterSet')]
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameAndLiteralPathParameterSet')]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameAndPathParameterSet')]
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameAndLiteralPathParameterSet')]
        [ValidateNotNull()]
        [Version]
        $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()]
        [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
        
        # 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

            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\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") -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()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameParameterSet')]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameParameterSet')]
        [ValidateNotNull()]
        [Version]
        $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()]
        [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

        if($PSCmdlet.ParameterSetName -eq "NameParameterSet")
        {
            $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
                                                           -Name $Name `
                                                           -TestWildcardsInName `
                                                           -MinimumVersion $MinimumVersion `
                                                           -MaximumVersion $MaximumVersion `
                                                           -RequiredVersion $RequiredVersion

            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['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()]
        [Version]
        $RequiredVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [PSCredential]
        $Credential,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [Uri]
        $Proxy,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [PSCredential]
        $ProxyCredential,

        [Parameter()]
        [Switch]
        $Force,

        [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

        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'

        $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()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameParameterSet')]
        [ValidateNotNull()]
        [Version]
        $RequiredVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameParameterSet')]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter(ParameterSetName='NameParameterSet')]
        [switch]
        $AllVersions,

        [Parameter()]
        [Switch]
        $Force
    )

    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

            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()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $RequiredVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter()]
        [switch]
        $AllVersions
    )

    Process
    {
        $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
                                                       -Name $Name `
                                                       -MinimumVersion $MinimumVersion `
                                                       -MaximumVersion $MaximumVersion `
                                                       -RequiredVersion $RequiredVersion `
                                                       -AllVersions:$AllVersions

        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

        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()]
        [Version]
        $MinimumVersion,

        [Parameter()]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter()]
        [ValidateNotNull()]
        [Version]
        $RequiredVersion,

        [Parameter()]
        [switch]
        $AllVersions,

        [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()]
        [Version]
        $MinimumVersion,

        [Parameter()]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter()]
        [ValidateNotNull()]
        [Version]
        $RequiredVersion,

        [Parameter()]
        [switch]
        $AllVersions,

        [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()]
        [Version]
        $MinimumVersion,
        
        [Parameter()]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,

        [Parameter()]
        [ValidateNotNull()]
        [Version]
        $RequiredVersion,

        [Parameter()]
        [switch]
        $AllVersions,

        [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
    {
        if($script:isNanoServer -or $script:IsCoreCLR) {
            $message = $LocalizedData.PublishPSArtifactUnsupportedOnNano -f "Script"
            ThrowError -ExceptionName "System.InvalidOperationException" `
                        -ExceptionMessage $message `
                        -ErrorId 'PublishScriptIsNotSupportedOnPowerShellCoreEdition' `
                        -CallerPSCmdlet $PSCmdlet `
                        -ExceptionObject $PSCmdlet `
                        -ErrorCategory InvalidOperation
        }

        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

        # Copy the source script file to temp location to publish
        $tempScriptPath = Microsoft.PowerShell.Management\Join-Path -Path $script:TempPath `
                              -ChildPath "$(Microsoft.PowerShell.Utility\Get-Random)\$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'
                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)
            {
                if($currentPSGetItemInfo.Version -eq $PSScriptInfo.Version)
                {
                    $message = $LocalizedData.ScriptVersionIsAlreadyAvailableInTheGallery -f ($scriptName,
                                                                                              $PSScriptInfo.Version,
                                                                                              $currentPSGetItemInfo.Version,
                                                                                              $currentPSGetItemInfo.RepositorySourceLocation)
                    ThrowError -ExceptionName "System.InvalidOperationException" `
                               -ExceptionMessage $message `
                               -ErrorId 'ScriptVersionIsAlreadyAvailableInTheGallery' `
                               -CallerPSCmdlet $PSCmdlet `
                               -ErrorCategory InvalidOperation
                }
                elseif(-not $Force -and ($currentPSGetItemInfo.Version -gt $PSScriptInfo.Version))
                {
                    $message = $LocalizedData.ScriptVersionShouldBeGreaterThanGalleryVersion -f ($scriptName,
                                                                                                 $PSScriptInfo.Version,
                                                                                                 $currentPSGetItemInfo.Version,
                                                                                                 $currentPSGetItemInfo.RepositorySourceLocation)
                    ThrowError -ExceptionName "System.InvalidOperationException" `
                               -ExceptionMessage $message `
                               -ErrorId "ScriptVersionShouldBeGreaterThanGalleryVersion" `
                               -CallerPSCmdlet $PSCmdlet `
                               -ErrorCategory InvalidOperation
                }
            }

            $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()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNull()]
        [Version]
        $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
    )

    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

        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
                
        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 
                                                        
                $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()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameAndPathParameterSet')]
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameAndLiteralPathParameterSet')]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameAndPathParameterSet')]
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameAndLiteralPathParameterSet')]
        [ValidateNotNull()]
        [Version]
        $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()]
        [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

        # 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

            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()]
        [Version]
        $MinimumVersion,

        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameParameterSet')]
        [ValidateNotNull()]
        [Version]
        $MaximumVersion,
        
        [Parameter(ValueFromPipelineByPropertyName=$true,
                   ParameterSetName='NameParameterSet')]
        [ValidateNotNull()]
        [Version]
        $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()]
        [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

        if($PSCmdlet.ParameterSetName -eq "NameParameterSet")
        {
            $ValidationResult = Validate-VersionParameters -CallerPSCmdlet $PSCmdlet `
                                                           -Name $Name `
                                                           -TestWildcardsInName `
                                                           -MinimumVersion $MinimumVersion `
                                                           -MaximumVersion $MaximumVersion `
                                                           -RequiredVersion $RequiredVersion

            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