Sunday, October 4, 2015

MVP renewal

This week I received the email notifying me that my MVP award had been renewed for another year.

Thank you to Microsoft. It's an honour to me.

And thanks to the PowerShell community. It's definitively a great place to be and I can't wait to meet you all in Seattle in a month.

Keep scripting.

Monday, September 28, 2015

Powershell gymnastics - the modulo operator and beyond

I am starting today a new series of blog posts aimed at improving general knowledge of the scripting functionalities of Powershell. This will be somewhat like gymnastics, or crossfit if you like, aimed at making you more comfortable with the language and with computer programming in general.

I suppose that it's a funny idea to start the series with a post on one of the less known arithmetic operators: the modulo.

Let's take a simple arithmetic problem: what's left over when you divide 13 by 3? The answer is easy to compute: divide 13 by 3 and take the remainder: 1. But how do you compute this in Powershell? The modulo operator, whose historic sign is '%', comes to the rescue. But, before we continue, let's make sure you remember what the terminology is. We are talking here of an Euclidean division, where 13 is the dividend, 3 is the divisor, 4 is the quotient and 1 is the remainder:
13 = 3 * 4 + 1
Now there is an easy way to get just the remainder, which is by using the modulo operator '%'. The syntax is:

dividend % divisor

13 % 3
will give the expected result: 1

Although typically performed with the dividend and the divisor both being integers (we are talking of an Euclidean division of two integers), Powershell allows other types of numeric operands, which is a bit misleading on my opinion. Perl in this case is more strict, and limit itself to an Euclidean division, so, if it receives fractional arguments, Perl will only use the integer portion of the fraction. This means that the following two operations are equivalent in Perl:
#my $result1 = 13.3.5 % 3.3;
#my $result2 = 13 % 3;

In Powershell on the contrary, the arguments can be floating-point numbers, so it will accept 13.3 as dividend and 3.3 as divisor and return 0.1 as remainder:
PS C:\> 13.3%3.3
PS C:\> 13.3%3.3 | Get-Member

   TypeName: System.Double
If we want Powershell to go strict we have first to constrain the Double into an Integer:
PS C:\> [int]13.3
then make the modulo operation:
PS C:\> [int]13.3%[int]3.3
The problem with forcing a double into an integer in modulo operations is that Powershell uses banker's rounding algorithm. This algorithm which means that if there are two nearest integers, like when the decimal part of a number is exactly 0.5, PowerShell rounds always to the nearest even:
PS C:\> [int]10.5
PS C:\> [int]11.5
PS C:\> [int]12.5
PS C:\> [int]13.5
See? The resulting integer is always even. This is how it is explained on MSDN:

Rounding to nearest, or banker's rounding
Midpoint values are rounded to the nearest even number. For example, both 3.75 and 3.85 round to 3.8, and both -3.75 and -3.85 round to -3.8. This form of rounding is represented by the MidpointRounding.ToEven enumeration member.
Rounding to nearest is the standard form of rounding used in financial and statistical operations. It conforms to IEEE Standard 754, section 4. When used in multiple rounding operations, it reduces the rounding error that is caused by consistently rounding midpoint values in a single direction. In some cases, this rounding error can be significant.

Though this is fine in most occasions but modulo operations cope badly with that and should be avoided.

When in a modulo operation there is no remainder, such is 5 % 1, the interpreter will return 0:
PS C:\> 5%1
With that in mind, it's useful to know here that you can put a modulo operation in an IF statement. In this case you do not need to check if the output -eq 0, because PowerShell evaluates 0 as boolean $False and 1 as boolean $True, and the code becomes shorter:
PS C:\> if(!(5%1)){"No remainder for this ops"}
No remainder for this ops
For sake of completeness, know that the modulo operation can be executed alongside an assignment to a variable. This is the syntax:

%=n Divide the value by n and assign the remainder

Here's an example:
$number = 13
$number %= 3
$number value will be set to 1, which is the remainder of 13 / 3.

Now that you have become familiar with the modulo operator, and to better appreciate it, let's see how you could get the same result going .NET and using the System.Math class. This class offers a DivRem method which beginners have a hard time understanding how it works. The reason is that is takes three parameters when the modulo operation logically needs just two: a dividend and a divisor.

If you use it with two parameters you'll get the following error:
PS C:\> [system.math]::DivRem(13,3)
Cannot find an overload for "DivRem" and the argument count: "2".
At line:1 char:1
+ [system.math]::DivRem(13,3)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodCountCouldNotFindBest
It looks like the third parameter is mandatory. Since we do not know what to pass to DivRem, let's try to give him a fake var:
PS C:\> [system.math]::DivRem(13,3,[ref]$fakevar)
[ref] cannot be applied to a variable that does not exist.
At line:1 char:1
+ [system.math]::DivRem(13,3,[ref]$fakevar)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (fakevar:VariablePath) [], RuntimeException
    + FullyQualifiedErrorId : NonExistingVariableReference
Finally a clear error message! What's happening here is that Powershell expect the third parameter be a declared variable of type System.Management.Automation.PSReference. Let's give him one:
PS C:\> $Remainder = 0

PS C:\> [system.math]::DivRem(13,3,[ref]$Remainder)
As you see, DivRem outputs the quotient (which is the result of the division) straight away. If we want to know the remainder, let's query the $Remainder variable:
PS C:\> $Remainder
Cool, it works! And differently from '%', the DivRem method will perform the banker's rounding out of the box:
PS C:\> [system.math]::DivRem(13.3,3.3,[ref]$Remainder2)
PS C:\> $Remainder2
That's because the Math.DivRem method takes Int32 (the default) or Int64 parameters, not floating-point numbers.

It looks like now you are proficient with modulo operations on this side of the river. The time has come to move on the other side into the binary world to see what else our computers have to offer for modulo operations. You probably already know that you can perform bitwise arithmetic in Powershell.

But, before we start looking at how modulo operation can be performed with bitwise operators, let's gain a better knowledge studying two interesting arithmetic operators which have been added to Powershell 3.0:
  • shr
  • shl
This section will force you to familiarize with binary operations and will make it easier to understand bitwise operations we will perform later.

What the -shr (shift-right) and -shl (shift-left) operators do is to shift bits inside processor registers, and they can also be used as a quick way to divide or multiple the number.

First some binary. We, humans, usually count with base 10, that is we have 10 digits to make numbers with, so we go in order 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, then we start adding them together to go beyond 10 numbers: 10, 11, 12, 13, 14, etc.

In base 2 though, there are only 2 digits to use: 0 and 1. So the same numbers go like this: 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, etc.

The conversion can be easily performed in Powershell using [Convert]:
PS C:\> 0..10 | % {[Convert]::ToString($_,2)}

Let's add some padding zeroes to make 1 byte long integers like if we would like to ideally fill a processor register (even do processor hardware is of no importance at all here because Powershell lies on a hardware abstraction layer and knows nothing of the underlying architecture, differently from C and C++ which are intended to be highly efficient languages):
PS C:\> 0..10 | % {[Convert]::ToString($_,2).PadLeft(8,'0')}

Or if we want Int32 (4 bytes, or, 1 word):
S C:\> 0..10 | % {[Convert]::ToString($_,2).PadLeft(32,'0')}

Be aware that these are not real binary numbers, but just textual representation of binary numbers.

If we use the -shl operator, we can transform binary 2 to binary 4, then to binary 8:

Let's start from decimal 2:
PS C:\> [Convert]::ToString(2,2).PadLeft(8,'0') # decimal 2

and proceed shifting bits leftward:
PS C:\> [Convert]::ToString(2 -shl 1,2).PadLeft(8,'0') # decimal 4
PS C:\> [Convert]::ToString(2 -shl 2,2).PadLeft(8,'0') # decimal 8
PS C:\> [Convert]::ToString(2 -shl 3,2).PadLeft(8,'0') # decimal 16
PS C:\> [Convert]::ToString(2 -shl 4,2).PadLeft(8,'0') # decimal 32
PS C:\> [Convert]::ToString(2 -shl 5,2).PadLeft(8,'0') # decimal 64
PS C:\> [Convert]::ToString(2 -shl 6,2).PadLeft(8,'0') # decimal 128

In a few words, what's happening here is that -shl is shifting all the bits in the provided value 1 spot the left, and chop of the extra zero. It turns out that this operation corresponds to raising 2 to the 2nd power in a loop:
PS C:\> 0..6 | % {[Convert]::ToString([math]::Pow(2,$_),2)}

When we add padding we get:
PS C:\> 0..7 | % {[Convert]::ToString([math]::Pow(2,$_),2).PadLeft(8,'0')}

which is the equivalent of:
PS C:\> 0..7 | % {[Convert]::ToString(1 -shl $_,2).PadLeft(8,'0')}

If you're not lost, at this point you should start feeling well stretched.
Now that you are familiar with all the binary representations of powers of 2, you are ready to know that there are other ways of performing modulo operations. Many experienced programmers know well that if they use a bitwise shift for multiplication or division (which is considered one of the slowest arithmetic operations) when they’re multiplying or dividing by a power of two, they will get faster calculations. One of these performance tricks works for modulo too.

The not-so-secret formula is:

x modulo y = (x & (y − 1))

which translates to the following Powershell oneliner:
$number -band ([Math]::Pow(2,$number) - 1)

  • -band is the operator that does a binary-and of the bits in the values on the left and on the right side
  • [Math]::Pow is the Powershell syntax for ^
Let's try to make an example:
PS C:\> 54 % 32

The bit pattern of 54 is:
PS C:\> [Convert]::ToString(54,2).PadLeft(8,'0')

In the example 32 is a power of two: 2^5

Since numbers which are power of two have only one significant bit set to 1 followed by less significant bits set to 0, its binary representation is:
PS C:\> [Convert]::ToString(32,2).PadLeft(8,'0')

Now if the divisor is a power of two (as 32 is) and we decrement it by one (from 32 to 31 in decimal), this sets all the less significant bits to 1 and the rest to 0. This yields therefore to the following binary representation:
PS C:\> [Convert]::ToString(32-1,2).PadLeft(8,'0')

If we perform a bitwise-and between 54 and 31 we get:

00110110 (54)
00011111 (31)
00010110 (22)

which is the equivalent of the following Powershell code:
PS C:\> 54 -band 31

Once we do the bitwise-and, the most significant bit from the original value is lost, and this leaves us with the remainder of the original value divided by the divisor.

In a few words, when you perform a modulo of a number against its power of 2, you just take its lower order bits. The number of bits at the end is determined by which power of two you're using.

Simple, isn't it?

Now let's move to see some practical uses of the modulo operations.

Modulo is useful when trying to determine whether a number is even or odd: if a number can be evenly divided by 2 it’s even; if a number can’t be evenly divided by 2 then it’s odd. This translates into Powershell like this:
$number = 101
if($number % 2) 

In the previous example, if the number in the $number variable is even, the operation will return 0, so False, and it will display "Even". If the number is odd, it will return 1, so True, and show "Odd" on the screen.

Of course in Powershell multiple if around modulo operations can be concatenated, for instance in the following example I'll find all the numbers between 1 and 100 that are multiples of 4 and 7:


As you can see I used the range operator (..) to go through all the numbers between 1 and 100, which I passed down to Where-Object with two conditions. Nice. And the interpreter does a good job of understanding my input even do there are no empty spaces in the line of code. Cool and very handful for code golfing competitions.

Modulo can also be used to determine whether a year is a leap year or not (a leap year is a year containing one additional day so to keep our calendar year synchronized with the astronomical year). There of course is a .NET method to get this piece of information, using the IsLeapYear method, as in the following example:
$year = 1900

But this can be gloriously achieved also with the following Powershell code:
PS C:\> $year = 2012
PS C:\> if(!($year%4)){"$year is a leap year"}
2012 is a leap year

To be precise, our Gregorian calendar removes three leap days every 400 years, so our algorithm has to evolve toward this:
$year = 2012
if((!($year % 4) -and ($year % 100)) -or !($year % 400))
    "$year is a leap year"
    "$year is not a leap year"

Note that the logical and operator has higher precedence than logical or and will be evaluated first.
This is classical example showing the modulo operation at its full power. Notwithstanding that, it turns out that the same result can be achieved using a bitwise-and operation, like those we saw above. The circle is almost full, I guess. We are now proceeding against some optimizations aimed at showing the full power of Powershell.

Let's start optimizing this leap year algorithm.

We know already that 4 being a power of 2, the first test ($year % 4) can be converted to:
($year) -band 3

We can also replace ($year % 100) with:
($year % 25)

This is valid because 100 results from 2 x 2 x 5 x 5. Since ($year % 4) has already checked for factors of 4, we can eliminate that factor from 100, leaving 25.

Concerning the third test ($year % 400), this can be replaced by a bitwise-and operation against the number 15. In fact, like we just saw for the second test, 400 results from 2 x 2 x 2 x 2 x 5 x 5. The factor of 25 can be taken out because we already checked it in the second test. This leaves us with 2 x 2 x 2 x 2, which gives 16. Being 16 a power of 2, we can replace ($year % 16) with:
($year -band 15)

The overly optimized final algorithm is here for you to see:
$year = 2012
if((!($year -band 3) -and ($year % 25)) -or !($year -band 15))
    "$year is a leap year"
    "$year is not a leap year"

Funny how a good understanding of binary operations and a good grasp on bitwise operators can make your code evolve toward something more performant.

A last example to make sure you have grasped the use of modular arithmetics, is to implement a Powershell script that converts an elapsed time in seconds to hours, minutes, and seconds:
$sec = 1500
$hrs = [math]::Truncate($sec / 3600)
$min = [math]::Truncate(($sec / 60) % 60)
$sec = $sec % 60
"{0}:{1}:{2}" -f $hrs,$min,$sec
The general idea is that modular arithmetics (and the modulo operation) are particularly useful when numbers wrap around when a certain value is reached (like in a clock).

I hope you enjoyed this first post on Powershell gymnastics. More to come soon.

Do not hesitate to post your examples of operations with modulo and with shifting bits, or to share with your friends if you liked this content.

Saturday, July 4, 2015

Announcing the winner of the Powershell Oneliner Contest 2015

A week ago I invited the Powershell Community to take part to a Powershell Oneliner Contest. People joined from across the world in search of glory and of riddles that could put them at wits' end. Today a winner has been selected:

Here's the top 10 oneliner warriors in the contest:

1st - Johannes Rössel (aka Joey)
2nd - John Roos

3rd - Simon Wåhlin
4th - Simon Walsh
5th - Bartek Bielawski
6th - Nathan Hartley
7th - Kevin Marquette
8th - Max Kozlov
9th - Rhys Edwards
10th - Wes

Congratulations to Joey for winning the Powershell Oneliner Contest 2015 with the following solutions:
Task 1: Who's taller? - 34 chars
Task 2: Can you count to five? - 8 chars
Task 3: PowerShell is the secret word - 164 chars


I am proud to announce that Joey has accepted to be our special guest blogger today. I am very honored to have you here.

Joey, tell us a bit about yourself.
I live in a small town in southern Germany named Tübingen (near-ish Stuttgart), working on a graph visualization (Note: We do have an awesome free graph/diagram/flowchart editor called yEd). I grew up and studied computer science with specialization in usability and UX in Rostock in northern Germany, which is a quite pretty city. This also wasn’t too long ago, so my professional experience is still quite limited. That doesn’t stop me from reading and trying to learn all kinds of new things in my spare time.

I am a daily bicycle commuter, even in winter. And I love board games.
How did you get to Powershell?
I read the announcements in the very beginning and actually found the concept quite cool. I think I played around with the beta back then, but not very productively. Around the time PowerShell v1 was current I decided on a whim to start learning it – by trying to golf Project Euler tasks. Since those tasks progress slowly in difficulty and the initial ones are trivial to solve with a bit of programming experience it’s actually quite a nice way of starting out. You don’t need to think so much about how to even solve the problem and instead can concentrate on how to express it in the language before you. And in the process you actually learn quite a few things how to use a language well. In PowerShell’s case this means for me using the pipeline as much as possible. Advice I’ve frequently given to others on Stack Overflow as well.

Eventually, although currently less active, I became involved with Pash, the open-source re-implementation of PowerShell on Mono.
Where does you one-liner passion comes from?

Well, I said before, I started learning the language by golfing Project Euler tasks. This eventually grew into a contest with a friend who was using Ruby. It was akin to a battle between the languages (PowerShell is better with date/time stuff, but overall golfs worse, sadly). I wouldn’t exactly narrow it down to only one-liners, though. You can golf quite well on multiple lines, too ;-)

The nice thing about golfing to learn a language is that eventually you learn every obscure little corner of the language and learn how to use it to your advantage. This also sometimes helps with real-world code in explaining surprising behavior of a particular script.
How did you approach Task 1?

Task 1 was the trivial one and didn’t leave that much room for varying approaches (at least not approaches that were also short). After initial confusion about the task itself it came down almost immediately to my final answer. First you need to grab all double numbers. You could do this with $n|?{$_-is[double]}, but that’s horribly long. What’s more, we actually need to iterate over the array for that to work, so that was right out.

The nicer approach here was $n-match’\.’ which exploits how comparison operators work in PowerShell: When the left operand is an array, they return all matching values instead of a boolean result. Another thing that’s at work here is that –match implicitly converts its left argument to a string – and those string conversions always use the invariant culture, thus ensuring that the decimal numbers have a dot in them. This implicit conversion is only applied during evaluation of the result, so the resulting items are still doubles, not strings.

Then we obviously needed to find the largest number. After a while of golfing you realize that there is only one way of doing that shortly and that is via sort and either using [-1] or [0], depending on whether you want the first or last result.

After that, the only thing left is trying to obtain the absolute value of the result. The obvious solution would be [Math]::Abs(), but that weighs in at 13 characters. Surely there are better options. Remember the part about implicit string conversion earlier? Turns out we can just use the –replace operator to get rid of the minus sign. Of course, in this case the result will be a string, but hey, that was allowed, so be it.

Another approach I tried, which didn’t work out was (''+($n-match'\.'|sort)[-1]).Trim('-') which has the unfortunate drawback that .Trim() needs the left operand to be a string. And there is no nice way of enforcing that here, thus requiring too many characters to fix that, pushing it to 38 – four more than my actual solution.

How did you cope with Task 2?

Task 2 had an evil restriction, in that no ASCII decimal digits were allowed in the code. This makes some things longer, of course. But then the challenge lies in trying to figure out how to avoid doing those things in the first place.

My very first attempt was abysmal: +-join([char[]]'+,-./'|%{[char](' '.Length+$_)}). 53 characters, just trying to represent the five digits by shifting their Unicode values down by six and then adding that again, converting the result into a char, then joining them into a string and converting that into an integer. Lots of conversions going on here, and the calculation isn’t pretty because I’m not allowed to use numbers (and there was no constant handy I could rely on). One thing is handy here, though, which is the leading unary + to convert the operand to a number; this will stick with us through the end.

A fun thing to try can be to just use control or otherwise unprintable characters. Heck, PowerShell strings may contain almost anything, so getting rid of part of the length above can be done simply by removing the need of adding numbers – there are Unicode characters with numbers 1 through 5. We can just use them (the following code uses the old IBM character set glyphs for those characters, so you can’t just copy the code, but you can enter those characters with Alt+01 through Alt+05): +-join[int[]][char[]]'☺☻♥♦♣'. 28 characters, just about half of the previous attempt, with essentially the same approach.

But maybe there’s another approach that cuts down on the frequent conversions here. Remember that PowerShell strings may contain any character. Maybe there is a Unicode character with number 12345? Well, sure, there is: , U+3039, Hangzhou Numeral Twenty. Now, in this context I don’t particularly care about what the character represents as long as it’s a convenient encoding for the number 12345. +[char]'〹' brings us down to 10 characters, which is much better than the previous attempts. This just leaves the pesky conversion of the string to char (PowerShell has no character literals, but you can cast and convert one-character strings to char). Well, the shortest way of casting a one-character string to char is by indexing into it, but +'〹'[0] wouldn’t be allowed. But there are quite a few things that can get coerced to the number 0 in this context: Uninitialized variables (and thus $null), $false, or, conveniently, the empty string. I’m fairly confident that it’s hard to get shorter than +'〹'['']. Unless we allow digits again.

What's your take on Task 3? It was quite of open question, wasn't it?

It was, indeed and usually I don’t like such questions too much in a contest, since they simply invite way too many non-serious answers. I’ve hosted contests myself, I also posted tasks to the Programming Puzzles and Code Golf StackExchange site. Golfing is ultimately about finding creative ways to solve a task within the confines of the task restrictions. However, in my experience too vague restrictions and conditions just invite people to be lazy and “funny” by posting joke answers one then has to sift through.

Given that you actually accepted my worst attempt at this task it seems like your interpretation of the task was more strict than mine. I interpreted the whitespace requirement way more loosely, coming up with all kinds of other solutions along the way.
As far as the task specification goes, “starting from a string” is too vague. Of course, it implies it has to be input of some sort, but I’d probably have defined it such that changing the string would have to change the output and that, depending on the string, more than one output would be possible.

So, task 3 went through quite a lot of iterations for me, most of them apparently invalid ;-). The first and accepted one was a trivial attempt: Subtract a common number from all characters in the output, then do an unary encoding of the resulting numbers and put that in the string. I chose to be clever with the two uppercase letters by conditionally adding 32, but that didn’t help too much: -join(-split'…'|%{$x=0}{[char]($_.Length+100-32*($x++%5-eq0))}) – 102 characters for the string alone (164 total), and the decoding logic is also quite long (the {$x=0} can be omitted, depending on how one’s stance on running in an unknown environment is – I chose to err on the safe side here). The part in the end can get a bit shorter with 32*!($x++%5), but unary encoding of direct character values is quite long regardless. In fact, I didn’t even bother submitting this variant.

I dabbled a bit with binary encoding and eventually hexadecimal with 15 different whitespace characters, with only minor reduction in character count. Eventually I used unary encoding of indices into a string with all the necessary characters to reduce it to 89, which probably was against your ideas of the task as well ;-).

Should I have accepted the answer "X"|%{"PowerShell"}? What is to you the spirit of a oneliner contest?

No, you shouldn’t. The spirit to me is to have fun, the other part of it is finding creative solutions around the restrictions of the tasks (if there are any). Such solutions don’t require any cognitive effort, many people will come up with the exact same one and to me they don’t represent the spirit of such contests. Now, I’ve said I hosted a few contests myself and one thing I learned is that the task specification should be very clear and, if possible, leave little room for language-lawyering that would result in solutions as the above one. In this particular case it’s difficult to specify the task where there is a clear line between solutions that are allowed and those that are not allowed. I usually try to have such a clear line, which is easiest by not including restrictions for the program at all, apart from the usual ones (e.g. putting the program in the file name and eval-ing that).

What's your opinion of loops in a oneliner... like for loops or while do until?

Well, in your particular case at least for loops weren’t allowed because of the no-semicolons rule. Generally, why not? If they make the solution shorter, I’m all for them. However, in my experience this will only be the case for the for loop which has a few opportunities for shortening that aren’t possible with pipelines. With while or do I never saw any benefit.

What's your take on Powershell for one-liners if compared to other languages you might know?

Mostly it works quite well. It’s about on par with Python, but can’t reach Ruby or Perl levels. Overall still nice for a language that wasn’t designed to be concise. The most annoying parts when golfing are the $ for variables, and forced braces around control structures like if.

Is there any oneliner-oriented community you know and would like to talk about?

Oh, well, there is the Programming Puzzles and Code Golf StackExchange site which has grown quite a bit in recent months. By now I’m rarely active there anymore, though, mostly because of a lack of time.

I have collected a few golfing tips for PowerShell there, too:

Thank you, Joey, for sharing your time and knowledge! The 'Hyper-V Best ¨Practices' book is yours!

For those wishing to contact Joey, here's where you can find him:
For those wishing to make the project Euler experience with Powershell, here's the place to go.


As a bonus, let me now introduce you John Roos. John came second in the contest and I got in touch with him as soon as I saw the nice Powershell V5 solution he produced for task 3. He immediately accepted to be my guest blogger today.

John, tell us a bit about you and show us the way to your v5 solution to Task 3.

Hi, I am currently working with Business Intelligence within Operations at H&M in Stockholm and spend a decent amount of time with PowerShell. I first started with PowerShell last year. I think it was around September when I wanted to get started with C# and stumbled upon the "Getting started with PowerShell 3.0" series on Channel 9 by Jason Helmick and Jeffrey Snover and I was hooked right away.

When I saw the third task in this contest I immediately started to think about a binary string where "X" would represent number 1 and a space would represent 0. That was my starting point.

Since I already had the result that this one-liner will produce I thought about this backwards. What number would represent a "P" and what number would be "o" and so on. The following code gets the numbers I need to have represented as binary:


Since I am lazy I used an online tool to convert these numbers to binary and ended up with the following:

80 = 01010000
111 = 01101111
119 = 01110111
101 = 01100101
114 = 01110010
83 = 01010011
104 = 01101000
101 = 01100101
108 = 01101100
108 = 01101100
Next is to put it all togehter in one string and then replace 1 with "X" and 0 with a space:

'01010000011011110111011101100101011100100101001101101000011001010110110001101100'.Replace(1,'X').Replace('0',' ')
' X X     XX XXXX XXX XXX XX  X X XXX  X  X X  XX XX X    XX  X X XX XX   XX XX  '
So now I had the starting string with just "X" and spaces and need to work my way back to the "PowerShell" output. The string need to be split into an array of strings with 8 characters each (one for each letter of the word). Regular expressions works well for this:

[regex]::Matches(' X X     XX XXXX XXX XXX XX  X X XXX  X  X X  XX XX X    XX  X X XX XX   XX XX  '.Replace(' ',0).Replace('X',1),'\d{8}')
Now lets pipe it further so that each binary string can be converted to [INT] (using base 2 since its binary) and then convert that to [CHAR].

[regex]::Matches(' X X     XX XXXX XXX XXX XX  X X XXX  X  X X  XX XX X    XX  X X XX XX   XX XX  '.Replace(' ',0).Replace('X',1),'\d{8}')|%{[char][Convert]::ToInt32("$_",2)}
Almost there. Now the result need to be converted from an array to a string. In Powershell 4 it doesnt really work well with string for this particular case:

[string]([regex]::Matches(' X X     XX XXXX XXX XXX XX  X X XXX  X  X X  XX XX X    XX  X X XX XX   XX XX  '.Replace(' ',0).Replace('X',1),'\d{8}')|%{[char][Convert]::ToInt32("$_",2)})
P o w e r S h e l l
I dont want those spaces between every character, but fortunately in Powershell 5 we get access to a new string method called New() which accepts an array of chars. So lets encapsulate the entire thing with this method:

[string]::new(([regex]::Matches(' X X     XX XXXX XXX XXX XX  X X XXX  X  X X  XX XX X    XX  X X XX XX   XX XX  '.Replace(' ',0).Replace('X',1),'\d{8}')|%{[char][Convert]::ToInt32("$_",2)}))
Now I have the answer to the question, but its 191 characters long. At this point I realised that all the binary strings start with "01". What if I remove that from the long string and add them in the loop in the end? In that case I would have to split the string with regex on only 6 chars instead of 8 and add "1" when converting back to integers (the leading zero is assumed since its binary):

[string]::new(([regex]::Matches(' X    X XXXXXX XXXX  X XXX  X  X  XXX X   X  X XX XX  X XX  '.Replace(' ',0).Replace('X',1),'\d{6}')|%{[char][Convert]::ToInt32("1$_",2)}))
The one-liner is now down to 172 characters and thats as far as I got. I tried lots of different solutions but this was the shortest I could come up with.

Thanks John for your explanation!

For those wishing to contact John Roos, here's where you can find him:
A last mention goes to a couple of fellow heavyweigth Microsoft MVPs who took part in the Contest:
  • Bartek Bielawski, who wrote a must-read blog post on his solutions. Check it here. Bartek was the winner of the Powershell Scripting Games in 2011, and he is an author at Powershell Magazine with excellent skills in Powershell golfing.
  • Emin Atac, who wrote an excellent blog post on his approach to the three tasks. Check it here. Even if Emin is not on the top-10 (just because he offered a solution to task 3 that didn't match my very subjective restrictions), this guy knows what he is talking about.
That's all for the Powershell Contest 2015. I hope you enjoyed reading the expert answers of our winners. Personally, I was very happy to host such an event and I want to thank you everyone who entered the game as well as our sponsor, Packt Publishing, for offering the prize.

Wednesday, June 24, 2015

Powershell Oneliner Contest 2015 - Win a Hyper-V book

I have always enjoyed taking part in most of the Powershell contests out there since Powershell is kind of a recreational administration language to me. I am thinking, for example, of the fun I had taking part in the oneliner contest (which I won) organized by fellow MVP Mike F Robbins, or of the Powershell Golf organized in 2013 by Robert Robelo on Twitter.
Being quite proud of my blog, and despite the fact that I am more of a system administrator than a developer, I have unilaterally decided to organize my self-hosted, self-managed Powershell Oneliner Contest.

The three ideas behind this game are that:
  1. experienced competitors (and I, of course!) should come away with a lot of tips from the brightest Powershell minds that will hopefully take part in the event
  2. novice Powershell scripters should learn that persistence pays off when looking for a solution to such a contest
  3. this is a fairly good occasion to sharpen your skills for the soon-to-start Powershell Scripting Games held by the community
  • The contest is split into three tasks. Each task consists of a simple scenario for which you have to produce a oneliner solution.
  • Submit your solutions via a comment to this blog article by 11AM (PDT) on Wednesday, July 1st, which is the deadline.
  • You MUST submit only one task solution per comment, so that I can easily see who was the first to submit the shortest solution on a per-task basis.
  • Should you find a shorter oneliner to solve a task you are allowed to post additional comments (just remember to sign your comments so that I know who's who).
  • Aliases are of course accepted
  • Backticks accepted for readability
  • No semi-colons
  • UPDATE - No Here-String
  • UPDATE - Please don't sign your comments as Unknown or I won't be able to know who you are.
  • If you use a Powershell version other than v4, I am okay with it, but please mention it in the comment so that I can test it on the same version. Powershell v5 is welcome.
  • Entries (comments) will not be made public until after the submission deadline.

  • The shortest solution in terms of chars wins.
  • The first person to produce the shortest working solutions to a task will get 1 point, the second 2 points, the third 3 points and so on.
  • The person with the lowest total score over the three mandatory tasks will be the winner.
  • The winner will be announced on Saturday, July 4th on this blog and the prize will be awarded at that time.
  • I'll be the only judge.

What? Is there a prize? Yes, of course. The prize will be a printed copy of the excellent book 'Hyper-V Best Practices' (5-Stars on by fellow MVP Benedict Berger  (@Benedict_Berger) offered by Packt Publishing!!!
I was the reviewer of the book as well of the ton of Powershell code it contains. I can tell you this is the book to read in these Hyper-V times!

As a bonus, and if the winner agrees, he/she will intervene as a guest blogger on this blog and will explain how one goes about learning the hidden bits of Windows Powershell. Sounds cool, doesn't it?

Let's now dive into the contest tasks.
TASK 1 - Who's taller?
This is a rather easy challenge and I hope it will make for a good warm-up session for your Powershell muscles, especially if you are a beginner. Given a $n variable showed below, write the shortest possible oneliner that outputs the absolute value of the largest double-precision floating-point number in the array.
$n = -1,-2,-5,-8.9,'b',-9.11,-6,-3,-2,-9.1,-1,-1.4,'a'

Expected output
Task-specific rules
  • The object in the output can be of any type
  • UPDATE - The one-liner must work also with different values of $n

TASK 2 - Can you count to five?

Time to delve into something harder. Write the shortest possible Powershell oneliner that outputs the number 12345.

Expected output
Task-specific rules
  • You are not allowed to use the digits 0 to 9 in your oneliner
  • The object in the output must be of type Int32
  • Your displayed output shouldn't contain any other char

TASK 3 - Powershell is the secret word

I hope that by this time you are enjoying the competition. It's time for the last hard task. Write the shortest possible Powershell oneliner that outputs the word 'PowerShell' starting from a text string composed only of uppercase Xs' and whitespaces.

Expected output
Task-specific rules
  • The string composed of X's and whitespaces must be part of the oneliner (backticks accepted!) and not be a variable defined on a separate line
  • You can use as many X's and empty spaces you like or need
  • P and S in the output must be uppercase
  • UPDATE - No Here-String
  • UPDATE - I consider jokes answers like "X "|%{"Powershell"}
On your marks, set, go! And remember to have fun, it's just a game meant to produce something useful for the growing and growing Powershell community!

UPDATE - Check-Task Function

I have decided to update this blog post with a function that will allow you to check if your proposed solutions are correct in terms of output and respect the task assignments. Kudos for this function go to my friend Joey!

function Check-Task ([int] $Task, [scriptblock] $Command) {
        $n = -1,-2,-5,-8.9,'b',-9.11,-6,-3,-2,-9.1,-1,-1.4,'a'
        $result = & $command
        $check = $false
        switch ($Task) {
            1 { $check = $result -eq '1.4' -or 
                [double]::Parse("$result") -eq 1.4 }
            2 {
                $check = ($result -is [int] -and $result -eq 12345) -and
                    ("$Command" -notmatch '[0-9]')
            3 {
                $check = ($result -is [string] -and $result -ceq 'PowerShell') -and
                    ("$Command" -match '([''"])[X`\s]+\1')
        if (!$check) {
            Write-Host -Fore Yellow "Expected: $((1.4,12345,'PowerShell')[$Task - 1])"
            Write-Host -Fore Red    "Actual:  $result"
        $color = ('Red','Green')[$check]
        Write-Host -Fore $color ('{0,4}: {1}' -f "$Command".Trim().Length,$command)
Sample usage:
Check-Task 1 { $n.gettype() }
Do not hesitate to test your solutions before posting them to my blog! Better safe than sorry.


If you want to give some visibility to this contest, feel free to twit about it. You can use the hashtags #poshcontest2015 and #powershell so that other competitors can share their thoughts (not the solutions of course!).

Thanks again to Packt Publishing (and to Mary in particular) for sponsoring this event!

UPDATEClick here to find the winner's name and his solutions!

Tuesday, June 2, 2015

Copy-Item improvements to support file copy over WinRM to NanoServers

If you follow this blog (you should!), then you know that I have just published a post on the procedure to install a Microsoft NanoServer.

If you read through the whole post, you know that this small footprint operating system is supposed to be managed through Powershell Remoting since it has no local logon capabilities.

Now, if you look well into the new cmdlets/parameters that come with the Windows Management Framework 5 (the one that comes with Windows 2016 TP2), you'll see that Copy-Item now supports file copy operations through WinRM.

The new key parameters are -ToSession and -FromSession.

Let's see with an example how they shoud be used., even do they are pretty self-explanatory.
First of all open a remoting session to the NanoServer:

$session = New-PSSession -ComputerName -Credential administrator
Then, to copy any file to the NanoServer over WinRM, just use the following syntax:

Copy-Item -ToSession $session -Path .\samplescript.ps1 -Destination c:\temp\
The operation can be performed both directions, so to retrieve a file just use:

Copy-Item -FromSession $session -Path c:\results.txt -Destination .
If you liked this post, please share!

How to build your first fantastic Nano Server

As it has been announced in recent events such as Ignite, Microsoft is working hard for the introduction of Nano Server, a cloud-oriented, GUI-less, small-everything, Powershell-managed version of Windows Server. This server version comes with no logon capability, which means that management tasks are performed remotely, from the very first logon. And, since the system is built to be extremely light, we can suppose that it will be blatantly fast for the specific workloads that come from the devops/virtualization/containerization world.
NanoServer goes even further than Server Core in terms of lightness
Sounds good, you say. But how to test it? Well, today Nano Server is part of Windows 2016 Technical Preview 2, which has been announced less than a month ago and that I have had the occasion to test in one of my labs. It was a tricky job that I am going to detail as long as the issues I faced during the deployment.

The starting point is the NanoServer folder stored in the Windows 2016 TP2 iso:

The folder size is a mere 181 MB, and it contains a .wim file as well as the following six file cabinets:

Directory: H:\NanoServer\Packages

Mode            LastWriteTime     Length Name
----            -------------     ------ ----
--r--    09/05/2015     03:01   10849819
--r--    09/05/2015     03:01    7690908
--r--    09/05/2015     03:01     327347
--r--    09/05/2015     03:01   12785830
--r--    09/05/2015     03:01    6900267
--r--    09/05/2015     03:01      49656
Let's begin with building the source repository by copying the whole content of this folder:

Copy-Item H:\NanoServer\* D:\nanoserver -Recurse
Then we have to convert the WIM file contained in the Windows iso file to a VHD that we can mount in Hyper-V. This is easily achieved with the Powershell script that Pronichkin developed and that you can download from here.

Put the script in the same repository you created above:

Set-Location D:\NanoServer

.\Convert-WindowsImage.ps1 -WIM .\NanoServer.wim -VHD .\NanoServer.vhd -DiskType Fixed -VHDFormat VHD -SizeBytes 1GB -Edition 1

Windows(R) Image to Virtual Hard Disk Converter for Windows(R) 8
Copyright (C) Microsoft Corporation.  All rights reserved.
Version 6.3.9600.7.amd64fre.fbl_core1_hyp_dev(mikekol).140217-3000 Release to Web

INFO   : Image 1 selected ()...
INFO   : Creating fixed disk...
INFO   : Attaching VHD...
INFO   : Disk initialized with MBR...
INFO   : Disk partitioned...
INFO   : Volume formatted...
INFO   : Access path (D:\) has been assigned...
INFO   : Applying image to VHD. This could take a while...
INFO   : Signing disk...
INFO   : Image applied. Making image bootable...
INFO   : Fixing the Device ID in the BCD store on VHD...
INFO   : Drive is bootable. Cleaning up...
INFO   : Closing VHD...
INFO   : Closing Windows image...
INFO   : Done.
As you can see, I created a 1GB disk, and this is enough for a test environment.


Next we need to stream in some dlls and packages into the VHD.

New-Item Dism -ItemType Directory
Set-Location Dism
Copy-Item H:\Sources\api*downlevel*.dll
Copy-Item H:\Sources\*dism*
Copy-Item H:\Sources\*provider*
This will copy 30 files in your Dism folder. 
Preparing the vhd...
Now mount the image:

Mount-DiskImage D:\NanoServer\NanoServer.vhd
In my case it got mounted as G:

Then to add the packages I mentioned before (the ones under H:\NanoServer\Packages), you can leverage the Add-WindowsPackage cmdlet:


In my case I encountered an issue with this action when I performed it on my Windows 2012 R2 server:

Add-WindowsPackage -Path G: -PackagePath *.cab
Add-WindowsPackage : To service this Windows image requires the latest version of the DISM. See to find the latest version of DISM, 
and to learn how to install the latest version of DISM from the ADK on your computer.
At line:1 char:1
+ Add-WindowsPackage -Path G: -PackagePath *.cab
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Add-WindowsPackage], COMException
    + FullyQualifiedErrorId : Microsoft.Dism.Commands.AddWindowsPackageCommand
In the DISM log I found the following error:

DISM Manager: PID=3092 TID=4604 It is an unsupported scenario to service an up level image using low level dism. - CDISMManager::CreateImageSessionFromLocation(hr:0x80070032)

I checked the version of the DISM cmdlets on Windows 2012 R2:

Add-WindowsPackage -Path G: -PackagePath .\ -Verbose
VERBOSE: Dism PowerShell Cmdlets Version
On Windows 10 Insider Preview we have version 10:

VERBOSE: Dism PowerShell Cmdlets Version
I tried to solve this by downloading the Windows Assessment and Deployment Kit (Windows ADK) for Windows 8.1 Update which I found here.

For your information, the adksetup.exe must be run from c:\ as an administrator otherwise it will fail with such an error:

Could not acquire privileges; GLE=0x514
Returning status 0x514

In any case it kept not working on Windows 2012 R2.


The known workaround is to use DISM from either Windows 10 or Windows Server 2016 Technical Preview 2 machine. In my case I luckily had a freshly installed Windows 10 CTP2 sitting there in a VM. I just copied the vhd over there, enable the administrator account, which is needed to be able to mount the vhd file, through the command

net user administrator /active:yes

On Windows 10, Add-WindowsPackage worked flawlessly (apart for the drivers package which took much longer):
Add-WindowsPackage –Path G:\ –PackagePath C:\NanoServer\Packages\
Add-WindowsPackage –Path G:\ –PackagePath C:\NanoServer\Packages\
Add-WindowsPackage –Path G:\ –PackagePath C:\NanoServer\Packages\
Add-WindowsPackage –Path G:\ –PackagePath C:\NanoServer\Packages\
Add-WindowsPackage –Path G:\ –PackagePath C:\NanoServer\Packages\
Add-WindowsPackage –Path G:\ –PackagePath C:\NanoServer\Packages\

Add-WindowsPackage in action on my Windows 10 Enterprise Insider Preview

Once all the packages are added, I dismounted the vhd image.

Dismount-DiskImage -ImagePath C:\Nanoserver\NanoServer.vhd
The vhd file is now ready.


One I copied the vhd back to my Windows 2012 R2 test bed I created the VM descriptors with Powershell:

New-VM -Name 'NanoServer1' -Generation 1 -MemoryStartupBytes 512MB -SwitchName LAN -Path 'N:\Hyper-V Virtual Machines\Virtual Machines\' -NoVHD
Copy-Item 'D:\NanoServer\NanoServer.vhd' -Destination 'N:\Hyper-V Virtual Machines\'
Get-VM 'NanoServer1' | Add-VMHardDiskDrive -Path 'N:\Hyper-V Virtual Machines\NanoServer.vhd'
Start-VM 'NanoServer1'
The machine booted, but the boot took almost twenty minutes. After a long wait a black screen with an underscore appeared. I didn't really expect something on the console to show, but I must admit I was unpleasantly surprised by the long boot up times.


After a long analysis and a bunch of re-deployments, I discovered that, even do the NanoServer virtual machines show the following screen, in reality they are already pingable and manageable:

Windows Nano Server is online well before the start-up is replaced by the black screen
Once Nano is up and running, the following screen appears:

The famous black screen with un underscore of a Windows NanoServer
As you can see it differs from the welcome screen of a standard Windows 2016 Technical Preview 2 installation in the fact that it lacks logon capabilities:

Windows 2016 logon screen
At this point you can connect to it remotely using PowerShell Remoting.

From a PowerShell prompt on a management PC, run the following two commands, replacing the IP address with the one of your Nano Server (you can check this on your local DHCP server list of leases):

Set-Item WSMan:\localhost\Client\TrustedHosts -Value 192.168.5 -Concatenate
Enter-PSSession -ComputerName -Credential Administrator
The Set-Item cmdlet is used to add Nano server to the list of trusted hosts for Remoting.

Note that the administrator password is blank by default, so when Enter-PSSession asks for a password just hit Enter.

Once you are logged in, you can check the default name that a NanoServer is given, which is "miniwinpc".

[]: PS C:\Users\Administrator\Documents> hostname
[]: PS C:\Users\Administrator\Documents> ipconfig /all

Windows IP Configuration

   Host Name . . . . . . . . . . . . : minwinpc
   Primary Dns Suffix  . . . . . . . :
   Node Type . . . . . . . . . . . . : Hybrid
   IP Routing Enabled. . . . . . . . : No
   WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter Ethernet:

   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Microsoft Hyper-V Network Adapter
   Physical Address. . . . . . . . . : 00-15-5D-01-64-03
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : fe80::b47c:4c39:433b:5628%4(Preferred)
   IPv4 Address. . . . . . . . . . . :
   Subnet Mask . . . . . . . . . . . :
   Lease Obtained. . . . . . . . . . : Monday, June 1, 2015 11:07:57 AM
   Lease Expires . . . . . . . . . . : Monday, June 1, 2015 11:07:57 PM
   Default Gateway . . . . . . . . . :
   DHCP Server . . . . . . . . . . . :
   DHCPv6 IAID . . . . . . . . . . . : 67114333
   DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-1C-FE-57-D3-00-15-5D-01-64-03
   DNS Servers . . . . . . . . . . . :
   NetBIOS over Tcpip. . . . . . . . : Disabled

Tunnel adapter Local Area Connection* 2:

   Media State . . . . . . . . . . . : Media disconnected
   Connection-specific DNS Suffix  . :
   Description . . . . . . . . . . . : Microsoft Failover Cluster Virtual Adapter
   Physical Address. . . . . . . . . : 02-92-9B-4B-EB-13
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
Here's the output of some other generic commands on a NanoServer:
[]: PS C:\> ls

    Directory: C:\

Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         5/6/2015  10:05 AM                EFI
d-----         5/6/2015  10:32 AM                Program Files
d-----         5/6/2015  10:05 AM                Program Files (x86)
d-r---         6/1/2015  12:40 PM                Users
d-----         6/1/2015  11:22 AM                Windows
-a----         6/1/2015   6:44 AM            300 Convert-WindowsImageInfo.txt
[]: PS C:\> Get-Process

Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
-------  ------    -----      ----- -----   ------     -- -----------
     94       6      596       1540 ...61     0.33    380 csrss
      0       0        0          4     0               0 Idle
    615      17     3160       9900 ...86     0.34    428 lsass
    243      10     2340       9140 ...81     0.34   1076 MsMpEng
    168       8     1452       4912 ...65     0.30    416 services
     44       3      280       1076 ...56     0.23    296 smss
    189       8     1396       5240 ...75     0.09    536 svchost
    223      12     1388       5484 ...75     0.06    576 svchost
    721      20    10732      20864 ...14     1.33    636 svchost
    354      14     3976      11628 ...26     0.13    692 svchost
    110       7     1136       5540 ...74     0.08    752 svchost
     93       6     1040       4552 ...71     0.00    768 svchost
    284      15     6972      11116 ...92     0.20    780 svchost
    209      14     2216       7180 ...80     0.00    884 svchost
    567      55     6152      15288 ...63     0.89    904 svchost
    263      26     3760       9264 ...86     0.23   1000 svchost
    329       0       76         80     2     4.16      4 System
     69       7      640       3476 ...63     0.05    404 wininit
    379      36    34160      54288 ...24     9.19   1544 wsmprovhost
[]: PS C:\> gcim win32_operatingsystem | fl *

Status                                    : OK
Name                                      : Microsoft Windows Server Technical Preview 2
FreePhysicalMemory                        : 3883052
FreeSpaceInPagingFiles                    : 233724
FreeVirtualMemory                         : 4188272
Caption                                   : Microsoft Windows Server Technical Preview 2 Tuva
Description                               :
InstallDate                               : 6/1/2015 11:07:56 AM
CreationClassName                         : Win32_OperatingSystem
CSCreationClassName                       : Win32_ComputerSystem
CSName                                    : MINWINPC
CurrentTimeZone                           : -420
Distributed                               : False
LastBootUpTime                            : 6/1/2015 11:07:46 AM
LocalDateTime                             : 6/1/2015 12:47:26 PM
MaxNumberOfProcesses                      : 4294967295
MaxProcessMemorySize                      : 137438953344
NumberOfLicensedUsers                     : 0
NumberOfProcesses                         : 20
NumberOfUsers                             : 0
OSType                                    : 18
OtherTypeDescription                      :
SizeStoredInPagingFiles                   : 233724
TotalSwapSpaceSize                        :
TotalVirtualMemorySize                    : 4427568
TotalVisibleMemorySize                    : 4193844
Version                                   : 10.0.10074
BootDevice                                : \Device\HarddiskVolume1
BuildNumber                               : 10074
BuildType                                 : Multiprocessor Free
CodeSet                                   : 1252
CountryCode                               : 1
CSDVersion                                :
DataExecutionPrevention_32BitApplications : True
DataExecutionPrevention_Available         : True
DataExecutionPrevention_Drivers           : True
DataExecutionPrevention_SupportPolicy     : 2
Debug                                     :
EncryptionLevel                           :
ForegroundApplicationBoost                :
LargeSystemCache                          :
Locale                                    : 0409
Manufacturer                              : Microsoft Corporation
MUILanguages                              : {en-US}
OperatingSystemSKU                        : 109
Organization                              : Microsoft
OSArchitecture                            : 64-bit
OSLanguage                                : 1033
OSProductSuite                            : 272
PAEEnabled                                :
PlusProductID                             :
PlusVersionNumber                         :
PortableOperatingSystem                   : False
Primary                                   : True
ProductType                               : 3
RegisteredUser                            : Microsoft
SerialNumber                              :
ServicePackMajorVersion                   : 0
ServicePackMinorVersion                   : 0
SuiteMask                                 : 272
SystemDevice                              : \Device\HarddiskVolume1
SystemDirectory                           : C:\Windows\system32
SystemDrive                               : C:
WindowsDirectory                          : C:\Windows
PSComputerName                            :
CimClass                                  : root/cimv2:Win32_OperatingSystem
CimInstanceProperties                     : {Caption, Description, InstallDate, Name...}
CimSystemProperties                       : Microsoft.Management.Infrastructure.CimSystemProperties
As a side note, notice that the good old Get-WMIObject (alias gwmi) is not implemented on NanoServer:

[]: PS C:\>  Get-WmiObject win32_computersystem
The term 'Get-WmiObject' is not recognized as the name of a cmdlet, function, script file, or operable program. Checkhe the spelling of the name, or if a path was included, verify that the path is correct and try again.
    + CategoryInfo          : ObjectNotFound: (Get-WmiObject:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException
Concerning Powershell, version 5 of the WMF is installed, exactly like on a Windows 2016:

[]: PS C:\> $PSVersionTable

Name                           Value
----                           -----
PSRemotingProtocolVersion      2.3
CLRVersion                     4.0.30319.34011
WSManStackVersion              3.0
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.10074.0
PSVersion                      5.0.10074.0
Now it would be interesting to compare Powershell capabilities in terms of accepted cmdlets on both Windows 2016 TP2 and Windows NanoServer.

Here's what you have on a Nano Server:

[]: PS C:\> Get-Command | Select Name,Module | Group Module | Sort Count -Descending

Count Name                      Group
----- ----                      -----
  140 Storage                   {@{Name=Disable-PhysicalDiskIndication; Module=Storage}, @{Name=Disable-StorageDiagn...
   92                           {@{Name=A:; Module=}, @{Name=B:; Module=}, @{Name=C:; Module=}, @{Name=cd..; Module=...
   74 Microsoft.PowerShell.U... {@{Name=Add-Member; Module=Microsoft.PowerShell.Utility}, @{Name=Clear-Variable; Mod...
   68 NetAdapter                {@{Name=Disable-NetAdapter; Module=NetAdapter}, @{Name=Disable-NetAdapterBinding; Mo...
   43 Dism                      {@{Name=Add-ProvisionedAppxPackage; Module=Dism}, @{Name=Apply-WindowsUnattend; Modu...
   38 Microsoft.PowerShell.M... {@{Name=Add-Content; Module=Microsoft.PowerShell.Management}, @{Name=Clear-Content; ...
   35 SmbShare                  {@{Name=Block-SmbShareAccess; Module=SmbShare}, @{Name=Close-SmbOpenFile; Module=Smb...
   34 NetTCPIP                  {@{Name=Find-NetRoute; Module=NetTCPIP}, @{Name=Get-NetCompartment; Module=NetTCPIP}...
   23 NetEventPacketCapture     {@{Name=Add-NetEventNetworkAdapter; Module=NetEventPacketCapture}, @{Name=Add-NetEve...
   14 EventTracingManagement    {@{Name=Add-EtwTraceProvider; Module=EventTracingManagement}, @{Name=Get-AutologgerC...
   14 CimCmdlets                {@{Name=Export-BinaryMiLog; Module=CimCmdlets}, @{Name=Get-CimAssociatedInstance; Mo...
   13 Microsoft.WSMan.Manage... {@{Name=Connect-WSMan; Module=Microsoft.WSMan.Management}, @{Name=Disable-WSManCredS...
   11 Defender                  {@{Name=Add-MpPreference; Module=Defender}, @{Name=Get-MpComputerStatus; Module=Defe...
    9 PcsvDevice                {@{Name=Clear-PcsvDeviceLog; Module=PcsvDevice}, @{Name=Get-PcsvDevice; Module=PcsvD...
    6 StorageQoS                {@{Name=Get-StorageQoSFlow; Module=StorageQoS}, @{Name=Get-StorageQoSPolicy; Module=...
    5 Microsoft.PowerShell.S... {@{Name=Get-AuthenticodeSignature; Module=Microsoft.PowerShell.Security}, @{Name=Get...
    4 PnpDevice                 {@{Name=Disable-PnpDevice; Module=PnpDevice}, @{Name=Enable-PnpDevice; Module=PnpDev...
    3 SmbWitness                {@{Name=Move-SmbClient; Module=SmbWitness}, @{Name=Get-SmbWitnessClient; Module=SmbW...
That's just a subset of what one can find on the last version of the Windows Server OS:

[]: PS C:\> Get-Command | Select Name,Module | Group Module | Sort Count -Descending

Count Name                      Group
----- ----                      -----
  140 Storage                   {@{Name=Disable-PhysicalDiskIndication; Module=Storage}, @{Name=Disable-StorageDiagn...
  105 Microsoft.PowerShell.U... {@{Name=Format-Hex; Module=Microsoft.PowerShell.Utility}, @{Name=Get-FileHash; Modul...
   98                           {@{Name=A:; Module=}, @{Name=B:; Module=}, @{Name=C:; Module=}, @{Name=cd..; Module=...
   86 Microsoft.PowerShell.M... {@{Name=Add-Computer; Module=Microsoft.PowerShell.Management}, @{Name=Add-Content; M...
   85 NetSecurity               {@{Name=Copy-NetFirewallRule; Module=NetSecurity}, @{Name=Copy-NetIPsecMainModeCrypt...
   78 RemoteDesktop             {@{Name=Add-RDServer; Module=RemoteDesktop}, @{Name=Add-RDSessionHost; Module=Remote...
   68 NetAdapter                {@{Name=Disable-NetAdapter; Module=NetAdapter}, @{Name=Disable-NetAdapterBinding; Mo...
   43 Dism                      {@{Name=Add-ProvisionedAppxPackage; Module=Dism}, @{Name=Apply-WindowsUnattend; Modu...
   42 NFS                       {@{Name=Disconnect-NfsSession; Module=NFS}, @{Name=Get-NfsClientConfiguration; Modul...
   41 MsDtc                     {@{Name=Add-DtcClusterTMMapping; Module=MsDtc}, @{Name=Get-Dtc; Module=MsDtc}, @{Nam...
   35 SmbShare                  {@{Name=Block-SmbShareAccess; Module=SmbShare}, @{Name=Close-SmbOpenFile; Module=Smb...
   34 NetTCPIP                  {@{Name=Find-NetRoute; Module=NetTCPIP}, @{Name=Get-NetCompartment; Module=NetTCPIP}...
   34 NetworkTransition         {@{Name=Add-NetIPHttpsCertBinding; Module=NetworkTransition}, @{Name=Disable-NetDnsT...
   32 BranchCache               {@{Name=Add-BCDataCacheExtension; Module=BranchCache}, @{Name=Clear-BCCache; Module=...
   27 IscsiTarget               {@{Name=Expand-IscsiVirtualDisk; Module=IscsiTarget}, @{Name=Export-IscsiTargetServe...
   23 NetEventPacketCapture     {@{Name=Add-NetEventNetworkAdapter; Module=NetEventPacketCapture}, @{Name=Add-NetEve...
   20 Pester                    {@{Name=AfterAll; Module=Pester}, @{Name=AfterEach; Module=Pester}, @{Name=Assert-Mo...
   19 ScheduledTasks            {@{Name=Disable-ScheduledTask; Module=ScheduledTasks}, @{Name=Enable-ScheduledTask; ...
   18 International             {@{Name=Get-WinAcceptLanguageFromLanguageListOptOut; Module=International}, @{Name=G...
   17 PSDesiredStateConfigur... {@{Name=Configuration; Module=PSDesiredStateConfiguration}, @{Name=Find-DscResource;...
   17 DnsClient                 {@{Name=Add-DnsClientNrptRule; Module=DnsClient}, @{Name=Clear-DnsClientCache; Modul...
   17 PKI                       {@{Name=Add-CertificateEnrollmentPolicyServer; Module=PKI}, @{Name=Export-Certificat...
   16 PSScheduledJob            {@{Name=Add-JobTrigger; Module=PSScheduledJob}, @{Name=Disable-JobTrigger; Module=PS...
   14 CimCmdlets                {@{Name=Export-BinaryMiLog; Module=CimCmdlets}, @{Name=Get-CimAssociatedInstance; Mo...
   14 UserAccessLogging         {@{Name=Disable-Ual; Module=UserAccessLogging}, @{Name=Enable-Ual; Module=UserAccess...
   14 EventTracingManagement    {@{Name=Add-EtwTraceProvider; Module=EventTracingManagement}, @{Name=Get-AutologgerC...
   13 Microsoft.PowerShell.S... {@{Name=ConvertFrom-SecureString; Module=Microsoft.PowerShell.Security}, @{Name=Conv...
   13 NetNat                    {@{Name=Add-NetNatExternalAddress; Module=NetNat}, @{Name=Add-NetNatStaticMapping; M...
   13 NetLbfo                   {@{Name=Add-NetLbfoTeamMember; Module=NetLbfo}, @{Name=Add-NetLbfoTeamNic; Module=Ne...
   13 Microsoft.WSMan.Manage... {@{Name=Connect-WSMan; Module=Microsoft.WSMan.Management}, @{Name=Disable-WSManCredS...
   13 iSCSI                     {@{Name=Connect-IscsiTarget; Module=iSCSI}, @{Name=Disconnect-IscsiTarget; Module=iS...
   12 Wdac                      {@{Name=Add-OdbcDsn; Module=Wdac}, @{Name=Disable-OdbcPerfCounter; Module=Wdac}, @{N...
   11 ServerManagerTasks        {@{Name=Get-SMCounterSample; Module=ServerManagerTasks}, @{Name=Get-SMPerformanceCol...
   11 SoftwareInventoryLogging  {@{Name=Get-SilComputer; Module=SoftwareInventoryLogging}, @{Name=Get-SilComputerIde...
   11 DirectAccessClientComp... {@{Name=Disable-DAManualEntryPointSelection; Module=DirectAccessClientComponents}, @...
   11 PowerShellGet             {@{Name=Find-Module; Module=PowerShellGet}, @{Name=Get-InstalledModule; Module=Power...
   11 Defender                  {@{Name=Add-MpPreference; Module=Defender}, @{Name=Get-MpComputerStatus; Module=Defe...
   10 PackageManagement         {@{Name=Find-Package; Module=PackageManagement}, @{Name=Get-Package; Module=PackageM...
   10 PSDiagnostics             {@{Name=Disable-PSTrace; Module=PSDiagnostics}, @{Name=Disable-PSWSManCombinedTrace;...
    9 PcsvDevice                {@{Name=Clear-PcsvDeviceLog; Module=PcsvDevice}, @{Name=Get-PcsvDevice; Module=PcsvD...
    8 BitsTransfer              {@{Name=Add-BitsFile; Module=BitsTransfer}, @{Name=Complete-BitsTransfer; Module=Bit...
    7 NetSwitchTeam             {@{Name=Add-NetSwitchTeamMember; Module=NetSwitchTeam}, @{Name=Get-NetSwitchTeam; Mo...
    7 ServerManager             {@{Name=Add-WindowsFeature; Module=ServerManager}, @{Name=Remove-WindowsFeature; Mod...
    7 TLS                       {@{Name=Disable-TlsCipherSuite; Module=TLS}, @{Name=Disable-TlsSessionTicketKey; Mod...
    6 Kds                       {@{Name=Add-KdsRootKey; Module=Kds}, @{Name=Clear-KdsCache; Module=Kds}, @{Name=Get-...
    5 AppLocker                 {@{Name=Get-AppLockerFileInformation; Module=AppLocker}, @{Name=Get-AppLockerPolicy;...
    5 PSReadline                {@{Name=Get-PSReadlineKeyHandler; Module=PSReadline}, @{Name=Get-PSReadlineOption; M...
    5 Microsoft.PowerShell.D... {@{Name=Export-Counter; Module=Microsoft.PowerShell.Diagnostics}, @{Name=Get-Counter...
    4 NetworkConnectivityStatus {@{Name=Get-DAConnectionStatus; Module=NetworkConnectivityStatus}, @{Name=Get-NCSIPo...
    4 PnpDevice                 {@{Name=Disable-PnpDevice; Module=PnpDevice}, @{Name=Enable-PnpDevice; Module=PnpDev...
    4 NetQos                    {@{Name=Get-NetQosPolicy; Module=NetQos}, @{Name=New-NetQosPolicy; Module=NetQos}, @...
    4 BestPractices             {@{Name=Get-BpaModel; Module=BestPractices}, @{Name=Get-BpaResult; Module=BestPracti...
    3 SmbWitness                {@{Name=Move-SmbClient; Module=SmbWitness}, @{Name=Get-SmbWitnessClient; Module=SmbW...
    3 WindowsErrorReporting     {@{Name=Disable-WindowsErrorReporting; Module=WindowsErrorReporting}, @{Name=Enable-...
    2 ServerCore                {@{Name=Get-DisplayResolution; Module=ServerCore}, @{Name=Set-DisplayResolution; Mod...
    2 Microsoft.PowerShell.A... {@{Name=Compress-Archive; Module=Microsoft.PowerShell.Archive}, @{Name=Expand-Archiv...
    2 NetConnection             {@{Name=Get-NetConnectionProfile; Module=NetConnection}, @{Name=Set-NetConnectionPro...
    2 PSWorkflow                {@{Name=New-PSWorkflowSession; Module=PSWorkflow}, @{Name=New-PSWorkflowExecutionOpt...
    2 Microsoft.PowerShell.Host {@{Name=Start-Transcript; Module=Microsoft.PowerShell.Host}, @{Name=Stop-Transcript;...
    1 PSWorkflowUtility         {@{Name=Invoke-AsWorkflow; Module=PSWorkflowUtility}}
    1 Microsoft.PowerShell.O... {@{Name=Export-ODataEndpointProxy; Module=Microsoft.PowerShell.ODataUtils}}
As you can see NanoServer boasts the whole bunch of Storage, SmbShare or NetTCPIP cmdlets, while it lacks modules like Netlbfo, Pester, NFS or PSDesiredStateConfiguration.


As a matter of fact, NanoServer is not aimed at being an all-round do-everything operating system, like any previous Windows till now. Nano Server has been designed for the automation of Cloud services. As Snover, the inventor of Powershell and lead architect for the Windows Server Division, stated recently: "I want automation. One of the key principles of the cloud is we want configuration as code."

Today it is up to you to find the most convenient use for this newborn technology. And even if there is for sure a lot of work to be done to correct the bugs that will come up, you can already forget about old style server management. Things are changing faster and faster. Powershell somewhat opened the way to everything you see now, and NanoServer is maybe the reason why all of this happened.
Stay tuned for more on NanoServer and Powershell.
Related Posts Plugin for WordPress, Blogger...