Tome's Land of IT

IT Notes from the Powertoe – Tome Tanasovski

Look back at 2014 and look forward to 2015

A look back at 2014

2014 was the year of containers for me.  I spent a lot of time looking at Docker, Kubernetes, Mesos with Marathon and Aurora, and working (and using) tooling around the core Linux Kernel components that make these platforms possible.

shipping2

Additionally, this was the year that I fully embraced and understood Apache Zookeeper and played with etcd.  For me, Zookeeper becomes the foundation of nearly any distributed system I write.  It’s easy and it works.  Etcd has a place when zookeeper is overkill, but I have yet to use it in anything real.

Elasticsearch – I finally got dirty with elasticsearch.  I have a lot of positive things to say about it.  I’m interested in seeing how far the software can be taken.  Specifically to see whether the datastore (that can now be backed up) will become an actual data tier rather than just an efficient layer on top of a data tier.

In the Perl world, I learned Moose which make Perl actually usable in modern day programming.  It provides objects and types to Perl.

I was really happy to have the opportunity to implement ZeroMQ into something I was working on.  I am really excited by this library and I hope 2015 gives me a chance to write something about PowerShell and ZeroMQ.  There are very few platform and language agnostic libraries out there.  Additionally, the perfect abstraction with robust patterns and documentation make it a lot of fun to tinker with new communication topologies with just a few minor changes to code.  I have not been so inspired or zealously passionate about something like this since PowerShell 2.0 took my brain.

I played with AngularJS a bit.  It was fun.  However, every time I sit down to do UI work, I feel defeated.  It’s just something I’m not amazing at nor do I think I really want to be.  I’m glad to understand the framework and how it works, but I’ll save the meaty part of that work for others.

Pester Pester Pester!!! Test-driven development took over my PowerShell life (as well as all other languages).  My coding takes longer, but I have much more faith in it.  Pester is the greatest thing to happen to PowerShell from the community ever!  I was really happy to work with my internal corporate teams to build SDLC best-practices for PowerShell that involve Continous Integration (CI) and a Pester as the testing framework.

In 2014 I was introduced by my mentor to some time management techniques outlined in Eat that Frog.  Basically it’s about turning your life into Agile.  That sounds strange and the book doesn’t mention agile once – it is my interpretation of it.  It’s really about prioritizing daily and choosing the items that are most impactful to your company and yourself while deprioritizing everything else.  Additionally, I have adopted the more and more common practice of ignoring most e-mails and checking them less frequently throughout the day.  If it’s important, they will get back to you in a way that you cannot ignore.  Otherwise, it’s just getting in the way of the things you prioritized for the day.  If you start to follow this advice, I would add that you should also set up some alerts to ensure that certain people are never ignored.

An unhealthy obsession with gaming returned to my life in 2014.  However, I was successful in squashing it at the end of 2014 – well all of it except for the updates to candy crush I have to do when a new level comes out :)  Hopefully the squash will return some valuable time I need in order to blog a bit more and round myself in the wee hours of the night.

The 2015 Hitlist

New-Year-Baby-2

Golang

Use golang in an actual project.  I really like golang.  It feels like an interpretive language (PowerShell, Python, Perl), but it is compiled and has the potential to automagically make things more efficient as the engine matures.  I have played with golang a bit, but I want to find a project to use it with that will prove/disprove my initial thoughts about the language.

Openstack

Learn Openstack.  I’m sick of being in conversations where I cannot speak with authority about what open stack can and can’t do.  I need to understand all of the components and how they work.  This is pure lab time that I should have done last year.

Public cloud

Re-evaluate the cloud providers.  It’s been about two years since I last looked at AWS and Azure.  I’d like to get a handle on the current offerings and take a closer look at the Google compute engine stuff.

PowerShell Talks and Blogs

Put some new talks together about PowerShell 5.0 and the ZeroMQ library.  Perhaps finally blog or do a talk about the heuristic and deterministic algorithm implementations I have done with PowerShell.

Publish my unpublished article around running a PowerShell script as any user in AD without credentials :) (it’s possible, but requires a configuration you will likely never want to do – but hey, from a research perspective, it’s fun to try).

Podcast

Revisit the cmdlet of the day podcast (no link because the storage is currently not working).  Of all of the things I have ever been involved with, this is the one that I get the most positive feedback from.  I have been thinking it would be fun to kick off the year giving 5-minute discussions about enterprise scripting best practices. There’s so much potential in the short-form podcast format for something highly technical.  I’d love to do this right and perhaps inspire others to pick up the torch in similar technologies that I could benefit from listening to.

The 2015 Watchlist

baby-with-glasses

 

PowerShell

PowerShell as a development language – I still firmly believe that PowerShell is one of the best languages ever written.  In my opinion it is a better interpreted development language than Python and Perl.  I would love to see it used the way it should be.  This is probably a losing battle as Microsoft’s focus is on making it feel like a development language strictly to get providers written for DSC, but I constantly hold my breath waiting for something more.  My hope is that the open sourcing of .NET along with the new language mode in 5.0 may open that door a bit more.  However, my face is slowly turning blue and I may not see the sweet release of air any time soon.  Additionally, I just don’t work on anything that would allow me to prove this outside of little pet projects here and there.  I suppose this is more of a crylist entry than a watchlist entry.

Microsoft open source

.NET being open sourced.  What does it mean?  What’s going to happen with it next?

Windows containers

Containers on Windows – What in the world does it all mean?  How will it manifest to IT shops, and how can I exploit it for the benefit of cheap, secure, and flexible compute where I work?

Checkpoint/Restore

In early 2013, I ran a successfull POC that leveraged CRIU to migrate an app including all of its state from one Linux server to another and have it start running again as if nothing happened.  Why is this not being exploited or am I missing projects that are leveraging it?  Either way, it’s still the most cutting-edge bit of magic out there.  I can’t wait to see where it goes.

Happy New Year!

Announcing PshOdata – Cmdlets that make Odata easy

I’m sitting in the PowerShell summit and just left the stage where I presented how the Odata extensions work and shared my new project (contributors welcome) to bring PowerShell-driven Odata endpoints to the masses

To make it clear just how easy it is to use, here is the code required to create a web service around get-process and stop-process.

$class = New-PshOdataClass Process -PK ID -Properties 'Name','ID'
$class |Set-PshOdataMethod -verb get -cmdlet get-process -Params Name, ID -FilterParams Name
$class |Set-PshOdataMethod -verb delete -cmdlet stop-process -FilterParams ID
$class |New-PshOdataEndpoint

This will generate three files in a folder called odata that can be copied up to your IIS server. After an IISReset, the Process endpoint will be available via the following URLs:

I hope you enjoy, and please post issues on GitHub if you encounter any.

Github Project

You Know PowerShell is an Object-Oriented Language, Right?

