Splatting the ScriptBlock

After making ScriptBlock work in a splat I just had to tinker.  I had implemented it in a production script and it worked very well.  With the usual need to tinker but more importantly to revive all of the logging I wanted to find a way to include the several lines I had in the script I was previously using for the start-job.

Using a generic script to do generic tasks I started to experiment.  First was to string a few commands each separated with the semi-colon (;) which worked well but in this case would comprise of a very long line of text, defeating a huge purpose of my goal to use splatting.  Here-String had to be the answer, but how do I get that to work.  Doing some research I came across the ScriptBlock class which includes a Create method.  I then looked around the community and this seemed like an approach that would work.

$sample = @”
write-Host ‘Test’ -ForegroundColor Green
(gwmi win32_operatingsystem).Caption
write-Host ‘Completed’ -foregroundcolor Red
“@
$sb = [scriptblock]::Create($sample)
$jobdat=@{
ScriptBlock = $sb
}
invoke-Command @jobdat

So I built the here string as my sample variable, then stored it as a script block within a new variable named sb.  I included that in my splatted list of command arguments and no errors and it executed as I expected.  Now to take this simple example and apply it to my production code.

Thanks to mjolinor – “The Powershell Workbench” and Steve Murawski – “Use Powershell” for some great help.

Async Copy Splat

It’s been quite some time since I last posted here.  A few things derailed my Powershell activity but with a new job I am back to learning Powershell. 

So there was an ongoing project for the WindowsXP to Windows7 migration company wide.  As I understand it the project was behind schedule and the push to get the project underway was pressing.  I was approached to write a script to address an issue that the use of USMT just wasn’t working or adequate.  The request was easy enough and I drafted the code.  Before it was even tested there was one of those “could you add”, after a few more of those I really wanted to re-work the whole thing but it was time to perform pilot testing so a re-work really wasn’t going to be well received.

Part of the migration is to also change the location and naming for the user “HomeDirectory” so data would have to be moved, or at least copied.  I chose a copy just to be safe as their original contents would still be in place until the user was able to login and verify, less headaches.

Well now the issue was how to facilitate up to 50 user updates and the coinciding data copies. Certainly “start-job” could be used so that I can process a user, start the file copy and go to the next user while, not after, the previous file copy was processed.  So I put together the code but noticed that the background jobs would be destroyed as soon as the script completed.  At first I thought maybe it was an issue with running it as a scheduled task or maybe I needed to start Powershell with –STA.

So using a simple local test on my home network I started to experiment.

 function copy-userdata {
Param(
	[string]$srcpath,
	[string]$destpath
)
"Starting backup of $srcpath to $destpath"
$jobdat = @{
    'Name' = "test"
    'ArgumentList' = $srcpath,$destpath
    'ScriptBlock' = {copy-Item -Path $args[0] -Destination $args[1] -Recurse -Force -ea 'SilentlyContinue' -Container}
}
start-Job @jobdat  
}
# Just cleaning up jobs leftover from previous test
get-Job | remove-job
copy-userdata "c:\Users\jkavanagh58" "\\jkav-homerig\public\Backup\test" 
# Wait for all jobs to complete
get-job | wait-Job 


Again the above code is just my test copy, but became the working model.  What seemed to be the issue was instead of worrying about making the get-job specific, I could just call it and pipe that to wait-job (get-job | wait-job).  So for the working copy during my ForEach statement it does the set-qaduser functions, starts the file copy job in the background and moves to the next user, when the ForEach loop is complete get-job | wait-job holds the script until the last job is completed.

Now I have to admit my first attempts to use start-job I was calling another script, but thought it would make things easier when (if) someone else looks at the code if it was a function in the same script.  Hmmmm how about if we splat the start-job, that should be easy.  Not as easy as I thought, at least not the ScriptBlock parameter.  So I got it to work with start-job @jobdat –ScriptBlock { <code>} but there had to be a way.  I found this post and now the whole start-job is splatted.

Nothing advanced here, was just fun to get back into some practical powershell.