diff --git a/DSCResources/MSFT_xDisk/MSFT_xDisk.psm1 b/DSCResources/MSFT_xDisk/MSFT_xDisk.psm1 index ae1cadba..ca82e143 100644 --- a/DSCResources/MSFT_xDisk/MSFT_xDisk.psm1 +++ b/DSCResources/MSFT_xDisk/MSFT_xDisk.psm1 @@ -143,9 +143,31 @@ function Set-TargetResource } else { - Write-Verbose -Message "The volume already exists, adjusting drive letter..." - $VolumeDriveLetter = ($Disk | Get-Partition | Get-Volume).driveletter - Set-Partition -DriveLetter $VolumeDriveLetter -NewDriveLetter $DriveLetter + $Volume = ($Disk | Get-Partition | Get-Volume) + + if ($Volume.DriveLetter) + { + if($Volume.DriveLetter -ne $DriveLetter) + { + Write-Verbose -Message "The volume already exists, adjusting drive letter..." + Set-Partition -DriveLetter $Volume.DriveLetter -NewDriveLetter $DriveLetter + } + } + else + { + # volume doesn't have an assigned letter + Write-Verbose -Message "Assigning drive letter..." + Set-Partition -DiskNumber $DiskNumber -PartitionNumber 2 -NewDriveLetter $DriveLetter + } + + if($PSBoundParameters.ContainsKey('FSLabel')) + { + if($Volume.FileSystemLabel -ne $FSLabel) + { + Write-Verbose -Message "Changing volume '$($Volume.DriveLetter)' label to $FsLabel" + $Volume | Set-Volume -NewFileSystemLabel $FSLabel + } + } } } catch diff --git a/DSCResources/MSFT_xMountImage/MSFT_xMountImage.psm1 b/DSCResources/MSFT_xMountImage/MSFT_xMountImage.psm1 index 4961e402..192d6f30 100644 --- a/DSCResources/MSFT_xMountImage/MSFT_xMountImage.psm1 +++ b/DSCResources/MSFT_xMountImage/MSFT_xMountImage.psm1 @@ -90,8 +90,9 @@ function Set-TargetResource $Image = Mount-DiskImage -ImagePath $ImagePath -PassThru | Get-Volume } - #Verify drive letter - $CimVolume = Get-CimInstance -ClassName Win32_Volume | where {$_.DeviceId -eq $Image.ObjectId} + #Verify drive letter. ObjectId is more verbose than DeviceId in Windows 10 Anniversary Edition, look for + #DeviceId in the ObjectId string to match volumes. + $CimVolume = Get-CimInstance -ClassName Win32_Volume | Where-Object -FilterScript {$Image.ObjectId.IndexOf($_.DeviceId) -ne -1} If($CimVolume.DriveLetter -ne $DriveLetter) { Write-Verbose "Drive letter does not match expected value. Expected DriveLetter $DriveLetter Actual DriverLetter $($CimVolume.DriveLetter)" diff --git a/README.md b/README.md index 0bae67f5..11cd6e1e 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ This module contains the **xMountImage, xDisk, and xWaitForDisk** resources. Th Before beginning that operation, the disk is marked 'Online' and if it is set to 'Read-Only', that property is removed. While this is intended to be non-destructive, as with all expiremental resources the scripts contained should be thoroughly evaluated and well understood before implementing in a production environment or where disk modifications could result in lost data. -**All of the resources in the DSC Resource Kit are provided AS IS, and are not supported through any Microsoft standard support program or service. The "x" in xDiskImage stands for experimental**, which means that these resources will be **fix forward** and monitored by the module owner(s). +**All of the resources in the DSC Resource Kit are provided AS IS, and are not supported through any Microsoft standard support program or service. The "x" in xStorage stands for experimental**, which means that these resources will be **fix forward** and monitored by the module owner(s). Please leave comments, feature requests, and bug reports in the Q & A tab for this module. @@ -27,7 +27,7 @@ To install **xstorage** module - If you are using WMF4 / PowerShell Version 4: Unzip the content under $env:ProgramFilesWindowsPowerShellModules folder -- If you are using WMF5 Preview: From an elevated PowerShell session run ‘Install-Module xDiskImage’ +- If you are using WMF5 Preview: From an elevated PowerShell session run ‘Install-Module xStorage’ To confirm installation @@ -86,10 +86,20 @@ choice We reserve resource and module names without prefixes ("x" or "c") for future use (e.g. "MSFT_Resource"). If the next version of Windows Server ships with a "DiskImage" resource, we don't want to break any configurations that use any community modifications. Please keep a prefix such as "c" on all community modifications. +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. + ## Versions ### Unreleased +### 2.7.0.0 +* Converted appveyor.yml to install Pester from PSGallery instead of from Chocolatey. +* added test for existing file system and no drive letter assignment to allow simple drive letter assignment in MSFT_xDisk.psm1 +* added unit test for volume with existing partition and no drive letter assigned for MSFT_xDisk.psm1 +* xMountImage: Fixed mounting disk images on Windows 10 Anniversary Edition + + ### 2.6.0.0 * MSFT_xDisk: Replaced Get-WmiObject with Get-CimInstance @@ -153,22 +163,22 @@ Configuration DataDisk { DiskNumber = 2 DriveLetter = 'G' - Size = 10GB + Size = 10GB } xDisk JVolume { DiskNumber = 2 DriveLetter = 'J' - FSLabel = 'Data - DependsOn = [xDisk]GVolume + FSLabel = 'Data' + DependsOn = [xDisk]GVolume } xDisk DataVolume { DiskNumber = 3 DriveLetter = 'S' - Size = 100GB + Size = 100GB AllocationUnitSize = 64kb } } diff --git a/Resources/ExampleScript.ps1 b/Resources/ExampleScript.ps1 index be3e3cf5..7504282a 100644 --- a/Resources/ExampleScript.ps1 +++ b/Resources/ExampleScript.ps1 @@ -28,4 +28,4 @@ configuration UnMountISO } UnMountISO -out c:\DSC\ -Start-DscConfiguration -Wait -Force -Path c:\DSC\ -Verbose \ No newline at end of file +Start-DscConfiguration -Wait -Force -Path c:\DSC\ -Verbose diff --git a/Resources/xDscResourceDesigner_CreateScript.ps1 b/Resources/xDscResourceDesigner_CreateScript.ps1 index fe58711f..57b1a407 100644 --- a/Resources/xDscResourceDesigner_CreateScript.ps1 +++ b/Resources/xDscResourceDesigner_CreateScript.ps1 @@ -17,4 +17,4 @@ if (!(test-path (join-path $modules $modulename))) { $P += New-xDscResourceProperty -Name DriveLetter -Type String -Attribute Write -Description 'Specifies the drive letter after the ISO is mounted' $P += New-xDscResourceProperty -Name Ensure -Type String -Attribute Write -ValidateSet 'Present','Absent' -Description 'Determines whether the setting should be applied or removed' New-xDscResource -Name MSFT_xMountImage -Property $P -FriendlyName xMountImage @standard -} \ No newline at end of file +} diff --git a/appveyor.yml b/appveyor.yml index 0fe7423f..82af9a93 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,14 +1,13 @@ #---------------------------------# # environment configuration # #---------------------------------# -version: 2.6.{build}.0 +version: 2.7.{build}.0 install: - - cinst -y pester - - git clone https://github.com/PowerShell/DscResource.Tests - - ps: Push-Location - - cd DscResource.Tests - - ps: Import-Module .\TestHelper.psm1 -force - - ps: Pop-Location + - git clone https://github.com/PowerShell/DscResource.Tests + - ps: | + Import-Module -Name .\DscResource.Tests\TestHelper.psm1 -Force + Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force + Install-Module -Name Pester -Repository PSGallery -Force #---------------------------------# # build configuration # @@ -39,7 +38,7 @@ deploy_script: # Creating project artifact $stagingDirectory = (Resolve-Path ..).Path $manifest = Join-Path $pwd "xStorage.psd1" - (Get-Content $manifest -Raw).Replace("2.6.0.0", $env:APPVEYOR_BUILD_VERSION) | Out-File $manifest + (Get-Content $manifest -Raw).Replace("2.7.0.0", $env:APPVEYOR_BUILD_VERSION) | Out-File $manifest $zipFilePath = Join-Path $stagingDirectory "$(Split-Path $pwd -Leaf).zip" Add-Type -assemblyname System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::CreateFromDirectory($pwd, $zipFilePath) diff --git a/tests/unit/MSFT_xDisk.tests.ps1 b/tests/unit/MSFT_xDisk.tests.ps1 index cdd1a3d2..cf38ed9e 100644 --- a/tests/unit/MSFT_xDisk.tests.ps1 +++ b/tests/unit/MSFT_xDisk.tests.ps1 @@ -9,7 +9,7 @@ Future and therefore should not be altered if possible. #> -$Global:DSCModuleName = 'xDisk' # Example xNetworking +$Global:DSCModuleName = 'xStorage' # Example xNetworking $Global:DSCResourceName = 'MSFT_xDisk' # Example MSFT_xFirewall #region HEADER @@ -65,6 +65,11 @@ try FileSystemLabel='myLabel' DriveLetter='F' } + + $global:mockedVolumeNoLetter = [pscustomobject] @{ + FileSystemLabel='myLabel' + DriveLetter=$null + } #endregion @@ -133,6 +138,7 @@ try Assert-MockCalled -CommandName Get-Volume -Times 0 } } + context 'Test mismatched AllocationUnitSize' { # verifiable (should be called) mocks Mock Get-WmiObject -mockwith {return $global:mockedWmi} @@ -159,6 +165,25 @@ try Assert-MockCalled -CommandName Get-Volume -Times 0 } } + + context 'Test changed FSLabel' { + # verifiable (should be called) mocks + Mock Get-WmiObject -mockwith {return $global:mockedWmi} + Mock Get-CimInstance -mockwith {return $global:mockedWmi} + Mock Get-Disk -mockwith {return $global:mockedDisk0} -verifiable + Mock Get-Partition -mockwith {return $Global:mockedPartition} -verifiable + Mock Get-Volume -mockwith {return $global:mockedVolume} + + $script:result = $null + + it 'calling test should not throw' { + {$script:result = Test-TargetResource -DiskNumber 0 -DriveLetter 'F' -FSLabel 'NewLabel' -verbose} | should not throw + } + + it "result should be false" { + $script:result | should be $false + } + } } #endregion @@ -167,18 +192,18 @@ try Describe "$($Global:DSCResourceName)\Set-TargetResource" { context 'Online Formatted disk' { # verifiable (should be called) mocks - Mock Format-Volume -mockwith {} Mock Get-Disk -mockwith {return $global:mockedDisk0Raw} -verifiable - Mock Initialize-Disk -mockwith {} -verifiable - Mock New-Partition -mockwith {return [pscustomobject] @{DriveLetter='Z'}} Mock Set-Partition -MockWith {} + Mock Get-Partition -mockwith {return $Global:mockedPartition} -verifiable + Mock Get-Volume -mockwith {return $global:mockedVolume} -verifiable # mocks that should not be called Mock Get-WmiObject -mockwith {return $global:mockedWmi} Mock Get-CimInstance -mockwith {return $global:mockedWmi} - Mock Get-Partition -mockwith {return $Global:mockedPartition} -verifiable - Mock Get-Volume -mockwith {return $global:mockedVolume} -verifiable Mock Set-Disk -mockwith {} + Mock Format-Volume -mockwith {} + Mock Initialize-Disk -mockwith {} -verifiable + Mock New-Partition -mockwith {return [pscustomobject] @{DriveLetter='Z'}} it 'Should not throw' { @@ -196,6 +221,40 @@ try Assert-MockCalled -CommandName New-Partition -Times 0 } } + + context 'Online Formatted disk No Drive Letter' { + # verifiable (should be called) mocks + Mock Get-Disk -mockwith {return $global:mockedDisk0Raw} -verifiable + Mock Get-Partition -mockwith {return $Global:mockedPartition} -verifiable + Mock Get-Volume -mockwith {return $global:mockedVolumeNoLetter} -verifiable + Mock Set-Partition -MockWith {} + + + # mocks that should not be called + Mock Get-WmiObject -mockwith {return $global:mockedWmi} + Mock Get-CimInstance -mockwith {return $global:mockedWmi} + Mock Set-Disk -mockwith {} + Mock New-Partition -mockwith {return [pscustomobject] @{DriveLetter='Z'}} + Mock Format-Volume -mockwith {} + Mock Initialize-Disk -mockwith {} -verifiable + + + it 'Should not throw' { + {Set-targetResource -diskNumber 0 -driveletter G -verbose} | should not throw + } + + it "the correct mocks were called" { + Assert-VerifiableMocks + Assert-MockCalled -CommandName Set-Partition -Times 1 -ParameterFilter { $DiskNumber -eq '0' -and $NewDriveLetter -eq 'G' } + Assert-MockCalled -CommandName Format-Volume -Times 0 + Assert-MockCalled -CommandName Get-Volume -Times 2 + Assert-MockCalled -CommandName Get-Partition -Times 2 + Assert-MockCalled -CommandName Set-Disk -Times 0 + Assert-MockCalled -CommandName Get-WmiObject -Times 0 + Assert-MockCalled -CommandName New-Partition -Times 0 + } + } + context 'Online Unformatted disk' { # verifiable (should be called) mocks Mock Format-Volume -mockwith {} @@ -227,6 +286,40 @@ try Assert-MockCalled -CommandName Get-Disk -Times 1 } } + + context 'Set changed FSLabel' { + # verifiable (should be called) mocks + Mock Get-Disk -mockwith {return $global:mockedDisk0Raw} -verifiable + Mock Get-Partition -mockwith {return $Global:mockedPartition} -verifiable + Mock Get-Volume -mockwith {return $global:mockedVolume} -verifiable + Mock Set-Volume -mockwith {return $null} -verifiable + + # mocks that should not be called + Mock Set-Partition -MockWith {} + Mock Get-WmiObject -mockwith {return $global:mockedWmi} + Mock Get-CimInstance -mockwith {return $global:mockedWmi} + Mock Set-Disk -mockwith {} + Mock New-Partition -mockwith {return [pscustomobject] @{DriveLetter='Z'}} + Mock Format-Volume -mockwith {} + Mock Initialize-Disk -mockwith {} -verifiable + + + it 'Should not throw' { + {Set-targetResource -diskNumber 0 -driveletter F -FsLabel 'NewLabel' -verbose} | should not throw + } + + it "the correct mocks were called" { + Assert-VerifiableMocks + Assert-MockCalled -CommandName Set-Volume -Times 1 -ParameterFilter { $NewFileSystemLabel -eq 'NewLabel' } + Assert-MockCalled -CommandName Set-Partition -Times 0 + Assert-MockCalled -CommandName Format-Volume -Times 0 + Assert-MockCalled -CommandName Get-Volume -Times 2 + Assert-MockCalled -CommandName Get-Partition -Times 2 + Assert-MockCalled -CommandName Set-Disk -Times 0 + Assert-MockCalled -CommandName Get-WmiObject -Times 0 + Assert-MockCalled -CommandName New-Partition -Times 0 + } + } # TODO: Complete Tests... } #endregion diff --git a/xStorage.psd1 b/xStorage.psd1 index 77a2e142..68f8fdc3 100644 --- a/xStorage.psd1 +++ b/xStorage.psd1 @@ -10,7 +10,7 @@ # RootModule = '' # Version number of this module. -ModuleVersion = '2.6.0.0' +ModuleVersion = '2.7.0.0' # ID used to uniquely identify this module GUID = '00d73ca1-58b5-46b7-ac1a-5bfcf5814faf' @@ -102,7 +102,11 @@ PrivateData = @{ # IconUri = '' # ReleaseNotes of this module - ReleaseNotes = '* MSFT_xDisk: Replaced Get-WmiObject with Get-CimInstance + ReleaseNotes = '* Converted appveyor.yml to install Pester from PSGallery instead of from Chocolatey. +* added test for existing file system and no drive letter assignment to allow simple drive letter assignment in MSFT_xDisk.psm1 +* added unit test for volume with existing partition and no drive letter assigned for MSFT_xDisk.psm1 +* xMountImage: Fixed mounting disk images on Windows 10 Anniversary Edition + ' @@ -118,3 +122,4 @@ PrivateData = @{ } +