Hyper-VのVM作成自動化とテスト

function New-HyperVVirtualMachine {
<#
.SYNOPSIS
Create virtual machine on Hyper-V using template vhdx file.

.EXAMPLE
New-HyperVVirtualMachine -VMNames $VMNames -VHDXSourcePath $VHDXSourcePath

.NOTES
Should be prepared template vhdx file.
Should run local administrator user.
#>    
    [CmdletBinding()]     
    Param
    (
        [Parameter(ValueFromPipeline=$true,Mandatory=$true)]
        [String[]]$VMNames,

        [Parameter(Mandatory=$false)]
        [String]$VHDXDir = (Get-VMHost).VirtualHardDiskPath,

        [Parameter(Mandatory=$true)]
        [String]$VHDXSourcePath,        
        
        [Parameter(Mandatory=$false)]
        [int]$ProcessorCount = 2,

        [Parameter(Mandatory=$false)]
        [int]$Generation = 1,

        [Parameter(Mandatory=$false)]
        [Int64]$ServerMaximumMemoryMB = 4096MB,

        [Parameter(Mandatory=$false)]
        [Int64]$ServerMinimumMemoryMB = 512MB,

        [Parameter(Mandatory=$false)]
        [Int64]$MemoryStartupBytes = 512MB,

        [Parameter(Mandatory=$false)]
        [Int64]$VHDXDiskSizeBytes = 127GB,        

        [Parameter(Mandatory=$false)]
        [String]$SwitchType = "Internal",

        [Parameter(Mandatory=$false)]
        [String]$SwitchName = "InternalSwitch"
    )
    Begin
    {
        Import-Module Hyper-V
        if(!(Test-Path -Path $VHDXDir)) { New-Item $VHDXDir -ItemType Directory | Out-Null }
        if ((Get-VMSwitch).SwitchType -notcontains $SwitchType -and (Get-VMSwitch).Name -notcontains $SwitchName) {
            New-VMSwitch -Name $SwitchName -SwitchType $SwitchType | Out-Null
        }

        $VMSettings = @{
          "ProcessorCount" = $ProcessorCount
          "MemoryMinimumBytes" = $ServerMinimumMemoryMB
          "MemoryMaximumBytes" = $ServerMaximumMemoryMB
          "DynamicMemory" = $true
          "Passthru" = $true
        }
    }
    Process
    {
        foreach($VMName in $VMNames) {
            try {
                $VHDXPath = (New-VHD -Path "$($VHDXDir)\$($VMName).vhdx" `
                                     -ParentPath $VHDXSourcePath `
                                     -SizeBytes $VHDXDiskSizeBytes `
                                     -ErrorAction Stop).Path
            }
            catch {
                Write-Verbose $_
                return 1
            }
            $VMParams = @{
                "Name" = [String]$VMName
                "Generation" = $Generation
                "MemoryStartupBytes" = $MemoryStartupBytes
                "SwitchName" = $SwitchName
                "VHDPath" = $VHDXPath
            }
            Write-Verbose "Creating VM : $($VMName)"
            New-VM @VMParams | Set-VM @VMSettings | Start-VM
            Write-Verbose "$($VMName) created successfully"
        }
        Write-Verbose "VM created successfully"        
    }
    End {}
}
function Remove-HyperVVirtualMachine {
<#
.SYNOPSIS
Delete virtual machine and vhdx file.

.EXAMPLE
Remove-HyperVVirtualMachine -VMNames $VMNames

.NOTES
Should run local administrator user.
#>       
    [CmdletBinding()]     
    Param
    (
        [Parameter(ValueFromPipeline=$true,Mandatory=$true)]
        [String[]]$VMNames,  

        [Parameter(Mandatory=$false)]
        [String]$VHDXDir = (Get-VMHost).VirtualHardDiskPath        
    )
    Import-Module Hyper-V
    foreach ($VMName in $VMNames) {
        Stop-VM $VMName -Force -ErrorAction SilentlyContinue
        Remove-VM $VMName -Force -ErrorAction SilentlyContinue
        Remove-Item (Join-Path $VHDXDir "$($VMName).vhdx") -ErrorAction SilentlyContinue
    }
}
$parent = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$parent\$sut"
. "$parent\Remove-HyperVVirtualMachine.ps1"
$TestConfig = Get-Content .\testData.json | ConvertFrom-Json
$PSDefaultParameterValues = @{
    "New-HyperVVirtualMachine:VMNames" = $TestConfig.VMNames.VMName
    "New-HyperVVirtualMachine:VHDXSourcePath" = $TestConfig.VHDXSourcePath
    "Remove-HyperVVirtualMachine:VMNames" = $TestConfig.VMNames.VMName
}

Describe "New-HyperVVirtualMachine" {
    Context "Run function nomally" {
        It "shold return null for creating VMs successfully" {
            Remove-HyperVVirtualMachine
            New-HyperVVirtualMachine | Should BeNullOrEmpty
        }
           It "Throw" {
        {throw "error message"} | Should Throw "error message"
    }
        It "should get specific vhdx file" {
            $VHDXDir = (Get-VMHost).VirtualHardDiskPath
            $VHDXFiles = (Get-ChildItem $VHDXDir).Name
            foreach ($VMName in $TestConfig.VMNames.VMName) {
                [Regex]::Match($VHDXFiles, $VMName).Success | Should Be $true   
            }
        }
        It "should get specific virtual machine" {
            foreach ($VMName in $TestConfig.VMNames.VMName) {            
                (Get-VM).Name -contains $VMName | Should Be $true
            }
        }
        It "should return exception value" {
            New-HyperVVirtualMachine | Should Be 1
        }
        Remove-HyperVVirtualMachine
    }
}
[
    {
        "VHDXSourcePath": "C:\\somewhere.vhdx",
        "VMNames":
        [
            {
                "VMName": "VM01"
            },
            {
                "VMName": "VM02"
            }
        ]
    }
]

VMをPowersehllから操作するための準備

3. WinRM起動

接続されるPCで実行

Enable-PSRemoting -Force
Enter-PSSession -ComputerName localhost

4. Firewall無効化

接続されるPCで実行

Get-NetFirewallProfile | Set-NetFirewallProfile -Enabled false

5. TrustedHosts設定

接続するPCで実行

Set-Item WSMan:\localhost\Client\TrustedHosts -Value * -Force
Get-Item WSMan:\localhost\Client\TrustedHosts
# Type            Name                           SourceOfValue   Value
# ----            ----                           -------------   -----
# System.String   TrustedHosts                                   *

6. PowershellからVMに接続

$cred = Get-Credential
Enter-PSSession -ComputerName "IP or HostName" -Credential $cred