Scripting Games 2013: Use of SupportsShouldProcess in Functions/Scripts

Edit: I was caught speeding when I put up this post. Move-Item will pick up on SupportsShouldProcess and handle the –Whatif and –Confirm without having to supply the $Pscmdlet.SupportsShouldProcess().  In fact, adding this to a cmdlet that already supports it natively will throw up 2 prompts with –Confirm instead of 1. –WhatIf will only display once.

You should still be mindful of what you are doing with this in the case of cmdlets and other things you are doing which may not have native support for this. Rather than completely re-writing this post, it will stand to show that no one here is perfect and we are learn from one another as well as make mistakes Smile!

While reviewing and voting on the entries for Event 1, I have been seeing some entries where they have the following:

[cmdletbinding(SupportsShouldProcess=$True)]

Ok, great! They are going to implement –WhatIf and –Confirm with their function so the user can take advantage of those parameters. But what I see later is rather disheartening.

Move-Item -Source $Source -Destination $Destination

Ok, this is just an example, but does represent exactly what I see and what you are seeing as well: Nothing has been implemented to support the SupportsShouldProcess attribute that was defined earlier!

Truth be told, it is incredibly simple to implement this into your code. Take a look below:

Function Move-LogFile {
    [cmdletbinding(SupportsShouldProcess)]
    Param (
        $File,
        $Destination
    )
    If ($Pscmdlet.ShouldProcess($File,"Move Item")) {
        Move-Item -Path $File -Destination $Destination
    }
}

Again, very basic function to prove the point of implementing –WhatIf. Just use an If statement with the $Pscmdlet.ShouldProcess() method and supply the ‘Target’ and an ‘Action’ parameter and you have just successfully set up the –WhatIf support.

 Move-LogFile -File "SomeLogFile.log" -Destination "C:\Backup" -WhatIf

image

Very simple to implement and it will save you from being docked points for only having this half done.

Posted in Scripting Games 2013, Tips | Tagged , , , | 5 Comments

What Forums Can I Go To For PowerShell Help?

Maybe you have been working on a script for a while and am just not sure what the next step is or perhaps you are looking for a peer review of something you wrote. Fortunately, there are several forums out there that can provide this help to you.

While this isn’t an exhaustive list if forums, it will hopefully provide you with a place to start. If I am missing something, feel free to add it in the comments below.

Find a forum that suits you and feel free to join in and help your fellow PowerShellers out!

General PowerShell

Technet PowerShell Forums

Technet Hey, Scripting Guy! Forums

StackOverflow Forums (There are multiple tags for PowerShell; this is a generic link via a search for PowerShell)

PowerShell.org Forums

PowerShell.com – Ask The Experts

PowerShell.com Forums

PowerShell-Scripting.com (French)

SpiceWorks PowerShell Forum

Minasi.com

Tek-tips.com

Platform/Technology Specific

Exchange

Minasi.com

PowerShell.org – Exchange

ExchangeServerPro.com

PowerShell.com -Exchange

Workflow

PowerShell.org – Workflow

PowerShell.com – Workflow

General Windows

PowerShell.com – Windows

Remoting

PowerShell.org – Remoting

PowerShell.com – Remoting

WMI/CIM

PowerShell.org – WMI/CIM

PowerShell.com – WMI

 

SQL

PowerShell.org – SQL

PowerShell.com – SQL

 

System Center

PowerShell.org – System Center

 

Forefront

PowerShell.org – Forefront

 

Sharepoint

PowerShell.org – Sharepoint

PowerShell.com – Sharepoint

 

IIS

PowerShell.org – IIS

IIS.net

PowerShell.com – IIS

 

Active Directory

PowerShell.org – Active Directory

PowerShell.com -Active Directory

Lync

PowerShell.org – Lync

PowerShell.com – Lync

Azure

PowerShell.com – Azure

Windows Server Update Services (WSUS)

PowerShell.com – WSUS

Office 365

PowerShell.org – Office 365

PowerShell.com – Office 365

Product Specific Forums

Sapien

Sapien PowerShell Forum

PowerGUI

PowerGUI Forums

Veeam

Veeam.com

PowerCLI

PowerCLI Forum

NetApp Data On Tap

PowerShell Data On Tap Forum

CISCO UCS

PowerShell.org – CISCO UCS

WinForms

Sapien PowerShell GUI Forum

Amazon Web Services

Amazon.com

XenApp 6 Management

