Learn about Windows PowerShell
Summary: Microsoft Scripting Guy, Ed Wilson, talks about the need to use .NET Framework classes from within Windows PowerShell code.
Microsoft Scripting Guy, Ed Wilson, is here. The Scripting Wife and I had a great meeting with the Windows PowerShell Users Group in Charlotte, North Carolina. It was a script club format, so there was no set agenda, nor was there a formal presentation. This provided a great chance to talk to people, find out what they were working on, and in general, have a lot of fun. Speaking of a lot of fun, make sure you check out the first ever Windows PowerShell Saturday that will be held in Columbus Ohio on March 10, 2012. This event, limited to 100 persons, is nearly sold out. So you need to hurry if you want to take advantage of a unique opportunity to network with a great bunch of Windows PowerShell people. The Scripting Wife and I will be there, as will an all-star group of other Windows PowerShell luminaries.
One of the questions I had from a group member was about using the .NET Framework from within Windows PowerShell. I have written quite a bit about using .NET Framework classes from within Windows PowerShell. Those blogs cover working with methods, discovering properties, finding documentation, and other bread-and-butter types of issues.
One of the things that I have not talked much about is why one needs to use .NET Framework classes inside of Windows PowerShell. Keep in mind, that as a best practice, I recommend using a native Windows PowerShell cmdlet when it exists—unless there are compelling reasons for not doing so. For example, I have seen a number of Windows PowerShell scripts (for example, when I was grading the Scripting Games submissions for the last three years), where participants use .NET Framework classes when there is a perfectly good Windows PowerShell option available. Here are two equivalent commands:
In the image that follows, I run both commands, and you can see that the output is essentially the same. (That the time indicated is three seconds later is a feature of the fact that for some reason it took me three seconds to run the second command.)
I can use the GetType method to verify that both commands return a System.Datetime object. These two commands are shown here.
PS C:\> ([datetime]::now).gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True DateTime System.ValueType
PS C:\> (Get-Date).gettype()
Because both commands return a DateTime .NET Framework class object, there is no advantage to the first command. Some may ask, what does the first command actually do? The command that appears here calls the static DateTime.Now property from the System.DateTime .NET Framework class.
The static Now property returns a System.DateTime object that represents the current local date and time—this is the same thing that the Get-Date cmdlet does. The difference? Well, the command Get-Date is much easier to read than [datetime]::now. So why do people use the static Now property? Well, I am convinced there are two reasons.
The first reason, I feel is legitimate: .NET developers may not know that the Get-Date cmdlet exists, and they have learned that to call a static member, they put the class name in square brackets and use the double colon before the member name. As I said, this is completely legitimate. Windows PowerShell is flexible enough, that you can write Windows PowerShell code as if it were C#, VB.NET, or even as if it were VBScript or Perl. Anything that helps you get the job done is fine with me—after all, Windows PowerShell is simply a tool for the vast majority of network administrators.
The second reason is more insidious. I think there are some people who simply want to use .NET Framework classes because they think it is cool, and that it makes the code appear to be more complex. Maybe they are attempting to impress their coworkers or their boss. Maybe they think that if people see things like Get-Date in a Windows PowerShell script, they will realize how easy Windows PowerShell is to use and to learn, and then they will no longer have the mantle as the “PowerShell guru.” I am all for job security, but I prefer to ensure job security by helping others maximize their potential. I prefer to show people how easy it is to use Windows PowerShell to become more productive than to attempt to obscure that fact by deliberately writing confusing code.
What do you think? I would love to hear from you.
Tomorrow I will discuss those occasions when I think it is OK to use .NET Framework code. There are times when it makes perfectly good sense.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at firstname.lastname@example.org, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
I think there is an element of obfusticaton/job insecurity, in using .net classes where cmdlets would do fine. Cmdlets are easier to read, and IMO, should be used wherever possible instead of .net static methods.
I think another reason people use .net classes is ignorance: They somehow percieve using the static methods as being more "real" than using the cmdlet "wrappers". As you have demonstrated, the cmdlets also create "real" .net objects.
I actually saw something like this in a script:
Thanks for the posting ED.. actually its also true that "some peoples comples there scripts" using .net rathe than keep it simple..
The last reasoning you've mentioned is pretty scary... Most of PowerShell geeks I know of are eager to share/ encourage others to use PowerShell whenever possible. If there are people who make their code look complicated to make sure nobody else can read it... I pity them. IMO they are also shooting themselves in the foot. One day they will open this "script" and will fail to read it at 3 AM in the middle of the fire...
For myself, in the instance of Get-Date, I just forget the cmdlet is even there.
For myself I find myself using [DateTime]::Now, which is longer and, as noted, perhaps less clear. On the other hand there is also
which are harder to achieve with Get-Date.
[dissent}::WhyOhWhy('Do they exists')
If the designers of PowerShell did not intend for use to use Net Classes direct then why did they provide type accelerators like:
[console], [adsi], [wmi], [wmiclass] etc.
These are all just shorthand for basic Net Classes. Tey are not defined in Net classes but are explicit additions to PowerShell. Onlky PowerSHell has Type Accellerators.
If a CmdLet does the job then it will likely make your task easier but use of type accellerators and net classes can allow us access to subtleties that are impossibe to obtain with CmdLets alone.
I confess that I tend to use Net Classes out of shear ignorance. I wnat to manage AD from a workstation that has no ActiveDirectory snapin support such as a WIndows XP machine. In my ignorance I can only see how to effectively do this with [adsi] and [adsisearcher]. This forces me to have to use Net Classes to keep the code the sa,e on all machines.
Net classes do not just expose static methods. They also expose properties and enums and can be used to create instances such as:
No - I insist that easy access to Net Classes is intentional.
I do agree that CmdLets can be much easier to use and do add functionality to the classes. Get-ADUser acts like a combination of [adsi] and [adsisearcher]. Most of the time it is more convenient and more useful.
Just a couple of dissenting thoughts to antogonize discussion.
Not so hard:
I think there is another aspect we're missing, which is not so negative - Innocence. I for one learned how to code with C++ and then C#, and I might use those without knowing there is a cmdlet equivalent. Of course, when I do discover the "PowerShell Way" I try to convert to using that, but I can't know all things without first learning of it. That's another reason why this site and the articles is so great and important! I learn every day.
And as some of you pointed out .Net is native to PowerShell, so always using the cmdlets over raw .Net classes is nothing more than a subjective value statement. I agree that reading PowerShell cmdlets is easier, but I find instances where using the raw class is better for automation, such as when I build scripts to access AD. The AD cmdlets are great when you have the AD module installed, but most of my computers do not have that. Therefore, I tend not to use it in any of my formal scripts because I value portability across my systems over ease of reading. Conversely, I'll use the AD module cmdlets for one-off queries, or if I know I'll only run a script on computers with the AD module.
> Get-date #[DateTime]::Today
These are not the same, [DateTime]::Today includes a zero time (ie. midnight), Get-Date is the current time, so
$someDate -lt [DateTime]::Today
is true if $someDate is yesterday or before.
Hi Ed, Hi @all
to cut things short: If you can: make the best out of both worlds!
There are no scary things involved!
PS is based on the Net 2.0 framework, it won't be here, without it!
Use cmdlets if appropriate and well known!
Use .Net 2.0 if you can and if nothing else is knwon to be available the PS way ...
#rjcox - sorry I flomoxed that one. Her is the correct version:
Saturday, February 11, 2012 12:00:00 AM
This is a key line in the article: "Keep in mind, that as a best practice, I recommend using a native Windows PowerShell cmdlet when it exists—unless there are compelling reasons for not doing so." In my mind this extends beyond just using static .Net methods but also using .Net classes to build objects that perform the same job as existing PowerShell cmdlets.
Sometimes it is a lack of education when a .Net method is used instead of a cmdlet that can be helped just by advising the individual of the correct PowerShell cmdlet. A number of examples I have seen recently are folks using System.Net.Mail.MailMessage instead of Send-MailMessage and it was just a case of not knowing that this was available. A quick comment on their blog letting them know about this and now they are using the cmdlet in future scripts. Other examples I have seen are using .Net for "pinging" a machine when Test-Connection works.
Other times it might be because of the background of the person writing the script where they have a heavy background as a .Net developer and just simply fall into the habit of what they use the most. It is just like a vbscripter who first steps into PowerShell and wants to continue to write code in a "vbscript way". Sometimes it just takes a little bit of time to adjust to a PowerShell frame of mind when writing the code.
In the case of dates, using a cmdlet is the preferred way to go. But in the case of downloading a webpage, at least in V2, using the .Net method (Net.WebClient) is the obvious best choice to work with until V3 goes RTM and then you can use something like Invoke-WebRequest to accomplish this. When working with Active Directory, it all depends on what you have available in your environment at the time. If you have access to the AD module, then you use that, otherwise you make use of the .Net methods in the way of the type accelerators ([adsi],[adsisearcher]) to accomplish your goal.
Just my 2 cents...
I see a lot judgemental statements in the posts - I myself really don't see a big difference between using [datetime] static property or get-date cmdlet. It could be just a habit, it could be just whatever came up first in googling when a beginner didn't know how to get current time, then he/she sticks to that method. Either way, big deal.
I will defend the blog. It has begun some good discussion. In programming and in all technical pursuits it is alwasy worthwhile to debate the pros and cons of any widely used methods. I feel we can all learn something from this kind of discussion.