I was recently reading an article that I’ll refrain from linking to for fear of a flame war. It infuriated me because it referred to PowerShell as a procedural/functional language that is antiquated and more like shell scripting.  I reflected on this for a while and I came to the realization that if I were to look at 99.99999% of the code out there I may think the same thing.  I also realized that there are reasons that PowerShell code appears procedural instead of object oriented.

This post will do a few things

  1. Show you how to do object-oriented programming with PowerShell using a traditional approach
  2. Show you the alternative (still object-based) so you can see why it’s generally used

A Class

Let’s describe a dog.

Properties

A dog has a name, color, and is some size.

$dogclass = new-object psobject -Property @{
   color = $null
   name = $null
   size = $null
}

A Constructor

While it may not be needed because you can instantiate the object without doing so (via psobject.copy()), object-oriented developers love their constructors. It’s also a good place to add some validation for your class. For example, in the below constructor we’ll restrict the size to either small, medium, or large.

function DogClass {
    param(
          [Parameter(Mandatory=$true)]
          [String]$name,
          [Parameter(Mandatory=$false)]
          [string]$color,
          [Parameter(Mandatory=$false)]
          [ValidateSet('Small','Medium','Large')]
          [String]$size
    )
    $dog = $DogClass.psobject.copy()
    $dog.name = $name
    $dog.color = $color
    $dog.size = $size
    $dog
}

Now you can start using your class

08:31:50 PS C:\> $lucy = DogClass -name Lucy -color brown -size large
08:45:07 PS C:\> $lucy

color                                       name                                        size
-----                                       ----                                        ----
brown                                       Lucy                                        large


A Method

A dog performs certain functions. For example, a dog is known to pee. We can modify our dog class with a method by using Add-Member. Also note that you can use the $this special variable to access the object that is invoking the method.

$DogClass |Add-Member -MemberType ScriptMethod -Name "Pee" -Value {
    "A warm refreshing pee trickles out of {0}" -f $this.name
}

With the method created, you can instantiate Lucy again from the modified class and access her new method.

08:50:50 PS C:\> $lucy = DogClass -name Lucy -color brown -size large
08:52:30 PS C:\> $lucy.Pee()
A warm refreshing pee trickles out of Lucy

Accessor Functions

Accessor functions help you protect the properties of an object. As in Perl and Python, there is no real protected or private property available to you. Therefore, you can use the same convention that these other languages use to supply an underscore prefix to any private methods or properties. It doesn’t actually prevent people from using it, but it’s a clear sign that they shouldn’t use it. For example, if we wanted to make the size property private, we would modify the class to look like this. Note: I’m adding the scriptmethod we created in one step using the -PassThru parameter of Add-Member.

$DogClass = new-object psobject -Property @{
   color = $null
   name = $null
   _size = $null
} |Add-Member -PassThru -MemberType ScriptMethod -Name "Pee" -Value {
    "A warm refreshing pee trickles out of {0}" -f $this.name
}

ScriptMethod

With the new _size property, it’s easy enough to modify our constructor to use the new property, but what if you want to control how people set or get the property of size. You can create an accessor function to do this. Basically, this is just a method that will set or return the data from _size.

$dogclass |Add-Member -PassThru -MemberType ScriptMethod -Name Size -Value {
    param(
        [Parameter(Mandatory=$false, Position=0)]
        $Size
    )
    if ($size) {
        $this._size = $size
    } else {
        $this._size
    }
}

Now, we can access the data in _size by using the accessor.

$lucy = DogClass -name Lucy -color brown -size large
"The dog is {0}" -f $lucy.Size()

We can also set the _size using the same function.

$lucy.Size('medium')

It’s important to note that I lost the property validator I have in the constructor. ScriptMethods break if you have an optional parameter that also has a validator. There are two ways to handle this. Either you add validation to the Size() method or you create two accessor functions, SetSize() and GetSize(). Both are acceptable and both are very easy to implement. Here’s an example of implementing your own validatior

ScriptProperty

A nice way to allow access to the pseudo private properties is to use the ScriptProperty member instead. This provides you with a way to perform a scripted action for a get, but it also allows you to do validation on a set. The difference is that it allows you to use the equal sign instead of a method to set the property.

Here’s what a ScriptProperty looks like. The first ScriptBlock is the get function and the second ScriptBlock is the set function.

$dogclass |Add-Member -MemberType ScriptProperty -name Size -Force -Value {
    $this._size
} {
    param(
        $Size
    )
    if (@('small','medium','large') -contains $size) {
        $this._size = $size
    } else {
        throw "This is not a valid size.  A size must be small, medium, or large"
    }
}

I’m using Force above to override the Size member I already created. In order to use the new property

In order to use this property, I can now do the following with my instantiated instance of Lucy.

PS C:\> $lucy.Size = 'blah'
Exception setting "Size": "This is not a valid size.  A size must be small, medium, or large"
At line:1 char:1
+ $lucy.Size = 'blah'
+ ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], SetValueInvocationException
    + FullyQualifiedErrorId : ScriptSetValueRuntimeException

PS C:\> $lucy.Size = 'medium'
PS C:\> $lucy.Size
medium

A nice thing about this technique is that your custom formatters will be able to see the property. In other words, it can be used in Select, Format-Table, Format-List, etc.

Class Inheritance

PowerShell doesn’t have real inheritance. However, the functionality of inheritance is very easily achieved. If you’re not familiar with inheritance, it’s pretty straightforward. Many times a class will have subclasses. For instance, a Scottish Terrier is a subclass of dog that is always small, black, and prefers to chase rats (rather than hunt like a beagle or keep your feet warm like a pug). Therefore, we can create a Scotty class that is based on the dog class, but has these properties set by default and has a method for hunting vermin.

Inherited Class

Because the definition of our class is simply an object, we can copy and modify it to create a new class that can be used later by other things.

$ScottyClass = $DogClass.psobject.copy()
$ScottyClass.color = 'black'
$ScottyClass._size = 'small'

One thing to note when creating an inherited class in PowerShell using this technique is that you need to recreate your constructors. This is probably the only unfortunate part of the pseudo-class inheritance that PowerShell offers. It basically forces override whether you want it or not on the constructor.

function New-Scotty {
    param(
          [Parameter(Mandatory=$true)]
          [String]$name
    )
    $dog = $ScottyClass.psobject.copy()
    $dog.name = $name
    $dog
}

Now we can use our new class:

$George = New-Scotty George

Overriding Methods

In the case of the Scotty class where we want to add a new method for catching rats, there’s nothing special that needs to be done. New methods are treated the same as on the base class. However, if you want to override a method that exists on the parent class, the technique is identical, but you’ll need to supply the force parameter to Add-Member. For example, if we want to override the Pee() method for the dog, we could do the following.

