diff --git a/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.psm1 b/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.psm1 new file mode 100644 index 00000000..c6cf548f --- /dev/null +++ b/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.psm1 @@ -0,0 +1,654 @@ +# +# Copyright (c) Microsoft Corporation. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +Import-LocalizedData -BindingVariable LocalizedData -filename MSFT_PSModule.strings.psd1 +Import-Module -Name "$PSScriptRoot\..\OneGetHelper.psm1" + +#DSC Resource for the $CurrentProviderName +$CurrentProviderName="PowerShellGet" + + +#Return the current state of the resource +function Get-TargetResource +{ + <# + .SYNOPSIS + + This DSC resource provides a mechanism to download PowerShell modules from the PowerShell + Gallery and install it on your computer. + + Get-TargetResource returns the current state of the resource. + + .PARAMETER Name + Specifies the name of the PowerShell module to be installed or uninstalled. + + .PARAMETER Repository + Specifies the name of the module source repository where the module can be found. + + .PARAMETER RequiredVersion + Provides the version of the module you want to install or uninstall. + + .PARAMETER MaximumVersion + Provides the maximum version of the module you want to install or uninstall. + + .PARAMETER MinimumVersion + Provides the minimum version of the module you want to install or uninstall. + + .PARAMETER Force + Forces the installation of modules. If a module of the same name and version already exists on the computer, + this parameter overwrites the existing module with one of the same name that was found by the command. + + .PARAMETER AllowClobber + Allows the installation of modules regardless of if other existing module on the computer have cmdlets + of the same name + + .PARAMETER SkipPublisherCheck + Allows the installation of modules that have not been catalog signed + #> + + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [parameter(Mandatory = $true)] + [System.String] + $Name, + + [System.String] + $Repository="PSGallery", + + [System.String] + $RequiredVersion, + + [System.String] + $MaximumVersion, + + [System.String] + $MinimumVersion, + + [Switch] + $Force, + + [Switch] + $AllowClobber, + + [Switch] + $SkipPublisherCheck + ) + + #Initialize the $Ensure variable + $ensure = 'Absent' + + $extractedArguments = ExtractArguments -FunctionBoundParameters $PSBoundParameters ` + -ArgumentNames ("Name", "Repository", "MinimumVersion", "MaximumVersion", "RequiredVersion") + + #Get the module with the right version and repository properties + $modules = Get-RightModule @extractedArguments -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + #If the module is found, the count > 0 + if ($modules.count -gt 0) + { + $ensure = 'Present' + + Write-Verbose -Message ($localizedData.ModuleFound -f $($Name)) + } + else + { + Write-Verbose -Message ($localizedData.ModuleNotFound -f $($Name)) + } + + Write-Debug -Message "Ensure of $($Name) module is $($ensure)" + + if ($ensure -eq 'Absent') + { + return @{ + Ensure = $ensure + Name = $Name + } + } + else + { + #Find a module with the latest version and return its properties + $latestModule = $modules[0] + + foreach ($module in $modules) + { + if ($module.Version -gt $latestModule.Version) + { + $latestModule = $module + } + } + + #Check if the repository matches + $repositoryName = Get-ModuleRepositoryName -Module $latestModule -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + $installationPolicy = Get-InstallationPolicy -RepositoryName $repositoryName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + return @{ + Ensure = $ensure + Name = $Name + Repository = $repositoryName + Description = $latestModule.Description + Guid = $latestModule.Guid + ModuleBase = $latestModule.ModuleBase + ModuleType = $latestModule.ModuleType + Author = $latestModule.Author + InstalledVersion = $latestModule.Version + InstallationPolicy=if($installationPolicy) {"Trusted"}else{"Untrusted"} + } + } +} + +function Test-TargetResource +{ + <# + .SYNOPSIS + + This DSC resource provides a mechanism to download PowerShell modules from the PowerShell + Gallery and install it on your computer. + + Test-TargetResource validates whether the resource is currently in the desired state. + + .PARAMETER Ensure + Determines whether the module to be installed or uninstalled. + + .PARAMETER Name + Specifies the name of the PowerShell module to be installed or uninstalled. + + .PARAMETER Repository + Specifies the name of the module source repository where the module can be found. + + .PARAMETER InstallationPolicy + Determines whether you trust the source repository where the module resides. + + .PARAMETER RequiredVersion + Provides the version of the module you want to install or uninstall. + + .PARAMETER MaximumVersion + Provides the maximum version of the module you want to install or uninstall. + + .PARAMETER MinimumVersion + Provides the minimum version of the module you want to install or uninstall. + + .PARAMETER Force + Forces the installation of modules. If a module of the same name and version already exists on the computer, + this parameter overwrites the existing module with one of the same name that was found by the command. + + .PARAMETER AllowClobber + Allows the installation of modules regardless of if other existing module on the computer have cmdlets + of the same name + + .PARAMETER SkipPublisherCheck + Allows the installation of modules that have not been catalog signed + #> + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [ValidateSet("Present","Absent")] + [System.String] + $Ensure="Present", + + [parameter(Mandatory = $true)] + [System.String] + $Name, + + [System.String] + $Repository="PSGallery", + + [ValidateSet("Trusted","Untrusted")] + [System.String] + $InstallationPolicy="Untrusted", + + [System.String] + $RequiredVersion, + + [System.String] + $MaximumVersion, + + [System.String] + $MinimumVersion, + + [Switch] + $Force, + + [Switch] + $AllowClobber, + + [Switch] + $SkipPublisherCheck + ) + + Write-Debug -Message "Calling Test-TargetResource" + + $extractedArguments = ExtractArguments -FunctionBoundParameters $PSBoundParameters ` + -ArgumentNames ("Name", "Repository", "MinimumVersion", "MaximumVersion", "RequiredVersion") + + $status = Get-TargetResource @extractedArguments + + #The ensure returned from Get-TargetResource is not equal to the desired $Ensure + # + if ($status.Ensure -ieq $Ensure) + { + Write-Verbose -Message ($localizedData.InDesiredState -f $Name) + return $true + } + else + { + Write-Verbose -Message ($localizedData.NotInDesiredState -f $Name) + return $false + } +} + +function Set-TargetResource +{ + <# + .SYNOPSIS + + This DSC resource provides a mechanism to download PowerShell modules from the PowerShell + Gallery and install it on your computer. + + Set-TargetResource sets the resource to the desired state. "Make it so". + + .PARAMETER Ensure + Determines whether the module to be installed or uninstalled. + + .PARAMETER Name + Specifies the name of the PowerShell module to be installed or uninstalled. + + .PARAMETER Repository + Specifies the name of the module source repository where the module can be found. + + .PARAMETER InstallationPolicy + Determines whether you trust the source repository where the module resides. + + .PARAMETER RequiredVersion + Provides the version of the module you want to install or uninstall. + + .PARAMETER MaximumVersion + Provides the maximum version of the module you want to install or uninstall. + + .PARAMETER MinimumVersion + Provides the minimum version of the module you want to install or uninstall. + + .PARAMETER Force + Forces the installation of modules. If a module of the same name and version already exists on the computer, + this parameter overwrites the existing module with one of the same name that was found by the command. + + .PARAMETER AllowClobber + Allows the installation of modules regardless of if other existing module on the computer have cmdlets + of the same name + + .PARAMETER SkipPublisherCheck + Allows the installation of modules that have not been catalog signed + #> + + [CmdletBinding()] + param + ( + [ValidateSet("Present","Absent")] + [System.String] + $Ensure="Present", + + [parameter(Mandatory = $true)] + [System.String] + $Name, + + [System.String] + $Repository="PSGallery", + + [ValidateSet("Trusted","Untrusted")] + [System.String] + $InstallationPolicy="Untrusted", + + [System.String] + $RequiredVersion, + + [System.String] + $MaximumVersion, + + [System.String] + $MinimumVersion, + + [Switch] + $Force, + + [Switch] + $AllowClobber, + + [Switch] + $SkipPublisherCheck + ) + + + #Validate the repository argument + if ($PSBoundParameters.ContainsKey("Repository")) + { + ValidateArgument -Argument $Repository -Type "PackageSource" -ProviderName $CurrentProviderName -Verbose + } + + if($Ensure -ieq "Present") + { + + #Version check + $extractedArguments = ExtractArguments -FunctionBoundParameters $PSBoundParameters ` + -ArgumentNames ("MinimumVersion","MaximumVersion", "RequiredVersion") + + ValidateVersionArgument @extractedArguments + + $extractedArguments = ExtractArguments -FunctionBoundParameters $PSBoundParameters ` + -ArgumentNames ("Name","Repository", "MinimumVersion", "MaximumVersion","RequiredVersion") + + Write-Verbose -Message ($localizedData.StartFindmodule -f $($Name)) + + + $modules = Find-Module @extractedArguments -ErrorVariable ev + + + if (-not $modules) + { + + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage ($localizedData.ModuleNotFoundInRepository -f $Name, $ev.Exception) ` + -ErrorId "ModuleNotFoundInRepository" ` + -ErrorCategory InvalidOperation + } + + $trusted = $null + $moduleFound = $null + + foreach ($m in $modules) + { + #Check for the installation policy + $trusted = Get-InstallationPolicy -RepositoryName $m.Repository -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + #Stop the loop if found a trusted repository + if ($trusted) + { + $moduleFound = $m + break; + } + } + + + #The respository is trusted, so we install it + if ($trusted) + { + Write-Verbose -Message ($localizedData.StartInstallModule -f $Name, $moduleFound.Version.toString(), $moduleFound.Repository ) + + #Extract the installation options + $extractedSwitches = ExtractArguments -FunctionBoundParameters $PSBoundParameters -ArgumentNames ("Force","AllowClobber", "SkipPublisherCheck") + + $moduleFound | Install-Module -ErrorVariable ev + } + #The repository is untrusted but user's installation policy is trusted, so we install it with a warning + elseif ($InstallationPolicy -ieq 'Trusted') + { + Write-Warning -Message ($localizedData.InstallationPolicyWarning -f $Name, $modules[0].Repository, $InstallationPolicy) + + # Extract installation options (Force implied by InstallationPolicy) + $extractedSwitches = ExtractArguments -FunctionBoundParameters $PSBoundParameters -ArgumentNames ("AllowClobber", "SkipPublisherCheck") + + #if all the repositories are untrusted, we choose the first one + $modules[0] | Install-Module @extractedSwitches -Force -ErrorVariable ev + } + #Both user and repository is untrusted + else + { + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage ($localizedData.InstallationPolicyFailed -f $InstallationPolicy, "Untrusted") ` + -ErrorId "InstallationPolicyFailed" ` + -ErrorCategory InvalidOperation + } + + if ($ev) + { + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage ($localizedData.FailtoInstall -f $Name, $ev.Exception) ` + -ErrorId "FailtoInstall" ` + -ErrorCategory InvalidOperation + } + else + { + Write-Verbose -Message ($localizedData.InstalledSuccess -f $($Name)) + } + } + #Ensure=Absent + else + { + + $extractedArguments = ExtractArguments -FunctionBoundParameters $PSBoundParameters ` + -ArgumentNames ("Name", "Repository", "MinimumVersion", "MaximumVersion", "RequiredVersion") + + + #Get the module with the right version and repository properties + $modules = Get-RightModule @extractedArguments -ErrorVariable ev + + if ((-not $modules) -or $ev) + { + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage ($localizedData.ModuleWithRightPropertyNotFound -f $Name, $ev.Exception) ` + -ErrorId "ModuleWithRightPropertyNotFound" ` + -ErrorCategory InvalidOperation + } + + foreach ($module in $modules) + { + #Get the path where the module is installed + $path=$module.ModuleBase + + Write-Verbose -Message ($localizedData.StartUnInstallModule -f $($Name)) + + #There is no Uninstall-Module cmdlet exists, so we will remove the ModuleBase folder as an uninstall operation + Microsoft.PowerShell.Management\Remove-Item -Path $path -Force -Recurse -ErrorVariable ev + + if($ev) + { + ThrowError -ExceptionName "System.InvalidOperationException" ` + -ExceptionMessage ($localizedData.FailtoUninstall -f $module.Name, $ev.Exception) ` + -ErrorId "FailtoUninstall" ` + -ErrorCategory InvalidOperation + } + else + { + Write-Verbose -Message ($localizedData.UnInstalledSuccess -f $($module.Name)) + } + + }#foreach + + } #Ensure=Absent +} + + +Function Get-RightModule +{ + <# + .SYNOPSIS + + This is a helper function. It returns the modules that meet the specified versions and the repository requirements + + .PARAMETER Name + Specifies the name of the PowerShell module. + + .PARAMETER RequiredVersion + Provides the version of the module you want to install or uninstall. + + .PARAMETER MaximumVersion + Provides the maximum version of the module you want to install or uninstall. + + .PARAMETER MinimumVersion + Provides the minimum version of the module you want to install or uninstall. + + .PARAMETER Repository + Specifies the name of the module source repository where the module can be found. + #> + + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Name, + + [System.String] + $RequiredVersion, + + [System.String] + $MinimumVersion, + + [System.String] + $MaximumVersion, + + [System.String] + $Repository + ) + + + Write-Verbose -Message ($localizedData.StartGetModule -f $($Name)) + + $modules = Microsoft.PowerShell.Core\Get-Module -Name $Name -ListAvailable -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + if (-not $modules) + { + return $null + } + + # + #As Get-Module does not take RequiredVersion, MinimumVersion, MaximumVersion, or Repository, below we need to check + #whether the modules are containing the right version and repository location. + + $extractedArguments = ExtractArguments -FunctionBoundParameters $PSBoundParameters ` + -ArgumentNames ("MaximumVersion","MinimumVersion", "RequiredVersion") + + $returnVal =@() + + foreach ($m in $modules) + { + $versionMatch = $false + $installedVersion = $m.Version + + #Case 1 - a user provides none of RequiredVersion, MinimumVersion, MaximumVersion + + if ($extractedArguments.Count -eq 0) + { + $versionMatch = $true + } + # + #Case 2 - a user provides RequiredVersion + # + elseif ($extractedArguments.ContainsKey("RequiredVersion")) + { + #Check if it matches with the installedversion + $versionMatch = ($installedVersion -eq [System.Version]$RequiredVersion) + } + else + { + #Case 3 - a user provides MinimumVersion + if ($extractedArguments.ContainsKey("MinimumVersion")) + { + $versionMatch = ($installedVersion -ge [System.Version]$extractedArguments['MinimumVersion']) + } + # + #Case 4 - a user provides MaximumVersion + # + if ($extractedArguments.ContainsKey("MaximumVersion")) + { + $isLessThanMax = ($installedVersion -le [System.Version]$extractedArguments['MaximumVersion']) + + if ($extractedArguments.ContainsKey("MinimumVersion")) + { + $versionMatch = $versionMatch -and $isLessThanMax + } + else + { + $versionMatch = $isLessThanMax + } + } + #Case 5 - Both MinimumVersion and MaximumVersion are provided. it's covered by the above + + #Do not return $false yet to allow the foreach to continue + if (-not $versionMatch) + { + Write-Verbose -Message ($localizedData.VersionMismatch -f $($Name), $($installedVersion)) + $versionMatch = $false + } + } + + #Case 6 - Version matches but need to check if the module is from the right repository + # + if ($versionMatch) + { + #a user does not provide Repository, we are good + if (-not $PSBoundParameters.ContainsKey("Repository")) + { + Write-Verbose -Message ($localizedData.ModuleFound -f "$($Name) $($installedVersion)") + $returnVal+=$m + + } + else + { + #Check if the Repository matches + $sourceName = Get-ModuleRepositoryName -Module $m + + if ($Repository -ieq $sourceName) + { + Write-Verbose -Message ($localizedData.ModuleFound -f "$($Name) $($installedVersion)") + $returnVal+=$m + } + else + { + Write-Verbose -Message ($localizedData.RepositoryMismatch -f $($Name), $($sourceName)) + } + } + } + + } #foreach + + return $returnVal +} + +Function Get-ModuleRepositoryName +{ + <# + .SYNOPSIS + + This is a helper function that returns the module's repository name + + .PARAMETER Module + Specifies the name of the PowerShell module. + #> + Param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Object]$Module + ) + + + #RepositorySourceLocation property is supported in PS V5 only. To work with the earlier PS version, we need to do a different way. + #PSGetModuleInfo.xml exists for any PS modules downloaded through PSModule provider. + + $psGetModuleInfoFileName = "PSGetModuleInfo.xml" + + $psGetModuleInfoPath = Microsoft.PowerShell.Management\Join-Path -Path $Module.ModuleBase -ChildPath $psGetModuleInfoFileName + + Write-Verbose -Message ($localizedData.FoundModulePath -f $($psGetModuleInfoPath)) + + if (Microsoft.PowerShell.Management\Test-path -Path $psGetModuleInfoPath) + { + $psGetModuleInfo = Microsoft.PowerShell.Utility\Import-Clixml -Path $psGetModuleInfoPath + + return $psGetModuleInfo.Repository + } +} + +Export-ModuleMember -function Get-TargetResource, Set-TargetResource, Test-TargetResource diff --git a/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.schema.mfl b/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.schema.mfl new file mode 100644 index 00000000..d7ad6743 --- /dev/null +++ b/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.schema.mfl @@ -0,0 +1,24 @@ +#pragma namespace("\\\\.\\root\\default") +instance of __namespace{ name="MS_409";}; +#pragma namespace("\\\\.\\root\\default\\MS_409") + +[AMENDMENT, LOCALE("MS_409")] +class MSFT_PSModule : OMI_BaseResource +{ + [Key,Description("Name of the module\n") : Amended] String Name; + [Description("Whether the module is to be installed or uninstalled.\nPresent {default} \nAbsent \n") : Amended] String Ensure; + [Description("The name of the module source where the module can be found.\n") : Amended] String Repository; + [Description("Whether the package is trusted or untrusted.\nTrusted {default} \nUntrusted \n") : Amended] String InstallationPolicy; + [Description("The required version of the module.\n") : Amended] String RequiredVersion; + [Description("The minimum version of the module.\n") : Amended] String MinimumVersion; + [Description("The maximum version of the module.\n") : Amended] String MaximumVersion; + [Description("Forces the installation of the module.\n" : Amended] Boolean Force; + [Description("Allows installation when existing cmdlets of the same name exist.\n" : Amended] Boolean AllowClobber; + [Description("Allows installation when module is not signed.\n" : Amended] Boolean SkipPublisherCheck; + [Description("The brief description of the module.\n") : Amended] string Description; + [Description("The version of the module that is installed.\n") : Amended] String InstalledVersion; + [Description("The identifier of the module.\n") : Amended] String Guid; + [Description("The base location where the module is installed.\n") : Amended] String ModuleBase; + [Description("The type of the module.\n") : Amended] String ModuleType; + [Description("The author of the module.\n") : Amended] String Author; +}; diff --git a/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.schema.mof b/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.schema.mof new file mode 100644 index 00000000..04029309 --- /dev/null +++ b/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.schema.mof @@ -0,0 +1,21 @@ + +[ClassVersion("1.0.0.0"),FriendlyName("PSModule")] +class MSFT_PSModule : OMI_BaseResource +{ + [Key] String Name; + [Write,ValueMap{"Present", "Absent"},Values{"Present", "Absent"}] String Ensure; + [Write] String Repository; + [Write,ValueMap{"Trusted", "Untrusted"},Values{"Trusted", "Untrusted"}] String InstallationPolicy; + [Write] String RequiredVersion; + [Write] String MaximumVersion; + [Write] String MinimumVersion; + [Write] Boolean Force; + [Write] Boolean AllowClobber; + [Write] Boolean SkipPublisherCheck; + [Read] string Description; + [Read] String InstalledVersion; + [Read] String Guid; + [Read] String ModuleBase; + [Read] String ModuleType; + [Read] String Author; +}; diff --git a/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.strings.psd1 b/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.strings.psd1 new file mode 100644 index 00000000..7bae9ca6 --- /dev/null +++ b/PowerShellGet/DSCResources/MSFT_PSModule/MSFT_PSModule.strings.psd1 @@ -0,0 +1,37 @@ +# +# Copyright (c) Microsoft Corporation. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +ConvertFrom-StringData @' +###PSLOC + FailtoUninstall=Failed to uninstall the module '{0}'. Message: {1} + FailtoInstall=Failed to install the module '{0}'. Message: {1} + InDesiredState=Resource '{0}' is in the desired state + NotInDesiredState=Resource '{0}' is not in the desired state + ModuleFound=Module '{0}' found in the node + ModuleNotFound=Module '{0}' not found in the node + ModuleWithRightPropertyNotFound=Module '{0}' with the right version or other properties not found in the node. Message: {1} + ModuleNotFoundInRepository=Module '{0}' with the right version or other properties not found in the repository. Message: {1} + StartGetModule=Begin invoking get-module '{0}' + StartFindModule=Begin invoking find-module '{0}' + StartInstallModule=Begin invoking install-module '{0}' version '{1}' from '{2}' repository + StartUnInstallModule=Begin invoking uninstall of the module '{0}' + InstalledSuccess=Successfully installed the module '{0}' + UnInstalledSuccess=Successfully uninstalled the module '{0}' + VersionMismatch=The installed Module '{0}' has the version: '{1}' + RepositoryMismatch=The installed Module '{0}' is from '{1}' repository + FoundModulePath=Found the module path:'{0}' + MultipleModuleFound=Total: '{0}' modules found with the same name. Please use RequiredVersion for filtering. Message: {1} + InstallationPolicyWarning=You are installing the module '{0}' from an untrusted repository' {1}'. Your current InstallationPolicy is '{2}'. If you trust the repository, set the policy to "Trusted". "Untrusted" otherwise. + InstallationPolicyFailed=Failed in the installation policy. Your current InstallationPolicy is '{0}' and the repository is '{1}'. If you trust the repository, set the policy to "Trusted". "Untrusted" otherwise. +###PSLOC + +'@ + diff --git a/PowerShellGet/DSCResources/OneGetHelper.psm1 b/PowerShellGet/DSCResources/OneGetHelper.psm1 new file mode 100644 index 00000000..b6409bb5 --- /dev/null +++ b/PowerShellGet/DSCResources/OneGetHelper.psm1 @@ -0,0 +1,301 @@ +# +# Copyright (c) Microsoft Corporation. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +#Helper functions for PackageManagement DSC Resouces + + +Import-LocalizedData -BindingVariable LocalizedData -filename OneGetHelper.strings.psd1 + + + Function ExtractArguments +{ + <# + .SYNOPSIS + + This is a helper function that extract the parameters from a given table. + + .PARAMETER FunctionBoundParameters + Specifies the hashtable containing a set of parameters to be extracted + + .PARAMETER ArgumentNames + Specifies A list of arguments you want to extract + #> + + Param + ( + [parameter(Mandatory = $true)] + [System.Collections.Hashtable] + $FunctionBoundParameters, + + #A list of arguments you want to extract + [parameter(Mandatory = $true)] + [System.String[]]$ArgumentNames + ) + + Write-Verbose -Message ($LocalizedData.CallingFunction -f $($MyInvocation.mycommand)) + + $returnValue=@{} + + foreach ($arg in $ArgumentNames) + { + if($FunctionBoundParameters.ContainsKey($arg)) + { + #Found an argument we are looking for, so we add it to return collection + $returnValue.Add($arg,$FunctionBoundParameters[$arg]) + } + } + + return $returnValue + } + +function ThrowError +{ + <# + .SYNOPSIS + + This is a helper function that throws an error. + + .PARAMETER ExceptionName + Specifies the type of errors, e.g. System.ArgumentException + + .PARAMETER ExceptionMessage + Specifies the exception message + + .PARAMETER ErrorId + Specifies an identifier of the error + + .PARAMETER ErrorCategory + Specifies the error category, e.g., InvalidArgument defined in System.Management.Automation. + + #> + + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ExceptionName, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ExceptionMessage, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $ErrorId, + + [parameter(Mandatory = $true)] + [ValidateNotNull()] + [System.Management.Automation.ErrorCategory] + $ErrorCategory + ) + + Write-Verbose -Message ($LocalizedData.CallingFunction -f $($MyInvocation.mycommand)) + + $exception = New-Object -TypeName $ExceptionName -ArgumentList $ExceptionMessage; + $errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList ($exception, $ErrorId, $ErrorCategory, $null) + throw $errorRecord +} + +Function ValidateArgument +{ + <# + .SYNOPSIS + + This is a helper function that validates the arguments. + + .PARAMETER Argument + Specifies the argument to be validated. + + .PARAMETER Type + Specifies the type of argument. + #> + + [CmdletBinding()] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [string]$Argument, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String]$Type, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [String]$ProviderName + ) + + Write-Verbose -Message ($LocalizedData.CallingFunction -f $($MyInvocation.mycommand)) + + switch ($Type) + { + + "SourceUri" + { + # Checks whether given URI represents specific scheme + # Most common schemes: file, http, https, ftp + $scheme =@('http', 'https', 'file', 'ftp') + + $newUri = $Argument -as [System.URI] + $returnValue = ($newUri -and $newUri.AbsoluteURI -and ($scheme -icontains $newuri.Scheme)) + + if ($returnValue -eq $false) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.InValidUri -f $Argument)` + -ErrorId "InValidUri" ` + -ErrorCategory InvalidArgument + } + + #Check whether it's a valid uri. Wait for the response within 2mins. + <#$result = Invoke-WebRequest $newUri -TimeoutSec 120 -UseBasicParsing -ErrorAction SilentlyContinue + + if ($null -eq (([xml]$result.Content).service )) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.InValidUri -f $Argument)` + -ErrorId "InValidUri" ` + -ErrorCategory InvalidArgument + }#> + + } + "DestinationPath" + { + $returnValue = Test-Path -Path $Argument + if ($returnValue -eq $false) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.PathDoesNotExist -f $Argument)` + -ErrorId "PathDoesNotExist" ` + -ErrorCategory InvalidArgument + } + } + "PackageSource" + { + #Argument can be either the package source Name or source Uri. + + #Check if the source is a uri + $uri = $Argument -as [System.URI] + + if($uri -and $uri.AbsoluteURI) + { + # Check if it's a valid Uri + ValidateArgument -Argument $Argument -Type "SourceUri" -ProviderName $ProviderName + } + else + { + #Check if it's a registered package source name + $source = PackageManagement\Get-PackageSource -Name $Argument -ProviderName $ProviderName -verbose -ErrorVariable ev + if ((-not $source) -or $ev) + { + #We do not need to throw error here as Get-PackageSource does already + Write-Verbose -Message ($LocalizedData.SourceNotFound -f $source) + } + } + } + default + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.UnexpectedArgument -f $Type)` + -ErrorId "UnexpectedArgument" ` + -ErrorCategory InvalidArgument + } + } +} + +Function ValidateVersionArgument +{ + <# + .SYNOPSIS + + This is a helper function that does the version validation. + + .PARAMETER RequiredVersion + Provides the required version. + + .PARAMETER MaximumVersion + Provides the maximum version. + + .PARAMETER MinimumVersion + Provides the minimum version. + #> + + [CmdletBinding()] + param + ( + [string]$RequiredVersion, + [string]$MinimumVersion, + [string]$MaximumVersion + + ) + + Write-Verbose -Message ($LocalizedData.CallingFunction -f $($MyInvocation.mycommand)) + + $isValid = $false + + #Case 1: No further check required if a user provides either none or one of these: minimumVersion, maximumVersion, and requiredVersion + if ($PSBoundParameters.Count -le 1) + { + return $true + } + + #Case 2: #If no RequiredVersion is provided + if (-not $PSBoundParameters.ContainsKey('RequiredVersion')) + { + #If no RequiredVersion, both MinimumVersion and MaximumVersion are provided. Otherwise fall into the Case #1 + $isValid = $PSBoundParameters['MinimumVersion'] -le $PSBoundParameters['MaximumVersion'] + } + + #Case 3: RequiredVersion is provided. + # In this case MinimumVersion and/or MaximumVersion also are provided. Otherwise fall in to Case #1. + # This is an invalid case. When RequiredVersion is provided, others are not allowed. so $isValid is false, which is already set in the init + + if ($isValid -eq $false) + { + ThrowError -ExceptionName "System.ArgumentException" ` + -ExceptionMessage ($LocalizedData.VersionError)` + -ErrorId "VersionError" ` + -ErrorCategory InvalidArgument + } +} + +Function Get-InstallationPolicy +{ + <# + .SYNOPSIS + + This is a helper function that retrives the InstallationPolicy from the given repository. + + .PARAMETER RepositoryName + Provides the repository Name. + + #> + + Param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String]$RepositoryName + ) + + Write-Verbose -Message ($LocalizedData.CallingFunction -f $($MyInvocation.mycommand)) + + $repositoryobj = PackageManagement\Get-PackageSource -Name $RepositoryName -ErrorAction SilentlyContinue -WarningAction SilentlyContinue + + if ($repositoryobj) + { + return $repositoryobj.IsTrusted + } +} diff --git a/PowerShellGet/DSCResources/OneGetHelper.strings.psd1 b/PowerShellGet/DSCResources/OneGetHelper.strings.psd1 new file mode 100644 index 00000000..37420224 --- /dev/null +++ b/PowerShellGet/DSCResources/OneGetHelper.strings.psd1 @@ -0,0 +1,22 @@ +# +# Copyright (c) Microsoft Corporation. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# culture="en-US" +ConvertFrom-StringData @' +###PSLOC + InValidUri=InValid Uri: '{0}'. A sample valid uri: https://www.powershellgallery.com/api/v2/. + PathDoesNotExist=Path: '{0}' does not exist + VersionError=MinimumVersion should be less than the maximumVersion. The MinimumVersion or maximumVersion cannot be used with the RequiredVersion in the same command. + UnexpectedArgument=Unexpected argument type: '{0}' + SourceNotFound=Source '{0}' not found. Please make sure you register it. + CallingFunction="Call a function '{0}'". +###PSLOC +'@