Citrix.com

 

Other PowerShell (Things that are not “traditional forums” but great for questions)

Twitter – #PoshHelp

Twitter – #PowerShell

Hey, Scripting Guy! Facebook Group

PowerShell Facebook Group

PowerShell Google+ Community

LinkedIn PowerShell Group

IRC #PowerShell Channel

Reddit/r/PowerShell

 

Posted in News, powershell | Tagged , , | 11 Comments

Sharing Variables and Live Objects Between PowerShell Runspaces

I’ve had requests for a while to talk about sharing data between runspaces and I was also asked about this during my recent interview on the Powerscripting Podcast last week. I admit that I have had this article in a draft status for close to a year now and actually forgot about it. So without further ado, here is my take on how to share variables and live data between runspaces in PowerShell.

I’ve shown in some articles various examples of using runspaces vs. PSJobs in your scripts and functions to achieve better performance and to make your UIs more fluid. What I haven’t really gotten into is another great feature of doing this which is to share your data between those runspaces or inject more data into a currently running runspace.

I would also like to leave a small disclaimer stating that this is an advanced technique and for anyone who is just getting into PowerShell, please do not get concerned if you do not understand what is going on or if it confusing. Just take it one command at a time and you will have it figured out in no time!

Synchronized Collections

The key component to all of this is done via a synchronized (thread safe) collection. There are multiple types of synchronized collections that include a hash table, arraylist, queue, etc… I typically use a synchronized hash table just because it is easier to call the variables or live objects by a name ($hash.name) versus using an arraylist or something similar and filtering for what I need using a Where-Object statement (($array | Where {$_.name –eq ‘Name’}).Value). Of course there may be cases when one might be better than another and in that case, always use the one that will help you out the most.

Creating a synchronized collection is pretty simply. This example will show how to create a synchronized hash table to use.

$hash = [hashtable]::Synchronized(@{})

All I had to do with use the [hashtable] type accelerator with the Synchronized() method and supply an empty hash table. Now I have a hash table that is synchronized and will work across runspaces regardless of the depth of the runspace.

Example of a PSJob with a synchronized hash table

First I want to show an example of using a synchronized hash table with a PSjob and see the outcome of the action.

Write-Host "PSJobs with a synchronized collection" -ForegroundColor Yellow -BackgroundColor Black
$hash = [hashtable]::Synchronized(@{})
$hash.One = 1
Write-host ('Value of $Hash.One before PSjob is {0}' -f $hash.one) -ForegroundColor Green -BackgroundColor Black
Start-Job -Name TestSync -ScriptBlock {
    Param ($hash)
    $hash.One++
} -ArgumentList $hash | Out-Null
Get-Job -Name TestSync | Wait-Job | Out-Null
Write-host ('Value of $Hash.One after PSjob is {0}' -f $hash.one) -ForegroundColor Green -BackgroundColor Black
Get-Job | Remove-Job

image

As expected, after supplying the synchronized hash table to the PSJob via the –ArgumentList parameter, instead of seeing the expected value of 2 from the hash table, it is still only a 1. This is because of rolling another runspace in the background of the current session, a new PowerShell process is spawned and performs the work before returning any data back when using Receive-Job.

Now we will take a look at using a synched hash table with a single runspace and with multiple runspaces using a runspace pool because each of these approaches has a slightly different way of injecting the synched collection into a runspace.

Synchronized hash table with a single runspace

The first thing we are going to do is create the synched hash table and add a value of 1 to it.

$hash = [hashtable]::Synchronized(@{})
$hash.One = 1

Next I am going to create the runspace using the [runspacefactory] accelerator and using the CreateRunspace() method. Before I can add anything into the runspace, it must first be opened using the Open() method.

Write-host ('Value of $Hash.One before background runspace is {0}' -f $hash.one) -ForegroundColor Green -BackgroundColor Black
$runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()

Now comes the moment where we will add the synched hash table into the runspace so that I can be accessed and used. Using the SetVariable() method of the $runspace.sessionstateproxy object, we add the synched hash table. We first give the a name of the variable and then add the actual synched collection.

$runspace.SessionStateProxy.SetVariable('Hash',$hash)

With that done, I then create the PowerShell instance and add my runspace object into it.

$powershell = [powershell]::Create()
$powershell.Runspace = $runspace

Using the AddScript() method, I add the code that will actually happen within my background runspace when it is invoked later on. As I did with my PSJob example, I am only going to increment the hash table by one.

