From 2f725596cea6b4db29ecc0dddbb17f3b8d6bc794 Mon Sep 17 00:00:00 2001 From: John Ferlito Date: Sun, 8 Jan 2017 14:27:27 +1100 Subject: [PATCH 01/10] Support setting disk type --- CHANGELOG.md | 2 + DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 | 45 ++++++++- DSCResources/MSFT_xVHD/MSFT_xVHD.schema.mof | 2 +- Examples/Sample_xVHD_DiffVHD.ps1 | 4 + Examples/Sample_xVHD_FixedVHD.ps1 | 44 ++++++++ README.md | 3 + Tests/Unit/MSFT_xVHD.tests.ps1 | 106 ++++++++++++++++++++ 7 files changed, 203 insertions(+), 3 deletions(-) create mode 100644 Examples/Sample_xVHD_FixedVHD.ps1 create mode 100644 Tests/Unit/MSFT_xVHD.tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d1f67..b25a531 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,8 @@ * Updated appveyor.yml to include codecov. * Added .codecov.yml. * Added codecov badges to Readme. +* MSFT_xVHD: + * Support setting the disk type. ## 3.8.0.0 diff --git a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 index d2fb91b..80c33a0 100644 --- a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 +++ b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 @@ -60,6 +60,12 @@ function Set-TargetResource # Size of Vhd to be created [Uint64]$MaximumSizeBytes, + # Type of Vhd to be created + [Parameter()] + [ValidateSet("Dynamic","Fixed","Differencing")] + [String] + $Type = "Dynamic", + # Virtual disk format - Vhd or Vhdx [ValidateSet("Vhd","Vhdx")] [String]$Generation = "Vhd", @@ -75,6 +81,16 @@ function Set-TargetResource Throw "Please ensure that Hyper-V role is installed with its PowerShell module" } + if($ParentPath -and $Type -ne "Differencing") + { + Throw "Parent path is only supported for Differencing disks" + } + + if($null -eq $ParentPath -and $Type -eq "Differencing") + { + Throw "Differencing requires a parent path" + } + # Construct the full path for the vhdFile $vhdName = GetNameWithExtension -Name $Name -Generation $Generation $vhdFilePath = Join-Path -Path $Path -ChildPath $vhdName @@ -135,6 +151,11 @@ function Set-TargetResource Write-Verbose -Message "$vhdFilePath is $Ensure and size is $MaximumSizeBytes." } } + + if($vhd.Type -ne $Type) + { + Throw "This module can't convert disk types" + } } # Vhd file is not present @@ -148,7 +169,12 @@ function Set-TargetResource } else { - $null = New-VHD -Path $vhdFilePath -SizeBytes $MaximumSizeBytes + $params = @{ + Path = $vhdFilePath + SizeBytes = $MaximumSizeBytes + $Type = $True + } + $null = New-VHD @params } Write-Verbose -Message "$vhdFilePath is now $Ensure" } @@ -181,6 +207,11 @@ function Test-TargetResource [ValidateSet("Vhd","Vhdx")] [String]$Generation = "Vhd", + # Type of Vhd to be created + [parameter()] + [ValidateSet("Dynamic","Fixed","Differencing")] + [String]$Type, + # Should the VHD be created or deleted [ValidateSet("Present","Absent")] [String]$Ensure = "Present" @@ -198,7 +229,17 @@ function Test-TargetResource { Throw "Either specify ParentPath or MaximumSizeBytes property." } - + + if($ParentPath -and $Type -ne "Differencing") + { + Throw "Parent path is only supported for Differencing disks" + } + + if($null -eq $ParentPath -and $Type -eq "Differencing") + { + Throw "Differencing requires a parent path" + } + if($ParentPath) { # Ensure only one value is specified - differencing disk or new disk diff --git a/DSCResources/MSFT_xVHD/MSFT_xVHD.schema.mof b/DSCResources/MSFT_xVHD/MSFT_xVHD.schema.mof index ede60f5..f41e9d2 100644 --- a/DSCResources/MSFT_xVHD/MSFT_xVHD.schema.mof +++ b/DSCResources/MSFT_xVHD/MSFT_xVHD.schema.mof @@ -8,7 +8,7 @@ class MSFT_xVHD : OMI_BaseResource [Write, Description("Virtual disk format - Vhd or Vhdx"), ValueMap{"Vhd","Vhdx"}, Values{"Vhd","Vhdx"}] String Generation; [Write, Description("Should the VHD be created or deleted"), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Read, Description("Virtual Disk Identifier")] String ID; - [Read, Description("Type of Vhd - Dynamic, Fixed, Differencing")] String Type; + [Write, Description("Type of Vhd - Dynamic, Fixed, Differencing"), ValueMap{"Dynamic","Fixed","Differencing"}, Values{"Dynamic","Fixed","Differencing"}] String Type; [Read, Description("Current size of the VHD")] Uint64 FileSizeBytes; [Read, Description("Is the VHD attached to a VM or not")] Boolean IsAttached; }; diff --git a/Examples/Sample_xVHD_DiffVHD.ps1 b/Examples/Sample_xVHD_DiffVHD.ps1 index 012c738..fb00c45 100644 --- a/Examples/Sample_xVHD_DiffVHD.ps1 +++ b/Examples/Sample_xVHD_DiffVHD.ps1 @@ -16,6 +16,9 @@ configuration Sample_xVhd_DiffVhd [ValidateSet("Vhd","Vhdx")] [string]$Generation = "Vhd", + [ValidateSet("Dynamic","Fixed","Differencing")] + [string]$Type = "Differencing", + [ValidateSet("Present","Absent")] [string]$Ensure = "Present" ) @@ -38,6 +41,7 @@ configuration Sample_xVhd_DiffVhd Path = $Path ParentPath = $ParentPath Generation = $Generation + Type = $Type DependsOn = '[WindowsFeature]HyperV' } } diff --git a/Examples/Sample_xVHD_FixedVHD.ps1 b/Examples/Sample_xVHD_FixedVHD.ps1 new file mode 100644 index 0000000..a7db420 --- /dev/null +++ b/Examples/Sample_xVHD_FixedVHD.ps1 @@ -0,0 +1,44 @@ +configuration Sample_xVhd_FixedVhd +{ + param + ( + [string[]]$NodeName = 'localhost', + + [Parameter(Mandatory)] + [string]$Name, + + [Parameter(Mandatory)] + [string]$Path, + + [ValidateSet("Vhd","Vhdx")] + [string]$Generation = "Vhd", + + [ValidateSet("Dynamic","Fixed","Differencing")] + [string]$Type = "Fixed", + + [ValidateSet("Present","Absent")] + [string]$Ensure = "Present" + ) + + Import-DscResource -module xHyper-V + + Node $NodeName + { + # Install HyperV feature, if not installed - Server SKU only + WindowsFeature HyperV + { + Ensure = 'Present' + Name = 'Hyper-V' + } + + xVhd DiffVhd + { + Ensure = $Ensure + Name = $Name + Path = $Path + Generation = $Generation + Type = $Type + DependsOn = '[WindowsFeature]HyperV' + } + } +} diff --git a/README.md b/README.md index 94e8a11..9698ad6 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,8 @@ Manages VHDs in a Hyper-V host. * **`[Uint64]` MaximumSizeBytes** _(Write)_: Maximum size of VHD to be created. * **`[String]` Generation** _(Write)_: Virtual disk format. The default value is Vhd. { *Vhd* | Vhdx }. +* **`[String]` Type** _(Write)_: Virtual disk type. + The default value is Dynamic. { *Dynamic* | Fixed | Differencing }. * **`[String]` Ensure** _(Write)_: Ensures that the VHD is Present or Absent. The default value is Present. { *Present* | Absent }. @@ -83,6 +85,7 @@ Manages VHDs in a Hyper-V host. #### Examples xVHD * [Create a new VHD](/Examples/Sample_xVHD_NewVHD.ps1) +* [Create a new Fixed VHD](/Examples/Sample_xVHD_FixedVHD.ps1) * [Create a differencing VHD](/Examples/Sample_xVHD_DiffVHD.ps1) ### xVhdFile diff --git a/Tests/Unit/MSFT_xVHD.tests.ps1 b/Tests/Unit/MSFT_xVHD.tests.ps1 new file mode 100644 index 0000000..13cb96f --- /dev/null +++ b/Tests/Unit/MSFT_xVHD.tests.ps1 @@ -0,0 +1,106 @@ +$script:DSCModuleName = 'xHyper-V' +$script:DSCResourceName = 'MSFT_xVHD' + +#region HEADER +# Unit Test Template Version: 1.1.0 +[String] $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +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 + InModuleScope $script:DSCResourceName { + # Function to create a exception object for testing output exceptions + function Get-InvalidArgumentError + { + [CmdletBinding()] + param + ( + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [System.String] + $ErrorId, + + [Parameter(Mandatory)] + [ValidateNotNullOrEmpty()] + [System.String] + $ErrorMessage + ) + + $exception = New-Object -TypeName System.ArgumentException ` + -ArgumentList $ErrorMessage + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument + $errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord ` + -ArgumentList $exception, $ErrorId, $errorCategory, $null + return $errorRecord + } # end function Get-InvalidArgumentError + + #region Pester Test Initialization + + $script:VMName = 'HyperVUnitTestsVM' + $script:TestISOPath = 'd:\test\test.iso' + + $script:splatParentPathFixed = @{ + Name = 'server' + Path = 'C:\VMs' + ParentPath = 'C:\VMs\Parent' + Type = 'Fixed' + Verbose = $True + } + + $script:splatNoParentPathDifferencing = @{ + Name = 'server' + Path = 'C:\VMs' + Type = 'Differencing' + Verbose = $True + } + + #region Function Set-TargetResource + Describe 'MSFT_xVHD\Set-TargetResource' { + Context 'Parent Path is passed fot a non Differencing disk' { + It 'should throw exception' { + { Set-TargetResource @script:splatParentPathFixed } | Should Throw 'Parent path is only supported for Differencing disks' + } + } + Context 'Differencing disk needs a Parent Path' { + It 'should throw exception' { + { Set-TargetResource @script:splatNoParentPathDifferencing } | Should Throw 'Differencing requires a parent path' + } + } + } + #endregion + + #region Function Test-TargetResource + Describe 'MSFT_xVHD\Test-TargetResource' { + Context 'Parent Path is passed fot a non Differencing disk' { + It 'should throw exception' { + { Test-TargetResource @script:splatParentPathFixed } | Should Throw 'Parent path is only supported for Differencing disks' + } + } + Context 'Differencing disk needs a Parent Path' { + It 'should throw exception' { + { Test-TargetResource @script:splatNoParentPathDifferencing } | Should Throw 'Differencing requires a parent path' + } + } + } + #endregion + } +} +finally +{ + #region FOOTER + Restore-TestEnvironment -TestEnvironment $TestEnvironment + #endregion +} From 36332f4a1f7596d2df62a7983834ceb7b08a9d85 Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Wed, 5 Jul 2017 20:38:38 +0200 Subject: [PATCH 02/10] fixed parameter validation logic (and removed from Set). fixed some of the styling and indentation issues. added comment based help --- DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 | 348 ++++++++++++++++---------- 1 file changed, 210 insertions(+), 138 deletions(-) diff --git a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 index 80c33a0..ea999a6 100644 --- a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 +++ b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 @@ -1,38 +1,61 @@ +<# +.SYNOPSIS + Gets MSFT_xVHD resource current state. + +.PARAMETER Name + The desired VHD file name. + +.PARAMETER Path + The desired Path where the VHD will be created. + +.PARAMETER Generation + Virtual disk format. +#> function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( - [parameter(Mandatory)] - [String]$Name, + [Parameter(Mandatory = $true)] + [String] + $Name, - [parameter(Mandatory)] - [String]$Path, + [Parameter(Mandatory = $true)] + [String] + $Path, - # Virtual disk format - Vhd or Vhdx + [Parameter()] [ValidateSet("Vhd","Vhdx")] - [String]$Generation = "Vhd" + [String] + $Generation = "Vhd" ) - + # Check if Hyper-V module is present for Hyper-V cmdlets if(!(Get-Module -ListAvailable -Name Hyper-V)) { - Throw "Please ensure that Hyper-V role is installed with its PowerShell module" + Throw 'Please ensure that Hyper-V role is installed with its PowerShell module' } - + # Construct the full path for the vhdFile $vhdName = GetNameWithExtension -Name $Name -Generation $Generation $vhdFilePath = Join-Path -Path $Path -ChildPath $vhdName - Write-Debug -Message "Vhd full path is $vhdFilePath" + Write-Verbose -Message "Vhd full path is $vhdFilePath" $vhd = Get-VHD -Path $vhdFilePath -ErrorAction SilentlyContinue + + $ensure = 'Absent' + if ($vhd) + { + $ensure = 'Present' + } + @{ Name = $Name Path = $Path ParentPath = $vhd.ParentPath Generation = $vhd.VhdFormat - Ensure = if($vhd){"Present"}else{"Absent"} + Ensure = $ensure ID = $vhd.DiskIdentifier Type = $vhd.VhdType FileSizeBytes = $vhd.FileSize @@ -41,127 +64,138 @@ function Get-TargetResource } } +<# +.SYNOPSIS + Configures MSFT_xVHD resource state. + +.PARAMETER Name + The desired VHD file name. + +.PARAMETER Path + The desired Path where the VHD will be created. + +.PARAMETER ParentPath + Parent VHD file path, for differencing disk. + +.PARAMETER MaximumSizeBytes + Maximum size of VHD to be created. + +.PARAMETER Type + Virtual disk type. + +.PARAMETER Generation + Virtual disk format. + +.PARAMETER Ensure + Ensures that the VHD is Present or Absent. +#> function Set-TargetResource { [CmdletBinding()] param ( - # Name of the VHD File - [parameter(Mandatory)] - [String]$Name, + [Parameter(Mandatory = $true)] + [String] + $Name, - # Folder where the VHD will be created - [parameter(Mandatory)] - [String]$Path, + [Parameter(Mandatory = $true)] + [String] + $Path, - # Parent VHD file path, for differencing disk - [String]$ParentPath, + [Parameter()] + [String] + $ParentPath, - # Size of Vhd to be created - [Uint64]$MaximumSizeBytes, + [Parameter()] + [Uint64] + $MaximumSizeBytes, - # Type of Vhd to be created [Parameter()] - [ValidateSet("Dynamic","Fixed","Differencing")] + [ValidateSet('Dynamic', 'Fixed', 'Differencing')] [String] - $Type = "Dynamic", + $Type = 'Dynamic', - # Virtual disk format - Vhd or Vhdx - [ValidateSet("Vhd","Vhdx")] - [String]$Generation = "Vhd", + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [String] + $Generation = 'Vhd', - # Should the VHD be created or deleted - [ValidateSet("Present","Absent")] - [String]$Ensure = "Present" + [Parameter()] + [ValidateSet('Present', 'Absent')] + [String] + $Ensure = 'Present' ) - - # Check if Hyper-V module is present for Hyper-V cmdlets - if(!(Get-Module -ListAvailable -Name Hyper-V)) - { - Throw "Please ensure that Hyper-V role is installed with its PowerShell module" - } - - if($ParentPath -and $Type -ne "Differencing") - { - Throw "Parent path is only supported for Differencing disks" - } - - if($null -eq $ParentPath -and $Type -eq "Differencing") - { - Throw "Differencing requires a parent path" - } # Construct the full path for the vhdFile $vhdName = GetNameWithExtension -Name $Name -Generation $Generation $vhdFilePath = Join-Path -Path $Path -ChildPath $vhdName - Write-Debug -Message "Vhd full path is $vhdFilePath" + Write-Verbose -Message "Vhd full path is $vhdFilePath" Write-Verbose -Message "Checking if $vhdFilePath is $Ensure ..." # If vhd should be absent, delete it - if($Ensure -eq "Absent") + if($Ensure -eq 'Absent') { - if (Test-Path $vhdFilePath) + if (Test-Path -Path $vhdFilePath) { Write-Verbose -Message "$vhdFilePath is not $Ensure" - Remove-Item -Path $vhdFilePath -Force -ErrorAction Stop + Remove-Item -Path $vhdFilePath -Force -ErrorAction Stop } Write-Verbose -Message "$vhdFilePath is $Ensure" - } + } else { # Check if the Vhd is present try { - $vhd = Get-VHD -Path $vhdFilePath -ErrorAction Stop + $vhd = Get-VHD -Path $vhdFilePath -ErrorAction Stop + + # If this is a differencing disk, check the parent path + if($ParentPath) + { + Write-Verbose -Message "Checking if $vhdFilePath parent path is $ParentPath ..." - # If this is a differencing disk, check the parent path - if($ParentPath) + # If the parent path is not set correct, fix it + if($vhd.ParentPath -ne $ParentPath) { - Write-Verbose -Message "Checking if $vhdFilePath parent path is $ParentPath ..." - - # If the parent path is not set correct, fix it - if($vhd.ParentPath -ne $ParentPath) - { - Write-Verbose -Message "$vhdFilePath parent path is not $ParentPath." - Set-VHD -Path $vhdFilePath -ParentPath $ParentPath - Write-Verbose -Message "$vhdFilePath parent path is now $ParentPath." - } - else - { - Write-Verbose -Message "$vhdFilePath is $Ensure and parent path is set to $ParentPath." - } + Write-Verbose -Message "$vhdFilePath parent path is not $ParentPath." + Set-VHD -Path $vhdFilePath -ParentPath $ParentPath + Write-Verbose -Message "$vhdFilePath parent path is now $ParentPath." } - - # This is a fixed disk, check the size else { - Write-Verbose -Message "Checking if $vhdFilePath size is $MaximumSizeBytes ..." - - # If the size is not correct, fix it - if($vhd.Size -ne $MaximumSizeBytes) - { - Write-Verbose -Message "$vhdFilePath size is not $MaximumSizeBytes." - Resize-VHD -Path $vhdFilePath -SizeBytes $MaximumSizeBytes - Write-Verbose -Message "$vhdFilePath size is now $MaximumSizeBytes." - } - else - { - Write-Verbose -Message "$vhdFilePath is $Ensure and size is $MaximumSizeBytes." - } + Write-Verbose -Message "$vhdFilePath is $Ensure and parent path is set to $ParentPath." } + } - if($vhd.Type -ne $Type) + # This is a fixed disk, check the size + else + { + Write-Verbose -Message "Checking if $vhdFilePath size is $MaximumSizeBytes ..." + + # If the size is not correct, fix it + if($vhd.Size -ne $MaximumSizeBytes) + { + Write-Verbose -Message "$vhdFilePath size is not $MaximumSizeBytes." + Resize-VHD -Path $vhdFilePath -SizeBytes $MaximumSizeBytes + Write-Verbose -Message "$vhdFilePath size is now $MaximumSizeBytes." + } + else { - Throw "This module can't convert disk types" + Write-Verbose -Message "$vhdFilePath is $Ensure and size is $MaximumSizeBytes." } - } + } - # Vhd file is not present - catch [System.Management.Automation.ActionPreferenceStopException] - { - + if($vhd.Type -ne $Type) + { + Throw 'This module can''t convert disk types' + } + } + + # Vhd file is not present + catch + { Write-Verbose -Message "$vhdFilePath is not $Ensure" if($ParentPath) { @@ -177,67 +211,93 @@ function Set-TargetResource $null = New-VHD @params } Write-Verbose -Message "$vhdFilePath is now $Ensure" + } } - - } - } +<# +.SYNOPSIS + Tests if MSFT_xVHD resource state is in the desired state or not. + +.PARAMETER Name + The desired VHD file name. + +.PARAMETER Path + The desired Path where the VHD will be created. + +.PARAMETER ParentPath + Parent VHD file path, for differencing disk. + +.PARAMETER MaximumSizeBytes + Maximum size of VHD to be created. + +.PARAMETER Type + Virtual disk type. + +.PARAMETER Generation + Virtual disk format. + +.PARAMETER Ensure + Ensures that the VHD is Present or Absent. +#> function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( - # Name of the VHD File - [parameter(Mandatory)] - [String]$Name, + [Parameter(Mandatory = $true)] + [String] + $Name, - # Folder where the VHD will be created - [parameter(Mandatory)] - [String]$Path, + [Parameter(Mandatory = $true)] + [String] + $Path, - # Parent VHD file path, for differencing disk - [String]$ParentPath, + [Parameter()] + [String] + $ParentPath, - # Size of Vhd to be created - [Uint64]$MaximumSizeBytes, + [Parameter()] + [Uint64] + $MaximumSizeBytes, - # Virtual disk format - Vhd or Vhdx - [ValidateSet("Vhd","Vhdx")] - [String]$Generation = "Vhd", + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [String] + $Generation = 'Vhd', - # Type of Vhd to be created - [parameter()] - [ValidateSet("Dynamic","Fixed","Differencing")] - [String]$Type, + [Parameter()] + [ValidateSet('Dynamic', 'Fixed', 'Differencing')] + [String] + $Type, - # Should the VHD be created or deleted - [ValidateSet("Present","Absent")] - [String]$Ensure = "Present" + [Parameter()] + [ValidateSet('Present', 'Absent')] + [String] + $Ensure = 'Present' ) - #region input validation - # Check if Hyper-V module is present for Hyper-V cmdlets if(!(Get-Module -ListAvailable -Name Hyper-V)) { Throw "Please ensure that Hyper-V role is installed with its PowerShell module" } - if(! ($ParentPath -or $MaximumSizeBytes)) + # input validation + if($Type -ne 'Differencing' -and -not $MaximumSizeBytes) { - Throw "Either specify ParentPath or MaximumSizeBytes property." + Throw 'Specify MaximumSizeBytes property for Fixed and Dynamic VHDs.' } - if($ParentPath -and $Type -ne "Differencing") + if($ParentPath -and $Type -ne 'Differencing') { - Throw "Parent path is only supported for Differencing disks" + Throw 'Parent path is only supported for Differencing disks' } - if($null -eq $ParentPath -and $Type -eq "Differencing") + if(-not $ParentPath -and $Type -eq 'Differencing') { - Throw "Differencing requires a parent path" + Throw 'Differencing requires a parent path' } if($ParentPath) @@ -245,20 +305,21 @@ function Test-TargetResource # Ensure only one value is specified - differencing disk or new disk if($MaximumSizeBytes) { - Throw "Cannot specify both ParentPath and MaximumSizeBytes. Specify only one and try again." + Throw 'Cannot specify both ParentPath and MaximumSizeBytes. Specify only one and try again.' } - - if(! (Test-Path -Path $ParentPath)) + + if(!(Test-Path -Path $ParentPath)) { Throw "$ParentPath does not exists" } - + # Check if the generation matches parenting disk if($Generation -and ($ParentPath.Split('.')[-1] -ne $Generation)) { Throw "Generation $geneartion should match ParentPath extension $($ParentPath.Split('.')[-1])" } } + if(!(Test-Path -Path $Path)) { Throw "$Path does not exists" @@ -267,7 +328,7 @@ function Test-TargetResource # Construct the full path for the vhdFile $vhdName = GetNameWithExtension -Name $Name -Generation $Generation $vhdFilePath = Join-Path -Path $Path -ChildPath $vhdName - Write-Debug -Message "Vhd full path is $vhdFilePath" + Write-Verbose -Message "Vhd full path is $vhdFilePath" # Add the logic here and at the end return either $true or $false. $result = Test-VHD -Path $vhdFilePath -ErrorAction SilentlyContinue @@ -275,16 +336,28 @@ function Test-TargetResource return ($result -and ($Ensure -eq "Present")) } -# Appends the generation to the name provided if it is not part of the name already. +<# +.SYNOPSIS + Appends generation appropriate file extension if not already specified. + +.PARAMETER Name + The desired VHD file name. + +.PARAMETER Generation + Virtual disk format. +#> function GetNameWithExtension { - param( - # Name of the VHD File - [parameter(Mandatory)] - [String]$Name, - [parameter(Mandatory)] - [String]$Generation ='Vhd' - ) + param + ( + [Parameter(Mandatory = $true)] + [String] + $Name, + + [Parameter(Mandatory = $true)] + [String] + $Generation = 'Vhd' + ) # If the name ends with vhd or vhdx don't append the generation to the vhdname. if ($Name -like '*.vhd' -or $Name -like '*.vhdx') @@ -295,8 +368,8 @@ function GetNameWithExtension throw "the extension $extension on the name does match the generation $Generation" } else - { - Write-Debug -Message "Vhd full name is $vhdName" + { + Write-Verbose -Message "Vhd full name is $vhdName" $vhdName = $Name } } @@ -304,11 +377,10 @@ function GetNameWithExtension { # Append generation to the name $vhdName = "$Name.$Generation" - Write-Debug -Message "Vhd full name is $vhdName" + Write-Verbose -Message "Vhd full name is $vhdName" } - return $vhdName + $vhdName } Export-ModuleMember -Function *-TargetResource - From 5a56a9f879bb58433646ef2b7469d6104ccbfa8d Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Wed, 5 Jul 2017 21:36:33 +0200 Subject: [PATCH 03/10] removed parameter validation which couldn't be reached anymore --- DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 index ea999a6..090e6bb 100644 --- a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 +++ b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 @@ -270,7 +270,7 @@ function Test-TargetResource [Parameter()] [ValidateSet('Dynamic', 'Fixed', 'Differencing')] [String] - $Type, + $Type = 'Dynamic', [Parameter()] [ValidateSet('Present', 'Absent')] @@ -302,12 +302,6 @@ function Test-TargetResource if($ParentPath) { - # Ensure only one value is specified - differencing disk or new disk - if($MaximumSizeBytes) - { - Throw 'Cannot specify both ParentPath and MaximumSizeBytes. Specify only one and try again.' - } - if(!(Test-Path -Path $ParentPath)) { Throw "$ParentPath does not exists" From 0e5da37e8b17ae0721c8b3beb8a32e44eb061dcb Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Wed, 5 Jul 2017 21:40:53 +0200 Subject: [PATCH 04/10] changed to make use of unit test template 1.2.0 and adjusted tests to check parameter conditions --- Tests/Unit/MSFT_xVHD.tests.ps1 | 116 +++++++++++---------------------- 1 file changed, 38 insertions(+), 78 deletions(-) diff --git a/Tests/Unit/MSFT_xVHD.tests.ps1 b/Tests/Unit/MSFT_xVHD.tests.ps1 index 13cb96f..b9101be 100644 --- a/Tests/Unit/MSFT_xVHD.tests.ps1 +++ b/Tests/Unit/MSFT_xVHD.tests.ps1 @@ -1,106 +1,66 @@ -$script:DSCModuleName = 'xHyper-V' -$script:DSCResourceName = 'MSFT_xVHD' - #region HEADER -# Unit Test Template Version: 1.1.0 -[String] $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) + +# Unit Test Template Version: 1.2.0 +$script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) 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 +Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force + $TestEnvironment = Initialize-TestEnvironment ` - -DSCModuleName $script:DSCModuleName ` - -DSCResourceName $script:DSCResourceName ` + -DSCModuleName 'xHyper-V' ` + -DSCResourceName 'MSFT_xVHD' ` -TestType Unit + #endregion HEADER -# Begin Testing -try +function Invoke-TestSetup { - #region Pester Tests - InModuleScope $script:DSCResourceName { - # Function to create a exception object for testing output exceptions - function Get-InvalidArgumentError - { - [CmdletBinding()] - param - ( - [Parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [System.String] - $ErrorId, - - [Parameter(Mandatory)] - [ValidateNotNullOrEmpty()] - [System.String] - $ErrorMessage - ) - $exception = New-Object -TypeName System.ArgumentException ` - -ArgumentList $ErrorMessage - $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidArgument - $errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord ` - -ArgumentList $exception, $ErrorId, $errorCategory, $null - return $errorRecord - } # end function Get-InvalidArgumentError +} - #region Pester Test Initialization +function Invoke-TestCleanup +{ + Restore-TestEnvironment -TestEnvironment $TestEnvironment +} - $script:VMName = 'HyperVUnitTestsVM' - $script:TestISOPath = 'd:\test\test.iso' +# Begin Testing +try +{ + Invoke-TestSetup - $script:splatParentPathFixed = @{ - Name = 'server' - Path = 'C:\VMs' - ParentPath = 'C:\VMs\Parent' - Type = 'Fixed' - Verbose = $True - } + InModuleScope 'MSFT_xVHD' { - $script:splatNoParentPathDifferencing = @{ - Name = 'server' - Path = 'C:\VMs' - Type = 'Differencing' - Verbose = $True - } + Describe 'MSFT_xVHD\Test-TargetResource' { - #region Function Set-TargetResource - Describe 'MSFT_xVHD\Set-TargetResource' { - Context 'Parent Path is passed fot a non Differencing disk' { - It 'should throw exception' { - { Set-TargetResource @script:splatParentPathFixed } | Should Throw 'Parent path is only supported for Differencing disks' - } + # Mocks "Get-Module -Name Hyper-V" so that the DSC resource thinks the Hyper-V module is on the test system + Mock -CommandName Get-Module -ParameterFilter { ($Name -eq 'Hyper-V') -and ($ListAvailable -eq $true) } -MockWith { + return $true } - Context 'Differencing disk needs a Parent Path' { - It 'should throw exception' { - { Set-TargetResource @script:splatNoParentPathDifferencing } | Should Throw 'Differencing requires a parent path' + + Context 'Parameter validation' { + It 'Fixed and Dynamic VHDs need MaximumSizeBytes specified' { + { Test-TargetResource -Name 'server' -Path 'C:\VMs' -Type 'Dynamic' } | + Should Throw 'Specify MaximumSizeBytes property for Fixed and Dynamic VHDs.' } - } - } - #endregion - #region Function Test-TargetResource - Describe 'MSFT_xVHD\Test-TargetResource' { - Context 'Parent Path is passed fot a non Differencing disk' { - It 'should throw exception' { - { Test-TargetResource @script:splatParentPathFixed } | Should Throw 'Parent path is only supported for Differencing disks' + It 'Parent Path is passed for a non Differencing disk' { + { Test-TargetResource -Name 'server' -Path 'C:\VMs' -ParentPath 'C:\VMs\Parent' -Type 'Fixed' -MaximumSizeBytes 1GB } | + Should Throw 'Parent path is only supported for Differencing disks' } - } - Context 'Differencing disk needs a Parent Path' { - It 'should throw exception' { - { Test-TargetResource @script:splatNoParentPathDifferencing } | Should Throw 'Differencing requires a parent path' + + It 'Differencing disk needs a Parent Path' { + { Test-TargetResource -Name 'server' -Path 'C:\VMs' -Type 'Differencing' } | + Should Throw 'Differencing requires a parent path' } } } - #endregion } } finally { - #region FOOTER - Restore-TestEnvironment -TestEnvironment $TestEnvironment - #endregion + Invoke-TestCleanup } From cf3f1d76f46bfff5536b41364258ddfd5818fdcd Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Thu, 6 Jul 2017 22:44:20 +0200 Subject: [PATCH 05/10] added test for coverage of Test-TargetResource and GetNameWithExtension. Fixed throw messages --- DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 | 4 +- Tests/Unit/MSFT_xVHD.tests.ps1 | 107 ++++++++++++++++++++++++++ 2 files changed, 109 insertions(+), 2 deletions(-) diff --git a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 index 090e6bb..e5d330c 100644 --- a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 +++ b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 @@ -310,7 +310,7 @@ function Test-TargetResource # Check if the generation matches parenting disk if($Generation -and ($ParentPath.Split('.')[-1] -ne $Generation)) { - Throw "Generation $geneartion should match ParentPath extension $($ParentPath.Split('.')[-1])" + Throw "Generation $Generation should match ParentPath extension $($ParentPath.Split('.')[-1])" } } @@ -359,7 +359,7 @@ function GetNameWithExtension $extension = $Name.Split('.')[-1] if ($Generation -ne $extension) { - throw "the extension $extension on the name does match the generation $Generation" + throw "the extension $extension on the name does not match the generation $Generation" } else { diff --git a/Tests/Unit/MSFT_xVHD.tests.ps1 b/Tests/Unit/MSFT_xVHD.tests.ps1 index b9101be..566c4bc 100644 --- a/Tests/Unit/MSFT_xVHD.tests.ps1 +++ b/Tests/Unit/MSFT_xVHD.tests.ps1 @@ -34,7 +34,53 @@ try InModuleScope 'MSFT_xVHD' { + Describe 'MSFT_xVHD\GetNameWithExtension' { + Context 'Name does not have extension' { + It 'Should return server.vhdx with generation vhdx' { + GetNameWithExtension -Name 'server' -Generation 'vhdx' | + Should Be 'server.vhdx' + } + + It 'Should return server.vhd with generation vhd' { + GetNameWithExtension -Name 'server' -Generation 'vhd' | + Should Be 'server.vhd' + } + + It 'Should not throw' { + { GetNameWithExtension -Name 'server' -Generation 'vhd' } | + Should Not Throw + } + } + + Context 'Name has extension' { + It 'Should return server.vhdx with Name server.vhdx and generation vhdx' { + GetNameWithExtension -Name 'server.vhd' -Generation 'vhd' | + Should Be 'server.vhd' + } + + It 'Should throw with mismatch with extension from name and generation' { + { GetNameWithExtension -Name 'server.vhdx' -Generation 'vhd' } | + Should Throw 'the extension vhdx on the name does not match the generation vhd' + } + } + } + Describe 'MSFT_xVHD\Test-TargetResource' { + # Create an empty function to be able to mock the missing Hyper-V cmdlet + function Test-VHD + { + + } + + Context 'Should stop when Hyper-V module is missing' { + Mock -CommandName Get-Module -ParameterFilter { ($Name -eq 'Hyper-V') -and ($ListAvailable -eq $true) } -MockWith { + return $false + } + It 'Should throw when the module is missing' { + { Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB } | + Should Throw 'Please ensure that Hyper-V role is installed with its PowerShell module' + } + } # Mocks "Get-Module -Name Hyper-V" so that the DSC resource thinks the Hyper-V module is on the test system Mock -CommandName Get-Module -ParameterFilter { ($Name -eq 'Hyper-V') -and ($ListAvailable -eq $true) } -MockWith { @@ -57,6 +103,67 @@ try Should Throw 'Differencing requires a parent path' } } + + Context 'ParentPath specified' { + Mock -CommandName Test-Path -MockWith { $false } + It 'Should throw when ParentPath does not exist' { + { Test-TargetResource -Name 'server' -Path 'C:\VMs' -Type 'Differencing' -ParentPath 'c:\boguspath' } | + Should Throw 'c:\boguspath does not exists' + } + + #"Generation $Generation should match ParentPath extension $($ParentPath.Split('.')[-1])" + Mock -CommandName Test-Path -MockWith { $true } + It 'Should throw when file extension and generation have a mismatch' { + { Test-TargetResource -Name 'server' -Path 'C:\VMs' -Type 'Differencing' -ParentPath 'c:\boguspath.vhd' -Generation 'Vhdx' } | + Should Throw 'Generation Vhdx should match ParentPath extension vhd' + } + } + + Context 'Path does not exist' { + It 'Should throw when the path does not exist' { + Mock -CommandName Test-Path -MockWith { $false } + { Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB } | + Should Throw 'C:\VMs does not exists' + } + } + + Context 'Vhd exists' { + BeforeEach { + Mock -CommandName Test-Path -MockWith { $true } + Mock -CommandName GetNameWithExtension -MockWith { 'server.vhdx' } + Mock -CommandName Test-VHD -MockWith { $true } + } + + It 'Should not throw' { + { Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB } | + Should not Throw + } + + It 'Should return a boolean and it should be true' { + $testResult = Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB + $testResult | Should BeOfType bool + $testResult -eq $true | Should Be $true + } + } + + Context 'Vhd does not exist' { + BeforeEach { + Mock -CommandName Test-Path -MockWith { $true } + Mock -CommandName GetNameWithExtension -MockWith { 'server.vhdx' } + Mock -CommandName Test-VHD -MockWith { $false } + } + + It 'Should not throw' { + { Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB } | + Should not Throw + } + + It 'Should return a boolean and it should be false' { + $testResult = Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB + $testResult | Should BeOfType bool + $testResult -eq $true | Should Be $false + } + } } } } From 84c4c0c617f0d21446c159d190890c76bd6a06be Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Thu, 6 Jul 2017 23:34:44 +0200 Subject: [PATCH 06/10] added testcases for Get-TargetResource --- Tests/Unit/MSFT_xVHD.tests.ps1 | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/Tests/Unit/MSFT_xVHD.tests.ps1 b/Tests/Unit/MSFT_xVHD.tests.ps1 index 566c4bc..e1b4623 100644 --- a/Tests/Unit/MSFT_xVHD.tests.ps1 +++ b/Tests/Unit/MSFT_xVHD.tests.ps1 @@ -33,6 +33,54 @@ try Invoke-TestSetup InModuleScope 'MSFT_xVHD' { + Describe 'MSFT_xVHD\Get-TargetResource' { + # Create an empty function to be able to mock the missing Hyper-V cmdlet + function Get-VHD + { + + } + + Context 'Should stop when Hyper-V module is missing' { + Mock -CommandName Get-Module -ParameterFilter { ($Name -eq 'Hyper-V') -and ($ListAvailable -eq $true) } -MockWith { + return $false + } + It 'Should throw when the module is missing' { + { Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB } | + Should Throw 'Please ensure that Hyper-V role is installed with its PowerShell module' + } + } + + # Mocks "Get-Module -Name Hyper-V" so that the DSC resource thinks the Hyper-V module is on the test system + Mock -CommandName Get-Module -ParameterFilter { ($Name -eq 'Hyper-V') -and ($ListAvailable -eq $true) } -MockWith { + return $true + } + + Mock -CommandName GetNameWithExtension -MockWith { 'server.vhdx' } + + Context 'VHD Present' { + It 'Should return a hashtable with Ensure being Present' { + Mock -CommandName Get-VHD -MockWith { + [pscustomobject]@{ + Path = 'server.vhdx' + } + } + + $getTargetResult = Get-TargetResource -Name 'server' -Path 'c:\boguspath' -Generation 'vhdx' + $getTargetResult.Ensure | Should Be 'Present' + $getTargetResult | Should BeOfType hashtable + } + } + + Context 'VHD Not Present' { + It 'Should return a hashtable with Ensure being Absent' { + Mock -CommandName Get-VHD + + $getTargetResult = Get-TargetResource -Name 'server' -Path 'c:\boguspath' -Generation 'vhdx' + $getTargetResult.Ensure | Should Be 'Absent' + $getTargetResult | Should BeOfType hashtable + } + } + } Describe 'MSFT_xVHD\GetNameWithExtension' { Context 'Name does not have extension' { From 5fd5a0072558aca937c1d3b42b66896cb5ece04e Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Fri, 7 Jul 2017 14:48:44 +0200 Subject: [PATCH 07/10] fixed bug where incorrect type threw an error instead of stopping the process. Fixed a bug when MaximumSizeBytes was not specified, resize was wrongly initialized. --- DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 index e5d330c..787c965 100644 --- a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 +++ b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 @@ -170,7 +170,7 @@ function Set-TargetResource } # This is a fixed disk, check the size - else + elseif ($PSBoundParameters.ContainsKey('MaximumSizeBytes')) { Write-Verbose -Message "Checking if $vhdFilePath size is $MaximumSizeBytes ..." @@ -189,7 +189,7 @@ function Set-TargetResource if($vhd.Type -ne $Type) { - Throw 'This module can''t convert disk types' + Write-Verbose -Message 'This module can''t convert disk types' } } From bb5ac47764d6f1efea17f03e7f9fad6f1bd7b7d6 Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Fri, 7 Jul 2017 14:48:59 +0200 Subject: [PATCH 08/10] added Set test cases --- Tests/Unit/MSFT_xVHD.tests.ps1 | 74 ++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/Tests/Unit/MSFT_xVHD.tests.ps1 b/Tests/Unit/MSFT_xVHD.tests.ps1 index e1b4623..b4a22ca 100644 --- a/Tests/Unit/MSFT_xVHD.tests.ps1 +++ b/Tests/Unit/MSFT_xVHD.tests.ps1 @@ -213,6 +213,80 @@ try } } } + + Describe 'MSFT_xVHD\Set-TargetResource' { + # Create an empty function to be able to mock the missing Hyper-V cmdlet + function Get-VHD + { + + } + + function Set-VHD + { + + } + + function Resize-VHD + { + + } + + function New-VHD + { + + } + + Context 'Ensure is Absent' { + Mock -CommandName Test-Path -MockWith { $true } + Mock -CommandName Remove-Item + Mock -CommandName GetNameWithExtension -MockWith { 'server.vhdx' } + + It 'Should remove when Ensure is Absent and vhdx exists' { + $null = Set-TargetResource -Name 'server.vhdx' -Path 'TestDrive:\' -Ensure 'Absent' + Assert-MockCalled -CommandName Remove-Item -Times 1 -Exactly + } + } + + Context 'Ensure is Present' { + BeforeEach { + Mock -CommandName Get-VHD -MockWith { + [pscustomobject]@{ + Path = 'server.vhdx' + ParentPath = 'c:\boguspath\server.vhdx' + Size = 1073741824 + Type = 'Differencing' + } + } + + Mock -CommandName Set-VHD + Mock -CommandName Resize-VHD + Mock -CommandName GetNameWithExtension -MockWith { 'server.vhdx' } + Mock -CommandName New-VHD -MockWith { } + } + + It 'Should Create a VHD when Ensure is present and no VHD exists yet for non Differencing disk' { + Mock -CommandName Get-VHD -MockWith { throw } + $null = Set-TargetResource -Name 'server.vhdx' -Path 'TestDrive:\' -Ensure 'Present' + Assert-MockCalled -CommandName New-VHD -Exactly -Times 1 -Scope It + } + + It 'Should Create a VHD when Ensure is present and no VHD exists yet for Differencing disk' { + Mock -CommandName Get-VHD -MockWith { throw } + $null = Set-TargetResource -Name 'server.vhdx' -Path 'TestDrive:\' -Ensure 'Present' -ParentPath 'c:\boguspath\server.vhdx' -Type 'Differencing' + Assert-MockCalled -CommandName New-VHD -Exactly -Times 1 -Scope It + } + + It 'Should resize a VHD which has a different size as intended' { + $null = Set-TargetResource -Name 'server.vhdx' -Path 'TestDrive:\' -MaximumSizeBytes 2GB -Ensure 'Present' + Assert-MockCalled -CommandName Resize-VHD -Exactly -Times 1 -Scope It + } + + It 'Should update the parentpath if it is different from intent' { + $null = Set-TargetResource -Name 'server.vhdx' -Path 'TestDrive:\' -ParentPath 'c:\boguspath2\server.vhdx' -Ensure 'Present' + Assert-MockCalled -CommandName Set-VHD -Exactly -Times 1 -Scope It + } + } + } } } finally From 1da8a251ae33f46a7dc5acb52281221f202b2425 Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Sat, 8 Jul 2017 10:18:57 +0200 Subject: [PATCH 09/10] fixes on reviewable comments @PlagueHO --- CHANGELOG.md | 3 ++ DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 | 31 +++++++-------- Examples/Sample_xVHD_FixedVHD.ps1 | 54 +++++++++++++++++---------- Tests/Unit/MSFT_xVHD.tests.ps1 | 13 +++++-- 4 files changed, 64 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b25a531..339de78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,9 @@ * Added codecov badges to Readme. * MSFT_xVHD: * Support setting the disk type. + * Added unit tests. + * Added example Sample\_xVHD\_FixedVHD.ps1 + * Style fixes ## 3.8.0.0 diff --git a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 index 787c965..f1e769c 100644 --- a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 +++ b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 @@ -32,7 +32,7 @@ function Get-TargetResource ) # Check if Hyper-V module is present for Hyper-V cmdlets - if(!(Get-Module -ListAvailable -Name Hyper-V)) + if (!(Get-Module -ListAvailable -Name Hyper-V)) { Throw 'Please ensure that Hyper-V role is installed with its PowerShell module' } @@ -134,7 +134,7 @@ function Set-TargetResource Write-Verbose -Message "Checking if $vhdFilePath is $Ensure ..." # If vhd should be absent, delete it - if($Ensure -eq 'Absent') + if ($Ensure -eq 'Absent') { if (Test-Path -Path $vhdFilePath) { @@ -152,12 +152,12 @@ function Set-TargetResource $vhd = Get-VHD -Path $vhdFilePath -ErrorAction Stop # If this is a differencing disk, check the parent path - if($ParentPath) + if ($ParentPath) { Write-Verbose -Message "Checking if $vhdFilePath parent path is $ParentPath ..." # If the parent path is not set correct, fix it - if($vhd.ParentPath -ne $ParentPath) + if ($vhd.ParentPath -ne $ParentPath) { Write-Verbose -Message "$vhdFilePath parent path is not $ParentPath." Set-VHD -Path $vhdFilePath -ParentPath $ParentPath @@ -175,7 +175,7 @@ function Set-TargetResource Write-Verbose -Message "Checking if $vhdFilePath size is $MaximumSizeBytes ..." # If the size is not correct, fix it - if($vhd.Size -ne $MaximumSizeBytes) + if ($vhd.Size -ne $MaximumSizeBytes) { Write-Verbose -Message "$vhdFilePath size is not $MaximumSizeBytes." Resize-VHD -Path $vhdFilePath -SizeBytes $MaximumSizeBytes @@ -187,7 +187,7 @@ function Set-TargetResource } } - if($vhd.Type -ne $Type) + if ($vhd.Type -ne $Type) { Write-Verbose -Message 'This module can''t convert disk types' } @@ -197,7 +197,7 @@ function Set-TargetResource catch { Write-Verbose -Message "$vhdFilePath is not $Ensure" - if($ParentPath) + if ($ParentPath) { $null = New-VHD -Path $vhdFilePath -ParentPath $ParentPath } @@ -210,6 +210,7 @@ function Set-TargetResource } $null = New-VHD @params } + Write-Verbose -Message "$vhdFilePath is now $Ensure" } } @@ -279,42 +280,42 @@ function Test-TargetResource ) # Check if Hyper-V module is present for Hyper-V cmdlets - if(!(Get-Module -ListAvailable -Name Hyper-V)) + if (!(Get-Module -ListAvailable -Name Hyper-V)) { Throw "Please ensure that Hyper-V role is installed with its PowerShell module" } # input validation - if($Type -ne 'Differencing' -and -not $MaximumSizeBytes) + if ($Type -ne 'Differencing' -and -not $MaximumSizeBytes) { Throw 'Specify MaximumSizeBytes property for Fixed and Dynamic VHDs.' } - if($ParentPath -and $Type -ne 'Differencing') + if ($ParentPath -and $Type -ne 'Differencing') { Throw 'Parent path is only supported for Differencing disks' } - if(-not $ParentPath -and $Type -eq 'Differencing') + if (-not $ParentPath -and $Type -eq 'Differencing') { Throw 'Differencing requires a parent path' } - if($ParentPath) + if ($ParentPath) { - if(!(Test-Path -Path $ParentPath)) + if (!(Test-Path -Path $ParentPath)) { Throw "$ParentPath does not exists" } # Check if the generation matches parenting disk - if($Generation -and ($ParentPath.Split('.')[-1] -ne $Generation)) + if ($Generation -and ($ParentPath.Split('.')[-1] -ne $Generation)) { Throw "Generation $Generation should match ParentPath extension $($ParentPath.Split('.')[-1])" } } - if(!(Test-Path -Path $Path)) + if (!(Test-Path -Path $Path)) { Throw "$Path does not exists" } diff --git a/Examples/Sample_xVHD_FixedVHD.ps1 b/Examples/Sample_xVHD_FixedVHD.ps1 index a7db420..94777a1 100644 --- a/Examples/Sample_xVHD_FixedVHD.ps1 +++ b/Examples/Sample_xVHD_FixedVHD.ps1 @@ -2,25 +2,35 @@ configuration Sample_xVhd_FixedVhd { param ( - [string[]]$NodeName = 'localhost', - - [Parameter(Mandatory)] - [string]$Name, - - [Parameter(Mandatory)] - [string]$Path, - - [ValidateSet("Vhd","Vhdx")] - [string]$Generation = "Vhd", - - [ValidateSet("Dynamic","Fixed","Differencing")] - [string]$Type = "Fixed", - - [ValidateSet("Present","Absent")] - [string]$Ensure = "Present" + [Parameter()] + [string[]] + $NodeName = 'localhost', + + [Parameter(Mandatory = $true)] + [string] + $Name, + + [Parameter(Mandatory = $true)] + [string] + $Path, + + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [string] + $Generation = 'Vhd', + + [Parameter()] + [ValidateSet('Dynamic', 'Fixed', 'Differencing')] + [string] + $Type = 'Fixed', + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [string] + $Ensure = 'Present' ) - Import-DscResource -module xHyper-V + Import-DscResource -ModuleName xHyper-V Node $NodeName { @@ -30,7 +40,13 @@ configuration Sample_xVhd_FixedVhd Ensure = 'Present' Name = 'Hyper-V' } - + + WindowsFeature HyperVPowerShell + { + Ensure = 'Present' + Name = 'Hyper-V-PowerShell' + } + xVhd DiffVhd { Ensure = $Ensure @@ -38,7 +54,7 @@ configuration Sample_xVhd_FixedVhd Path = $Path Generation = $Generation Type = $Type - DependsOn = '[WindowsFeature]HyperV' + DependsOn = '[WindowsFeature]HyperV', '[WindowsFeature]HyperVPowerShell' } } } diff --git a/Tests/Unit/MSFT_xVHD.tests.ps1 b/Tests/Unit/MSFT_xVHD.tests.ps1 index b4a22ca..83d779c 100644 --- a/Tests/Unit/MSFT_xVHD.tests.ps1 +++ b/Tests/Unit/MSFT_xVHD.tests.ps1 @@ -44,6 +44,7 @@ try Mock -CommandName Get-Module -ParameterFilter { ($Name -eq 'Hyper-V') -and ($ListAvailable -eq $true) } -MockWith { return $false } + It 'Should throw when the module is missing' { { Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB } | Should Throw 'Please ensure that Hyper-V role is installed with its PowerShell module' @@ -124,6 +125,7 @@ try Mock -CommandName Get-Module -ParameterFilter { ($Name -eq 'Hyper-V') -and ($ListAvailable -eq $true) } -MockWith { return $false } + It 'Should throw when the module is missing' { { Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB } | Should Throw 'Please ensure that Hyper-V role is installed with its PowerShell module' @@ -153,15 +155,17 @@ try } Context 'ParentPath specified' { - Mock -CommandName Test-Path -MockWith { $false } It 'Should throw when ParentPath does not exist' { + Mock -CommandName Test-Path -MockWith { $false } + { Test-TargetResource -Name 'server' -Path 'C:\VMs' -Type 'Differencing' -ParentPath 'c:\boguspath' } | Should Throw 'c:\boguspath does not exists' } - #"Generation $Generation should match ParentPath extension $($ParentPath.Split('.')[-1])" - Mock -CommandName Test-Path -MockWith { $true } + # "Generation $Generation should match ParentPath extension $($ParentPath.Split('.')[-1])" It 'Should throw when file extension and generation have a mismatch' { + Mock -CommandName Test-Path -MockWith { $true } + { Test-TargetResource -Name 'server' -Path 'C:\VMs' -Type 'Differencing' -ParentPath 'c:\boguspath.vhd' -Generation 'Vhdx' } | Should Throw 'Generation Vhdx should match ParentPath extension vhd' } @@ -170,6 +174,7 @@ try Context 'Path does not exist' { It 'Should throw when the path does not exist' { Mock -CommandName Test-Path -MockWith { $false } + { Test-TargetResource -Name 'server.vhdx' -Path 'C:\VMs' -Type 'Fixed' -MaximumSizeBytes 1GB } | Should Throw 'C:\VMs does not exists' } @@ -266,12 +271,14 @@ try It 'Should Create a VHD when Ensure is present and no VHD exists yet for non Differencing disk' { Mock -CommandName Get-VHD -MockWith { throw } + $null = Set-TargetResource -Name 'server.vhdx' -Path 'TestDrive:\' -Ensure 'Present' Assert-MockCalled -CommandName New-VHD -Exactly -Times 1 -Scope It } It 'Should Create a VHD when Ensure is present and no VHD exists yet for Differencing disk' { Mock -CommandName Get-VHD -MockWith { throw } + $null = Set-TargetResource -Name 'server.vhdx' -Path 'TestDrive:\' -Ensure 'Present' -ParentPath 'c:\boguspath\server.vhdx' -Type 'Differencing' Assert-MockCalled -CommandName New-VHD -Exactly -Times 1 -Scope It } From 1326858b5826e6ff1705cb40bf28b8a1f70a4cdc Mon Sep 17 00:00:00 2001 From: Ben Gelens Date: Sat, 8 Jul 2017 23:22:04 +0200 Subject: [PATCH 10/10] fixed style from xVHD examples --- .../Sample_xVHD_AdditionalPropertyVHD.ps1 | 40 ++++++++----- Examples/Sample_xVHD_DiffVHD.ps1 | 60 ++++++++++++------- Examples/Sample_xVHD_MissingPropertyVHD.ps1 | 26 ++++---- Examples/Sample_xVHD_NewVHD.ps1 | 52 ++++++++++------ 4 files changed, 111 insertions(+), 67 deletions(-) diff --git a/Examples/Sample_xVHD_AdditionalPropertyVHD.ps1 b/Examples/Sample_xVHD_AdditionalPropertyVHD.ps1 index 9138d0d..c552cbe 100644 --- a/Examples/Sample_xVHD_AdditionalPropertyVHD.ps1 +++ b/Examples/Sample_xVHD_AdditionalPropertyVHD.ps1 @@ -2,26 +2,34 @@ configuration Sample_xVHD_AdditionalPropertyVHD { param ( - [Parameter(Mandatory)] - [string]$Name, - - [Parameter(Mandatory)] - [string]$Path, - - [Parameter(Mandatory)] - [string]$ParentPath, + [Parameter(Mandatory = $true)] + [string] + $Name, - [Parameter(Mandatory)] - [string]$MaximumSizeBytes, - - [ValidateSet("Vhd","Vhdx")] - [string]$Generation = "Vhd", + [Parameter(Mandatory = $true)] + [string] + $Path, - [ValidateSet("Present","Absent")] - [string]$Ensure = "Present" + [Parameter(Mandatory = $true)] + [string] + $ParentPath, + + [Parameter(Mandatory = $true)] + [string] + $MaximumSizeBytes, + + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [string] + $Generation = 'Vhd', + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [string] + $Ensure = 'Present' ) - Import-DscResource -Module xHyper-V + Import-DscResource -ModuleName xHyper-V Node localhost { diff --git a/Examples/Sample_xVHD_DiffVHD.ps1 b/Examples/Sample_xVHD_DiffVHD.ps1 index fb00c45..303544a 100644 --- a/Examples/Sample_xVHD_DiffVHD.ps1 +++ b/Examples/Sample_xVHD_DiffVHD.ps1 @@ -2,28 +2,38 @@ configuration Sample_xVhd_DiffVhd { param ( - [string[]]$NodeName = 'localhost', - - [Parameter(Mandatory)] - [string]$Name, - - [Parameter(Mandatory)] - [string]$Path, - - [Parameter(Mandatory)] - [string]$ParentPath, - - [ValidateSet("Vhd","Vhdx")] - [string]$Generation = "Vhd", - - [ValidateSet("Dynamic","Fixed","Differencing")] - [string]$Type = "Differencing", - - [ValidateSet("Present","Absent")] - [string]$Ensure = "Present" + [Parameter()] + [string[]] + $NodeName = 'localhost', + + [Parameter(Mandatory = $true)] + [string] + $Name, + + [Parameter(Mandatory = $true)] + [string] + $Path, + + [Parameter(Mandatory = $true)] + [string] + $ParentPath, + + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [string] + $Generation = 'Vhd', + + [Parameter()] + [ValidateSet('Dynamic', 'Fixed', 'Differencing')] + [string]$Type = 'Differencing', + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [string] + $Ensure = 'Present' ) - Import-DscResource -module xHyper-V + Import-DscResource -ModuleName xHyper-V Node $NodeName { @@ -33,7 +43,13 @@ configuration Sample_xVhd_DiffVhd Ensure = 'Present' Name = 'Hyper-V' } - + + WindowsFeature HyperVPowerShell + { + Ensure = 'Present' + Name = 'Hyper-V-PowerShell' + } + xVhd DiffVhd { Ensure = $Ensure @@ -42,7 +58,7 @@ configuration Sample_xVhd_DiffVhd ParentPath = $ParentPath Generation = $Generation Type = $Type - DependsOn = '[WindowsFeature]HyperV' + DependsOn = '[WindowsFeature]HyperV', '[WindowsFeature]HyperVPowerShell' } } } diff --git a/Examples/Sample_xVHD_MissingPropertyVHD.ps1 b/Examples/Sample_xVHD_MissingPropertyVHD.ps1 index f623ab7..baa7037 100644 --- a/Examples/Sample_xVHD_MissingPropertyVHD.ps1 +++ b/Examples/Sample_xVHD_MissingPropertyVHD.ps1 @@ -2,17 +2,23 @@ configuration Sample_xVHD_MissingPropertyVHD { param ( - [Parameter(Mandatory)] - [string]$Name, - - [Parameter(Mandatory)] - [string]$Path, - - [ValidateSet("Vhd","Vhdx")] - [string]$Generation = "Vhd", + [Parameter(Mandatory = $true)] + [string] + $Name, - [ValidateSet("Present","Absent")] - [string]$Ensure = "Present" + [Parameter(Mandatory = $true)] + [string] + $Path, + + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [string] + $Generation = 'Vhd', + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [string] + $Ensure = 'Present' ) Import-DscResource -module xHyper-V diff --git a/Examples/Sample_xVHD_NewVHD.ps1 b/Examples/Sample_xVHD_NewVHD.ps1 index 935d023..f607afb 100644 --- a/Examples/Sample_xVHD_NewVHD.ps1 +++ b/Examples/Sample_xVHD_NewVHD.ps1 @@ -2,25 +2,33 @@ configuration Sample_xVHD_NewVhd { param ( - [string[]]$NodeName = 'localhost', - - [Parameter(Mandatory)] - [string]$Name, - - [Parameter(Mandatory)] - [string]$Path, - - [Parameter(Mandatory)] - [Uint64]$MaximumSizeBytes, - - [ValidateSet("Vhd","Vhdx")] - [string]$Generation = "Vhd", - - [ValidateSet("Present","Absent")] - [string]$Ensure = "Present" + [Parameter()] + [string[]] + $NodeName = 'localhost', + + [Parameter(Mandatory = $true)] + [string] + $Name, + + [Parameter(Mandatory = $true)] + [string] + $Path, + + [Parameter(Mandatory = $true)] + [Uint64] + $MaximumSizeBytes, + + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [string]$Generation = 'Vhd', + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [string] + $Ensure = 'Present' ) - Import-DscResource -module xHyper-V + Import-DscResource -ModuleName xHyper-V Node $NodeName { @@ -30,7 +38,13 @@ configuration Sample_xVHD_NewVhd Ensure = 'Present' Name = 'Hyper-V' } - + + WindowsFeature HyperVPowerShell + { + Ensure = 'Present' + Name = 'Hyper-V-PowerShell' + } + xVhd NewVhd { Ensure = $Ensure @@ -38,7 +52,7 @@ configuration Sample_xVHD_NewVhd Path = $Path Generation = $Generation MaximumSizeBytes = $MaximumSizeBytes - DependsOn = '[WindowsFeature]HyperV' + DependsOn = '[WindowsFeature]HyperV', '[WindowsFeature]HyperVPowerShell' } } }