From 1ada77fb59a0a0fa2bcf3319d0492b1c63be11ae Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sun, 21 Jan 2024 20:17:14 +0100 Subject: [PATCH] Set-PSModulePath: New parameter set (#114) --- CHANGELOG.md | 6 ++ build.yaml | 6 ++ source/Public/Set-PSModulePath.ps1 | 69 ++++++++++++-- tests/Unit/Public/Set-PSModulePath.Tests.ps1 | 98 ++++++++++++++++++++ 4 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 tests/Unit/Public/Set-PSModulePath.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 485d8e7..e58db14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Tasks for automating documentation for the GitHub repository wiki ([issue #110](https://github.com/dsccommunity/DscResource.Common/issues/110)). +- `Set-PSModulePath` + - A new parameters set takes two parameters `FromTarget` and `ToTarget` + that can copy from omne target to the other ([issue #102](https://github.com/dsccommunity/DscResource.Common/issues/102)). + - A new parameter `PassThru` that, if specified, returns the path that + was set. ### Changed @@ -17,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Command documentation was moved from README to GitHub repository wiki. - Change the word cmdlet to command throughout in the documentation, code and localization strings. +- A meta task now removes the built module from the session if it is imported. - `Get-LocalizedData` - Refactored to simplify execution and debugging. The command previously used a steppable pipeline (proxies `Import-LocalizedData`), that was diff --git a/build.yaml b/build.yaml index 325ca24..4e4a3be 100644 --- a/build.yaml +++ b/build.yaml @@ -19,6 +19,7 @@ BuildWorkflow: - test build: + - Remove_BuiltModule_From_Session - Clean - Build_Module_ModuleBuilder - Build_NestedModules_ModuleBuilder @@ -51,6 +52,11 @@ BuildWorkflow: - publish_module_to_gallery - Publish_GitHub_Wiki_Content + Remove_BuiltModule_From_Session: | + { + Remove-Module -Name 'DscResource.Common' -ErrorAction SilentlyContinue + } + #################################################### # PESTER Configuration # #################################################### diff --git a/source/Public/Set-PSModulePath.ps1 b/source/Public/Set-PSModulePath.ps1 index 82f7e58..ce35418 100644 --- a/source/Public/Set-PSModulePath.ps1 +++ b/source/Public/Set-PSModulePath.ps1 @@ -17,6 +17,15 @@ If set the PSModulePath will be changed machine wide. If not set, only the current session will be changed. + .PARAMETER FromTarget + The target environment variable to copy the value from. + + .PARAMETER ToTarget + The target environment variable to set the value to. + + .PARAMETER PassThru + If specified, returns the set value. + .EXAMPLE Set-PSModulePath -Path ';' @@ -28,6 +37,12 @@ Sets the machine environment variable `PSModulePath` to the specified path or paths (separated with semi-colons). + + .EXAMPLE + Set-PSModulePath -FromTarget 'MAchine' -ToTarget 'User' + + Copies the value of the machine environment variable `PSModulePath` to the + user environment variable `PSModulePath`. #> function Set-PSModulePath { @@ -36,25 +51,65 @@ function Set-PSModulePath '', Justification = 'ShouldProcess is not supported in DSC resources.' )] - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'Default')] + [OutputType([System.String])] param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory = $true, ParameterSetName = 'Default')] [ValidateNotNullOrEmpty()] [System.String] $Path, + [Parameter(ParameterSetName = 'Default')] + [System.Management.Automation.SwitchParameter] + $Machine, + + [Parameter(Mandatory = $true, ParameterSetName = 'TargetParameters')] + [ValidateSet('Session', 'User', 'Machine')] + [System.String] + $FromTarget, + + [Parameter(Mandatory = $true, ParameterSetName = 'TargetParameters')] + [ValidateSet('Session', 'User', 'Machine')] + [System.String] + $ToTarget, + [Parameter()] [System.Management.Automation.SwitchParameter] - $Machine + $PassThru ) - if ($Machine.IsPresent) + if ($PSCmdlet.ParameterSetName -eq 'Default') + { + if ($Machine.IsPresent) + { + [System.Environment]::SetEnvironmentVariable('PSModulePath', $Path, [System.EnvironmentVariableTarget]::Machine) + } + else + { + $env:PSModulePath = $Path + } + } + elseif ($PSCmdlet.ParameterSetName -eq 'TargetParameters') { - [System.Environment]::SetEnvironmentVariable('PSModulePath', $Path, [System.EnvironmentVariableTarget]::Machine) + $Path = Get-EnvironmentVariable -Name 'PSModulePath' -FromTarget $FromTarget + + switch ($ToTarget) + { + 'Session' + { + [System.Environment]::SetEnvironmentVariable('PSModulePath', $Path) + } + + default + { + [System.Environment]::SetEnvironmentVariable('PSModulePath', $Path, [System.EnvironmentVariableTarget]::$ToTarget) + } + } } - else + + if ($PassThru.IsPresent) { - $env:PSModulePath = $Path + return $Path } } diff --git a/tests/Unit/Public/Set-PSModulePath.Tests.ps1 b/tests/Unit/Public/Set-PSModulePath.Tests.ps1 new file mode 100644 index 0000000..fd65c30 --- /dev/null +++ b/tests/Unit/Public/Set-PSModulePath.Tests.ps1 @@ -0,0 +1,98 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:moduleName = 'DscResource.Common' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + # Re-import the module using force to get any code changes between runs. + Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop' + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Remove-Module -Name $script:moduleName +} + +Describe 'Set-PSModulePath' { + Context 'When using the parameter set TargetParameters' { + Context 'When using FromTarget and ToTarget parameters' { + BeforeAll { + $originalPSModulePath = $env:PSModulePath + + Mock -CommandName Get-EnvironmentVariable -MockWith { + return '/tmp/path' + } + } + + AfterAll { + $env:PSModulePath = $originalPSModulePath + } + + It 'Should not throw an error and have set the correct value' { + { Set-PSModulePath -FromTarget 'User' -ToTarget 'Session' } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-EnvironmentVariable -Exactly -Times 1 -Scope It + + [Environment]::GetEnvironmentVariable('PSModulePath') | Should -Be '/tmp/path' + } + + It 'Should have returned the user PSModulePath to the original value' { + { Set-PSModulePath -Path $originalPSModulePath } | Should -Not -Throw + + [Environment]::GetEnvironmentVariable('PSModulePath') | Should -Be $originalPSModulePath + } + } + + Context 'When using PassThru parameter' { + BeforeAll { + $originalPSModulePath = $env:PSModulePath + } + + AfterEach { + $env:PSModulePath = $originalPSModulePath + } + + It 'Should not throw an error and return the correct value' { + $result = Set-PSModulePath -Path 'C:\Module' -PassThru + + $result | Should -Be 'C:\Module' + } + + It 'Should have set the session PSModulePath to the new value' { + $env:PSModulePath | Should -Be $originalPSModulePath + } + } + } +}