MegaBites-AI/Windows-powershell
0308
1# Copyright (c) Microsoft Corporation.2# Licensed under the MIT License.3Describe "Import-Module" -Tags "CI" {4 $moduleName = "Microsoft.PowerShell.Security"5 BeforeAll {6 $originalPSModulePath = $env:PSModulePath7 New-Item -ItemType Directory -Path "$testdrive\Modules\TestModule\1.1" -Force > $null8 New-Item -ItemType Directory -Path "$testdrive\Modules\TestModule\2.0" -Force > $null9 $env:PSModulePath += [System.IO.Path]::PathSeparator + "$testdrive\Modules"10 New-ModuleManifest -Path "$testdrive\Modules\TestModule\1.1\TestModule.psd1" -ModuleVersion 1.111 New-ModuleManifest -Path "$testdrive\Modules\TestModule\2.0\TestModule.psd1" -ModuleVersion 2.012 }13 14 AfterAll {15 $env:PSModulePath = $originalPSModulePath16 }17 18 BeforeEach {19 Remove-Module -Name $moduleName -Force20 (Get-Module -Name $moduleName).Name | Should -BeNullOrEmpty21 Remove-Module -Name TestModule -Force -ErrorAction SilentlyContinue22 }23 24 AfterEach {25 Import-Module -Name $moduleName -Force26 (Get-Module -Name $moduleName).Name | Should -BeExactly $moduleName27 }28 29 It "should be able to add a module with using Name switch" {30 { Import-Module -Name $moduleName } | Should -Not -Throw31 (Get-Module -Name $moduleName).Name | Should -BeExactly $moduleName32 }33 34 It "should be able to load a module with a trailing directory separator: <modulePath>" -TestCases @(35 @{ modulePath = (Get-Module -ListAvailable $moduleName)[0].ModuleBase + [System.IO.Path]::DirectorySeparatorChar; expectedName = $moduleName },36 @{ modulePath = Join-Path -Path $TestDrive -ChildPath "\Modules\TestModule\"; expectedName = "TestModule" }37 ) {38 param( $modulePath, $expectedName )39 { Import-Module -Name $modulePath -ErrorAction Stop } | Should -Not -Throw40 (Get-Module -Name $expectedName).Name | Should -BeExactly $expectedName41 }42 43 It "should be able to add a module with using ModuleInfo switch" {44 $a = (Get-Module -ListAvailable $moduleName)[0]45 { Import-Module -ModuleInfo $a } | Should -Not -Throw46 (Get-Module -Name $moduleName).Name | Should -BeExactly $moduleName47 }48 49 It "should be able to load an already loaded module" {50 Import-Module $moduleName51 { $script:module = Import-Module $moduleName -PassThru -ErrorAction Stop } | Should -Not -Throw52 Get-Module -Name $moduleName | Should -BeExactly $script:module53 }54 55 It "should only load the specified version" {56 Import-Module TestModule -RequiredVersion 1.157 (Get-Module TestModule).Version | Should -BeIn "1.1"58 }59 60 It 'ProcessorArchitecture should work' {61 $currentProcessorArchitecture = switch ([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture) {62 'X86' { 'x86' }63 'X64' { 'amd64' }64 'Arm64' { 'arm' }65 'Arm' { 'arm' }66 default { throw "Unknown processor architecture" }67 }68 New-ModuleManifest -Path "$TestDrive\TestModule.psd1" -ProcessorArchitecture $currentProcessorArchitecture69 $module = Import-Module -Name "$TestDrive\TestModule.psd1" -PassThru70 $module.ProcessorArchitecture | Should -Be $currentProcessorArchitecture71 }72}73 74Describe "Import-Module with ScriptsToProcess" -Tags "CI" {75 76 BeforeAll {77 $moduleRootPath = Join-Path $TestDrive 'TestModules'78 New-Item $moduleRootPath -ItemType Directory -Force | Out-Null79 Push-Location $moduleRootPath80 81 "1 | Out-File out.txt -Append -NoNewline" | Out-File script1.ps182 "2 | Out-File out.txt -Append -NoNewline" | Out-File script2.ps183 New-ModuleManifest module1.psd1 -ScriptsToProcess script1.ps184 New-ModuleManifest module2.psd1 -ScriptsToProcess script2.ps1 -NestedModules module1.psd185 }86 87 AfterAll {88 Pop-Location89 }90 91 BeforeEach {92 New-Item out.txt -ItemType File -Force | Out-Null93 }94 95 AfterEach {96 $m = @('module1','module2','script1','script2')97 Remove-Module $m -Force -ErrorAction SilentlyContinue98 Remove-Item out.txt -Force -ErrorAction SilentlyContinue99 }100 101 $testCases = @(102 @{ TestNameSuffix = 'for top-level module'; ipmoParms = @{'Name'='.\module1.psd1'}; Expected = '1' }103 @{ TestNameSuffix = 'for top-level and nested module'; ipmoParms = @{'Name'='.\module2.psd1'}; Expected = '21' }104 @{ TestNameSuffix = 'for top-level module when -Version is specified'; ipmoParms = @{'Name'='.\module1.psd1'; 'Version'='0.0.1'}; Expected = '1' }105 @{ TestNameSuffix = 'for top-level and nested module when -Version is specified'; ipmoParms = @{'Name'='.\module2.psd1'; 'Version'='0.0.1'}; Expected = '21' }106 )107 108 It "Verify ScriptsToProcess are executed <TestNameSuffix>" -TestCases $testCases {109 param($TestNameSuffix,$ipmoParms,$Expected)110 Import-Module @ipmoParms111 Get-Content out.txt | Should -BeExactly $Expected112 }113}114 115Describe "Import-Module for Binary Modules in GAC" -Tags 'Feature' {116 Context "Modules are not loaded from GAC" {117 It "Load PSScheduledJob from Windows Powershell Modules folder should fail" -Skip:(-not $IsWindows) {118 # NOTE:119 # This test attempts to load an assembly from the GAC and expects to fail.120 # However, if the assembly is already loaded, the assembly will be resolved before121 # the DisableGACLoading flag comes into effect, meaning no error is thrown and the test fails.122 #123 # Since the System32 module direction is now on the module path and Get-Module -ListAvailable124 # loads assemblies, the assembly is resolved and this test will fail if any other tests before125 # it call Get-Module -ListAvailable.126 #127 # So for now, the solution is to run this test in a fresh process.128 # Since disabling GAC loading is supposed to be a startup option, this is possibly appropriate.129 130 $testScript = {131 [System.Management.Automation.Internal.InternalTestHooks]::SetTestHook('DisableGACLoading', $true)132 $modulePath = Join-Path $env:windir "System32/WindowsPowershell/v1.0/Modules/PSScheduledJob"133 Import-Module $modulePath -SkipEditionCheck134 }135 $err = (& "$PSHOME\pwsh.exe" -c $testScript 2>&1 | Where-Object { $_ -is [System.Management.Automation.ErrorRecord] })[0]136 $err.FullyQualifiedErrorId | Should -Be "FormatXmlUpdateException,Microsoft.PowerShell.Commands.ImportModuleCommand"137 }138 }139 140 Context "Modules are loaded from GAC" {141 It "Load PSScheduledJob from Windows Powershell Modules folder" -Skip:(-not $IsWindows) {142 $modulePath = Join-Path $env:windir "System32/WindowsPowershell/v1.0/Modules/PSScheduledJob"143 Import-Module $modulePath -SkipEditionCheck144 (Get-Command New-JobTrigger).Name | Should -BeExactly 'New-JobTrigger'145 }146 }147}148 149Describe "Import-Module for Binary Modules" -Tags 'CI' {150 151 BeforeAll {152 $src = @"153 using System.Management.Automation;154 namespace ModuleCmdlets155 {156 [Cmdlet(VerbsDiagnostic.Test,"BinaryModuleCmdlet1")]157 public class TestBinaryModuleCmdlet1Command : Cmdlet158 {159 protected override void BeginProcessing()160 {161 WriteObject("BinaryModuleCmdlet1 exported by the ModuleCmdlets module.");162 }163 }164 }165"@166 Add-Type -TypeDefinition $src -OutputAssembly $TESTDRIVE\System.dll167 Add-Type -TypeDefinition $src -OutputAssembly $TESTDRIVE\System.exe168 }169 170 It "PS should try to load the binary module from a file path with extension: <extension>" -TestCases (171 @{extension = "dll"},172 @{extension = "exe"}173 ) {174 param ($extension)175 176 try {177 $TestModulePath = Join-Path $TESTDRIVE "System.$extension"178 $job = Start-Job -ScriptBlock {179 $module = Import-Module $using:TestModulePath -PassThru;180 $module.ImplementingAssembly.Location;181 Test-BinaryModuleCmdlet1182 }183 $assemblyLocation, $cmdletOutput = $job | Wait-Job -Timeout 30 | Receive-Job184 }185 finally {186 $job | Remove-Job -ErrorAction Ignore187 }188 189 $assemblyLocation | Should -BeExactly $TestModulePath190 $cmdletOutput | Should -BeExactly "BinaryModuleCmdlet1 exported by the ModuleCmdlets module."191 }192 193 It 'PS should be able to load the executable as a root module' {194 $psdFile = Join-Path $TESTDRIVE test.psd1195 $exe = Join-Path $TESTDRIVE System.exe196 New-ModuleManifest -Path $psdFile -RootModule $exe197 198 try {199 $job = Start-Job -ScriptBlock { Import-Module $using:psdFile -PassThru }200 $module = $job | Wait-Job -Timeout 30 | Receive-Job201 }202 finally {203 $job | Remove-Job -ErrorAction Ignore204 }205 206 $module | Should -Not -BeNullOrEmpty207 $module.ModuleType.ToString() | Should -Be 'Binary'208 $module.RootModule | Should -Be $exe209 $module.ExportedCmdlets['Test-BinaryModuleCmdlet1'] | Should -Be 'Test-BinaryModuleCmdlet1'210 }211 212 It 'PS should be able to load the executable as a nested module' {213 $psdFile = Join-Path $TESTDRIVE test.psd1214 $exe = Join-Path $TESTDRIVE System.exe215 New-ModuleManifest -Path $psdFile -NestedModules $exe216 217 try {218 $job = Start-Job -ScriptBlock {219 $module = Import-Module $using:psdFile -PassThru220 # return the module and the nested module assembly location221 $module222 $module.NestedModules[0].ImplementingAssembly.Location223 }224 $module, $location = $job | Wait-Job -Timeout 30 | Receive-Job225 }226 finally {227 $job | Remove-Job -ErrorAction Ignore228 }229 230 $module | Should -Not -BeNullOrEmpty231 $module.ModuleType.ToString() | Should -Be 'Manifest'232 $module.ExportedCmdlets['Test-BinaryModuleCmdlet1'] | Should -Be 'Test-BinaryModuleCmdlet1'233 $module.NestedModules | Should -Not -BeNullOrEmpty234 $location | Should -Be $exe235 }236 237 It "PS should try to load the assembly from assembly name if file path doesn't exist" {238 $psdFile = Join-Path $TESTDRIVE test.psd1239 $nestedModule = Join-Path NOExistedPath Microsoft.PowerShell.Commands.Utility.dll240 New-ModuleManifest -Path $psdFile -NestedModules $nestedModule241 242 try {243 $job = Start-Job -ScriptBlock {244 $module = Import-Module $using:psdFile -PassThru245 # return the module and the assembly location246 $module247 $module.NestedModules[0].ImplementingAssembly.Location248 }249 $module, $location = $job | Wait-Job -Timeout 30 | Receive-Job250 }251 finally {252 $job | Remove-Job -ErrorAction Ignore253 }254 255 $module.NestedModules | Should -Not -BeNullOrEmpty256 $assemblyLocation = [Microsoft.PowerShell.Commands.AddTypeCommand].Assembly.Location257 $location | Should -Be $assemblyLocation258 }259 260 It 'Should load from ModuleBase path before looking up in GAC' -Skip:(-not $IsWindows) {261 $module = Get-Module PSScheduledJob -ListAvailable -SkipEditionCheck262 $moduleBasePath = Split-Path $module.Path263 $destPath = New-Item -ItemType Directory -Path "$TestDrive/PSScheduledJob"264 $gacAssemblyPath = (Get-ChildItem "${env:WinDir}\Microsoft.NET\assembly\GAC_MSIL\Microsoft.PowerShell.ScheduledJob" -Recurse -Filter 'Microsoft.PowerShell.ScheduledJob.dll').FullName265 266 # Copy format, type and psd1267 Copy-Item "$moduleBasePath/PSScheduledJob*.*" -Destination $destPath -Force268 269 # Copy assembly to temp module folder"270 Copy-Item $gacAssemblyPath -Destination $destPath -Force271 272 # Use a different pwsh so that we do not have the PSScheduledJob module already loaded.273 $loadedAssemblyLocation = & "$PSHOME/pwsh" -noprofile -c "Import-Module $destPath -Force; [Microsoft.PowerShell.ScheduledJob.AddJobTriggerCommand].Assembly.Location"274 $loadedAssemblyLocation | Should -BeLike "$TestDrive*\Microsoft.PowerShell.ScheduledJob.dll"275 }276}277 278Describe "Import-Module should be case insensitive" -Tags 'CI' {279 BeforeAll {280 $defaultPSModuleAutoloadingPreference = $PSModuleAutoLoadingPreference281 $originalPSModulePath = $env:PSModulePath.Clone()282 $modulesPath = "$TestDrive\Modules"283 $env:PSModulePath += [System.IO.Path]::PathSeparator + $modulesPath284 $PSModuleAutoLoadingPreference = "none"285 }286 287 AfterAll {288 $global:PSModuleAutoloadingPreference = $defaultPSModuleAutoloadingPreference289 $env:PSModulePath = $originalPSModulePath290 }291 292 AfterEach {293 Remove-Item -Recurse -Path $modulesPath -Force -ErrorAction SilentlyContinue294 }295 296 It "Import-Module can import a module using different casing using '<modulePath>' and manifest:<manifest>" -TestCases @(297 @{modulePath="TESTMODULE/1.1"; manifest=$true},298 @{modulePath="TESTMODULE" ; manifest=$true},299 @{modulePath="TESTMODULE" ; manifest=$false}300 ) {301 param ($modulePath, $manifest)302 New-Item -ItemType Directory -Path "$modulesPath/$modulePath" -Force > $null303 if ($manifest) {304 New-ModuleManifest -Path "$modulesPath/$modulePath/TESTMODULE.psd1" -RootModule "TESTMODULE.psm1" -ModuleVersion 1.1305 }306 Set-Content -Path "$modulesPath/$modulePath/TESTMODULE.psm1" -Value "function mytest { 'hello' }"307 Import-Module testMODULE308 $m = Get-Module TESTmodule309 $m | Should -BeOfType System.Management.Automation.PSModuleInfo310 $m.Name | Should -BeIn "TESTMODULE"311 mytest | Should -BeExactly "hello"312 Remove-Module TestModule313 Get-Module tESTmODULE | Should -BeNullOrEmpty314 }315}316 317Describe "Circular nested module test" -tags "CI" {318 BeforeAll {319 $moduleFolder = Join-Path $TestDrive CircularNestedModuleTest320 $psdPath = Join-Path $moduleFolder CircularNestedModuleTest.psd1321 $psmPath = Join-Path $moduleFolder CircularNestedModuleTest.psm1322 323 New-Item -Path $moduleFolder -ItemType Directory -Force > $null324 Set-Content -Path $psdPath -Value "@{ ModuleVersion = '0.0.1'; RootModule = 'CircularNestedModuleTest'; NestedModules = @('CircularNestedModuleTest') }" -Encoding Ascii325 Set-Content -Path $psmPath -Value "function bar {}" -Encoding Ascii326 }327 328 AfterAll {329 Remove-Module -Name CircularNestedModuleTest -Force -ErrorAction SilentlyContinue330 }331 332 It "Loading the module should succeed and return a module with circular nested module" {333 $m = Import-Module $psdPath -PassThru334 $m.NestedModules[0] | Should -Be $m335 }336}337 338Describe "Import-Module -Force behaviour" -Tag "CI" {339 BeforeAll {340 $moduleContent = 'function Test-One { return 101 }'341 $newModuleContent = "function Test-One { return 93 }`nfunction Test-Two { return 14 }"342 $modulePath = Join-Path $TestDrive 'ipmofTestModule.psm1'343 }344 345 AfterEach {346 Get-Module 'ipmofTestModule' | Remove-Module347 }348 349 It "Loads new functions when Import-Module is called with -Force" {350 Set-Content -Path $modulePath -Value $moduleContent351 Import-Module $modulePath352 353 Test-One | Should -Be 101354 { Test-Two } | Should -Throw -ErrorId 'CommandNotFoundException'355 356 Set-Content -Path $modulePath -Value $newModuleContent -Force357 Import-Module -Force $modulePath358 359 Test-One | Should -Be 93360 Test-Two | Should -Be 14361 }362 363 It "Does not load new functions when Import-Module is called without -Force" {364 Set-Content -Path $modulePath -Value $moduleContent365 Import-Module $modulePath366 367 Test-One | Should -Be 101368 { Test-Two } | Should -Throw -ErrorId 'CommandNotFoundException'369 370 Set-Content -Path $modulePath -Value $newModuleContent -Force371 Import-Module $modulePath372 373 Test-One | Should -Be 101374 { Test-Two } | Should -Throw -ErrorId 'CommandNotFoundException'375 }376}377 378Describe "Module with FileList" -Tag "CI" {379 BeforeAll {380 $src = @"381 using System;382 namespace ModuleCmdlets383 {384 public class FileListLoad385 {386 }387 }388"@389 390 $originalPSModulePath = $env:PSModulePath391 New-Item -ItemType Directory -Path "$testdrive\Modules\FileListLoadTest\" -Force > $null392 393 $asmPath = "$TESTDRIVE\Modules\FileListLoadTest\FileListLoadTest.dll"394 Add-Type -TypeDefinition $src -OutputAssembly $asmPath395 396 $env:PSModulePath += [System.IO.Path]::PathSeparator + "$testdrive\Modules"397 New-ModuleManifest -Path "$testdrive\Modules\FileListLoadTest\FileListLoadTest.psd1" -FileList @("FileListLoadTest.dll")398 }399 400 AfterAll {401 $env:PSModulePath = $originalPSModulePath402 }403 404 It "Assemblies in FileList are not loaded" {405 Import-Module FileListLoadTest406 $asms = [System.AppDomain]::CurrentDomain.GetAssemblies().Location407 $asmPath | Should -Not -BeIn $asms408 }409}410 