diff --git a/src/HyperVLab/Classes.ps1 b/src/HyperVLab/Classes.ps1 index 7b00dc1..0c920c1 100644 --- a/src/HyperVLab/Classes.ps1 +++ b/src/HyperVLab/Classes.ps1 @@ -206,11 +206,13 @@ class LabNetworkAdapter : LabObject { [LabNetwork]$Network [string]$StaticMacAddress [string]$StaticIPAddress + [string]$DefaultGateway [Hashtable] ToMachineConfiguration() { $hashtable = @{ StaticMacAddress = $this.StaticMacAddress StaticIPAddress = $this.StaticIPAddress + DefaultGateway = $this.DefaultGateway } if ($this.Network) { @@ -224,6 +226,7 @@ class LabNetworkAdapter : LabObject { $hashtable = @{ StaticMacAddress = $this.StaticMacAddress StaticIPAddress = $this.StaticIPAddress + DefaultGateway = $this.DefaultGateway } if ($this.Network) { diff --git a/src/HyperVLab/Functions/LabAccess/Publish-LabAccess.ps1 b/src/HyperVLab/Functions/LabAccess/Publish-LabAccess.ps1 new file mode 100644 index 0000000..b09626e --- /dev/null +++ b/src/HyperVLab/Functions/LabAccess/Publish-LabAccess.ps1 @@ -0,0 +1,110 @@ +#Requires -Version 5.0 + +function Publish-LabAccess { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '', Justification = 'TODO: implement ShouldProcess')] + [CmdletBinding(DefaultParameterSetName = 'EnvironmentName')] + param ( + [Parameter(Mandatory = $true, ParameterSetName = 'Environment', ValueFromPipeline = $true)] + [LabEnvironment[]]$Environment, + [Parameter(Mandatory = $true, ParameterSetName = 'EnvironmentName')] + [string[]]$EnvironmentName, + [Parameter(Mandatory = $false)] + [string]$OutputPath + ) + + Process { + try{ + Import-Module "${env:ProgramFiles(x86)}\code4ward.net\Royal TS V4\RoyalDocument.PowerShell.dll" -Verbose:$false -ErrorAction Stop + }catch + { + throw "Unable to find Royal TS V4" + } + + if ($($PSCmdlet.ParameterSetName) -in 'EnvironmentName') { + if ($EnvironmentName) { + $Environment = Get-LabEnvironment -Name $EnvironmentName + } + else { + $Environment = Get-LabEnvironment + } + } + + if (-not $OutputPath) { + $OutputPath = Join-Path -Path (Get-Location) -ChildPath 'PublishLabAccess' + } + if (-not (Test-Path -Path $OutputPath -PathType Container)) { + New-Item -Path $OutputPath -ItemType Directory -Force + } + + function EnsureRoyalDocument{ + param ( + [String]$OutputPath, + [String]$EnvironmentName + ) + Process { + Write-Verbose "Ensure existence of RoyalDocument $EnvironmentName in $OutputPath" + $royalDocumentFileName="$(Join-Path -Path $OutputPath -ChildPath $EnvironmentName).rtsz" + $store=New-RoyalStore -UserName ($env:USERDOMAIN + '\' + $env:USERNAME) + $rv=Open-RoyalDocument -FileName $RoyalDocumentFileName -Store $store -ErrorAction SilentlyContinue + if(!$rv){ + $rv=New-RoyalDocument -Name $EnvironmentName -FileName $royalDocumentFileName -Store $store + } + return $rv + } + } + + function EnsureRoyalObject{ + param ( + [String]$Type, + [RoyalDocumentLibrary.RoyalFolder]$Path, + [String]$ChildPath + ) + Process { + Write-Verbose "Ensure existence of $Type $ChildPath in $($Path.ListInfoPath)" + $rv=Get-RoyalObject -Type $Type -Name $ChildPath -Folder $Path + if(!$rv){ + $rv=New-RoyalObject -Type $Type -Name $ChildPath -Folder $Path + } + return $rv + } + } + + foreach($e in $Environment){ + $royalDocument=EnsureRoyalDocument -OutputPath $OutputPath -EnvironmentName $e.Name + $royalCredentials=EnsureRoyalObject -Type RoyalFolder -Path $royalDocument -ChildPath 'Credentials' + $royalConnections=EnsureRoyalObject -Type RoyalFolder -Path $royalDocument -ChildPath 'Connections' + $royalLocalAdministratorFolder=EnsureRoyalObject -Type RoyalFolder -Path $royalConnections -ChildPath '.\Administrator' + + foreach($m in $e.Machines){ + #Ensure existence of RDP session with local administrator + $royalLocalAdministratorRDP=EnsureRoyalObject -Type RoyalRDSConnection -Path $royalLocalAdministratorFolder -ChildPath "$($m.Name)@.\Administrator" + $royalLocalAdministratorRDP.URI=$m.NetworkAdapters | ?{$_.Network.Name -eq "Internal"} | %{$_.StaticIPAddress} + $royalLocalAdministratorRDP.CredentialMode=2 + $royalLocalAdministratorRDP.CredentialUserName=".\Administrator" + $royalLocalAdministratorRDP.CredentialPassword=[System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($m.AdministratorPassword)) + + foreach($d in $m.Environment.Domains){ + #Ensure existence of domain credential + $royalDomainAdministratorCredential=EnsureRoyalObject -Type RoyalCredential -Path $royalCredentials -ChildPath "$($d.NetbiosName)\Administrator" + $royalDomainAdministratorCredential.UserName="$($d.NetbiosName)\Administrator" + $royalDomainAdministratorCredential.Password=[System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($d.AdministratorPassword)) + + #Ensure existence of domain folder + $royalDomainFolder=EnsureRoyalObject -Type RoyalFolder -Path $royalConnections -ChildPath "$($d.NetbiosName)\Administrator" + $royalDomainFolder.CredentialMode=3 + $royalDomainFolder.CredentialId=$royalDomainAdministratorCredential.ID + + #Ensure existence of RDP session with domain administrator + $royalDomainAdministratorRDP=EnsureRoyalObject -Type RoyalRDSConnection -Path $royalDomainFolder -ChildPath "$($m.Name)@$($d.NetbiosName)\Administrator" + $royalDomainAdministratorRDP.URI=$m.NetworkAdapters | ?{$_.Network.Name -eq "Internal"} | %{$_.StaticIPAddress} + $royalDomainAdministratorRDP.CredentialMode = 3 + $royalDomainAdministratorRDP.CredentialFromParent = $true + } + } + + #Save and close Royal TS document + Out-RoyalDocument -Document $royalDocument + Close-RoyalDocument -Document $royalDocument + } + } +} diff --git a/src/HyperVLab/Functions/LabHostShare/Update-LabHostShare.ps1 b/src/HyperVLab/Functions/LabHostShare/Update-LabHostShare.ps1 index a0a7504..9195807 100644 --- a/src/HyperVLab/Functions/LabHostShare/Update-LabHostShare.ps1 +++ b/src/HyperVLab/Functions/LabHostShare/Update-LabHostShare.ps1 @@ -51,12 +51,18 @@ function Update-LabHostShare { if (-not (Get-CimInstance -ClassName Win32_Share -Filter "name='$Name'")) { Write-Verbose -Message "Sharing folder '$Path' as '$Name'." - (Get-CimInstance -ClassName Win32_Share -List).Create($Path, $Name, 0) | Out-Null + $arguments = @{ + Path = $Path + Name = $Name + Description = $Name + Type = [uint32]0 + } + Invoke-CimMethod -ClassName Win32_Share -MethodName Create -Arguments $arguments | Out-Null } Write-Verbose -Message "Ensuring folder '$Path' as '$Name'." $acl = Get-Acl -Path $Path - if (-not ($acl.Access | Where-obj { $_.IdentityReference -match "$($UserName)$" })) { + if (-not ($acl.Access | Where-Object { $_.IdentityReference -match "$($UserName)$" })) { Write-Verbose -Message "Allow access to share '$Name' by '$UserName'." $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule $UserName,'FullControl','Allow' $acl.SetAccessRule($accessRule) diff --git a/src/HyperVLab/Internal/Generic/Convert-FromJsonObject.ps1 b/src/HyperVLab/Internal/Generic/Convert-FromJsonObject.ps1 index f5e82b9..3c47fbc 100644 --- a/src/HyperVLab/Internal/Generic/Convert-FromJsonObject.ps1 +++ b/src/HyperVLab/Internal/Generic/Convert-FromJsonObject.ps1 @@ -223,6 +223,7 @@ function Convert-FromJsonObject { $networkAdapter = New-Object LabNetworkAdapter -Property @{ StaticMacAddress = $InputObject.StaticMacAddress StaticIPAddress = $InputObject.StaticIPAddress + DefaultGateway = $InputObject.DefaultGateway } $networkAdapter.Network = ($RootObject.Networks | Where-Object { $_.Name -eq $InputObject.Network } | Select-Object -First 1) return $networkAdapter diff --git a/src/HyperVLab/Internal/LabConfiguration/Publish-DscModuleAndMof.ps1 b/src/HyperVLab/Internal/LabConfiguration/Publish-DscModuleAndMof.ps1 index cff946d..a825238 100644 --- a/src/HyperVLab/Internal/LabConfiguration/Publish-DscModuleAndMof.ps1 +++ b/src/HyperVLab/Internal/LabConfiguration/Publish-DscModuleAndMof.ps1 @@ -83,7 +83,7 @@ function Publish-DscModuleAndMof { return } - Write-Log -Scope $MyInvocation -Message "Copying modules and checksums to [$moduleRepository]." + Write-Log -Scope $MyInvocation -Message "Copying modules and checksums to [$moduleRepository]" if ($Session) { Copy-Item -Path "$Path\*.zip*" -Destination $moduleRepository -ToSession $Session -Force } @@ -119,7 +119,7 @@ function Publish-DscModuleAndMof { return } - Write-Log -Scope $MyInvocation -Message "Copying mofs and checksums to [$moduleRepository]." + Write-Log -Scope $MyInvocation -Message "Copying mofs and checksums to [$mofRepository]" if ($Session) { Copy-Item -Path "$Path\*.mof*" -Destination $mofRepository -ToSession $Session -Force }