Welcome to MSDN Blogs Sign in | Join | Help

PowerPack Challenge

Quest Software’s PowerPack Challenge’09 is on... calling all script warriors to show their skills.

See the details here - http://powergui.org/powerpackchallenge.jspa

Happy Scritping

Osama Sajid, Program Manager

Why is Get-ChildItem so Slow?

We get this question fairly frequently when it comes to slow network connections.

The performance of directory listings (especially on a laggy network) are limited by the .NET APIs we call to retrieve the directory information. There are two limitations to the current set of APIs:

Forced Retrieval of Attributes

When we do a directory listing, we show the standard attributes of the file or directory: Mode, LastWriteTime, Length, and Name. The core Windows API is highly optimized for this basic scenario, and returns these attributes by default along with the rest of the file information. However, the .NET Framework doesn’t take advantage of this data, and instead goes back to the network location to ask for all of the file attributes. This chatty behaviour adds a handful of network round trips for each file or directory, making the directory listing many times slower: hundreds or thousands of times slower in many cases. The Framework team addressed this as part of .NET 4.0, and you’ll see the benefits of this new feature as soon as we are able to adopt it.

In version two, even without the benefit of the new .NET API, though, you’ll see a huge improvement in wildcarded directory listings (both local and remote.)

As a background, PowerShell wildcards are different than straight cmd.exe wildcards. For example, PowerShell wildcards do not match the 8.3 short file name, while the native filesystem filtering (exposed by cmd.exe wildcards) do. PowerShell’s wildcards support character ranges, while the native file system filtering support does not. Because of this, PowerShell wildcard processing happens AFTER we’ve retrieved all of the files.

This comes at a cost, however. Native file system filtering (as exposed by the –Filter parameter) is MUCH faster, as its processing is wired into the Windows file system.

In version two, we did a bunch of work to resolve this strain. When you provide a PowerShell wildcard, we convert as much of it as possible to a native filesystem filter, and then apply our wildcarding logic to the much smaller set of results. You’ve probably noticed this most in tab completion, but it makes huge improvements in regular wildcarded directory listings. Especially remote ones. Since the native filtering is processed by the remote file system, we don’t need to suffer the performance penalty of accessing attributes of files that you ultimately don’t care about anyways. In version one, you can work around the issue by specifying the –Filter parameter directly. If this still doesn’t provide the speed you need, you can call “cmd.exe /c dir”.

 

Lack of Enumeration API

This issue raises itself for directory listings that contain many files. The DirectoryInfo.GetFiles() method returns an array. When creating that result list, the .NET Framework does many re-allocations (and copies) of that array, causing an exponential performance degradation:

GetChildItemPerf

 

This, too, has been resolved in the .NET 4.0 updates, by offering an API that lets you enumerate through a directory result, rather than retrieve them all at once. If you are running into these limitations, you can again apply a wildcarding approach. If this still doesn’t provide the speed you need, you can call “cmd.exe /c <command>”.

Why Don’t We Fix It?

Since cmd.exe isn’t impacted by these issues, why don’t we just do the same thing and call into the core Windows APIs directly? The reason is twofold:

  1. A core tenet of PowerShell is providing access to the REAL underlying .NET objects. If we implemented the semantics ourselves, we’d have to return new types of objects – something like PSFileInfo and PSDirectoryInfo. V1 scripts (or downstream cmdlets) that expect the REAL underlying .NET objects would fail to work. While we could add a new switch (-Raw?), users would still have to change their scripts to support it. In that case, they might as well use the existing cmd /c workaround.
  2. This issue is ultimately transient. While it’s annoying to drag out over a few years, it will ultimately come and go without users having to change their behaviour. One day, you’ll install a build and the issues will just magically be gone.

Again, thanks for your continuing feedback. That’s what ultimately helped us discover the issue and make sure the right people knew about it.

 

Lee Holmes [MSFT]
Windows PowerShell Development
Microsoft Corporation

Workaround for Add-Member on plain .Net objects

Introduction