$ScottyClass|Add-Member -Force -MemberType ScriptMethod -Name "Pee" -Value {
    "The Scotty sniffs the tree.  A warm refreshing pee trickles out of {0}" -f $this.name
}

Note about PIA 2.0

Bruce Payette has a great set of code in PowerShell in Action 2.0 about extending PowerShell to wrap the OO-ability of the language in something that looks cleaner. The end result is you can define a class like this:

DogClass {
    property name 
    property size
    method Pee { "Oh yeah"}
}
$dog = new DogClass

While doing research for this post, I realized that I had never noticed this section of the book. We really need to make this a publicly available extension. It’s pretty simple to do, but I don’t want to paste his code due to copyright reasons. Actually, if you’re the kind of person who has been looking for OO in PowerShell and have never read Bruce’s book, you probably should because it will answer a whole lot more about PowerShell than just this for you.

Objects from New-Module

The PowerShell team added a shortcut way to do all of the above. Modules exist in their own closure. Because of this, they may contain their own scoped variables that can be stored within the module itself. There is a parameter on New-Module called -AsCustomObject that will convert your defined scriptblock module into a PowerShell object with note properties and script methods. Here’s an example of the Dog class using this technique.

function New-Dog {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Name,
        [Parameter(Mandatory=$false)]
        [ValidateSet('small', 'medium','large', $null)]
        [string]$size,
        [Parameter(Mandatory=$false)]
        [string]$color
    )
    New-Module -Argumentlist @($name,$size,$color) -AsCustomObject {
        param(
            [Parameter(Mandatory=$true)]
            [string]$Name,
            [Parameter(Mandatory=$false)]
            [ValidateSet('small', 'medium','large', $null)]
            [string]$size,
            [Parameter(Mandatory=$false)]
            [string]$color
        )
        function Pee {
            "A warm refreshing pee trickles out of {0}" -f $Name
        }
        Export-ModuleMember -Function Pee -Variable Name, Size, Color
    }
}

If we look at the members that this creates, you’ll see it looks very similar to what we’ve been doing up until now.

$Lucy = New-Dog -Name Lucy
$Lucy |Get-Member

   TypeName: System.Management.Automation.PSCustomObject

Name        MemberType   Definition
----        ----------   ----------
Equals      Method       bool Equals(System.Object obj)
GetHashCode Method       int GetHashCode()
GetType     Method       type GetType()
ToString    Method       string ToString()
color       NoteProperty System.String color=
Name        NoteProperty System.String Name=blah
size        NoteProperty System.String size=
Pee         ScriptMethod System.Object Pee();

The PowerShell Way

So what we’ve been looking at is modern object oriented programming. However, it’s rarely seen in the wild with PowerShell even though it’s very simple to implement. Why is that exactly? Sure, there are plenty of beginners out there who weren’t even developers until now, but I believe it’s deeper than that. I personally know that this exists. However, I’ve only used it on one project.

The reality is that PowerShell lives and breaths objects through everything. Also, these objects are very flexible because they can be extended or modified on the fly. Functions can take objects as input and the type of Input provided by strongly typed objects can more easily be achieved with strongly type parameters. I see the param() block of a function as something that describes the properties of an object that I expect to see.

Now this is PowerShell to me. This is a paradigm shift in the way we do object-oriented programming. To me, when my peers ask me why I’m so PowerShell crazy, this is the answer. It looks like it’s functional, but it is far from that.

function New-Dog {
    param(
        [Parameter(Mandatory=$true)]
        [string]$Name,
        [Parameter(Mandatory=$false)]
        [ValidateSet('small', 'medium','large', $null)]
        [string]$size,
        [Parameter(Mandatory=$false)]
        [string]$color
    )
    New-Object psobject -property @{
        Name = $Name
        Size = $Size
        Color = $color
    }
}

function Invoke-Pee {
    param(
        [Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
        [String]$Name
    )
    PROCESS {
        "A warm refreshing pee trickles out of {0}" -f $Name
    }
}

New-Dog -Name Lucy |Invoke-Pee
A warm refreshing pee trickles out of Lucy

Not only do I have a dog that can pee, but I also can use the same Invoke-Pee function for anything that has a name property. It can also invoke-pee on a number of dogs without having to create a loop.  If I really needed to be sure it was a dog, I could take the entire psobject as a parameter and validate that it had the properties that make it a dog.  Perhaps even write the Test-Dog function to do that.

Finally, I would personally wrap the above in a module named Dog and use a prefix more like New-Dog and Invoke-DogPee. Then it’s easy to import the module and inspect what methods are available using Get-Command -Module Dog. Again, this looks and smells like it’s functional, but it’s all objects and encapsulation, and it’s amazing!

Powerbits #10 – history |grep or hgrep in PowerShell

I’ve been working a bit more in Linux. Besides it inspiring me to write a lexical parser in python for PowerShell (don’t get your hopes up – it’s too much work, and I can’t do it), I keep getting little inspirations for cool projects. For example, someone needs to create tmux for PowerShell; I digress. This powerbit is from that inspiration. Recently, my laptop’s up and down arrows stopped working. Because of this, I have been relying on history |grep something in Linux so that I can quickly copy and paste that something back into the commandline. Context Swtich! Yesterday I was in PowerShell, and I got frustrated by the output of get-history (I really only want the commandline property) and the complexity it takes to filter for what I want using Where-Object.   As I was discussing this with a colleague, I said, let me just wrap this already and never worry about it again. So here it is, hgrep:

function hgrep {
    param(
        [Parameter(Mandatory=$false, Position=0)]
        [string]$Regex,
        [Parameter(Mandatory=$false)]
        [switch]$Full
    )
    $commands = get-history |?{$_.commandline -match $regex}
    if ($full) {
        $commands |ft *
    }
    else {
        foreach ($command in ($commands |select -ExpandProperty commandline)) {
            # This ensures that only the first line is shown of a multiline command
            if ($command -match '\r\n') {
                ($command -split '\r\n')[0] + " ..."
            }
            else {
                $command
            }
        }
    }
}

you can use it like this:

hgrep something

While, it’s bad practice to add the |ft command to the function, I find it useful so that I can use the -full switch to get everything I want in the format I want to see it:

11:17:22 PS D:\Dropbox\scripts> hgrep longfunction -full

   Id CommandLine                  ExecutionStatus StartExecutionTime              EndExecutionTime               
   -- -----------                  --------------- ------------------              ----------------               
   9 longfunction                        Completed 9/26/2013 11:00:00 AM           9/26/2013 11:14:41 AM

You can fork or clone this gist off of github here, or just run the following:

git clone https://gist.github.com/6715170.git

Learning a New Language – Perl, Python, and PowerShell – Part I – Executing a System Command

I have been doing development in some form or another for a long time. I learned Perl around 1997. I toyed with Basic and Pascal in high school and college, but it was nothing serious. Since that time, I have been fluent with C++, Perl, C#, and PowerShell while toying with languages like Javascript, Java, and a handful of others. Most recently I’ve tasked myself with learning Python for some new Linux scripts I have to write for work. When sitting down to learn a new language, I realize that there are topics that you must learn that go beyond the core syntax in order to feel comfortable tackling a development task (especially if you are more of an IT Pro than a developer). There are plenty of books and tutorials that can teach you the syntax of a language, but that’s really only the tip of the iceberg. I believe that these are very basic recipes that you need to learn about and store in your utility belt as quickly as possible in order to become efficient with a language.

Because, I’m seriously learning Python now, I thought I would document this as I go. And hey, since most people come to my blog to learn PowerShell and since I happen to know most of this stuff in Perl, I’ll explain how to do it in all three languages. I think it will also give people a fair assessment of the strengths, weaknesses, and overall quirks in the languages to help us have a more informed discussion about language in the wild. So without further ado, Part I of learning a new programming language.

Learning a New Programming Language – Perl, Python, and PowerShell – Part I – Executing a System Command

Generally the libraries that come with most languages these days can do everything you could ever dream of, but there are often occasions when the libraries fall short of a native command in Linux or Windows or there is a binary that does something better than you could ever code. For example, to rewrite robocopy.exe or rsync in any language is a waste of time. No offense intended to those who are writing libraries that duplicate their functionality – if they are robust and do what I need, I’ll be happy to use them :)

