[CmdletBinding()] Param ( [Parameter()] [Boolean]$Aux = $False, [Parameter()] [Boolean]$Close = $True, [Parameter()] [String]$Command = "Echo-VMs", [Parameter()] #[String]$ffmpegPath = "[redeacted]", [String]$ffmpegPath = "[redeacted]", #[String]$ffmpegPath = "[redeacted]", [Parameter()] [String]$ffmpegWrapperPath = "[redeacted]", [Parameter()] [String]$GalleryDrive = "[redeacted]", [Parameter()] [String]$GalleryPath = "[redeacted]", [Parameter()] [String]$GalleryPassword, [Parameter()] [String]$GalleryRoot = "[redacted]", [Parameter()] [String]$GallerySecretPath = [redeacted]", [Parameter()] [String]$GalleryUser = "[redeacted]", [Parameter()] [Boolean]$HardShutdown = $False, [Parameter()] [String]$SetWindowPath = "[redeacted]", [Parameter()] [String]$Temperature = "Warm", [Parameter()] [String]$VMPath = "[redeacted]", [Parameter()] [String]$VMCPath = "[redeacted]", [Parameter()] [String]$VMOPath = "[redeacted]", [Parameter()] [String]$VMRCPath = "[redeacted]", [Parameter()] [String]$VMRCURL = "[redeacted]", [Parameter()] [String]$VMsPath = ".\vms.csv", [Parameter()] [String]$VMsAuxPath = ".\vms-aux.csv", [Parameter()] [String[]]$VMsSubset = @() ) ############################################################################### # # Manage-MultivisorHost.ps1, Copyright 2020-2024, by Josh Moyer # All rights reserved. # # Another great PS script! :-) # # To do: # - set window sizes and desktop postions on vm launch # - launch vms synchronously, so that we don't have to hard code load # dependent sleep intervals # ############################################################################### Function Boot($Full) { $Command = "Start-VMs" $Aux = $False Main If ($Full -EQ $True) { $Aux = $True Main } } Function MountGalleryShare($GalleryRoot, $GalleryDrive, $GalleryUser, $GallerySecretPath) { Add-Type -Assembly System.Security $EncryptedPassword = Get-Content -Enc Byte $GallerySecretPath $Password = ` [System.Security.Cryptography.ProtectedData]::Unprotect( ` $EncryptedPassword, $Null, 'CurrentUser') $Password = [System.Text.Encoding]::Unicode.GetString($Password) New-SMBMapping ` -LocalPath $GalleryDrive ` -RemotePath $GalleryRoot ` -UserName $GalleryUser ` -Password $Password } Function SetGalleryPassword($Password, $SecretPath) { Add-Type -Assembly System.Security $PasswordBytes = [System.Text.Encoding]::Unicode.GetBytes($Password) $EncrytpedPassword = ` [System.Security.Cryptography.ProtectedData]::Protect( ` $PasswordBytes, $Null, 'CurrentUser') $EncrytpedPassword | Set-Content -Enc Byte $SecretPath } Function Shutdown() { $Command = "Suspend-VMs" $Aux = $True Main $Aux = $False Main If ($HardShutdown -EQ $True) { Stop-Computer } } Function StartEncoder($VM) { #Return If ((Test-Path $GalleryDrive$GalleryPath) -EQ $False) { MountGalleryShare $GalleryRoot $GalleryDrive $GalleryUser $GallerySecretPath } $OriginalLocation = Get-Location Set-Location "$($GalleryDrive)$($GalleryPath)" $OldErrorActionPreference = $ErrorActionPreference $ErrorActionPreference = "Continue" mkdir $VM.Name # This can fail, but did it fail because the dir was already there or because of some other reason? $ErrorActionPreference = $OldErrorActionPreference Set-Location $VM.Name If ((Get-Location).Path -EQ "$($GalleryDrive)$($GalleryPath)\$($VM.Name)") { Remove-Item * } Else { Write-Error "Couldn't set encoder path." Return } Switch ($VM.Encode) { "VMRC" { $WindowTitle = "$($VM.Name) - VMware Remote Console" Start-Process $VMRCPath "$($VMRCURL)$($VM.VMRCI)" Wait-Event -Timeout 10 (New-Object -ComObject WScript.Shell).SendKeys("`n") Wait-Event -Timeout 10 Break } "VMWW" { $WindowTitle = "$($VM.Name) - VMware Workstation" Break } } # $DebugPreference = "Continue" # Write-Debug $ffmpegWrapperPath # Write-Debug "`"$($VM.Name)`"" "`"$($ffmpegPath)`"" $VM.FrameRate $VM.InputSize "`"$($WindowTitle)`"" $VM.OutputSize $VM.OffsetX $VM.OffsetY $VM.VBR # $DebugPreference = "SilentlyContinue" Start-Process -NoNewWindow -FilePath $ffmpegWrapperPath -ArgumentList @("`"$($VM.Name)`"","`"$($ffmpegPath)`"",$VM.FrameRate,$VM.InputSize,"`"$($WindowTitle)`"",$VM.OutputSize,$VM.OffsetX,$VM.OffsetY,$VM.VBR) Set-Location $OriginalLocation } Function StartVM($VM, $Temperature) { Write-Debug ( "SkipStartup=" + $VM.SkipStartup ) If ([bool]::Parse($VM.SkipStartup) -EQ $True) { Write-Debug "Skipping startup of $($VM.Name)..." Return } $VMX = "$VMPath$($VM.Name)\$($VM.Name).vmx" $VMObj = New-Object -TypeName NDDN.VirtualMachines.VirtualMachine -ArgumentList $VMX Write-Output "$($VM.Name + ", " + $VM.Interactive)" If ([bool]::Parse($VM.SkipStartup) -NE $True) { Start-VM $VMObj -Interactive $VM.Interactive If ($VM.Interactive -AND $Temperature -EQ "Cold") { Wait-Event -Timeout $VM.StartupDelayCold } If ($VM.Interactive -AND $Temperature -EQ "Instant") { Wait-Event -Timeout 5 } If ($VM.Interactive -AND $Temperature -EQ "Warm") { Wait-Event -Timeout $VM.StartupDelayWarm } } #If ($VM.Encode) { StartEncoder $VM } } Function StopEncoder($VM) { & TASKKILL "/FI" "WINDOWTITLE eq $($VM.Name)" Wait-Event -Timeout 1 Switch ($VM.Encode) { "VMRC" { & TASKKILL "/FI" "WINDOWTITLE eq $($VM.Name) - VMware Remote Console" Break } # "VMWW" # { # & TASKKILL "/FI" "WINDOWTITLE eq $($VM.Name) - VMware Workstation" # Break # } } } Function SuspendVM($VM, $Close) { Write-Debug "In SuspendVM" If ([bool]::Parse($VM.SkipShutdown)) { Return } $VMX = "$VMPath$($VM.Name)\$($VM.Name).vmx" $VMObj = New-Object -TypeName NDDN.VirtualMachines.VirtualMachine -ArgumentList $VMX Write-Output $VM.Name If ($VM.Encode) { StopEncoder $VM } If ([bool]::Parse($VM.SkipShutdown) -NE $True) { Unpause-VM $VMObj Suspend-VM $VMObj Wait-Event -Timeout 3 } If ($Close) { & TASKKILL "/FI" "WINDOWTITLE eq $($VM.Name) - VMware Workstation" } } Function Main { $VMs = Import-CSV $VMsPath $VMs | ForEach { Write-Debug $_ } $VMsAux = Import-CSV $VMsAuxPath $VMsAux | ForEach { Write-Debug $_ } Write-Debug $Command If ($Command -EQ "Boot") { Boot } ElseIf ($Command -EQ "Mount-GalleryShare") { MountGalleryShare $GalleryRoot $GalleryDrive $GalleryUser $GallerySecretPath } ElseIf ($Command -EQ "Set-GalleryPassword") { SetGalleryPassword $GalleryPassword $GallerySecretPath Write-Output "Password updated." } ElseIf ($Command -EQ "Shutdown") { Shutdown } Else { #$DebugPreference = "SilentlyContinue" $ErrorActionPreference = "Stop" # Silence warning about unapproved verbs. $WarningPreference="SilentlyContinue" Import-Module $VMCPath $WarningPreference="Continue" Import-Module $VMOPath If ($Aux) { $VMs = $VMsAux } If ($VMsSubset) { ForEach ($VMName in $VMsSubset) { $FoundVM = $False ForEach ($VM in $VMs) { If ([bool]::Parse($VM.Active) -EQ $False) { Continue } If ($VMName -EQ $VM.Name) { $NewVMs += ,@($VM) $FoundVM = $True } } If ($FoundVM -EQ $False) { Write-Error "VM not found." Return } } $VMs = $NewVMs } If ( $Command -EQ "Echo-VMs" -OR $Command -EQ "Stop-Encoders" -OR $Command -EQ "Suspend-VMs" ) { [array]::Reverse($VMs) } Write-Debug "Before main loop." ForEach ($VM in $VMs) { If ([bool]::Parse($VM.Active) -EQ $False) { Write-Debug ( "Skipping " + $VM.Name ) Continue } Switch ($Command) { "Echo-VMs" { Write-Debug ( "Echo-VMS: " + $VM.Name ) Write-Output $VM.Name Break } "Start-Encoders" { Write-Debug ( "Start-Encoders: " + $VM.Name ) StartEncoder $VM Break } "Start-VMs" { Write-Debug ( "Start-VMs: " + $VM.Name ) StartVM $VM $Temperature Break } "Stop-Encoders" { Write-Debug ( "Stop-Encoders: " + $VM.Name ) StopEncoder $VM Break } "Suspend-VMs" { Write-Debug ( "Suspend-VMs: " + $VM.Name ) SuspendVM $VM $Close Break } #"Toggle" { Depends on current state of NDDN.VirtualMachines } } } Remove-Module VirtualMachineObject Remove-Module VirtualMachineCmdlets Return } } Main # SIG # Begin signature block [redacted] # SIG # End signature block