From 9c490ae82d7487a16cd9d5c9f7dde852928b77aa Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Peters Date: Tue, 7 Feb 2023 08:12:03 +0100 Subject: [PATCH] Fix casing on VHD to be able to build on Linux --- source/DSCResources/DSC_Vhd/DSC_Vhd.psm1 | 387 ++++++++++++++++++ .../DSCResources/DSC_Vhd/DSC_Vhd.schema.mof | 14 + source/DSCResources/DSC_Vhd/README.md | 8 + .../DSC_Vhd/en-US/DSC_Vhd.strings.psd1 | 2 + 4 files changed, 411 insertions(+) create mode 100644 source/DSCResources/DSC_Vhd/DSC_Vhd.psm1 create mode 100644 source/DSCResources/DSC_Vhd/DSC_Vhd.schema.mof create mode 100644 source/DSCResources/DSC_Vhd/README.md create mode 100644 source/DSCResources/DSC_Vhd/en-US/DSC_Vhd.strings.psd1 diff --git a/source/DSCResources/DSC_Vhd/DSC_Vhd.psm1 b/source/DSCResources/DSC_Vhd/DSC_Vhd.psm1 new file mode 100644 index 0000000..51e2b9b --- /dev/null +++ b/source/DSCResources/DSC_Vhd/DSC_Vhd.psm1 @@ -0,0 +1,387 @@ +$script:dscResourceCommonModulePath = Join-Path -Path $PSScriptRoot -ChildPath '../../Modules/DscResource.Common' + +Import-Module -Name $script:dscResourceCommonModulePath + +$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' + +<# +.SYNOPSIS + Gets DSC_VHD 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 = $true)] + [System.String] + $Name, + + [Parameter(Mandatory = $true)] + [System.String] + $Path, + + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [System.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' + } + + # Construct the full path for the vhdFile + $vhdName = GetNameWithExtension -Name $Name -Generation $Generation + $vhdFilePath = Join-Path -Path $Path -ChildPath $vhdName + 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 = $ensure + ID = $vhd.DiskIdentifier + Type = $vhd.VhdType + FileSizeBytes = $vhd.FileSize + MaximumSizeBytes = $vhd.Size + IsAttached = $vhd.Attached + } +} + +<# +.SYNOPSIS + Configures DSC_VHD 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 + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter(Mandatory = $true)] + [System.String] + $Path, + + [Parameter()] + [System.String] + $ParentPath, + + [Parameter()] + [System.UInt64] + $MaximumSizeBytes, + + [Parameter()] + [ValidateSet('Dynamic', 'Fixed', 'Differencing')] + [System.String] + $Type = 'Dynamic', + + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [System.String] + $Generation = 'Vhd', + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present' + ) + + # Construct the full path for the vhdFile + $vhdName = GetNameWithExtension -Name $Name -Generation $Generation + $vhdFilePath = Join-Path -Path $Path -ChildPath $vhdName + 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 (Test-Path -Path $vhdFilePath) + { + Write-Verbose -Message "$vhdFilePath is not $Ensure" + 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 + + # If this is a differencing disk, check the parent path + 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) + { + 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." + } + } + + # This is a fixed disk, check the size + elseif ($PSBoundParameters.ContainsKey('MaximumSizeBytes')) + { + 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." + } + } + + if ($vhd.Type -ne $Type) + { + Write-Verbose -Message 'This module can''t convert disk types' + } + } + + # Vhd file is not present + catch + { + Write-Verbose -Message "$vhdFilePath is not $Ensure" + if ($ParentPath) + { + $null = New-VHD -Path $vhdFilePath -ParentPath $ParentPath + } + else + { + $params = @{ + Path = $vhdFilePath + SizeBytes = $MaximumSizeBytes + $Type = $True + } + $null = New-VHD @params + } + + Write-Verbose -Message "$vhdFilePath is now $Ensure" + } + } +} + +<# +.SYNOPSIS + Tests if DSC_VHD 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 + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter(Mandatory = $true)] + [System.String] + $Path, + + [Parameter()] + [System.String] + $ParentPath, + + [Parameter()] + [System.UInt64] + $MaximumSizeBytes, + + [Parameter()] + [ValidateSet('Vhd', 'Vhdx')] + [System.String] + $Generation = 'Vhd', + + [Parameter()] + [ValidateSet('Dynamic', 'Fixed', 'Differencing')] + [System.String] + $Type = 'Dynamic', + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.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' + } + + # input validation + if ($Type -ne 'Differencing' -and -not $MaximumSizeBytes) + { + throw 'Specify MaximumSizeBytes property for Fixed and Dynamic VHDs.' + } + + if ($ParentPath -and $Type -ne 'Differencing') + { + throw 'Parent path is only supported for Differencing disks' + } + + if (-not $ParentPath -and $Type -eq 'Differencing') + { + throw 'Differencing requires a parent path' + } + + if ($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 $Generation should match ParentPath extension $($ParentPath.Split('.')[-1])" + } + } + + if (!(Test-Path -Path $Path)) + { + throw "$Path does not exists" + } + + # Construct the full path for the vhdFile + $vhdName = GetNameWithExtension -Name $Name -Generation $Generation + $vhdFilePath = Join-Path -Path $Path -ChildPath $vhdName + 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 + Write-Verbose -Message "Vhd $vhdFilePath is present:$result and Ensure is $Ensure" + return ($result -and ($Ensure -eq 'Present')) +} + +<# +.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 + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name, + + [Parameter(Mandatory = $true)] + [System.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') + { + $extension = $Name.Split('.')[-1] + if ($Generation -ne $extension) + { + throw "the extension $extension on the name does not match the generation $Generation" + } + else + { + Write-Verbose -Message "Vhd full name is $vhdName" + $vhdName = $Name + } + } + else + { + # Append generation to the name + $vhdName = "$Name.$Generation" + Write-Verbose -Message "Vhd full name is $vhdName" + } + + $vhdName +} + +Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_Vhd/DSC_Vhd.schema.mof b/source/DSCResources/DSC_Vhd/DSC_Vhd.schema.mof new file mode 100644 index 0000000..6a61ea5 --- /dev/null +++ b/source/DSCResources/DSC_Vhd/DSC_Vhd.schema.mof @@ -0,0 +1,14 @@ +[ClassVersion("1.0.0"), FriendlyName("Vhd")] +class DSC_Vhd : OMI_BaseResource +{ + [Key, Description("The desired VHD file name.")] String Name; + [Key, Description("The desired Path where the VHD will be created.")] String Path; + [Write, Description("Parent VHD file path, for differencing disk.")] String ParentPath; + [Write, Description("Maximum size of VHD to be created.")] Uint64 MaximumSizeBytes; + [Write, Description("Virtual disk format. The default value is `Vhd`."), ValueMap{"Vhd","Vhdx"}, Values{"Vhd","Vhdx"}] String Generation; + [Write, Description("Specifies if the virtual disk should be present (if not it will be created) or absent (if present it will be removed). Default value is `Present`."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; + [Read, Description("Returns the virtual disk identifier.")] String ID; + [Write, Description("The type of virtual disk. The default value is `Dynamic`."), ValueMap{"Dynamic","Fixed","Differencing"}, Values{"Dynamic","Fixed","Differencing"}] String Type; + [Read, Description("Returns the current size of the virtual disk.")] Uint64 FileSizeBytes; + [Read, Description("Returns if the virtual disk is attached to a VM.")] Boolean IsAttached; +}; diff --git a/source/DSCResources/DSC_Vhd/README.md b/source/DSCResources/DSC_Vhd/README.md new file mode 100644 index 0000000..b0f90d1 --- /dev/null +++ b/source/DSCResources/DSC_Vhd/README.md @@ -0,0 +1,8 @@ +# Description + +Manages VHDs in a Hyper-V host. + +## Requirements + +* The Hyper-V Role has to be installed on the machine. +* The Hyper-V PowerShell module has to be installed on the machine. diff --git a/source/DSCResources/DSC_Vhd/en-US/DSC_Vhd.strings.psd1 b/source/DSCResources/DSC_Vhd/en-US/DSC_Vhd.strings.psd1 new file mode 100644 index 0000000..3b35d66 --- /dev/null +++ b/source/DSCResources/DSC_Vhd/en-US/DSC_Vhd.strings.psd1 @@ -0,0 +1,2 @@ +ConvertFrom-StringData @' +'@