The following will break down the different ways to call external commands in each language while trying to satisfy the following three separate use cases that I generally have for system commands, i.e., execute and wait to get the exit code, execute and continue, execute and retrieve the output so that the text from STDOUT can be parsed or stored for later use. If you are not familiar with the term STDOUT it stands for standard output; this is the normal text output from a non-windowed command.

For the sake of this article, I am assuming that we are talking about external commands within a Windows operating system.

Perl

Perl has a few ways that you can interact with the system depending on what you expect to do with the external command. When it comes to simplicity, Perl gets it right.

Execute and wait to get the exit code – System

The following will run an ipconfig command and return an exit code to Perl:

$Exitcode = System("ipconfig");

If you want to suppress the output since you only care about the return code, you can redirect the command to NULL:

$Exitcode = System("iconfig >nul");

Execute and continue – Exec

Exec executes an external command and continues. You receive no indication about how the command ran.

Exec("robocopy d:\\folder1 d:\\folder2");

Again, if you want to suppress the output, you can redirect to NULL:

Exec("robocopy d:\\folder1 d:\\folder2 >nul");

Execute and retrieve the output – Backticks

If you want to capture the output of the command, you need to use backticks. For example, the following will populate the $ipinfo variable with the returned output from ipconfig. The print will display it to the screen.

$ipinfo = `ipconfig`;
Print $ipinfo;

PowerShell

PowerShell has many ways to launch system commands as well, but it’s mainly due to the fact that system commands can be run natively in PowerShell. Just type an executable and it will run. Because of this, you can spawn a background PowerShell job with start-job or execute a command on a remote computer with invoke-command. Mind you, I’m not showing all of the ways that you can execute a command, only the ways that I personally use over and over.

Execute and continue – Start-Process

Start-Process is very versatile. I personally like to use the alias start whenever I use this cmdlet. If you want to launch a command and not wait for the output, you can do the following:

start ipconfig

However, if you want to launch a command with command line arguments, you’ll need to use the ArgumentList parameter. This can be feel a bit awkward, but it’s not difficult. The following illustrates how to use robocopy with arguments in Start-Process:

start robocopy -ArgumentList 'D:\Folder1', 'D:\Folder2'

Execute and wait to get the exit code – -Wait & .Exitcode

You can wait for a command to finish by using the -Wait parameter

start robocopy -ArgumentList 'D:\Folder1', 'D:\Folder2' -Wait

There is also a passthru command that will give you the process object for the process you are starting. Here is my personal technique for getting the exitcode (yes, there is more than one way to get exit codes, this is just my preferred method):

(start ipconfig -wait -passthru).exitcode

Execute and retrieve the output

Generally if I need to parse the return text from a command I’ll just execute the command inline. For example to set the variable $ipconfig to the output of ipconfig.exe, you can do the following:

$ipconfig = ipconfig

In the above, $ipconfig is actually a collection of strings. Each line of the output is an element in the collection. If you expect it to return a single string, you’ll need to join the elements together with “`r`n”.

$ipconfig = $ipconfig -join "`r`n"

Finally, if you need to use spaces in your command, you’ll need to use the call operator (&). It won’t hurt anything to use the following for all of the commands you need from STDOUT, but just remember that it takes a collection of strings. For example, the following will work (note that d:\folder1 isn’t quoted, but it still works because it will attempt to convert anything it sees into a string):

& 'c:\path with spaces\robocopy.exe' d:\folder1 'd:\folder2'

However, this will fail:

& 'c:\path with spaces\robocopy.exe d:\folder1 d:\folder2'

To do the above, you would need to use Invoke-Expression, but I very rarely use that function as it is considered bad practice. The honest truth is that I care very little about injection attacks in most of my code. If I did care, I’m sure this article would be littered with it for discussion with every language.

For more information about all of the ways to call system commands from PowerShell, check out the following article.

Python

Python also has a few ways of calling external programs. According to the documentation, it appears that all use cases should now use the subprocess module. To launch an external command and return the exit code, you can simply use the call() method.

Execute and wait to get the exit code – Subprocess.Call()

Import subprocess
Exitcode = subprocess.call("ipconfig")

One thing to note, if you are using a function that exists in cmd.exe, the above won’t work. You must use the shell=True argument as well. For example, to use dir you would do the following:

Import subprocess
Exitcode = subprocess.call(["dir", "/ad", "c:\\"], shell=True)

You can do the above with a single string as well:

Exitcode = subprocess.call("dir /ad c:\\", shell=True)

Execute and continue – subprocess.Popen()

In order to execute without waiting for the exit code, you need to use the Popen() method of subprocess. Everything with this feels a bit more developery than it does with Perl and Python. However, the entire subprocess module is packed with a ton of things – useful things? I’m unsure as of yet, but here is what I know I need.

subprocess.Popen("ipconfig")

This technique shares STDOUT and partially STDIN. This gets really confusing when you do this:

t=subprocess.Popen("powershell")

The above is a fun party trick that will alternate between the PowerShell and Python prompts and interactive interpreters. It’s probably not a good idea to run interactive commands this way.

If you want to suppress the output from displaying, you can use the redirect to NULL like we saw earlier in this article when discussing Perl. However, there are some neat little tricks with the subprocess module that I think are worth learning about. You can set STDOUT to NULL when invoking Popen(). You can also set other streams such as STDERR this way. For example, the below will set STDOUT to NULL and then STDERR to STDOUT.

