PSHVTag.psm1
Write-Verbose 'Importing from [C:\MyProjects\PSHVTag\PSHVTag\private]' # .\PSHVTag\private\Convert-VMNoteTagsToObject.ps1 function Convert-VMNoteTagsToObject { <# .SYNOPSIS Converts a Vm object to Vm object including tags .DESCRIPTION Converts a Hyper-V VM object including State, Status and Notes to a VMWithTag Object including the custom Tag information .PARAMETER VM A Hyper-V VM object including, State, Status and Notes. .EXAMPLE Get-VM -Name 'Test1' | Convert-VMNoteTagsToObject #> [CmdletBinding()] param( [Parameter(Mandatory = $true, ValueFromPipeline)] $VM ) $VM.Notes -Match '(\<Env\>(?<Environment>.+)\<\/Env\>|\<Service\>(?<Service>.+)\<\/Service\>|\<DependsOn\>(?<DependsOn>.+)\<\/DependsOn\>)+' |Out-Null #[VMWithTag]::new('PI-LAB-GW03',(New-Guid),'PI-LAB','Network',@('HY','AZ')) #$VmWithTag = [VMWithTag]::new($VM.Name, $Vm, ($Matches.Environment -split ','), ($Matches.Service -split ','), ($Matches.DependsOn -split ',')) $VmWithTag = [VMWithTag]::new($VM.Name, $Vm, ($Matches.Environment -split ',' | Where-Object {$_ -ne ''}), ($Matches.Service -split ','| Where-Object {$_ -ne ''}), ($Matches.DependsOn -split ','| Where-Object {$_ -ne ''})) $VmWithTag } # .\PSHVTag\private\Get-ClonedObject.ps1 function Get-ClonedObject { <# .SYNOPSIS Clones object on Binary level .DESCRIPTION Clones object on Binary level .PARAMETER DeepCopyObject Object to Clone .EXAMPLE $currentEdgeList = [hashtable] (Get-ClonedObject $edgeList) .NOTES Idea from http://stackoverflow.com/questions/7468707/deep-copy-a-dictionary-hashtable-in-powershell borrowed from http://stackoverflow.com/questions/8982782/does-anyone-have-a-dependency-graph-and-topological-sorting-code-snippet-for-pow #> param($DeepCopyObject) $memStream = new-object IO.MemoryStream $formatter = new-object Runtime.Serialization.Formatters.Binary.BinaryFormatter $formatter.Serialize($memStream, $DeepCopyObject) $memStream.Position = 0 $formatter.Deserialize($memStream) } # .\PSHVTag\private\Get-EdgeHashtableFromVMNote.ps1 function Get-EdgeHashtableFromVMNote { <# .SYNOPSIS Creates a hashtable with KeyProperty as Key and Value property as (an array of) Value(s) .DESCRIPTION Creates a hashtable with KeyProperty as Key and Value property as (an array of) Value(s) .PARAMETER VM A VMwithTag object .PARAMETER KeyProperty The property of the VM object which should be used as Key in the hashtable to create .PARAMETER ValueProperty The property of the VM object to use as value of the hashtable to create .EXAMPLE Get-EdgeHashtableFromVMNote -VM $VM -KeyProperty Service -ValueProperty DependsOn #> [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param( # Vm object with tags [Parameter(Mandatory = $true)] [VMwithTag[]] $VM, #Property to use as Key [Parameter(Mandatory = $true)] [string] $KeyProperty, #Property to use as Value [Parameter(Mandatory = $true)] [string] $ValueProperty ) $EdgeList = @{} foreach ($Node in $VM) { Write-Verbose -Message ('Processing VM ' + $Node.Name + ' Key Property: ' + $KeyProperty) Foreach ($Key in $Node.$KeyProperty) { Write-Verbose -Message ('Processing VM ' + $Node.Name + ' Key Property: ' + $KeyProperty + ' Key value: ' + $Key) If (!($EdgeList.ContainsKey($Key))) { Write-Verbose -Message ('Creating new Key for ' + $Key) $EdgeList.Add($Key, $null) } Foreach ($Value in $Node.$ValueProperty) { Write-Verbose -Message ('Processing VM ' + $Node.Name + ' Key Property: ' + $Key + ' Value Property: ' + $Value) If ($EdgeList.Item($Key) -notcontains $Value) { Write-Verbose -Message ('Adding ' + $Value + ' to Key Property ' + $Key + ' values') [array]$EdgeList.Item($Key) += [string]$Value } } } } $EdgeList #.GetEnumerator() | Sort-Object -Property Name } # .\PSHVTag\private\Get-TopologicalSort.ps1 function Get-TopologicalSort { <# .SYNOPSIS Sorts Keys of a Hashtable containing dependent Keys as Value array as a topology. .DESCRIPTION Sorts Keys of a Hashtable containing dependent Keys as Value array as a topology. And returns an orederd list. .PARAMETER edgeList A hashtable containing the edges from the Key to the values .EXAMPLE Get-TopologicalSort -edgeList @{ServiceA=@(ServiceB,ServiceC),ServiceB=@(ServiceC)} .NOTES Thanks to http://stackoverflow.com/questions/8982782/does-anyone-have-a-dependency-graph-and-topological-sorting-code-snippet-for-pow Input is a hashtable of @{ID = @(Depended,On,IDs);...} #> param( [Parameter(Mandatory = $true, Position = 0)] [hashtable] $edgeList ) # Make sure we can use HashSet Add-Type -AssemblyName System.Core # Clone it so as to not alter original $currentEdgeList = [hashtable] (Get-ClonedObject $edgeList) # algorithm from http://en.wikipedia.org/wiki/Topological_sorting#Algorithms $topologicallySortedElements = New-Object System.Collections.ArrayList $setOfAllNodesWithNoIncomingEdges = New-Object System.Collections.Queue $fasterEdgeList = @{} # Keep track of all nodes in case they put it in as an edge destination but not source $allNodes = New-Object -TypeName System.Collections.Generic.HashSet[object] -ArgumentList (, [object[]] $currentEdgeList.Keys) foreach ($currentNode in $currentEdgeList.Keys) { $currentDestinationNodes = [array] $currentEdgeList[$currentNode] if ($currentDestinationNodes.Length -eq 0) { $setOfAllNodesWithNoIncomingEdges.Enqueue($currentNode) } foreach ($currentDestinationNode in $currentDestinationNodes) { if (!$allNodes.Contains($currentDestinationNode)) { [void] $allNodes.Add($currentDestinationNode) } } # Take this time to convert them to a HashSet for faster operation If ($currentDestinationNodes -ne $null) { $currentDestinationNodes = New-Object -TypeName System.Collections.Generic.HashSet[object] -ArgumentList (, [object[]] $currentDestinationNodes ) } [void] $fasterEdgeList.Add($currentNode, $currentDestinationNodes) } # Now let's reconcile by adding empty dependencies for source nodes they didn't tell us about foreach ($currentNode in $allNodes) { if (!$currentEdgeList.ContainsKey($currentNode)) { [void] $currentEdgeList.Add($currentNode, (New-Object -TypeName System.Collections.Generic.HashSet[object])) $setOfAllNodesWithNoIncomingEdges.Enqueue($currentNode) } } $currentEdgeList = $fasterEdgeList while ($setOfAllNodesWithNoIncomingEdges.Count -gt 0) { $currentNode = $setOfAllNodesWithNoIncomingEdges.Dequeue() [void] $currentEdgeList.Remove($currentNode) [void] $topologicallySortedElements.Add($currentNode) foreach ($currentEdgeSourceNode in $currentEdgeList.Keys) { $currentNodeDestinations = $currentEdgeList[$currentEdgeSourceNode] if ($null -ne $currentNodeDestinations -and $currentNodeDestinations.Contains($currentNode)) { [void] $currentNodeDestinations.Remove($currentNode) if ($currentNodeDestinations.Count -eq 0) { [void] $setOfAllNodesWithNoIncomingEdges.Enqueue($currentEdgeSourceNode) } } } } if ($currentEdgeList.Count -gt 0) { throw "Graph has at least one cycle!" } return $topologicallySortedElements } # .\PSHVTag\private\Get-VMEnvironment.ps1 function Get-VMEnvironment { <# .SYNOPSIS Creates a (array of) VMEnvironment object(s) .DESCRIPTION Creates a (array of) VMEnvironment object(s) based on the list of tagged VMs defnied by the parameter VM. .PARAMETER VM A (list of) VM object(s) with Tags from which to build the VMEnvironment object .EXAMPLE Get-VMEnvironment -VM (Get-VMWithTag | Convert-VMNoteTagsToObject) #> [CmdletBinding()] param( # VM with Tag object gathered by Convert-VMNoteTagsToObject [Parameter(Mandatory = $true)] [VMWithTag[]] $VM ) $EdgeList = (Get-EdgeHashtableFromVMNote -VM $VM -KeyProperty 'Environment' -ValueProperty 'Service') [array]$VMEnvironment = @() foreach ($Environment in $EdgeList.Keys) { $EnvironmentVM = $VM | Where-Object -Property Environment -eq $Environment $Service = Get-VMService -VM $EnvironmentVM $EnvironmentServiceEdgeList = Get-EdgeHashtableFromVMNote -VM $EnvironmentVM -KeyProperty 'Service' -ValueProperty 'DependsOn' $EnvironmentOrder = Get-TopologicalSort -edgeList $EnvironmentServiceEdgeList If (Compare-Object -ReferenceObject ($Service | Select-Object -ExpandProperty Name) -DifferenceObject $EnvironmentOrder) { Throw 'One or more required services are not provided by a VM' } [array]$VMEnvironment += [VMEnvironment]::new($Environment, $Service, $EnvironmentVM, $EnvironmentServiceEdgeList, $EnvironmentOrder) } $VMEnvironment } # .\PSHVTag\private\Get-VMService.ps1 function Get-VMService { <# .SYNOPSIS Creates a (array of) VMService object(s) .DESCRIPTION Creates a (array of) VMService object(s) based on the list of tagged VMs defined by the parameter VM. .PARAMETER VM A (list of) VM object(s) with Tags from which to build the VMEnvironment object .EXAMPLE Get-VMService -VM (Get-VMWithTag | Convert-VMNoteTagsToObject) #> [CmdletBinding()] [OutputType([array])] param( # VM with Tag object gathered by Convert-VMNoteTagsToObject [Parameter(Mandatory = $true)] [VMWithTag[]] $VM ) $EdgeList = Get-EdgeHashtableFromVMNote -VM $VM -KeyProperty 'Service' -ValueProperty 'DependsOn' [array]$VMService = @() foreach ($Service in $EdgeList.Keys) { [array]$VmService += [VMService]::new($Service, ($VM | Where-Object -Property Service -eq $Service), $EdgeList.Item($Service)) } $VMService } # .\PSHVTag\private\Get-VMWithTag.ps1 function Get-VMWithTag { <# .SYNOPSIS Gets all VMs containing Tags on a given host .DESCRIPTION Gets all VMs containing Tags on a Hyper-V-Host given by the parameter Computername .PARAMETER Computername The Hyper-V-Host getting the VMs conatining Tags from .EXAMPLE Get-VMWithTag -Computername localhost #> [CmdletBinding()] param( # Specifies the VM Host. [Parameter(Mandatory = $false, Position = 0, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = "Name of VM Host computer(s)")] [ValidateNotNullOrEmpty()] [string] $Computername = 'localhost' ) Get-VM -ComputerName $Computername | Where-Object {$_.Notes -match '\<.*\>'} } Write-Verbose 'Importing from [C:\MyProjects\PSHVTag\PSHVTag\public]' # .\PSHVTag\public\Get-VMTopology.ps1 function Get-VMTopology { <# .SYNOPSIS Gets a VM Topology object for tagged VMs .DESCRIPTION Gets a VM Topology object for tagged VMs on the Hyper-V-Host defined by the paramater Computername .PARAMETER Computername A Hyper-V-Host with tagged VMs .EXAMPLE Get-VMTopology -Computername hyper-v-host.contoso.com #> [CmdletBinding()] param( # Parameter help description [Parameter(Mandatory = $false)] [string] $Computername = 'localhost' ) $VM = Get-VMWithTag -Computername $Computername | ForEach-Object {Convert-VMNoteTagsToObject -VM $_} $Environment = Get-VMEnvironment -VM $VM $VMTopology = [VMTopology]::new($Computername, $VM, $Environment) $VMTopology } # .\PSHVTag\public\Get-VMTopologyGraph.ps1 #Requires -Modules PSGraph function Get-VMTopologyGraph { <# .SYNOPSIS Exports a Topological Graph .DESCRIPTION Exports a Topological Graph as JPEG and opens it .PARAMETER VMTopology A VM Topology object .EXAMPLE Get-VMTopology -VMTopology (Get-VMTopology) #> [CmdletBinding()] param( # VMTopology to show [Parameter(Mandatory = $true)] [VMTopology] $VMTopology ) Import-Module PSGraph $Graph = graph "myGraph" { node -Default @{shape = 'box'} $subGraphID = 0 ForEach ($Environment in $VMTopology.Environment) { subgraph $subGraphID -Attributes @{label = $Environment.Name} { Foreach ($Service in $Environment.Service) { #Node ($Environment.Name + '|' + $Service.Name) @{label = $Service.Name} Record -Name ($Environment.Name + '|' + $Service.Name) -Rows ((($VMTopology.Environment | Where-Object -Property Name -Value $Environment.Name -EQ).Service | Where-Object -Property Name -Value $Service.Name -EQ).VM.Name) -Label $Service.Name ForEach ($DependsOn in $Service.DependsOn) { If ($DependsOn -ne '') { edge -from ($Environment.Name + '|' + $Service.Name) -to ($Environment.Name + '|' + $DependsOn) } } } } $subGraphID = $subGraphID + 1 } } $Graph } # .\PSHVTag\public\Set-VMTag.ps1 function Set-VMTag { <# .SYNOPSIS Tag a VM .DESCRIPTION This function tags one or more VMs with the Environment, Service and DependsOn Tag .PARAMETER Environment The environment the VM belongs to .PARAMETER Service The service the VM provides .PARAMETER DependsOn The Services the VM depends on .PARAMETER VMName The name of the VM .PARAMETER VM The VM object .PARAMETER Computername The VM host .PARAMETER Force Overwrite existing values .EXAMPLE Set-VMTag -Environment 'LAB01' -Service 'Domain' -DependsOn @('Gateway','DHCP') -VMName 'DomainController01' -Force #> [CmdletBinding(SupportsShouldProcess = $true)] param( # Name of the VMEnvironment the VM belongs to [Parameter(Mandatory = $false)] [string[]] $Environment, # Name of the VMService the VM provides [Parameter(Mandatory = $false)] [string[]] $Service, # Name of the VMServices the VM depends on [Parameter(Mandatory = $false)] [string[]] $DependsOn, # The name of the VM [Parameter(ParameterSetName = 'Name', Mandatory = $true)] [string[]] $VMName, # The VM object [Parameter(ParameterSetName = 'VMObject', Mandatory = $true)] $VM, # Specifies the VM Host. [Parameter(Mandatory = $false)] [ValidateNotNullOrEmpty()] [string] $Computername = 'localhost', # Force overwrite of existing Tag [Parameter()] [switch] $Force ) Begin { $TagPattern = '\<Env\>.*\<\/Env\>\<Service\>.*\<\/Service\>\<DependsOn\>.*\<\/DependsOn\>' $returnObject = [pscustomobject]@{ Success = @(); Error = @()} If ($PSCmdlet.ParameterSetName -eq 'Name') { $VM = @() foreach ($Name in $VMName) { try { $VM += Get-VM -ComputerName $Computername | Where-Object -Property Name -EQ $Name } catch { Write-Verbose "Can not find a VM with the name $Name at the host $Computername" $returnObject.Error += $Name } } } If (!($Vm)) { Throw 'Can not find any VM for these parameters' } } Process { foreach ($Node in $VM) { If ($Node.Notes -Match $TagPattern -and (-not $Force)) { Write-Verbose -Message "VM: $($VM.Name) already has a Tag and the paramater -force is not used" $returnObject.Error += $Node.Name } elseif (($Node.Notes -Match $TagPattern -and $Force) -or ($Node.Notes -notMatch $TagPattern)) { $Tag = '<Env>' + ($Environment -join ',') + '</Env><Service>' + ($Service -join ',') + '</Service><DependsOn>' + ($DependsOn -join ',') + '</DependsOn>' if ($Node.Notes -Match $TagPattern) { $NewNotes = $Node.Notes -replace $TagPattern, $Tag } Elseif ($null -ne $Node.Notes -and $Node.Notes -ne '') { $NewNotes = $Node.Notes + "`r`n" + $Tag + "`r`n" } Else { $NewNotes = $Tag + "`r`n" } Write-Verbose -Message "Setting Tag on VM $($VM.Name) to $NewNotes" if ($PSCmdlet.ShouldProcess(('Setting VM Notes of: ' + $Node.Name + ' to ' + $NewNotes))) { Try { Set-Vm -VM $Node -Notes $NewNotes $returnObject.Success += $Node.Name } catch { Write-Verbose -Message "Could not set Tag on VM $($VM.Name) to $NewNotes" $returnObject.Error += $Node.Name } } } } } End { $returnObject } } # .\PSHVTag\public\Start-VMService.ps1 function Start-VMService { <# .SYNOPSIS Starts all VMs of a VM Service in a VM Topology .DESCRIPTION Starts all VMs of a VM Service in a VM Topology and all VMs of required Vm Services .PARAMETER ServiceName The name of the VM Service to start .PARAMETER EnvironmentName The name of the VM Environment the VM Service is in .PARAMETER Service VMService object of the VM Service to start .PARAMETER Environment VMEnvironment object of the VM Service to start .PARAMETER VMTopology The VMTopology containing all VM Services and Environments .PARAMETER Recurse Start all required VM Services before starting the current VM Service .PARAMETER AdditionalWaitTime Additional time to wait after all VMs of a service are started successfully .PARAMETER VMWaitFor Item to wait for to determine if a VM is started successfully (IPAddress or Heartbeat) .EXAMPLE Start-VMService -ServiceName Domain -Environment Lab -VMTopology (Get-VMTopology) -Recurse #> [CmdletBinding(DefaultParameterSetName = 'String', SupportsShouldProcess = $true)] [OutputType([Bool])] param( # Name of the VM Service to start [Parameter(ParameterSetName = 'String', Mandatory = $true)] [Parameter(ParameterSetName = 'Object-String', Mandatory = $true)] [string] $ServiceName, # Name of the Environment of the service to start [Parameter(ParameterSetName = 'String', Mandatory = $true)] [Parameter(ParameterSetName = 'String-Object', Mandatory = $true)] [string] $EnvironmentName, # Name of the VM Service to start [Parameter(ParameterSetName = 'Object', Mandatory = $true)] [Parameter(ParameterSetName = 'String-Object', Mandatory = $true)] [VMService] $Service, # Name of the Environment of the service to start [Parameter(ParameterSetName = 'Object', Mandatory = $true)] [Parameter(ParameterSetName = 'Object-String', Mandatory = $true)] [VMEnvironment] $Environment, # VMTopology [Parameter(Mandatory = $true)] [VMTopology] $VMTopology, # Start VM Services recursively [Parameter()] [switch] $Recurse, # Additional seconds to wait after VM is started [Parameter()] [int] $AdditionalWaitTime = 20, # Wait For [Parameter()] [String] [ValidateSet('IPAddress', 'Heartbeat')] $VMWaitFor = 'IPAddress' ) Begin { switch ($PsCmdlet.ParameterSetName) { 'Object' { $ServiceName = $Service.Name $EnvironmentName = $Environment.Name } 'Object-String' { $EnvironmentName = $Environment.Name } 'String-Object' { $ServiceName = $Service.Name } } $Service = ($VMTopology.Environment | where-object -property name -eq $EnvironmentName).Service | Where-Object Name -eq $ServiceName If (!($Service)) { Throw ('Could not find any VM for the service ' + $ServiceName + ' in the environment ' + $EnvironmentName) } } Process { if ($Recurse) { foreach ($Dependency in $Service.DependsOn ) { Write-Verbose ('Starting required service: ' + $Dependency) Start-VMService -ServiceName $Dependency -EnvironmentName $EnvironmentName -VMTopology $VMTopology -Recurse | Out-Null } } foreach ($Node in $Service.VM) { If ($Node.VM.State -ne 'Running') { if ($PSCmdlet.ShouldProcess(('Starting VM: ' + $Node.Name))) { Start-VM -VM $Node.Vm $State = Wait-VM -VM $Node.vm -For $VMWaitFor -Timeout 120 -Passthru Start-Sleep -Seconds $AdditionalWaitTime If (!($State.State -eq 'Running')) { Throw ('Could not start VM: ' + $Node.Name) } } } } } End { Write-Verbose ('Successfully started VM Service: ' + $ServiceName) $true } } # .\PSHVTag\public\Stop-VMService.ps1 function Stop-VMService { <# .SYNOPSIS Stopps all VMs of a VM Service in a VM Topology .DESCRIPTION Stopps all VMs of a VM Service in a VM Topology and all VMs of required Vm Services .PARAMETER ServiceName The name of the VM Service to start .PARAMETER EnvironmentName The name of the VM Environment the VM Service is in .PARAMETER Service VMService object of the VM Service to stop .PARAMETER Environment VMEnvironment object of the VM Service to stop .PARAMETER VMTopology The VMTopology containing all VM Services and Environments .PARAMETER Recurse Stop all required VM Services after stopping the current VM Service .PARAMETER Force Force shutdown of VMs .EXAMPLE Stop-VMService -ServiceName Domain -EnvironmentName Lab -VMTopology (Get-VMTopology) -Recurse #> [CmdletBinding(DefaultParameterSetName = 'String', SupportsShouldProcess = $true)] [OutputType([Bool])] param( # Name of the VM Service to stop [Parameter(ParameterSetName = 'String', Mandatory = $true)] [Parameter(ParameterSetName = 'Object-String', Mandatory = $true)] [string] $ServiceName, # Name of the Environment of the service to stop [Parameter(ParameterSetName = 'String', Mandatory = $true)] [Parameter(ParameterSetName = 'String-Object', Mandatory = $true)] [string] $EnvironmentName, # Name of the VM Service to stop [Parameter(ParameterSetName = 'Object', Mandatory = $true)] [Parameter(ParameterSetName = 'String-Object', Mandatory = $true)] [VMService] $Service, # Name of the Environment of the service to stop [Parameter(ParameterSetName = 'Object', Mandatory = $true)] [Parameter(ParameterSetName = 'Object-String', Mandatory = $true)] [VMEnvironment] $Environment, # VMTopology [Parameter(Mandatory = $true)] [VMTopology] $VMTopology, # Stop VM Services recursively [Parameter()] [switch] $Recurse, # Force stopping of VM [Parameter()] [switch] $Force ) Begin { switch ($PsCmdlet.ParameterSetName) { 'Object' { $ServiceName = $Service.Name $EnvironmentName = $Environment.Name } 'Object-String' { $EnvironmentName = $Environment.Name } 'String-Object' { $ServiceName = $Service.Name } } $Service = ($VMTopology.Environment | where-object -property name -eq $EnvironmentName).Service | Where-Object Name -eq $ServiceName If (!($Service)) { Throw ('Could not find the service ' + $ServiceName + ' in the environment ' + $EnvironmentName) } } Process { foreach ($Node in $Service.VM) { If ($Node.VM.State -ne 'Off') { if ($PSCmdlet.ShouldProcess(('Stopping VM: ' + $Node.Name))) { If ($Force) { $State = Stop-VM -VM $Node.Vm -Passthru -Force } else { $State = Stop-VM -VM $Node.Vm -Passthru } If (!($State.State -eq 'Off')) { Throw ('Could not stop VM: ' + $Node.Name) } } } } if ($Recurse) { foreach ($Dependency in $Service.DependsOn ) { Write-Verbose ('Stopping required service: ' + $Dependency) If ($Force) { Stop-VMService -ServiceName $Dependency -EnvironmentName $EnvironmentName -VMTopology $VMTopology -Recurse -Force | Out-Null } else { Stop-VMService -ServiceName $Dependency -EnvironmentName $EnvironmentName -VMTopology $VMTopology -Recurse | Out-Null } } } } End { Write-Verbose ('Successfully stopped VM Service: ' + $ServiceName) $true } } Write-Verbose 'Importing from [C:\MyProjects\PSHVTag\PSHVTag\classes]' # .\PSHVTag\classes\1VMWithTag.ps1 # VM with Tag class VMWithTag { # Name of the VM [string] $Name # VM ID $VM # Environment [String[]] $Environment # Service provided by VM [String[]] $Service # DependsOn Services [String[]] $DependsOn # Constructor VMWithTag ([string] $name, $VM, [String[]]$Environment, [String[]] $Service, [String[]] $DependsOn) { $this.Name = $name $this.VM = $VM $this.Environment = $Environment $this.Service = $Service $this.DependsOn = $DependsOn } } # .\PSHVTag\classes\2VMService.ps1 class VMService { [string]$Name [VMWithTag[]]$VM [array]$DependsOn VMService ([string]$Name, [VMWithTag[]]$VM, [array]$DependsOn) { $this.Name = $Name $this.VM = $VM $this.DependsOn = $DependsOn } } # .\PSHVTag\classes\3VMEnvironment.ps1 class VMEnvironment { [string]$Name [VMService[]]$Service [VMWithTag[]] $VM [System.Collections.ArrayList]$EdgeList [Array]$Order VMEnvironment ([string] $Name, [VMService[]]$Service, [VMWithTag[]] $VM, [System.Collections.ArrayList]$EdgeList, [Array]$Order) { $this.Name = $Name $this.Service = $Service $this.VM = $VM $this.EdgeList = $EdgeList $this.Order = $Order } } # .\PSHVTag\classes\4VMTopology.ps1 class VMTopology { [string] $Computername [VMWithTag[]] $VM [VMEnvironment[]] $Environment # Constructor VMTopology ([string] $Computername, [VMWithTag[]] $VM, [VMEnvironment[]] $Environment) { $this.Computername = $Computername $this.VM = $VM $this.Environment = $Environment } } |