I'm trying to setup Powershell ISE to manage few VMs hosted under Hyper-V and using Powershell Direct.
What I'm trying to do is:
collect in one script all relevant "settings" under variables whose name starts with an appropriate prefix, for example "vms";
at the end of this script open a
PowerShellTab
for each VM to manage (if not already opened);copy in the runspace of this new Tab all the relevant settings variables (I think this is necessary for the next step);
start a remote
PSSession
with the VM (if not already started) and copy or update the settings variables also in this remotePSSession
;enter interactively this
PSSession
to be able to launch my commands (F8) after selecting portions of sample/template scripts.
My script is this one.
$vms = 'VMName1','VMName2'
$vmsCredentials = @{
VMName1 = [pscredential]::new('User1', (ConvertTo-SecureString 'pw1' -AsPlainText -force))
VMName2 = [pscredential]::new('User2', (ConvertTo-SecureString 'pw2' -AsPlainText -force))
}
$vmsInfo1 = 'blah,blah,blah'
$vmsInfo2 = @{}
$vmsInfo3 = @(1,2,3)
$tabPrevious = $psISE.CurrentPowerShellTab
$vms |% {
Write-Information $_
$tab = $psISE.PowerShellTabs |? DisplayName -eq $_
if ($tab -eq $null)
{
# opens new PS ISE Tab
$tab = $psISE.PowerShellTabs.Add()
$psISE.PowerShellTabs.SetSelectedPowerShellTab($tabPrevious)
$tab.DisplayName = $_
$tab.ExpandedScript = $true
$tab.Files.Clear()
# open all files in new tab
$tabPrevious.Files |% FullPath |? { Test-Path $_ } |% {
[void]$tab.Files.Add($_)
}
}
else
{
# exit remote interactive session, if any
if ($tab.Prompt -match "^\[$_\]: ") {
while (!$tab.CanInvoke) { sleep -Milliseconds 100 }
$tab.Invoke('exit')
}
}
# export/update variables to tab
while (!$tab.CanInvoke) { sleep -Milliseconds 100 }
$rs = ($tab.InvokeSynchronous({ $ExecutionContext.Host.Runspace }, $false))[0]
if ($null -ne $rs) {
Get-Variable "vms*" |% { $rs.SessionStateProxy.SetVariable($_.Name, $_.Value) }
}
# start a new remote PSSession for the tab, if not already done
while (!$tab.CanInvoke) { sleep -Milliseconds 100 }
$tab.Invoke("if (`$null -eq `$pchPSSession) { `$pchPSSession = New-PSSession -VMName '$_' -Credential `$vmsCredentials['$_'] }")
# export/update variables to the remote PSSession and enter interactively
while (!$tab.CanInvoke) { sleep -Milliseconds 100 }
$tab.Invoke("Invoke-Command `$pchPSSession { `$args |% { Set-Variable `$_.Name `$_.Value } } -ArgumentList (Get-Variable 'vms*'); Enter-PSSession -Session `$pchPSSession")
# uncomment this line and no error occurs
#[void]$psISE.PowerShellTabs.Remove($tab)
}
Unfortunately this script works well:
- the very first time I run the script in a fresh ISE,
- or when only one new Tab need to be opened,
- or if I close immediately the just added Tab (uncomment last line),
- or under Debugger
otherwise the two last PowerShellTab.Invoke
fails (Null Reference).
Any idea to solve this error? Any way to do it better?