Powershell find silverlight time elasped - silverlight

I'm trying to use PowerShell to find the total time elapsed for a Silverlight web application (IE10) to load. Since this is a Silverlight app, I wished to find the time elapsed AFTER Silverlight loads, not just when the web page loads. I've tried the following but Silverlight always crashes.
$ie = New-Object -ComObject internetexplorer.application
$ie.visible = $true
while($ie.busy){}#wait for browser to load
$time = measure-command -expression{
$ie.navigate('http://www.mysilverlightapp.com')
while($ie.readyState -ne 4){}
}
write-host "$($time.totalseconds)"
Please help me on what I'm doing wrong.

Related

Powershell start-sleep freeze/block interaction on my winforms

I am trying to enter a 10 second wait in order to execute a command in my script.
The problem is that when I run start-sleep my interface flickers or blocks the window.
I tried to do a special function without using start-sleep but the same thing happens.
First solution (Freeze/Block interaction windows)
if ($Timeout -gt 0) {
Start-Sleep -seconds $Timeout
}
Second solution (Freeze/Block interaction windows)
if ($Timeout -gt 0) {
Timeout $Timeout
}
function Timeout($seconds) {
$doneDT = (Get-Date).AddSeconds($seconds)
while($doneDT -gt (Get-Date)) {
$secondsLeft = $doneDT.Subtract((Get-Date)).TotalSeconds
write-host $secondsLeft
}
}
How could I do to timeout code execution without freezing my winforms? Thank you
I would suggest you to do a Background Job using Start-Job (easiest) or Runspace (a little hard to do but efficient) for your task so u do not have to rely on the sleep timer to make sure ur command completed. But that is your prerogative.
However, you can use this neat little trick although not ideal, to counter your non-responsive form problem. Use the below block to introduce the 10s delay.
for ($i = 0; $i -lt 50; $i++)
{
Start-Sleep -Milliseconds 200
[System.Windows.Forms.Application]::DoEvents()
}
EDIT: Including suggestions.
Sure you can do this inside WinForms. I have done this before. I just moved onto Runspaces later for reasons of efficiency and resources. But for simple purposes, Start-Job is the easiest way to go.
$ScriptBlock = {
#super lengthy code enclosed in paranthesis to create a scriptblock
#say takes a large amount of time to complete
}
$myJob = Start-Job -ScriptBlock $ScriptBlock
Do
{
Start-Sleep -Milliseconds 100
[System.Windows.Forms.Application]::DoEvents()
}
While ($myJob.State -ne "Completed")
$myJob | Receive-Job
Now you can include contingencies for when the job fails and stuff, but I will let u figure that out.

PowerShell/WPF: Disable Button on Click

I'm writing a little toolbox at work for the common vSphere tasks. This time around, I wanted to dip into WPF.
I have created an initial connect-to-server GUI, and everything works as designed. But now I'm stuck at the following:
When clicking the Connect button (btnConnect), I want it to become greyed out/disabled, followed by the connection attempt. Once the attempt is done, it can become active again. This is to prevent people from clicking on it multiple times in a row.
This is my first attempt (I'm unable to show the complete thing, given that it's 4 files and there's some stuff in it that I'm not allowed to freely share, so I will post what's relevant):
$Window.btnConnect.Add_Click({
$Window.btnConnect.IsEnabled = $False
$Window.btnConnect.Content = 'Connecting...'
Connect-CompanyVIServer -VIServer 'ServerName' -VICredential 'PSCredentialObject'
$Window.btnConnect.Content = 'Connect'
$Window.btnConnect.IsEnabled = $True
})
Essentially, I disable the button, change it's text to Connecting..., and connect to the VMware vCenter Server. Afterwards I change the button label back and re-enable it.
When I click on the button, the form hangs while it's loading and making the connection attempt. This is to be expected, being that they're in the same thread. That's fine, since the form should do anything until the attempt is completed anyway (and learning both WPF AND runspaces at the same time would make it too complex).
The problem is that even though the $Window.btnConnect.IsEnabled = $False is at the top, the form doesn't actually update until the entire block is done processing. Until that time, I can continue clicking on the button and it'll just buffer the attempts and execute them after one-another.
So I figured I'd split them up into separate events:
$Window.btnConnect.Add_Click({ $Window.btnConnect.IsEnabled = $False })
$Window.btnConnect.Add_IsEnabledChanged({
If ($Window.btnConnect.IsEnabled -eq $False) {
$Window.btnConnect.Content = 'Connecting...'
Connect-CompanyVIServer -VIServer 'ServerName' -VICredential 'PSCredentialObject'
$Window.btnConnect.Content = 'Connect'
$Window.btnConnect.IsEnabled = $True
}
})
A valiant attempt, didn't work though. I get the exact same thing.
So now I'm out of ideas. I was considering writing a trigger into the WPF code to disable the button, but I have no idea if that works. If I do something to run the connection attempt asynchronously, I'd need to be able to query fir the outcome somehow. I'm still experimenting. In the meantime, I come here for help.
My goal is to open a new window once the connection is present and then let it close this window. The important part is that I prevent users from clicking on the button more than once.
Anyone?
As a comment above alludes to, turning the button off, doing work, and then turning it on again is on a particular thread, but not the thread that updates the GUI. It seems as though it happens instantaneously from the GUI thread perspective, i.e. off then on, nothing happens.
If you use the dispatcher to send a message to the GUI thread, i.e.
$Window.Dispatcher.invoke([action]{$Window.btnConnect.IsEnabled -eq $False})
you would see that now you have successfully disabled the button (grayed it out) after a single click. Unfortunately, that's now a permanent situation on the GUI.
To do the "turn off, work, turn on" in a different thread, using a runspace, would go something like (forgive me if not perfect):
function my_func {
param($Window,$btnConnect)
$Runspace = [runspacefactory]::CreateRunspace()
$Runspace.ApartmentState = "STA"
$Runspace.ThreadOptions = "ReuseThread"
$Runspace.Open()
$Runspace.SessionStateProxy.SetVariable("Window",$Window)
$Runspace.SessionStateProxy.SetVariable("btnConnect",$btnConnect)
#add server name/credentials with SetVariable so they can be seen in code block
$code = {
$Window.Dispatcher.invoke(
[action] {$Window.Dispatcher.btnConnect.IsEnabled = $False})
$Window.btnConnect.Content = 'Connecting...'
Connect-CompanyVIServer -VIServer 'ServerName' -VICredential 'PSCredentialObject'
$Window.btnConnect.Content = 'Connect'
#below line throws away any clicks since we've disabled button
[System.Windows.Forms.Application]::DoEvents()
$Window.Dispatcher.invoke(
[action] {$Window.Dispatcher.btnConnect.IsEnabled = $True})
}
$PSinstance = [powershell]::Create().AddScript($code)
$PSinstance.Runspace = $Runspace
$job = $PSinstance.BeginInvoke()
}
$Window.btnConnect.Add_Click({
my_func $Window $Window.btnConnect
})

PowerShell Forms Won't Trigger DragDrop

There's nothing to suggest that a simple Windows Forms DragDrop won't work in PowerShell, and several resources explaining that it does work, however I cannot get any of them working. Even something as simple as this:
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$form = New-Object System.Windows.Forms.Form
$TBcode = New-Object System.Windows.Forms.TextBox
$form.Controls.Add($TBcode)
$TBcode.Dock = "Fill"
$TBcode.Multiline = $true
$TBCode.ScrollBars = "Vertical"
$TBCode.AllowDrop = $true
$TBcode.Add_DragEnter({ Write-Host "DragEnter"; $_.Effects = "Copy" })
$TBcode.Add_DragDrop({ Write-Host "DragDrop" })
$TBcode.Add_MouseEnter({ Write-Host "Mouse Enter" })
$form.ShowDialog()
The MouseEnter event triggers normally however when attempting to drag anything in to the TextBox nothing happens.
I had a sudden realisation and was able to confirm that this is in fact User Account Control.
Because I'm on Windows 10 I've got my PowerShell running as Administrator so I can actually do what I need to, however an object from the User-level Explorer process (or anything else running as a user) will simply refuse to interact with the Administrator-level PowerShell form.
Running PowerShell as a user allows the DragDrop to work as expected, but good luck if you need it to be admin! >_>

winform displaying in classic view outside of ISE

Not sure what is causing this issue but I have a PowerShell script that uses Windows Forms as the UI. When developing it inside of the PowerShell ISE everything looked nice with modern style buttons. When I run it from PowerShell it displays in a Windows Classic style view and crashes when I make a call to New-Object System.Windows.Forms.SaveFileDialog. Is there a fix for this that I can add to my code so my script not only looks better but actually functions outside of the ISE?
Edit:
This is my function where I call SaveFileDialog. This works inside of the ISE but when I run the script from PowerShell itself it crashes when I call this.
function exportToCSV([System.Object[]] $expArray) {
$save = New-Object System.Windows.Forms.SaveFileDialog
$save.CreatePrompt = $False
$save.SupportMultiDottedExtensions = $True
$save.DefaultExt = "csv"
$save.Filter = "CSV (*.csv) | *.csv*"
$save.Title = "Export to CSV"
if ($save.ShowDialog() -eq "OK") {
$expArray | export-csv $save.FileName
}
}
Include the following command in your script before showing the form to get modern style appearance.
[System.Windows.Forms.Application]::EnableVisualStyles()
This should however not affect the savefiledialog. I'm gonna need more to help you with that since you're saying it works in ISE, but not in normal console.
A workaround for your SaveFileDialog is adding:
$save.ShowHelp = $true
In PS3.0 everything works fine, but in PS2.0 the dialog doesn't show. The ShowHelp fixes that, but also gives you an old-style dialog. However, functionality is more imporant then appearance. :)

In PowerShell Form.Show() does not work right, but Form.ShowDialog() does

I am trying to display an image via powershell. I made a script based on this forum post.
If I use ShowDialog() it works fine, except the powershell execution stops while the dialog is up. However, that is by design for a modal dialog. If I call Form.Show() in PowershellISE the form shows up, but freezes and cannot be moved or dismissed. Behavior is similar if I copy and past the code to a powershell console.
How do I make the dialog non-modal, and not freeze.
First Answer Why it appends.
In a Windows graphic program the thread which create a Window must loop in a message pump in order to redistribute (translate) messages coming from the user action to events in his Windows.
In a modal window, the modal code that handles the window display runs its own message pump loop and doesn't return until the window is closed. That's why the code after ShowDialog() won't execute until the window is closed.
Show(), just ask to show the Window, but if there is no pump loop to manage the messages coming from user action, it just freezes.
Second a simple way to have two threads
The CmdLet start-job use another thread from the pool allocated by Powershell so it makes the dialog non-modal, and it does not freeze.
function goForm
{
[void][reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
$file = (get-item 'C:\temp\jpb.png')
#$file = (get-item "c:\image.jpg")
$img = [System.Drawing.Image]::Fromfile($file);
# This tip from http://stackoverflow.com/questions/3358372/windows-forms-look-different-in-powershell-and-powershell-ise-why/3359274#3359274
[System.Windows.Forms.Application]::EnableVisualStyles();
$form = new-object Windows.Forms.Form
$form.Text = "Image Viewer"
$form.Width = $img.Size.Width;
$form.Height = $img.Size.Height;
$pictureBox = new-object Windows.Forms.PictureBox
$pictureBox.Width = $img.Size.Width;
$pictureBox.Height = $img.Size.Height;
$pictureBox.Image = $img;
$form.controls.add($pictureBox)
$form.Add_Shown( { $form.Activate() } )
$form.ShowDialog()
}
Clear-Host
start-job $function:goForm
$name = Read-Host "What is you name"
Write-Host "your name is $name"
There are ways to make this work, but nothing is worth spending five hours explaining on an open forum. There are other free, shrink-wrapped ways to do this on powershell. Most notably with the free WPF powershell toolkit: Show-UI at http://showui.codeplex.com/ (previously known as WPK and/or PowerBoots - they are merged now.)
If your goal is actually to not block the interactive console when an image is shown then you still can use the script as it is with ShowDialog but you should start it using, for example, Start-Job. Thus, the dialog is still modal but it blocks execution in another runspace. The main runspace still can be used for invoking other commands.
Caveats: 1) You should close all opened dialogs before closing the interactive console. 2) If you care, you should remove completed jobs yourself (when a dialog is closed a job that started it still exists).
I use a similar approach in my custom host and it works fine. I also tested it with the script from your link. I changed it slightly so that it is called show-image.ps1 and accepts a file path as a parameter.
This command shows an image and blocks the calling runspace:
show-image.ps1 C:\TEMP\_110513_055058\test.png
This command shows an image and does not block the calling runspace:
Start-Job { show-image.ps1 $args[0] } -ArgumentList C:\TEMP\_110513_055058\test.png
Building on #JPBlanc's anwer, this would also be possible (and faster) using a runspace.
Here's a basic example (the rest would basically remain the same)
$ps = [PowerShell]::Create()
[void]$ps.AddScript({
Add-Type -AssemblyName System.Windows.Forms
$form = [Windows.Forms.Form]::new()
$form.ShowDialog()
})
[void]$ps.BeginInvoke()

Resources