Thursday, May 31, 2012

Alternate to Jobs via a Batch and a Wait-Job to manage them.

We have a series of retrieve process that run each morning.  Most of these can run Async, but I have had two problems with using Jobs to accomplish this.

  1. If we pass simple variables to the job we have to make a DB call to get the full record and Dot Includes to the functions we have don't seem to want to work. 
  2. If we gather the details and populate the class to pass along we get serialization issues.
We should be able to resolve both items in the long run. In the short term however we have a batch file that runs multiple powershell.exe using "Start" to let them run async.  This is running on a server and the the some of the PowerShell scripts need to launch and interact with GUI applications.  So we have a scheduled job that calls Sysinternals psExec.exe to launch and RDC session off the console on the server.  Now I realize this sounds horrible to someone that doesn't work with me.  But this process creates a clean environment for the retrieves to work in.

Once the process is over the batch needs to log-out to release the session.  Simply waiting for the process to close doesn't seem to always cut it for us on 2003 Server.  But if Start has each one running on its own, we need to know when those are done.  So before we can call the ShutDown.exe logout command, we need to test that every powerShell session is closed.  And we need to make sure that only the sessions in this RDC are being checked.  It is helpful to mention that the server has 5 or 6 interactive users RDC in at times.


#$SessionID = Get-Process | Where-Object { $_.ID -eq $pid } | Select -expandproperty SessionID # 24 MilliSeconds
$SessionID = [System.Diagnostics.Process]::GetCurrentProcess() |
            Select -expandproperty SessionID# 15 MilliSeconds
    Sleep -seconds 30
    $ActivePSEXE = Get-process PowerShell |
        Where {$_.SessionID -eq $SessionID -and $_.ID -ne $pid}
While ($ActivePSEXE)

Will asked why not use a threading approach, but these scripts load some generated code that has overlapping namespaces and they would fail to load if called from the same appdomain. (9:17a CT)

Monday, May 7, 2012

Table of an array

I had a a PSObject with to fields [bool]"Done" and [string]"Name".  To signify the status of some production items.
I need these results to be human readable and not print pages of data.
I don't propose that this is the best solution, but this is what I came up with as a quick solution.

This forces each name to a 20 character column and puts for columns on the page at once.

$data2 | Group {$_.Done} | %{
            $ColumnCount = 4
            $Count = $_.Group.Count
            For  ($index = 0$index -le $Count;$index+=$ColumnCount)
              For ($i=0;$i -lt $columnCount;$i++)
                if ($index+$i -lt $Count) {
                    Write-host $_.Group[$index+$i].Name.Padleft(20-NoNewline              

Try number 2 breaks out the old modulus function.  I asked Will if he had an answer and did a quick "Is this what you mean?" using a 1..11 array.  Seeing the array as numbers modulus was the clear grouping method.

$data2 | Group {$_.Done} | %{
            Write-host $_.Name
            $ColumnCount = 6           
            For  ($index = 0$index -lt $_.Group.Count;$index++)
              Write-host $_.Group[$index].Name.Padleft(20-NoNewline               
              if ($index $ColumnCount -eq 0) { Write-host }

I also considered, and I may yet revise my solution, creating a PSObject with 4 members and assign them in a similar fashion.  This would allow me to ConvertTo-CSV, and use the normal Format-Table.