Calling Mocha and piping results to string - powershell

I've created a a FileSystemWatcher object that I have events registered for. I intend that this script will run an execute mocha in the same directory. I can execute mocha from the script using:
$testProgram = "mocha"
& $testProgam
I get the results..
...
3 test complete....
Now when I take this same code and wrap it in the event like this...
$changed = Register-ObjectEvent $watcher "Changed" -Action {
clear
write-host "Running Test Scripts.........."
write-host "Changed: $($eventArgs.FullPath)"
& testProgram
}
I get this...
Running Test Scripts.......................
Changed: C:\files\main.js
Where are the results of the & testProgram?

I don't have PS to test this atm, so please correct me if I'm wrong. I can think of multiple problems that you could check out:
You got a typo. In your action block, testProgram is missing a dollar-sign in front.
I'm pretty sure that an ObjectEvent runs the action block in a seperate scope where you can't get the parameters from your script. You could try to use e.g. $global:testProgram.
Relative paths may not work here. You might need absolute path to the "mocha" executable or what it is.
EDIT: I found a solution you can try for the possible scope-problem (reaching the testprogram variable inside your action block). Shay Levi posted this code sample on Technet. It uses the -MessageData parameter to pass input into your action-block. Here's his codesample:
#Use the -MessageData parameter:
Register-ObjectEvent ... -MessageData $foo
#Access the variable from within the action block
$event.MessageData

Related

Powershell - Replace add_Click link on LinkLabel

I am creating a PowerShell GUI that uses a link label. My code for this link is
$ExLinkLabel = New-Object System.Windows.Forms.LinkLabel
$ExLinkLabel.Location = New-Object System.Drawing.Size(15,130)
$ExLinkLabel.Size = New-Object System.Drawing.Size(150,20)
$ExLinkLabel.LinkColor = "BLUE"
$ExLinkLabel.ActiveLinkColor = "RED"
$ExLinkLabel.Text = "Link Example"
$ExLinkLabel.add_Click({[system.Diagnostics.Process]::start("https://google.com")})
$Form.Controls.Add($ExLinkLabel)
Now say I want to change it another website later in the code based on certain conditions, I tried doing this:
$ExLinkLabel.add_Click({[system.Diagnostics.Process]::start("https://yahoo.com")})
The problem that this now has two links open, both google and then yahoo.
Is there a way to clear or just replace that first link with my new one?
Thank you
Adding an event handler with an .add_<EventName>() method call does just that: It adds an additional event handler, of which there can be many.
In order to replace an event handler, you must first remove its old incarnation with .remove_<EventName>(), and then add the new incarnation with .add_<EventName>().
To that end, you must store the original incarnation in a variable that you can later pass to the .remove_EventName>() call:
# Define the original event handler, store it in a variable,
# and add it to the control.
$currEventHandler = { Start-Process https://google.com }
$ExLinkLabel.add_Click($currEventHandler)
# ...
# Remove the current event handler...
$ExLinkLabel.remove_Click($currEventHandler)
# ... and add the new one:
$currEventHandler = { Start-Process https://yahoo.com }
$ExLinkLabel.add_Click($currEventHandler)
Note that I've replaced [system.Diagnostics.Process]::start($url) with a simpler, PowerShell-idiomatic call to the Start-Process cmdlet.
In your simple case, where the two event handlers only differ by the URL they open, consider the alternative recommended by Theo:
Retain the original event handler and make it retrieve the URL to open from a variable defined outside the event handler, namely in the script scope. That way, all you need to do is to update the variable.
# Set the original URL
$url = 'https://google.com'
# Due to PowerShell's dynamic scoping, the event-handler script
# block - even though it runs in a *child* scope - sees the
# script scope's definition of variable $url
# You can make this cross-scope access explicit by using $script:url
# (If you wanted to *update* the variable from inside the child
# scope $script:url *must* be used.)
$ExLinkLabel.add_Click({ Start-Process $url })
# ...
# Update the variable, after which the event handler will
# use the new URL.
$url = 'https://yahoo.com'

How to create collection of scheduler task path in powershell script

I have a powershell script where I have to enable or disable task. In the script following thing I'm doing
read the $TaskPath = '\Microsoft\Windows\PowerShell\ScheduledJobs'
Get-ScheduledTask via $TaskPath
Get-ScheduledJob
Now in my project we have many different schedule task which is present in different path like few present at '\Microsoft\Windows\PowerShell\ScheduledJobs' and some task present at root path like '\printtask'.
Now when I pass the taskname to execute in the script and if that task is not present in the $TaskPath = '\Microsoft\Windows\PowerShell\ScheduledJobs' then it will not execute. To solve this issue I have to add another if condition for setting root path.
Lets say in the future if we have new task with some different path then I have to again add new if condition. To avoid that situation I am looking a way to have collection/list of task paths to check, Then we go through that collection/list and find the scheduled job and execute.
If in the future we need to add new task with other path, we can just add that task path to that collection/list and avoid having additional if statement.
Anyone has any suggestion how I can archive this..?
You can store all the TaskPaths in your initial logic by building an array of objects and add all of your Task Paths in there, somewhat like this:
$TaskPathList = #()
$TaskPathList += New-Object -TypeName PSObject -Property #{TaskPath = $TaskPath1;}
$TaskPathList += New-Object -TypeName PSObject -Property #{TaskPath = $TaskPath2;}
Later on, you can iterate through this collection of TaskPaths to read them do the decision making accordingly:
$TaskPathList | ForEach-Object {
if(<Place your condition to check against $_.TaskPath >)
{
#Do your stuff
}
}

How to make the output in the pipeline appear on the console when running pester tests?

By default, the output in the pipeline is hidden,But sometimes I really want to know the output at that time.
Of course, I knew I could add additional commands, such as write-host or out-default.
But does Pester itself have a mechanism to make the output display properly?
I checked the help document and didn't find the relevant content, so I came here for help.
It is possible to write a custom Should wrapper (proxy) using this technique. The wrapper can write the pipeline objects to the console.
Here is a complete example of such a Should wrapper and how to override Pester's Should.
To apply it to your case, edit the process{} block of the wrapper like this:
process {
try {
# Here $_ is the current pipeline object
Write-Host "Current test case input:`n$( $_ | Out-String )"
# forward it to "process" block of original "Should"
$steppablePipeline.Process( $_ )
} catch {
throw
}
}

Invoke-Pester to only run a single Assert/It block

I am writing unit tests for my Powershell Modules, with a file for each module, and Describe blocks for each function. Context blocks organize the tests along the behavior I am trying to test for with some arrange code, and my It blocks contain minimal arrange/act code and a assert.
I can limit my tests to only run a single test file by using Invoke-Pester "Path/To/Module"
I can also limit based on the Describe blocks by using Invoke-Pester "Path/To/Module" -TestName #("RunThisDescribe","AndRunThisDescribe")
As I am adding a new assertion (via a new It block) to an existing file/Describe/Context, I want to test/debug my new assertion alone, without the rest of the assertions of a given describe/context running (but with any mocks/variables that I set at the describe/context scope still available.
I have been commenting out my existing assertions while I am developing the new one, then remove the block comments and run them all after I am finished with the new test. This works, but is clunky.
Is there a way to run Invoke-Pester to only execute a given list of Its?
Is there a better workflow for developing/debuging new tests other than either letting all of them run or commenting them out?
I know, this question is pretty old, but it deserves an update:
Starting with Pester version 5, you can have a -Tag on everything: Describe, Context, It
This makes it really easy to run specific assertions and nothing else.
You can even exclude specific code with -ExcludeTag.
Please see https://github.com/pester/Pester#tags for details.
Also check out the braking changes, if you plan to migrate from version 4 to 5!
It doesn't look like there's any way to specify tests to run by the name of the It block.
You could split your new test in to a new Describe block and then run it via the -TestName parameter as you described, or give it a -Tag and then specify that tag via Invoke-Pester, however that doesn't seem to work for a nested Describe, it has to be at the top level.
I assume this wouldn't work for you because your Mocks and Variables would be in the other describe.
VSCode with the PowerShell extension installed allows you to run individual Describe blocks via a "Run Tests" link at the top of the Describe and this does work for nested blocks. However i'm not sure if this would result in the Mocks/Variables from the parent Describe block being invoked (my guess would be not).
Example of nested Describe, which can be individually run within VSCode:
Describe 'My-Tests' {
It 'Does something' {
$true | Should -Be $true
}
Describe 'NewTest' {
It 'Does something new' {
$true | Should -Be $true
}
}
}
It's a shame you can't currently put Tags on Context blocks for filtering in/out certain sets of tests. That was requested as a feature 2 years ago but it seems is not simple to implement.
To add to Tofuburger's answer, and based on Pester 5.3.1, you can also manipulate tests programmatically, in your test scripts, based on tags.
Describe 'Colour' -Tag 'Epistemology' {
BeforeAll {
$ParentBlockTags = $____Pester.CurrentBlock.Tag
if ($ParentBlockTags -eq 'Epistemology')
{
Set-ItResult -Inconclusive
}
}
BeforeEach {
$ItTags = $____Pester.CurrentTest.Tag
if ($ItTags -eq 'HSL')
{
Set-ItResult -Skipped -Because 'Not implemented'
}
}
It 'Saturates' -Tag 'HSL' {
1 | Should -Be 2
}
It 'Greens' -Tag 'RGB' {
1 | Should -Be 3
}
}

Getting result of .Net object asynchronous method in powershell

I'm trying to call an async method on a .Net object instantiated in Powershell :
Add-Type -Path 'my.dll'
$myobj = new-object mynamespace.MyObj()
$res = $myobj.MyAsyncMethod("arg").Result
Write-Host "Result : " $res
When executing the script, the shell doesn't seem to wait for MyAsyncMethod().Result and displays nothing, although inspecting the return value indicates it is the correct type (Task<T>). Various other attempts, such as intermediary variables, Wait(), etc. gave no results.
Most of the stuff I found on the web is about asynchronously calling a Powershell script from C#. I want the reverse, but nobody seems to be interested in doing that. Is that even possible and if not, why ?
I know this is a very old thread, but it might be that you were actually getting an error from the async method but it was being swallowed because you were using .Result.
Try using .GetAwaiter().GetResult() instead of .Result and that will cause any exceptions to be bubbled up.
For long running methods, use the PSRunspacedDelegate module, which will enable you to run the task asynchronously:
$task = $myobj.MyAsyncMethod("arg");
$continuation = New-RunspacedDelegate ( [Action[System.Threading.Tasks.Task[object]]] {
param($t)
# do something with $t.Result here
} );
$task.ContinueWith($continuation);
See documentation on GitHub. (Disclaimer: I wrote it).
This works for me.
Add-Type -AssemblyName 'System.Net.Http'
$myobj = new-object System.Net.Http.HttpClient
$res = $myobj.GetStringAsync("https://google.com").Result
Write-Host "Result : " $res
Perhaps check that PowerShell is configured to use .NET 4:
How can I run PowerShell with the .NET 4 runtime?