While I was fixing bugs, I came across an interesting bug (https://connect.microsoft.com/PowerShell/feedback/ViewFeedback.aspx?FeedbackID=382818) that seemed to have a very simple fix upon first glance. However, after doing some more research, I found out that it was actually very tricky to fix the root cause. If you do the following:

$table = @{ key1="val1"; key2="val2" }
Add-Member -in $table -MemberType NoteProperty -Name test -Value testValue

Now if you pipe $table to Get-Member you will notice that the test property is missing. No matter how many times you repeat the same Add-Member operation, $table seems to be totally unaffected. However, if you access the test property or even a nonexistent property before you use Add-Member, the command will behave correctly.

Why is this happening?

In PowerShell, we create .Net objects as System.Object as opposed to System.Management.Automation.PSObject for performance reasons. This is because every time an object is converted from System.Object to PSObject, PowerShell has to build the metadata information by reflecting on the .Net object. Doing so can introduce unnecessary overhead since not all operations require PSObjects. When you do something with it (i.e. property access), it becomes a PSObject. However, when you pass a variable ($table) bound to an Object to a cmdlet such as Add-Member, the cmdlet internally converts the bound object into a PSObject. This effectively creates a copy of the original object and anything done to the PSObject is not reflected on the input object.

How can we work around it?

We are hoping to fix the root cause in the next release. However, the workaround is actually quite simple. Since Add-Member is able to emit the modified object if the –PassThru flag is specified, all you have to do is assigned the object back to your initial variable.

$table = Add-Member -in $table NoteProperty Test "Test property" –PassThru

Tianjie (James) Wei [MSFT]
Software Design Engineer
Windows PowerShell Team

Quick, Dirty, Super-Useful Scripting

Last weekend I installed the super-awesome W7 Ultimate on all the machines at home.  This weekend I decided to install the XP Virtual mode download.  I started to do this and noticed that it was 500MB.  That is large and is going to take a long time FOR EACH PC I have.  One of the reasons I got the Ultimate SKU is that it has BranchCache.  This is EXACTLY what Branchcache was designed to do.  One PC downloads something and puts it into a distributed cache and then when the other PCs go to download it, they get it from their peers instead of from the internet (given the way my son reacts when my downloads affects the network and  his ability to kill Nazi Zombies, I’m motivated to minimize the usage of the network :-) ).

That sounds great but the Branchcache is not enabled by default so you have to set it up.  I was doing this and it was a pain in the butt so I decided to experiment with a quick and dirty script and I LOVE the results so I thought I would share.

The issue is that they way you configure Branchcache is with NETSH.  The problem with that is that NETSH isn’t remotable.  I was going back and forth between machines trying things out.  I gave myself a dopeslap and I realized what I was doing and established a remote PowerShell session to the machines.  For a while I was doing Enter-PSSession which gives you an interactive session to the remote machine.  That was great but I have more than one machine so I either had to switch machines or have a couple of windows open.  Then I decided I would use Invoke-Command.  I created a remote connection to all the machines and then collected them in a variable $s and used ICM.

PS> $s = GSN
PS> icm $s {netsh branchcache show localcache}

That worked great but it was a little clumsy to work with so I decided to write a quick-n-dirty function to make my life better.

function b { icm $s -ScriptBlock $([scriptblock]::create("netsh branchcache $args "))}

Notice that I’m not using VERB-NOUN.  Why should I?  I’m after FAST (minimal typing) and this is a throw away function.  “B” is perfect.

Notice that I didn’t declare parameters.  Why should I?  I’m going quick.  I need it to work but I don’t need it to be formal.

Notice that I use positional parameters and aliases?  Why not? 

Now what I’m able to do is:

PS> b show localcache
PS> b set service mode=DISTRIBUTED

<UPDATE>
I realized from the comments that I didn't deliver the punchline.  The WHOLE point was that the command is going to run on ALL the machines!  THAT's the crazy wonderful part of it.
</UPDATE>

I haven’t got Branchcache working yet but I’m am zooming and having a blast.   We spend a lot of time talking about best practices and formal scripting.  That is all super great and super important but there is NOTHING wrong with quick-n-dirty scripting for adhoc functions.  The fact that we designed it so that you can do both with PowerShell is a source of great pride.

GOD I LOVE POWERSHELL!

Experiment!  Enjoy!  Engage!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Sending Automated emails with Send-MailMessage, ConvertTo-HTML, and the PowerShellPack’s TaskScheduler module

On October 15th I released a large collection of scripts called the PowerShellPack.  The PowerShellPack has tons of PowerShell V2 scripts that can be used to do all sorts of fun and practical things.  Today, we’ll show how to use a module in the PowerShell Pack to schedule sending a daily automated email with information about the installed programs on a given system.

Turning the output of a PowerShell script into an automated email is a snap in PowerShell V2, thanks to a nifty new cmdlet called Send-MailMessage.  Send-MailMessage sends out emails with the credentials of the current user (or an arbitrary user) and an SMTP server.  Send-MailMessage can send HTML emails by using the –BodyAsHtml switch, and ConvertTo-HTML can take the output of a cmdlet and turn it into an HTML chunk.  If the email needs some introduction and a signature, you can always use ConvertTo-HTML’s new –PreContent and –PostContent parameters.

Here’s a quick chunk of script that will send the email message once.  Notice that instead of having a very long line with a lot of parameters, I keep the parameters to Send-MailMessage in a Hashtable and use Splatting to provide them to Send-MailMessage

            $messageParameters = @{                        
                Subject = "Installed Program report for $env:ComputerName.$env:USERDNSDOMAIN - $((Get-Date).ToShortDateString())"                        
                Body = Get-WmiObject Win32_Product |                         
                    Select-Object Name, Version, Vendor |             
                    Sort-Object Name |             
                    ConvertTo-Html |                         
                    Out-String                        
                From = "Me@MyCompany.com"                        
                To = "Me@MyCompany.com"                        
                SmtpServer = "SmtpHost"                        
            }                        
            Send-MailMessage @messageParameters -BodyAsHtml                        

Now that we've got that chunk of code down, let's go ahead and make sure that any problems we encounter get put into a file somewhere.  I can do this by setting one of PowerShell’s magic variables $ErrorActionPreference = “Stop”, and adding a try/catch around all of my code:

        $ErrorActionPreference = "Stop"                        
        try {                        
            $messageParameters = @{                        
                Subject = "Installed Program report for $env:ComputerName.$env:USERDNSDOMAIN - $((Get-Date).ToShortDateString())"                        
                Body = Get-WmiObject Win32_Product |                         
                    Select-Object Name, Version, Vendor |             
                    Sort-Object Name |             
                    ConvertTo-Html |                         
                    Out-String                        
                From = "Me@MyCompany.com"                        
                To = "Me@MyCompany.com"                        
                SmtpServer = "SmtpHost"                        
            }                        
            Send-MailMessage @messageParameters -BodyAsHtml                        
        } catch {                        
            $_ |                         
                Out-File $env:TEMP\ProblemsSendingHotfixReport.log.txt -Append -Width 1000                        
        }

Finally, I’ll just go ahead and use the TaskScheduler module from PowerShellPack to make sure the email arrives every day.  To do this, I’ll need to download the PowerShellPack to the machine I’ll be scheduling the task on.   Scheduling a task with the PowerShell Pack involves a short pipeline:  Ours will look something like:

New-Task |            
    Add-TaskAction -Script {            
        # Our Emailer Here            
    } |            
    Add-TaskTrigger -Daily -At "9:00 AM" |             
    Add-TaskTrigger -OnRegistration |             
    Register-ScheduledTask "DailyHotfixReport"                

Piece of cake, right?  In our case, we’re sending an email at 9 AM every day (and when the task is registered) with the output of a simple cmdlet, but I could also use this to run a more complex task, and I can play around with the different trigger types to send the emails whenever I’d like.

Here’s the full script:

 

New-Task |                        
    Add-TaskAction -Hidden -Script {                        
        $ErrorActionPreference = "Stop"                        
        try {                        
            $messageParameters = @{                        
                Subject = "Installed Program report for $env:ComputerName.$env:USERDNSDOMAIN - $((Get-Date).ToShortDateString())"                        
                Body = Get-WmiObject Win32_Product |                         
                    Select-Object Name, Version, Vendor |             
                    Sort-Object Name |             
                    ConvertTo-Html |                         
                    Out-String                        
                From = "Me@MyCompany.com"                        
                To = "Me@MyCompany.com"                        
                SmtpServer = "SmtpHost"                        
            }                        
            Send-MailMessage @messageParameters -BodyAsHtml                        
        } catch {                        
            $_ |                         
                Out-File $env:TEMP\ProblemsSendingHotfixReport.log.txt -Append -Width 1000                        
        }                        
    } |            
    Add-TaskTrigger -Daily -At "9:00 AM" |                        
    Add-TaskTrigger -OnRegistration |                         
    Register-ScheduledTask "DailyHotfixReport"

That wasn't bad, was it?  It took only 24 lines of PowerShell script to create a schedule task that emails me a fairly detailed report of all of the installed programs on the machine. As you can see, PowerShell V2 makes sending automated emails a snap, and the PowerShellPack makes scheduling this or any other script on a regular basis a piece of cake.

Hope this Helps,

James Brundage [MSFT]

Windows Management Framework is here!

Windows Management Framework, which includes Windows PowerShell 2.0, WinRM 2.0, and BITS 4.0, was officially released to the world this morning. By providing a consistent management interface across the various flavors of Windows, we are making our platform that much more attractive to deploy. IT Professionals can now easily manage their Windows XP, Windows Server 2003, Windows Vista, Windows Server 2008, Windows 7, and Windows Server 2008 R2 machines through PowerShell remoting – that’s a huge win!

You can download the packages here: http://go.microsoft.com/fwlink/?LinkID=151321

 

Lee Holmes [MSFT]

Tonight is the Virtual Launch Party @ PowerScripting Podcast

Tonight is the night! 

I was super happy when we shipped V1 of PowerShell.  It started the journey.  That said, V2 is the release that we really wanted to release. 

Today Windows 7 is publicly available and every version has PowerShell V2 in it. 

Tonight – we party!

I’ll be cracking a beer with Hal Rottenberg and Jonathan Walz (hosts of the PowerScripting Podcast) in a PowerShell V2 Virtual Launch Party tonight at 9:30 PM EDT (GMT-4). 

For more details and info on how to join us go HERE.  I’m looking forward to seeing you.  Note, you can always watch the podcast after the fact but if you join, you can make comments and ask questions in the chat room – lots of fun.

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

PowerShell V2 Virtual Launch Party

I’ll be joining Hal Rottenberg and Jonathan Walz (hosts of the PowerScripting Podcast) in a PowerShell V2 Virtual Launch Party this Thursday, Oct 22nd, 9:30 PM EDT (GMT-4). 

For more details and info on how to join us go HERE.

Hmmm, I wonder if it is BYOB… :-)

Experiment!  Enjoy!  Engage!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Announcing: Open Source PowerShell Cmdlet and Help Designer

http://www.codeplex.com/CmdletDesigner

During the development of Windows 7, most cmdlet design and help authoring in Microsoft went through an internal tool called the “Cmdlet Designer.”

cmdlet_designerThe Cmdlet Designer makes it much easier for teams to concentrate on the design, naming, and consistency of their cmdlets, while also guaranteeing name registration and collision avoidance across Microsoft.

To sweeten the deal, it offers:

  • Integrated help authoring
  • Efficient bulk operations (parameter and cmdlet cloning)
  • Generation of cmdlet code
  • Full scripting support
  • Automatic code-spec comparison and testing
  • Role-based security, history logging, and more.

So why blog about it? Because it’s now yours!

We just posted the entirety of the Cmdlet Designer, its source code, design specification, and deployment guide to http://www.codeplex.com/CmdletDesigner under the most permissive Microsoft Open Source license, the Microsoft Public License (MS-PL).

Architecturally, the Cmdlet Designer offers a reference implementation to benefit developers as well:

  • UI on top of Cmdlets
  • Script-based UI extensibility
  • Cmdlet / Webservice interaction
  • Role-based security, with a trusted subsystem implementation

Download, and enjoy!

 

Lee Holmes [MSFT]
Windows PowerShell Development
Microsoft Corporation

Introducing the Windows 7 Resource Kit PowerShell Pack

Since I work on the PowerShell team, I’ve been lucky enough to get a couple of years jump start on producing PowerShell V2 scripts and modules.  With every new script I write in V2 I get more and more amazed by the possibilities in PowerShell.  I’ve discovered how to do many cool things that, as some of my colleagues outside of the PowerShell team have put it, have showed them the Power of PowerShell.

At each CTP of PowerShell, I’ve tried to share this power of PowerShell here on this blog.  Thanks to Mitch Tulloch (the main author of the Windows 7 Resource Kit) and Ed Wilson (the Scripting Guy), I was able to collect some of my V2 modules for the companion CD of the resource kit.  This collection of scripts became know as the Windows 7 Resource Kit PowerShell Pack.

Today, the Windows 7 Resource Kit should be available in stores, and the PowerShell Pack is available for download on code gallery.

The PowerShell Pack contains over 800 scripts in 10 different modules.  Here’s a brief overview:

WPK
Create rich user interfaces quick and easily from Windows PowerShell. Think HTA, but easy. Over 600 scripts to help you build quick user interfaces.  To get started learning how to write rich WPF UIs in script, check out Writing User Interfaces with WPK.

IsePack
Supercharge your scripting in the Integrated Scripting Environment with over 35 shortcuts.

TaskScheduler
List scheduled tasks, create or delete tasks

FileSystem
Monitor files and folders, check for duplicate files, and check disk space

DotNet
Explore loaded types, find commands that can work with a type, and explore how you can use PowerShell, DotNet and COM together

PSImageTools
Convert, rotate, scale, and crop images and get image metadata

PSRSS
Harness the FeedStore from PowerShell

PSSystemTools
Get Operating System or Hardware Information

PSUserTools
Get the users on a system, check for elevation, and start-processaadministrator

PSCodeGen
Generates PowerShell scripts, C# code, and P/Invoke

I’ll be posting a lot more about these modules in the next weeks, both here and on Channel9, but you can start exploring the modules now by checking out the PowerShellPack on code gallery.  I will also be tweeting some cool tidbits about the PowerShell Pack under the tags: #PowerShellPack, #WPK and #IsePack

I’ll also be on Hal Rotenberg’s PowerScripting Podcast tonight talking about the PowerShell Pack.

Hope this helps,

James Brundage [MSFT]

Quick Note: The MSI was updated at ~ 4:30pm on day of release. If you downloaded it before this time, please download the MSI again.

Posted by PowerShellTeam | 13 Comments
Filed under: , ,

Understanding the Feedback Process

During the development of any product, the vision for the upcoming release is driven by the desire to help as many customers in the most effective way possible.

One of the interesting aspects of a release is balancing the effort you spend on different aspects of that project:

  • New features and broad changes designed to address significantly new customer scenarios.
  • Feature updates and incremental changes designed to improve scenarios already (or partially) addressed by existing features.
  • Bug fixes designed to address functionality that doesn’t work as designed.

When weighing these factors, a critical factor is customer importance. Aggregate customer needs (and user research) heavily influence the first bucket, so the customer impact there is clear. The second two buckets come by way of direct customer feedback and bug submissions: http://connect.microsoft.com/powershell and pose a more difficult problem.

When looking at a piece of feedback in isolation, the customer impact is difficult to judge. While it is clear that the original feedback submitter ran into the problem, are they the only one to have run into it? Clearly, bugs and feedback that have broad customer impact are easy decisions to make when your goal is maximum value for the customer. Conversely, bugs and feedback that have little customer impact shouldn’t disrupt the features, feedback items, and bug fixes that do.

We’ve updated our Connect site to make this process as clear as possible:

clip_image002

If you are impacted by an issue, following those directions is the most constructive way to make your feedback known.

The key point here is that customer impact drives our decisions. You are the key for helping us determine customer impact. A vote for an existing bug or feature request is just as impactful (if not more!) than the original submission.

If you are impacted by an issue or have a suggestion, please visit http://connect.microsoft.com/PowerShell.


Lee Holmes [MSFT]

What's Up With Command Prefixes?

We like to say that PowerShell uses Verb-Noun naming.  If we were accurate, we would say that PowerShell uses Verb-PrefixNoun naming.  For instance: Get-WinEvent .  WIN is a prefix for Windows.  Every now and again people look at this and ask “what's up with command prefixes ?!?”.  Actually, the question usually comes from teams that are implementing Cmdlets and don't understand why they have to use prefixes.  They sometimes feel like their noun is unique or they want to own the noun or they think they may get reorganized into a different group so they are not sure what a good prefix would be (hey - is a legitimate issue for some teams – it just has nothing to do with the customer.)

Prefixes mitigate naming collisions. 

Consider the case of the recent cmdlet Get-WinEvent which was developed by the Windows Diagnostics team (the same great team that brought you the super awesome W7 troubleshooting [which uses PowerShell heavily]).  What would've happened if they'd just called it Get-Event.  The PowerShell team needed to use the name Get-Event Cmdlet (I'll explain why it doesn't use a prefix later) so without a prefix these two Cmdlet names would collide.  So what happens with a collision?  Well one wins and the other loses.  Specifically, last writer wins.  So if you had a script that uses Get-Event, it is going to use would ever last defined that name.  In other words your script will break. 

(NOTE: For the record – the story is much more complicated that that.  The Diag team used the name “Get-Event” first and we OKed it with them and then sometime later we got crisp about our policy for when PowerShell needs to own generic nouns and made them change it.  It was an unfortunate situation and the diag team ended up “taking one for the team” and doing a bunch of extra work so that we could deliver a great customer experience. We all owe them a big THANK YOU.)

No matter what we do, naming collisions will occur so let's talk about how you deal with that when it happens.  The solution is simple, you use the full Cmdlet name.  Full Cmdlet name?  Yes that's right, every Cmdlet that has a short and a full name.  The names you use all day long are the short Cmdlet names.  The full name Get-WinEvent is Microsoft.PowerShell.Commands.Diagnostics\Get-WinEvent.  That’s right, if anyone comes along and collides with Get-WinEvent, you just go change all your scripts to use Microsoft.PowerShell.Commands.Diagnostics\Get-WinEvent.  OUCH!  Clearly this is an undesirable situation but at the end of the day these things happen so you have to have a solution.  That said, it should be obvious why we want to avoid collisions as much as possible.

Think through the problem. 

  1. There are lots of things that need to be named.
  2. Everything has to have a universally unique name.  This either means a GUID or long human readable name.
    1. e2454d24-a4d9-4d41-b514-7b81f4257b64  vs. Microsoft.PowerShell.Commands.Diagnostics\Get-WinEvent
  3. You want to have short names and use them whenever possible.  In other words you want to avoid having collisions that require you to use the universally unique name.

When we thought through this problem we made some guesses about how many things needed to be named.  It's been many years since we had the discussion but I believe the numbers were something like this:

  1. We expected there'd be hundreds of thousands of Cmdlets in the industry.
  2. A large customer shop might have the 30-50 thousand Cmdlets running on all machines in their enterprise.
  3. Any particular machine might have 1-5 thousand Cmdlets on it.

The key observation here was that we had to minimize the possibility of short names colliding on a particular machine (not a customer site or the industry). 

Verb names are meant to be standard so they're always going to collide - that's a good thing (because it means you can guess which you want to do in your guess will be correct).  So this is really an issue of increasing the Hamming Distance of noun names.  Adding a 2-4 character prefix (indicating the team or product that owns the noun) in front of the noun solves this problem. 

  Chance of Collision
Without a prefix
Chance of Collision
With a prefix
Industry Absolute High
Large IT shop Very High Low
Machine High Very Low

 

NOTE:  The side benefit of using prefixes is that it provides an easy way to find all the commands from a particular source.  For instance, the Active Directory team chose the prefix “AD” so you can type:  Get-Command *-AD* to find all their Cmdlets.

 

So that is the reason why we are hardcore on the guidance to use prefixes in front of your noun names.

 

Oh wait, I promised to tell you why PowerShell sometimes doesn't use the prefix PS in its Cmdlets.  There are three reasons for this:

  1. Writing the code has its privileges.  :-) 
    1. Certain nouns are going to be used all the time and PowerShell is always there (by definition) so we used our unique position to grab some names to deliver a good user experience.
  2. We use generic noun names whenever we provide the framework for other people to plug into. 
    1. We used the name Get-Event because our eventing system is an extensible subsystem that anyone can plug into.  Get-Event then provides a common front end to all those plugins.  This is also the case for JOB, ITEM, etc
  3. We screwed up.
    1. In V2, we used the PS prefix a lot but I don’t think we were as consistent as we could have been.  Certainly this was the case for V1 where there are a number of cmdlets that should have used the PS prefix.  Live and learn.

But I hope this clarifies the importance of prefixing.  As a community it is in your best interest to enforce this standard quite getting grief to those teams and companies that don't adhere to it.

 

Enjoy!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Remoting for non-Admins

Per Østergaard has a great blog entry with all the steps for enabling this HERE.  You’ll want to bookmark this one.  :-)

 

Enjoy!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Select –ExpandProperty <PropertyName>

Most of us are familiar with the traditional use of Select –ExpandProperty <propertyname>.  This takes a the value of an incoming object, enumerates its values and outputs each of those values as a single record on the output stream after adding any properties specified by the –PROPERTIES <propertyname[]> parameter.  An example will help:

PS> gps |Select -ExpandProperty Modules -ea SilentlyContinue |Group ModuleName |Sort Count |Select -Last 4

Count Name                      Group
----- ----                      -----
   58 kernel32.dll              {System.Diagnostics.ProcessModule (kernel32....
   58 msvcrt.dll                {System.Diagnostics.ProcessModule (msvcrt.dl...
   58 KERNELBASE.dll            {System.Diagnostics.ProcessModule (KERNELBAS...
   72 ntdll.dll                 {System.Diagnostics.ProcessModule (ntdll.dll...

 

 

A while ago, Lee Holmes turned me on to another use of –ExpandProperty and I’ve been meaning to blog it ever since.  Have you ever wanted to get just the value for a property from every object?  You’d think you could do this and it would work:

PS> gps *ss |select name

Name
----
csrss
csrss
lsass
smss

 

Sadly, this is not what you want. This gives you a set of objects each of which has exactly one property:  NAME.  What you wanted was a stream of VALUES.  What I’ve always ended up doing was this:

 

PS> gps *ss | foreach {$_.Name}
csrss
csrss
lsass
smss

 

 

This works, it is not too hard but it always sorta pissed me off that I had to do it this way.  Sadly, addressing this never made it above the cut like for V2.  Again – to ship is the choose.  I was complaining about this one day and Lee pointed out that if you specify a scalar property (a property that is NOT a collection) for –ExpandProperty – it gives you exactly what you want.

PS> gps *ss |select -ExpandProperty name
csrss
csrss
lsass
smss

 

SWEET!

Enjoy!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

The Glory of Quick and Dirty Scripting

One of the things I want us to consider doing in the future is to leverage our Universal Code Execution infrastructure to execute any kind of code. For example, imagine that I have some script foo.vbs, I’d like to do the following:

PS>  Invoke-Command –FilePath foo.vbs –computer (cat servers.txt)

I was about to file a record for us to consider this and thought – wait – I bet that there are other commands that take a FilePath need to be updated as well.  The question is – which commands take the FilePath parameter?   As I write this up, I now remember the correct solution to this question.  We all know that you can Get-Help on a command like Invoke-Command

PS> Get-Help Invoke-Command
…….

But did you realize that you can also get help about the parameters of a command?

PS> Get-Help Invoke-Command -Parameter FilePath

-FilePath <string>
    Runs the specified local script on one or more remote computers. Enter the path and file name of the script, o
    r pipe a script path to Invoke-Command. The script must reside on the local computer or in a directory that th
    e local computer can access. Use the ArgumentList parameter to specify the values of parameters in the script.
    When you use this parameter, Windows PowerShell converts the contents of the specified script file to a script
     block, transmits the script block to the remote computer, and runs it on the remote computer.
    Required?                    true
    Position?                    2
    Default value               
    Accept pipeline input?       false
    Accept wildcard characters?  false

 

 

A lot of people know that one but I wonder how many people realized that you can actually omit the command name to find all the commands that use a parameter:

PS> get-help * -Parameter FilePath

Name                              Category  Synopsis                                                                                                                      
----                              --------  --------                                                                                                                      
Invoke-WSManAction                Cmdlet    Invokes an action on the object that is specified by the Resource URI and by the selectors.                                   
Set-WSManInstance                 Cmdlet    Modifies the management information that is related to a resource.                                                            
Invoke-Command                    Cmdlet    Runs commands on local and remote computers.                                                                                  
Start-Job                         Cmdlet    Starts a Windows PowerShell background job.                                                                                   
Out-File                          Cmdlet    Sends output to a file.                                                                                                       
Tee-Object                        Cmdlet    Saves command output in a file or variable, and displays it in the console.                                                   
Set-TraceSource                   Cmdlet    Configures, starts, and stops a trace of Windows PowerShell components.                                                       
Trace-Command                     Cmdlet    Configures and starts a trace of the specified expression or command.                                                         
Start-Process                     Cmdlet    Starts one or more processes on the local computer.                                                                           
Get-PfxCertificate                Cmdlet    Gets information about .pfx certificate files on the computer.                                                                
Get-AuthenticodeSignature         Cmdlet    Gets information about the Authenticode signature in a file.                                                                  
Set-AuthenticodeSignature         Cmdlet    Adds an Authenticode signature to a Windows PowerShell script or other file.                                                  

 

Pretty awesome isn’t it?

 

But here is the deal – I forgot about that when I had the problem so I wrote myself a quick and dirty script that gave me exactly what I needed.  Notice that when I’m writing throw away scripts, I almost allows name them “t” or “t1” or “t2”…   Why? Because its easy to type and I’m throwing the thing away when I’m done.

PS> function t ($p) {gcm -Type Cmdlet  |where {$_.Parameters.$p}}
PS> t filepath

CommandType     Name                                              Definition                                     
-----------     ----                                              ----------                                     
Cmdlet          Get-AuthenticodeSignature                         Get-AuthenticodeSignature [-FilePath] <String...
Cmdlet          Get-PfxCertificate                                Get-PfxCertificate [-FilePath] <String[]> [-V...
Cmdlet          Invoke-Command                                    Invoke-Command [-ScriptBlock] <ScriptBlock> [...
Cmdlet          Invoke-WSManAction                                Invoke-WSManAction [-ResourceURI] <Uri> [-Act...
Cmdlet          New-WSManInstance                                 New-WSManInstance [-ResourceURI] <Uri> [-Sele...
Cmdlet          Out-File                                          Out-File [-FilePath] <String> [[-Encoding] <S...
Cmdlet          Set-AuthenticodeSignature                         Set-AuthenticodeSignature [-FilePath] <String...
Cmdlet          Set-TraceSource                                   Set-TraceSource [-Name] <String[]> [[-Option]...
Cmdlet          Set-WSManInstance                                 Set-WSManInstance [-ResourceURI] <Uri> [[-Sel...
Cmdlet          Start-Job                                         Start-Job [-ScriptBlock] <ScriptBlock> [[-Ini...
Cmdlet          Start-Process                                     Start-Process [-FilePath] <String> [[-Argumen...
Cmdlet          Tee-Object                                        Tee-Object [-FilePath] <String> [-InputObject...
Cmdlet          Trace-Command                                     Trace-Command [-Name] <String[]> [-Expression...

 

 

 

That was the real point of this blog – that sometimes you just want to write a quick and dirty script and that is perfectly OK – you can skip all the best practices and just go go go! 

 

But wait – it get’s better.  When I looked at the output of those 2 approaches, something didn’t seem right so I thought I would do a little more investigation

PS> $x1 = get-help * -param filepath |select -expand name |sort
PS> $x2 = t filepath |select -expand name |sort
PS> compare $x1 $x2

InputObject                                               SideIndicator                                          
-----------                                               -------------                                          
New-WSManInstance                                         =>                                                     

PS> get-help New-WSManInstance -param  f* |select name

name                                                                                                             
----                                                                                                             
File                                                                                                             

 

So what that means is that we have a documentation bug (a benign one but still a bug).  It has documented the parameter as “FILE” when in fact it is “FILEPATH”.

 

 

I gotta tell you – I just LOVE working with PowerShell.  It makes you feel so POWERFUL.  That sounds corny and trite but it’s true!

Go have some fun!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

More Posts Next page »
 
Page view tracker