$powershell.AddScript({
    $hash.one++
}) | Out-Null

The Out-Null at the end is used to prevent the output of the object that occurs.

Next, I actually kick off the runspace using BeginInvoke(). It is very important to save the output of this to a variable so you have a way to end the runspace when it has completed, especially when you are expecting to output some sort of object or other types of output. I also use my $handle variable to better track the state of the runspace so I can tell when it has finished.

$handle = $powershell.BeginInvoke()
While (-Not $handle.IsCompleted) {
    Start-Sleep -Milliseconds 100
}

Once the runspace has completed, I then perform the necessary cleanup tasks. Note where I use my $handle variable with EndInvoke() to end the PowerShell instance.

$powershell.EndInvoke($handle)
$runspace.Close()
$powershell.Dispose()

Lastly, we can now see that the value did indeed increment in the runspace.

Write-host ('Value of $Hash.One after background runspace is {0}' -f $hash.one) -ForegroundColor Green -BackgroundColor Black

image

Pretty cool, right?

How about injecting more data or even viewing the state of the synched hash table while it is running? This can easily be done as well with the following example. I set up a loop within my background runspace that will run until I inject a boolean value to stop the loop. But before I do that, I will play with the data inside by seeing the value and then resetting it back to something else.

$hash = [hashtable]::Synchronized(@{})
$hash.value = 1
$hash.Flag = $True
$hash.Host = $host
Write-host ('Value of $Hash.value before background runspace is {0}' -f $hash.value) -ForegroundColor Green -BackgroundColor Black
$runspace = [runspacefactory]::CreateRunspace()
$runspace.Open()
$runspace.SessionStateProxy.SetVariable('Hash',$hash)
$powershell = [powershell]::Create()
$powershell.Runspace = $runspace
$powershell.AddScript({
    While ($hash.Flag) {
        $hash.value++
        $hash.Services = Get-Service
        $hash.host.ui.WriteVerboseLine($hash.value)
        Start-Sleep -Seconds 5
    }
}) | Out-Null
$handle = $powershell.BeginInvoke()

I also added the parent host runspace into the child runspace so I can use the WriteVerboseLine() method to write the values to the parent session. I’ll sleep for 5 seconds to give me some time to inject values and read the values if needed. Also added is a call to Get-Service so I can pull live objects as well.

image

As you can see, the values continue to rise and I can even call $hash.value from my parent runspace to see the value or data. This can even include live objects if needed as seen below.

image

And now I inject some new data into the synched hash table to reset the counter.

image

Ok, enough fun here, time to close down the loop.

image

Don’t worry about the weird placement of the characters above. As long as you continue with the typing and hit return, the command will execute like you want it to.

That is really all with working with a single runspace. You can in fact go many many levels deep with background runspaces and use the same synched collection. The important thing to remember is that you must add the synched collection into each new runspace using the SetVariable() method that I talked about earlier.

Working with a runspace pool

I mentioned that working with synched collections is a little different with runspace pools than with a single runspace and now I will show you why. First I am going to set up my runspace pools with a helper function to handle the runspaces and also a scriptblock that will be added into the runspace pool.

Function Get-RunspaceData {
    [cmdletbinding()]
    param(
        [switch]$Wait
    )
    Do {
        $more = $false         
        Foreach($runspace in $runspaces) {
            If ($runspace.Runspace.isCompleted) {
                $runspace.powershell.EndInvoke($runspace.Runspace)
                $runspace.powershell.dispose()
                $runspace.Runspace = $null
                $runspace.powershell = $null                 
            } ElseIf ($runspace.Runspace -ne $null) {
                $more = $true
            }
        }
        If ($more -AND $PSBoundParameters['Wait']) {
            Start-Sleep -Milliseconds 100
        }   
        #Clean out unused runspace jobs
        $temphash = $runspaces.clone()
        $temphash | Where {
            $_.runspace -eq $Null
        } | ForEach {
            Write-Verbose ("Removing {0}" -f $_.computer)
            $Runspaces.remove($_)
        }  
        [console]::Title = ("Remaining Runspace Jobs: {0}" -f ((@($runspaces | Where {$_.Runspace -ne $Null}).Count)))             
    } while ($more -AND $PSBoundParameters['Wait'])
}
$ScriptBlock = {
    Param ($computer,$hash)
    $hash[$Computer]=([int]$computer*10)
}
$Script:runspaces = New-Object System.Collections.ArrayList   
$Computername = 1,2,3,4,5
$hash = [hashtable]::Synchronized(@{})
$sessionstate = [system.management.automation.runspaces.initialsessionstate]::CreateDefault()
$runspacepool = [runspacefactory]::CreateRunspacePool(1, 10, $sessionstate, $Host)
$runspacepool.Open() 

I only created an empty synched hash table because I will be adding data into it for each runspace in the runspace pool. With the runspace pool, I set the max concurrent runspaces running to 10 which will easily handle the 5 items that I want to add for each runspace.

Now I will iterate through each of the items and add them into the runspace pool.

ForEach ($Computer in $Computername) {
    #Create the powershell instance and supply the scriptblock with the other parameters 
    $powershell = [powershell]::Create().AddScript($scriptBlock).AddArgument($computer).AddArgument($hash)
           
    #Add the runspace into the powershell instance
    $powershell.RunspacePool = $runspacepool
           
    #Create a temporary collection for each runspace
    $temp = "" | Select-Object PowerShell,Runspace,Computer
    $Temp.Computer = $Computer
    $temp.PowerShell = $powershell
           
    #Save the handle output when calling BeginInvoke() that will be used later to end the runspace
    $temp.Runspace = $powershell.BeginInvoke()
    Write-Verbose ("Adding {0} collection" -f $temp.Computer)
    $runspaces.Add($temp) | Out-Null               
}

 

As you can see, I use the AddArgument() parameter to add the synched hash table into the runspace. This works hand in hand with the Param() statement that I had in the scriptblock that was also added into the PowerShell instance using AddScript().

Calling the $hash.GetEnumerator() to show all of the values, we can see that I can view all of the data of each runspace (if it has written data to it yet).

$hash.GetEnumerator()

image

As expected again, I see the values from each runspace in the pool. Now I need to clean up after myself using my helper function.

Get-RunspaceData -Wait 

Just like my other examples using the single runspace, I could inject values into the synched collection and monitor the synched collection. These are all simple examples that I have shown you but hopefully it is enough to take what I have shown you and expand out with more complex scripts/functions.

As always, I am interested to hear your thoughts and also any examples of what you have done using some of my techniques/examples that have been presented here.

Posted in powershell | Tagged , , , | 13 Comments

The 2013 Scripting Games Are Coming!

SG_Judge

The 2013 Scripting Games are coming up very quickly (April 25nd, to be exact) and things are a little different than last year. This year the competition is being hosted by PowerShell.org instead of by Microsoft\Hey, Scripting Guy! and the scripts will be uploaded to a different site instead of poshcode.org.

The judging has also changed to be more community minded versus just the judges voting on what we believe is the best script. The judges still decide what we think are the best and worst scripts in each category and are now going to blog about said scripts to say what we felt could have changed or why this was the top script in our own opinion. Lastly, there are a panel of celebrity judges who will take our picks and make a decisive pick for 1st, 2nd and 3rd place overall.

Instead of 10 events to work through in a 2 week timespan, there will be only 6 events with a week to write the script followed by another week to allow the community to vote on the scripts.

As mentioned earlier, I am a judge again this year (my second year doing so) and definitely look forward to seeing what everyone does during this years competition!

Check out the Schedule of events here:

http://powershell.org/wp/2013/04/03/2013-scripting-games-schedule/

Check out the judges here:

http://powershell.org/wp/2013/04/06/2013-scripting-games-judges/

Check out the celebrity judges here:

http://powershell.org/wp/2013/04/06/2013-scripting-games-mighty-panel-of-celebrity-judges/

Scripting Games Competitors Guide

http://powershell.org/games/2013CompetitorGuide.pdf

Good luck to all of the competitors!

Posted in 2013 Scripting Games Judges Notes, News, powershell, Scripting Games 2013 | Tagged , | Leave a comment

Guest Article on Hey, Scripting Guy! Talking WSUS on Server 2012

I have a guest article that is out today talking about installing WSUS on Windows Server 2012. There will be at least one more article coming from Hey,Scripting Guy! talking about WSUS on Server 2012 and the new UpdateServices module that comes with it to manage the WSUS server coming sometime. Until then, check out my article and let me know what you think!

http://blogs.technet.com/b/heyscriptingguy/archive/2013/04/15/installing-wsus-on-windows-server-2012.aspx

Posted in News, powershell | Tagged , , | Leave a comment