subprocess.Popen("ipconfig", stdout=(open(os.devnull, 'w')),stderr=subprocess.STDOUT)

Execute and retrieve the output – suprocess.PIPE

Similarly how we set stdout to null, we can also set stdout to equal PIPE so that we can later inspect the stdout property of the object returned by Popen(). The following illustrates this:

p = subprocess.Popen("ipconfig", stdout=subprocess.PIPE)
output=p.stdout.read()

Summary

Scripting languages by their nature are designed to be extremely versatile. There are sometimes just too many ways to do the same thing. This sort of sprawl can make things both extremely easy to use and extremely difficult to figure out at the same time. Because of this, it is really important to track the techniques that work for you and build up a library for your common use cases. Personally, I think the three use cases that I outlined in this article are more than sufficient: execute and wait to get the exit code, execute and continue, execute and retrieve the output. I think in the case of all three languages there are fair ways to accomplish these tasks.

The Python technique stands out because it is a bit cumbersome. To be fair, the Python subprocess module appears to be filled with tons o’ fun so it is understandable that it is a bit heavy to wield. To be further fair to Python, there are other ways of doing the above in Python using methods in modules and libraries that the documentation recommends you no longer use. Running commands in PowerShell at the command line and with the call (&) operator feels easy, but part of the reason for that is because PowerShell is intended to be a native shell to Windows. It almost seems unfair – like comparing how you run commands in ksh versus bash versus cmd. Actually, when you compare bash to PowerShell or even cmd to PowerShell, PowerShell has such quirks that it would probably lose that battle. As I think we’ll see in the upcoming articles, there are pros, cons, quirks, and angles to all 3 sides of this coin.

Get a list of metro apps and launch them in Windows 8 using PowerShell

I’ve been playing with Windows 8 store apps (metro apps) in C# and Xaml recently, and of course I thought it would be cool to launch these apps from within Windows PowerShell.  After some fruitless research trying to find a native way to do this in PowerShell or C#, I learned about a C++ interface called IApplicationActivationManager.

Fortunately, I was able to find some code on Stack Overflow that showed how to use this in C# (the post also listed the registry information I will describe in this article).  After some tweaking the code and the Add-Type syntax, I was able to expose the function I needed into PowerShell.  After that it was only a matter of wrapping the function into something that resembles PowerShell.

The code can be found on poshcode.

Get-MetroApp

This is a simple function that returns all of the metro apps installed on your machine.  Any filtering must be done with Where-Object.  Here’s a sample of what the cmdlet looks like when run:

23:48:22 PS D:\dropbox\scripts> Get-MetroApp |ft -AutoSize

EntryPoint                                                 ID                                                                      
----------                                                 --                                                                      
default.html                                               26720RandomSaladGamesLLC.HeartsDeluxe_kx24dqmazqk8j!App                 
Magic.UltimateTuner.App                                    26739TheMagicSoftware.UltimateTuner_hf01bqnspr91a!App                   
ContosoCookbook.App                                        4d1ddc26-6768-4a0d-97db-7cd72fc805c9_d6s28v2r30d6p!App                  
DataBindingTest.App                                        51da487c-5876-4ec7-9cad-fb5762b5032c_d6s28v2r30d6p!App                  
Tuner.App                                                  76f04ed9-49c3-434c-8d45-e392388e7e4d_d6s28v2r30d6p!App                  
BoxeeRemote.App                                            8c2b4686-67a7-46c2-aa34-5ac085571fed_d6s28v2r30d6p!App                  
Microsoft.Expression.DesignHost.Isolation.IsolationProcess App.a875b8f2e.a8a0c.a437b.aa93f.a4b3cf406091a_8wekyb3d8bbwe!Designer.App
DefaultBrowser.DefaultBrowserActivatableClass              DefaultBrowser_NOPUBLISHERID!Chrome                                     
HSW.Client.App                                             DiscoveryCommunicationsIn.HowStuffWorks_qa3esp0sj9xn6!App               
default.html                                               Microsoft.BingWeather_8wekyb3d8bbwe!App                                 
default.html                                               Microsoft.SkypeApp_kzf8qxf38zg5c!App                                    
MetroTwit.App                                              PixelTuckerPtyLtd.MetroTwit_5kbmb3e034y6r!App

The code behind this function is all about the registry. However, this is not an easy story to tell. The registry keys are not consistent. Basically, xaml apps are shows differently than HTML5 apps. Also, I’m still not entirely sure what DirectX apps will look like, but I assume that the Chrome browser is a C++ app so hopefully we’re covered there. Here is the logic behind what Get-MetroApp looks for in the registry:

The starting point for everything is in HKCU:\Software\Classes\ActivatableClasses\Package.  Each key is a separate app.  Each of these keys contains a Sever key and a key called ActivatableClassID.

The server key contains two keys.  The one of these that is not named BackgroundTransferHost.1 is the one that will have a property called AppUserModelID.  The value of this is what is needed in order to launch a metro app.  This is the ID property returned from Get-MetroApp.

Unfortunately, it’s not always obvious which app is which from this key so the Get-MetroApp also looks in the ActivatableClassID key for another key that has a CustomAttributes key with a property named AppObject.EntryPoint.   I found that the best key to try first was one called App if it existed, followed by app.wwa.  If neither of those is found, I iterate through each key looking for the AppObject.EntryPoint property.

In the case of xaml apps, the value of Appobject.Entrypoint appears to show the name of the app.  In html5 apps, it appears to only show default.html.  That is, unless there are other keys or sources out there that we (the community) have yet to discover.  In all of the apps that I had installed, I was able to tell which app was which by reading one or the other property returned by Get-MetroApp.

Start-MetroApp

You can ether pass an ID returned by Get-MetroApp

Start-MetroApp PixelTuckerPtyLtd.MetroTwit_5kbmb3e034y6r!Ap

or you can pipe one of the results from get-metroapp into Start-MetroApp.

Get-MetroApp |? entrypoint -match metrotwit |Start-MetroApp

I used the following to test that it was able to start every app i had installed:

Get-MetroApp |%{Start-MetroApp;sleep5}

The End?

I know this will come in handy to many. I have already added the module in my profile and have bound a few functions to allow me to quickly switch to specific metro apps very quickly. However, I’m not sure this is over yet. I’m curious if we will find better ways to grab the name of the app and link it with the ID. Please feel free to use the comments section of this page if you learn anything beyond what I have done.


Edit: I just learned about Get-AppxPackage in the Appx module. It appears to have a cleaner name, but it does not have the launch id required to launch the app. I’m sure it will be easy to correlate the packages to this name using some of the other keys. This will have to wait for another day, but it’s at least a lead to a better Get-MetroApp cmdlet.

Powerbits #9 – Get the directory of the calling script or get the current working directory of a session

