From ffaaef19c8b983f2b0a29ec737b98e576a8945d5 Mon Sep 17 00:00:00 2001 From: Stu Mace Date: Sun, 17 Dec 2017 09:36:18 +1300 Subject: [PATCH 01/45] initial commit of optical disk drive letter fixes #96 --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 275 ++++++++++ .../MSFT_xOpticalDiskDriveLetter.schema.mof | 8 + .../MSFT_xOpticalDiskDriveLetter/README.md | 17 + .../MSFT_xOpticalDiskDriveLetter.strings.psd1 | 12 + ...xOpticalDiskDriveLetter_SetDriveLetter.ps1 | 17 + README.md | 2 + ...ticalDiskDriveLetter.Integration.Tests.ps1 | 93 ++++ .../MSFT_xOpticalDiskDriveLetter.config.ps1 | 8 + .../MSFT_xOpticalDiskDriveLetter.Tests.ps1 | 470 ++++++++++++++++++ 9 files changed, 902 insertions(+) create mode 100644 Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 create mode 100644 Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof create mode 100644 Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md create mode 100644 Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 create mode 100644 Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 create mode 100644 Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 create mode 100644 Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 create mode 100644 Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 new file mode 100644 index 00000000..f1d618e2 --- /dev/null +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -0,0 +1,275 @@ +# Suppressed as per PSSA Rule Severity guidelines for unit/integration tests: +# https://github.com/PowerShell/DscResources/blob/master/PSSARuleSeverities.md +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '')] +param () + +$modulePath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -ChildPath 'Modules' + +# Import the Storage Common Modules +Import-Module -Name (Join-Path -Path $modulePath ` + -ChildPath (Join-Path -Path 'StorageDsc.Common' ` + -ChildPath 'StorageDsc.Common.psm1')) + +# Import the Storage Resource Helper Module +Import-Module -Name (Join-Path -Path $modulePath ` + -ChildPath (Join-Path -Path 'StorageDsc.ResourceHelper' ` + -ChildPath 'StorageDsc.ResourceHelper.psm1')) + +# Import Localization Strings +$localizedData = Get-LocalizedData ` + -ResourceName 'MSFT_xOpticalDiskDriveLetter' ` + -ResourcePath (Split-Path -Parent $Script:MyInvocation.MyCommand.Path) + +<# + .SYNOPSIS + This helper function returns the current drive letter assigned to the optical disk. + +#> +function Get-OpticalDiskDriveLetter +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + ) + + <# + The Caption and DeviceID properties are checked to avoid mounted ISO images in Windows 2012+ and Windows 10. + The device ID is required because a CD/DVD in a Hyper-V virtual machine has the same caption as a mounted ISO. + + Example DeviceID for a virtual drive in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006 + Example DeviceID for a mounted ISO in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002 + #> + $driveLetter = (Get-CimInstance -ClassName win32_cdromdrive | Where-Object { + -not ( + $_.Caption -eq "Microsoft Virtual DVD-ROM" -and + ($_.DeviceID.Split("\")[-1]).Length -gt 10 + ) + } + ).Drive + + return $driveLetter +} + +<# + .SYNOPSIS + Returns the current drive letter assigned to the optical disk. + + .PARAMETER DriveLetter + Specifies the preferred letter to assign to the optical disk. + +#> +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + # specify the drive letter as a single letter, optionally include the colon + [Parameter(Mandatory = $true)] + [System.String] + $DriveLetter + ) + + # allow use of drive letter without colon + $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.UsingGetCimInstanceToFetchDriveLetter) + ) -join '' ) + + $currentDriveLetter = Get-OpticalDiskDriveLetter + + if (-not $currentDriveLetter) + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.NoOpticalDiskDrive) + ) -join '' ) + + $Ensure = 'Present' + } + else { + # check if $driveletter is the location of the optical disk + if ($currentDriveLetter -eq $DriveLetter) + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDriveSetAsRequested -f $DriveLetter) + ) -join '' ) + + $Ensure = 'Present' + } + else + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDriveNotSetAsRequested -f $currentDriveLetter,$DriveLetter) + ) -join '' ) + + $Ensure = 'Absent' + } + } + + $returnValue = @{ + DriveLetter = $currentDriveLetter + Ensure = $Ensure + } + + $returnValue + +} # Get-TargetResource + +<# + .SYNOPSIS + Sets the drive letter of the optical disk. + + .PARAMETER DriveLetter + Specifies the drive letter to assign to the optical disk. + + .PARAMETER Ensure + Determines whether the setting should be applied or removed. +#> +function Set-TargetResource +{ + [CmdletBinding(SupportsShouldProcess=$True, + ConfirmImpact='Low')] + param + ( + # specify the drive letter as a single letter, optionally include the colon + [Parameter(Mandatory = $true)] + [System.String] + $DriveLetter, + + [ValidateSet('Present','Absent')] + [System.String] + $Ensure = 'Present' + ) + + # allow use of drive letter without colon + $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon + + + $currentDriveLetter = Get-OpticalDiskDriveLetter + + if ($currentDriveLetter -eq $DriveLetter -and $Ensure -eq 'Present') + { + return + } + + # assuming a drive letter is found + if ($currentDriveLetter) + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.AttemptingToSetDriveLetter -f $currentDriveLetter,$DriveLetter) + ) -join '' ) + + if ($PSCmdlet.ShouldProcess("Setting optical disk letter to $DriveLetter")) + { + + # if $Ensure -eq Absent this will remove the drive letter from the optical disk + if ($Ensure -eq 'Absent') + { + $DriveLetter = $null + } + Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$currentDriveLetter'" | + Set-CimInstance -Property @{ DriveLetter = $DriveLetter } + } + } + else + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.NoOpticalDiskDrive) + ) -join '' ) + } +} # Set-TargetResource + +<# + .SYNOPSIS + Tests the optical disk letter is set as expected + + .PARAMETER DriveLetter + Specifies the drive letter to test if it is assigned to the optical disk. + + .PARAMETER Ensure + Determines whether the setting should be applied or removed. +#> +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + # specify the drive letter as a single letter, optionally include the colon + [Parameter(Mandatory = $true)] + [System.String] + $DriveLetter, + + [ValidateSet('Present','Absent')] + [System.String] + $Ensure = 'Present' + ) + + # allow use of drive letter without colon + $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon + + # is there a optical disk + $opticalDrive = Get-CimInstance -ClassName Win32_cdromdrive -Property Id + # what type of drive is attached to $driveletter + $volumeDriveType = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$DriveLetter'" -Property DriveType + + # check there is a optical disk + if ($opticalDrive) + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDiskDriveFound -f $opticaDrive.id) + ) -join '' ) + + if ($volumeDriveType.DriveType -eq 5) + { + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.DriveLetterVolumeType -f $driveletter, $volumeDriveType.DriveType) + ) -join '' ) + + } + else + { + + Write-Warning -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.DriveLetterExistsButNotOptical -f $driveletter) + ) -join '' ) + + } + + # return true if the drive letter is a optical disk resource + $result = [System.Boolean]($volumeDriveType.DriveType -eq 5) + + # return false if the drive letter specified is a optical disk resource & $Ensure -eq 'Absent' + if ($Ensure -eq 'Absent') + { + $result = -not $result + } + } + else + { + # return true if there is no optical disk - can't set what isn't there! + Write-Warning -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.NoOpticalDiskDrive) + ) -join '' ) + + $result = $false + } + + $result +} + +Export-ModuleMember -Function *-TargetResource + diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof new file mode 100644 index 00000000..44d2d208 --- /dev/null +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof @@ -0,0 +1,8 @@ + +[ClassVersion("1.0.0.0"), FriendlyName("xOpticalDiskDriveLetter")] +class MSFT_xOpticalDiskDriveLetter : OMI_BaseResource +{ + [Key, Description("Specifies the drive letter of the optical drive to modify.")] String DriveLetter; + [Write, Description("Determines whether the optical drive drive letter should be changed or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; +}; + diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md new file mode 100644 index 00000000..558d7b83 --- /dev/null +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md @@ -0,0 +1,17 @@ +# Description + +The resource is used to set the drive letter of an optical disk drive (e.g. a + CDROM or DVD drive). + +It is designed to ignore 'temporary' optical disk drives that are created when +mounting ISOs on Windows Server 2012+. + +With the Device ID, we look for the length of the string after the final +backslash (crude, but appears to work so far). + +Example: + # DeviceID for a virtual drive in a Hyper-V VM + SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\**000006** + + # DeviceID for a mounted ISO in a Hyper-V VM + SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\**2&1F4ADFFE&0&000002** diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 new file mode 100644 index 00000000..4e52c01d --- /dev/null +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 @@ -0,0 +1,12 @@ +ConvertFrom-StringData @' + UsingGetCimInstanceToFetchDriveLetter = Using Get-CimInstance to get the drive letter of optical disks in the system. + NoOpticalDiskDrive = Without an optical disk in the system, this resource has nothing to do. Note that this resource does not change the drive letter of mounted ISOs. + OpticalDriveSetAsRequested = Optical disk drive letter is currently set to {0} as requested. + OpticalDriveNotSetAsRequested = Optical disk drive letter is currently set to {0}, not {1} as requested. + + AttemptingToSetDriveLetter = The current drive letter is {0}, attempting to set to {1}. + + OpticalDiskDriveFound = Optical disk found with device id: {0}. + DriveLetterVolumeType = Volume with driveletter {0} is type '{1}' (type '5' is an optical disk). + DriveLetterExistsButNotOptical = Volume with driveletter {0} is already present but is not a optical disk. +'@ diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 new file mode 100644 index 00000000..a04c87ad --- /dev/null +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 @@ -0,0 +1,17 @@ +<# + .EXAMPLE + This configuration will set the drive letter of the optical disk drive to 'Z'. +#> +Configuration Example +{ + + Import-DSCResource -ModuleName xStorage + + Node localhost + { + xOpticalDiskDriveLetter MapOpticalDiskToZ + { + DriveLetter = "Z" + } + } +} diff --git a/README.md b/README.md index 4e4b1a39..588e95b2 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ The **xStorage** module contains the following resources: - **xDisk**: used to initialize, format and mount the partition as a drive letter. - **xDiskAccessPath**: used to initialize, format and mount the partition to a folder access path. +- **xOpticalDiskDriveLetter**: used to change the drive letter of an optical + disk drive (e.g. a CDROM or DVD drive). This resource ignores mounted ISOs. - **xWaitForDisk** wait for a disk to become available. - **xWaitForVolume** wait for a drive to be mounted and become available. diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 new file mode 100644 index 00000000..13dafc43 --- /dev/null +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 @@ -0,0 +1,93 @@ +$script:DSCModuleName = 'xStorage' +$script:DSCResourceName = 'MSFT_xOpticalDiskDriveLetter' + +Import-Module -Name (Join-Path -Path (Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'TestHelpers') -ChildPath 'CommonTestHelper.psm1') -Global + +#region HEADER +# Integration Test Template Version: 1.1.1 +[string] $script:moduleRoot = Join-Path -Path $(Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $Script:MyInvocation.MyCommand.Path))) -ChildPath 'Modules\xStorage' +if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) +{ + & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) +} + +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force +$TestEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:DSCModuleName ` + -DSCResourceName $script:DSCResourceName ` + -TestType Integration +#endregion + +# Using try/finally to always cleanup even if something awful happens. +try +{ + $LastDrive = ((Get-Volume).DriveLetter | Sort-Object | Select-Object -Last 1) + $DriveLetter = [char](([int][char]$LastDrive)+1) + + # Change drive letter of the optical drive + $ConfigFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DSCResourceName).config.ps1" + . $ConfigFile -Verbose -ErrorAction Stop + + Describe "$($script:DSCResourceName)_Integration" { + BeforeAll { + $currentDriveLetter = (Get-CimInstance -ClassName win32_cdromdrive | Where-Object { + -not ( + $_.Caption -eq "Microsoft Virtual DVD-ROM" -and + ($_.DeviceID.Split("\")[-1]).Length -gt 10 + ) + } + ).Drive + } + + Context 'Assign a Drive Letter to the optical drive' { + #region DEFAULT TESTS + + It 'Should compile and apply the MOF without throwing' { + { + # This is to pass to the Config + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + DriveLetter = $DriveLetter + } + ) + } + + & "$($script:DSCResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + #endregion + + if ($currentDriveLetter -eq $null) + { + Write-Verbose 'An optical drive is required to run the drive letter integration test. Mounted ISOs are ignored' + $skipTests = @{ Skip = $true } + } + + It 'Should have set the resource and all the parameters should match' @skipTests { + $current = Get-DscConfiguration | Where-Object { + $_.ConfigurationName -eq "$($script:DSCResourceName)_Config" + } + $current.DriveLetter | Should Be $DriveLetter + $current.Ensure | Should Be 'Present' + } + } + } + + #endregion +} +finally +{ + #region FOOTER + Restore-TestEnvironment -TestEnvironment $TestEnvironment + #endregion +} diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 new file mode 100644 index 00000000..e274668e --- /dev/null +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 @@ -0,0 +1,8 @@ +configuration MSFT_xOpticalDiskDriveLetter_config { + Import-DSCResource -ModuleName xStorage + node localhost { + xOpticalDiskDriveLetter Integration_Test { + DriveLetter = $Node.DriveLetter + } + } +} diff --git a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 new file mode 100644 index 00000000..ff9a32d2 --- /dev/null +++ b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 @@ -0,0 +1,470 @@ +$script:DSCModuleName = 'xStorage' +$script:DSCResourceName = 'MSFT_xOpticalDiskDriveLetter' + +Import-Module -Name (Join-Path -Path (Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'TestHelpers') -ChildPath 'CommonTestHelper.psm1') -Global + +#region HEADER +# Unit Test Template Version: 1.1.0 +[string] $script:moduleRoot = Join-Path -Path $(Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $Script:MyInvocation.MyCommand.Path))) -ChildPath 'Modules\xStorage' +if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) +{ + & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) +} + +Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force +$TestEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:DSCModuleName ` + -DSCResourceName $script:DSCResourceName ` + -TestType Unit +#endregion HEADER + +# Begin Testing +try +{ + #region Pester Tests + + # The InModuleScope command allows you to perform white-box unit testing on the internal + # (non-exported) code of a Script Module. + InModuleScope $script:DSCResourceName { + + $script:testDriveLetter = 'X:' + + $script:mockedNoOpticalDrive = $null + + $script:mockedOpticalDrive = [pscustomobject] @{ + Drive = $script:testDriveLetter + Caption = 'Microsoft Virtual DVD-ROM' + DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006' + Id = $script:testDriveLetter + } + + $script:mockedVolume = [pscustomobject] @{ + DriveLetter = $script:testDriveLetter + DriveType = 5 + } + + $script:mockedWrongLetterOpticalDrive = [pscustomobject] @{ + Drive = 'W:' + Caption = 'Microsoft Virtual DVD-ROM' + DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006' + } + + $script:mockedWrongVolume = [pscustomobject] @{ + DriveLetter = 'W:' + } + + $script:mockedVolumeNotOpticalDrive = [pscustomobject] @{ + DriveLetter = $script:testDriveLetter + DriveType = 3 + } + + $script:mockedOpticalDriveISO = [pscustomobject] @{ + Drive = 'I:' + Caption = 'Microsoft Virtual DVD-ROM' + DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002' + } + + $script:mockedOpticalDriveIDE = [pscustomobject] @{ + Drive = 'I:' + Caption = 'Msft Virtual CD/ROM ATA Device' + DeviceID = 'IDE\CDROMMSFT_VIRTUAL_CD/ROM_____________________1.0_____\5&CFB56DE&0&1.0.0' + } + + function Set-CimInstance { + Param + ( + [CmdletBinding()] + [Parameter(ValueFromPipeline)] + $InputObject, + + [hashtable] + $Property + ) + } + + #region Function Get-TargetResource + Describe 'MSFT_xOpticalDiskDriveLetter\Get-TargetResource' { + Context 'Optical disk drive present with correct drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDrive } ` + -Verifiable + + $resource = Get-TargetResource ` + -DriveLetter $script:testDriveLetter ` + -Verbose + + It "DriveLetter should be $($script:testDriveLetter)" { + $resource.DriveLetter | Should Be $script:testDriveLetter + } + + It 'all the get mocks should be called' { + Assert-VerifiableMocks + } + } + + Context 'Optical disk drive present with incorrect drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedWrongLetterOpticalDrive } ` + -Verifiable + + $resource = Get-TargetResource ` + -DriveLetter $script:testDriveLetter ` + -Verbose + + It "DriveLetter should be $($script:testDriveLetter)" { + $resource.DriveLetter | Should Not Be $script:testDriveLetter + } + + It 'all the get mocks should be called' { + Assert-VerifiableMocks + } + } + + + Context 'IDE optical disk drive present with incorrect drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDriveIDE } ` + -Verifiable + + $resource = Get-TargetResource ` + -DriveLetter $script:testDriveLetter ` + -Verbose + + It "DriveLetter should be $($script:testDriveLetter)" { + $resource.DriveLetter | Should Not Be $script:testDriveLetter + } + + It 'all the get mocks should be called' { + Assert-VerifiableMocks + } + } + + Context 'Optical disk drive not present' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedNoOpticalDrive } ` + -Verifiable + + $resource = Get-TargetResource ` + -DriveLetter $script:testDriveLetter ` + -Verbose + + It "DriveLetter should be null" { + $resource.DriveLetter | Should Be $null + } + + It 'all the get mocks should be called' { + Assert-VerifiableMocks + } + } + } + + #region Function Set-TargetResource + Describe 'MSFT_xOpticalDiskDriveLetter\Set-TargetResource' { + Context 'Optical disk drive with the correct drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDrive } ` + -Verifiable + + It 'Should not throw' { + { + Set-TargetResource ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should not throw + } + + It 'the correct mocks were called' { + Assert-VerifiableMocks + Assert-MockCalled -CommandName Get-CimInstance -Times 1 + } + } + + Context 'Optical disk drive with the correct drive letter when Ensure is set to Absent' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDrive } ` + -Verifiable + + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_volume" + } ` + -MockWith { $script:mockedVolume } ` + -Verifiable + + Mock ` + -CommandName Set-CimInstance ` + -MockWith { } ` + -Verifiable + + It 'Should not throw' { + { + Set-TargetResource ` + -Driveletter $script:testDriveLetter ` + -Ensure 'Absent' ` + -Verbose + } | Should not throw + } + + It 'the correct mocks were called' { + Assert-VerifiableMocks + Assert-MockCalled -CommandName Get-CimInstance -Times 1 + } + } + + Context 'Optical disk with the wrong drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedWrongLetterOpticalDrive } ` + -Verifiable + + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_volume" + } ` + -MockWith { $script:mockedWrongVolume } ` + -Verifiable + + Mock ` + -CommandName Set-CimInstance ` + -MockWith { } ` + -Verifiable + + It 'Should not throw' { + { + Set-TargetResource ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should not throw + } + + It 'the correct mocks were called' { + Assert-VerifiableMocks + Assert-MockCalled -CommandName Get-CimInstance -Times 2 + Assert-MockCalled -CommandName Set-CimInstance -Times 1 + } + } + + Context 'IDE optical disk drive with the wrong drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDriveide } ` + -Verifiable + + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_volume" + } ` + -MockWith { $script:mockedWrongVolume } ` + -Verifiable + + Mock ` + -CommandName Set-CimInstance ` + -MockWith { } ` + -Verifiable + + It 'Should not throw' { + { + Set-TargetResource ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should not throw + } + + It 'the correct mocks were called' { + Assert-VerifiableMocks + Assert-MockCalled -CommandName Get-CimInstance -Times 2 + Assert-MockCalled -CommandName Set-CimInstance -Times 1 + } + } + + # This resource does not change the drive letter of mounted ISO images. + Context 'Mounted ISO with the wrong drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDriveISO } ` + -Verifiable + + It 'Should not throw' { + { + Set-TargetResource ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should not throw + } + + It 'the correct mocks were called' { + Assert-VerifiableMocks + Assert-MockCalled -CommandName Get-CimInstance -Times 1 + } + } + } + + Describe 'MSFT_xOpticalDiskDriveLetter\Test-TargetResource' { + + Context 'Drive letter is a valid optical disk drive' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDrive } ` + -Verifiable + + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_volume" + } ` + -MockWith { $script:mockedVolume } ` + -Verifiable + + $resource = Test-TargetResource ` + -DriveLetter $script:testDriveLetter ` + -Verbose | Should Be $true + + It 'all the get mocks should be called' { + Assert-VerifiableMocks + } + } + + Context 'Drive letter is a valid optical disk drive and $Ensure is set to Absent' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDrive } ` + -Verifiable + + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_volume" + } ` + -MockWith { $script:mockedVolume } ` + -Verifiable + + $resource = Test-TargetResource ` + -DriveLetter $script:testDriveLetter ` + -Ensure 'Absent' ` + -Verbose | Should Be $false + + It 'all the get mocks should be called' { + Assert-VerifiableMocks + } + } + + Context 'There is no optical disk drive' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedNoOpticalDrive } ` + -Verifiable + + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_volume" + } ` + -MockWith { $script:mockedWrongVolume } ` + -Verifiable + + $resource = Test-TargetResource ` + -DriveLetter $script:testDriveLetter ` + -Ensure 'Present' ` + -Verbose | Should Be $false + + It 'all the get mocks should be called' { + Assert-VerifiableMocks + } + } + + Context 'The drive letter already exists on a volume that is not a optical disk drive' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_cdromdrive" + } ` + -MockWith { $script:mockedOpticalDrive } ` + -Verifiable + + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq "win32_volume" + } ` + -MockWith { $script:mockedVolumeNotOpticalDrive } ` + -Verifiable + + $resource = Test-TargetResource ` + -DriveLetter $script:testDriveLetter ` + -Ensure 'Present' ` + -Verbose | Should Be $false + + It 'all the get mocks should be called' { + Assert-VerifiableMocks + } + } + } + + #endregion + } +} +finally +{ + #region FOOTER + Restore-TestEnvironment -TestEnvironment $TestEnvironment + #endregion +} From 665075460a73949abd3ee8c92008fb0f51d441cb Mon Sep 17 00:00:00 2001 From: Stu Mace Date: Sun, 17 Dec 2017 09:42:05 +1300 Subject: [PATCH 02/45] updated CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97a3dfea..2df3573c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ - Added new contexts to integration tests improve clarity. - Fix bug when size not specified and disk partitioned and formatted but not assigned to path - See [Issue 103](https://github.com/PowerShell/xStorage/issues/103). +- xOpticalDiskDriveLetter: + - Added new resource. + - Added support for setting the drive letter of optical drives (CD/DVD drives). ## 3.3.0.0 From cd1d9467c61304afd3d72df2402eb4e666dc2874 Mon Sep 17 00:00:00 2001 From: Stu Mace Date: Sun, 17 Dec 2017 09:55:15 +1300 Subject: [PATCH 03/45] style - single quotes instead of double quotes --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index f1d618e2..685825e9 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -42,8 +42,8 @@ function Get-OpticalDiskDriveLetter #> $driveLetter = (Get-CimInstance -ClassName win32_cdromdrive | Where-Object { -not ( - $_.Caption -eq "Microsoft Virtual DVD-ROM" -and - ($_.DeviceID.Split("\")[-1]).Length -gt 10 + $_.Caption -eq 'Microsoft Virtual DVD-ROM' -and + ($_.DeviceID.Split('\')[-1]).Length -gt 10 ) } ).Drive From 76900700e8d8fa22eef4e00e04c19bc8208f742d Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Thu, 21 Dec 2017 20:50:58 +1100 Subject: [PATCH 04/45] Changes made as per recommendations from @PlagueHO in https://github.com/PowerShell/xStorage/pull/133 . Spacing changes and capitalization. --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 36 +++++++++---------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index 685825e9..f6fecfc7 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -23,7 +23,6 @@ $localizedData = Get-LocalizedData ` <# .SYNOPSIS This helper function returns the current drive letter assigned to the optical disk. - #> function Get-OpticalDiskDriveLetter { @@ -40,7 +39,7 @@ function Get-OpticalDiskDriveLetter Example DeviceID for a virtual drive in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006 Example DeviceID for a mounted ISO in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002 #> - $driveLetter = (Get-CimInstance -ClassName win32_cdromdrive | Where-Object { + $driveLetter = (Get-CimInstance -ClassName Win32_CDROMDrive | Where-Object { -not ( $_.Caption -eq 'Microsoft Virtual DVD-ROM' -and ($_.DeviceID.Split('\')[-1]).Length -gt 10 @@ -90,7 +89,8 @@ function Get-TargetResource $Ensure = 'Present' } - else { + else + { # check if $driveletter is the location of the optical disk if ($currentDriveLetter -eq $DriveLetter) { @@ -113,12 +113,10 @@ function Get-TargetResource } $returnValue = @{ - DriveLetter = $currentDriveLetter - Ensure = $Ensure - } - - $returnValue - + DriveLetter = $currentDriveLetter + Ensure = $Ensure + } + return $returnValue } # Get-TargetResource <# @@ -133,8 +131,7 @@ function Get-TargetResource #> function Set-TargetResource { - [CmdletBinding(SupportsShouldProcess=$True, - ConfirmImpact='Low')] + [CmdletBinding()] param ( # specify the drive letter as a single letter, optionally include the colon @@ -142,6 +139,7 @@ function Set-TargetResource [System.String] $DriveLetter, + [Parameter()] [ValidateSet('Present','Absent')] [System.String] $Ensure = 'Present' @@ -150,7 +148,6 @@ function Set-TargetResource # allow use of drive letter without colon $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon - $currentDriveLetter = Get-OpticalDiskDriveLetter if ($currentDriveLetter -eq $DriveLetter -and $Ensure -eq 'Present') @@ -178,6 +175,7 @@ function Set-TargetResource Set-CimInstance -Property @{ DriveLetter = $DriveLetter } } } + else { Write-Verbose -Message ( @( @@ -208,6 +206,7 @@ function Test-TargetResource [System.String] $DriveLetter, + [Parameter()] [ValidateSet('Present','Absent')] [System.String] $Ensure = 'Present' @@ -217,7 +216,8 @@ function Test-TargetResource $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon # is there a optical disk - $opticalDrive = Get-CimInstance -ClassName Win32_cdromdrive -Property Id + $opticalDrive = Get-CimInstance -ClassName Win32_CDROMDrive -Property Id + # what type of drive is attached to $driveletter $volumeDriveType = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$DriveLetter'" -Property DriveType @@ -236,7 +236,6 @@ function Test-TargetResource "$($MyInvocation.MyCommand): " $($localizedData.DriveLetterVolumeType -f $driveletter, $volumeDriveType.DriveType) ) -join '' ) - } else { @@ -245,7 +244,6 @@ function Test-TargetResource "$($MyInvocation.MyCommand): " $($localizedData.DriveLetterExistsButNotOptical -f $driveletter) ) -join '' ) - } # return true if the drive letter is a optical disk resource @@ -267,9 +265,7 @@ function Test-TargetResource $result = $false } - - $result + + return $result } - -Export-ModuleMember -Function *-TargetResource - +Export-ModuleMember -Function *-TargetResource \ No newline at end of file From 44e454369ad359a13ab49dc9548e0008e7446cc2 Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Thu, 21 Dec 2017 21:05:00 +1100 Subject: [PATCH 05/45] Set single quotes around Z as per @PlagueHO suggestion. https://github.com/PowerShell/xStorage/pull/133 --- .../1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 index a04c87ad..ce785d62 100644 --- a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 @@ -11,7 +11,7 @@ Configuration Example { xOpticalDiskDriveLetter MapOpticalDiskToZ { - DriveLetter = "Z" + DriveLetter = 'Z' } } } From 8de1744e7f7bd7bd0afe5c092cec184861aab129 Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Thu, 21 Dec 2017 21:08:11 +1100 Subject: [PATCH 06/45] Added -ErrorAction and -Message parameters as suggested by @PlagueHO. https://github.com/PowerShell/xStorage/pull/133 --- .../MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 index 13dafc43..864b5f5d 100644 --- a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 @@ -58,7 +58,7 @@ try & "$($script:DSCResourceName)_Config" ` -OutputPath $TestDrive ` -ConfigurationData $configData - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force + Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force -ErrorAction Stop } | Should -Not -Throw } @@ -69,7 +69,7 @@ try if ($currentDriveLetter -eq $null) { - Write-Verbose 'An optical drive is required to run the drive letter integration test. Mounted ISOs are ignored' + Write-Verbose -Message 'An optical drive is required to run the drive letter integration test. Mounted ISOs are ignored' $skipTests = @{ Skip = $true } } @@ -90,4 +90,4 @@ finally #region FOOTER Restore-TestEnvironment -TestEnvironment $TestEnvironment #endregion -} +} \ No newline at end of file From 8b009b4bd951c3ebb702951c3540877797e146e9 Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Thu, 21 Dec 2017 21:42:01 +1100 Subject: [PATCH 07/45] Capitilization, Pester V4 updates and some clean up of parameters as suggested by @PlagueHO. https://github.com/PowerShell/xStorage/pull/133 --- .../MSFT_xOpticalDiskDriveLetter.Tests.ps1 | 102 +++++++++--------- 1 file changed, 49 insertions(+), 53 deletions(-) diff --git a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 index ff9a32d2..74ece399 100644 --- a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 +++ b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 @@ -90,7 +90,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable @@ -100,10 +100,10 @@ try -Verbose It "DriveLetter should be $($script:testDriveLetter)" { - $resource.DriveLetter | Should Be $script:testDriveLetter + $resource.DriveLetter | Should -Be $script:testDriveLetter } - It 'all the get mocks should be called' { + It 'Should call all the Get mocks' { Assert-VerifiableMocks } } @@ -113,7 +113,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedWrongLetterOpticalDrive } ` -Verifiable @@ -123,21 +123,20 @@ try -Verbose It "DriveLetter should be $($script:testDriveLetter)" { - $resource.DriveLetter | Should Not Be $script:testDriveLetter + $resource.DriveLetter | Should -Not -Be $script:testDriveLetter } - It 'all the get mocks should be called' { + It 'Should call all the Get mocks' { Assert-VerifiableMocks } } - Context 'IDE optical disk drive present with incorrect drive letter' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDriveIDE } ` -Verifiable @@ -146,11 +145,11 @@ try -DriveLetter $script:testDriveLetter ` -Verbose - It "DriveLetter should be $($script:testDriveLetter)" { - $resource.DriveLetter | Should Not Be $script:testDriveLetter + It "Should be DriveLetter $($script:testDriveLetter)" { + $resource.DriveLetter | Should -Not -Be $script:testDriveLetter } - It 'all the get mocks should be called' { + It 'Should call all the Get mocks' { Assert-VerifiableMocks } } @@ -160,7 +159,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedNoOpticalDrive } ` -Verifiable @@ -170,14 +169,14 @@ try -Verbose It "DriveLetter should be null" { - $resource.DriveLetter | Should Be $null + $resource.DriveLetter | Should -Be $null } - It 'all the get mocks should be called' { + It 'Should call all the Get mocks' { Assert-VerifiableMocks } } - } + } #endregion #region Function Set-TargetResource Describe 'MSFT_xOpticalDiskDriveLetter\Set-TargetResource' { @@ -186,7 +185,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable @@ -196,10 +195,10 @@ try Set-TargetResource ` -Driveletter $script:testDriveLetter ` -Verbose - } | Should not throw + } | Should -Not -Throw } - It 'the correct mocks were called' { + It 'Should call the correct mocks' { Assert-VerifiableMocks Assert-MockCalled -CommandName Get-CimInstance -Times 1 } @@ -210,7 +209,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable @@ -218,14 +217,13 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_volume" + $ClassName -eq 'Win32_Volume' } ` -MockWith { $script:mockedVolume } ` -Verifiable Mock ` -CommandName Set-CimInstance ` - -MockWith { } ` -Verifiable It 'Should not throw' { @@ -234,10 +232,10 @@ try -Driveletter $script:testDriveLetter ` -Ensure 'Absent' ` -Verbose - } | Should not throw + } | Should -Not -Throw } - It 'the correct mocks were called' { + It 'Should call the correct mocks' { Assert-VerifiableMocks Assert-MockCalled -CommandName Get-CimInstance -Times 1 } @@ -248,7 +246,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedWrongLetterOpticalDrive } ` -Verifiable @@ -256,14 +254,13 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_volume" + $ClassName -eq 'Win32_Volume' } ` -MockWith { $script:mockedWrongVolume } ` -Verifiable Mock ` -CommandName Set-CimInstance ` - -MockWith { } ` -Verifiable It 'Should not throw' { @@ -271,10 +268,10 @@ try Set-TargetResource ` -Driveletter $script:testDriveLetter ` -Verbose - } | Should not throw + } | Should -Not -Throw } - It 'the correct mocks were called' { + It 'Should call the correct mocks' { Assert-VerifiableMocks Assert-MockCalled -CommandName Get-CimInstance -Times 2 Assert-MockCalled -CommandName Set-CimInstance -Times 1 @@ -286,7 +283,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDriveide } ` -Verifiable @@ -294,7 +291,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_volume" + $ClassName -eq 'Win32_Volume' } ` -MockWith { $script:mockedWrongVolume } ` -Verifiable @@ -309,10 +306,10 @@ try Set-TargetResource ` -Driveletter $script:testDriveLetter ` -Verbose - } | Should not throw + } | Should -Not -Throw } - It 'the correct mocks were called' { + It 'Should call the correct mocks' { Assert-VerifiableMocks Assert-MockCalled -CommandName Get-CimInstance -Times 2 Assert-MockCalled -CommandName Set-CimInstance -Times 1 @@ -325,7 +322,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDriveISO } ` -Verifiable @@ -335,24 +332,23 @@ try Set-TargetResource ` -Driveletter $script:testDriveLetter ` -Verbose - } | Should not throw + } | Should -Not -Throw } - It 'the correct mocks were called' { + It 'Should call the correct mocks' { Assert-VerifiableMocks Assert-MockCalled -CommandName Get-CimInstance -Times 1 } } - } + } #endregion Describe 'MSFT_xOpticalDiskDriveLetter\Test-TargetResource' { - Context 'Drive letter is a valid optical disk drive' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable @@ -360,16 +356,16 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_volume" + $ClassName -eq 'Win32_Volume' } ` -MockWith { $script:mockedVolume } ` -Verifiable $resource = Test-TargetResource ` -DriveLetter $script:testDriveLetter ` - -Verbose | Should Be $true + -Verbose | Should -Be $true - It 'all the get mocks should be called' { + It 'Should call all the Get mocks' { Assert-VerifiableMocks } } @@ -379,7 +375,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable @@ -387,7 +383,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_volume" + $ClassName -eq 'Win32_Volume' } ` -MockWith { $script:mockedVolume } ` -Verifiable @@ -395,9 +391,9 @@ try $resource = Test-TargetResource ` -DriveLetter $script:testDriveLetter ` -Ensure 'Absent' ` - -Verbose | Should Be $false + -Verbose | Should -Be $false - It 'all the get mocks should be called' { + It 'Should call all the Get mocks' { Assert-VerifiableMocks } } @@ -407,7 +403,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedNoOpticalDrive } ` -Verifiable @@ -415,7 +411,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_volume" + $ClassName -eq 'Win32_Volume' } ` -MockWith { $script:mockedWrongVolume } ` -Verifiable @@ -423,9 +419,9 @@ try $resource = Test-TargetResource ` -DriveLetter $script:testDriveLetter ` -Ensure 'Present' ` - -Verbose | Should Be $false + -Verbose | Should -Be $false - It 'all the get mocks should be called' { + It 'Should call all the Get mocks' { Assert-VerifiableMocks } } @@ -435,7 +431,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_cdromdrive" + $ClassName -eq 'Win32_CDROMDrive' } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable @@ -443,7 +439,7 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq "win32_volume" + $ClassName -eq 'Win32_Volume' } ` -MockWith { $script:mockedVolumeNotOpticalDrive } ` -Verifiable @@ -451,9 +447,9 @@ try $resource = Test-TargetResource ` -DriveLetter $script:testDriveLetter ` -Ensure 'Present' ` - -Verbose | Should Be $false + -Verbose | Should -Be $false - It 'all the get mocks should be called' { + It 'Should call all the Get mocks' { Assert-VerifiableMocks } } From 8d164acc02ca355ea3686846ed9c2eb77f354f91 Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Fri, 22 Dec 2017 17:39:56 +1100 Subject: [PATCH 08/45] Added a new line at the end of MSFT_xOpticalDiskDriveLetter.psm1 as it failed the AppVeyor test. --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index f6fecfc7..5ded7ccb 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -268,4 +268,4 @@ function Test-TargetResource return $result } -Export-ModuleMember -Function *-TargetResource \ No newline at end of file +Export-ModuleMember -Function *-TargetResource From 3ba24a91ab52af3c5172a9f20fcee66525e4576c Mon Sep 17 00:00:00 2001 From: Stu Mace Date: Sat, 23 Dec 2017 12:25:06 +1300 Subject: [PATCH 09/45] attempting to fix merge conflict --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3606aa47..f34f8dd0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,10 @@ - Added new contexts to integration tests improve clarity. - Fix bug when size not specified and disk partitioned and formatted but not assigned to path - See [Issue 103](https://github.com/PowerShell/xStorage/issues/103). +- Updated tests to meet Pester V4 guidelines - fixes [Issue #120](https://github.com/PowerShell/xStorage/issues/120). - xOpticalDiskDriveLetter: - Added new resource. - Added support for setting the drive letter of optical drives (CD/DVD drives). -- Updated tests to meet Pester V4 guidelines - fixes [Issue #120](https://github.com/PowerShell/xStorage/issues/120). ## 3.3.0.0 From e3e1a39a64bd4a46610a9ad7867d5f9b87386af7 Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Sat, 30 Dec 2017 14:13:22 +1100 Subject: [PATCH 10/45] Updates as per @PlagueHO comments. https://github.com/PowerShell/xStorage/pull/133. HAVE NOT INCLUDED Why not move this assignment = True --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index 5ded7ccb..0bea140f 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -171,11 +171,11 @@ function Set-TargetResource { $DriveLetter = $null } + Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$currentDriveLetter'" | Set-CimInstance -Property @{ DriveLetter = $DriveLetter } } } - else { Write-Verbose -Message ( @( From 96658137984a7fad9ebc1fd37f1d4f9a76bb80da Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Sat, 30 Dec 2017 14:15:12 +1100 Subject: [PATCH 11/45] Updates as per @PlagueHO comments. https://github.com/PowerShell/xStorage/pull/133. Addition of CRLF. --- .../MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 index 864b5f5d..a9c762be 100644 --- a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 @@ -90,4 +90,4 @@ finally #region FOOTER Restore-TestEnvironment -TestEnvironment $TestEnvironment #endregion -} \ No newline at end of file +} From 813d41c93edc7b26f8bc5b89f9626cdde230d66c Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Sat, 30 Dec 2017 14:16:30 +1100 Subject: [PATCH 12/45] Updates as per @PlagueHO comments. https://github.com/PowerShell/xStorage/pull/133. End region(s) on next line and -MockWith{} removed. --- Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 index 74ece399..8f35fe80 100644 --- a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 +++ b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 @@ -176,7 +176,8 @@ try Assert-VerifiableMocks } } - } #endregion + } + #endregion #region Function Set-TargetResource Describe 'MSFT_xOpticalDiskDriveLetter\Set-TargetResource' { @@ -298,7 +299,6 @@ try Mock ` -CommandName Set-CimInstance ` - -MockWith { } ` -Verifiable It 'Should not throw' { @@ -340,7 +340,8 @@ try Assert-MockCalled -CommandName Get-CimInstance -Times 1 } } - } #endregion + } + #endregion Describe 'MSFT_xOpticalDiskDriveLetter\Test-TargetResource' { Context 'Drive letter is a valid optical disk drive' { From 04fe89b35aa1697d7bf987ab21c38a4e5911bcdc Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Sat, 6 Jan 2018 13:23:16 +1300 Subject: [PATCH 13/45] Moved entry for new xOpticalDiskDriveLetter resource into Unreleased section --- CHANGELOG.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f34f8dd0..a0a8fe5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +- xOpticalDiskDriveLetter: + - Added new resource. + - Added support for setting the drive letter of optical drives (CD/DVD drives). + ## 3.4.0.0 - xDisk: @@ -14,9 +18,6 @@ - Fix bug when size not specified and disk partitioned and formatted but not assigned to path - See [Issue 103](https://github.com/PowerShell/xStorage/issues/103). - Updated tests to meet Pester V4 guidelines - fixes [Issue #120](https://github.com/PowerShell/xStorage/issues/120). -- xOpticalDiskDriveLetter: - - Added new resource. - - Added support for setting the drive letter of optical drives (CD/DVD drives). ## 3.3.0.0 From 7faf0b837ad66c70375674c8526165e2616c6be1 Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Sat, 6 Jan 2018 21:59:07 +1300 Subject: [PATCH 14/45] Refactored xOpticalDiskDriveLetter to be IsSingleInstance --- CHANGELOG.md | 3 + .../MSFT_xOpticalDiskDriveLetter.psm1 | 175 ++++++---- .../MSFT_xOpticalDiskDriveLetter.schema.mof | 3 +- ...xOpticalDiskDriveLetter_SetDriveLetter.ps1 | 3 +- ...ticalDiskDriveLetter.Integration.Tests.ps1 | 48 +-- .../MSFT_xOpticalDiskDriveLetter.config.ps1 | 3 +- .../MSFT_xOpticalDiskDriveLetter.Tests.ps1 | 325 +++++++++++------- 7 files changed, 329 insertions(+), 231 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a0a8fe5e..ddbfeda0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ - xOpticalDiskDriveLetter: - Added new resource. - Added support for setting the drive letter of optical drives (CD/DVD drives). + - Converted to be single instance pattern. + - Removed ShouldProcess from `Set-TargetResource`. + - Optimized `Test-TargetResource` to reduce code duplication. ## 3.4.0.0 diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index 0bea140f..5d36312f 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -7,13 +7,13 @@ $modulePath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot # Import the Storage Common Modules Import-Module -Name (Join-Path -Path $modulePath ` - -ChildPath (Join-Path -Path 'StorageDsc.Common' ` - -ChildPath 'StorageDsc.Common.psm1')) + -ChildPath (Join-Path -Path 'StorageDsc.Common' ` + -ChildPath 'StorageDsc.Common.psm1')) # Import the Storage Resource Helper Module Import-Module -Name (Join-Path -Path $modulePath ` - -ChildPath (Join-Path -Path 'StorageDsc.ResourceHelper' ` - -ChildPath 'StorageDsc.ResourceHelper.psm1')) + -ChildPath (Join-Path -Path 'StorageDsc.ResourceHelper' ` + -ChildPath 'StorageDsc.ResourceHelper.psm1')) # Import Localization Strings $localizedData = Get-LocalizedData ` @@ -40,12 +40,12 @@ function Get-OpticalDiskDriveLetter Example DeviceID for a mounted ISO in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002 #> $driveLetter = (Get-CimInstance -ClassName Win32_CDROMDrive | Where-Object { - -not ( + -not ( $_.Caption -eq 'Microsoft Virtual DVD-ROM' -and ($_.DeviceID.Split('\')[-1]).Length -gt 10 ) } - ).Drive + ).Drive return $driveLetter } @@ -54,9 +54,12 @@ function Get-OpticalDiskDriveLetter .SYNOPSIS Returns the current drive letter assigned to the optical disk. - .PARAMETER DriveLetter - Specifies the preferred letter to assign to the optical disk. + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. + .PARAMETER DriveLetter + Specifies the drive letter to assign to the optical disk. Can be a + single letter, optionally followed by a colon. #> function Get-TargetResource { @@ -64,58 +67,64 @@ function Get-TargetResource [OutputType([System.Collections.Hashtable])] param ( - # specify the drive letter as a single letter, optionally include the colon + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance, + [Parameter(Mandatory = $true)] [System.String] $DriveLetter ) - # allow use of drive letter without colon + # Allow use of drive letter without colon $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.UsingGetCimInstanceToFetchDriveLetter) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.UsingGetCimInstanceToFetchDriveLetter) + ) -join '' ) $currentDriveLetter = Get-OpticalDiskDriveLetter if (-not $currentDriveLetter) { Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.NoOpticalDiskDrive) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.NoOpticalDiskDrive) + ) -join '' ) $Ensure = 'Present' } - else + else { - # check if $driveletter is the location of the optical disk + # Check if $driveletter is the location of the optical disk if ($currentDriveLetter -eq $DriveLetter) { Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.OpticalDriveSetAsRequested -f $DriveLetter) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDriveSetAsRequested -f $DriveLetter) + ) -join '' ) $Ensure = 'Present' } else { Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.OpticalDriveNotSetAsRequested -f $currentDriveLetter,$DriveLetter) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDriveNotSetAsRequested -f $currentDriveLetter, $DriveLetter) + ) -join '' ) $Ensure = 'Absent' } } $returnValue = @{ - DriveLetter = $currentDriveLetter - Ensure = $Ensure - } + IsSingleInstance = 'Yes' + DriveLetter = $currentDriveLetter + Ensure = $Ensure + } + return $returnValue } # Get-TargetResource @@ -123,8 +132,12 @@ function Get-TargetResource .SYNOPSIS Sets the drive letter of the optical disk. + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. + .PARAMETER DriveLetter - Specifies the drive letter to assign to the optical disk. + Specifies the drive letter to assign to the optical disk. Can be a + single letter, optionally followed by a colon. .PARAMETER Ensure Determines whether the setting should be applied or removed. @@ -134,18 +147,22 @@ function Set-TargetResource [CmdletBinding()] param ( - # specify the drive letter as a single letter, optionally include the colon + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance, + [Parameter(Mandatory = $true)] [System.String] $DriveLetter, [Parameter()] - [ValidateSet('Present','Absent')] + [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present' ) - # allow use of drive letter without colon + # Allow use of drive letter without colon $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon $currentDriveLetter = Get-OpticalDiskDriveLetter @@ -155,33 +172,29 @@ function Set-TargetResource return } - # assuming a drive letter is found + # Assuming a drive letter is found if ($currentDriveLetter) { Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.AttemptingToSetDriveLetter -f $currentDriveLetter,$DriveLetter) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.AttemptingToSetDriveLetter -f $currentDriveLetter, $DriveLetter) + ) -join '' ) - if ($PSCmdlet.ShouldProcess("Setting optical disk letter to $DriveLetter")) + # If $Ensure -eq Absent this will remove the drive letter from the optical disk + if ($Ensure -eq 'Absent') { - - # if $Ensure -eq Absent this will remove the drive letter from the optical disk - if ($Ensure -eq 'Absent') - { - $DriveLetter = $null - } - - Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$currentDriveLetter'" | - Set-CimInstance -Property @{ DriveLetter = $DriveLetter } + $DriveLetter = $null } + + Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$currentDriveLetter'" | + Set-CimInstance -Property @{ DriveLetter = $DriveLetter } } else { Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.NoOpticalDiskDrive) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.NoOpticalDiskDrive) + ) -join '' ) } } # Set-TargetResource @@ -189,8 +202,12 @@ function Set-TargetResource .SYNOPSIS Tests the optical disk letter is set as expected + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. + .PARAMETER DriveLetter - Specifies the drive letter to test if it is assigned to the optical disk. + Specifies the drive letter to assign to the optical disk. Can be a + single letter, optionally followed by a colon. .PARAMETER Ensure Determines whether the setting should be applied or removed. @@ -201,55 +218,62 @@ function Test-TargetResource [OutputType([System.Boolean])] param ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance, + # specify the drive letter as a single letter, optionally include the colon [Parameter(Mandatory = $true)] [System.String] $DriveLetter, [Parameter()] - [ValidateSet('Present','Absent')] + [ValidateSet('Present', 'Absent')] [System.String] $Ensure = 'Present' ) - # allow use of drive letter without colon + # Allow use of drive letter without colon $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon - # is there a optical disk + # Is there a optical disk? $opticalDrive = Get-CimInstance -ClassName Win32_CDROMDrive -Property Id - # what type of drive is attached to $driveletter - $volumeDriveType = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$DriveLetter'" -Property DriveType + # What type of drive is attached to $driveletter + $volumeDriveType = Get-CimInstance ` + -ClassName Win32_Volume ` + -Filter "DriveLetter = '$DriveLetter'" ` + -Property DriveType - # check there is a optical disk + # Check there is a optical disk if ($opticalDrive) { Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.OpticalDiskDriveFound -f $opticaDrive.id) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDiskDriveFound -f $opticaDrive.id) + ) -join '' ) if ($volumeDriveType.DriveType -eq 5) { - Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.DriveLetterVolumeType -f $driveletter, $volumeDriveType.DriveType) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.DriveLetterVolumeType -f $driveletter, $volumeDriveType.DriveType) + ) -join '' ) + + $result = $true } else { - Write-Warning -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.DriveLetterExistsButNotOptical -f $driveletter) - ) -join '' ) - } + "$($MyInvocation.MyCommand): " + $($localizedData.DriveLetterExistsButNotOptical -f $driveletter) + ) -join '' ) - # return true if the drive letter is a optical disk resource - $result = [System.Boolean]($volumeDriveType.DriveType -eq 5) + $result = $false + } - # return false if the drive letter specified is a optical disk resource & $Ensure -eq 'Absent' + # Return false if the drive letter specified is a optical disk resource & $Ensure -eq 'Absent' if ($Ensure -eq 'Absent') { $result = -not $result @@ -257,15 +281,16 @@ function Test-TargetResource } else { - # return true if there is no optical disk - can't set what isn't there! + # Return false if there is no optical disk - can't set what isn't there! Write-Warning -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.NoOpticalDiskDrive) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.NoOpticalDiskDrive) + ) -join '' ) $result = $false } - + return $result } + Export-ModuleMember -Function *-TargetResource diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof index 44d2d208..8ddcc56a 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof @@ -2,7 +2,8 @@ [ClassVersion("1.0.0.0"), FriendlyName("xOpticalDiskDriveLetter")] class MSFT_xOpticalDiskDriveLetter : OMI_BaseResource { - [Key, Description("Specifies the drive letter of the optical drive to modify.")] String DriveLetter; + [Key, Description("Specifies the resource is a single instance, the value must be 'Yes'."), ValueMap{"Yes"}, Values{"Yes"}] String IsSingleInstance; + [Required, Description(" Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon.")] String DriveLetter; [Write, Description("Determines whether the optical drive drive letter should be changed or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; }; diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 index ce785d62..e90863e3 100644 --- a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 @@ -11,7 +11,8 @@ Configuration Example { xOpticalDiskDriveLetter MapOpticalDiskToZ { - DriveLetter = 'Z' + IsSingleInstance = 'Yes' + DriveLetter = 'Z' } } } diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 index a9c762be..2a79706c 100644 --- a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 @@ -1,5 +1,5 @@ -$script:DSCModuleName = 'xStorage' -$script:DSCResourceName = 'MSFT_xOpticalDiskDriveLetter' +$script:DSCModuleName = 'xStorage' +$script:DSCResourceName = 'MSFT_xOpticalDiskDriveLetter' Import-Module -Name (Join-Path -Path (Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'TestHelpers') -ChildPath 'CommonTestHelper.psm1') -Global @@ -7,9 +7,9 @@ Import-Module -Name (Join-Path -Path (Join-Path -Path (Split-Path $PSScriptRoot # Integration Test Template Version: 1.1.1 [string] $script:moduleRoot = Join-Path -Path $(Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $Script:MyInvocation.MyCommand.Path))) -ChildPath 'Modules\xStorage' if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` - (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { - & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) + & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) } Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force @@ -23,7 +23,7 @@ $TestEnvironment = Initialize-TestEnvironment ` try { $LastDrive = ((Get-Volume).DriveLetter | Sort-Object | Select-Object -Last 1) - $DriveLetter = [char](([int][char]$LastDrive)+1) + $DriveLetter = [char](([int][char]$LastDrive) + 1) # Change drive letter of the optical drive $ConfigFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DSCResourceName).config.ps1" @@ -32,17 +32,15 @@ try Describe "$($script:DSCResourceName)_Integration" { BeforeAll { $currentDriveLetter = (Get-CimInstance -ClassName win32_cdromdrive | Where-Object { - -not ( - $_.Caption -eq "Microsoft Virtual DVD-ROM" -and - ($_.DeviceID.Split("\")[-1]).Length -gt 10 - ) - } - ).Drive + -not ( + $_.Caption -eq "Microsoft Virtual DVD-ROM" -and + ($_.DeviceID.Split("\")[-1]).Length -gt 10 + ) + } + ).Drive } Context 'Assign a Drive Letter to the optical drive' { - #region DEFAULT TESTS - It 'Should compile and apply the MOF without throwing' { { # This is to pass to the Config @@ -58,32 +56,38 @@ try & "$($script:DSCResourceName)_Config" ` -OutputPath $TestDrive ` -ConfigurationData $configData - Start-DscConfiguration -Path $TestDrive -ComputerName localhost -Wait -Verbose -Force -ErrorAction Stop + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop } | Should -Not -Throw } It 'Should be able to call Get-DscConfiguration without throwing' { { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw } - #endregion + $skipTests = @{} if ($currentDriveLetter -eq $null) { - Write-Verbose -Message 'An optical drive is required to run the drive letter integration test. Mounted ISOs are ignored' - $skipTests = @{ Skip = $true } + Write-Verbose -Message 'An optical drive is required to run the drive letter integration test. Mounted ISOs are ignored.' + $skipTests = @{ + Skip = $true + } } It 'Should have set the resource and all the parameters should match' @skipTests { - $current = Get-DscConfiguration | Where-Object { + $current = Get-DscConfiguration | Where-Object -FilterScript { $_.ConfigurationName -eq "$($script:DSCResourceName)_Config" } - $current.DriveLetter | Should Be $DriveLetter - $current.Ensure | Should Be 'Present' + $current.DriveLetter | Should -Be "$($DriveLetter):" + $current.Ensure | Should -Be 'Present' } } } - - #endregion } finally { diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 index e274668e..84ca5f47 100644 --- a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 @@ -2,7 +2,8 @@ configuration MSFT_xOpticalDiskDriveLetter_config { Import-DSCResource -ModuleName xStorage node localhost { xOpticalDiskDriveLetter Integration_Test { - DriveLetter = $Node.DriveLetter + IsSingleInstance = 'Yes' + DriveLetter = $Node.DriveLetter } } } diff --git a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 index 8f35fe80..b40f3606 100644 --- a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 +++ b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 @@ -1,5 +1,5 @@ -$script:DSCModuleName = 'xStorage' -$script:DSCResourceName = 'MSFT_xOpticalDiskDriveLetter' +$script:DSCModuleName = 'xStorage' +$script:DSCResourceName = 'MSFT_xOpticalDiskDriveLetter' Import-Module -Name (Join-Path -Path (Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'TestHelpers') -ChildPath 'CommonTestHelper.psm1') -Global @@ -7,9 +7,9 @@ Import-Module -Name (Join-Path -Path (Join-Path -Path (Split-Path $PSScriptRoot # Unit Test Template Version: 1.1.0 [string] $script:moduleRoot = Join-Path -Path $(Split-Path -Parent (Split-Path -Parent (Split-Path -Parent $Script:MyInvocation.MyCommand.Path))) -ChildPath 'Modules\xStorage' if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` - (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) { - & git @('clone','https://github.com/PowerShell/DscResource.Tests.git',(Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) + & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath '\DSCResource.Tests\')) } Import-Module (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1') -Force @@ -27,57 +27,59 @@ try # The InModuleScope command allows you to perform white-box unit testing on the internal # (non-exported) code of a Script Module. InModuleScope $script:DSCResourceName { - $script:testDriveLetter = 'X:' $script:mockedNoOpticalDrive = $null - $script:mockedOpticalDrive = [pscustomobject] @{ - Drive = $script:testDriveLetter - Caption = 'Microsoft Virtual DVD-ROM' - DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006' - Id = $script:testDriveLetter - } + $script:mockedOpticalDrive = [pscustomobject] @{ + Drive = $script:testDriveLetter + Caption = 'Microsoft Virtual DVD-ROM' + DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006' + Id = $script:testDriveLetter + } $script:mockedVolume = [pscustomobject] @{ - DriveLetter = $script:testDriveLetter - DriveType = 5 - } + DriveLetter = $script:testDriveLetter + DriveType = 5 + } $script:mockedWrongLetterOpticalDrive = [pscustomobject] @{ - Drive = 'W:' - Caption = 'Microsoft Virtual DVD-ROM' - DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006' - } + Drive = 'W:' + Caption = 'Microsoft Virtual DVD-ROM' + DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006' + } $script:mockedWrongVolume = [pscustomobject] @{ - DriveLetter = 'W:' - } + IsSingleInstance = 'Yes' + DriveLetter = 'W:' + } $script:mockedVolumeNotOpticalDrive = [pscustomobject] @{ - DriveLetter = $script:testDriveLetter - DriveType = 3 - } + DriveLetter = $script:testDriveLetter + DriveType = 3 + } $script:mockedOpticalDriveISO = [pscustomobject] @{ - Drive = 'I:' - Caption = 'Microsoft Virtual DVD-ROM' - DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002' - } + Drive = 'I:' + Caption = 'Microsoft Virtual DVD-ROM' + DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002' + } $script:mockedOpticalDriveIDE = [pscustomobject] @{ - Drive = 'I:' - Caption = 'Msft Virtual CD/ROM ATA Device' - DeviceID = 'IDE\CDROMMSFT_VIRTUAL_CD/ROM_____________________1.0_____\5&CFB56DE&0&1.0.0' - } + Drive = 'I:' + Caption = 'Msft Virtual CD/ROM ATA Device' + DeviceID = 'IDE\CDROMMSFT_VIRTUAL_CD/ROM_____________________1.0_____\5&CFB56DE&0&1.0.0' + } - function Set-CimInstance { + function Set-CimInstance + { Param ( [CmdletBinding()] [Parameter(ValueFromPipeline)] $InputObject, + [Parameter()] [hashtable] $Property ) @@ -90,21 +92,26 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable - $resource = Get-TargetResource ` - -DriveLetter $script:testDriveLetter ` - -Verbose + It 'Should not throw an exception' { + { + $script:result = Get-TargetResource ` + -IsSingleInstance 'Yes' ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } It "DriveLetter should be $($script:testDriveLetter)" { - $resource.DriveLetter | Should -Be $script:testDriveLetter + $script:result.DriveLetter | Should -Be $script:testDriveLetter } It 'Should call all the Get mocks' { - Assert-VerifiableMocks + Assert-VerifiableMock } } @@ -113,21 +120,26 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedWrongLetterOpticalDrive } ` -Verifiable - $resource = Get-TargetResource ` - -DriveLetter $script:testDriveLetter ` - -Verbose + It 'Should not throw an exception' { + { + $script:result = Get-TargetResource ` + -IsSingleInstance 'Yes' ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } It "DriveLetter should be $($script:testDriveLetter)" { - $resource.DriveLetter | Should -Not -Be $script:testDriveLetter + $script:result.DriveLetter | Should -Not -Be $script:testDriveLetter } It 'Should call all the Get mocks' { - Assert-VerifiableMocks + Assert-VerifiableMock } } @@ -136,21 +148,26 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDriveIDE } ` -Verifiable - $resource = Get-TargetResource ` - -DriveLetter $script:testDriveLetter ` - -Verbose + It 'Should not throw an exception' { + { + $script:result = Get-TargetResource ` + -IsSingleInstance 'Yes' ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } It "Should be DriveLetter $($script:testDriveLetter)" { - $resource.DriveLetter | Should -Not -Be $script:testDriveLetter + $script:result.DriveLetter | Should -Not -Be $script:testDriveLetter } It 'Should call all the Get mocks' { - Assert-VerifiableMocks + Assert-VerifiableMock } } @@ -159,24 +176,29 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedNoOpticalDrive } ` -Verifiable - $resource = Get-TargetResource ` - -DriveLetter $script:testDriveLetter ` - -Verbose + It 'Should not throw an exception' { + { + $script:result = Get-TargetResource ` + -IsSingleInstance 'Yes' ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } - It "DriveLetter should be null" { - $resource.DriveLetter | Should -Be $null + It 'DriveLetter should be null' { + $script:result.DriveLetter | Should -Be $null } It 'Should call all the Get mocks' { - Assert-VerifiableMocks + Assert-VerifiableMock } } - } + } #endregion #region Function Set-TargetResource @@ -186,22 +208,23 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable - It 'Should not throw' { + It 'Should not throw an exception' { { Set-TargetResource ` + -IsSingleInstance 'Yes' ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw } It 'Should call the correct mocks' { - Assert-VerifiableMocks - Assert-MockCalled -CommandName Get-CimInstance -Times 1 + Assert-VerifiableMock + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 } } @@ -210,16 +233,16 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_Volume' - } ` + $ClassName -eq 'Win32_Volume' + } ` -MockWith { $script:mockedVolume } ` -Verifiable @@ -227,9 +250,10 @@ try -CommandName Set-CimInstance ` -Verifiable - It 'Should not throw' { + It 'Should not throw an exception' { { Set-TargetResource ` + -IsSingleInstance 'Yes' ` -Driveletter $script:testDriveLetter ` -Ensure 'Absent' ` -Verbose @@ -237,8 +261,8 @@ try } It 'Should call the correct mocks' { - Assert-VerifiableMocks - Assert-MockCalled -CommandName Get-CimInstance -Times 1 + Assert-VerifiableMock + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 2 } } @@ -247,16 +271,16 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedWrongLetterOpticalDrive } ` -Verifiable Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_Volume' - } ` + $ClassName -eq 'Win32_Volume' + } ` -MockWith { $script:mockedWrongVolume } ` -Verifiable @@ -264,18 +288,19 @@ try -CommandName Set-CimInstance ` -Verifiable - It 'Should not throw' { + It 'Should not throw an exception' { { Set-TargetResource ` + -IsSingleInstance 'Yes' ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw } It 'Should call the correct mocks' { - Assert-VerifiableMocks - Assert-MockCalled -CommandName Get-CimInstance -Times 2 - Assert-MockCalled -CommandName Set-CimInstance -Times 1 + Assert-VerifiableMock + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 2 + Assert-MockCalled -CommandName Set-CimInstance -Exactly -Times 1 } } @@ -284,16 +309,16 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDriveide } ` -Verifiable Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_Volume' - } ` + $ClassName -eq 'Win32_Volume' + } ` -MockWith { $script:mockedWrongVolume } ` -Verifiable @@ -301,18 +326,19 @@ try -CommandName Set-CimInstance ` -Verifiable - It 'Should not throw' { + It 'Should not throw an exception' { { Set-TargetResource ` + -IsSingleInstance 'Yes' ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw } It 'Should call the correct mocks' { - Assert-VerifiableMocks - Assert-MockCalled -CommandName Get-CimInstance -Times 2 - Assert-MockCalled -CommandName Set-CimInstance -Times 1 + Assert-VerifiableMock + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 2 + Assert-MockCalled -CommandName Set-CimInstance -Exactly -Times 1 } } @@ -322,25 +348,26 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDriveISO } ` -Verifiable - It 'Should not throw' { + It 'Should not throw an exception' { { Set-TargetResource ` + -IsSingleInstance 'Yes' ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw } It 'Should call the correct mocks' { - Assert-VerifiableMocks - Assert-MockCalled -CommandName Get-CimInstance -Times 1 + Assert-VerifiableMock + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 } } - } + } #endregion Describe 'MSFT_xOpticalDiskDriveLetter\Test-TargetResource' { @@ -349,25 +376,34 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_Volume' - } ` + $ClassName -eq 'Win32_Volume' + } ` -MockWith { $script:mockedVolume } ` -Verifiable - $resource = Test-TargetResource ` - -DriveLetter $script:testDriveLetter ` - -Verbose | Should -Be $true + It 'Should not throw an exception' { + { + $script:result = Test-TargetResource ` + -IsSingleInstance 'Yes' ` + -DriveLetter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } + + It 'Should return $true' { + $script:result | Should -Be $true + } It 'Should call all the Get mocks' { - Assert-VerifiableMocks + Assert-VerifiableMock } } @@ -376,26 +412,35 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_Volume' - } ` + $ClassName -eq 'Win32_Volume' + } ` -MockWith { $script:mockedVolume } ` -Verifiable - $resource = Test-TargetResource ` - -DriveLetter $script:testDriveLetter ` - -Ensure 'Absent' ` - -Verbose | Should -Be $false + It 'Should not throw an exception' { + { + $script:result = Test-TargetResource ` + -IsSingleInstance 'Yes' ` + -DriveLetter $script:testDriveLetter ` + -Ensure 'Absent' ` + -Verbose + } | Should -Not -Throw + } + + It 'Should return $false' { + $script:result | Should -Be $false + } It 'Should call all the Get mocks' { - Assert-VerifiableMocks + Assert-VerifiableMock } } @@ -404,26 +449,35 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedNoOpticalDrive } ` -Verifiable Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_Volume' - } ` + $ClassName -eq 'Win32_Volume' + } ` -MockWith { $script:mockedWrongVolume } ` -Verifiable - $resource = Test-TargetResource ` - -DriveLetter $script:testDriveLetter ` - -Ensure 'Present' ` - -Verbose | Should -Be $false + It 'Should not throw an exception' { + { + $script:result = Test-TargetResource ` + -IsSingleInstance 'Yes' ` + -DriveLetter $script:testDriveLetter ` + -Ensure 'Present' ` + -Verbose + } | Should -Not -Throw + } + + It 'Should return $false' { + $script:result | Should -Be $false + } It 'Should call all the Get mocks' { - Assert-VerifiableMocks + Assert-VerifiableMock } } @@ -432,26 +486,35 @@ try Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_CDROMDrive' - } ` + $ClassName -eq 'Win32_CDROMDrive' + } ` -MockWith { $script:mockedOpticalDrive } ` -Verifiable Mock ` -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_Volume' - } ` + $ClassName -eq 'Win32_Volume' + } ` -MockWith { $script:mockedVolumeNotOpticalDrive } ` -Verifiable - $resource = Test-TargetResource ` - -DriveLetter $script:testDriveLetter ` - -Ensure 'Present' ` - -Verbose | Should -Be $false + It 'Should not throw an exception' { + { + $script:result = Test-TargetResource ` + -IsSingleInstance 'Yes' ` + -DriveLetter $script:testDriveLetter ` + -Ensure 'Present' ` + -Verbose + } | Should -Not -Throw + } + + It 'Should return $false' { + $script:result | Should -Be $false + } It 'Should call all the Get mocks' { - Assert-VerifiableMocks + Assert-VerifiableMock } } } From a5a246e064aeb9096bef1b33839646139d40a089 Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Sat, 6 Jan 2018 22:13:04 +1300 Subject: [PATCH 15/45] Minor comment and layout tweaks to xOpticalDiskDriveLetter --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 6 +++--- .../MSFT_xOpticalDiskDriveLetter.schema.mof | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index 5d36312f..a72c2615 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -237,7 +237,7 @@ function Test-TargetResource # Allow use of drive letter without colon $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon - # Is there a optical disk? + # Is there an optical disk? $opticalDrive = Get-CimInstance -ClassName Win32_CDROMDrive -Property Id # What type of drive is attached to $driveletter @@ -246,7 +246,7 @@ function Test-TargetResource -Filter "DriveLetter = '$DriveLetter'" ` -Property DriveType - # Check there is a optical disk + # Check there is an optical disk if ($opticalDrive) { Write-Verbose -Message ( @( @@ -273,7 +273,7 @@ function Test-TargetResource $result = $false } - # Return false if the drive letter specified is a optical disk resource & $Ensure -eq 'Absent' + # Return false if the drive letter specified is an optical disk resource & $Ensure -eq 'Absent' if ($Ensure -eq 'Absent') { $result = -not $result diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof index 8ddcc56a..12414b8e 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof @@ -3,7 +3,7 @@ class MSFT_xOpticalDiskDriveLetter : OMI_BaseResource { [Key, Description("Specifies the resource is a single instance, the value must be 'Yes'."), ValueMap{"Yes"}, Values{"Yes"}] String IsSingleInstance; - [Required, Description(" Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon.")] String DriveLetter; + [Required, Description("Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon.")] String DriveLetter; [Write, Description("Determines whether the optical drive drive letter should be changed or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; }; From f748352d06ea212f1276ccf48d8893104e35e78c Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Mon, 8 Jan 2018 21:15:53 +1300 Subject: [PATCH 16/45] Refactored resource to handle systems with multiple optical disks. --- CHANGELOG.md | 3 +- .../MSFT_xOpticalDiskDriveLetter.psm1 | 327 ++++++++------ .../MSFT_xOpticalDiskDriveLetter.schema.mof | 6 +- .../MSFT_xOpticalDiskDriveLetter/README.md | 10 +- .../MSFT_xOpticalDiskDriveLetter.strings.psd1 | 19 +- ...ticalDiskDriveLetter_RemoveDriveLetter.ps1 | 20 + ...xOpticalDiskDriveLetter_SetDriveLetter.ps1 | 9 +- .../StorageDsc.Common/StorageDsc.Common.psm1 | 10 +- ...MSFT_xMountImage_ISO.Integration.Tests.ps1 | 2 +- ...ticalDiskDriveLetter.Integration.Tests.ps1 | 133 +++++- .../MSFT_xOpticalDiskDriveLetter.config.ps1 | 17 +- .../MSFT_xOpticalDiskDriveLetter.Tests.ps1 | 418 ++++++++++++++---- 12 files changed, 715 insertions(+), 259 deletions(-) create mode 100644 Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index ddbfeda0..dec7b6c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,8 @@ - xOpticalDiskDriveLetter: - Added new resource. - Added support for setting the drive letter of optical drives (CD/DVD drives). - - Converted to be single instance pattern. - Removed ShouldProcess from `Set-TargetResource`. - - Optimized `Test-TargetResource` to reduce code duplication. + - Refactored resource to handle systems with multiple optical disks. ## 3.4.0.0 diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index a72c2615..f90fa18a 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -22,7 +22,33 @@ $localizedData = Get-LocalizedData ` <# .SYNOPSIS - This helper function returns the current drive letter assigned to the optical disk. + This helper function returns the current drive letter assigned + to the a disk number disk found in the system. + + If the drive exists but is not mounted to a drive letter then + it will return an empty string. + + If there are no optical disks found in the system, return null. + + .PARAMETER DiskId + Specifies the optical disk number for the disk to return the drive + letter of. + + .PARAMETER ReturnDeviceIdOnNoDriveLetter + This switch will cause the Drive Letter to be returned with the + default value that Drive is set to when no Drive Letter is assigned + e.g. 'Volume{bba1802b-e7a1-11e3-824e-806e6f6e6963}'. + + Otherwise the Drive Letter will be empty + + .NOTES + The Caption and DeviceID properties are checked to avoid + mounted ISO images in Windows 2012+ and Windows 10. The + device ID is required because a CD/DVD in a Hyper-V virtual + machine has the same caption as a mounted ISO. + + Example DeviceID for a virtual drive in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006 + Example DeviceID for a mounted ISO in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002 #> function Get-OpticalDiskDriveLetter { @@ -30,22 +56,74 @@ function Get-OpticalDiskDriveLetter [OutputType([System.String])] param ( + [Parameter(Mandatory = $true)] + [System.Int32] + $DiskId, + + [Parameter()] + [Switch] + $ReturnDeviceIdOnNoDriveLetter ) - <# - The Caption and DeviceID properties are checked to avoid mounted ISO images in Windows 2012+ and Windows 10. - The device ID is required because a CD/DVD in a Hyper-V virtual machine has the same caption as a mounted ISO. - - Example DeviceID for a virtual drive in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006 - Example DeviceID for a mounted ISO in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002 - #> - $driveLetter = (Get-CimInstance -ClassName Win32_CDROMDrive | Where-Object { - -not ( - $_.Caption -eq 'Microsoft Virtual DVD-ROM' -and - ($_.DeviceID.Split('\')[-1]).Length -gt 10 - ) + $driveLetter = $null + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.UsingGetCimInstanceToFetchDriveLetter -f $DiskId) + ) -join '' ) + + # Get the optical disk matching the Id + $opticalDisks = Get-CimInstance -ClassName Win32_CDROMDrive | + Where-Object -FilterScript { + -not ( + $_.Caption -eq 'Microsoft Virtual DVD-ROM' -and + ($_.DeviceID.Split('\')[-1]).Length -gt 10 + ) + } + + if ($opticalDisks) + { + $opticalDisk = $opticalDisks[$DiskId - 1] + + if ($opticalDisk) + { + try + { + # Make sure the current DriveLetter is an actual drive letter + $driveLetter = Assert-DriveLetterValid -DriveLetter $opticalDisk.Drive -Colon + } + catch + { + # Optical drive exists but is not mounted to a drive letter + if ($ReturnDeviceIdOnNoDriveLetter) + { + $driveLetter = $opticalDisk.Drive + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDiskAssignedDriveLetter -f $DiskId, $driveLetter) + ) -join '' ) + } + else + { + $driveLetter = '' + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDiskNotAssignedDriveLetter -f $DiskId) + ) -join '' ) + + } + } } - ).Drive + } + + if ($null -eq $driveLetter) + { + New-InvalidArgumentException ` + -Message ($localizedData.NoOpticalDiskDriveError -f $DiskId) ` + -ArgumentName 'DiskId' + } return $driveLetter } @@ -54,8 +132,9 @@ function Get-OpticalDiskDriveLetter .SYNOPSIS Returns the current drive letter assigned to the optical disk. - .PARAMETER IsSingleInstance - Specifies the resource is a single instance, the value must be 'Yes'. + .PARAMETER DiskId + Specifies the optical disk number for the disk to assign the drive + letter to. .PARAMETER DriveLetter Specifies the drive letter to assign to the optical disk. Can be a @@ -68,61 +147,40 @@ function Get-TargetResource param ( [Parameter(Mandatory = $true)] - [ValidateSet('Yes')] - [System.String] - $IsSingleInstance, + [System.Int32] + $DiskId, [Parameter(Mandatory = $true)] [System.String] $DriveLetter ) - # Allow use of drive letter without colon - $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon + $ensure = 'Absent' - Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.UsingGetCimInstanceToFetchDriveLetter) - ) -join '' ) - - $currentDriveLetter = Get-OpticalDiskDriveLetter + # Get the drive letter assigned to the optical disk + $currentDriveLetter = Get-OpticalDiskDriveLetter -DiskId $DiskId - if (-not $currentDriveLetter) + if ([System.String]::IsNullOrWhiteSpace($currentDriveLetter)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " - $($localizedData.NoOpticalDiskDrive) + $($localizedData.OpticalDiskNotAssignedDriveLetter -f $DiskId) ) -join '' ) - - $Ensure = 'Present' } else { - # Check if $driveletter is the location of the optical disk - if ($currentDriveLetter -eq $DriveLetter) - { - Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.OpticalDriveSetAsRequested -f $DriveLetter) - ) -join '' ) - - $Ensure = 'Present' - } - else - { - Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.OpticalDriveNotSetAsRequested -f $currentDriveLetter, $DriveLetter) - ) -join '' ) + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDiskAssignedDriveLetter -f $DiskId, $DriveLetter) + ) -join '' ) - $Ensure = 'Absent' - } + $Ensure = 'Present' } - $returnValue = @{ - IsSingleInstance = 'Yes' - DriveLetter = $currentDriveLetter - Ensure = $Ensure + $returnValue += @{ + DiskId = $DiskId + DriveLetter = $currentDriveLetter + Ensure = $ensure } return $returnValue @@ -130,17 +188,19 @@ function Get-TargetResource <# .SYNOPSIS - Sets the drive letter of the optical disk. + Sets the drive letter of an optical disk. - .PARAMETER IsSingleInstance - Specifies the resource is a single instance, the value must be 'Yes'. + .PARAMETER DiskId + Specifies the optical disk number for the disk to assign the drive + letter to. .PARAMETER DriveLetter Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon. .PARAMETER Ensure - Determines whether the setting should be applied or removed. + Determines whether a drive letter should be assigned to the + optical disk. Defaults to 'Present'. #> function Set-TargetResource { @@ -148,9 +208,8 @@ function Set-TargetResource param ( [Parameter(Mandatory = $true)] - [ValidateSet('Yes')] - [System.String] - $IsSingleInstance, + [System.Int32] + $DiskId, [Parameter(Mandatory = $true)] [System.String] @@ -165,52 +224,65 @@ function Set-TargetResource # Allow use of drive letter without colon $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon - $currentDriveLetter = Get-OpticalDiskDriveLetter + # Get the drive letter assigned to the optical disk + $currentDriveLetter = Get-OpticalDiskDriveLetter -DiskId $DiskId - if ($currentDriveLetter -eq $DriveLetter -and $Ensure -eq 'Present') + if ([System.String]::IsNullOrWhiteSpace($currentDriveLetter)) { - return + <# + If the current drive letter is empty then the volume must be looked up by DeviceId + The DeviceId in the volume will show as \\?\Volume{bba1802b-e7a1-11e3-824e-806e6f6e6963}\ + So we need to change the currentDriveLetter to match this value when we set the drive letter + #> + $deviceId = Get-OpticalDiskDriveLetter -DiskId $DiskId -ReturnDeviceIdOnNoDriveLetter + + $volume = Get-CimInstance ` + -ClassName Win32_Volume ` + -Filter "DeviceId = '\\\\?\\$deviceId\\'" + } + else + { + $volume = Get-CimInstance ` + -ClassName Win32_Volume ` + -Filter "DriveLetter = '$currentDriveLetter'" } - # Assuming a drive letter is found - if ($currentDriveLetter) + # Does the Drive Letter need to be added or removed + if ($Ensure -eq 'Absent') { Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.AttemptingToSetDriveLetter -f $currentDriveLetter, $DriveLetter) - ) -join '' ) - - # If $Ensure -eq Absent this will remove the drive letter from the optical disk - if ($Ensure -eq 'Absent') - { - $DriveLetter = $null - } + "$($MyInvocation.MyCommand): " + $($localizedData.AttemptingToRemoveDriveLetter -f $diskId, $currentDriveLetter) + ) -join '' ) - Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$currentDriveLetter'" | - Set-CimInstance -Property @{ DriveLetter = $DriveLetter } + $volume | Set-CimInstance -Property @{ DriveLetter = $null } } else { Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.NoOpticalDiskDrive) - ) -join '' ) + "$($MyInvocation.MyCommand): " + $($localizedData.AttemptingToSetDriveLetter -f $diskId, $currentDriveLetter, $DriveLetter) + ) -join '' ) + + $volume | Set-CimInstance -Property @{ DriveLetter = $DriveLetter } } } # Set-TargetResource <# .SYNOPSIS - Tests the optical disk letter is set as expected + Tests the disk letter assigned to an optical disk is correct. - .PARAMETER IsSingleInstance - Specifies the resource is a single instance, the value must be 'Yes'. + .PARAMETER DiskId + Specifies the optical disk number for the disk to assign the drive + letter to. .PARAMETER DriveLetter Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon. .PARAMETER Ensure - Determines whether the setting should be applied or removed. + Determines whether a drive letter should be assigned to the + optical disk. Defaults to 'Present'. #> function Test-TargetResource { @@ -219,11 +291,9 @@ function Test-TargetResource param ( [Parameter(Mandatory = $true)] - [ValidateSet('Yes')] - [System.String] - $IsSingleInstance, + [System.Int32] + $DiskId, - # specify the drive letter as a single letter, optionally include the colon [Parameter(Mandatory = $true)] [System.String] $DriveLetter, @@ -234,63 +304,74 @@ function Test-TargetResource $Ensure = 'Present' ) + $desiredConfigurationMatch = $true + # Allow use of drive letter without colon $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon - # Is there an optical disk? - $opticalDrive = Get-CimInstance -ClassName Win32_CDROMDrive -Property Id + # Get the drive letter assigned to the optical disk + $currentDriveLetter = Get-OpticalDiskDriveLetter -DiskId $DiskId - # What type of drive is attached to $driveletter - $volumeDriveType = Get-CimInstance ` - -ClassName Win32_Volume ` - -Filter "DriveLetter = '$DriveLetter'" ` - -Property DriveType - - # Check there is an optical disk - if ($opticalDrive) + if ($Ensure -eq 'Absent') { - Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.OpticalDiskDriveFound -f $opticaDrive.id) - ) -join '' ) - - if ($volumeDriveType.DriveType -eq 5) + # The Drive Letter should be absent from the optical disk + if ([System.String]::IsNullOrWhiteSpace($currentDriveLetter)) { Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " - $($localizedData.DriveLetterVolumeType -f $driveletter, $volumeDriveType.DriveType) + $($localizedData.DriveLetterDoesNotExistAndShouldNot -f $DiskId) ) -join '' ) - - $result = $true } else { - Write-Warning -Message ( @( + # The Drive Letter needs to be dismounted + Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " - $($localizedData.DriveLetterExistsButNotOptical -f $driveletter) + $($localizedData.DriveLetterExistsButShouldNot -f $DiskId, $currentDriveLetter) ) -join '' ) - $result = $false - } - - # Return false if the drive letter specified is an optical disk resource & $Ensure -eq 'Absent' - if ($Ensure -eq 'Absent') - { - $result = -not $result + $desiredConfigurationMatch = $false } } else { - # Return false if there is no optical disk - can't set what isn't there! - Write-Warning -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.NoOpticalDiskDrive) - ) -join '' ) - - $result = $false + if ($currentDriveLetter -eq $DriveLetter) + { + # The optical disk drive letter is already set correctly + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.DriverLetterExistsAndIsCorrect -f $DiskId, $DriveLetter) + ) -join '' ) + } + else + { + # Is a desired drive letter already assigned to a different drive? + $existingVolume = Get-CimInstance ` + -ClassName Win32_Volume ` + -Filter "DriveLetter = '$DriveLetter'" + + if ($existingVolume) + { + # The desired drive letter is already assigned to another drive - can't proceed + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.DriveLetterAssignedToAnotherDrive -f $DriveLetter) + ) -join '' ) + } + else + { + # The optical drive letter needs to be changed + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.DriverLetterExistsAndIsNotCorrect -f $DiskId, $currentDriveLetter, $DriveLetter) + ) -join '' ) + + $desiredConfigurationMatch = $false + } + } } - return $result + return $desiredConfigurationMatch } Export-ModuleMember -Function *-TargetResource diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof index 12414b8e..255835b1 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof @@ -2,8 +2,8 @@ [ClassVersion("1.0.0.0"), FriendlyName("xOpticalDiskDriveLetter")] class MSFT_xOpticalDiskDriveLetter : OMI_BaseResource { - [Key, Description("Specifies the resource is a single instance, the value must be 'Yes'."), ValueMap{"Yes"}, Values{"Yes"}] String IsSingleInstance; - [Required, Description("Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon.")] String DriveLetter; - [Write, Description("Determines whether the optical drive drive letter should be changed or not."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Key, Description("Specifies the optical disk number for the disk to assign the drive letter to.")] String DiskId; + [Write, Description("Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon.")] String DriveLetter; + [Write, Description("Determines whether a drive letter should be assigned to the optical disk. Defaults to 'Present'."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; }; diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md index 558d7b83..2a867073 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md @@ -1,9 +1,13 @@ # Description -The resource is used to set the drive letter of an optical disk drive (e.g. a - CDROM or DVD drive). +The resource is used to set the drive letter of an optical disk drive (e.g. +a CDROM or DVD drive). -It is designed to ignore 'temporary' optical disk drives that are created when +It can be used to set the drive letter of a specific optical disk drive if +there are multiple in the system by specifying a value greater than 1 for +the `DiskId` parameter. + +It is designed to ignore _temporary_ optical disk drives that are created when mounting ISOs on Windows Server 2012+. With the Device ID, we look for the length of the string after the final diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 index 4e52c01d..0760466b 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 @@ -1,12 +1,15 @@ ConvertFrom-StringData @' - UsingGetCimInstanceToFetchDriveLetter = Using Get-CimInstance to get the drive letter of optical disks in the system. - NoOpticalDiskDrive = Without an optical disk in the system, this resource has nothing to do. Note that this resource does not change the drive letter of mounted ISOs. - OpticalDriveSetAsRequested = Optical disk drive letter is currently set to {0} as requested. - OpticalDriveNotSetAsRequested = Optical disk drive letter is currently set to {0}, not {1} as requested. + UsingGetCimInstanceToFetchDriveLetter = Using Get-CimInstance to get the drive letter of optical disk {0} in the system. + OpticalDiskAssignedDriveLetter = The optical disk {0} is currently assigned drive letter '{1}'. + OpticalDiskNotAssignedDriveLetter = The optical disk {0} is not currently assigned a drive letter. + NoOpticalDiskDriveError = The optical disk {0} could not be found in the system, so this resource has nothing to do. This resource does not change the drive letter of mounted ISOs. - AttemptingToSetDriveLetter = The current drive letter is {0}, attempting to set to {1}. + AttemptingToSetDriveLetter = The optical disk {0} drive letter is '{1}', attempting to set to '{2}'. + AttemptingToRemoveDriveLetter = The optical disk {0} drive letter is '{1}', attempting to remove it. - OpticalDiskDriveFound = Optical disk found with device id: {0}. - DriveLetterVolumeType = Volume with driveletter {0} is type '{1}' (type '5' is an optical disk). - DriveLetterExistsButNotOptical = Volume with driveletter {0} is already present but is not a optical disk. + DriveLetterDoesNotExistAndShouldNot = The optical disk {0} does not have a drive letter assigned. Change not required. + DriveLetterExistsButShouldNot = The optical disk {0} is assigned the drive letter '{1}' which should be removed. Change required. + DriverLetterExistsAndIsCorrect = The optical disk {0} is assigned the drive letter '{1}' which is correct. Change not required. + DriveLetterAssignedToAnotherDrive = Drive letter '{0}' is already present but assigned to a another volume. Change can not proceed. + DriverLetterExistsAndIsNotCorrect = The optical disk {0} is assigned the drive letter '{1}' but should be '{2}'. Change required. '@ diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 new file mode 100644 index 00000000..10e8d23b --- /dev/null +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 @@ -0,0 +1,20 @@ +<# + .EXAMPLE + This configuration will remove the drive letter of the first + optical disk drive. +#> +Configuration Example +{ + + Import-DSCResource -ModuleName xStorage + + Node localhost + { + xOpticalDiskDriveLetter RemoveFirstOpticalDiskDriveLetter + { + DiskId = 1 + DriveLetter = 'X' # This value is ignored + Ensure = 'Absent' + } + } +} diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 index e90863e3..94bc5e70 100644 --- a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 @@ -1,6 +1,7 @@ <# .EXAMPLE - This configuration will set the drive letter of the optical disk drive to 'Z'. + This configuration will set the drive letter of the first + optical disk drive in the system to 'Z'. #> Configuration Example { @@ -9,10 +10,10 @@ Configuration Example Node localhost { - xOpticalDiskDriveLetter MapOpticalDiskToZ + xOpticalDiskDriveLetter SetFirstOpticalDiskDriveLetterToZ { - IsSingleInstance = 'Yes' - DriveLetter = 'Z' + DiskId = 1 + DriveLetter = 'Z' } } } diff --git a/Modules/xStorage/Modules/StorageDsc.Common/StorageDsc.Common.psm1 b/Modules/xStorage/Modules/StorageDsc.Common/StorageDsc.Common.psm1 index 0addded6..bf77ee7b 100644 --- a/Modules/xStorage/Modules/StorageDsc.Common/StorageDsc.Common.psm1 +++ b/Modules/xStorage/Modules/StorageDsc.Common/StorageDsc.Common.psm1 @@ -33,20 +33,24 @@ function Assert-DriveLetterValid $Colon ) - $Matches = @([regex]::matches($DriveLetter, '^([A-Za-z]):?$', 'IgnoreCase')) - if (-not $Matches) + $matches = @([regex]::matches($DriveLetter, '^([A-Za-z]):?$', 'IgnoreCase')) + + if (-not $matches) { # DriveLetter format is invalid New-InvalidArgumentException ` -Message $($LocalizedData.InvalidDriveLetterFormatError -f $DriveLetter) ` -ArgumentName 'DriveLetter' } + # This is the drive letter without a colon - $DriveLetter = $Matches.Groups[1].Value + $DriveLetter = $matches.Groups[1].Value + if ($Colon) { $DriveLetter = $DriveLetter + ':' } # if + return $DriveLetter } # end function Assert-DriveLetterValid diff --git a/Tests/Integration/MSFT_xMountImage_ISO.Integration.Tests.ps1 b/Tests/Integration/MSFT_xMountImage_ISO.Integration.Tests.ps1 index a540be4e..0cf0044e 100644 --- a/Tests/Integration/MSFT_xMountImage_ISO.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xMountImage_ISO.Integration.Tests.ps1 @@ -35,7 +35,7 @@ try if (-not (Test-Path -Path $ISOPath)) { Write-Verbose -Message "$($script:DSCResourceName) integration tests cannot be run because the ISO File '$ISOPath' is not available." -Verbose - Return + return } # if # Get a spare drive letter diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 index 2a79706c..e5c76d90 100644 --- a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 @@ -22,25 +22,79 @@ $TestEnvironment = Initialize-TestEnvironment ` # Using try/finally to always cleanup even if something awful happens. try { - $LastDrive = ((Get-Volume).DriveLetter | Sort-Object | Select-Object -Last 1) - $DriveLetter = [char](([int][char]$LastDrive) + 1) + $opticalDisk = Get-CimInstance -ClassName Win32_CDROMDrive | + Where-Object -FilterScript { + -not ( + $_.Caption -eq "Microsoft Virtual DVD-ROM" -and + ($_.DeviceID.Split("\")[-1]).Length -gt 10 + ) + }[0] + + if (-not $opticalDisk) + { + Write-Verbose -Message "$($script:DSCResourceName) integration tests cannot be run because there is no optical disk in the system." -Verbose + return + } + + $currentDriveLetter = $opticalDisk.Drive + $volume = Get-CimInstance -ClassName Win32_Volume -Filter "DriveLetter = '$currentDriveLetter'" + + $lastDrive = ((Get-Volume).DriveLetter | Sort-Object | Select-Object -Last 1) + $driveLetter = [char](([int][char]$lastDrive) + 1) # Change drive letter of the optical drive $ConfigFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DSCResourceName).config.ps1" . $ConfigFile -Verbose -ErrorAction Stop Describe "$($script:DSCResourceName)_Integration" { - BeforeAll { - $currentDriveLetter = (Get-CimInstance -ClassName win32_cdromdrive | Where-Object { - -not ( - $_.Caption -eq "Microsoft Virtual DVD-ROM" -and - ($_.DeviceID.Split("\")[-1]).Length -gt 10 - ) + # Dismount the optical disk from a drive letter + $volume | Set-CimInstance -Property @{ DriveLetter = $null } + + Context 'Assign a Drive Letter to an optical drive that is not mounted' { + It 'Should compile and apply the MOF without throwing' { + { + # This is to pass to the Config + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + DiskId = 1 + DriveLetter = $driveLetter + Ensure = 'Present' + } + ) + } + + & "$($script:DSCResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:DSCResourceName)_Config" } - ).Drive + $current.DiskId | Should -Be 1 + $current.DriveLetter | Should -Be "$($driveLetter):" + } } - Context 'Assign a Drive Letter to the optical drive' { + $driveLetter = [char](([int][char]$lastDrive) + 2) + + Context 'Assign a Drive Letter to an optical drive that is already mounted' { It 'Should compile and apply the MOF without throwing' { { # This is to pass to the Config @@ -48,7 +102,9 @@ try AllNodes = @( @{ NodeName = 'localhost' - DriveLetter = $DriveLetter + DiskId = 1 + DriveLetter = $driveLetter + Ensure = 'Present' } ) } @@ -56,6 +112,7 @@ try & "$($script:DSCResourceName)_Config" ` -OutputPath $TestDrive ` -ConfigurationData $configData + Start-DscConfiguration ` -Path $TestDrive ` -ComputerName localhost ` @@ -70,21 +127,54 @@ try { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw } - $skipTests = @{} - if ($currentDriveLetter -eq $null) - { - Write-Verbose -Message 'An optical drive is required to run the drive letter integration test. Mounted ISOs are ignored.' - $skipTests = @{ - Skip = $true + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:DSCResourceName)_Config" } + $current.DiskId | Should -Be 1 + $current.DriveLetter | Should -Be "$($driveLetter):" + } + } + + Context 'Remove a Drive Letter from an optical drive that is already mounted' { + It 'Should compile and apply the MOF without throwing' { + { + # This is to pass to the Config + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + DiskId = 1 + DriveLetter = 'X' + Ensure = 'Absent' + } + ) + } + + & "$($script:DSCResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw } - It 'Should have set the resource and all the parameters should match' @skipTests { + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { $current = Get-DscConfiguration | Where-Object -FilterScript { $_.ConfigurationName -eq "$($script:DSCResourceName)_Config" } - $current.DriveLetter | Should -Be "$($DriveLetter):" - $current.Ensure | Should -Be 'Present' + $current.DiskId | Should -Be 1 + $current.DriveLetter | Should -Be '' } } } @@ -93,5 +183,8 @@ finally { #region FOOTER Restore-TestEnvironment -TestEnvironment $TestEnvironment + + # Mount the optical disk back to where it was + $volume | Set-CimInstance -Property @{ DriveLetter = $currentDriveLetter } #endregion } diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 index 84ca5f47..f8766d30 100644 --- a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 @@ -1,9 +1,20 @@ configuration MSFT_xOpticalDiskDriveLetter_config { Import-DSCResource -ModuleName xStorage node localhost { - xOpticalDiskDriveLetter Integration_Test { - IsSingleInstance = 'Yes' - DriveLetter = $Node.DriveLetter + if ($Node.Ensure) + { + xOpticalDiskDriveLetter Integration_Test { + DiskId = $Node.DiskId + DriveLetter = $Node.DriveLetter + Ensure = $Node.Ensure + } + } + else + { + xOpticalDiskDriveLetter Integration_Test { + DiskId = $Node.DiskId + DriveLetter = $Node.DriveLetter + } } } } diff --git a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 index b40f3606..94791c32 100644 --- a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 +++ b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 @@ -28,6 +28,8 @@ try # (non-exported) code of a Script Module. InModuleScope $script:DSCResourceName { $script:testDriveLetter = 'X:' + $script:testDriveLetterNoVolume = 'Volume{47b90a5d-f340-11e7-80fd-806e6f6e6963}' + $script:testVolumeDeviceId = '"\\?\$($script:testDriveLetterNoVolume)\"' $script:mockedNoOpticalDrive = $null @@ -38,37 +40,51 @@ try Id = $script:testDriveLetter } - $script:mockedVolume = [pscustomobject] @{ - DriveLetter = $script:testDriveLetter - DriveType = 5 + $script:mockedOpticalDriveNoDriveLetter = [pscustomobject] @{ + Drive = $script:testDriveLetterNoVolume + Caption = 'Microsoft Virtual DVD-ROM' + DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006' + Id = $script:testDriveLetterNoVolume } + $script:mockedOpticalDriveMultiDisks = @( + $script:mockedOpticalDriveNoDriveLetter + $script:mockedOpticalDrive + ) + $script:mockedWrongLetterOpticalDrive = [pscustomobject] @{ Drive = 'W:' Caption = 'Microsoft Virtual DVD-ROM' DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006' - } - - $script:mockedWrongVolume = [pscustomobject] @{ - IsSingleInstance = 'Yes' - DriveLetter = 'W:' - } - - $script:mockedVolumeNotOpticalDrive = [pscustomobject] @{ - DriveLetter = $script:testDriveLetter - DriveType = 3 + Id = 'W:' } $script:mockedOpticalDriveISO = [pscustomobject] @{ Drive = 'I:' Caption = 'Microsoft Virtual DVD-ROM' DeviceID = 'SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002' + Id = 'I:' } $script:mockedOpticalDriveIDE = [pscustomobject] @{ Drive = 'I:' Caption = 'Msft Virtual CD/ROM ATA Device' DeviceID = 'IDE\CDROMMSFT_VIRTUAL_CD/ROM_____________________1.0_____\5&CFB56DE&0&1.0.0' + Id = 'I:' + } + + $script:mockedVolume = [pscustomobject] @{ + DriveLetter = $script:testDriveLetter + DriveType = 5 + DeviceId = '\\?\Volume{bba1802b-e7a1-11e3-824e-806e6f6e6963}\' + Id = $script:testDriveLetter + } + + $script:mockedWrongVolume = [pscustomobject] @{ + DriveLetter = 'W:' + DriveType = 5 + DeviceId = $script:testVolumeDeviceId + Id = 'W:' } function Set-CimInstance @@ -85,6 +101,156 @@ try ) } + #region Function Get-TargetResource + Describe 'MSFT_xOpticalDiskDriveLetter\Get-OpticalDiskDriveLetter' { + Context 'Single optical disk drive present and assigned a drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq 'Win32_CDROMDrive' + } ` + -MockWith { + $script:mockedOpticalDrive + } ` + -Verifiable + + It 'Should not throw an exception' { + { + $script:result = Get-TargetResource ` + -DiskId 1 ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } + + It "DriveLetter should be $($script:testDriveLetter)" { + $script:result.DriveLetter | Should -Be $script:testDriveLetter + } + + It 'Should call all the Get mocks' { + Assert-VerifiableMock + } + } + + Context 'Single optical disk drive present and not assiged a drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq 'Win32_CDROMDrive' + } ` + -MockWith { + $script:mockedOpticalDriveNoDriveLetter + } ` + -Verifiable + + It 'Should not throw an exception' { + { + $script:result = Get-TargetResource ` + -DiskId 1 ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } + + It "DriveLetter should be empty" { + $script:result.DriveLetter | Should -Be '' + } + + It 'Should call all the Get mocks' { + Assert-VerifiableMock + } + } + + Context 'Multiple optical disk drives present and second one is assigned a drive letter' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq 'Win32_CDROMDrive' + } ` + -MockWith { + $script:mockedOpticalDriveMultiDisks + } ` + -Verifiable + + It 'Should not throw an exception' { + { + $script:result = Get-TargetResource ` + -DiskId 2 ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Not -Throw + } + + It "DriveLetter should be $($script:testDriveLetter)" { + $script:result.DriveLetter | Should -Be $script:testDriveLetter + } + + It 'Should call all the Get mocks' { + Assert-VerifiableMock + } + } + + Context 'Single optical disk drive present but second disk is requested' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq 'Win32_CDROMDrive' + } ` + -MockWith { + $script:mockedOpticalDrive + } ` + -Verifiable + + $errorRecord = Get-InvalidArgumentRecord ` + -Message ($LocalizedData.NoOpticalDiskDriveError -f 2) ` + -ArgumentName 'DiskId' + + It 'Should throw expected exception' { + { + $script:result = Get-TargetResource ` + -DiskId 2 ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Throw $errorRecord + } + + It 'Should call all the Get mocks' { + Assert-VerifiableMock + } + } + + Context 'Single optical disk drive present but is mounted with ISO' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq 'Win32_CDROMDrive' + } ` + -MockWith { + $script:mockedOpticalDriveISO + } ` + -Verifiable + + It 'Should throw expected exception' { + { + $script:result = Get-TargetResource ` + -DiskId 1 ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Throw $errorRecord + } + + It 'Should call all the Get mocks' { + Assert-VerifiableMock + } + } + } + #endregion + #region Function Get-TargetResource Describe 'MSFT_xOpticalDiskDriveLetter\Get-TargetResource' { Context 'Optical disk drive present with correct drive letter' { @@ -94,13 +260,15 @@ try -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDrive } ` + -MockWith { + $script:mockedOpticalDrive + } ` -Verifiable It 'Should not throw an exception' { { $script:result = Get-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw @@ -108,6 +276,7 @@ try It "DriveLetter should be $($script:testDriveLetter)" { $script:result.DriveLetter | Should -Be $script:testDriveLetter + $script:result.Ensure | Should -Be 'Present' } It 'Should call all the Get mocks' { @@ -122,13 +291,15 @@ try -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedWrongLetterOpticalDrive } ` + -MockWith { + $script:mockedWrongLetterOpticalDrive + } ` -Verifiable It 'Should not throw an exception' { { $script:result = Get-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw @@ -136,6 +307,7 @@ try It "DriveLetter should be $($script:testDriveLetter)" { $script:result.DriveLetter | Should -Not -Be $script:testDriveLetter + $script:result.Ensure | Should -Be 'Present' } It 'Should call all the Get mocks' { @@ -150,13 +322,15 @@ try -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDriveIDE } ` + -MockWith { + $script:mockedOpticalDriveIDE + } ` -Verifiable It 'Should not throw an exception' { { $script:result = Get-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw @@ -164,6 +338,7 @@ try It "Should be DriveLetter $($script:testDriveLetter)" { $script:result.DriveLetter | Should -Not -Be $script:testDriveLetter + $script:result.Ensure | Should -Be 'Present' } It 'Should call all the Get mocks' { @@ -178,20 +353,22 @@ try -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedNoOpticalDrive } ` + -MockWith { + $script:mockedNoOpticalDrive + } ` -Verifiable - It 'Should not throw an exception' { + $errorRecord = Get-InvalidArgumentRecord ` + -Message ($LocalizedData.NoOpticalDiskDriveError -f 1) ` + -ArgumentName 'DiskId' + + It 'Should throw expected exception' { { $script:result = Get-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Verbose - } | Should -Not -Throw - } - - It 'DriveLetter should be null' { - $script:result.DriveLetter | Should -Be $null + } | Should -Throw $errorRecord } It 'Should call all the Get mocks' { @@ -203,20 +380,22 @@ try #region Function Set-TargetResource Describe 'MSFT_xOpticalDiskDriveLetter\Set-TargetResource' { - Context 'Optical disk drive with the correct drive letter' { + Context 'Optical disk drive exists with the correct drive letter' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDrive } ` + -MockWith { + $script:mockedOpticalDrive + } ` -Verifiable It 'Should not throw an exception' { { Set-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw @@ -228,14 +407,16 @@ try } } - Context 'Optical disk drive with the correct drive letter when Ensure is set to Absent' { + Context 'Optical disk drive exists with a drive letter when Ensure is set to Absent' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDrive } ` + -MockWith { + $script:mockedOpticalDrive + } ` -Verifiable Mock ` @@ -243,7 +424,9 @@ try -ParameterFilter { $ClassName -eq 'Win32_Volume' } ` - -MockWith { $script:mockedVolume } ` + -MockWith { + $script:mockedVolume + } ` -Verifiable Mock ` @@ -253,7 +436,7 @@ try It 'Should not throw an exception' { { Set-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Ensure 'Absent' ` -Verbose @@ -266,14 +449,16 @@ try } } - Context 'Optical disk with the wrong drive letter' { + Context 'Optical disk drive exists with the wrong drive letter' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedWrongLetterOpticalDrive } ` + -MockWith { + $script:mockedWrongLetterOpticalDrive + } ` -Verifiable Mock ` @@ -281,7 +466,9 @@ try -ParameterFilter { $ClassName -eq 'Win32_Volume' } ` - -MockWith { $script:mockedWrongVolume } ` + -MockWith { + $script:mockedWrongVolume + } ` -Verifiable Mock ` @@ -291,7 +478,7 @@ try It 'Should not throw an exception' { { Set-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw @@ -304,14 +491,16 @@ try } } - Context 'IDE optical disk drive with the wrong drive letter' { + Context 'IDE optical disk drive exists with the wrong drive letter' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDriveide } ` + -MockWith { + $script:mockedOpticalDriveIDE + } ` -Verifiable Mock ` @@ -319,7 +508,9 @@ try -ParameterFilter { $ClassName -eq 'Win32_Volume' } ` - -MockWith { $script:mockedWrongVolume } ` + -MockWith { + $script:mockedWrongVolume + } ` -Verifiable Mock ` @@ -329,7 +520,7 @@ try It 'Should not throw an exception' { { Set-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw @@ -342,57 +533,55 @@ try } } - # This resource does not change the drive letter of mounted ISO images. - Context 'Mounted ISO with the wrong drive letter' { + Context 'Optical disk drive not present' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDriveISO } ` + -MockWith { + $script:mockedNoOpticalDrive + } ` -Verifiable - It 'Should not throw an exception' { + $errorRecord = Get-InvalidArgumentRecord ` + -Message ($LocalizedData.NoOpticalDiskDriveError -f 1) ` + -ArgumentName 'DiskId' + + It 'Should throw expected exception' { { - Set-TargetResource ` - -IsSingleInstance 'Yes' ` + $script:result = Set-TargetResource ` + -DiskId 1 ` -Driveletter $script:testDriveLetter ` -Verbose - } | Should -Not -Throw + } | Should -Throw $errorRecord } - It 'Should call the correct mocks' { + It 'Should call all the Get mocks' { Assert-VerifiableMock - Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 } } } #endregion Describe 'MSFT_xOpticalDiskDriveLetter\Test-TargetResource' { - Context 'Drive letter is a valid optical disk drive' { + Context 'Optical drive exists and is assigned expected drive letter' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDrive } ` - -Verifiable - - Mock ` - -CommandName Get-CimInstance ` - -ParameterFilter { - $ClassName -eq 'Win32_Volume' + -MockWith { + $script:mockedOpticalDrive } ` - -MockWith { $script:mockedVolume } ` -Verifiable It 'Should not throw an exception' { { $script:result = Test-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -DriveLetter $script:testDriveLetter ` -Verbose } | Should -Not -Throw @@ -407,28 +596,22 @@ try } } - Context 'Drive letter is a valid optical disk drive and $Ensure is set to Absent' { + Context 'Optical drive exists but is assigned a drive letter but should not be' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDrive } ` - -Verifiable - - Mock ` - -CommandName Get-CimInstance ` - -ParameterFilter { - $ClassName -eq 'Win32_Volume' + -MockWith { + $script:mockedOpticalDrive } ` - -MockWith { $script:mockedVolume } ` -Verifiable It 'Should not throw an exception' { { $script:result = Test-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -DriveLetter $script:testDriveLetter ` -Ensure 'Absent' ` -Verbose @@ -444,36 +627,39 @@ try } } - Context 'There is no optical disk drive' { + Context 'The drive letter already exists on a volume that is not an optical disk drive' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedNoOpticalDrive } ` + -MockWith { + $script:mockedWrongLetterOpticalDrive + } ` -Verifiable Mock ` - -CommandName Get-CimInstance ` + -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_Volume' } ` - -MockWith { $script:mockedWrongVolume } ` + -MockWith { + $script:mockedVolume + } ` -Verifiable It 'Should not throw an exception' { { $script:result = Test-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -DriveLetter $script:testDriveLetter ` - -Ensure 'Present' ` -Verbose } | Should -Not -Throw } - It 'Should return $false' { - $script:result | Should -Be $false + It 'Should return $true' { + $script:result | Should -Be $true } It 'Should call all the Get mocks' { @@ -481,44 +667,98 @@ try } } - Context 'The drive letter already exists on a volume that is not a optical disk drive' { + Context 'The optical drive is assigned a drive letter but should not be' { # verifiable (should be called) mocks Mock ` -CommandName Get-CimInstance ` -ParameterFilter { $ClassName -eq 'Win32_CDROMDrive' } ` - -MockWith { $script:mockedOpticalDrive } ` + -MockWith { + $script:mockedOpticalDrive + } ` -Verifiable + It 'Should not throw an exception' { + { + $script:result = Test-TargetResource ` + -DiskId 1 ` + -DriveLetter $script:testDriveLetter ` + -Ensure 'Absent' ` + -Verbose + } | Should -Not -Throw + } + + It 'Should return $false' { + $script:result | Should -Be $false + } + + It 'Should call all the Get mocks' { + Assert-VerifiableMock + } + } + + Context 'The optical drive is not assigned a drive letter and should not be' { + # verifiable (should be called) mocks Mock ` - -CommandName Get-CimInstance ` + -CommandName Get-CimInstance ` -ParameterFilter { - $ClassName -eq 'Win32_Volume' + $ClassName -eq 'Win32_CDROMDrive' + } ` + -MockWith { + $script:mockedOpticalDriveNoDriveLetter } ` - -MockWith { $script:mockedVolumeNotOpticalDrive } ` -Verifiable It 'Should not throw an exception' { { $script:result = Test-TargetResource ` - -IsSingleInstance 'Yes' ` + -DiskId 1 ` -DriveLetter $script:testDriveLetter ` - -Ensure 'Present' ` + -Ensure 'Absent' ` -Verbose } | Should -Not -Throw } - It 'Should return $false' { - $script:result | Should -Be $false + It 'Should return $true' { + $script:result | Should -Be $true } It 'Should call all the Get mocks' { Assert-VerifiableMock } } - } + Context 'Optical disk drive not present' { + # verifiable (should be called) mocks + Mock ` + -CommandName Get-CimInstance ` + -ParameterFilter { + $ClassName -eq 'Win32_CDROMDrive' + } ` + -MockWith { + $script:mockedNoOpticalDrive + } ` + -Verifiable + + $errorRecord = Get-InvalidArgumentRecord ` + -Message ($LocalizedData.NoOpticalDiskDriveError -f 1) ` + -ArgumentName 'DiskId' + + It 'Should throw expected exception' { + { + $script:result = Test-TargetResource ` + -DiskId 1 ` + -Driveletter $script:testDriveLetter ` + -Verbose + } | Should -Throw $errorRecord + } + + It 'Should call all the Get mocks' { + Assert-VerifiableMock + } + } + } #endregion } } From fef97ed5f4ee396c4ea89907f86a7b5e801f35ce Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Mon, 8 Jan 2018 21:28:51 +1300 Subject: [PATCH 17/45] Fix integration tests for xOpticalDiskDriveLetter --- .../MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 index e5c76d90..825b3f0b 100644 --- a/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 @@ -185,6 +185,9 @@ finally Restore-TestEnvironment -TestEnvironment $TestEnvironment # Mount the optical disk back to where it was - $volume | Set-CimInstance -Property @{ DriveLetter = $currentDriveLetter } + if ($volume) + { + $volume | Set-CimInstance -Property @{ DriveLetter = $currentDriveLetter } + } #endregion } From 5a28ee4cf40fc03ac560dcb9793a4cd3c65bf672 Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Mon, 8 Jan 2018 21:36:45 +1300 Subject: [PATCH 18/45] Correct DiskId type in xOpticalDiskDriveLetter --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index f90fa18a..364b53bb 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -57,7 +57,7 @@ function Get-OpticalDiskDriveLetter param ( [Parameter(Mandatory = $true)] - [System.Int32] + [System.String] $DiskId, [Parameter()] @@ -147,7 +147,7 @@ function Get-TargetResource param ( [Parameter(Mandatory = $true)] - [System.Int32] + [System.String] $DiskId, [Parameter(Mandatory = $true)] @@ -208,7 +208,7 @@ function Set-TargetResource param ( [Parameter(Mandatory = $true)] - [System.Int32] + [System.String] $DiskId, [Parameter(Mandatory = $true)] @@ -291,7 +291,7 @@ function Test-TargetResource param ( [Parameter(Mandatory = $true)] - [System.Int32] + [System.String] $DiskId, [Parameter(Mandatory = $true)] From bbb9ae9784ec9503f0b039a1f9c957d2ad4a2487 Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Tue, 9 Jan 2018 13:56:46 +1300 Subject: [PATCH 19/45] Correct Required in MSFT_xOpticalDiskDriveLetter --- .../MSFT_xOpticalDiskDriveLetter.schema.mof | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof index 255835b1..226cdd95 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof @@ -3,7 +3,6 @@ class MSFT_xOpticalDiskDriveLetter : OMI_BaseResource { [Key, Description("Specifies the optical disk number for the disk to assign the drive letter to.")] String DiskId; - [Write, Description("Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon.")] String DriveLetter; - [Write, Description("Determines whether a drive letter should be assigned to the optical disk. Defaults to 'Present'."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] string Ensure; + [Required, Description("Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon.")] String DriveLetter; + [Write, Description("Determines whether a drive letter should be assigned to the optical disk. Defaults to 'Present'."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; }; - From 3e9cdf6e94b60552a20134e085052d4e912d6c46 Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Wed, 10 Jan 2018 20:40:01 +1300 Subject: [PATCH 20/45] Changes as per PR comments --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 143 +++++++++--------- .../MSFT_xOpticalDiskDriveLetter.schema.mof | 2 +- .../MSFT_xOpticalDiskDriveLetter/README.md | 10 ++ ...ticalDiskDriveLetter_RemoveDriveLetter.ps1 | 1 - ...xOpticalDiskDriveLetter_SetDriveLetter.ps1 | 1 - .../MSFT_xOpticalDiskDriveLetter.Tests.ps1 | 29 ++-- 6 files changed, 94 insertions(+), 92 deletions(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index 364b53bb..35071124 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -22,33 +22,29 @@ $localizedData = Get-LocalizedData ` <# .SYNOPSIS - This helper function returns the current drive letter assigned - to the a disk number disk found in the system. + This helper function returns a hashtable containing the current + drive letter assigned to the optical disk in the system matching + the disk number. - If the drive exists but is not mounted to a drive letter then - it will return an empty string. + If the drive exists but is not mounted to a drive letter then + the DriveLetter will be empty, but the DeviceId will contain the + DeviceId representing the optical disk. - If there are no optical disks found in the system, return null. + If there are no optical disks found in the system an exception + will be thrown. .PARAMETER DiskId - Specifies the optical disk number for the disk to return the drive - letter of. - - .PARAMETER ReturnDeviceIdOnNoDriveLetter - This switch will cause the Drive Letter to be returned with the - default value that Drive is set to when no Drive Letter is assigned - e.g. 'Volume{bba1802b-e7a1-11e3-824e-806e6f6e6963}'. - - Otherwise the Drive Letter will be empty + Specifies the optical disk number for the disk to return the drive + letter of. .NOTES - The Caption and DeviceID properties are checked to avoid - mounted ISO images in Windows 2012+ and Windows 10. The - device ID is required because a CD/DVD in a Hyper-V virtual - machine has the same caption as a mounted ISO. + The Caption and DeviceID properties are checked to avoid + mounted ISO images in Windows 2012+ and Windows 10. The + device ID is required because a CD/DVD in a Hyper-V virtual + machine has the same caption as a mounted ISO. - Example DeviceID for a virtual drive in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006 - Example DeviceID for a mounted ISO in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002 + Example DeviceID for a virtual drive in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\000006 + Example DeviceID for a mounted ISO in a Hyper-V VM - SCSI\CDROM&VEN_MSFT&PROD_VIRTUAL_DVD-ROM\2&1F4ADFFE&0&000002 #> function Get-OpticalDiskDriveLetter { @@ -58,11 +54,7 @@ function Get-OpticalDiskDriveLetter ( [Parameter(Mandatory = $true)] [System.String] - $DiskId, - - [Parameter()] - [Switch] - $ReturnDeviceIdOnNoDriveLetter + $DiskId ) $driveLetter = $null @@ -81,8 +73,17 @@ function Get-OpticalDiskDriveLetter ) } + $deviceId = '' + if ($opticalDisks) { + <# + To behave in a similar fashion to the other xStorage resources the + DiskId represents the number of the optical disk in the system. + However as these are returned as an array of 0..x elements then + subtract one from the DiskId to get the actual optical disk number + that is required. + #> $opticalDisk = $opticalDisks[$DiskId - 1] if ($opticalDisk) @@ -95,25 +96,13 @@ function Get-OpticalDiskDriveLetter catch { # Optical drive exists but is not mounted to a drive letter - if ($ReturnDeviceIdOnNoDriveLetter) - { - $driveLetter = $opticalDisk.Drive - - Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.OpticalDiskAssignedDriveLetter -f $DiskId, $driveLetter) - ) -join '' ) - } - else - { - $driveLetter = '' - - Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.OpticalDiskNotAssignedDriveLetter -f $DiskId) - ) -join '' ) - - } + $deviceId = $opticalDisk.Drive + $driveLetter = '' + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($localizedData.OpticalDiskNotAssignedDriveLetter -f $DiskId) + ) -join '' ) } } } @@ -125,20 +114,27 @@ function Get-OpticalDiskDriveLetter -ArgumentName 'DiskId' } - return $driveLetter + $driveInfo = @{ + DriveLetter = $driveLetter + DeviceId = $deviceId + + } + + return $driveInfo } <# .SYNOPSIS - Returns the current drive letter assigned to the optical disk. + Returns the current drive letter assigned to the optical disk. .PARAMETER DiskId - Specifies the optical disk number for the disk to assign the drive - letter to. + Specifies the optical disk number for the disk to assign the drive + letter to. .PARAMETER DriveLetter - Specifies the drive letter to assign to the optical disk. Can be a - single letter, optionally followed by a colon. + Specifies the drive letter to assign to the optical disk. Can be a + single letter, optionally followed by a colon. This value is ignored + if Ensure is set to Absent. #> function Get-TargetResource { @@ -158,7 +154,8 @@ function Get-TargetResource $ensure = 'Absent' # Get the drive letter assigned to the optical disk - $currentDriveLetter = Get-OpticalDiskDriveLetter -DiskId $DiskId + $currentDriveInfo = Get-OpticalDiskDriveLetter -DiskId $DiskId + $currentDriveLetter = $currentDriveInfo.DriveLetter if ([System.String]::IsNullOrWhiteSpace($currentDriveLetter)) { @@ -188,19 +185,20 @@ function Get-TargetResource <# .SYNOPSIS - Sets the drive letter of an optical disk. + Sets the drive letter of an optical disk. .PARAMETER DiskId - Specifies the optical disk number for the disk to assign the drive - letter to. + Specifies the optical disk number for the disk to assign the drive + letter to. .PARAMETER DriveLetter - Specifies the drive letter to assign to the optical disk. Can be a - single letter, optionally followed by a colon. + Specifies the drive letter to assign to the optical disk. Can be a + single letter, optionally followed by a colon. This value is ignored + if Ensure is set to Absent. .PARAMETER Ensure - Determines whether a drive letter should be assigned to the - optical disk. Defaults to 'Present'. + Determines whether a drive letter should be assigned to the + optical disk. Defaults to 'Present'. #> function Set-TargetResource { @@ -225,7 +223,8 @@ function Set-TargetResource $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon # Get the drive letter assigned to the optical disk - $currentDriveLetter = Get-OpticalDiskDriveLetter -DiskId $DiskId + $currentDriveInfo = Get-OpticalDiskDriveLetter -DiskId $DiskId + $currentDriveLetter = $currentDriveInfo.DriveLetter if ([System.String]::IsNullOrWhiteSpace($currentDriveLetter)) { @@ -234,7 +233,7 @@ function Set-TargetResource The DeviceId in the volume will show as \\?\Volume{bba1802b-e7a1-11e3-824e-806e6f6e6963}\ So we need to change the currentDriveLetter to match this value when we set the drive letter #> - $deviceId = Get-OpticalDiskDriveLetter -DiskId $DiskId -ReturnDeviceIdOnNoDriveLetter + $deviceId = $currentDriveInfo.DeviceId $volume = Get-CimInstance ` -ClassName Win32_Volume ` @@ -270,19 +269,20 @@ function Set-TargetResource <# .SYNOPSIS - Tests the disk letter assigned to an optical disk is correct. + Tests the disk letter assigned to an optical disk is correct. .PARAMETER DiskId - Specifies the optical disk number for the disk to assign the drive - letter to. + Specifies the optical disk number for the disk to assign the drive + letter to. .PARAMETER DriveLetter - Specifies the drive letter to assign to the optical disk. Can be a - single letter, optionally followed by a colon. + Specifies the drive letter to assign to the optical disk. Can be a + single letter, optionally followed by a colon. This value is ignored + if Ensure is set to Absent. .PARAMETER Ensure - Determines whether a drive letter should be assigned to the - optical disk. Defaults to 'Present'. + Determines whether a drive letter should be assigned to the + optical disk. Defaults to 'Present'. #> function Test-TargetResource { @@ -310,7 +310,8 @@ function Test-TargetResource $DriveLetter = Assert-DriveLetterValid -DriveLetter $DriveLetter -Colon # Get the drive letter assigned to the optical disk - $currentDriveLetter = Get-OpticalDiskDriveLetter -DiskId $DiskId + $currentDriveInfo = Get-OpticalDiskDriveLetter -DiskId $DiskId + $currentDriveLetter = $currentDriveInfo.DriveLetter if ($Ensure -eq 'Absent') { @@ -353,10 +354,8 @@ function Test-TargetResource if ($existingVolume) { # The desired drive letter is already assigned to another drive - can't proceed - Write-Verbose -Message ( @( - "$($MyInvocation.MyCommand): " - $($localizedData.DriveLetterAssignedToAnotherDrive -f $DriveLetter) - ) -join '' ) + New-InvalidOperationException ` + -Message $($localizedData.DriveLetterAssignedToAnotherDrive -f $DriveLetter) } else { diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof index 226cdd95..09cd7944 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof @@ -3,6 +3,6 @@ class MSFT_xOpticalDiskDriveLetter : OMI_BaseResource { [Key, Description("Specifies the optical disk number for the disk to assign the drive letter to.")] String DiskId; - [Required, Description("Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon.")] String DriveLetter; + [Required, Description("Specifies the drive letter to assign to the optical disk. Can be a single letter, optionally followed by a colon. This value is ignored if Ensure is set to Absent.")] String DriveLetter; [Write, Description("Determines whether a drive letter should be assigned to the optical disk. Defaults to 'Present'."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; }; diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md index 2a867073..c782ec95 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md @@ -7,6 +7,16 @@ It can be used to set the drive letter of a specific optical disk drive if there are multiple in the system by specifying a value greater than 1 for the `DiskId` parameter. +In a system with a single optical disk drive then the `DiskId` should +be set to 1. + +In systems with multiple optical disks, the `DiskId` should be set to +the ordinal number of the required optical disk found in the list returned +when executing the following cmdlet: +```powershell +Get-CimInstance -ClassName Win32_CDROMDrive +``` + It is designed to ignore _temporary_ optical disk drives that are created when mounting ISOs on Windows Server 2012+. diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 index 10e8d23b..532c7a93 100644 --- a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 @@ -5,7 +5,6 @@ #> Configuration Example { - Import-DSCResource -ModuleName xStorage Node localhost diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 index 94bc5e70..3ca6f573 100644 --- a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 @@ -5,7 +5,6 @@ #> Configuration Example { - Import-DSCResource -ModuleName xStorage Node localhost diff --git a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 index 94791c32..75eaf631 100644 --- a/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 +++ b/Tests/Unit/MSFT_xOpticalDiskDriveLetter.Tests.ps1 @@ -101,7 +101,7 @@ try ) } - #region Function Get-TargetResource + #region Function Get-OpticalDiskDriveLetter Describe 'MSFT_xOpticalDiskDriveLetter\Get-OpticalDiskDriveLetter' { Context 'Single optical disk drive present and assigned a drive letter' { # verifiable (should be called) mocks @@ -117,9 +117,8 @@ try It 'Should not throw an exception' { { - $script:result = Get-TargetResource ` + $script:result = Get-OpticalDiskDriveLetter ` -DiskId 1 ` - -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw } @@ -147,15 +146,15 @@ try It 'Should not throw an exception' { { - $script:result = Get-TargetResource ` + $script:result = Get-OpticalDiskDriveLetter ` -DiskId 1 ` - -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw } It "DriveLetter should be empty" { $script:result.DriveLetter | Should -Be '' + $script:result.DeviceId | Should -Be $script:testDriveLetterNoVolume } It 'Should call all the Get mocks' { @@ -177,9 +176,8 @@ try It 'Should not throw an exception' { { - $script:result = Get-TargetResource ` + $script:result = Get-OpticalDiskDriveLetter ` -DiskId 2 ` - -Driveletter $script:testDriveLetter ` -Verbose } | Should -Not -Throw } @@ -211,9 +209,8 @@ try It 'Should throw expected exception' { { - $script:result = Get-TargetResource ` + $script:result = Get-OpticalDiskDriveLetter ` -DiskId 2 ` - -Driveletter $script:testDriveLetter ` -Verbose } | Should -Throw $errorRecord } @@ -237,9 +234,8 @@ try It 'Should throw expected exception' { { - $script:result = Get-TargetResource ` + $script:result = Get-OpticalDiskDriveLetter ` -DiskId 1 ` - -Driveletter $script:testDriveLetter ` -Verbose } | Should -Throw $errorRecord } @@ -649,17 +645,16 @@ try } ` -Verifiable - It 'Should not throw an exception' { + $errorRecord = Get-InvalidOperationRecord ` + -Message $($localizedData.DriveLetterAssignedToAnotherDrive -f $script:testDriveLetter) + + It 'Should throw expected exception' { { $script:result = Test-TargetResource ` -DiskId 1 ` -DriveLetter $script:testDriveLetter ` -Verbose - } | Should -Not -Throw - } - - It 'Should return $true' { - $script:result | Should -Be $true + } | Should -Throw $errorRecord } It 'Should call all the Get mocks' { From c96247f66dca7e98cc3492867cf201ee03c167de Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Wed, 10 Jan 2018 20:44:55 +1300 Subject: [PATCH 21/45] Final changes as per PR comments --- .../MSFT_xOpticalDiskDriveLetter/README.md | 4 +++ ...icalDiskDriveLetter_RemoveDriveLetter.ps1} | 0 ...calDiskDriveLetter_SetDriveLetterMulti.ps1 | 34 +++++++++++++++++++ 3 files changed, 38 insertions(+) rename Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/{1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 => 2-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1} (100%) create mode 100644 Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md index c782ec95..23323184 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md @@ -17,6 +17,10 @@ when executing the following cmdlet: Get-CimInstance -ClassName Win32_CDROMDrive ``` +Warning: Adding and removing optical drive devices to a system may cause the +order the optical drives appear in the system to change. Therefore, the +drive ordinal number may be affected in these situations. + It is designed to ignore _temporary_ optical disk drives that are created when mounting ISOs on Windows Server 2012+. diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/2-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 similarity index 100% rename from Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 rename to Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/2-xOpticalDiskDriveLetter_RemoveDriveLetter.ps1 diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 new file mode 100644 index 00000000..6146f846 --- /dev/null +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 @@ -0,0 +1,34 @@ +<# + .EXAMPLE + This configuration will set the drive letter of the first + optical disk drive in the system to 'Y'. It will set the + drive letter of the second optical disk drive to 'Z'. It + will remove the drive letter from the third optical disk + drive in the system. +#> +Configuration Example +{ + Import-DSCResource -ModuleName xStorage + + Node localhost + { + xOpticalDiskDriveLetter SetFirstOpticalDiskDriveLetterToY + { + DiskId = 1 + DriveLetter = 'Y' + } + + xOpticalDiskDriveLetter SetSecondOpticalDiskDriveLetterToZ + { + DiskId = 2 + DriveLetter = 'Z' + } + + xOpticalDiskDriveLetter RemoveThurdOpticalDiskDriveLetter + { + DiskId = 3 + DriveLetter = 'A' + Ensure = 'Absent' + } + } +} From 3188d196b73e7c1bbbfc71a4fb7e95b662f7dc2e Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Wed, 10 Jan 2018 20:54:02 +1300 Subject: [PATCH 22/45] Correct failed tests due to long MD lines --- .../DSCResources/MSFT_xOpticalDiskDriveLetter/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md index 23323184..37dee5b6 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md @@ -11,8 +11,8 @@ In a system with a single optical disk drive then the `DiskId` should be set to 1. In systems with multiple optical disks, the `DiskId` should be set to -the ordinal number of the required optical disk found in the list returned -when executing the following cmdlet: +the ordinal number of the required optical disk found in the list +returnedwhen executing the following cmdlet: ```powershell Get-CimInstance -ClassName Win32_CDROMDrive ``` @@ -21,8 +21,8 @@ Warning: Adding and removing optical drive devices to a system may cause the order the optical drives appear in the system to change. Therefore, the drive ordinal number may be affected in these situations. -It is designed to ignore _temporary_ optical disk drives that are created when -mounting ISOs on Windows Server 2012+. +It is designed to ignore _temporary_ optical disk drives that are created +when mounting ISOs on Windows Server 2012+. With the Device ID, we look for the length of the string after the final backslash (crude, but appears to work so far). From 0f62bc9a5e39f809918989e4fb14437feccf2d16 Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Wed, 10 Jan 2018 20:59:52 +1300 Subject: [PATCH 23/45] Fix other markdown violations --- .../xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md index 37dee5b6..099eec94 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md @@ -13,6 +13,7 @@ be set to 1. In systems with multiple optical disks, the `DiskId` should be set to the ordinal number of the required optical disk found in the list returnedwhen executing the following cmdlet: + ```powershell Get-CimInstance -ClassName Win32_CDROMDrive ``` From a9d8cc207317d6a292bf8e22f347121cd2162f3c Mon Sep 17 00:00:00 2001 From: Daniel Scott-Raynsford Date: Thu, 11 Jan 2018 20:53:42 +1300 Subject: [PATCH 24/45] Fixes as per PR comments --- .../MSFT_xOpticalDiskDriveLetter.psm1 | 7 ++----- .../DSCResources/MSFT_xOpticalDiskDriveLetter/README.md | 2 +- .../3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 index 35071124..712f2993 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 @@ -96,7 +96,6 @@ function Get-OpticalDiskDriveLetter catch { # Optical drive exists but is not mounted to a drive letter - $deviceId = $opticalDisk.Drive $driveLetter = '' Write-Verbose -Message ( @( @@ -104,6 +103,7 @@ function Get-OpticalDiskDriveLetter $($localizedData.OpticalDiskNotAssignedDriveLetter -f $DiskId) ) -join '' ) } + $deviceId = $opticalDisk.Drive } } @@ -114,13 +114,10 @@ function Get-OpticalDiskDriveLetter -ArgumentName 'DiskId' } - $driveInfo = @{ + return @{ DriveLetter = $driveLetter DeviceId = $deviceId - } - - return $driveInfo } <# diff --git a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md index 099eec94..9df3ce47 100644 --- a/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md +++ b/Modules/xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/README.md @@ -12,7 +12,7 @@ be set to 1. In systems with multiple optical disks, the `DiskId` should be set to the ordinal number of the required optical disk found in the list -returnedwhen executing the following cmdlet: +returned when executing the following cmdlet: ```powershell Get-CimInstance -ClassName Win32_CDROMDrive diff --git a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 index 6146f846..f9a8b950 100644 --- a/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 +++ b/Modules/xStorage/Examples/Resources/xOpticalDiskDriveLetter/3-xOpticalDiskDriveLetter_SetDriveLetterMulti.ps1 @@ -24,7 +24,7 @@ Configuration Example DriveLetter = 'Z' } - xOpticalDiskDriveLetter RemoveThurdOpticalDiskDriveLetter + xOpticalDiskDriveLetter RemoveThirdOpticalDiskDriveLetter { DiskId = 3 DriveLetter = 'A' From ffa3109ca2df9be99ac65e4cb3acdbb48d3bcc4b Mon Sep 17 00:00:00 2001 From: Tim Haintz Date: Wed, 24 Jan 2018 23:05:33 +1100 Subject: [PATCH 25/45] BREAKING CHANGE. Renamed xStorage to StorageDsc and also renamed DSC resources. --- .github/ISSUE_TEMPLATE.md | 2 +- .github/PULL_REQUEST_TEMPLATE.md | 4 +-- .gitignore | 4 +-- CHANGELOG.md | 11 +++++++- .../DSCResources/MSFT_Disk/MSFT_Disk.psm1} | 2 +- .../MSFT_Disk/MSFT_Disk.schema.mof} | 4 +-- .../DSCResources/MSFT_Disk}/README.md | 0 .../MSFT_Disk/en-us/MSFT_Disk.strings.psd1} | 0 .../MSFT_DiskAccessPath.psm1} | 2 +- .../MSFT_DiskAccessPath.schema.mof} | 4 +-- .../MSFT_DiskAccessPath}/README.md | 0 .../en-us/MSFT_DiskAccessPath.strings.psd1} | 0 .../MSFT_MountImage/MSFT_MountImage.psm1} | 2 +- .../MSFT_MountImage.schema.mof} | 4 +-- .../DSCResources/MSFT_MountImage}/README.md | 0 .../en-us/MSFT_MountImage.strings.psd1} | 0 .../MSFT_OpticalDiskDriveLetter.psm1} | 2 +- .../MSFT_OpticalDiskDriveLetter.schema.mof} | 4 +-- .../MSFT_OpticalDiskDriveLetter}/README.md | 0 .../MSFT_OpticalDiskDriveLetter.strings.psd1} | 0 .../MSFT_WaitForDisk/MSFT_WaitForDisk.psm1} | 2 +- .../MSFT_WaitForDisk.schema.mof} | 4 +-- .../DSCResources/MSFT_WaitForDisk}/README.md | 0 .../en-us/MSFT_WaitForDisk.strings.psd1} | 0 .../MSFT_WaitForVolume.psm1} | 2 +- .../MSFT_WaitForVolume.schema.mof} | 4 +-- .../MSFT_WaitForVolume}/README.md | 0 .../en-us/MSFT_WaitForVolume.strings.psd1} | 0 .../Disk/1-Disk_InitializeDataDisk.ps1} | 16 +++++------ ...-Disk_InitializeDataDiskUsingUniqueId.ps1} | 18 ++++++------ ...Path_InitializeDataDiskWithAccessPath.ps1} | 12 ++++---- ...zeDataDiskWithAccessPathUsingUniqueId.ps1} | 12 ++++---- .../MountImage/1-MountImage_DismountISO.ps1} | 4 +-- .../MountImage/2-MountImage_MountISO.ps1} | 6 ++-- .../MountImage/3-MountImage_MountVHD.ps1} | 6 ++-- ...OpticalDiskDriveLetter_SetDriveLetter.ps1} | 4 +-- .../1-WaitForDisk_InitializeDataDisk.ps1} | 12 ++++---- ...Disk_InitializeDataDiskWithAccessPath.ps1} | 12 ++++---- ...Disk_InitializeDataDiskWithAccessPath.ps1} | 12 ++++---- ...zeDataDiskWithAccessPathUsingUniqueId.ps1} | 12 ++++---- .../WaitForVolume/1-WaitForVolume_VHD.ps1} | 6 ++-- .../WaitForVolume/2-WaitForVolume_ISO.ps1} | 6 ++-- .../StorageDsc.Common/StorageDsc.Common.psm1 | 0 .../en-us/StorageDsc.Common.strings.psd1 | 0 .../StorageDsc.ResourceHelper.psm1 | 0 .../StorageDsc.psd1} | 8 +++--- README.md | 28 +++++++++---------- ...ts.ps1 => MSFT_Disk.Integration.Tests.ps1} | 6 ++-- ..._xDisk.config.ps1 => MSFT_Disk.config.ps1} | 16 +++++------ ...MSFT_DiskAccessPath.Integration.Tests.ps1} | 20 ++++++------- ...fig.ps1 => MSFT_DiskAccessPath.config.ps1} | 8 +++--- ...MSFT_MountImage_ISO.Integration.Tests.ps1} | 6 ++-- ...MSFT_MountImage_VHD.Integration.Tests.ps1} | 6 ++-- ...s1 => MSFT_MountImage_dismount.config.ps1} | 4 +-- ...g.ps1 => MSFT_MountImage_mount.config.ps1} | 6 ++-- ...icalDiskDriveLetter.Integration.Tests.ps1} | 6 ++-- .../MSFT_OpticalDiskDriveLetter.config.ps1 | 8 ++++++ ...=> MSFT_WaitForDisk.Integration.Tests.ps1} | 6 ++-- ...config.ps1 => MSFT_WaitForDisk.config.ps1} | 6 ++-- ... MSFT_WaitForVolume.Integration.Tests.ps1} | 6 ++-- ...nfig.ps1 => MSFT_WaitForVolume.config.ps1} | 6 ++-- .../MSFT_xOpticalDiskDriveLetter.config.ps1 | 8 ------ Tests/Integration/ModuleConflict.Tests.ps1 | 4 +-- Tests/TestHarness.psm1 | 6 ++-- ...FT_xDisk.Tests.ps1 => MSFT_Disk.Tests.ps1} | 12 ++++---- ...ests.ps1 => MSFT_DiskAccessPath.Tests.ps1} | 14 +++++----- ...ge.Tests.ps1 => MSFT_MountImage.Tests.ps1} | 16 +++++------ ... => MSFT_OpticalDiskDriveLetter.Tests.ps1} | 12 ++++---- ...k.Tests.ps1 => MSFT_WaitForDisk.Tests.ps1} | 12 ++++---- ...Tests.ps1 => MSFT_WaitForVolume.Tests.ps1} | 12 ++++---- Tests/Unit/StorageDsc.Common.Tests.ps1 | 2 +- appveyor.yml | 2 +- 72 files changed, 225 insertions(+), 216 deletions(-) rename Modules/{xStorage/DSCResources/MSFT_xDisk/MSFT_xDisk.psm1 => StorageDsc/DSCResources/MSFT_Disk/MSFT_Disk.psm1} (99%) rename Modules/{xStorage/DSCResources/MSFT_xDisk/MSFT_xDisk.schema.mof => StorageDsc/DSCResources/MSFT_Disk/MSFT_Disk.schema.mof} (93%) rename Modules/{xStorage/DSCResources/MSFT_xDisk => StorageDsc/DSCResources/MSFT_Disk}/README.md (100%) rename Modules/{xStorage/DSCResources/MSFT_xDisk/en-us/MSFT_xDisk.strings.psd1 => StorageDsc/DSCResources/MSFT_Disk/en-us/MSFT_Disk.strings.psd1} (100%) rename Modules/{xStorage/DSCResources/MSFT_xDiskAccessPath/MSFT_xDiskAccessPath.psm1 => StorageDsc/DSCResources/MSFT_DiskAccessPath/MSFT_DiskAccessPath.psm1} (99%) rename Modules/{xStorage/DSCResources/MSFT_xDiskAccessPath/MSFT_xDiskAccessPath.schema.mof => StorageDsc/DSCResources/MSFT_DiskAccessPath/MSFT_DiskAccessPath.schema.mof} (88%) rename Modules/{xStorage/DSCResources/MSFT_xDiskAccessPath => StorageDsc/DSCResources/MSFT_DiskAccessPath}/README.md (100%) rename Modules/{xStorage/DSCResources/MSFT_xDiskAccessPath/en-us/MSFT_xDiskAccessPath.strings.psd1 => StorageDsc/DSCResources/MSFT_DiskAccessPath/en-us/MSFT_DiskAccessPath.strings.psd1} (100%) rename Modules/{xStorage/DSCResources/MSFT_xMountImage/MSFT_xMountImage.psm1 => StorageDsc/DSCResources/MSFT_MountImage/MSFT_MountImage.psm1} (99%) rename Modules/{xStorage/DSCResources/MSFT_xMountImage/MSFT_xMountImage.schema.mof => StorageDsc/DSCResources/MSFT_MountImage/MSFT_MountImage.schema.mof} (90%) rename Modules/{xStorage/DSCResources/MSFT_xMountImage => StorageDsc/DSCResources/MSFT_MountImage}/README.md (100%) rename Modules/{xStorage/DSCResources/MSFT_xMountImage/en-us/MSFT_xMountImage.strings.psd1 => StorageDsc/DSCResources/MSFT_MountImage/en-us/MSFT_MountImage.strings.psd1} (100%) rename Modules/{xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.psm1 => StorageDsc/DSCResources/MSFT_OpticalDiskDriveLetter/MSFT_OpticalDiskDriveLetter.psm1} (99%) rename Modules/{xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/MSFT_xOpticalDiskDriveLetter.schema.mof => StorageDsc/DSCResources/MSFT_OpticalDiskDriveLetter/MSFT_OpticalDiskDriveLetter.schema.mof} (70%) rename Modules/{xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter => StorageDsc/DSCResources/MSFT_OpticalDiskDriveLetter}/README.md (100%) rename Modules/{xStorage/DSCResources/MSFT_xOpticalDiskDriveLetter/en-us/MSFT_xOpticalDiskDriveLetter.strings.psd1 => StorageDsc/DSCResources/MSFT_OpticalDiskDriveLetter/en-us/MSFT_OpticalDiskDriveLetter.strings.psd1} (100%) rename Modules/{xStorage/DSCResources/MSFT_xWaitForDisk/MSFT_xWaitForDisk.psm1 => StorageDsc/DSCResources/MSFT_WaitForDisk/MSFT_WaitForDisk.psm1} (99%) rename Modules/{xStorage/DSCResources/MSFT_xWaitForDisk/MSFT_xWaitForDisk.schema.mof => StorageDsc/DSCResources/MSFT_WaitForDisk/MSFT_WaitForDisk.schema.mof} (84%) rename Modules/{xStorage/DSCResources/MSFT_xWaitForDisk => StorageDsc/DSCResources/MSFT_WaitForDisk}/README.md (100%) rename Modules/{xStorage/DSCResources/MSFT_xWaitForDisk/en-us/MSFT_xWaitForDisk.strings.psd1 => StorageDsc/DSCResources/MSFT_WaitForDisk/en-us/MSFT_WaitForDisk.strings.psd1} (100%) rename Modules/{xStorage/DSCResources/MSFT_xWaitForVolume/MSFT_xWaitForVolume.psm1 => StorageDsc/DSCResources/MSFT_WaitForVolume/MSFT_WaitForVolume.psm1} (99%) rename Modules/{xStorage/DSCResources/MSFT_xWaitForVolume/MSFT_xWaitForVolume.schema.mof => StorageDsc/DSCResources/MSFT_WaitForVolume/MSFT_WaitForVolume.schema.mof} (77%) rename Modules/{xStorage/DSCResources/MSFT_xWaitForVolume => StorageDsc/DSCResources/MSFT_WaitForVolume}/README.md (100%) rename Modules/{xStorage/DSCResources/MSFT_xWaitForVolume/en-us/MSFT_xWaitForVolume.strings.psd1 => StorageDsc/DSCResources/MSFT_WaitForVolume/en-us/MSFT_WaitForVolume.strings.psd1} (100%) rename Modules/{xStorage/Examples/Resources/xDisk/1-xDisk_InitializeDataDisk.ps1 => StorageDsc/Examples/Resources/Disk/1-Disk_InitializeDataDisk.ps1} (80%) rename Modules/{xStorage/Examples/Resources/xDisk/2-xDisk_InitializeDataDiskUsingUniqueId.ps1 => StorageDsc/Examples/Resources/Disk/2-Disk_InitializeDataDiskUsingUniqueId.ps1} (83%) rename Modules/{xStorage/Examples/Resources/xWaitForDisk/2-xWaitForDisk_InitializeDataDiskWithAccessPath.ps1 => StorageDsc/Examples/Resources/DiskAccessPath/1-DiskAccessPath_InitializeDataDiskWithAccessPath.ps1} (74%) rename Modules/{xStorage/Examples/Resources/xDiskAccessPath/2-xDiskAccessPath_InitializeDataDiskWithAccessPathUsingUniqueId.ps1 => StorageDsc/Examples/Resources/DiskAccessPath/2-DiskAccessPath_InitializeDataDiskWithAccessPathUsingUniqueId.ps1} (80%) rename Modules/{xStorage/Examples/Resources/xMountImage/1-xMountImage_DismountISO.ps1 => StorageDsc/Examples/Resources/MountImage/1-MountImage_DismountISO.ps1} (77%) rename Modules/{xStorage/Examples/Resources/xMountImage/2-xMountImage_MountISO.ps1 => StorageDsc/Examples/Resources/MountImage/2-MountImage_MountISO.ps1} (75%) rename Modules/{xStorage/Examples/Resources/xWaitForVolume/1-xWaitForVolume_VHD.ps1 => StorageDsc/Examples/Resources/MountImage/3-MountImage_MountVHD.ps1} (76%) rename Modules/{xStorage/Examples/Resources/xOpticalDiskDriveLetter/1-xOpticalDiskDriveLetter_SetDriveLetter.ps1 => StorageDsc/Examples/Resources/OpticalDiskDriveLetter/1-OpticalDiskDriveLetter_SetDriveLetter.ps1} (69%) rename Modules/{xStorage/Examples/Resources/xWaitForDisk/1-xWaitForDisk_InitializeDataDisk.ps1 => StorageDsc/Examples/Resources/WaitForDisk/1-WaitForDisk_InitializeDataDisk.ps1} (82%) rename Modules/{xStorage/Examples/Resources/xWaitForDisk/3-xWaitForDisk_InitializeDataDiskWithAccessPath.ps1 => StorageDsc/Examples/Resources/WaitForDisk/2-WaitForDisk_InitializeDataDiskWithAccessPath.ps1} (74%) rename Modules/{xStorage/Examples/Resources/xDiskAccessPath/1-xDiskAccessPath_InitializeDataDiskWithAccessPath.ps1 => StorageDsc/Examples/Resources/WaitForDisk/3-WaitForDisk_InitializeDataDiskWithAccessPath.ps1} (74%) rename Modules/{xStorage/Examples/Resources/xWaitForDisk/4-xWaitForDisk_InitializeDataDiskWithAccessPathUsingUniqueId.ps1 => StorageDsc/Examples/Resources/WaitForDisk/4-WaitForDisk_InitializeDataDiskWithAccessPathUsingUniqueId.ps1} (80%) rename Modules/{xStorage/Examples/Resources/xMountImage/3-xMountImage_MountVHD.ps1 => StorageDsc/Examples/Resources/WaitForVolume/1-WaitForVolume_VHD.ps1} (76%) rename Modules/{xStorage/Examples/Resources/xWaitForVolume/2-xWaitForVolume_ISO.ps1 => StorageDsc/Examples/Resources/WaitForVolume/2-WaitForVolume_ISO.ps1} (75%) rename Modules/{xStorage => StorageDsc}/Modules/StorageDsc.Common/StorageDsc.Common.psm1 (100%) rename Modules/{xStorage => StorageDsc}/Modules/StorageDsc.Common/en-us/StorageDsc.Common.strings.psd1 (100%) rename Modules/{xStorage => StorageDsc}/Modules/StorageDsc.ResourceHelper/StorageDsc.ResourceHelper.psm1 (100%) rename Modules/{xStorage/xStorage.psd1 => StorageDsc/StorageDsc.psd1} (95%) rename Tests/Integration/{MSFT_xDisk.Integration.Tests.ps1 => MSFT_Disk.Integration.Tests.ps1} (99%) rename Tests/Integration/{MSFT_xDisk.config.ps1 => MSFT_Disk.config.ps1} (82%) rename Tests/Integration/{MSFT_xDiskAccessPath.Integration.Tests.ps1 => MSFT_DiskAccessPath.Integration.Tests.ps1} (99%) rename Tests/Integration/{MSFT_xDiskAccessPath.config.ps1 => MSFT_DiskAccessPath.config.ps1} (76%) rename Tests/Integration/{MSFT_xMountImage_ISO.Integration.Tests.ps1 => MSFT_MountImage_ISO.Integration.Tests.ps1} (97%) rename Tests/Integration/{MSFT_xMountImage_VHD.Integration.Tests.ps1 => MSFT_MountImage_VHD.Integration.Tests.ps1} (97%) rename Tests/Integration/{MSFT_xMountImage_dismount.config.ps1 => MSFT_MountImage_dismount.config.ps1} (64%) rename Tests/Integration/{MSFT_xMountImage_mount.config.ps1 => MSFT_MountImage_mount.config.ps1} (58%) rename Tests/Integration/{MSFT_xOpticalDiskDriveLetter.Integration.Tests.ps1 => MSFT_OpticalDiskDriveLetter.Integration.Tests.ps1} (96%) create mode 100644 Tests/Integration/MSFT_OpticalDiskDriveLetter.config.ps1 rename Tests/Integration/{MSFT_xWaitForDisk.Integration.Tests.ps1 => MSFT_WaitForDisk.Integration.Tests.ps1} (97%) rename Tests/Integration/{MSFT_xWaitForDisk.config.ps1 => MSFT_WaitForDisk.config.ps1} (65%) rename Tests/Integration/{MSFT_xWaitForVolume.Integration.Tests.ps1 => MSFT_WaitForVolume.Integration.Tests.ps1} (94%) rename Tests/Integration/{MSFT_xWaitForVolume.config.ps1 => MSFT_WaitForVolume.config.ps1} (72%) delete mode 100644 Tests/Integration/MSFT_xOpticalDiskDriveLetter.config.ps1 rename Tests/Unit/{MSFT_xDisk.Tests.ps1 => MSFT_Disk.Tests.ps1} (99%) rename Tests/Unit/{MSFT_xDiskAccessPath.Tests.ps1 => MSFT_DiskAccessPath.Tests.ps1} (99%) rename Tests/Unit/{MSFT_xMountImage.Tests.ps1 => MSFT_MountImage.Tests.ps1} (99%) rename Tests/Unit/{MSFT_xOpticalDiskDriveLetter.Tests.ps1 => MSFT_OpticalDiskDriveLetter.Tests.ps1} (97%) rename Tests/Unit/{MSFT_xWaitForDisk.Tests.ps1 => MSFT_WaitForDisk.Tests.ps1} (98%) rename Tests/Unit/{MSFT_xWaitForVolume.Tests.ps1 => MSFT_WaitForVolume.Tests.ps1} (94%) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index f95f6b5f..87c37218 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,7 +1,7 @@ **Details of the scenario you tried and the problem that is occurring:** diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 051c2306..62fe5d56 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,8 @@