Latent response to interact with form Powershell GUI - powershell

So I have about wrapped up my holiday break personal project.
I have a form that refreshes on a set interval(which with this last problem solved will start creating a config file)
Before I added the on_tick function and on load function that allowed for the functionality I wanted, the program ran fine if not the results I wanted. When I mean ran fine I mean if I clicked close("X" button in top right) or wanted to move the window I could
After I added the fixes for refresh The Form window is now unresponsive or will take forever to register a "close" command
########################################################################
#Purpose to have a UI running at a 30 second intervel to update on
#network and machine performance metrics
########################################################################
function OnApplicationLoad {
return $true
}
function OnApplicationExit {
$script:ExitCode = 0
}
function Get-ComputerStats {
process {
$avg = Get-WmiObject win32_processor |
Measure-Object -property LoadPercentage -Average |
Foreach {$_.Average}
$mem = Get-WmiObject win32_operatingsystem |
Foreach {"{0:N2}" -f ((($_.TotalVisibleMemorySize - $_.FreePhysicalMemory)*100)/ $_.TotalVisibleMemorySize)}
$free = Get-WmiObject Win32_Volume -Filter "DriveLetter = 'C:'" |
Foreach {"{0:N2}" -f (($_.FreeSpace / $_.Capacity)*100)}
[pscustomobject] [ordered] #{
ComputerName = $env:computername
AverageCpu = $avg
MemoryUsage = $mem
PercentFree = $free
}
}
}
function GenerateForm {
[void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")
[void][reflection.assembly]::Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[void][reflection.assembly]::Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
[System.Windows.Forms.Application]::EnableVisualStyles()
$form = New-Object System.Windows.Forms.Form
$button = New-Object System.Windows.Forms.Button
$outputBox = New-Object System.Windows.Forms.RichTextBox
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 30000
$form.ForeColor = "#25c420"
$form.BackColor = "#000000"
#tick function - code that actually gets the metrics all other code is for the silly gui
Function Timer_Tick(){
$date = Get-Date -Format "HH:mm:ss"
$form.Text = "Network and Health Monitor ($date)"
$outputBox.ForeColor = "#25c420"
$outputBox.BackColor = "#000000"
$outputBox.Text += "`n"
$pySpeedDir = "C:\Users\CentralTerminal\AppData\Local\Programs\Python\Python36\Scripts\pyspeedtest.exe"
$speed = & $pySpeedDir
$table = Get-ComputerStats | Select-Object ComputerName,AverageCpu,MemoryUsage,PercentFree | Out-String
#$outputBox.Text += get-date
$outputBox.Text += "$date`n"
$outputBox.Text += "CPU and Memory Utilization`n"
$outputBox.Text += $table
$outputBox.Text += "`r`n"
$outputBox.Text += "Network Test in Progress...`n"
$outputBox.Text += $speed[0]+ "`n" + $speed[1] + "`n" + $speed[2] + "`n" + $speed[3]
$outputBox.Text += "`r`n"
$outputBox.Select()
$outputBox.SelectionStart = $outputBox.Text.Length
$outputBox.ScrollToCaret()
$outputBox.Refresh()
}
Function Form_Load{
#$form.Text = "Timer started"
Timer_Tick
$timer.Start()
}
$form_StateCorrection_Load={
$form.WindowState = $InitialFormWindowState
}
$form.Controls.Add($outputBox)
$form.Text = "Network and Machine Load"
$form.Name = "GUM"
$form.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$form.ClientSize = New-Object System.Drawing.Size(800,400)
$form.BackgroundImageLayout = "None"
$form.add_Load({Form_Load})
$timer.Add_Tick({Timer_Tick})
$outputBox.Name = "outputBox"
$outputBox.Text = ""
$outputBox.DataBindings.DefaultDataSourceUpdateMode = [System.Windows.Forms.DataSourceUpdateMode]::OnValidation
$outputBox.Location = New-Object System.Drawing.Point(5,35)
$outputBox.Size = New-Object System.Drawing.Size(785,320)
$outputBox.font = "lucida console"
$outputBox.TabIndex = 0
$InitialFormWindowState = $form.WindowState
$form.add_Load($form_StateCorrection_Load)
return $form.ShowDialog()
}
if(OnApplicationLoad -eq $true){
GenerateForm | Out-Null
OnApplicationExit
}
My problem is that I have no exceptions being thrown. I am going to add a try catch to this system as well but there are no error messages or anything that is technically breaking for me to start my investigation. If you also just know where to start debugging that would be helpful too as I am trying to get better at Production Support in general
Thanks for reading

Related

PowerShell checkbox controls button function

This is my very first school project in PowerShell. Its going to be simple. Type path and press button to Get-Acl, which works, but I want to have an option for recurse. Which also works, but I have not been able to make a checkbox determine what function button has.. Specifically The checkboxstatechanged is what I need help with.
function ChckBx_chkd {
$table = Get-ChildItem -directory -path $Textbox1.Text -recurse
$Rtbx = #()
foreach ($dir in $table)
{
$Access = (Get-Acl $dir.FullName).Access
$Rtbx += $dir.PSPath
$Rtbx += $Access | Format-Table | out-string
}
}
function ChkcBx_unchkd {
$Rtbx.Text = (Get-Acl $Textbox1.Text).Access| Format-Table| Out-String
}
$Form = New-Object System.Windows.Forms.Form
#Själva Formen
$Form.Text = "ACL GUI"
$Font = New-Object System.Drawing.Font("Lucida Console",8)
$Form.Font = $Font
$Form.Width = 1000
$Form.Height = 500
$Rtbx = New-Object System.Windows.Forms.RichTextBox
$Rtbx.Location = '200, 100'
$Rtbx.Width = 750
$Rtbx.Font = $Font
$Rtbx.Height = 300
$Rtbx.Font
$Form.Controls.Add($Rtbx)
$Chkbx1 = New-Object System.Windows.Forms.CheckBox
$Chkbx1.Location = '50, 150'
$Chkbx1.Text = "undermappar"
$Chkbx1.Checked = $true
$Chkbx1.Add_CheckStateChanged({
if($Chkbx1.checked) {
$Btn1Click = ChckBx_chkd
}
else
{
$Btn1Click = ChkcBx_unchkd
}
})
$Form.Controls.Add($Chkbx1)
$Textbox1 = New-Object System.Windows.Forms.TextBox
$Textbox1.Location = '50, 50'
$Textbox1.Width = 700
$Form.Controls.Add($Textbox1)
$Btn1 = New-Object System.Windows.Forms.Button
$Btn1.Location = '50, 100'
$Btn1.Text = "Get ACL"
$Btn1.Font =
$Btn1.Width = 100
$Btn1.Add_Click($Btn1Click)
$Form.Controls.Add($Btn1)
$Form.ShowDialog()
I have to say that with the code formatted as it is, it makes it very hard to see where the functions and loops start and end. Pick a style a stick with it.
Your function names are spelt oddly which is confusing ChckBx_unchkd and ChkcBx_chkd - why reverse ck in the prefix?
Your ChkcBx_chkd code doesn't appear to work - you're redefining the variable $Rtbx as an array where you want to set the .Text property.
You have no default value set so $Btn1Click is undefined until you change the checkbox state at least once.
Your assignment of $Btn1Click = ChckBx_chkd actually calls that function at that point where you appear be using it as a reference which you then call later. You should do $Btn1Click = "ChckBx_chkd" (i.e. a string name of the function) then later use Invoke-Expression $Btn1Click
The scope of your variables is not the same. Changing $Btn1Click does not affect the value. Write-Host is your friend - print the variables out to help you debug what values they have. I've used Get-Variable/Set-Variable so I can use the variables in the global scope.
Revised code
function ChckBx_chkd {
Write-Host "ChckBx_chkd called"
$table = Get-ChildItem -directory -path $Textbox1.Text -recurse
$Rtbx.Text = ""
foreach ($dir in $table) {
$Access = (Get-Acl $dir.FullName).Access
$Rtbx.Text += $dir.PSPath
$Rtbx.Text += $Access | Format-Table | out-string
}
}
function ChkcBx_unchkd {
Write-Host "ChkcBx_unchkd called"
$Rtbx.Text = (Get-Acl $Textbox1.Text).Access | Format-Table| Out-String
}
Set-Variable -Name Btn1Click -Value "ChckBx_chkd" -Scope Global
$Font = New-Object System.Drawing.Font("Lucida Console",8)
$Form = New-Object System.Windows.Forms.Form
$Form.Text = "ACL GUI"
$Form.Font = $Font
$Form.Width = 1000
$Form.Height = 500
$Rtbx = New-Object System.Windows.Forms.RichTextBox
$Rtbx.Location = '200, 100'
$Rtbx.Width = 750
$Rtbx.Font = $Font
$Rtbx.Height = 300
$Rtbx.Font
$Form.Controls.Add($Rtbx)
$Chkbx1 = New-Object System.Windows.Forms.CheckBox
$Chkbx1.Location = '50, 150'
$Chkbx1.Text = "undermappar"
$Chkbx1.Checked = $true
$Chkbx1.Add_CheckStateChanged({
Write-Host $Chkbx1.checked $(Get-Variable -Name Btn1Click -Scope Global).Value
if ($Chkbx1.checked) {
Set-Variable -Name Btn1Click -Value "ChckBx_chkd" -Scope Global
} else {
Set-Variable -Name Btn1Click -Value "ChkcBx_unchkd" -Scope Global
}
Write-Host $Chkbx1.checked $(Get-Variable -Name Btn1Click -Scope Global).Value
})
$Form.Controls.Add($Chkbx1)
$Textbox1 = New-Object System.Windows.Forms.TextBox
$Textbox1.Location = '50, 50'
$Textbox1.Width = 700
$Form.Controls.Add($Textbox1)
$Btn1 = New-Object System.Windows.Forms.Button
$Btn1.Location = '50, 100'
$Btn1.Text = "Get ACL"
$Btn1.Font =
$Btn1.Width = 100
$Btn1.Add_Click({Invoke-Expression $(Get-Variable -Name Btn1Click -Scope Global).Value})
$Form.Controls.Add($Btn1)
$Form.ShowDialog()

DataGridView. Run Job while entering new row parallel

The script included is to check the replication and repair for each Server that I add. The goal I have in mind is for it to automatically check the connection of each computer as I add them as well as check the uptime.
The current issue I'm having is that it will delay to check the uptime before it allows me to input my next computer.
As you can see in my script I'm trying to use a start-job which is not working at all for me as it says the 'ComputerName' is null, but the ComputerName is set in the Get-Uptime function.
I may be going about this all wrong. Any help would be great!!
function Check-Replication {
#----------------------------------------------
#region Import the Assemblies
#----------------------------------------------
[void][Reflection.Assembly]::Load('System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
[void][Reflection.Assembly]::Load('System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089')
[void][Reflection.Assembly]::Load('System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
[void][Reflection.Assembly]::Load('System.DirectoryServices, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
[void][Reflection.Assembly]::Load('System.ServiceProcess, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a')
#endregion Import Assemblies
$base64Image = "iVBORw0KGgoAAAANSUhEUgAAABMAAAATCAQAAADYWf5HAAAABGdBTUEAALGPC/xhBQAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAWG3AAFhtwFW7IyrAAAAB3RJTUUH4goDDxY48JvtEgAAAg9JREFUKM9NkT9MU1EUxn/33kf/APVPYQGaYImLYQAikU6kidFoWBwYjLgw6SZxkLhgnExc0A1ZHDC6uOmMDQ5KLCYuqINxoFgq2Ce0fbx/912GvhDOlzN9X77znXMEAFyhL7Uxmbl9vjjQn1ahrv35Vdp7NbxWc1eJaxFJIX9h+UZ9yZTMF/PVlM1Hs2Jm6yPLl/KwCIinPGZwxHsxPnGTXhQSgSEi4oB3rK7LO1vfFlA75Ib2X54rTJNFIBGAISLE0MdOrjo69GHDlteT9nxXYZQMEWBOQNPBGJmCPX81qZzL/kIuPUwPHVjxSIiI0Pj4/MXOV8pWa6Yzm0XFhIzXimLAGTqzrRkrKnbThSYgxELEwoiQkJCATrppFi09kCKJwSNJgEEgMBhCAjwCEqTQA5ZW7SME+AiiE24BPgaJQiuptI5zaCLMcRs0bSZEaSm3D/HwCdBodCzS6Dibh4valrLUoEGLQ1x8guPoPh6HODRpQkkNOs5UIp0mgUIAEZoQH5cm+/yjym6965GarXwfdC8msOJfhrFPW1Sjgl65tqRsfXrz/4SXkxg0IR4uDg322aPGFo3PPfc399QD3ti95dZYKxfg4+LQ4gCbXapUaKwn7/78MYeA59yjkK8/NNPpsxlSKDQuTRxbvs0++fT7GXOI9g+n6E+VJw9umaLJhcrSoiJKp16Pr1Xd9wAcAYNiEWcBi781AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE4LTEwLTAzVDE1OjIyOjU2LTA0OjAwISeC9gAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOC0xMC0wM1QxNToyMjo1Ni0wNDowMFB6OkoAAAAASUVORK5CYII="
$imageBytes = [Convert]::FromBase64String($base64Image)
$memStream = New-Object IO.MemoryStream($imageBytes, 0, $imageBytes.Length)
$memStream.Write($imageBytes, 0, $imageBytes.Length);
$imageGrey = [System.Drawing.Bitmap]::FromStream($memStream, $true)
$base64Image = "iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH4goDDxstKOh3tAAABJVJREFUOMtVlNtvVFUUxn/r3M8w7bSddloYWkpALlqoEBJ9IIQoSUUTEYj6B8CLMSbySOKTvtQYnlDf1ITggwHFiEAIl4CVxPBAAhQKIVwCpXTaTjuXM3PmXOZsH6aA7uTbe2Vl5Vt7rXxrCf85V69epVKpkMvlejVNW2saZtq2HU3XdA+gmcRdYRRKGIalJEkm6vX6M8uy1ObNm19wyHPj2rVrJEliua671bGdnFetPbwwdm7g1v3xVTPFmXbTMLUlqXRheM3wo5HtI0U3neoJgqAahuGYpmn+8PDwS8Lx8XGSJGlzHPtz07SWnT5/ev63yye2VbTqJiujp6wlpogIoR+rZjXxcnbvnd1bd13Z/uZ2I4zDsu/7h3RdXxgaGkKuX79Oo9EwM5n2L0zD+uT4mWP1Hy791FfL1my1VBGkAiIjBAEjNnHqDvqMTrbWGe/fvr/47rb39DAKf/Y876Bpmr5hGAau6+7WNf3T38+e0L85e2h5qb+kq/6EZrYJ7SB2qzMqBKoK3dF5NjlljJ79utc0zOCtN97eZ9nWDdd1fzR83+9LuakDE/fuZL87972aWzYrskpQeZBuDdIKLEAJEivwhKRdoeyEyeYk354/bK/Mr7SX9/Z/Vi6VL2oi8m4QhJuOXfiVh9YjkRUtMpYCvQp6gRyQU5AD1QcsVUgeZFC4pSb4458/iaJoSET2akqpXZNTj+0rD/9G9SXQI0g3SBeoTlDtQBuojEAGJAN0AVmgB5KehL8eXGa2OGskSfK+EUfx6/cfP6DQfIZ0AG0K0kAaJAU4gC6AAmNRY3ErCW2tJE8LT5mcfUrKTW3U6vV6R6FYIDBDcARsWj0zQAxpkT2HAZiAqVAmYCtwFL40KJaL+HU/ozUaDYmiCEFQAiIvJ0ct3uqF9XIe5LlDtcQcxTG+74vWTJrltJPGbtrQWJRG1CpLxQrVBEkUkihoKogXEQEhSAAOLq7h0Gw2K5pK1I2u9i5yeg7KIFXAE1Qd8IEGECyiAcoHaoKqAR6oMuTtPGkrTaKSW5ph6KeWpNqjDd0b0GcENStQBJkHKYFUgEVIGaQksNCKUXOgF3U29W1GFz0xDOOUls12n7Rt8+aWFVsYjAZRTxLUlIJpoADMPoe03gIwrWAKeKxYr69nY+8QmsjdTCZzXM/n85XBFSuCZpS80yEdxuPJJ9TCKpIIhK2yVX3xp0VgRmAK5KGivzTAx2s+JJvqjjq7Or86evToGX10dJSBgYG7Cwvz3SbmlqVmn3hzVYJKiBEYaDUdKYFWFIw5E6dg4046rA3W8MGqPfSlelVHR8eRda+uGx3eOBwKwKVLl2hra+u6ffv2l4Xpwr6F6rxzv/SAp/EkDScAp6UPLdBwohT97gCr21eRttJRNps9svqV1Qc9z5vduXPnywU7NjZGJpNxb9y8+dH83NyBeq021IgC3U8CYmJEwBILx3AxdbPpOs69bHf28Lq1646Uy2Vvx44d/9/YAIVCgVwux4WLFwann03v9TxvTxAEr8VxnBEEXdcrlmVNpNvSJ3t6en4ZGRm5PzU1pfL5/AuOfwFWfAyFldyKLAAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOC0xMC0wM1QxNToyNzo0NS0wNDowMDpMU7EAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTgtMTAtMDNUMTU6Mjc6NDUtMDQ6MDBLEesNAAAAAElFTkSuQmCC"
$imageBytes = [Convert]::FromBase64String($base64Image)
$memStream = New-Object IO.MemoryStream($imageBytes, 0, $imageBytes.Length)
$memStream.Write($imageBytes, 0, $imageBytes.Length);
$imageGreen = [System.Drawing.Bitmap]::FromStream($memStream, $true)
$base64Image = "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"
$imageBytes = [Convert]::FromBase64String($base64Image)
$memStream = New-Object IO.MemoryStream($imageBytes, 0, $imageBytes.Length)
$memStream.Write($imageBytes, 0, $imageBytes.Length);
$imageRed = [System.Drawing.Bitmap]::FromStream($memStream, $true)
#----------------------------------------------
#region Generated Form Objects
#----------------------------------------------
[System.Windows.Forms.Application]::EnableVisualStyles()
$form1 = New-Object 'System.Windows.Forms.Form'
$labelTypeEachComputerName = New-Object 'System.Windows.Forms.Label'
$textbox1 = New-Object 'System.Windows.Forms.TextBox'
$datagridview1 = New-Object 'System.Windows.Forms.DataGridView'
$buttonRun = New-Object 'System.Windows.Forms.Button'
$Online = New-Object 'System.Windows.Forms.DataGridViewImageColumn'
$Uptime = New-Object 'System.Windows.Forms.DataGridViewTextBoxColumn'
$Computer = New-Object 'System.Windows.Forms.DataGridViewTextBoxColumn'
$Status = New-Object 'System.Windows.Forms.DataGridViewTextBoxColumn'
$InitialFormWindowState = New-Object 'System.Windows.Forms.FormWindowState'
#endregion Generated Form Objects
#----------------------------------------------
# Function Get-Uptime
#----------------------------------------------
#region - Get-Uptime
$Uptime1 = {
function Get-Uptime {
Params ($ComputerName)
$global:ComputerName = $row.cells[2].Value
$os = Get-WmiObject win32_operatingsystem -ComputerName $ComputerName -ErrorAction SilentlyContinue
if ($os.LastBootUpTime) {
$uptime = (Get-Date) - $os.ConvertToDateTime($os.LastBootUpTime)
#Write-Output ("Last boot: " + $os.ConvertToDateTime($os.LastBootUpTime) )
Write-Output ("" + $uptime.Days + "d " + $uptime.Hours + "h " + $uptime.Minutes + "m" )
} else {
Write-Warning "Unable to connect to $computername"
}
}
}
#endregion
#----------------------------------------------
# User Generated Script
#----------------------------------------------
$FormEvent_Load = {
}
$textbox1_Validated = {
if ($textbox1.Text -ne "") {
$i = $datagridview1.Rows.Add(1)
$row = $datagridview1.Rows[$i]
$row.SetValues(#($imageGrey,'',$textbox1.Text,'pending'))
$textbox1.Text = ''
$textbox1.Focus()
if ($row.Cells[2].Value -ne "") {
if (Test-Connection -ComputerName $row.cells[2].Value -Count 1 -Quiet) {
$Time = Get-Date
Start-Job -InitializationScript $Uptime1 -scriptblock {(Get-Uptime -ComputerName $args[0])} -Args $row.cells[2].Value |
#Start-Job -InitializationScript $Uptime1 -scriptblock {(Get-Uptime)}|
Wait-Job | Receive-Job
$row.SetValues(#($imageGrey,($Uptime),$row.Cells[2].Value))
#Remove-Job -Name CheckSiteUptime
$Time = Get-date
$row.Cells[0].Value = $imageGreen
} else {
$row.Cells[0].Value = $imageRed}
}
}
}
$buttonRun_Click = {
$datagridview1.Rows | ForEach-Object {
$row = [System.Windows.Forms.DataGridViewRow]$_
$CommandResult = Invoke-Command -ComputerName $row.cells[2].Value -ArgumentList $row -ScriptBlock{
Param($row)
Import-Module Hyper-V
if ((Get-VM -ErrorAction Stop | Where-Object {$_.name -like '*SR*'} | Get-VMReplication -ErrorAction Stop).Replicationhealth -eq 'critical') {
try{
Get-VM -ErrorAction Stop | Where-Object {$_.name -like '*SR*'} | Resume-VMReplication -ErrorAction Stop
if ((Get-VM -ErrorAction Stop | Where-Object {$_.name -like '*SR*'} | Get-VMReplication -ErrorAction Stop).Replicationhealth -eq 'critical') {
throw [System.Exception] "Replicationhealth critical"
}
} catch {
try{
Get-VM -ErrorAction Stop | Where-Object {$_.name -like '*SR*'} | Resume-VMReplication -Resynchronize -ErrorAction Stop
} catch {
return 'FAILED: Resume-VMReplication -Resynchronize'
break
}
return 'Successful: Resume-VMReplication -Resynchronize'
break
}
return 'Successful: Resume-VMReplication'
} else {
return 'Successful: No action replication is NOT critical'
}
}
switch ($CommandResult) {
"FAILED: Resume-VMReplication -Resynchronize" {
$row.Cells | %{$_.Style.BackColor = 'pink'}
$Row.Cells[3].Value = $CommandResult
}
"Successful: Resume-VMReplication -Resynchronize" {
$row.Cells | %{$_.Style.BackColor = 'lightgreen'}
$Row.Cells[3].Value = $CommandResult
}
"Successful: Resume-VMReplication" {
$row.Cells | %{$_.Style.BackColor = 'lightgreen'}
$Row.Cells[3].Value = $CommandResult
}
"Successful: No action replication is NOT critical" {
$row.Cells | %{$_.Style.BackColor = 'lightgreen'}
$Row.Cells[3].Value = $CommandResult
}
}
}
$datagridview1.ReadOnly = $true
}
# --End User Generated Script--
#----------------------------------------------
#region Generated Events
#----------------------------------------------
$Form_StateCorrection_Load = {
#Correct the initial state of the form to prevent the .Net maximized form issue
$form1.WindowState = $InitialFormWindowState
}
$Form_Cleanup_FormClosed = {
#Remove all event handlers from the controls
try {
$textbox1.remove_Validated($textbox1_Validated)
$buttonRun.remove_Click($buttonRun_Click)
$form1.remove_Load($FormEvent_Load)
$form1.remove_Load($Form_StateCorrection_Load)
$form1.remove_FormClosed($Form_Cleanup_FormClosed)
} catch {
Out-Null <# Prevent PSScriptAnalyzer warning #>
}
}
#endregion Generated Events
#----------------------------------------------
#region Generated Form Code
#----------------------------------------------
$form1.SuspendLayout()
#
# form1
#
$form1.Controls.Add($labelTypeEachComputerName)
$form1.Controls.Add($textbox1)
$form1.Controls.Add($datagridview1)
$form1.Controls.Add($buttonRun)
$form1.AutoScaleDimensions = '6, 13'
$form1.AutoScaleMode = 'Font'
$form1.ClientSize = '625, 600'
$form1.FormBorderStyle = 'FixedDialog'
$form1.MaximizeBox = $False
$form1.MinimizeBox = $False
$form1.Name = 'form1'
$form1.StartPosition = 'CenterScreen'
$form1.Text = 'Replication Check'
$form1.add_Load($FormEvent_Load)
#
# labelTypeEachComputerName
#
$labelTypeEachComputerName.Location = '20, 18'
$labelTypeEachComputerName.Name = 'labelTypeEachComputerName'
$labelTypeEachComputerName.Size = '240, 49'
#$labelTypeEachComputerName.TabIndex = 5
$labelTypeEachComputerName.Text = 'Type each computer name ending with a <tab> it will be added to the list. Click run when alll have been added.'
$labelTypeEachComputerName.UseCompatibleTextRendering = $True
#
# textbox1
#
$textbox1.CharacterCasing = 'Upper'
$textbox1.Location = '20, 81'
$textbox1.Name = 'textbox1'
$textbox1.Size = '285, 20'
#$textbox1.TabIndex = 1
$textbox1.add_Validated($textbox1_Validated)
#
# datagridview1
#
$datagridview1.AllowUserToAddRows = $False
$datagridview1.AllowUserToDeleteRows = $False
$datagridview1.AllowUserToResizeColumns = $True
$datagridview1.AllowUserToResizeRows = $False
$datagridview1.ColumnHeadersHeightSizeMode = 'AutoSize'
[void]$datagridview1.Columns.Add($Online)
[void]$datagridview1.Columns.Add($Uptime)
[void]$datagridview1.Columns.Add($Computer)
[void]$datagridview1.Columns.Add($Status)
$datagridview1.columns[0].Width = '40'
$datagridview1.columns[3].Width = '250'
$datagridview1.Location = '20, 113'
$datagridview1.Name = 'datagridview1'
$datagridview1.ReadOnly = $True
$datagridview1.Size = '583, 470'
$datagridview1.TabIndex = 3
$datagridview1.DefaultCellStyle.WrapMode = "True"
#
# buttonRun
#
$buttonRun.Location = '325, 80'
$buttonRun.Name = 'buttonRun'
$buttonRun.Size = '75, 23'
$buttonRun.TabIndex = 2
$buttonRun.TabStop = $False
$buttonRun.Text = 'Run'
$buttonRun.UseCompatibleTextRendering = $True
$buttonRun.UseVisualStyleBackColor = $True
$buttonRun.add_Click($buttonRun_Click)
#
# Online
#
$Online.HeaderText = 'Online'
$Online.Name = 'Online'
$Online.DataPropertyName = 'Online'
#
# Uptime
#
$Uptime.HeaderText = 'Uptime'
$Uptime.Name = 'Uptime'
$Uptime.ReadOnly = $True
#
# Computer
#
$Computer.HeaderText = 'Server'
$Computer.Name = 'Server'
$Computer.ReadOnly = $True
#
# Status
#
$Status.HeaderText = 'Status'
$Status.Name = 'Status'
$Status.ReadOnly = $True
$form1.ResumeLayout()
#endregion Generated Form Code
#----------------------------------------------
#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($Form_StateCorrection_Load)
#Clean up the control events
$form1.add_FormClosed($Form_Cleanup_FormClosed)
#Show the Form
return $form1.ShowDialog()
} #End Function
#Call the form
Check-Replication | Out-Null
Because PowerShell jobs run in a separate runspace, even declaring a variable as $global: does not make it available inside your job. Instead, you need to pass the value in to your job when you create it.
For example, you could change your code as follows:
...
Function Get-Uptime {
params ($ComputerName)
$global:ComputerName = $ComputerName
...
Start-Job -InitializationScript $Uptime1 -scriptblock {(Get-Uptime -ComputerName $args[0])} -Args $row.cells[2].Value
A similar issue is described here: https://social.technet.microsoft.com/Forums/ie/en-US/5b369c15-d2ad-4ee8-a1fc-3f0ca8df230a/powershell-jobs-and-global-variables?forum=ITCG
Another resource on some options other than PS jobs, which tend to be relatively inefficient: https://randombrainworks.com/2018/01/28/powershell-background-jobs-runspace-jobs-thread-jobs/
Another way around your base issue of de-coupling your form/GUI from your backend code is to use runspaces and a synchronized hashtable. The advantage of this model is that your can have many threads simultaneously performing work and actively updating your form, and instead of passing variables around, you have a single copy and pass references.
This is a great article to get started: https://learn-powershell.net/2012/10/14/powershell-and-wpf-writing-data-to-a-ui-from-a-different-runspace/

Array behaviour difference in PowerShell 2 to PowerShell 3

I have observed a difference in behavior between PowerShell 2.0 code and 3.0 code but can't seem to fix it. I am hoping I can get some help. Please see code below.
If you run this in V2 (please change ServerA and ServerB to a server on your network) you will see after selecting and clicking the button, write-host shows them as seperate names. In version 3 the listbox populates it as 1.
$Servers = #()
[array]$ServerstoPing = ("ServerA","ServerB")
# Generate the form
Add-Type -AssemblyName System.Windows.Forms
$Form1 = New-Object system.Windows.Forms.Form
$Form1.Text = "Ping Some Servers"
$Font = New-Object System.Drawing.Font("Calibri",18,[System.Drawing.FontStyle]::regular)
$Fontboxes = New-Object System.Drawing.Font("Lucida Sans",8,[System.Drawing.FontStyle]::regular)
$Fontdate = New-Object System.Drawing.Font("Lucida Sans",11,[System.Drawing.FontStyle]::bold)
$FontProgress = New-Object System.Drawing.Font("Lucida Sans",11,[System.Drawing.FontStyle]::bold)
$Form1.Font = $Font
$Serverlistbox = New-Object System.Windows.Forms.Listbox
$Serverlistbox.Location = New-Object System.Drawing.Size(11,137)
$Serverlistbox.Size = New-Object System.Drawing.Size(200,170)
$Serverlistbox.SelectionMode = "MultiExtended"
$Serverlistbox.font = $Fontboxes
foreach($item in $ServerstoPing){
[void] $Serverlistbox.Items.Add("$item")
}
$Form1.Controls.Add($Serverlistbox)
$SubmitButton = New-Object System.Windows.Forms.button
$SubmitButton.text = "Ping Servers"
$SubmitButton.Location = New-Object System.Drawing.Size(171,305)
$SubmitButton.AutoSize = $True
$Form1.Controls.Add($SubmitButton)
$Form1.StartPosition = "CenterScreen"
$OutputPing = New-Object System.Windows.Forms.TextBox
$OutputPing.MultiLine = $True
$OutputPing.ScrollBars = "Vertical"
$OutputPing.text = "Server ping status will be displayed here once done'."
$OutputPing.font = $Fontboxes
$OutputPing.Location = New-Object System.Drawing.Size(226,40)
$OutputPing.Size = New-Object System.Drawing.Size(200,255)
$Form1.Controls.Add($OutputPing)
$SubmitButton.add_click({
#foreach ($objItem in $ServerstoPing)
foreach ($objItem in $Serverlistbox.SelectedItems)
{
$Servers += $objItem
}
write-host $ServerstoPing
Foreach($server in $servers)
{
ping -n 1 -w 1000 $server | out-null
if($? -eq $true){
write-host ("$server ping success")
}
else
{
write-host ("$server did not respond to ping, not extracting events")
}
}
})
$Form1.ShowDialog()

Powershell script does not work properly

There is a script on powershell, that creates and removes vpn connection from the user.
The script is a simple form with two buttons "Create" and "Delete", and the output textbox.
If i run a script and click create, the connection is created. But if not closing the form, press delete, the connection is not removed. If i reopen the form, then everything works and connection delete
What could be the problem?
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Windows.Forms.Application]::EnableVisualStyles()
#################Main Form#################
$Form = New-Object System.Windows.Forms.Form
$Form.Size = New-Object System.Drawing.Size(552,654)
$form.MaximizeBox = $false
$Form.StartPosition = "CenterScreen"
$Form.FormBorderStyle = 'Fixed3D'
$Form.Text = "VPN create"
##########Constants and Variables##########
$IpAddress = #("172.17.0.0/16", "192.168.197.0/24", "192.168.196.0/24")
$vpnConnection = Get-VpnConnection -AllUserConnection
#########Start functions############
function CreateVPN {
if ($vpnConnection.Name -eq "ConWork") {
$outputBox.Text = "connection is already there"
} else {
Add-VpnConnection -Name "ConWork" -ServerAddress "xxx.xxx.xxx.xxx" -TunnelType IKEv2 -EncryptionLevel Required -AuthenticationMethod Eap -SplitTunneling -RememberCredential -AllUserConnection | Out-String
$outputBox.Text += ("Connection created")
$outputBox.Text += "`r`n"
$outputBox.Text += "Routes added"
foreach ($ip in $IpAddress) {
$outputBox.Text += Add-VpnConnectionRoute -ConnectionName "ConWork" -DestinationPrefix $ip -PassThru | Out-String
}
}
}
function RemoveVPN {
if ($vpnConnection.Name -eq "ConWork") {
$outputBox.Text += ("Routes delete")
foreach ($ip in $IpAddress) {
$outputBox.Text += Remove-VpnConnectionRoute -ConnectionName "ConWork" -DestinationPrefix $ip -PassThru | Out-String
}
$outputBox.Text += ("Connection delete")
$outputBox.Text += Remove-VpnConnection -Name "ConWork" -Force -PassThru -AllUserConnection | Out-String
} else {
$outputBox.text = "No such connection"
}
}
###########end functions################
############Start text fields###########
$outputBox = New-Object System.Windows.Forms.TextBox
$outputBox.Location = New-Object System.Drawing.Size(206,23)
$outputBox.Size = New-Object System.Drawing.Size(318,578)
$outputBox.MultiLine = $True
$outputBox.ScrollBars = "Vertical"
$outputBox.font = "lucida console"
$Form.Controls.Add($outputBox)
###############end text fields################
##############Start buttons################
$CreateTun = New-Object System.Windows.Forms.Button
$CreateTun.Location = New-Object System.Drawing.Size(42,23)
$CreateTun.Size = New-Object System.Drawing.Size(89,43)
$CreateTun.Text = "Create"
$CreateTun.Add_Click({CreateVPN})
$Form.Controls.Add($CreateTun)
$Removetun = New-Object System.Windows.Forms.Button
$Removetun.Location = New-Object System.Drawing.Size(42,90)
$Removetun.Size = New-Object System.Drawing.Size(89,43)
$Removetun.Text = "Delete"
$Removetun.Add_Click({RemoveVPN})
$Form.Controls.Add($Removetun)
############################################## end buttons
#$Form.Add_Shown({$Form.Activate()})
$Form.ShowDialog()
Your problem is that you are checking for VPN connection only once, when the script is started:
$vpnConnection = Get-VpnConnection -AllUserConnection
After that you are reusing this variable to in your RemoveVPN function. It will never find any new connections. To make it work, just move the line from above inside your RemoveVPN function

Counting Services on multiple servers

I'm still a beginner with powershell, but love to learn and research all the things it can do.
So with that, I am looking to create a script that will output to a datagridview table. I created a simple enough form that has a multi-line text box where you can enter in a list of servers and then just a simple "check" button that calls my function to actually query each server for their services and outputs that info into the datagridview below it.
That part was easy enough for me to create. My thing is, I want it to do the following":
query each server and pull the list of all services on that server
then in the datagridview, I want it to show the service name in column 1, and then the count of how many servers have that service in column 2
Hope this make since. Can't really provide any code as I don't know how to properly write it! I'm thinking there is someway to generate the full list, then do a loop and count type thing, but not sure.
I thank you for any assistance with this. Been googling and reading up like crazy. Either not correct search criteria or something just isn't clicking for me.
Update - Adding in current script I have:
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$xForm = 800
$yForm = 800
$SVCForm = New-Object System.Windows.Forms.Form
$SVCForm.Text = "Automatic Services Query"
$SVCForm.Size = New-Object System.Drawing.Size($xForm,$yForm)
$SVCForm.FormBorderStyle = "FixedSingle"
$SVCForm.StartPosition = "CenterScreen"
$SVCForm.ControlBox = $true
$SVCForm.KeyPreview = $True
$SVCForm.ShowIcon = $false
$SVCForm.MinimizeBox = $True
$SVCForm.MaximizeBox = $false
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size(365,720)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({$x=$CancelButton.Text;$SVCForm.Close()})
$SVCForm.Controls.Add($CancelButton)
$ServerListGroup = New-Object System.Windows.Forms.GroupBox
$ServerListGroup.Location = New-Object System.Drawing.Size(5,10)
$ServerListGroup.size = New-Object System.Drawing.Size(780,300)
$ServerListGroup.text = "Enter list of servers you want to check:"
$SVCForm.Controls.Add($ServerListGroup)
$ServerList = New-object System.Windows.Forms.TextBox
$ServerList.Location = New-object System.Drawing.Size(5,25)
$ServerList.Size = New-Object System.Drawing.Size(280,270)
$ServerList.Multiline = $True
$ServerList.ScrollBars = "Vertical"
#$ServerList.add_TextChanged({ONValButton})
$ServerListGroup.Controls.Add($ServerList)
$SVCButton = New-Object System.Windows.Forms.Button
$SVCButton.Location = New-Object System.Drawing.Size(505,140)
$SVCButton.Size = New-Object System.Drawing.Size(180,22)
$SVCButton.Text = "SVC Check"
$SVCButton.Enabled = $True
$SVCButton.Add_Click({SvcCheckCount})
$ServerListGroup.Controls.Add($SVCButton)
$SvcListGroup = New-Object System.Windows.Forms.GroupBox
$SvcListGroup.Location = New-Object System.Drawing.Size(5,330)
$SvcListGroup.size = New-Object System.Drawing.Size(780,380)
$SvcListGroup.text = "Automatic Running/Not-Running Services are listed below:"
$SVCForm.Controls.Add($SvcListGroup)
#$SvcList = New-object System.Windows.Forms.TextBox
#$SvcList.Location = New-object System.Drawing.Size(5,25)
#$SvcList.Size = New-Object System.Drawing.Size(765,350)
#$SvcList.Multiline = $True
#$SvcList.ScrollBars = "Vertical"
#$SvcList.Readonly= $True
#$SvcListGroup.Controls.Add($SvcList)
$SvcGrid = New-Object System.Windows.Forms.DataGridView
$SvcGrid.Location = New-Object System.Drawing.Size(5,15)
$SvcGrid.Size = New-Object System.Drawing.Size(760,360)
$SvcGrid.ColumnHeadersBorderStyle = [System.Windows.Forms.DataGridViewHeaderBorderStyle]::Single
$SvcGrid.CellBorderStyle = [System.Windows.Forms.DataGridViewCellBorderStyle]::Single
$SvcGrid.ColumnHeadersHeightSizeMode = [System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode]::DisableResizing
$SvcGrid.GridColor = [System.Drawing.Color]::Black
$SvcGrid.RowHeadersVisible = $false
$SvcGrid.AllowUserToAddRows = $false
$SvcGrid.AllowUserToResizeColumns = $False
$SvcGrid.AllowUserToResizeRows = $false
$SvcGrid.ColumnHeadersHeight = 23
$SvcGrid.SelectionMode = [System.Windows.Forms.DataGridViewSelectionMode]::FullRowSelect
$Scroll = New-Object System.Windows.Forms.VScrollBar
$Scroll.Dock = [System.Windows.Forms.DockStyle]::Right
$Scroll.width = 18
$Scroll.isAccessible = $false
$SvcGrid.Controls.Add($Scroll)
$SvcGrid.Columns.Add("Name","Service Name") > $null
$SvcGrid.Columns["Name"].Width = 200
$SvcGrid.Columns["Name"].HeaderCell.Style.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft
$SvcGrid.Columns["Name"].DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft
$SvcGrid.Columns["Name"].ReadOnly = $False
$SvcGrid.Columns.Add("StartMode", "Start Mode") > $null
$SvcGrid.Columns["StartMode"].Width = 180
$SvcGrid.Columns["StartMode"].HeaderCell.Style.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft
$SvcGrid.Columns["StartMode"].DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleLeft
$SvcGrid.Columns["StartMode"].ReadOnly = $False
$SvcGrid.Columns.Add("Running","Running") > $null
$SvcGrid.Columns["Running"].Width = 180
$SvcGrid.Columns["Running"].HeaderCell.Style.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter
$SvcGrid.Columns["Running"].DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter
$SvcGrid.Columns["Running"].ReadOnly = $true
$SvcGrid.Columns.Add("NotRunng","Not Running")>$null
$SvcGrid.Columns["NotRunng"].Width = 180
$SvcGrid.Columns["NotRunng"].HeaderCell.Style.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter
$SvcGrid.Columns["NotRunng"].DefaultCellStyle.Alignment = [System.Windows.Forms.DataGridViewContentAlignment]::MiddleCenter
$SvcGrid.Columns["NotRunng"].ReadOnly = $true
$SvcListGroup.Controls.Add($SvcGrid)
Function SvcCheckCount
{
$SvcGrid.Rows.Clear()
$Servername = $ServerList.Text.Split("`n")|%{$_.trim()}
foreach($Server in $Servername)
{
$Server = $Server.ToUpper()
$svctest = Get-WmiObject Win32_Service | Where-Object {$_.StartMode -eq 'Auto'} | Select-Object Name, Startmode, State
Foreach ($svc in $svctest)
{
$name = $svc.Name
$startmode = $svc.StartMode
$state = $svc.State
If($state-eq"Running"){$SvcGrid.Rows.add($name,$startmode,$state)}
If($state-eq"Stopped"){$SvcGrid.Rows.add($name,$startmode,$null,$state)}
}
}
}
$SVCForm.Topmost = $True
$SVCForm.Add_Shown({$SVCForm.Activate()})
[void] $SVCForm.ShowDialog()
Since you already have the GUI portion of this functioning I am going to focus us the grouping of the data you are looking for. Going into this the one thing I am fuzzy on is why you have the if statements are for but we can work on that if need be. The following is meant to be in place of your foreach loop
$services = #()
foreach($Server in $Servername){
$Server = $Server.ToUpper()
$services += Get-WmiObject Win32_Service -ComputerName $Server -Filter 'StartMode="Auto"' |
Select-Object Name, Startmode, State |
Add-Member -MemberType NoteProperty -Value $Server -Name "Server" -PassThru
}
$services | Group-Object Name | ForEach-Object{
$SvcGrid.Rows.add($_.Name,$_.Count)
}
First thing: you were not using the $server variable in your wmi call so all the results would have been from the one machine you were running this from. Also, I moved the Where into a -Filter so that should speed up processing on remote machines.
Collect all of this information into an array (adding the computer name in case it becomes useful later). Then, using the results from that use Group-Object to get the counts you were looking for. Pipe that into another ForEach-Object to get the results in your grid ( which i have not tested.)
Side note: If you just want the info in a grid you can use Out-GridView
$services | Group-Object Name | Select name,count | Out-GridView