diff --git a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 index f1e769c..da53f8c 100644 --- a/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 +++ b/DSCResources/MSFT_xVHD/MSFT_xVHD.psm1 @@ -30,7 +30,6 @@ function Get-TargetResource [String] $Generation = "Vhd" ) - # Check if Hyper-V module is present for Hyper-V cmdlets if (!(Get-Module -ListAvailable -Name Hyper-V)) { @@ -378,4 +377,53 @@ function GetNameWithExtension $vhdName } +function Export-TargetResource +{ + [CmdletBinding()] + [OutputType([System.String])] + $InformationPreference = "Continue" + + # Get all VMs on the host + $allVMs = Get-VM + $i = 1 + $content = "" + + # Loop through all VMs to get their VHDs; + foreach ($vm in $allVMs) + { + Write-Information " [$i/$($allVMs.Count)] Scanning VHDs for VM {$($vm.Name)}" + $vhds = Get-VHD -VMId $vm.ID + $j = 1 + foreach ($vhd in $vhds) + { + Write-Information " [$j/$($vhds.Count)] $($vhd.Path)" + + # Defining the Key parameters to allow Get-TargetResource to retrieve the instance; + $vhdPathParts = $vhd.Path.Split('\') + $vhdName = $vhdPathParts[$vhdPathParts.Length - 1].Split('.')[0] + $vhdPath = $vhd.Path.Replace($vhdPathParts[$vhdPathParts.Length - 1], "") + + $keyParams = @{ + Name = $vhdName + Generation = $vhd.VHDFormat + Path = $vhdPath + } + + # Retrieving the current instance based on the key parameters; + $result = Get-TargetResource @keyParams + + $content += " xVHD " + (New-GUID).ToString() + "`r`n" + $content += " {`r`n" + + # This is where the magic happens. Converting the retrieved Hashtable into a DSC consumable string; + $currentDSCBlock = Get-DSCBlock -Params $result -ModulePath $PSScriptRoot + $content += $currentDSCBlock + $content += " }`r`n" + $j++ + } + $i++ + } + return $content +} + Export-ModuleMember -Function *-TargetResource diff --git a/Misc/ReverseDSCCollector.psm1 b/Misc/ReverseDSCCollector.psm1 new file mode 100644 index 0000000..ad38f03 --- /dev/null +++ b/Misc/ReverseDSCCollector.psm1 @@ -0,0 +1,59 @@ +function Export-HyperVConfiguration +{ + [CmdletBinding()] + [OutputType([System.String])] + + $InformationPreference = "Continue" + + $DSCContent = "Configuration HyperVConfiguration`r`n{`r`n" + $DSCContent += " Import-DSCResource -ModuleName xHyper-V`r`n`r`n" + $DSCContent += " Node localhost`r`n" + $DSCContent += " {`r`n" + + #region xVHD + Write-Information "Extracting xVHD..." + $xVHDModulePath = Join-Path -Path $PSScriptRoot ` + -ChildPath "..\DSCResources\MSFT_xVHD\MSFT_xVHD.psm1" ` + -Resolve + Import-Module $xVHDModulePath | Out-Null + $DSCContent += Export-TargetResource + #endregion + + $DSCContent += " }`r`n}`r`n" + + #region Prompt the user for a location to save the extract and generate the files + if ($null -eq $Path -or "" -eq $Path) + { + $OutputDSCPath = Read-Host "Destination Path" + } + else + { + $OutputDSCPath = $Path + } + + while ((Test-Path -Path $OutputDSCPath -PathType Container -ErrorAction SilentlyContinue) -eq $false) + { + try + { + Write-Information "Directory `"$OutputDSCPath`" doesn't exist; creating..." + New-Item -Path $OutputDSCPath -ItemType Directory | Out-Null + if ($?) {break} + } + catch + { + Write-Warning "$($_.Exception.Message)" + Write-Warning "Could not create folder $OutputDSCPath!" + } + $OutputDSCPath = Read-Host "Please Provide Output Folder for DSC Configuration (Will be Created as Necessary)" + } + <## Ensures the path we specify ends with a Slash, in order to make sure the resulting file path is properly structured. #> + if (!$OutputDSCPath.EndsWith("\") -and !$OutputDSCPath.EndsWith("/")) + { + $OutputDSCPath += "\" + } + $outputDSCFile = $OutputDSCPath + "HyperVConfiguration.ps1" + $DSCContent | Out-File $outputDSCFile + + Invoke-Item -Path $OutputDSCPath + #endregion +} diff --git a/appveyor.yml b/appveyor.yml index 0b5eafc..e19ea71 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,6 +9,7 @@ environment: install: - git clone https://github.com/PowerShell/DscResource.Tests + - ps: Install-Module ReverseDSC -RequiredVersion 1.9.4.5 -Force - ps: Write-Verbose -Message "PowerShell version $($PSVersionTable.PSVersion)" -Verbose - ps: Import-Module -Name "$env:APPVEYOR_BUILD_FOLDER\DscResource.Tests\AppVeyor.psm1" - ps: Invoke-AppveyorInstallTask diff --git a/xHyper-V.psd1 b/xHyper-V.psd1 index e323b5d..f6719ee 100644 --- a/xHyper-V.psd1 +++ b/xHyper-V.psd1 @@ -20,14 +20,20 @@ Description = 'Module with DSC Resources for Hyper-V area' # Minimum version of the Windows PowerShell engine required by this module PowerShellVersion = '4.0' +# Adds dependency to ReverseDSC +RequiredModules = @(@{ModuleName = "ReverseDSC"; RequiredVersion = "1.9.4.5"; }) + # Minimum version of the common language runtime (CLR) required by this module CLRVersion = '4.0' # Functions to export from this module FunctionsToExport = '*' +# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess +NestedModules = @('Misc\ReverseDSCCollector.psm1') + # Cmdlets to export from this module -CmdletsToExport = '*' +CmdletsToExport = 'Export-HyperVConfiguration' # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. PrivateData = @{