This is one of my most used snippits of code. I generally put this at the beginning of every script. Every time I need it, I always say I need to post this as a powerbit so that I can find it more easily. Well, my wait is finally over, and you get the pleasant side effect of learning my most used trick.

The following bit of code will populate $currdir. If the script is run via a .ps1 file, it will set $currdir to be the directory where the .ps1 file lives. This will allow you to right click on a file and say “run with powershelll”, and have it use the files in that directory. The problem with this is that it will notwork if you are developing in ISE or in a powershell.exe host window. In that scenario, you generally want $currdir set to the directory your shell is in. This snippit will do just that, i.e., if it is not run via .ps1 file, it will load from $pwd (with some regex to strip out the psprovider nonesense).

$currdir = ''
if ($MyInvocation.MyCommand.Path) {
    $currdir = Split-Path $MyInvocation.MyCommand.Path
} else {
    $currdir = $pwd -replace '^\S+::',''
}

You can fork or clone this gist off of github here, or just run the following:

git clone https://gist.github.com/6715996.git

Median and Mode in a Measure-Object Proxy Function or How to Add Properties to the Return Object in a Proxy Function

I was poking around Khan Academy for something to do.  Because I’ve been living and breathing data, I thought it only appropriate to run through the statistics lessons up there.  While, I’m no slouch at statistics, I figured it can’t hurt to listen to lesson 1: Mean, Median, and Mode.  I started to think about how to do perform these calculations in PowerShell.  Mean required no thought at all:

Mean

$data = (0,1,1,3,5)
($data |Measure-Object -Average).Average

Median and Mode required some thought.  I quickly mocked up the following which worked like a charm:

Median

$data = (0,1,1,3,5)
$data = $data |sort
if ($data.count%2) {
    #odd
    $medianvalue = $data[[math]::Floor($data.count/2)]
}
else {
    #even
    $MedianValue = ($data[$data.Count/2],$data[$data.count/2-1] |measure -Average).average
}    
$MedianValue

Mode

$data = (0,1,1,3,5)

$i=0
$modevalue = @()
foreach ($group in ($data |group |sort -Descending count)) {
    if ($group.count -ge $i) {
        $i = $group.count
        $modevalue += $group.Name
    }
    else {
        break
    }
}
$modevalue

This is all fine and dandy, but working on this made me think of a great talk that Kirk Munro did at TEC 2012 about proxy functions. This is a topic that I’ve been dying to play with, but I have not had the desire beyond curiosity. This, however, was a perfect occasion. I decided to extend Measure-Object to include a -Median and a -Mode parameter.

I’m not going to dig into how to do proxy functions. If you’d like a step-by-step guide, I’d suggest reading Shay Levy’s blog post on Hey Scripting Guy! It’s really the best there is on the subject. However, after you read that article, you will likely scratch your head as I did when thinking about how to perform your own calculation on the objects in the pipeline, and then modify the return object to include new properties.

Perform your own calculation on the objects in the pipeline within the proxy function

The first problem to solve was easy in my opinion. I wanted to collect all of the objects passed to the Process block, and then do my calculations on this acquired list in the End block. I initialize an array called $data in Begin. Within the Process block, you can simply add $_ to that $data list.  Actually, in the case of Measure-Object you need to also be mindful of whether someone used the Property parameter. If they do, you need to ensure that you are collecting the values of the property specified for the objects in the pipeline rather than the object itself.  Here is the relevant snippits with elipses (…) indicating the missing code. You will be able to see the full code at the end of this article:

begin
    {
        try {
            # Initialize my $data array
            $data = @()
...

   process
    {
        try {
            if ($Property) {
               $data += $_.($property)
            } else {
               $data += $_
            }
...

With the above code, you can now access $data in the End block. However, this is not enough. In order for my proxy function to feel like a single function it needs to return the data along with object that the function normally returns.

Modify the return object of the original function

At first glance it looks like you could call Add-Member on $steppablePipeline.End(). This will not work. The End() method does not actually return anything at all. I think it’s a bit counter-intuitive. Unfortunately, the only way I have found to solve this problem is to call the original function on the data, and then call Add-Member on the return value of the function. Shay points out a subtle hint in his article to this, by telling us that we must use the full namespace\cmdletname to the function in order to call the original function (the non-proxied version). The only thing you need to be careful about is that you properly call the function with the original parameters.  This can be done by using $pscmdlet.MyInvocation.BoundParameters, but you need to be sure to exclude the InputObject and the Property parameter.   The InputObject should be taken from the $data variable you have populated. The property parameter needs to be excluded because you have already flattened the data down to the value of the property in the Process block as described in the previous section.  The following code illustrates how all of this can be accomplished in your end block:

$params = @{}
foreach ($key in ($pscmdlet.MyInvocation.BoundParameters.Keys |?{($_ -ne 'inputobject') -and ($_ -ne 'Property')})) {
     $params.($key) = $pscmdlet.MyInvocation.BoundParameters.($key)
}
$return = $data |Microsoft.PowerShell.Utility\Measure-Object @params
$return |add-member noteproperty -Name SomeName -Value SomeValue
$return

Here is the final version of my code that extends Measure-Object to include -Median and -Mode. The only decision I made that makes it feel not a part of the original function is that I do not add the Median and Mode properties to the return object unless the respective parameters are specified.  I have consciously done this in order to avoid any negative performance impact if I do not use the Median or Mode switch parameters.  It’s also debatable whether the Measure-Object cmdlet should return one of its normal properties if the parameter switch for that property was not used, but that’s not something I’m here to debate.

function Measure-Object {
    [CmdletBinding(DefaultParameterSetName='GenericMeasure', HelpUri='http://go.microsoft.com/fwlink/?LinkID=113349', RemotingCapability='None')]
    param(
        [Parameter(ParameterSetName='GenericMeasure')]
        [switch]
        ${Average},

        [Parameter(ValueFromPipeline=$true)]
        [psobject]
        ${InputObject},

        [Parameter(Position=0)]
        [ValidateNotNullOrEmpty()]
        [string[]]
        ${Property},

        [Parameter(ParameterSetName='GenericMeasure')]
        [switch]
        ${Sum},

        [Parameter(ParameterSetName='GenericMeasure')]
        [switch]
        ${Maximum},

        [Parameter(ParameterSetName='GenericMeasure')]
        [switch]
        ${Minimum},

        # Add my two parameters
        [Parameter(ParameterSetName='GenericMeasure')]
        [switch]
        $Mode,

        [Parameter(ParameterSetName='GenericMeasure')]
        [switch]
        $Median,
        # Parameters added

        [Parameter(ParameterSetName='TextMeasure')]
        [switch]
        ${Line},

        [Parameter(ParameterSetName='TextMeasure')]
        [switch]
        ${Word},

        [Parameter(ParameterSetName='TextMeasure')]
        [switch]
        ${Character},

        [Parameter(ParameterSetName='TextMeasure')]
        [switch]
        ${IgnoreWhiteSpace})

    begin
    {
        try {
            # Initialize my $data array
            $data = @()
            # $data array initialized

            $outBuffer = $null
            if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
            {
                $PSBoundParameters['OutBuffer'] = 1
            }
            $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Measure-Object', [System.Management.Automation.CommandTypes]::Cmdlet)

            # Remove my parameters if they are used so that errors are not thrown when passed to the Measure-Object function
            if ($PSBoundParameters['Mode']) {
                $PSBoundParameters.Remove('Mode') |Out-Null            
            }

            if ($PSBoundparameters['Median']) {
                $PSBoundParameters.Remove('Median') |Out-Null            
            }
            #Parameters removed

            $scriptCmd = {& $wrappedCmd @PSBoundParameters }
            $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
            $steppablePipeline.Begin($PSCmdlet)
        } catch {
            throw
        }
    }

    process
    {
        try {
            # If one of my parameters is used, populate $data with the objects        
            if ($Median -or $Mode) {
                if ($Property) {
                    # The next line ensures that I'm populating the array with the values I should be measuring
                    # if the -Property parameter is used
                    $data += $_.($property)
                } else {
                    $data += $_
                }
            }
            # $data populated
            else {
                $steppablePipeline.Process($_)
            }
        } catch {
            throw
        }
    }

    end
    {
        try {
            # If my parameters are used, calculate and add the property to the return
            if ($Median -or $Mode) {
                # Grab all of the parameters except for InputObject
                $params = @{}
                foreach ($key in ($pscmdlet.MyInvocation.BoundParameters.Keys |?{($_ -ne 'inputobject') -and ($_ -ne 'Property')})) {
                    $params.($key) = $pscmdlet.MyInvocation.BoundParameters.($key)
                }
                # Call the original Measure-Object on the data so that I can add-Member my
                # properties to this later
                $return = $data |Microsoft.PowerShell.Utility\Measure-Object @params
                if ($Median) {
                    $data = $data |sort
                    if ($data.count%2) {
                        #odd
                        $medianvalue = $data[[math]::Floor($data.count/2)]
                    }
                    else {
                        #even
                        $MedianValue = ($data[$data.Count/2],$data[$data.count/2-1] |measure -Average).average
                    }    
                    $return |Add-Member Noteproperty -Name Median -Value $MedianValue
                }
                if ($Mode) {
                    $i=0
                    $modevalue = @()
                    foreach ($group in ($data |group |sort -Descending count)) {
                        if ($group.count -ge $i) {
                            $i = $group.count
                            $modevalue += $group.Name
                        }
                        else {
                            break
                        }
                    }
                    if ($modevalue.Count -gt 1) {
                        $return |Add-Member Noteproperty -Name Mode -Value $modevalue
                    } else {
                        $return |Add-Member Noteproperty -Name Mode -Value $modevalue[0]
                    }
                }
                $return
            }
            else {
                $steppablePipeline.End()
            }
        } catch {
            throw
        }
    }
    <#     .ForwardHelpTargetName Measure-Object     .ForwardHelpCategory Cmdlet     #>

}

Next Steps

The only thing remaining is to consider whether or not I should even used $wrappedcmd at all. Part of me thinks it might be best to drop it completely and create a function that just processes InputObject so that I can build it into a collection to be used later. Part of me says this is not worth thinking about right now. The latter has won. Good night.

How to Execute PowerShell Scripts Without the CPU Hit to Start PowerShell

Background – The Problem

I have been playing a lot with Splunk recently. If you’re not familiar with the product, it is a horizontally scalable database that leverages map-reduce to give you real-time analytics about your data. That’s probably a topic for another day, but the relevant part is that they have an agent that can run on a Windows desktop called the Universal Forwarder. They also have a PowerShell SDK that lets you send data to Splunk via PowerShell. Again, the details about these topics should be saved for another day. The topic for today is that in order to send data from my system with any regularity I encounter a fairly known problem with PowerShell performance: Starting powershell.exe takes longer-than-I’d-like time and it incurs a bit of a CPU hit. Both of which are unacceptable to me if I’m going to run these scripts on every desktop in my enterprise.  This is especially true when you consider that a good proportion of those will be virtual desktops that are sharing CPU with each other.

The Solution

I’ve been thinking about this problem a lot, and I have a trimmed-down script-only version of my proposed solution. The technique is not that hard to follow.  The first step is to create a PowerShell script that will run indefinitely.  The script has the following requirements:

  • It should read through a directory for scripts.  If a script exists, it should execute it in its current runspace.
  • The order in which the scripts are entered in the queue directory matters, i.e., the first script in should be the first script run.
  • After every script is run, it should remove the variables that were created by the script, and then call [gc]::collect() to ensure that memory does not become unmanageable.  This is the magic part of the script.  For many, this post may be worth this snippit alone :) You can use this technique anytime your PowerShell session is using up too much RAM for your tastes.
  • It should allow an initialization script to run so that you can load any global variables that should not be deleted or modules that should stay loaded in the session.
  • It should sleep for a variable number of seconds between runs
  • Parameters should consist of, the queue directory name, the initialization script, and the delay between retries in the loop.

The Script

The end result is a script called longrunnings.ps1 (for lack of any thought put into the name) that looks like this:

param(
    [Parameter(Mandatory=$true,Position=0)]
    [ValidateScript({Test-Path $_ -PathType Container})]
    [string] $QueueDirectory,
    [Parameter(Mandatory=$false)]
    [ValidateScript({Test-Path $_ -PathType Leaf})]
    [string] $InitializationScript,
    [Parameter(Mandatory=$false)]
    [int] $SleepSeconds = 15
)
if ($InitializationScript) {
    Write-Verbose "Dot sourcing $InitializationScript"
    . $InitializationScript
}

Write-Verbose "Capturing the list of variables in the session so they are not removed between executions"
$vars = dir variable: |select -ExpandProperty name
# There's a few variables that get set in this script, and a few others that will be seen when called as a script
$vars += ('args','input','MyInvocation','PSBoundParameters','PSDebugContext','file','vars','files','foreach')

# Enter the infinite loop
while ($true) {
    $files = dir $QueueDirectory -file -Filter *.ps1 |sort lastwritetime
    if ($files) {
        foreach ($file in $files) {
            Write-Verbose ('Reading {0}' -f $file.fullname)
            $content =  [System.IO.File]::OpenText($file.fullname).ReadToEnd()
            Write-Verbose ('Executing {0}' -f $file.fullname)
            Invoke-Expression $content
        }
        $newvars = dir variable: |select -ExpandProperty name
        foreach ($var in $newvars) {
            if ($vars -notcontains $var) {
                Write-Verbose ('Removing ${0}' -f $var)
                Remove-Variable $var
            }
        }
        Write-Verbose 'Garbage Collection'
        [gc]::Collect()

        Write-Verbose ('Deleting {0}' -f $file.fullname)
        del $file.fullname
    }
    else {
        sleep $SleepSeconds
    }
}

The SCHTASKS job

Here’s an export of the schtasks xml I am using to ensure that it runs constantly.  I even have it set to restart every 24 hours, but that may not be necessary.

<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
 <RegistrationInfo>
 <Date>2012-06-25T16:30:49.0052527</Date>
 <Author>TOENUFF\Administrator</Author>
 </RegistrationInfo>
 <Triggers>
 <CalendarTrigger>
 <Repetition>
 <Interval>PT5M</Interval>
 <StopAtDurationEnd>false</StopAtDurationEnd>
 </Repetition>
 <StartBoundary>2012-06-25T16:26:37.0340001</StartBoundary>
 <ExecutionTimeLimit>P1D</ExecutionTimeLimit>
 <Enabled>true</Enabled>
 <ScheduleByDay>
 <DaysInterval>1</DaysInterval>
 </ScheduleByDay>
 </CalendarTrigger>
 </Triggers>
 <Principals>
 <Principal id="Author">
 <UserId>TOENUFF\Administrator</UserId>
 <LogonType>S4U</LogonType>
 <RunLevel>HighestAvailable</RunLevel>
 </Principal>
 </Principals>
 <Settings>
 <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
 <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
 <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>
 <AllowHardTerminate>true</AllowHardTerminate>
 <StartWhenAvailable>false</StartWhenAvailable>
 <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
 <IdleSettings>
 <StopOnIdleEnd>true</StopOnIdleEnd>
 <RestartOnIdle>false</RestartOnIdle>
 </IdleSettings>
 <AllowStartOnDemand>true</AllowStartOnDemand>
 <Enabled>true</Enabled>
 <Hidden>false</Hidden>
 <RunOnlyIfIdle>false</RunOnlyIfIdle>
 <WakeToRun>false</WakeToRun>
 <ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
 <Priority>7</Priority>
 <RestartOnFailure>
 <Interval>PT15M</Interval>
 <Count>4</Count>
 </RestartOnFailure>
 </Settings>
 <Actions Context="Author">
 <Exec>
 <Command>powershell.exe</Command>
 <Arguments>-windowstyle hidden -file D:\DropBox\scripts\longrunning\longrunning.ps1 -queuedirectory d:\dropbox\scripts\longrunning\queue -InitializationScript d:\DropBox\scripts\longrunning\init.ps1</Arguments>
 </Exec>
 </Actions>
</Task>

You can load the above by running

schtasks /create /xml d:\pathtoabovexml.xml

Controlling What Gets Run

Finally, to control when things are run, we obviously cannot rely on PowerShell because we’ll be introducing the overhead we are trying to avoid. Instead you can use schtasks again to copy your scripts into the queue directory at the intervals you expect them to run. Mind you, this does not ensure that the script runs at the specified time. It only ensures that it is scheduled to run. Alternatively, you could copy files directly into the directory from some remote server that controls what is run, but for my purposes the schtasks solution is fine.

Discussion

I mentioned at the beginning of this post that this is a script-only interpretation of my solution. I originally wanted to create this as a C# compiled service that created a PowerShell runspace and managed it nearly exactly the way I’m doing it in the script. The truth is that so far the technique I’m using seems to be extremely reliable. I’m sure I’ll hit snags along the way, but for now the technique is sound and the problem is solved. Whether I’ll propose this as a production solution is TBD, but I’m happy to see my dream realized.

Receiving a Disconnected PowerShell Session Asjob

I was down in Washington DC delivering a presentation about Windows Server 2012 for a roadshow that Microsoft put on. This was one stop in a few that I was lucky enough to be a part of (actually it’s not over yet – Boston is coming up on Wednesday). During that presentation I was showing off how you can disconnect a PowerShell session and then receive that session from another computer. This is a great new feature in PowerShell remoting that is integral to the new movement in Server to use PowerShell or tools that leverage PowerShell like the new server manager as the management tool of choice.

The demo goes like this:

Setup

3 computers

Server1 – The computer I am starting on. Windows Server 2012 RC1 (with PowerShell v3)
Server2 – The computer I am connecting to. Windows Server 2012 RC1 (with PowerShell v3)
Server3 – The computer I will use to connect to Server2 after Server1 is disconnected. Winows Server 2012 RC1 (with PowerShell v3)

The following script gets run on Server1 to start it off:

# Create a remote session
$s = New-PSSession -ComputerName server2
$s
# Start a long running command as a job on the session
$job = Invoke-Command $s {1..10000 | % {sleep 1; "Output $_"}} -AsJob
$job

After the job runs for a few seconds, you run the following on Server1 to disconnect the session:

Disconnect-PSSession $s

You can then close PowerShell on Server1 and open it on Server3. The following command will show you what sessions are available on Server2:

Get-PSSession -Computername Server2

The demo is finalized by performing the following to get into the session that was disconnected on Server1:

Get-PSSession -Computername Server2 |Receive-Session

This is a great demo that shows one of the best new features in the new version of the management framework. The only downside with the above is that the command started as a job, but when you call receive-pssession you are placed in the middle of the session as if you typed enter-pssesion. The problem with this is that ctrl-c will now break your running process. The natural question that was posed during the demonstration was, “How do you run receive-pssession, but keep it as a job?” My first inclination was to see if receive-pssession had an -asjob parameter. The answer is no. The solution is rather simple, but it did throw me for a loop. So much so that I thought I would share.

Solution

If you want to call receive-pssession asjob, simply run start-job with receive-pssession:

$job = Start-Job -ScriptBlock {Get-PSSession -ComputerName Server2|Receive-PSSession}

I told you it was simple, and I’m sure plenty of you who are reading this had figured this out without having to read the article. However, I thought it was worth discussing. If nothing else, this article at least highlights one of the great new features in PowerShell v3 Remoting.

Updated Solution – 6/26/2012

Thanks to Steve and Andreas in the comments (they require approval so I read them at the same time before they were visible on the page), there is a parameter in Receive-PSSession called OutTarget.  You can specify the following to force a Receive-PSSession to return a job:

$job = Get-PSSession -Computername Server2 |Receive-PSSession -OutTarget Job

I don’t like this.  I don’t like this so much that I have filed a connect suggestion to make Receive-PSSession use the more familiar -ASJob parameter.  Feel free to vote it up, if you agree.  Now, with that distraction, I hope no one noticed that I absolutely did not read the full Get-Help before making this post.  <ahem> wait…. I’ll come up with an excuse eventually.  All kidding aside, thanks for reading!  And thank you for helping make the site accurate!

Follow

Get every new post delivered to your Inbox.

Join 39 other followers

%d bloggers like this: