From 59d2446560c19fb420d18fa5509e802d5e225d52 Mon Sep 17 00:00:00 2001 From: Matthew Collera Date: Fri, 9 Nov 2018 16:09:12 -0500 Subject: [PATCH 1/9] Added vlan tagging and Network Settings to xNetworkAdapater Dsc Resource --- .vscode/launch.json | 48 +++ CHANGELOG.md | 5 + .../MSFT_xVMNetworkAdapter.psm1 | 348 +++++++++++++++++- .../MSFT_xVMNetworkAdapter.schema.mof | 12 + .../en-US/MSFT_xVMNetworkAdapter.psd1 | 16 +- .../Sample_xVMNetworkAdapter_ManagementOS.ps1 | 3 + ...xVMNetworkAdapter_MultipleManagementOS.ps1 | 6 + .../Sample_xVMNetworkAdapter_MultipleVM.ps1 | 11 +- ...xVMNetworkAdapter_MultipleVMMACAddress.ps1 | 6 + ...NetworkAdapter_VMStaticNetworkSettings.ps1 | 21 ++ ...Sample_xVMNetworkAdapter_VMVlanTagging.ps1 | 18 + README.md | 17 + Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 | 197 +++++++++- 13 files changed, 668 insertions(+), 40 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1 create mode 100644 Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1 diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..96266b0 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,48 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Launch Current File", + "script": "${file}", + "args": [], + "cwd": "${file}" + }, + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Launch Current File in Temporary Console", + "script": "${file}", + "args": [], + "cwd": "${file}", + "createTemporaryIntegratedConsole": true + }, + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Launch Current File w/Args Prompt", + "script": "${file}", + "args": [ + "${command:SpecifyScriptArgs}" + ], + "cwd": "${file}" + }, + { + "type": "PowerShell", + "request": "attach", + "name": "PowerShell Attach to Host Process", + "processId": "${command:PickPSHostProcess}", + "runspaceId": 1 + }, + { + "type": "PowerShell", + "request": "launch", + "name": "PowerShell Interactive Session", + "cwd": "" + } + ] +} \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 68053a3..29aee8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +* MSFT_xVMNetworkAdapter: + * __Breaking change:__ Added NetworkSettings to be able to statically set IPAddress or use as DHCP. This is + a required field. + * Added option for Vlan tagging. You can now setup a Network Adapeter as an access switch on a specific Vlan. + ## 3.13.0.0 * MSFT_xVMSwitch: diff --git a/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.psm1 b/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.psm1 index e1b6712..9999fad 100644 --- a/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.psm1 +++ b/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.psm1 @@ -3,7 +3,7 @@ if (Test-Path "${PSScriptRoot}\${PSUICulture}") { Import-LocalizedData -BindingVariable LocalizedData -filename MSFT_xVMNetworkAdapter.psd1 ` -BaseDirectory "${PSScriptRoot}\${PSUICulture}" -} +} else { #fallback to en-US @@ -28,6 +28,9 @@ else .PARAMETER VMName Specifies the name of the VM to which the network adapter will be connected. Specify VMName as ManagementOS if you wish to connect the adapter to host OS. + +.PARAMETER IpAddress + Specifies the IpAddress information for the network adapter. #> Function Get-TargetResource { @@ -35,16 +38,20 @@ Function Get-TargetResource [OutputType([System.Collections.Hashtable])] Param ( [Parameter(Mandatory)] - [String] $Id, + [String] $Id, [Parameter(Mandatory)] - [String] $Name, + [String] $Name, [Parameter(Mandatory)] [String] $SwitchName, [Parameter(Mandatory)] - [String] $VMName + [String] $VMName, + + [Parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance] + $NetworkSetting ) $configuration = @{ @@ -81,10 +88,22 @@ Function Get-TargetResource } elseif ($netAdapter.VMName) { - $configuration.Add('MacAddress', $netAdapter.MacAddress) + $configuration.Add('MacAddress', $netAdapter.MacAddress) $configuration.Add('DynamicMacAddress', $netAdapter.DynamicMacAddressEnabled) } + + $networkInfo = Get-NetworkInformation -VMName $VMName -Name $Name + $item = New-CimInstance -ClassName MSFT_xNetworkSettings -Property $networkInfo -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly + $configuration.Add('NetworkSetting', $item) + $configuration.Add('Ensure','Present') + + Write-Verbose -Message $localizedData.GetVMNetAdapterVlan + $netAdapterVlan = Get-VMNetworkAdapterVlan -VMNetworkAdapter $netAdapter + if ($netAdapterVlan.OperationMode -ne 'Untagged') + { + $configuration.Add('VlanId', $netAdapterVlan.AccessVlanId) + } } else { @@ -116,6 +135,12 @@ Function Get-TargetResource Specifies the MAC address for the network adapter. This is not applicable if VMName is set to ManagementOS. Use this parameter to specify a static MAC address. +.PARAMETER IpAddress + Specifies the IpAddress information for the network adapter. + +.PARAMETER VlanId + Specifies the Vlan Id for the network adapter. + .PARAMETER Ensure Specifies if the network adapter should be Present or Absent. #> @@ -124,7 +149,7 @@ Function Set-TargetResource [CmdletBinding()] Param ( [Parameter(Mandatory)] - [String] $Id, + [String] $Id, [Parameter(Mandatory)] [String] $Name, @@ -138,6 +163,13 @@ Function Set-TargetResource [Parameter()] [String] $MacAddress, + [Parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance] + $NetworkSetting, + + [Parameter()] + [String] $VlanId, + [Parameter()] [ValidateSet('Present','Absent')] [String] $Ensure='Present' @@ -156,10 +188,10 @@ Function Set-TargetResource $arguments.Add('ManagementOS', $true) $arguments.Add('SwitchName', $SwitchName) } - + Write-Verbose -Message $localizedData.GetVMNetAdapter $netAdapterExists = Get-VMNetworkAdapter @arguments -ErrorAction SilentlyContinue - + if ($Ensure -eq 'Present') { if ($netAdapterExists) @@ -188,13 +220,13 @@ Function Set-TargetResource $updateMacAddress = $true } } - + if ($netAdapterExists.SwitchName -ne $SwitchName) { Write-Verbose -Message $localizedData.PerformSwitchConnect Connect-VMNetworkAdapter -VMNetworkAdapter $netAdapterExists -SwitchName $SwitchName -ErrorAction Stop -Verbose } - + if (($updateMacAddress)) { Write-Verbose -Message $localizedData.PerformVMNetModify @@ -228,7 +260,75 @@ Function Set-TargetResource $arguments.Add('SwitchName',$SwitchName) } Write-Verbose -Message $localizedData.AddVMNetAdapter - Add-VMNetworkAdapter @arguments -ErrorAction Stop + $netAdapterExists = Add-VMNetworkAdapter @arguments -Passthru -ErrorAction Stop + } + + if ($VmName -ne 'ManagementOS') + { + $networkInfo = Get-NetworkInformation -VMName $VMName -Name $Name + if ($NetworkSetting.CimInstanceProperties["Dhcp"].Value) + { + if (-not $networkInfo.Dhcp) + { + Write-Verbose -Message $localizedData.EnableDhcp + Set-NetworkInformation -VMName $VMName -Name $Name -Dhcp + } + } + else + { + $parameters = @{} + if ($ipAddress = $NetworkSetting.CimInstanceProperties["IpAddress"].Value) + { + if (-not $ipAddress) + { + throw $localizedData.MissingIPAndSubnet + } + $parameters.Add('IPAddress', $ipAddress) + } + if ($subnet = $NetworkSetting.CimInstanceProperties["Subnet"].Value) + { + if (-not $subnet) + { + throw $localizedData.MissingIPAndSubnet + } + $parameters.Add('Subnet', $subnet) + } + if ($defaultGateway = $NetworkSetting.CimInstanceProperties["DefaultGateway"].Value) + { + $parameters.Add('DefaultGateway', $defaultGateway) + } + if ($dnsServer = $NetworkSetting.CimInstanceProperties["DnsServer"].Value) + { + $parameters.Add('DnsServer', $dnsServer) + } + + Set-NetworkInformation -VMName $VMName -Name $Name @parameters + } + + Write-Verbose -Message $localizedData.GetVMNetAdapterVlan + $netAdapterVlan = Get-VMNetworkAdapterVlan -VMNetworkAdapter $netAdapterExists + if ($netAdapterVlan) + { + if ($VlanId) + { + $setVlan = $true + } + else + { + Write-Verbose -Message $localizedData.RemovingVlanTag + Set-VMNetworkAdapterVlan -VMNetworkAdapter $netAdapterExists -Untagged + } + } + elseif ($VlanId) + { + $setVlan = $true + } + + if ($setVlan) + { + Write-Verbose -Message $localizedData.SettingVlan + Set-VMNetworkAdapterVlan -VMNetworkAdapter $netAdapterExists -Access -VlanId $VlanId + } } } else @@ -259,6 +359,12 @@ Function Set-TargetResource Specifies the MAC address for the network adapter. This is not applicable if VMName is set to ManagementOS. Use this parameter to specify a static MAC address. +.PARAMETER IpAddress + Specifies the IpAddress information for the network adapter. + +.PARAMETER VlanId + Specifies the Vlan Id for the network adapter. + .PARAMETER Ensure Specifies if the network adapter should be Present or Absent. #> @@ -268,8 +374,8 @@ Function Test-TargetResource [OutputType([System.Boolean])] Param ( [Parameter(Mandatory)] - [String] $Id, - + [String] $Id, + [Parameter(Mandatory)] [String] $Name, @@ -282,6 +388,13 @@ Function Test-TargetResource [Parameter()] [String] $MacAddress, + [Parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance] + $NetworkSetting, + + [Parameter()] + [String] $VlanId, + [Parameter()] [ValidateSet('Present','Absent')] [String] $Ensure='Present' @@ -300,7 +413,7 @@ Function Test-TargetResource $arguments.Add('ManagementOS', $true) $arguments.Add('SwitchName', $SwitchName) } - + Write-Verbose -Message $localizedData.GetVMNetAdapter $netAdapterExists = Get-VMNetworkAdapter @arguments -ErrorAction SilentlyContinue @@ -330,25 +443,109 @@ Function Test-TargetResource Write-Verbose -Message $localizedData.EnableDynamicMacAddress return $false } - } - + } + + $networkInfo = Get-NetworkInformation -VMName $VMName -Name $Name + if ($NetworkSetting.CimInstanceProperties["Dhcp"].Value) + { + if (-not $networkInfo.Dhcp) + { + Write-Verbose -Message $localizedData.NotDhcp + return $false + } + } + else + { + if ($networkInfo.Dhcp) + { + Write-Verbose -Message $localizedData.Dhcp + return $false + } + else + { + $ipAddress = $NetworkSetting.CimInstanceProperties["IpAddress"].Value + $subnet = $NetworkSetting.CimInstanceProperties["Subnet"].Value + $defaultGateway = $NetworkSetting.CimInstanceProperties["DefaultGateway"].Value + $dnsServer = $NetworkSetting.CimInstanceProperties["DnsServer"].Value + + if (-not $IpAddress -or -not $subnet) + { + throw $localizedData.MissingIPAndSubnet + } + + if ($ipAddress -and -not $networkInfo.IPAddress.Split(',').Contains($ipAddress)) + { + Write-Verbose -Message $localizedData.IPAddressNotConfigured + return $false + } + + if ($defaultGateway -and -not $networkInfo.DefaultGateway.Split(',').Contains($defaultGateway)) + { + Write-Verbose -Message $localizedData.GatewayNotConfigured + return $false + } + + if ($dnsServer -and -not $networkInfo.DNSServer.Split(',').Contains($dnsServer)) + { + Write-Verbose -Message $localizedData.DNSServerNotConfigured + return $false + } + } + } + + Write-Verbose -Message $localizedData.GetVMNetAdapterVlan + $netAdapterVlan = Get-VMNetworkAdapterVlan -VMNetworkAdapter $netAdapterExists + if ($netAdapterVlan) + { + if ($netAdapterVlan.OperationMode -eq 'Untagged') + { + if ($VlanId) + { + Write-Verbose -Message $localizedData.VlanNotUntagged + return $false + } + } + else + { + if ($VlanId) + { + if ($netAdapterVlan.AccessVlanId -ne $VlanId) + { + Write-Verbose -Message $localizedData.VlanDoesNotMatch + return $false + } + } + else + { + Write-Verbose -Message $localizedData.VlanShouldntBeTagged + return $false + } + } + } + elseif ($VlanId) + { + Write-Verbose -Message $localizedData.VlanNotUntagged + return $false + } + if ($netAdapterExists.SwitchName -ne $SwitchName) { Write-Verbose -Message $localizedData.SwitchIsDifferent return $false - } + } else { Write-Verbose -Message $localizedData.VMNetAdapterExistsNoActionNeeded return $true } + } else { Write-Verbose -Message $localizedData.VMNetAdapterExistsNoActionNeeded return $true } - } + } else { Write-Verbose -Message $localizedData.VMNetAdapterDoesNotExistShouldAdd @@ -370,4 +567,119 @@ Function Test-TargetResource } } +function Get-NetworkInformation +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + Param ( + [Parameter(Mandatory)] + [String] $VMName, + + [Parameter(Mandatory)] + [String] $Name + ) + + $vm = Get-WmiObject -Namespace 'root\virtualization\v2' -Class 'Msvm_ComputerSystem' | Where-Object { $_.ElementName -ieq "$VmName" } + $vmSettings = $vm.GetRelated('Msvm_VirtualSystemSettingData') | Where-Object { $_.VirtualSystemType -eq 'Microsoft:Hyper-V:System:Realized' } + $vmNetAdapter = $vmSettings.GetRelated('Msvm_SyntheticEthernetPortSettingData') | Where-Object { $_.ElementName -ieq "$Name" } + $networkSettings = $vmNetAdapter.GetRelated("Msvm_GuestNetworkAdapterConfiguration") + + if ($networkSettings.DHCPEnabled) + { + return @{ + Dhcp = $true + } + } + else + { + return @{ + Dhcp = $false + IpAddress = $networkSettings.IPAddresses -join ',' + Subnet = $networkSettings.Subnets -join ',' + DefaultGateway = $networkSettings.DefaultGateways -join ',' + DnsServer = $networkSettings.DNSServers -join ',' + } + } + +} + +function Set-NetworkInformation +{ + [CmdletBinding()] + Param ( + [Parameter(Mandatory)] + [String] $VMName, + + [Parameter(Mandatory)] + [String] $Name, + + [Parameter(ParameterSetName='Dhcp')] + [switch] $Dhcp, + + [Parameter(Mandatory, ParameterSetName='Static')] + [String] $IPAddress, + + [Parameter(Mandatory, ParameterSetName='Static')] + [String] $Subnet, + + [Parameter(ParameterSetName='Static')] + [String] $DefaultGateway, + + [Parameter(ParameterSetName='Static')] + [String] $DnsServer + ) + + $vm = Get-WmiObject -Namespace 'root\virtualization\v2' -Class 'Msvm_ComputerSystem' | Where-Object { $_.ElementName -ieq "$VmName" } + $vmSettings = $vm.GetRelated('Msvm_VirtualSystemSettingData') | Where-Object { $_.VirtualSystemType -eq 'Microsoft:Hyper-V:System:Realized' } + $vmNetAdapter = $vmSettings.GetRelated('Msvm_SyntheticEthernetPortSettingData') | Where-Object { $_.ElementName -ieq $Name } + $networkSettings = $vmNetAdapter.GetRelated("Msvm_GuestNetworkAdapterConfiguration") | Select-Object -First 1 + + switch ($PSCmdlet.ParameterSetName) + { + 'Dhcp' + { + $networkSettings.DHCPEnabled = $true + $networkSettings.IPAddresses = @() + $networkSettings.Subnets = @() + $networkSettings.DefaultGateways = @() + $networkSettings.DNSServers = @() + } + 'Static' + { + $networkSettings.IPAddresses = $IPAddress + $networkSettings.Subnets = $Subnet + + if ($DefaultGateway) + { + $networkSettings.DefaultGateways = $DefaultGateway + } + if ($DnsServer) + { + $networkSettings.DNSServers = $DNSServer + } + $networkSettings.DHCPEnabled = $false + } + } + $networkSettings.ProtocolIFType = 4096 + + $service = Get-WmiObject -Class "Msvm_VirtualSystemManagementService" -Namespace "root\virtualization\v2" + $setIP = $service.SetGuestNetworkAdapterConfiguration($vm, $networkSettings.GetText(1)) + + if ($setIP.ReturnValue -eq 4096) + { + $job = [WMI]$setIP.job + + while ($job.JobState -eq 3 -or $job.JobState -eq 4) + { + Start-Sleep 1 + $job = [WMI]$setIP.job + } + + if($job.JobState -ne 7) + { + throw $job.GetError().Error + } + } +} + Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.schema.mof b/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.schema.mof index 89c4b30..8b9334d 100644 --- a/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.schema.mof +++ b/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.schema.mof @@ -1,4 +1,14 @@ +[ClassVersion("2.0.0.0")] +Class xNetworkSettings +{ + [Required] Boolean Dhcp; + [Write] string IpAddress; + [Write] string Subnet; + [Write] string DefaultGateway; + [Write] string DnsServer; +}; + [ClassVersion("2.0.0.0"), FriendlyName("xVMNetworkAdapter")] class MSFT_xVMNetworkAdapter : OMI_BaseResource { @@ -7,6 +17,8 @@ class MSFT_xVMNetworkAdapter : OMI_BaseResource [Required] String SwitchName; [Required] String VMName; [Write] String MacAddress; + [Required, EmbeddedInstance("xNetworkSettings")] String NetworkSetting; + [Write] String VlanId; [Write, ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Read] Boolean DynamicMacAddress; }; diff --git a/DSCResources/MSFT_xVMNetworkAdapter/en-US/MSFT_xVMNetworkAdapter.psd1 b/DSCResources/MSFT_xVMNetworkAdapter/en-US/MSFT_xVMNetworkAdapter.psd1 index c60f3ff..b5e1676 100644 --- a/DSCResources/MSFT_xVMNetworkAdapter/en-US/MSFT_xVMNetworkAdapter.psd1 +++ b/DSCResources/MSFT_xVMNetworkAdapter/en-US/MSFT_xVMNetworkAdapter.psd1 @@ -1,7 +1,21 @@ -ConvertFrom-StringData @' +ConvertFrom-StringData @' VMNameAndManagementTogether=VMName cannot be provided when ManagementOS is set to True. MustProvideVMName=Must provide VMName parameter when ManagementOS is set to False. GetVMNetAdapter=Getting VM Network Adapter information. + GetVMNetAdapterVlan=Getting VM Network Adapter VLAN information. + VlanShouldntBeTagged=VM Network Adapter should not have a Vlan tag. + VlanNotUntagged=Vlan is tagged. It will be removed. + VlanDoesNotMatch=VlanId does not match. + RemovingVlanTag=Removing Vlan tagging on Network Adapter. + SettingVlan=Setting VlanId on network adapter. + IpAddressIsNotSet=Ip Address is not set. + NotDhcp=Ethernet Adapter is not configured for Dhcp. + Dhcp=Ethernet Adapter is configured for Dhcp. + EnableDhcp=Enabling DHCP. + IPAddressNotConfigured=IPAddress is not configured. + GatewayNotConfigured=Gateway is not configured. + DNSServerNotConfigured=DNS Server not configured. + MissingIPAndSubnet=Missing IPAddress or Subnet. FoundVMNetAdapter=Found VM Network Adapter. NoVMNetAdapterFound=No VM Network Adapter found. StaticMacAddressChosen=Static MAC Address has been specified. diff --git a/Examples/Sample_xVMNetworkAdapter_ManagementOS.ps1 b/Examples/Sample_xVMNetworkAdapter_ManagementOS.ps1 index 7be0ae5..d787341 100644 --- a/Examples/Sample_xVMNetworkAdapter_ManagementOS.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_ManagementOS.ps1 @@ -8,6 +8,9 @@ Name = 'Management-NIC' SwitchName = 'SETSwitch' VMName = 'ManagementOS' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } Ensure = 'Present' } } diff --git a/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1 b/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1 index a0cd100..c02efd1 100644 --- a/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1 @@ -8,6 +8,9 @@ Name = 'Management-NIC' SwitchName = 'SETSwitch' VMName = 'ManagementOS' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } Ensure = 'Present' } @@ -16,6 +19,9 @@ Name = 'Cluster-NIC' SwitchName = 'SETSwitch' VMName = 'ManagementOS' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } Ensure = 'Present' } } diff --git a/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1 b/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1 index 81b7b0b..8d9d51e 100644 --- a/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1 @@ -8,6 +8,9 @@ Name = 'MyVM01-NIC' SwitchName = 'SETSwitch' VMName = 'MyVM01' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } Ensure = 'Present' } @@ -16,6 +19,9 @@ Name = 'NetAdapter' SwitchName = 'SETSwitch' VMName = 'MyVM02' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } Ensure = 'Present' } @@ -24,6 +30,9 @@ Name = 'NetAdapter' SwitchName = 'SETSwitch' VMName = 'MyVM03' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } Ensure = 'Present' - } + } } diff --git a/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1 b/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1 index 80f0ead..b601379 100644 --- a/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1 @@ -9,6 +9,9 @@ SwitchName = 'SETSwitch' MacAddress = '001523be0c' VMName = 'MyVM01' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } Ensure = 'Present' } @@ -18,6 +21,9 @@ SwitchName = 'SETSwitch' MacAddress = '001523be0d' VMName = 'MyVM02' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } Ensure = 'Present' } } diff --git a/Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1 b/Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1 new file mode 100644 index 0000000..bc27c1f --- /dev/null +++ b/Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1 @@ -0,0 +1,21 @@ +Configuration VMAdapter +{ + Import-DscResource -ModuleName xHyper-V -Name xVMNetworkAdapter + Import-DscResource -ModuleName PSDesiredStateConfiguration + + xVMNetworkAdapter MyVM01NIC { + Id = 'MyVM01-NIC' + Name = 'MyVM01-NIC' + SwitchName = 'SETSwitch' + MacAddress = '001523be0c' + VMName = 'MyVM01' + NetworkSetting = xNetworkSettings { + Dhcp = $false + IpAddress = "192.168.0.100" + Subnet = "255.255.255.255" + DefaultGateway = "192.168.0.1" + DnsServer = "192.168.0.1" + } + Ensure = 'Present' + } +} diff --git a/Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1 b/Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1 new file mode 100644 index 0000000..b9fd007 --- /dev/null +++ b/Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1 @@ -0,0 +1,18 @@ +Configuration VMAdapter +{ + Import-DscResource -ModuleName xHyper-V -Name xVMNetworkAdapter + Import-DscResource -ModuleName PSDesiredStateConfiguration + + xVMNetworkAdapter MyVM01NIC { + Id = 'MyVM01-NIC' + Name = 'MyVM01-NIC' + SwitchName = 'SETSwitch' + MacAddress = '001523be0c' + VMName = 'MyVM01' + NetworkSetting = xNetworkSettings { + Dhcp = $true + } + VlanId = '1' + Ensure = 'Present' + } +} diff --git a/README.md b/README.md index 38d78c3..bca8684 100644 --- a/README.md +++ b/README.md @@ -368,11 +368,26 @@ Manages VMNetadapters attached to a Hyper-V virtual machine or the management OS * **`[String]` VMName** _(Required)_: Name of the VM to attach to. If you want to attach new VM Network adapter to the management OS, set this property to 'Management OS'. +* **`[xNetworkSettings]` NetworkSetting** _(Required)_: Network Settings of the network adapter. * **`[String]` MacAddress** _(Write)_: Use this to specify a Static MAC Address. If this parameter is not specified, dynamic MAC Address will be set. +* **`[String]` VlanId** _(Write)_: Use this to specify a Vlan id on the +* Network Adapter. * **`[String]` Ensure** _(Write)_: Ensures that the VM Network Adapter is Present or Absent. The default value is Present. { *Present* | Absent }. + ##### xNetworkSettings Class + +* **`[Boolean]` Dhcp** _(Required)_: Indicates if you want Dhcp enabled. +* **`[String]` IpAddress** _(Write)_: IpAddress to give the network adapter. + Only used if not Dhcp. Required if not Dhcp. +* **`[String]` Subnet** _(Write)_: Subnet to give the network adapter. + Only used if not Dhcp. Required if not Dhcp. +* **`[String]` DefaultGateway** _(Write)_: DefaultGateway to give the network adapter. + Only used if not Dhcp. +* **`[String]` DnsServer** _(Write)_: DNSServer to give the network adapter. + Only used if not Dhcp. + #### Read-Only Properties from Get-TargetResource for xVMNetworkAdapter * **`[Boolean]` DynamicMacAddress** _(Read)_: Does the VMNetworkAdapter use a @@ -384,6 +399,8 @@ Manages VMNetadapters attached to a Hyper-V virtual machine or the management OS * [Add multiple VM Network adapters to a VM](/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1) * [Add a couple of VM Network adapters in the management OS](/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1) * [Add multiple VM Network adapters to a VM using status MAC addresses](/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1) +* [Add VM Network adapters to a VM with a Vlan tag](/Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1) +* [Add VM Network adapters to a VM with a static IpAddress](/Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1) ### xVMProcessor diff --git a/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 b/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 index 8bad180..457cfe4 100644 --- a/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 +++ b/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 @@ -15,7 +15,7 @@ Import-Module .\DSCResource.Tests\TestHelper.psm1 -Force $TestEnvironment = Initialize-TestEnvironment ` -DSCModuleName $Global:DSCModuleName ` -DSCResourceName $Global:DSCResourceName ` - -TestType Unit + -TestType Unit #endregion # Begin Testing @@ -32,11 +32,26 @@ try VMName = 'ManagementOS' } + $properties = @{ + Dhcp = $true + } + + $networkSettings = New-CimInstance -ClassName xNetworkSettings -Property $properties -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly + + $propertiesStatic = @{ + Dhcp = $false + IpAddress = "192.168.0.1" + Subnet = "255.255.255.0" + } + + $networkSettingsStatic = New-CimInstance -ClassName xNetworkSettings -Property $properties -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly + $TestAdapter = [PSObject]@{ Id = $MockHostAdapter.Id Name = $MockHostAdapter.Name SwitchName = $MockHostAdapter.SwitchName VMName = $MockHostAdapter.VMName + NetworkSetting = $networkSettings } $MockAdapter = [PSObject]@{ @@ -44,16 +59,28 @@ try SwitchName = $MockHostAdapter.SwitchName IsManagementOs = $True MacAddress = '14FEB5C6CE98' - } - + } + + $MockAdapterVlanUntagged = [PSObject]@{ + OperationMode = 'Untagged' + } + + $MockAdapterVlanTagged = [PSObject]@{ + OperationMode = 'Access' + AccessVlanId = '1' + } + Describe "$($Global:DSCResourceName)\Get-TargetResource" { #Function placeholders function Get-VMNetworkAdapter { } function Set-VMNetworkAdapter { } function Remove-VMNetworkAdapter { } - function Add-VMNetworkAdapter { } + function Get-VMNetworkAdapterVlan { } + function Add-VMNetworkAdapter { } + function Get-NetworkInformation { } Context 'NetAdapter does not exist' { Mock Get-VMNetworkAdapter + Mock Get-VMNetworkAdapterVlan It 'should return ensure as absent' { $Result = Get-TargetResource ` @TestAdapter @@ -61,13 +88,44 @@ try } It 'should call the expected mocks' { Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 - } + Assert-MockCalled -commandName Get-VMNetworkAdapterVlan -Exactly 0 + } + } + + Context 'NetAdapter exists' { + Mock -CommandName Get-VMNetworkAdapter -MockWith { + $MockAdapter + } + Mock -CommandName Get-VMNetworkAdapterVlan -MockWith { + $MockAdapterVlanUntagged + } + Mock -CommandName Get-NetworkInformation -MockWith { + @{ Dhcp = $true } + } + + It 'should return adapter properties' { + $Result = Get-TargetResource @TestAdapter + $Result.Ensure | Should Be 'Present' + $Result.Name | Should Be $TestAdapter.Name + $Result.SwitchName | Should Be $TestAdapter.SwitchName + $Result.VMName | Should Be 'ManagementOS' + $Result.Id | Should Be $TestAdapter.Id + $Result.VlanId | Should -BeNullOrEmpty + $Result.NetworkSetting | Should -Not -BeNullOrEmpty + } + It 'should call the expected mocks' { + Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 + Assert-MockCalled -commandName Get-VMNetworkAdapterVlan -Exactly 1 + } } - + Context 'NetAdapter exists' { Mock -CommandName Get-VMNetworkAdapter -MockWith { $MockAdapter } + Mock -CommandName Get-VMNetworkAdapterVlan -MockWith { + $MockAdapterVlanTagged + } It 'should return adapter properties' { $Result = Get-TargetResource @TestAdapter @@ -76,9 +134,11 @@ try $Result.SwitchName | Should Be $TestAdapter.SwitchName $Result.VMName | Should Be 'ManagementOS' $Result.Id | Should Be $TestAdapter.Id + $Result.VlanId | Should Be '1' } It 'should call the expected mocks' { Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 + Assert-MockCalled -commandName Get-VMNetworkAdapterVlan -Exactly 1 } } } @@ -86,42 +146,54 @@ try Describe "$($Global:DSCResourceName)\Set-TargetResource" { #Function placeholders function Get-VMNetworkAdapter { } + function Get-VMNetworkAdapterVlan { } function Set-VMNetworkAdapter { } + function Set-VMNetworkAdapterVlan { } function Remove-VMNetworkAdapter { } - function Add-VMNetworkAdapter { } + function Add-VMNetworkAdapter { } + function Get-NetworkInformation { } + function Set-NetworkInformation { } + $newAdapter = [PSObject]@{ Id = 'UniqueString' Name = $TestAdapter.Name SwitchName = $TestAdapter.SwitchName - VMName = 'ManagementOS' + VMName = 'VMName' + NetworkSetting = $networkSettingsStatic Ensure = 'Present' } - + Context 'Adapter does not exist but should' { - + Mock Get-VMNetworkAdapter + Mock Get-VMNetworkAdapterVlan Mock Add-VMNetworkAdapter Mock Remove-VMNetworkAdapter - + Mock Set-VMNetworkAdapterVlan + Mock Set-NetworkInformation + It 'should not throw error' { - { + { Set-TargetResource @newAdapter } | Should Not Throw } It 'should call expected Mocks' { Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 + Assert-MockCalled -CommandName Set-VMNetworkAdapterVlan -Exactly 0 Assert-MockCalled -commandName Add-VMNetworkAdapter -Exactly 1 Assert-MockCalled -commandName Remove-VMNetworkAdapter -Exactly 0 + Assert-MockCalled -CommandName Set-NetworkInformation -Exactly 1 } } - Context 'Adapter exists but should not exist' { + Context 'Adapter exists but should not exist' { Mock Get-VMNetworkAdapter Mock Add-VMNetworkAdapter Mock Remove-VMNetworkAdapter + Mock Set-VMNetworkAdapterVlan It 'should not throw error' { - { + { $updateAdapter = $newAdapter.Clone() $updateAdapter.Ensure = 'Absent' Set-TargetResource @updateAdapter @@ -131,6 +203,7 @@ try Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 Assert-MockCalled -commandName Add-VMNetworkAdapter -Exactly 0 Assert-MockCalled -commandName Remove-VMNetworkAdapter -Exactly 1 + Assert-MockCalled -CommandName Set-VMNetworkAdapterVlan -Exactly 0 } } } @@ -138,20 +211,25 @@ try Describe "$($Global:DSCResourceName)\Test-TargetResource" { #Function placeholders function Get-VMNetworkAdapter { } + function Get-VMNetworkAdapterVlan { } function Set-VMNetworkAdapter { } function Remove-VMNetworkAdapter { } - function Add-VMNetworkAdapter { } + function Add-VMNetworkAdapter { } + function Get-NetworkInformation { } + $newAdapter = [PSObject]@{ Id = 'UniqueString' Name = $TestAdapter.Name SwitchName = $TestAdapter.SwitchName VMName = 'ManagementOS' + NetworkSetting = $networkSettings Ensure = 'Present' } - + Context 'Adapter does not exist but should' { Mock Get-VMNetworkAdapter - + Mock Get-VMNetworkAdapterVlan + It 'should return false' { Test-TargetResource @newAdapter | Should be $false } @@ -160,7 +238,7 @@ try } } - Context 'Adapter exists but should not exist' { + Context 'Adapter exists but should not exist' { Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } It 'should return $false' { @@ -173,7 +251,7 @@ try } } - Context 'Adapter exists and no action needed' { + Context 'Adapter exists and no action needed without Vlan tag' { Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } It 'should return true' { @@ -185,7 +263,67 @@ try } } - Context 'Adapter does not exist and no action needed' { + Context 'Adapter exists and no action needed with Vlan tag' { + Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } + Mock Get-VMNetworkAdapterVlan -MockWith { $MockAdapterVlanTagged } + Mock -CommandName Get-NetworkInformation -MockWith { + @{ Dhcp = $true } + } + + It 'should return true' { + $updateAdapter = $newAdapter.Clone() + $updateAdapter.VMName = "VMName" + $updateAdapter.MacAddress = '14FEB5C6CE98' + $updateAdapter.VlanId = '1' + Test-TargetResource @updateAdapter | Should Be $true + } + It 'should call expected Mocks' { + Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 + Assert-MockCalled -commandName Get-VMNetworkAdapterVlan -Exactly 1 + } + } + + Context 'Adapter exists but Vlan is not tagged' { + Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } + Mock Get-VMNetworkAdapterVlan + Mock -CommandName Get-NetworkInformation -MockWith { + @{ Dhcp = $true } + } + + It 'should return false' { + $updateAdapter = $newAdapter.Clone() + $updateAdapter.VMName = "VMName" + $updateAdapter.MacAddress = '14FEB5C6CE98' + $updateAdapter.VlanId = '1' + Test-TargetResource @updateAdapter | Should Be $false + } + It 'should call expected Mocks' { + Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 + Assert-MockCalled -commandName Get-VMNetworkAdapterVlan -Exactly 1 + } + } + + Context 'Adapter exists but Vlan tag is wrong' { + Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } + Mock Get-VMNetworkAdapterVlan -MockWith { $MockAdapterVlanTagged } + Mock -CommandName Get-NetworkInformation -MockWith { + @{ Dhcp = $true } + } + + It 'should return false' { + $updateAdapter = $newAdapter.Clone() + $updateAdapter.VMName = "VMName" + $updateAdapter.MacAddress = '14FEB5C6CE98' + $updateAdapter.VlanId = '2' + Test-TargetResource @updateAdapter | Should Be $false + } + It 'should call expected Mocks' { + Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 + Assert-MockCalled -commandName Get-VMNetworkAdapterVlan -Exactly 1 + } + } + + Context 'Adapter does not exist and no action needed' { Mock Get-VMNetworkAdapter It 'should return true' { @@ -197,6 +335,25 @@ try Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 } } + + Context 'Adapter exists but network settings are not correct' { + Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } + Mock Get-VMNetworkAdapterVlan -MockWith { $MockAdapterVlanTagged } + Mock -CommandName Get-NetworkInformation -MockWith { + @{ Dhcp = $false } + } + + It 'should return false' { + $updateAdapter = $newAdapter.Clone() + $updateAdapter.VMName = "VMName" + $updateAdapter.MacAddress = '14FEB5C6CE98' + Test-TargetResource @updateAdapter | Should Be $false + } + It 'should call expected Mocks' { + Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 + Assert-MockCalled -commandName Get-NetworkInformation -Exactly 1 + } + } } } From 16671c137609a6353c64542c7a98a7e20e5bcf5a Mon Sep 17 00:00:00 2001 From: Matthew Collera Date: Fri, 9 Nov 2018 16:10:53 -0500 Subject: [PATCH 2/9] Removing .vscode directory --- .vscode/analyzersettings.psd1 | 53 ----------------------------------- .vscode/launch.json | 48 ------------------------------- .vscode/settings.json | 14 --------- 3 files changed, 115 deletions(-) delete mode 100644 .vscode/analyzersettings.psd1 delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json diff --git a/.vscode/analyzersettings.psd1 b/.vscode/analyzersettings.psd1 deleted file mode 100644 index be415e4..0000000 --- a/.vscode/analyzersettings.psd1 +++ /dev/null @@ -1,53 +0,0 @@ -@{ - <# - For the custom rules to work, the DscResource.Tests repo must be - cloned. It is automatically clone as soon as any unit or - integration tests are run. - #> - CustomRulePath = '.\DSCResource.Tests\DscResource.AnalyzerRules' - - IncludeRules = @( - # DSC Resource Kit style guideline rules. - 'PSAvoidDefaultValueForMandatoryParameter', - 'PSAvoidDefaultValueSwitchParameter', - 'PSAvoidInvokingEmptyMembers', - 'PSAvoidNullOrEmptyHelpMessageAttribute', - 'PSAvoidUsingCmdletAliases', - 'PSAvoidUsingComputerNameHardcoded', - 'PSAvoidUsingDeprecatedManifestFields', - 'PSAvoidUsingEmptyCatchBlock', - 'PSAvoidUsingInvokeExpression', - 'PSAvoidUsingPositionalParameters', - 'PSAvoidShouldContinueWithoutForce', - 'PSAvoidUsingWMICmdlet', - 'PSAvoidUsingWriteHost', - 'PSDSCReturnCorrectTypesForDSCFunctions', - 'PSDSCStandardDSCFunctionsInResource', - 'PSDSCUseIdenticalMandatoryParametersForDSC', - 'PSDSCUseIdenticalParametersForDSC', - 'PSMisleadingBacktick', - 'PSMissingModuleManifestField', - 'PSPossibleIncorrectComparisonWithNull', - 'PSProvideCommentHelp', - 'PSReservedCmdletChar', - 'PSReservedParams', - 'PSUseApprovedVerbs', - 'PSUseCmdletCorrectly', - 'PSUseOutputTypeCorrectly', - 'PSAvoidGlobalVars', - 'PSAvoidUsingConvertToSecureStringWithPlainText', - 'PSAvoidUsingPlainTextForPassword', - 'PSAvoidUsingUsernameAndPasswordParams', - 'PSDSCUseVerboseMessageInDSCResource', - 'PSShouldProcess', - 'PSUseDeclaredVarsMoreThanAssignments', - 'PSUsePSCredentialType', - - <# - This is to test all the DSC Resource Kit custom rules. - The name of the function-blocks of each custom rule start - with 'Measure*'. - #> - 'Measure-*' - ) -} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 96266b0..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "PowerShell", - "request": "launch", - "name": "PowerShell Launch Current File", - "script": "${file}", - "args": [], - "cwd": "${file}" - }, - { - "type": "PowerShell", - "request": "launch", - "name": "PowerShell Launch Current File in Temporary Console", - "script": "${file}", - "args": [], - "cwd": "${file}", - "createTemporaryIntegratedConsole": true - }, - { - "type": "PowerShell", - "request": "launch", - "name": "PowerShell Launch Current File w/Args Prompt", - "script": "${file}", - "args": [ - "${command:SpecifyScriptArgs}" - ], - "cwd": "${file}" - }, - { - "type": "PowerShell", - "request": "attach", - "name": "PowerShell Attach to Host Process", - "processId": "${command:PickPSHostProcess}", - "runspaceId": 1 - }, - { - "type": "PowerShell", - "request": "launch", - "name": "PowerShell Interactive Session", - "cwd": "" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 0969e57..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "powershell.codeFormatting.openBraceOnSameLine": false, - "powershell.codeFormatting.newLineAfterOpenBrace": false, - "powershell.codeFormatting.newLineAfterCloseBrace": true, - "powershell.codeFormatting.whitespaceBeforeOpenBrace": true, - "powershell.codeFormatting.whitespaceBeforeOpenParen": true, - "powershell.codeFormatting.whitespaceAroundOperator": true, - "powershell.codeFormatting.whitespaceAfterSeparator": true, - "powershell.codeFormatting.ignoreOneLineBlock": false, - "powershell.codeFormatting.preset": "Custom", - "files.trimTrailingWhitespace": true, - "files.insertFinalNewline": true, - "powershell.scriptAnalysis.settingsPath": ".vscode\\analyzersettings.psd1" -} From 5943f4f2d9a2904fbe323d8af829fa2780f69b00 Mon Sep 17 00:00:00 2001 From: Matthew Collera Date: Fri, 9 Nov 2018 16:12:12 -0500 Subject: [PATCH 3/9] Adding .vscode folder back --- .vscode/analyzersettings.psd1 | 53 +++++++++++++++++++++++++++++++++++ .vscode/settings.json | 14 +++++++++ 2 files changed, 67 insertions(+) create mode 100644 .vscode/analyzersettings.psd1 create mode 100644 .vscode/settings.json diff --git a/.vscode/analyzersettings.psd1 b/.vscode/analyzersettings.psd1 new file mode 100644 index 0000000..be415e4 --- /dev/null +++ b/.vscode/analyzersettings.psd1 @@ -0,0 +1,53 @@ +@{ + <# + For the custom rules to work, the DscResource.Tests repo must be + cloned. It is automatically clone as soon as any unit or + integration tests are run. + #> + CustomRulePath = '.\DSCResource.Tests\DscResource.AnalyzerRules' + + IncludeRules = @( + # DSC Resource Kit style guideline rules. + 'PSAvoidDefaultValueForMandatoryParameter', + 'PSAvoidDefaultValueSwitchParameter', + 'PSAvoidInvokingEmptyMembers', + 'PSAvoidNullOrEmptyHelpMessageAttribute', + 'PSAvoidUsingCmdletAliases', + 'PSAvoidUsingComputerNameHardcoded', + 'PSAvoidUsingDeprecatedManifestFields', + 'PSAvoidUsingEmptyCatchBlock', + 'PSAvoidUsingInvokeExpression', + 'PSAvoidUsingPositionalParameters', + 'PSAvoidShouldContinueWithoutForce', + 'PSAvoidUsingWMICmdlet', + 'PSAvoidUsingWriteHost', + 'PSDSCReturnCorrectTypesForDSCFunctions', + 'PSDSCStandardDSCFunctionsInResource', + 'PSDSCUseIdenticalMandatoryParametersForDSC', + 'PSDSCUseIdenticalParametersForDSC', + 'PSMisleadingBacktick', + 'PSMissingModuleManifestField', + 'PSPossibleIncorrectComparisonWithNull', + 'PSProvideCommentHelp', + 'PSReservedCmdletChar', + 'PSReservedParams', + 'PSUseApprovedVerbs', + 'PSUseCmdletCorrectly', + 'PSUseOutputTypeCorrectly', + 'PSAvoidGlobalVars', + 'PSAvoidUsingConvertToSecureStringWithPlainText', + 'PSAvoidUsingPlainTextForPassword', + 'PSAvoidUsingUsernameAndPasswordParams', + 'PSDSCUseVerboseMessageInDSCResource', + 'PSShouldProcess', + 'PSUseDeclaredVarsMoreThanAssignments', + 'PSUsePSCredentialType', + + <# + This is to test all the DSC Resource Kit custom rules. + The name of the function-blocks of each custom rule start + with 'Measure*'. + #> + 'Measure-*' + ) +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..0969e57 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,14 @@ +{ + "powershell.codeFormatting.openBraceOnSameLine": false, + "powershell.codeFormatting.newLineAfterOpenBrace": false, + "powershell.codeFormatting.newLineAfterCloseBrace": true, + "powershell.codeFormatting.whitespaceBeforeOpenBrace": true, + "powershell.codeFormatting.whitespaceBeforeOpenParen": true, + "powershell.codeFormatting.whitespaceAroundOperator": true, + "powershell.codeFormatting.whitespaceAfterSeparator": true, + "powershell.codeFormatting.ignoreOneLineBlock": false, + "powershell.codeFormatting.preset": "Custom", + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "powershell.scriptAnalysis.settingsPath": ".vscode\\analyzersettings.psd1" +} From e7f4c9497c20a68ad8f7663d0a739616078716ae Mon Sep 17 00:00:00 2001 From: Matthew Collera Date: Mon, 12 Nov 2018 09:46:53 -0500 Subject: [PATCH 4/9] Made NetworkSettings non mandatory --- CHANGELOG.md | 3 +- .../MSFT_xVMNetworkAdapter.psm1 | 32 ++++++++----------- .../MSFT_xVMNetworkAdapter.schema.mof | 3 +- .../Sample_xVMNetworkAdapter_ManagementOS.ps1 | 3 -- ...xVMNetworkAdapter_MultipleManagementOS.ps1 | 6 ---- .../Sample_xVMNetworkAdapter_MultipleVM.ps1 | 9 ------ ...xVMNetworkAdapter_MultipleVMMACAddress.ps1 | 6 ---- ...NetworkAdapter_VMStaticNetworkSettings.ps1 | 1 - ...Sample_xVMNetworkAdapter_VMVlanTagging.ps1 | 3 -- README.md | 14 ++++---- Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 | 27 +++------------- 11 files changed, 28 insertions(+), 79 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 29aee8e..856da63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,7 @@ ## Unreleased * MSFT_xVMNetworkAdapter: - * __Breaking change:__ Added NetworkSettings to be able to statically set IPAddress or use as DHCP. This is - a required field. + * Added NetworkSettings to be able to statically set IPAddress. * Added option for Vlan tagging. You can now setup a Network Adapeter as an access switch on a specific Vlan. ## 3.13.0.0 diff --git a/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.psm1 b/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.psm1 index 9999fad..65ec9b5 100644 --- a/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.psm1 +++ b/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.psm1 @@ -47,11 +47,7 @@ Function Get-TargetResource [String] $SwitchName, [Parameter(Mandatory)] - [String] $VMName, - - [Parameter(Mandatory = $true)] - [Microsoft.Management.Infrastructure.CimInstance] - $NetworkSetting + [String] $VMName ) $configuration = @{ @@ -93,8 +89,11 @@ Function Get-TargetResource } $networkInfo = Get-NetworkInformation -VMName $VMName -Name $Name - $item = New-CimInstance -ClassName MSFT_xNetworkSettings -Property $networkInfo -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly - $configuration.Add('NetworkSetting', $item) + if($networkInfo) + { + $item = New-CimInstance -ClassName MSFT_xNetworkSettings -Property $networkInfo -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly + $configuration.Add('NetworkSetting', $item) + } $configuration.Add('Ensure','Present') @@ -163,7 +162,7 @@ Function Set-TargetResource [Parameter()] [String] $MacAddress, - [Parameter(Mandatory = $true)] + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $NetworkSetting, @@ -266,9 +265,9 @@ Function Set-TargetResource if ($VmName -ne 'ManagementOS') { $networkInfo = Get-NetworkInformation -VMName $VMName -Name $Name - if ($NetworkSetting.CimInstanceProperties["Dhcp"].Value) + if (-not $NetworkSetting) { - if (-not $networkInfo.Dhcp) + if($networkInfo) { Write-Verbose -Message $localizedData.EnableDhcp Set-NetworkInformation -VMName $VMName -Name $Name -Dhcp @@ -388,7 +387,7 @@ Function Test-TargetResource [Parameter()] [String] $MacAddress, - [Parameter(Mandatory = $true)] + [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $NetworkSetting, @@ -446,9 +445,9 @@ Function Test-TargetResource } $networkInfo = Get-NetworkInformation -VMName $VMName -Name $Name - if ($NetworkSetting.CimInstanceProperties["Dhcp"].Value) + if (-not $NetworkSetting) { - if (-not $networkInfo.Dhcp) + if($networkInfo) { Write-Verbose -Message $localizedData.NotDhcp return $false @@ -456,7 +455,7 @@ Function Test-TargetResource } else { - if ($networkInfo.Dhcp) + if (-not $networkInfo) { Write-Verbose -Message $localizedData.Dhcp return $false @@ -586,14 +585,11 @@ function Get-NetworkInformation if ($networkSettings.DHCPEnabled) { - return @{ - Dhcp = $true - } + return $null } else { return @{ - Dhcp = $false IpAddress = $networkSettings.IPAddresses -join ',' Subnet = $networkSettings.Subnets -join ',' DefaultGateway = $networkSettings.DefaultGateways -join ',' diff --git a/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.schema.mof b/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.schema.mof index 8b9334d..8929134 100644 --- a/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.schema.mof +++ b/DSCResources/MSFT_xVMNetworkAdapter/MSFT_xVMNetworkAdapter.schema.mof @@ -2,7 +2,6 @@ [ClassVersion("2.0.0.0")] Class xNetworkSettings { - [Required] Boolean Dhcp; [Write] string IpAddress; [Write] string Subnet; [Write] string DefaultGateway; @@ -17,7 +16,7 @@ class MSFT_xVMNetworkAdapter : OMI_BaseResource [Required] String SwitchName; [Required] String VMName; [Write] String MacAddress; - [Required, EmbeddedInstance("xNetworkSettings")] String NetworkSetting; + [Write, EmbeddedInstance("xNetworkSettings")] String NetworkSetting; [Write] String VlanId; [Write, ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; [Read] Boolean DynamicMacAddress; diff --git a/Examples/Sample_xVMNetworkAdapter_ManagementOS.ps1 b/Examples/Sample_xVMNetworkAdapter_ManagementOS.ps1 index d787341..7be0ae5 100644 --- a/Examples/Sample_xVMNetworkAdapter_ManagementOS.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_ManagementOS.ps1 @@ -8,9 +8,6 @@ Name = 'Management-NIC' SwitchName = 'SETSwitch' VMName = 'ManagementOS' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } Ensure = 'Present' } } diff --git a/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1 b/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1 index c02efd1..a0cd100 100644 --- a/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_MultipleManagementOS.ps1 @@ -8,9 +8,6 @@ Name = 'Management-NIC' SwitchName = 'SETSwitch' VMName = 'ManagementOS' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } Ensure = 'Present' } @@ -19,9 +16,6 @@ Name = 'Cluster-NIC' SwitchName = 'SETSwitch' VMName = 'ManagementOS' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } Ensure = 'Present' } } diff --git a/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1 b/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1 index 8d9d51e..56d0a55 100644 --- a/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_MultipleVM.ps1 @@ -8,9 +8,6 @@ Name = 'MyVM01-NIC' SwitchName = 'SETSwitch' VMName = 'MyVM01' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } Ensure = 'Present' } @@ -19,9 +16,6 @@ Name = 'NetAdapter' SwitchName = 'SETSwitch' VMName = 'MyVM02' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } Ensure = 'Present' } @@ -30,9 +24,6 @@ Name = 'NetAdapter' SwitchName = 'SETSwitch' VMName = 'MyVM03' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } Ensure = 'Present' } } diff --git a/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1 b/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1 index b601379..80f0ead 100644 --- a/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_MultipleVMMACAddress.ps1 @@ -9,9 +9,6 @@ SwitchName = 'SETSwitch' MacAddress = '001523be0c' VMName = 'MyVM01' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } Ensure = 'Present' } @@ -21,9 +18,6 @@ SwitchName = 'SETSwitch' MacAddress = '001523be0d' VMName = 'MyVM02' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } Ensure = 'Present' } } diff --git a/Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1 b/Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1 index bc27c1f..2d192bc 100644 --- a/Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_VMStaticNetworkSettings.ps1 @@ -10,7 +10,6 @@ MacAddress = '001523be0c' VMName = 'MyVM01' NetworkSetting = xNetworkSettings { - Dhcp = $false IpAddress = "192.168.0.100" Subnet = "255.255.255.255" DefaultGateway = "192.168.0.1" diff --git a/Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1 b/Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1 index b9fd007..0c17245 100644 --- a/Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1 +++ b/Examples/Sample_xVMNetworkAdapter_VMVlanTagging.ps1 @@ -9,9 +9,6 @@ SwitchName = 'SETSwitch' MacAddress = '001523be0c' VMName = 'MyVM01' - NetworkSetting = xNetworkSettings { - Dhcp = $true - } VlanId = '1' Ensure = 'Present' } diff --git a/README.md b/README.md index bca8684..8a0d8d7 100644 --- a/README.md +++ b/README.md @@ -363,22 +363,22 @@ Manages VMNetadapters attached to a Hyper-V virtual machine or the management OS * **`[String]` Id** _(Key)_: Unique string for identifying the resource instance. * **`[String]` Name** _(Required)_: Name of the network adapter as it appears either - in the management OS or attached to a VM. +in the management OS or attached to a VM. * **`[String]` SwitchName** _(Required)_: Virtual Switch name to connect to. * **`[String]` VMName** _(Required)_: Name of the VM to attach to. - If you want to attach new VM Network adapter to the management OS, - set this property to 'Management OS'. -* **`[xNetworkSettings]` NetworkSetting** _(Required)_: Network Settings of the network adapter. +If you want to attach new VM Network adapter to the management OS, +set this property to 'Management OS'. +* **`[xNetworkSettings]` NetworkSetting** _(Write)_: Network Settings of the network adapter. +If not supplied thne network adapter will be set for DHCP. * **`[String]` MacAddress** _(Write)_: Use this to specify a Static MAC Address. - If this parameter is not specified, dynamic MAC Address will be set. +If this parameter is not specified, dynamic MAC Address will be set. * **`[String]` VlanId** _(Write)_: Use this to specify a Vlan id on the * Network Adapter. * **`[String]` Ensure** _(Write)_: Ensures that the VM Network Adapter is - Present or Absent. The default value is Present. { *Present* | Absent }. +Present or Absent. The default value is Present. { *Present* | Absent }. ##### xNetworkSettings Class -* **`[Boolean]` Dhcp** _(Required)_: Indicates if you want Dhcp enabled. * **`[String]` IpAddress** _(Write)_: IpAddress to give the network adapter. Only used if not Dhcp. Required if not Dhcp. * **`[String]` Subnet** _(Write)_: Subnet to give the network adapter. diff --git a/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 b/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 index 457cfe4..b619402 100644 --- a/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 +++ b/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 @@ -32,14 +32,7 @@ try VMName = 'ManagementOS' } - $properties = @{ - Dhcp = $true - } - - $networkSettings = New-CimInstance -ClassName xNetworkSettings -Property $properties -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly - $propertiesStatic = @{ - Dhcp = $false IpAddress = "192.168.0.1" Subnet = "255.255.255.0" } @@ -51,7 +44,6 @@ try Name = $MockHostAdapter.Name SwitchName = $MockHostAdapter.SwitchName VMName = $MockHostAdapter.VMName - NetworkSetting = $networkSettings } $MockAdapter = [PSObject]@{ @@ -99,9 +91,7 @@ try Mock -CommandName Get-VMNetworkAdapterVlan -MockWith { $MockAdapterVlanUntagged } - Mock -CommandName Get-NetworkInformation -MockWith { - @{ Dhcp = $true } - } + Mock -CommandName Get-NetworkInformation It 'should return adapter properties' { $Result = Get-TargetResource @TestAdapter @@ -111,7 +101,7 @@ try $Result.VMName | Should Be 'ManagementOS' $Result.Id | Should Be $TestAdapter.Id $Result.VlanId | Should -BeNullOrEmpty - $Result.NetworkSetting | Should -Not -BeNullOrEmpty + $Result.NetworkSetting | Should -BeNullOrEmpty } It 'should call the expected mocks' { Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 @@ -222,7 +212,6 @@ try Name = $TestAdapter.Name SwitchName = $TestAdapter.SwitchName VMName = 'ManagementOS' - NetworkSetting = $networkSettings Ensure = 'Present' } @@ -266,9 +255,7 @@ try Context 'Adapter exists and no action needed with Vlan tag' { Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } Mock Get-VMNetworkAdapterVlan -MockWith { $MockAdapterVlanTagged } - Mock -CommandName Get-NetworkInformation -MockWith { - @{ Dhcp = $true } - } + Mock -CommandName Get-NetworkInformation It 'should return true' { $updateAdapter = $newAdapter.Clone() @@ -286,9 +273,7 @@ try Context 'Adapter exists but Vlan is not tagged' { Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } Mock Get-VMNetworkAdapterVlan - Mock -CommandName Get-NetworkInformation -MockWith { - @{ Dhcp = $true } - } + Mock -CommandName Get-NetworkInformation It 'should return false' { $updateAdapter = $newAdapter.Clone() @@ -306,9 +291,7 @@ try Context 'Adapter exists but Vlan tag is wrong' { Mock Get-VMNetworkAdapter -MockWith { $MockAdapter } Mock Get-VMNetworkAdapterVlan -MockWith { $MockAdapterVlanTagged } - Mock -CommandName Get-NetworkInformation -MockWith { - @{ Dhcp = $true } - } + Mock -CommandName Get-NetworkInformation It 'should return false' { $updateAdapter = $newAdapter.Clone() From e3b69b508202bb811464b38ac51179516655b15e Mon Sep 17 00:00:00 2001 From: Matthew Collera Date: Mon, 12 Nov 2018 10:02:01 -0500 Subject: [PATCH 5/9] Fixed read me --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8a0d8d7..f8f1ebc 100644 --- a/README.md +++ b/README.md @@ -363,21 +363,21 @@ Manages VMNetadapters attached to a Hyper-V virtual machine or the management OS * **`[String]` Id** _(Key)_: Unique string for identifying the resource instance. * **`[String]` Name** _(Required)_: Name of the network adapter as it appears either -in the management OS or attached to a VM. + in the management OS or attached to a VM. * **`[String]` SwitchName** _(Required)_: Virtual Switch name to connect to. * **`[String]` VMName** _(Required)_: Name of the VM to attach to. -If you want to attach new VM Network adapter to the management OS, -set this property to 'Management OS'. + If you want to attach new VM Network adapter to the management OS, + set this property to 'Management OS'. * **`[xNetworkSettings]` NetworkSetting** _(Write)_: Network Settings of the network adapter. -If not supplied thne network adapter will be set for DHCP. + If not supplied thne network adapter will be set for DHCP. * **`[String]` MacAddress** _(Write)_: Use this to specify a Static MAC Address. -If this parameter is not specified, dynamic MAC Address will be set. + If this parameter is not specified, dynamic MAC Address will be set. * **`[String]` VlanId** _(Write)_: Use this to specify a Vlan id on the * Network Adapter. * **`[String]` Ensure** _(Write)_: Ensures that the VM Network Adapter is -Present or Absent. The default value is Present. { *Present* | Absent }. + Present or Absent. The default value is Present. { *Present* | Absent }. - ##### xNetworkSettings Class +##### xNetworkSettings Class * **`[String]` IpAddress** _(Write)_: IpAddress to give the network adapter. Only used if not Dhcp. Required if not Dhcp. From aadca3664a5dbfd2d70a31c9495a880df7cee13c Mon Sep 17 00:00:00 2001 From: Matthew Collera Date: Wed, 15 May 2019 08:46:14 -0400 Subject: [PATCH 6/9] fixed test --- Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 b/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 index b619402..cd65429 100644 --- a/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 +++ b/Tests/Unit/MSFT_xVMNetworkAdapter.Tests.ps1 @@ -91,7 +91,14 @@ try Mock -CommandName Get-VMNetworkAdapterVlan -MockWith { $MockAdapterVlanUntagged } - Mock -CommandName Get-NetworkInformation + Mock -CommandName Get-NetworkInformation -MockWith { + return @{ + IpAddress = '10.10.10.10' + Subnet = '255.255.255.0' + DefaultGateway = '10.10.10.1' + DnsServer = '10.10.10.1' + } + } It 'should return adapter properties' { $Result = Get-TargetResource @TestAdapter @@ -101,7 +108,7 @@ try $Result.VMName | Should Be 'ManagementOS' $Result.Id | Should Be $TestAdapter.Id $Result.VlanId | Should -BeNullOrEmpty - $Result.NetworkSetting | Should -BeNullOrEmpty + $Result.NetworkSetting | Should -Not -BeNullOrEmpty } It 'should call the expected mocks' { Assert-MockCalled -commandName Get-VMNetworkAdapter -Exactly 1 From 92686794d46e5f88a1b56fdd281ea59c772d25c1 Mon Sep 17 00:00:00 2001 From: Anthony Romano Date: Thu, 1 Aug 2019 14:11:47 -0400 Subject: [PATCH 7/9] cleaned up whitespace --- .../MSFT_xVhdFileDirectory.psm1 | 142 +++++++++--------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/DSCResources/MSFT_xVhdFileDirectory/MSFT_xVhdFileDirectory.psm1 b/DSCResources/MSFT_xVhdFileDirectory/MSFT_xVhdFileDirectory.psm1 index b808bd5..218d243 100644 --- a/DSCResources/MSFT_xVhdFileDirectory/MSFT_xVhdFileDirectory.psm1 +++ b/DSCResources/MSFT_xVhdFileDirectory/MSFT_xVhdFileDirectory.psm1 @@ -1,6 +1,6 @@ <# -# Get the current configuration of the machine +# Get the current configuration of the machine # This function is called when you do Get-DscConfiguration after the configuration is set. #> function Get-TargetResource @@ -26,7 +26,7 @@ function Get-TargetResource if ( -not (Test-path $VhdPath)) { $item = New-CimInstance -ClassName MSFT_FileDirectoryConfiguration -Property @{DestinationPath = $VhdPath; Ensure = "Absent"} -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly - + Return @{ VhdPath = $VhdPath FileDirectory = $item @@ -35,18 +35,18 @@ function Get-TargetResource # Mount VHD. $mountVHD = EnsureVHDState -Mounted -vhdPath $vhdPath - + $itemsFound = foreach($Item in $FileDirectory) { $item = GetItemToCopy -item $item $mountedDrive = $mountVHD | Get-Disk | Get-Partition | Where-Object -FilterScript {$_.Type -ne 'Recovery'} | Get-Volume $letterDrive = (-join $mountedDrive.DriveLetter) + ":\" - + # show the drive letters. - Get-PSDrive | Write-Verbose + Get-PSDrive | Write-Verbose $finalPath = Join-Path $letterDrive $item.DestinationPath - + Write-Verbose "Getting the current value at $finalPath ..." if (Test-Path $finalPath) @@ -54,19 +54,19 @@ function Get-TargetResource New-CimInstance -ClassName MSFT_FileDirectoryConfiguration -Property @{DestinationPath = $finalPath; Ensure = "Present"} -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly } else - { - New-CimInstance -ClassName MSFT_FileDirectoryConfiguration -Property @{DestinationPath = $finalPath ; Ensure = "Absent"} -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly + { + New-CimInstance -ClassName MSFT_FileDirectoryConfiguration -Property @{DestinationPath = $finalPath ; Ensure = "Absent"} -Namespace root/microsoft/windows/desiredstateconfiguration -ClientOnly } } # Dismount VHD. - EnsureVHDState -Dismounted -vhdPath $VhdPath - + EnsureVHDState -Dismounted -vhdPath $VhdPath + # Return the result. Return @{ VhdPath = $VhdPath FileDirectory = $itemsFound - } + } } @@ -83,15 +83,15 @@ function Set-TargetResource [Parameter(Mandatory = $true)] [Microsoft.Management.Infrastructure.CimInstance[]] $FileDirectory, - + [Parameter()] [ValidateSet('ModifiedDate','SHA-1','SHA-256','SHA-512')] [System.String] $CheckSum = 'ModifiedDate' ) - if (-not (Test-Path $VhdPath)) { throw "Specified destination path $VhdPath does not exist!"} - + if (-not (Test-Path $VhdPath)) { throw "Specified destination path $VhdPath does not exist!"} + # mount the VHD. $mountedVHD = EnsureVHDState -Mounted -vhdPath $VhdPath @@ -101,15 +101,15 @@ function Set-TargetResource Get-PSDrive | Write-Verbose $mountedDrive = $mountedVHD | Get-Disk | Get-Partition | Where-Object -FilterScript {$_.Type -ne 'Recovery'} | Get-Volume - + foreach ($item in $FileDirectory) { $itemToCopy = GetItemToCopy -item $item $letterDrive = (-join $mountedDrive.DriveLetter) + ":\" $finalDestinationPath = $letterDrive $finalDestinationPath = Join-Path $letterDrive $itemToCopy.DestinationPath - - # if the destination should be removed + + # if the destination should be removed if (-not($itemToCopy.Ensure)) { if (Test-Path $finalDestinationPath) @@ -136,7 +136,7 @@ function Set-TargetResource # Create file/folder scenario SetVHDFile -destinationPath $finalDestinationPath -type $itemToCopy.Type -force:($itemToCopy.Force) -content $itemToCopy.Content - } + } # Set Attribute scenario if ($itemToCopy.Attributes) @@ -150,7 +150,7 @@ function Set-TargetResource finally { EnsureVHDState -Dismounted -vhdPath $VhdPath - } + } } # This function returns if the current configuration of the machine is the same as the desired configration for this resource. @@ -167,7 +167,7 @@ function Test-TargetResource [Parameter(Mandatory = $true)] [Microsoft.Management.Infrastructure.CimInstance[]] $FileDirectory, - + [Parameter()] [ValidateSet('ModifiedDate','SHA-1','SHA-256','SHA-512')] [System.String] @@ -178,14 +178,14 @@ function Test-TargetResource if ( -not (Test-Path $VhdPath)) { throw "VHD does not exist in the specified path $VhdPath" - } + } # mount the vhd. $mountedVHD = EnsureVHDState -Mounted -vhdPath $VhdPath - try + try { - # Show the drive letters after mount + # Show the drive letters after mount Get-PSDrive | Write-Verbose $mountedDrive = $mountedVHD | Get-Disk | Get-Partition | Where-Object -FilterScript {$_.Type -ne 'Recovery'} | Get-Volume @@ -196,16 +196,16 @@ function Test-TargetResource $result = $true foreach ($item in $FileDirectory) - { + { $itemToCopy = GetItemToCopy -item $item - $destination = $itemToCopy.DestinationPath + $destination = $itemToCopy.DestinationPath Write-Verbose ("Testing the file with relative VHD destination $destination") $destination = $itemToCopy.DestinationPath $finalDestinationPath = $letterDrive - $finalDestinationPath = Join-Path $letterDrive $destination + $finalDestinationPath = Join-Path $letterDrive $destination - if (Test-Path $finalDestinationPath) - { + if (Test-Path $finalDestinationPath) + { if( -not ($itemToCopy.Ensure)) { $result = $false @@ -219,7 +219,7 @@ function Test-TargetResource if ($itemToCopyIsFile -and $destinationIsFolder) { # Verify if the file exist inside the folder - $fileName = Split-Path $itemToCopy.SourcePath -Leaf + $fileName = Split-Path $itemToCopy.SourcePath -Leaf Write-Verbose "Checking if $fileName exist under $finalDestinationPath" $fileExistInDestination = Test-Path (Join-Path $finalDestinationPath $fileName) @@ -227,12 +227,12 @@ function Test-TargetResource Write-Verbose "File exist on the destination under $finalDestinationPath :- $fileExistInDestination" $result = $fileExistInDestination $result = $result -and -not(ItemHasChanged -sourcePath $itemToCopy.SourcePath -destinationPath (Join-Path $finalDestinationPath $fileName) -CheckSum $CheckSum) - } - + } + if (($itemToCopy.Type -eq "Directory") -and ($itemToCopy.Recurse)) { $result = $result -and -not(ItemHasChanged -sourcePath $itemToCopy.SourcePath -destinationPath $finalDestinationPath -CheckSum $CheckSum) - + if (-not ($result)) { break; @@ -247,39 +247,39 @@ function Test-TargetResource { $result = $false break; - } + } } - # Check the attribute + # Check the attribute if ($itemToCopy.Attributes) { $currentAttribute = @(Get-ItemProperty -Path $finalDestinationPath | ForEach-Object -MemberName Attributes) $result = $currentAttribute.Contains($itemToCopy.Attributes) - } + } } } finally { EnsureVHDState -Dismounted -vhdPath $VhdPath } - + Write-Verbose "Test returned $result" return $result; } # Assert the state of the VHD. -function EnsureVHDState +function EnsureVHDState { - [CmdletBinding(DefaultParametersetName="Mounted")] - param( - + [CmdletBinding(DefaultParametersetName="Mounted")] + param( + [Parameter(ParameterSetName = "Mounted")] [switch]$Mounted, - [Parameter(ParameterSetName = "Dismounted")] + [Parameter(ParameterSetName = "Dismounted")] [switch]$Dismounted, [Parameter(Mandatory=$true)] - $vhdPath + $vhdPath ) if ( -not ( Get-Module -ListAvailable Hyper-v)) @@ -295,10 +295,10 @@ function EnsureVHDState if ($var) { Write-Verbose "Mounting Failed. Attempting to dismount and mount it back" - Dismount-VHD $vhdPath + Dismount-VHD $vhdPath $mountedVHD = Mount-VHD -Path $vhdPath -Passthru -ErrorAction SilentlyContinue - return $mountedVHD + return $mountedVHD } else { @@ -308,7 +308,7 @@ function EnsureVHDState else { Dismount-VHD $vhdPath -ea SilentlyContinue - + } } @@ -319,12 +319,12 @@ function GetItemToCopy [Parameter()] [Microsoft.Management.Infrastructure.CimInstance] $item ) - + #Initialize Return Object $returnValue = @{} - + #Define Default Values - + $DesiredProperties = [ordered]@{ 'SourcePath' = $null 'DestinationPath' = $null @@ -335,11 +335,11 @@ function GetItemToCopy 'Attributes' = $null 'Type' = 'Directory' } - + [string[]]($DesiredProperties.Keys) | Foreach-Object -Process { #Get Property Value $thisItem = $item.CimInstanceProperties[$_].Value - + if (-not $thisItem -and $_ -in $DefaultValues.Keys) { #If unset and a default value is defined enter here @@ -361,20 +361,20 @@ function GetItemToCopy $returnValue[$_] = $item.CimInstanceProperties[$_].Value } } - + #Relies on default values in the $DesiredProperties object being the $True equivalent values $PropertyValuesToBoolean = @( 'Force', 'Recurse', 'Ensure' ) - + # Convert string values to boolean for ease of programming. $PropertyValuesToBoolean | ForEach-Object -Process { $returnValue[$_] = $returnValue[$_] -eq $DesiredProperties[$_] } - - + + $returnValue.Keys | ForEach-Object -Process { Write-Verbose "$_ => $($returnValue[$_])" } @@ -386,30 +386,30 @@ function GetItemToCopy # This is the main function that gets called after the file is mounted to perform copy, set or new operations on the mounted drive. function SetVHDFile { - [CmdletBinding(DefaultParametersetName="Copy")] - param( + [CmdletBinding(DefaultParametersetName="Copy")] + param( [Parameter(Mandatory=$true,ParameterSetName = "Copy")] - $sourcePath, + $sourcePath, [Parameter()] [switch]$recurse, [Parameter()] [switch]$force, - [Parameter(ParameterSetName = "New")] + [Parameter(ParameterSetName = "New")] $type, - [Parameter(ParameterSetName = "New")] - $content, + [Parameter(ParameterSetName = "New")] + $content, [Parameter(Mandatory=$true)] - $destinationPath, - [Parameter(Mandatory=$true,ParameterSetName = "Set")] + $destinationPath, + [Parameter(Mandatory=$true,ParameterSetName = "Set")] $attribute, [Parameter(Mandatory=$true,ParameterSetName = "Delete")] - [switch]$ensure - ) - + [switch]$ensure + ) + Write-Verbose "Setting the VHD file $($PSCmdlet.ParameterSetName)" if ($PSCmdlet.ParameterSetName -eq 'Copy') { - New-Item -Path (Split-Path $destinationPath) -ItemType Directory -ErrorAction SilentlyContinue + New-Item -Path (Split-Path $destinationPath) -ItemType Directory -ErrorAction SilentlyContinue Copy-Item -Path $sourcePath -Destination $destinationPath -Force:$force -Recurse:$recurse -ErrorAction SilentlyContinue } elseif ($PSCmdlet.ParameterSetName -eq 'New') @@ -421,7 +421,7 @@ function SetVHDFile else { New-Item -Path $destinationPath -ItemType $type - $content | Out-File $destinationPath + $content | Out-File $destinationPath } } @@ -441,7 +441,7 @@ function ItemHasChanged { param( [Parameter(Mandatory=$true)] - [ValidateScript({Test-Path $_})] + [ValidateScript({Test-Path $_})] $sourcePath, [Parameter(Mandatory=$true)] [ValidateScript({Test-Path $_})] @@ -451,7 +451,7 @@ function ItemHasChanged $CheckSum = 'ModifiedDate' ) - $itemIsFolder = Test-Path $sourcePath -Type Container + $itemIsFolder = Test-Path $sourcePath -Type Container $sourceItems = $null; $destinationItems = $null; @@ -472,7 +472,7 @@ function ItemHasChanged { return $true; } - + # Compute the difference using the algorithem specified. $difference = $null @@ -481,7 +481,7 @@ function ItemHasChanged 'ModifiedDate' { $difference = Compare-Object -ReferenceObject $sourceItems -DifferenceObject $destinationItems -Property LastWriteTime - } + } 'SHA-1' { $difference = Compare-Object -ReferenceObject ($sourceItems | Get-FileHash -Algorithm SHA1) -DifferenceObject ($destinationItems | Get-FileHash -Algorithm SHA1) -Property Hash From fd9437726ae03312c9258396b2bcf060b1321c52 Mon Sep 17 00:00:00 2001 From: Anthony Romano Date: Thu, 1 Aug 2019 16:09:45 -0400 Subject: [PATCH 8/9] fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 98f620a..ce8f76f 100644 --- a/README.md +++ b/README.md @@ -371,7 +371,7 @@ Manages VMNetadapters attached to a Hyper-V virtual machine or the management OS If you want to attach new VM Network adapter to the management OS, set this property to 'Management OS'. * **`[xNetworkSettings]` NetworkSetting** _(Write)_: Network Settings of the network adapter. - If not supplied thne network adapter will be set for DHCP. + If this parameter is not supplied, DHCP will be used. * **`[String]` MacAddress** _(Write)_: Use this to specify a Static MAC Address. If this parameter is not specified, dynamic MAC Address will be set. * **`[String]` VlanId** _(Write)_: Use this to specify a Vlan id on the From 4aaad6386ef637e58372c7eaaa4446eeabff5a83 Mon Sep 17 00:00:00 2001 From: Michael Greene Date: Wed, 30 Oct 2019 10:29:08 -0500 Subject: [PATCH 9/9] Releasing version 3.17.0.0 --- CHANGELOG.md | 2 ++ xHyper-V.psd1 | 14 +++++--------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index adc493a..d82d90d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +## 3.17.0.0 + * MSFT_xVMNetworkAdapter: * Added NetworkSettings to be able to statically set IPAddress. * Added option for Vlan tagging. You can now setup a Network Adapeter as an access switch on a specific Vlan. diff --git a/xHyper-V.psd1 b/xHyper-V.psd1 index e323b5d..e4809a6 100644 --- a/xHyper-V.psd1 +++ b/xHyper-V.psd1 @@ -1,6 +1,6 @@ @{ # Version number of this module. -moduleVersion = '3.16.0.0' +moduleVersion = '3.17.0.0' # ID used to uniquely identify this module GUID = 'f5a5f169-7026-4053-932a-19a7c37b1ca5' @@ -47,14 +47,9 @@ PrivateData = @{ # IconUri = '' # ReleaseNotes of this module - ReleaseNotes = '* MSFT_xVMHyperV: - * Moved localization string data to own file. - * Fixed code styling issues. - * Fixed bug where StartupMemory was not evaluated in Test-TargetResource. - * Redo of abandoned PRs: - * [PR 148](https://github.com/PowerShell/xHyper-V/pull/148), Fixes [Issue 149](https://github.com/PowerShell/xHyper-V/issues/149). - * [PR 67](https://github.com/PowerShell/xHyper-V/pull/67), Fixes [Issue 145](https://github.com/PowerShell/xHyper-V/issues/145). - * Fixed Get throws error when NetworkAdapters are not attached or missing properties. + ReleaseNotes = '* MSFT_xVMNetworkAdapter: + * Added NetworkSettings to be able to statically set IPAddress. + * Added option for Vlan tagging. You can now setup a Network Adapeter as an access switch on a specific Vlan. ' @@ -77,3 +72,4 @@ PrivateData = @{ +