From 1d1cffd0c5d26689bcf5b78346c69f09f5db1578 Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 6 Mar 2017 16:26:06 -0800 Subject: [PATCH] Auto-mounted file system drives correctly created when mounted inside a module (#3034) Fixes #2442 --- .../engine/SessionStateDriveAPIs.cs | 13 ++-- .../Provider/AutomountSubstDrive.ps1 | 38 ++++++++++ .../Provider/AutomountSubstDriveCore.ps1 | 31 ++++++++ .../powershell/Provider/AutomountVHDDrive.ps1 | 76 +++++++++++++++++++ .../Pester.AutomountedDrives.Tests.ps1 | 55 ++++++++++++++ 5 files changed, 207 insertions(+), 6 deletions(-) create mode 100644 test/powershell/Provider/AutomountSubstDrive.ps1 create mode 100644 test/powershell/Provider/AutomountSubstDriveCore.ps1 create mode 100644 test/powershell/Provider/AutomountVHDDrive.ps1 create mode 100644 test/powershell/Provider/Pester.AutomountedDrives.Tests.ps1 diff --git a/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs b/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs index b70e4811ea..ea21579e8d 100644 --- a/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs +++ b/src/System.Management.Automation/engine/SessionStateDriveAPIs.cs @@ -508,12 +508,13 @@ namespace System.Management.Automation if (result == null && automount) { - result = AutomountBuiltInDrive(name); - } - - if (result == null && this == ExecutionContext.TopLevelSessionState) - { - result = AutomountFileSystemDrive(name); + // first try to automount as a file system drive + result = AutomountFileSystemDrive(name); + // if it didn't work, then try automounting as a BuiltIn drive (e.g. "Cert"/"Certificate"/"WSMan") + if (result == null) + { + result = AutomountBuiltInDrive(name); // internally this calls GetDrive(name, false) + } } if (result == null) diff --git a/test/powershell/Provider/AutomountSubstDrive.ps1 b/test/powershell/Provider/AutomountSubstDrive.ps1 new file mode 100644 index 0000000000..726366d2ff --- /dev/null +++ b/test/powershell/Provider/AutomountSubstDrive.ps1 @@ -0,0 +1,38 @@ +# Precondition: start from fresh PS session, do not have the media mounted +param([switch]$useModule, [string]$FullPath) + +$global:CoreScriptPath = Join-Path $PSScriptRoot 'AutomountSubstDriveCore.ps1' + +if ($useModule) +{ + $m = New-Module { + function Test-DrivePresenceFromModule + { + param ([String]$Path) + + & $global:CoreScriptPath -Path $Path + } + + Export-ModuleMember -Function Test-DrivePresenceFromModule + } +} + +try +{ + if ($useModule) + { + Import-Module $m -Force + Test-DrivePresenceFromModule -Path $FullPath + } + else + { + & $global:CoreScriptPath -Path $FullPath + } +} +finally +{ + if ($useModule) + { + Remove-Module $m + } +} diff --git a/test/powershell/Provider/AutomountSubstDriveCore.ps1 b/test/powershell/Provider/AutomountSubstDriveCore.ps1 new file mode 100644 index 0000000000..0f60f6a595 --- /dev/null +++ b/test/powershell/Provider/AutomountSubstDriveCore.ps1 @@ -0,0 +1,31 @@ +param ([String]$Path) + +try +{ + # Get a drive letter between F and Y that is not being used for the drive name. + $driveLetter = [char[]](70..89) | Where-Object {$_ -notin (Get-PSDrive).Name} | Select-Object -Last 1 + + $dir = New-Item $Path -ItemType Directory -Force + + # Create virtual drive pointing to the parent of the directory + subst.exe "$driveLetter`:" $dir.Parent.FullName + $exitCode = $LASTEXITCODE + if ($exitCode -ne 0) { Write-Error "Creating drive with subst.exe failed with exit code $exitCode" } + + $root = [String]::Format('{0}:\', $driveLetter) + $pathToCheck = Join-Path -Path $root -ChildPath $dir.Name + + if (Test-Path $pathToCheck) + { + "Drive found" + if (-not (Get-PSDrive -Name $driveLetter -Scope Global -ErrorAction SilentlyContinue)) + { + Write-Error "Drive is NOT in Global scope" + } + } + else { Write-Error "$pathToCheck not found" } +} +finally +{ + subst.exe "$driveLetter`:" /d +} diff --git a/test/powershell/Provider/AutomountVHDDrive.ps1 b/test/powershell/Provider/AutomountVHDDrive.ps1 new file mode 100644 index 0000000000..3401f2459f --- /dev/null +++ b/test/powershell/Provider/AutomountVHDDrive.ps1 @@ -0,0 +1,76 @@ +# Precondition: start from fresh PS session, do not have the media mounted +param([switch]$useModule, [string]$VHDPath) + +function CreateVHD ($VHDPath, $Size) +{ + $drive = (New-VHD -path $vhdpath -SizeBytes $size -Dynamic | ` + Mount-VHD -Passthru | ` + get-disk -number {$_.DiskNumber} | ` + Initialize-Disk -PartitionStyle MBR -PassThru | ` + New-Partition -UseMaximumSize -AssignDriveLetter:$False -MbrType IFS | ` + Format-Volume -Confirm:$false -FileSystem NTFS -force | ` + get-partition | ` + Add-PartitionAccessPath -AssignDriveLetter -PassThru | ` + get-volume).DriveLetter + + $drive +} + +if ($useModule) +{ + $m = New-Module { + function Test-DrivePresenceFromModule + { + param ([String]$Path) + + if (Test-Path $Path) + { + "Drive found" + if (-not (Get-PSDrive -Name $Path[0] -Scope Global -ErrorAction SilentlyContinue)) + { + Write-Error "Drive is NOT in Global scope" + } + } + else { Write-Error "$Path not found" } + } + + Export-ModuleMember -Function Test-DrivePresenceFromModule + } +} + +try +{ + if ($useModule) + { + Import-Module $m -Force + } + + $drive = CreateVHD -VHDPath $VHDPath -Size 5mb + $pathToCheck = "${drive}:" + + if ($useModule) + { + Test-DrivePresenceFromModule -Path $pathToCheck + } + else + { + if (Test-Path $pathToCheck) + { + "Drive found" + if (-not (Get-PSDrive -Name $drive -Scope Global -ErrorAction SilentlyContinue)) + { + Write-Error "Drive is NOT in Global scope" + } + } + else { Write-Error "$pathToCheck not found" } + } +} +finally +{ + if ($useModule) + { + Remove-Module $m + } + Dismount-VHD $VHDPath + Remove-Item $VHDPath +} diff --git a/test/powershell/Provider/Pester.AutomountedDrives.Tests.ps1 b/test/powershell/Provider/Pester.AutomountedDrives.Tests.ps1 new file mode 100644 index 0000000000..1082313bb1 --- /dev/null +++ b/test/powershell/Provider/Pester.AutomountedDrives.Tests.ps1 @@ -0,0 +1,55 @@ +<############################################################################################ + # File: Pester.AutomountedDrives.Tests.ps1 + # Pester.AutomountedDrives.Tests suite contains Tests that are + # used for validating automounted PowerShell drives. + ############################################################################################> +$script:TestSourceRoot = $PSScriptRoot +Describe "Test suite for validating automounted PowerShell drives" -Tags "CI","Slow" { + + BeforeAll { + $powershell = Join-Path -Path $PsHome -ChildPath "powershell" + + $AutomountVHDDriveScriptPath = Join-Path $script:TestSourceRoot 'AutomountVHDDrive.ps1' + $vhdPath = Join-Path $TestDrive 'TestAutomountVHD.vhd' + + $AutomountSubstDriveScriptPath = Join-Path $script:TestSourceRoot 'AutomountSubstDrive.ps1' + $substDir = Join-Path (Join-Path $TestDrive 'TestAutomountSubstDrive') 'TestDriveRoot' + New-Item $substDir -ItemType Directory -Force | Out-Null + + $SubstNotFound = $false + try { subst.exe } catch { $SubstNotFound = $true } + + $VHDToolsNotFound = $false + try + { + $tmpVhdPath = Join-Path $TestDrive 'TestVHD.vhd' + New-VHD -path $tmpVhdPath -SizeBytes 5mb -Dynamic -ErrorAction Stop + Remove-Item $tmpVhdPath + } + catch + { $VHDToolsNotFound = $true } + } + + Context "Validating automounting FileSystem drives" { + + It "Test automounting using subst.exe" -Skip:$SubstNotFound { + & $powershell -noprofile -command "& '$AutomountSubstDriveScriptPath' -FullPath '$substDir'" | Should Be "Drive found" + } + + It "Test automounting using New-VHD/Mount-VHD" -Skip:$VHDToolsNotFound { + & $powershell -noprofile -command "& '$AutomountVHDDriveScriptPath' -VHDPath '$vhdPath'" | Should Be "Drive found" + } + } + + Context "Validating automounting FileSystem drives from modules" { + + It "Test automounting using subst.exe" -Skip:$SubstNotFound { + & $powershell -noprofile -command "& '$AutomountSubstDriveScriptPath' -useModule -FullPath '$substDir'" | Should Be "Drive found" + } + + It "Test automounting using New-VHD/Mount-VHD" -Skip:$VHDToolsNotFound { + $vhdPath = Join-Path $TestDrive 'TestAutomountVHD.vhd' + & $powershell -noprofile -command "& '$AutomountVHDDriveScriptPath' -useModule -VHDPath '$vhdPath'" | Should Be "Drive found" + } + } +}