Quantcast
Channel: Hey, Scripting Guy! Blog
Viewing all 3333 articles
Browse latest View live

PowerShell Mini-Scripting Games 2014: Problem 5

$
0
0

Summary: Here is the final problem in Windows PowerShell Mini-Scripting Games 2014.

Microsoft Scripting Guy, Ed Wilson, is here. This is it. It is day five of the Mini-Scripting Games. Next week, I will share solutions to the questions (PowerTips) and problems from this week.

Problem 5 description

Your manager has tasked you to help a junior admin with a script. It appears that the junior admin wants to solicit input from the user when the script is running. Then based on the input from the user, the script will  do something else.

Task

You only have to write a piece of sample code that will solicit input from the command line, and then take action based on the input. Your manager does not want you to write the script for the junior admin, only to help him over the hurdle.

Hint: Depending on your situation, you may want to consider limiting the input, or testing the permissible input to provide a more robust example. You might even consider creating a bit of error checking to help with improper input.

This is all of the events for the Windows PowerShell Mini-Scripting Games 2014. Join me tomorrow for a special post from the Scripting Editor. It is way cool, and it provides special insider information about the Hey, Scripting Guy! Blog. Hey, it is like a backstage pass…only better.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 


PowerTip: Mini-Scripting Games 2014 Question 5

$
0
0

Summary: Here is the fifth short-answer question for Mini-Scripting Games 2014.

Hey, Scripting Guy! Question You created a constant variable in your Windows PowerShell console.
           Now when you attempt to delete the variable, you get an error message.
           How can you remove a constant variable?

Hey, Scripting Guy! Answer Answer to be posted next week!

The Scripting Editor Tells All

$
0
0

Summary: Dia Reeves, aka the Scripting Editor, has some fun talking about working on the Hey, Scripting Guy! Blog.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a guest blog from my editor, Dia Reeves...

Photo of Dia Reeves

Hello to all you Windows PowerShell scripters and fans of the Hey, Scripting Guy! Blog! I have been editing and publishing this blog since 2011, and I thought it would be fun to write a post that helps you understand my part in our process and shares some stats about our blog.

Maybe I will let Ed edit and publish my post!

Well, maybe not...

Although I have been a technical editor for 14 years, I don't mind admitting that I do not consider myself very technically oriented. In my only programming class, I sat in horror as all the other students celebrated with glee when "Hello World!" appeared on their screens. I finally summoned the instructor to help me. "You're missing a comma...See? Right here," he drawled.

Are you kidding me? Missing a tiny little comma? What kind of crazy person would want to do this all day, every day? (...she asked, winking at all you dev dudes and dudettes.)

Of course, the irony is that I now thrive on missing and misplaced commas...

misused semicolons...

misspelled words...

misplaced modifiers...

Stop me!

So I chose the path of an editor, not a dev.

The true value of an editor is mysteriously hidden behind the scenes. My main goal is to make writers look good with no one knowing I was there. For fun, I marked up a paragraph from a blog post so you can see the types of changes I make without the writers ever knowing (sshhhh):

Image of text

This example simply needed a little punctuation and a little clarification, but publishing it as written would not have been the best plan.

Hey! I have a great idea! What if we could package simple issues such as those in a Windows PowerShell command? No one would ever need an editor again. Enter the best cmdlet ever, Get-Editor, and its nifty parameter -ClearConciseConsistent:

PS C:\> $edit = Get-Editor -ClearConciseConsistent

But alas, such a command could never replace the total logic in an editor's head. What the heck am I looking for aside from proper spelling, capitalization, and punctuation? The editor's head sees fascinating factoids such as these:

  • Blog writers like to use "so" and "now" a lot. I kill hundreds every year.
  • Have we said anything that could possibly offend anyone in the world?
  • Writers like to use "just" when they really mean "simply" or "only."
  • Do you know that our style dictates using "following" or "under" instead of "below"?
  • "Since" has a different meaning than "because, and "once" does not mean "when" or "after."
  • Although "PowerShell" is common terminology amongst the community, we are still obligated to use "Windows PowerShell" in our documentation.
  • Who else really cares if that S in PowerShell is capped?
  • Are the cmdlets, parameters, and objects formatted correctly?
  • Does every sentence make sense? Sometimes writers ramble, and with many readers in countries where English is not the first language, the text needs to be clear and concise.

If all this sounds very mundane and unimportant to you, it should! Most of this is stuff that writers (or readers) should not have to concern themselves with...

One moment, please...

"Yes, Ed?"

"This just goes to show why having an editor is a good thing. Even when editors are writing, they can accidentally end a sentence with a preposition from time-to-time."

"Thanks for the excellent feedback, but I think I'll exercise my writer's prerogative and leave it."

Now where was I? Oh, yes...A writing hat is far different than an editing hat. Writers should feel free to ramble, knowing that a good editor will sort it out behind them.

Traditional writing and editing practices are a back and forth dance. The writer submits a document and the editor sends it back full of suggested changes. The writer takes the good and ignores the bad, then sends it back to the editor with more suggestions. And around it goes...

This collaborative effort is so much fun! But it is very time consuming, and things are moving fast in the computing world, including the world of Windows PowerShell. We post a blog and a PowerTip every day of the year, so it is easy to see that this traditional format will not work. Because we have worked together for several years and Ed trusts me (Ed added that phrase), in our model, Ed tosses me an article, and I edit and publish it. No reviews involved.

Editors also act as the writer's first reader. I provide a fresh set of eyes for a document that has been re-read and rewritten to ad nauseam. For example, check out this little surprise that I found in a script we were going to post. Every one of you dev types knows that the writer was exhausted by the time he wrote this, and he exchanged the values for .People and .Eater in the output:

Image of code

He owes me dinner for catching that one.

Here is the user interface of the Telligent tool that I use to publish our blog:

Image of tool

It looks straight-forward enough, right? I dump in the text from the edited Word doc and the tool magically spits out a webpage. But if everything is not input appropriately, the formatting can be funky and the images won't be sized correctly. Don't even mention that the publication date might not be set correctly, or that clicking an improperly set link can totally engulf the screen with a new site.

Ed is a brilliant writer and he is taxed with coming up with two posts per day. Why should he have to deal with this tool? Luckily, I love messing with it. So he can focus on writing.

Did you know that publishing the Hey, Scripting Guy! Blog 365 days a year was originally classified as an "experiment"? No one knew if there would be interest in a daily blog about Windows PowerShell or if there would be enough content to write about on a daily basis.

But as the world of Windows PowerShell grows, so does the information Ed shares in this blog. In fact, everything is growing so fast that he has enlisted the help of many guest bloggers. I have been lucky to also edit the works of brilliant authors such as Sean Kearney, Richard Siddaway, Boe Prox, the Scripting Wife, and a variety of other Honorary Scripting Guys and guest bloggers.

The Hey, Scripting Guy! Blog has grown to be the number 1 blog on MSDN and on TechNet. Here are some interesting stats from our July 2014 statistics compilation:

  • We had over 990,000 page views this month.
  • In January 2014, we had 2,096,293 page views!
  • The most popular article for the last 12 months is Use PowerShell to Replace Text in Strings. Even though it was published in March 2011, it received over 109,000 hits between January and July this year. I imagine that after this post publishes, it will have even more!
  • Close to 50% of our readership comes from outside countries where English is spoken as the first language.
  • Our unique visitor stat is up by 80,000 readers since this month last year.

Of course, I would like to attribute this growing popularity to excellent editing, but the main truth is that Ed has found a perfect formula for teaching people about Windows PowerShell in easy-to-read snippets and examples. I think we can conclude that our "experiment" has been successful.

If you are thinking that one reason for me writing this post is to illuminate the value of editing, you're right! A writer without an editor is like a doctor without a nurse, an anchorwoman without a cameraman, a rock band without a drummer. In today's world of instant publishing, anyone can write and publish a blog, but will people want to continuously read it? It needs to be clear, concise, and consistent. And guess what? Those are the three tenants of good editing!

~Dia

Thanks, Dia! This was fun.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

PowerTip: Change Value of Element in PowerShell Array

$
0
0

Summary: Learn how to change the value of an element in a Windows PowerShell array.

Hey, Scripting Guy! Question How can I use Windows PowerShell to change the value of the first element in an array?

Hey, Scripting Guy! Answer Use the Set method and specify the element number and the new value, for example:

PS C:\> $a = 1,2,3,4,5

PS C:\> $a.Set(0,50)

Weekend Scripter: Many Paths to a PowerShell Command

$
0
0

Summary: Microsoft Scripting Guy Ed Wilson talks about using different types of commands in Windows PowerShell.

Microsoft Scripting Guy, Ed Wilson, is here. A while ago, someone said there must be 50 ways to stop a process in Windows PowerShell. Although I am not certain that number is entirely accurate, it probably comes close. The great thing about all the different ways of doing things in Windows PowerShell is that it permits us to meet Windows PowerShell from our current backgrounds. This enables us to leverage as much previous knowledge as possible.

For example, suppose you spent years as a .NET developer, and you are very knowledgeable about .NET development. When you learn that Windows PowerShell is built on .NET, is basically a .NET application, and uses .NET in the background, you can begin to use your prior knowledge to quickly begin writing Windows PowerShell script.

For example, to get the current date, I can use the nowstatic property from the System.DateTime object. It would look like this:

[datetime]::now

In addition, when I learn that Windows PowerShell also returns objects, I can capture that returned System.DateTime object in a variable and perform date manipulation by using standard .NET methods from the DateTime class.

That is all good. But eventually, you may want to learn that you can just as easily obtain the current date and time (as a DateTime object) by using the Get-Date cmdlet. And that is part of the point. You do not have to learn everything about Windows PowerShell immediately. You can use whatever previous knowledge you have. Then if you want to update to using "native PowerShell," you can as you have time.

The whole thing about Windows PowerShell is to make the job easier. It is not that Microsoft is “forcing me to learn Windows PowerShell,” but rather that I want to use Windows PowerShell because it will make the job easier.

Like everything, there is a learning curve that you need to go through. Let's think about the process of removing a bolt. There are lots of tools that can do this. I can use a crescent wrench, and it will remove lots of different size bolts. But of course, the crescent wrench is not really the best tool for the job because it has a tendency to slip and to round over edges.

Maybe the next tool to consider would be a combination wrench. Now here is a learning curve. I need to be able to pick out exactly the right wrench. No longer can I sort of get it right—I need to be precise. In addition, there are two ends on the combination wrench, and I need to learn what each end is good for. When I make it past this learning curve, I can start to do a better job of removing bolts.

But then someone comes along with a ratchet and socket system. There are multiple sizes of ratchets and hundreds of sockets, extensions, swivels, and even breaker bars. Dude, talk about a learning curve. I just went from one crescent wrench, to 13 combination wrenches, to hundreds of pieces in the socket set.

Now my boss comes along and says he has a couple of air ratchets and an impact wrench. Now we have air compressors, hoses, fittings, oil for wrenches (some of which are oil-less).

Dude, the list goes on. But each new tool brings me further up-the-line in terms of precision and automation.

One problem with so many different ways to do something is that it can complicate learning among people who are just beginning. So it is with learning Windows PowerShell. When new learners find three different examples, all purporting to show how to do something, and all three examples show completely different things, it can be confusing. But it can also be useful because I now have three ways of doing something, and I can simply choose the one that makes sense for me. The challenge is to move beyond copying examples so you can discover how and why the examples actually work.

There are those who try to be “pure Windows PowerShell” and who try to only use the “PowerShell way” of doing things. Surprisingly, maybe the Scripting Wife falls into this category. For her, the decision was to learn the “PowerShell way” of doing things and to avoid confusion that may crop up by doing things the .NET way, the WMI way, or the VBScript way. It makes sense to an extent.

For me, I simply prefer the easiest way of doing things. For me, easiest actually translates to the first thing I think of to solve my problem. In this manner, I am not a Windows PowerShell purist.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Find PowerShell Canonical Aliases

$
0
0

Summary: Find Windows PowerShell aliases that are read-only and available in all scopes.

Hey, Scripting Guy! Question How can I produce a list of Windows PowerShell aliases that are read-only and are available in
           all Windows PowerShell scopes?

Hey, Scripting Guy! Answer Use the Get-Alias cmdlet to produce a list of aliases, filter on aliases that have an option of read-only,
           and select the name, definition, and options:

Get-Alias | Where options -match 'readonly' | select name, definition, options

PowerShell Mini-Scripting Games 2014: Answer 1

$
0
0

Summary: Here is the answer to Problem 1 in Windows PowerShell Mini-Scripting Games 2014.

Microsoft Scripting Guy, Ed Wilson, is here. Here is an answer to Problem 1 in Windows PowerShell Mini-Scripting Games 2014. Last week, I posted the complete Problem 1 description and task outline.

Problem one synopsis

You are reading a CSV file that was created from another source. The CSV file has four fields that are to be read and then used to update four attributes in Active Directory. The problem is that the CSV file does not have all four fields filled out. In some cases, there is a space in the field, in others a tab, others are null, and others are empty.

When a field does not have a proper value, the attempt to update the attribute in Active Directory results in an error message. Your boss has decided to make the script your problem.

Solution

You need to write some logic that will identify all sorts of white space, including null fields. Detecting a null, a space, or a whatever seems to beg for a nice regular expression. It is also possible to do this manually by using a series of if statements.

Note  For a great reference, see Regular Expression Language - Quick Reference.

For example, if I want to match a space, I can simply supply a space, as shown here:

PS C:\> $a = " "

PS C:\> $a -match " "

True

Is $a null? I can also test that:

PS C:\> $a = $null

PS C:\> $a -match $null

True

I can incorporate this into logic, and use code that looks like the following:

PS C:\> If ($a -match " " -OR $a -match $null) {'$a is either a space or null'}

$a is either a space or null

Match a whitespace character

I can use a character class to try to match the empty field. Whitespace characters are things like a space, a tab, a carriage return, or a line feed. The regular expression character class for whitespace characters is backslash with a lowercase s: ( \s ). Windows PowerShell uses a backtick with a lowercase t for a Tab: ( `t ).

Note  Regular expression character classes are case sensitive. There is an excellent description of character classes on MSDN: Character Classes in Regular Expressions.  

In my first example, I use the Windows PowerShell `t character to store a Tab character in the variable $a. I then display it to the console, which is really nothing to see.

PS C:\> $a = "`t"

PS C:\> $a

Now, I attempt to match a space, which does not match a Tab. This is shown here:

PS C:\> $a -match " "

False

Now I use the \s whitespace character class from Regular Expressions, and I can see that it does match:

PS C:\> $a -match "\s"

True

Of course, it will also match the Windows PowerShell Tab character, `t:

PS C:\> $a -match "`t"

True

But the whitespace class does not match a null, as shown here:

PS C:\> $a = $null

PS C:\> $a -match "\s"

False

But it will match one or more spaces. This is shown here:

PS C:\> $a = " "

PS C:\> $a -match "\s"

True

PS C:\> $a = "  "

PS C:\> $a -match "\s"

True

How about not matching

Rather than trying to match every possible blank or empty sort of thing, how about if I simply don’t match any letter or number? I can easily do this by specifying a couple of character groups. All lower case letters, all upper case letters, and all numbers will pretty much do it. To specify a character group, I use square brackets for all lower case letters [a-z] or for all upper case letters [A-Z]. The asterisk ( * ) means zero or more instances of the characters.

I create my two character groups and store them in a variable I call pattern:

$pattern = "[a-z][A-Z]*"

Now I check to see if it does not match my various test conditions. First I check to see if It does not match a blank space:

PS C:\> $pattern = "[a-z][A-Z]*"

PS C:\> $a = " "

PS C:\> $a -notmatch $pattern

True

Then I check to see if it does not match a null:

PS C:\> $a = $null

PS C:\> $a -notmatch $pattern

True

Now I check to see if it does not match a Tab and a carriage return line feed:

PS C:\> $a = "`t"

PS C:\> $a -notmatch $pattern

True

PS C:\> $a = "`r`n"

PS C:\> $a -notmatch $pattern

True

Application to the problem

So, if I create a simple CSV file that has a few empty fields, it might look like the following:

"f1","f2","f3","f4"

"a","b","c","d"

"","b","c","d"

"a"," ","c","d"

Now, I write a script that reads this CSV file, and contains the pattern I used earlier. To walk through the CSV file, I use the GetEnumerator() method. I then use While and the MoveNext() method to proceed from each record to the next one. I then use an IF statement to see if I find a match. Here is the script:

PROBLEM1SOLUTION.PS1

$data = Import-Csv -Path C:\DataIn\q1.csv

$pattern = "[a-z][A-Z]*"

     $e = $data.GetEnumerator()

     While ($e.MoveNext())

      {

       If ($e.current.f1 -notmatch $pattern) {"$($e.current)  does not match"}

       If ($e.current.f2 -notmatch $pattern) {"$($e.current)  does not match"}

       If ($e.current.f3 -notmatch $pattern) {"$($e.current)  does not match"}

       If ($e.current.f4 -notmatch $pattern) {"$($e.current)  does not match"}

       } 

That is one approach to the problem. Mini-Scripting Games Answer Week will continue tomorrow when I will have a solution for Problem 2.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Mini-Scripting Games 2014 Answer 1

$
0
0

Summary: Here is the answer to the first question in Mini-Scripting Games 2014.

Hey, Scripting Guy! Question On your laptop running Windows 8.1, you opened the Windows PowerShell console and typed Get-Disk
           You were greeted with an error message that says: 
                “Get-Disk: Access to a CIM resource was not available to the client." 
            What is the issue?

Hey, Scripting Guy! Answer You need to open the Windows PowerShell console with Admin rights. Right-click the icon for the
           Windows PowerShell console and choose “Run as Administrator” from the action menu.


PowerShell Mini-Scripting Games 2014: Answer 2

$
0
0

Summary: Here is the answer to Problem 2 in Windows PowerShell Mini-Scripting Games 2014.

Microsoft Scripting Guy, Ed Wilson, is here. Problem 2 could be a bear to solve. After all, it involves text manipulation. Last week, I posted the complete Problem 2 description and task outline.

Problem 2 synopsis

You have a CSV file that contains five columns. It comes from the HR department and it contains information that you do not need. You only need to work with three of the columns.

Moving forward

As I said, it could be a bear to solve this problem, unless you remember that when imported, a CSV file produces objects. Therefore, all I need to do is to use the Select-Object cmdlet to select the columns I need, and export the file back to a CSV file. Here is a simple CSV file that I can use:

Fname,Lname,Group,Phone,Email

adam,adams,admin,555-1212,aa@contoso.msft

betty,barnes,business,555-1213,bb@contoso.msft

charlie,cassidy,customer relations,555-1214,cc@contoso.msft

Let's say that I need the Fname, Lname, and Email from this file. All I need to do is to import the CSV file, select the three fields I want, and then export the file back out. Here is how I do it:

Problem2Answer.ps1

Import-Csv C:\DataIn\p2.csv |

Select-Object Fname, Lname, Email |

Export-Csv C:\DataOut\p2Groomed.csv -Append -NoTypeInformation

The groomed data is shown here:

"Fname","Lname","Email"

"adam","adams","aa@contoso.msft"

"betty","barnes","bb@contoso.msft"

"charlie","cassidy","cc@contoso.msft"

That is all there is to solving Problem 2. Mini-Scripting Games Answer Week will continue tomorrow when I will talk about the answer to Problem 3.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Mini-Scripting Games 2014 Answer 2

$
0
0

Summary: Here is the answer to the second question in Mini-Scripting Games 2014.

Hey, Scripting Guy! Question On your laptop running Windows 8.1, you are running Hyper-V.
           You have heard that there are cmdlets that let you manage this.
           You open Windows PowerShell and type the following command:

Get-VM

Absolutely nothing comes back. But you know you have several virtual machines on your computer.
Why does nothing return?

Hey, Scripting Guy! Answer The Hyper-V cmdlets require Admin rights. Therefore, you need to open the Windows PowerShell console
           with Admin rights. Right-click the icon and select “Run As Administrator” from the action menu.
           Unfortunately, these cmdlets do not return any error messages if you try to run them without proper rights.

PowerShell Mini-Scripting Games 2014: Answer 3

$
0
0

Summary: Here is the answer to Problem 3 in Windows PowerShell Mini-Scripting Games 2014.

Microsoft Scripting Guy, Ed Wilson, is here. Today it is time to look at Problem 3. Last week, I posted the complete Problem 3 description and task outline.

Problem 3 synopsis

One of your teammates wrote a script that runs against a select subgroup of users once a week. This script takes a rather long time to complete (upwards of five minutes in some cases). Therefore, the sign-in appears to hang when it is their turn for processing. Users have done everything (called the Help Desk, rebooted the computers, booted up with the network cable unplugged) until they completed signing in with cached credentials to get around the annoying problem.

Your manager has tasked you with providing some sort of visual feedback to show the progress of the script. He did not task you with improving the script or figuring out another way to accomplish the task. He only wants you to write some code that will provide visual feedback to the users that something is happening, and that their computers are not “locked up.”

Write-Progress to the rescue

Windows PowerShell includes the Write-Progress cmdlet to provide visual feedback on the progress of one or more tasks that the script performs. For this problem, this Windows PowerShell cmdlet is ideal. It can provide notification about the task being performed, the current status of the activity, and even the progress towards completion. To make the script output a bit easier to track, I included the Start-Sleep command to cause the script to pause for a half-second before each increment.

To demonstrate using the Write-Progress cmdlet, I will simply monitor progress towards counting to the number 25. This is an ideal place to use the For statement. First, I count to 25. I do this by beginning at 1 and continuing while the number $i is less than or equal to 25. After each iteration, I increment the value of $i by 1. This is done by using $i++. Here is my For statement:

For($i=1; $i -le 25 ; $i++)

In the script block for the For statement, I use the Write-Progress cmdlet. The activity is “Counting to 25”, and the status is a display of the value of $i at that moment. I calculate the percentage of completeness, and I use that to display the progress bar. Here is that portion of the script:

Write-Progress -Activity "Counting to 25" -Status "

   Currently at $i" -PercentComplete($i / 25 * 100)

After the Write-Progress command, I sleep for a half-second. This is the command that accomplishes that task:

Start-Sleep -Milliseconds 500 

The complete script is shown here:

For($i=1; $i -le 25 ; $i++)

 { Write-Progress -Activity "Counting to 25" -Status "

   Currently at $i" -PercentComplete($i / 25 * 100)

   Start-Sleep -Milliseconds 500

   }

That is all there is to solving Problem 3. Mini-Scripting Games Answer Week will continue tomorrow when I will talk about solving Problem 4.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Mini-Scripting Games 2014 Answer 3

$
0
0

Summary: Here is the answer to the third question in Mini-Scripting Games 2014.

Hey, Scripting Guy! Question You are writing a script, and when it runs, you receive an error message that states:
               “You cannot call a method on a null-valued expression."
           What is the first thing you should check?

Hey, Scripting Guy! Answer Check the code that creates the object that you stored in the variable. It is probable that there is a
            problem with that code. For example, let's say I read from a database and store the results from
            that database to a variable, and then I call the MoveNext() method.

   If I get an error message that tells me I cannot call a method on a null-valued expression, it means that
   I did not successfully connect to the database or I did not return a record set from the database.

   This could be due to an invalid query or a query that returned no rows from the database.

PowerShell Mini-Scripting Games 2014: Answer 4

$
0
0

Summary: Here is the answer to Problem 4 in Windows PowerShell Mini-Scripting Games 2014.

Microsoft Scripting Guy, Ed Wilson, is here. It is time for the answer to Problem 4 in Mini-Scripting Games 2014. Last week, I posted the complete Problem 4 description and task outline.

Problem 4 synopsis

Your manager tasked you with what he considers to be a really important issue. The people at the Help Desk want a tool that will permit them to easily stop processes. Your manager doesn’t want to give them permission to use Task Manager because it carries too much power.

He decided that he wants you to write a script that will permit people who run the script to kill any process that they have user rights to stop. Your manager does not want people to be able to stop any process, only those for which they have user rights.            

Approaching the problem

First of all, I need to admit to a bogus requirement. The part about security was a distractor. Windows PowerShell does not permit a user to do anything that the user does not have rights to do. Therefore, if there is a process the user does not have access to, that user will not be able to kill that process. So that portion of the problem description can be ignored.

Now for the second part...

A graphical interface is all in the eye of the beholder. The hint said don’t do any more work than required, so I decided to use the Out-GridView cmdlet with the –PassThru parameter. This will permit me to select processes from the list, and kill them by using the Stop-Process cmdlet.

Here are the steps to my approach:

  1. Use Get-Process to grab the list of processes.
  2. Use Out-GridView to display the processes.
  3. Use Stop-Process to stop the processes.

Here is my script:

Get-Process |

Out-GridView -PassThru |

Stop-Process 

That is it. I use Get-Process to grab the processes, and I pipe them to the Out-GridView cmdlet. The trick is to use the –PassThru parameter so that the process objects that are selected will pass to Stop-Process.

In the Out-GridView pane, all I need to do is select the processes I want to kill. It is a graphical thingy after all, so I feel it meets the requirements. Sweet. Three very simple lines of script.

That is all there is to solving Problem 4. Mini-Scripting Games Answer Week will continue tomorrow when I will talk about Problem 5.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Mini-Scripting Games 2014 Answer 4

$
0
0

Summary: Here is the answer to the fourth question in Mini-Scripting Games 2014.

Hey, Scripting Guy! Question You are attempting to use Try/Catch/Finally in your script. No matter what you try,
            the script never seems to catch it. What is the most likely cause of the problem?

Hey, Scripting Guy! Answer The most likely cause of the problem is that your Try statement does not generate a terminating error,
            and therefore, there is nothing for Catch to catch.

 One easy way to fix this is to change your $ErrorActionPreference variable from Continue to Stop.
 This will cause your non-terminating errors to actually terminate and send the control to the 
 Catch portion of your script.

PowerShell Mini-Scripting Games 2014: Answer 5

$
0
0

Summary: Here is the answer to Problem 5 in Windows PowerShell Mini-Scripting Games 2014.

Microsoft Scripting Guy, Ed Wilson, is here. It is time for the answer to Problem 5 in Mini-Scripting Games 2014. Last week, I posted the complete Problem 5 description and task outline.

Problem 5 synopsis

Your manager has tasked you to help a junior admin with a script. It appears that the junior admin wants to solicit input from the user when the script is running. Then based on the input from the user, the script will do something else.

Answer

There are many ways of obtaining input from the user. One way to do it is to create parameters for a Windows PowerShell function, and then when the function is called, the input is gleaned. You can also use VBScript style input boxes or other tools. But to me, the easiest way to do it is to use the Read-Host cmdlet.

To use the Read-Host cmdlet, all I do is specify a value for the Prompt, and store the results in a variable. I can then use that variable later.

Note  It can be dangerous to provide an unchecked input box, so it is a good idea to implement some checks for validity of the data that is input.

In this example, I ask for the name of a process, and I supply a couple of valid examples for the syntax. I store the inputted data in the $a variable.

$a = Read-host -Prompt "Process to start: ex. notepad / calc"

I now do a simple check to see if the inputted data matches notepad or calc. If it does, I pass the value of $a to the Start-Process cmdlet. Otherwise, I state that I cannot start the process. Here is the complete script:

$a = Read-host -Prompt "Process to start: ex. notepad / calc"

if($a -match 'notepad' -or $a -match 'calc')

    { Start-Process $a }

ELSE { "cannot start the $a process"}

   Note  This is a very rudimentary example and a very basic check. It would be rather easy to work around this
   type of check.

That is all there is to solving Problem 5. The answer to the final question will arrive in a few hours in the PowerTip, at which time Mini-Scripting Games Week will conclude. Join me tomorrow for more cool Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy


PowerTip: Mini-Scripting Games 2014 Answer 5

$
0
0

Summary: Here is the answer to the final question in Mini-Scripting Games 2014.

Hey, Scripting Guy! Question You created a constant variable in your Windows PowerShell console. Now, when you attempt to delete the variable,
           you get an error message. How can you remove a constant variable?

Hey, Scripting Guy! Answer A constant variable is created by using the New-Variable cmdlet, for example:

New-Variable c "c" -Option Constant

   After a variable is created as a constant, it cannot be removed until the console (or ISE) is closed and reopened.

Weekend Scripter: PowerShell and Chocolatey

$
0
0

Summary: Guest blogger and Honorary Scripting Guy, June Blender, talks about using Windows PowerShell and Chocolatey.

Microsoft Scripting Guy, Ed Wilson, is here. Today, I welcome back guest blogger, June Blender.

I’m probably one of five people on earth who really do not like chocolate, so I wasn’t too keen to learn about something called “Chocolatey.” But I kept hearing about Chocolatey and other “package installers,” such as NuGet, and I wanted to know what all of the fuss was about. Then along comes Windows PowerShell 5.0 Preview with a module called OneGet that works with Chocolatey. It was clearly past time to figure it out.

What’s a package installer?

Package installers install programs and groups of related programs called packages. In this guise, they’re not much different than an EXE or MSI file. But unlike simple installers, package installers also know about dependencies, which are other programs that the to-be-installed program requires, and they’ll install any missing dependencies for you automatically. Beyond that, they solve easy problems, such as expanding zip files and installing tools in a consistent place. They can also solve very difficult installation problems for you, including installing programs on your computer that are designed for a different platform or operating system.

This last feature is truly the most appealing. I took a great Android app programming class from Coursera called Creative, Serious, and Playful Science of Android Apps. It’s a terrific class, and I really recommend it. For me, the most difficult part of the class was installing the programming tools on my PC, which is running Windows, because they’re designed for an iOS or UNIX platform. I had to install five tools to install the tools that I needed. These include a tool to unzip (or whatever) TGZ files, appropriately called “tarballs.” Well-designed package installers handle this mess for you.

Package installers are also great for open-source collaborative projects, like those on GitHub. Contributors can collect their files into packages and submit the package in a pull request. When other contributors clone the project, they can use the package installer to install all of the contributed pieces.

What’s Chocolatey?

Chocolatey is a package installer that’s designed especially for working with Windows PowerShell. You can learn all about Chocolatey at the Chocolatey Gallery site. Chocolatey is also an open-source project. You can view and contribute to the Chocolatey source at Chocolatey GitHub.

You can use Windows PowerShell to script Chocolatey installations, but you can also use the search feature on the pretty Chocolatey Packages website:

Image of website

What’s OneGet?

OneGet is a Windows PowerShell module that is included in Windows Management Framework 5.0 Preview. The cmdlets in the module manage packages, including those on the Chocolatey site. They find packages, get installed packages, get the source of a package, and uninstall packages, among other things. 

OneGet includes Windows PowerShell cmdlets with names like Find-Package, Get-Package, and Install-Package. The preview version gets only Chocolatey packages, but I bet that will change. Also, the preview version doesn’t yet have Help files, although it’s set up for updatable Help. Again, we’ll probably see those when the full product is released.

Installing OneGet and/or Chocolatey

You can install OneGet or Chocolatey or both. They’re completely independent, and they don’t require each other.

You can install Windows Management Framework 5.0 Preview (with OneGet) from the Microsoft Download Center: Windows Management Framework 5.0 Preview May 2014.

To install Chocolatey, run the Install.ps1 script from the Chocolatey website (inspect it first):

  1. Start Windows PowerShell with the “Run as administrator” option.
  2. At the Windows PowerShell prompt, run the following command. It starts a web-based script (Install.ps1), which installs Chocolatey. You don’t need to replace any values.

Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

Try OneGet!

Let’s play with the OneGet module so we have a sense of how it works.

Find-Package cmdlet

The Find-Package cmdlet gets information about all available packages. It returns a SoftwareIdentity object (Microsoft.OneGet.Core.Packaging.SoftwareIdentity) for each package.

Be patient. The cmdlet can take a full minute to run because it’s getting data from a website.

Image of command output

In the preview, the source is always “Chocolatey” and the status is always “Available,” but it’s only a preview.

PS C:\> Find-Package | Group-Object –Property Source

Count Name                      Group

----- ----                      -----

 2050 chocolatey                {Microsoft.OneGet.Core.Packaging.SoftwareIdentity, Mi

 

PS C:\> Find-Package | Group-Object –Property Status

Count Name                      Group

----- ----                      -----

 2050 Available                 {Microsoft.OneGet.Core.Packaging.SoftwareIdentity, Mi

You can use the Name parameter of Find-Package to filter by package name. You can enter part of the package name, but this cmdlet does not support wildcard characters. Cmdlets that launch REST APIs (web page queries) rarely do.

This command gets packages with names that include Autorun:

PS C:\> Find-Package -Name Autorun

 

Name               Version   Status    Source         Summary

----               -------   ------    ------         -------

AutoRuns           12.0      Available chocolatey     Shows what programs are

AutorunscPortable  12.0.0.0  Available chocolatey

AutorunsPortable   12.0.0.0  Available chocolatey

 

PS C:\> Find-Package -Name Autorun*

WARNING: No Package Found:Autorun*

The SoftwareIdentity object includes useful information about the package. This command gets the Autoruns package and formats all (*) of its properties in a list:

PS C:\> Find-Package -Name Autoruns | Format-List -Property *

ProviderName  : Chocolatey

Source        : chocolatey

Name          : AutoRuns

Version       : 12.0

VersionScheme : semver

Status        : Available

Summary       : Shows what programs are configured to run during system bootup or login

Install-Package cmdlet

To install a package, use the Install-Package cmdlet. You can also pipe a Find-Package command to the Install-Package cmdlet.

I use the parameters of the Find-Package cmdlet to create a command that gets only the package that I want to install. Then, I pipe it to Install-Package. I use the Verbose parameter to see where the package is installed.

   Note  To see all parameters of Find-Package, type: Get-Command Find-Package –Syntax.

PS C:\> Find-Package -Name Autoruns -RequiredVersion 12.0

 

Name     Version    Status    Source         Summary

----     -------    ------    ------         -------

AutoRuns 12.0       Available chocolatey     Shows what programs are configured...

 

PS C:\> Find-Package -Name Autoruns -RequiredVersion 12.0 | Install-Package -Verbose

The Install-Package cmdlet prompts me to verify that I trust the package and then installs it. It begins by installing a ZIP file in a temporary directory in my user profile. Then it unzips the file and installs it in a C:\chocolatey directory.

PS C:\ps-test> Find-Package -Name Autoruns -RequiredVersion 12.0 | Install-Package –Verbose

Installing Package 'AutoRuns' from untrusted source

WARNING: This package source is not marked as safe. Are you sure you want to install software from 'chocolatey'

[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"): y

VERBOSE: Performing the operation "Install Package" on target "AutoRuns".

VERBOSE: NuGet:Installing 'AutoRuns 12.0'.

VERBOSE: NuGet:Successfully installed 'AutoRuns 12.0'.

VERBOSE: InstallChocolateyZipPackage:AutoRuns

VERBOSE: CreateFolder

Success:C:\Users\juneb\AppData\Local\Temp\Microsoft.OneGet.Utility\11\chocolatey\AutoRuns

VERBOSE: GetChocolateyWebFile:AutoRuns => http://download.sysinternals.com/files/Autoruns.zip

VERBOSE: Downloading:'http://download.sysinternals.com/files/Autoruns.zip' to

'C:\Users\juneb\AppData\Local\Temp\Microsoft.OneGet.Utility\11\chocolatey\AutoRuns\AutoRunsinstall.zip'

VERBOSE:

GetChocolateyUnzip:C:\Users\juneb\AppData\Local\Temp\Microsoft.OneGet.Utility\11\chocolatey\AutoRuns\AutoRunsinstall.zip

VERBOSE: CreateFolder -- C:\Chocolatey\lib\AutoRuns.12.0

VERBOSE: Taking Snapshot:C:\Chocolatey\lib\AutoRuns.12.0\Tools

VERBOSE: CreateFolder -- C:\Chocolatey\lib\AutoRuns.12.0\Tools

VERBOSE: Diffing Snapshot:C:\Chocolatey\lib\AutoRuns.12.0\Tools

VERBOSE: Package Successfully Installed:AutoRuns

Name     Version    Status    Source         Summary

----     -------    ------    ------         -------

AutoRuns 12.0       Available chocolatey     Shows what programs are configured...

To indicate that the installation was successful, Install-Package returns a SoftwareIdentity object that represents the package that it installed. You can use this feature in a script that includes a package installation, for example:

if (Get-Package Autoruns | Install-Package) { <do the next thing> }

-or-

Foreach ($pkg in $packages)

{

$result = Install-Package -Name $pkg

if ($result.Name –eq $pkg) {<do the next thing>}

            }

Get-Package cmdlet

To get all packages that the OneGet cmdlets installed, use the Get-Package cmdlet. (Get-Package gets only packages that Install-Package installed. It does not get packages that you install by other means, including Chocolatey.

PS C:\>Get-Package

Name     Version    Status    Source         Summary

----     -------    ------    ------         -------

AutoRuns 12.0       Available chocolatey     Shows what programs are configured...

To run the package, at the Windows PowerShell prompt, type Autoruns. (You can also use the Start page, Start menu, or Run box.) The starting method might differ for other tools.    

To uninstall the package, use the Uninstall-Package cmdlet. I’ve installed and uninstalled packages repeatedly without any errors, so test away!

Try Chocolatey!

Now let’s try Chocolatey.

To install Chocolatey when you have the OneGet module, use the Install-Package cmdlet:

PS C:\> Find-Package –Name Chocolatey

Name        Version          Status           Source         Summary

----        -------          ------           ------         -------

chocolatey  0.9.8.28-alpha2  Available        chocolatey     Chocolatey is your machine level N...

 

PS C:\> Find-Package –Name Chocolatey | Install-Package -Verbose

I’ll use Windows PowerShell to run the Chocolatey commands, but you do not need to have Windows PowerShell or OneGet to run the commands. You can use the website or the native or GUI Chocolatey clients.

When you review the Chocolatey commands, you’ll notice immediately that the command names don’t have the familiar verb-noun format of cmdlets. And Get-Help won’t help you with these commands. The following Chocolatey wiki is useful: Command Reference.

To run Chocolatey commands without warnings, you must start Windows PowerShell with the “Run as administrator” option (also known as “elevated”).

To search for a package (the equivalent of Find-Package), use the List or Search commands. These commands are aliases of each other, and they can be used interchangeably.

For example, to search for the Autoruns tool, type:

[ADMIN] PS C:\> choco list Autoruns

AutoRuns 12.0

Again, you can type part of the name of the tool you’re searching for, such as choco list Auto, but you cannot use wildcard characters.

[ADMIN] PS C:> choco search Autorun

AutoRuns 12.0

AutorunsPortable 12.0.0.0

AutorunscPortable 12.0.0.0

bitdefender-usb-immunizer 2.0.1.90

cmdaliases 1.0.0.1

The List and Search commands search all fields for the Autorun phrase, not only the name field. In this case, the description of the cmdaliases tool includes “autorun.” Also, the Chocolatey commands return strings of the package names. They don’t return SoftwareIdentity objects. 

To install a package, use the choco install or cinst command. The following command installs the Autoruns tool.

PS C:\> choco install Autoruns

Chocolatey doesn’t have a command like Get-Package, but it does have commands to uninstall packages and get the source code for the package.

Using OneGet and Chocolatey together

You can use both OneGet and Chocolatey. However, in OneGet preview and the current incarnation of Chocolatey, they’re not aware of each other. For example, Get-Package gets only the packages that Install-Package installs. It doesn’t get the packages that Chocolatey installs.

The installation location might vary with the package that you install, but Chocolatey installs the Autoruns tool in a different place than Install-Package installs it. If you use both, the installations are independent. This isn’t a problem for a simple tool like Autoruns, but it might create problems for more complex packages.

OneGet: C:\Chocolatey\lib\AutoRuns.12.0\Tools\Autoruns.exe

Chocolatey: C:\ProgramData\chocolatey\lib\AutoRuns.12.0\Tools

Is Find-Package temporary?

One more hint before you start scripting. 

The Find-Package command gets data from a website (or websites) where the data changes frequently. The results of Find-Package time out, even if you save them in a variable. If you save the output for more than a few minutes, it disappears.

For example, if you save the results of the Find-Package cmdlet in an $a variable, you can display the value of $a as usual. But if you wait a few minutes and repeat the command that displays the value of $a, the value is gone!

PS C:\> $a = Find-Package

PS C:\> $a | Format-Table –Property Name, Summary -Autosize

Name                      Summary

----                      -------

1password                 1Password - Have you ever forgotten a password?

7zip                      7-Zip is a file archiver with a high compression

7zip.commandline          7-Zip is a file archiver with a high compression

7zip.install              7-Zip is a file archiver with a high compression

ack                       ack is a tool like grep, designed

acr

ActiveMQ                  Apache ActiveMQ is a messaging and integration server

ActivePerl                ActivePerl is the leading commercial-grade ActivePerl-EqEmu-x86      ActivePerl-EqEmu-x86

ActiveTcl

Wait 3 minutes...

PS C:\> $a | Format-Table -Property Name, Summary -Autosize

Name Summary

---- -------

The objects are still there, but their content is missing.

PS C:\ps-test> $a | Get-Member

   TypeName: Microsoft.OneGet.Core.Packaging.SoftwareIdentity

Name                      MemberType Definition

----                      ---------- ----------

CreateObjRef              Method     System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)

Equals                    Method     bool Equals(System.Object obj)

GetHashCode               Method     int GetHashCode()

GetLifetimeService        Method     System.Object GetLifetimeService()

GetType                   Method     type GetType()

InitializeLifetimeService Method     System.Object InitializeLifetimeService()

ToString                  Method     string ToString()

Name                      Property   string Name {get;set;}

ProviderName              Property   string ProviderName {get;set;}

Source                    Property   string Source {get;set;}

Status                    Property   string Status {get;set;}

Summary                   Property   string Summary {get;set;}

Version                   Property   string Version {get;set;}

VersionScheme             Property   string VersionScheme {get;set;}

 

PS C:\> $a[0]

Name      Version          Status           Source         Summary

----      -------          ------           ------         -------

You might never encounter this in a script, but if you’re playing around in the console, it might surprise you.

Now, go off and have fun. There are some amazing Chocolatey packages. I installed a trial version of my favorite tool, .NET Reflector from Red Gate Software. And ironically, I installed 7Zip, which unzips any file type, even though I might never need to use it again.

~June

Thanks, June. This is useful and fun. Great job.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Use PowerShell to Install Sysinternals

$
0
0

Summary: Learn to use Windows PowerShell to easily install Sysinternals utilities.

Hey, Scripting Guy! Question How do I find a Chocolatey package that installs Sysinternals?

Hey, Scripting Guy! Answer Use the Find-Package cmdlet:

Find-Package –Name Sysinternals

Note   This command requires the OneGet module in Windows PowerShell 5.0.

Weekend Scripter: Use PowerShell to Troubleshoot Group Policy

$
0
0

Summary: Guest blogger, Alex Verboon, talks about using Windows PowerShell to troubleshoot delays in Group Policy performance.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have a new guest blogger, Alex Verboon. I was reading Alex’s blog page. I liked what he had to say and I invited him to contribute a guest blog post here. You can read his blog at Anything about IT.

Now, here is Alex...

For years, I have been reading and consuming content from the Hey, Scripting Guy! Blog, so it's a big pleasure to give something back. Today I want to share with you a Windows PowerShell script I put together recently that collects the Group Policy processing time on a client. The script might come in handy when you are troubleshooting or reviewing system startup performance or to prove that it's not Group Policy that's causing delays.

If you are not familiar with troubleshooting Group Policy, I recommend that you read the TechNet article Troubleshooting Group Policy Using Event Logs.

The script accepts multiple computer names as input, so you can specify multiple computers that are located in different locations if you're interested to find out what the Group Policy processing time is within the different locations of the company.

Here is what the script does for each computer specified and when online:

  • Retrieves the last end policy processing event of the user that logged on to that computer
  • Retrieves the last end policy processing event for the computer
  • Gets the unique activity ID for the instance of the user Group Policy processing cycle
  • Retrieves the domain controller name from event 5308 from the user processing cycle
  • Retrieves network information from event 5314 from the user processing cycle
  • Gets the unique activity ID for the instance of the computer Group Policy processing cycle
  • Retrieves the domain controller name from event 5308 from the computer processing cycle
  • Retrieves network information from event 5314 from the computer processing cycle

The script also writes the following computer information to a custom object:

  • Computer end policy processing event ID
  • Event ID description
  • Event message
  • Time stamp
  • Activity ID
  • Policy processing time (in seconds)
  • Computer name
  • Bandwidth (in Kbps)
  • Slow link (yes or no)
  • Domain controller used

And it writes the following user information to a custom object:

  • User end policy processing event ID
  • Event ID description
  • Event message
  • Time stamp
  • Activity ID
  • Policy processing time (in seconds)
  • Bandwidth (in Kbps)
  • Slow link (yes or no)
  • Domain controller used

If the script is launched with the –Computer parameter, the script output is:

Image of command output

When specifying the optional –ShowDetails switch, the script output is:

Image of command output

Following is the full script. You can download this script from the Script Center Repository: Get-GPProcessingTime.

function Get-GPProcessingtime

{

<#

.Synopsis

   Get Group Policy processing time from the Group Policy event log on local and remote computers

.DESCRIPTION

   The Get-GPProcessingtime cmdlet gets Group Policy processing time for the user and computer related

   Group Policies that are processed on the specified computer(s).

   The last user and computer Group Policy processing event is used.

.EXAMPLE

   Get-GPProcessingtime -Computer TestClient1,TestClient2,TestClient3

   Lists additional details of the Group Policy processing duration information

    Cmp_PrincipalSamName         Cmp_PolicyElaspedTimeInSeconds      Usr_PolicyElaspedTimeInSeconds    

    --------------------         ------------------------------      ------------------------------    

    CORP\TestClient1$               1                                   2                                 

    CORP\TestClient2$               2                                   2                                  

    CORP\TestClient3$               12                                  49

.EXAMPLE

    Get-GPProcessingtime -Computer TestClient1 -ShowDetails

    Cmp_ID                         : 8004

    Cmp_EventTypeDescription       : Successful computer manual refresh event

    Cmp_Message  : Completed manual processing of policy for computer CORP\TestClient1$ in 1 second.

    Cmp_TimeCreated                : 8/1/2014 8:13:40 PM

    Cmp_ActivityID                 : e872d44e-1b89-434a-bf79-b1875ec810cf

    Cmp_PolicyElaspedTimeInSeconds : 1

    Cmp_PrincipalSamName           : CORP\TestClient1$

    Cmp_BandwidthInkbps            : 185508

    Cmp_IsSlowLink                 : false

    Cmp_DomainController           : dc01.corp.com

    Usr_ID                         : 8001

    Usr_EventTypeDescription       : Successful user end event

    Usr_Message                    : Completed user logon policy processing for CORP\User1 in 2 seconds.

    Usr_TimeCreated                : 7/30/2014 4:55:42 PM

    Usr_ActivityID                 : 43ca8a03-2b98-4e92-8613-aad67990bca3

    Usr_PolicyElaspedTimeInSeconds : 2

    Usr_PrincipalSamName           : CORP\User1

    Usr_BandwidthInkbps            : 1200750

    Usr_IsSlowLink                 : false

    Usr_DomainController           : dc01.corp.com

.PARAMETER Computer

    Type the NetBIOS name, an Internet Protocol (IP) address, or the fully qualified domain name of the computer.

    The default value is the local computer.

    To get Group Policy processing information from remote computers, the firewall port for the event log service must be configured to allow remote access.

    This cmdlet does not rely on Windows PowerShell remoting. You can use the ComputerName parameter even if your computer is not configured to run remote commands.

.PARAMETER ShowDetails

    The ShowDetails switch is optional. When set, additonal Group Policy processing information is listed,    such as the type of the Group Policy processing event (periodic, manual), the Activity ID network bandwidth, and the domain controller being contacted.

.LINKS

# http://technet.microsoft.com/library/cc749336.aspx   

#>

[CmdletBinding()]

 Param(

    [Parameter(Mandatory=$False,

    ValueFromPipelineByPropertyName=$true,HelpMessage="Enter Computername(s)",

    Position=0)]

    [Alias("ipaddress","host")]

    [String[]]$Computer = "localhost",

    [switch]$ShowDetails

    )

begin{

    # User Event IDs

    $ugeventcodes = @{

    "8001" = "Successful user end event";

    "8003" = "Successful user network change event";

    "8005" = "Successful user manual refresh event";

    "8007" = "Successful user periodic refresh event";

    "7001" = "Error during user end event";

    "7003" = "Error during user network change event";

    "7005" = "Error during user manual refresh event";

    "7007" = "Error during user periodic refresh event";

    "6001" = "Warnings during user end event";

    "6003" = "Warnings during  user network change event";

    "6005" = "Warnings during  user manual refresh event";

    "6007" = "Warnings during  user periodic refresh event";

    }

    # Computer Event IDs

    $cgeventcodes = @{

    "8000" = "Successful computer end event";

    "8002" = "Successful computer network change event";

    "8004" = "Successful computer manual refresh event";

    "8006" = "Successful computer periodic refresh event";

    "7000" = "Error duing computer end event";

    "7002" = "Error during computer network change event";

    "7004" = "Error during computer manual refresh event";

    "7006" = "Error during computer periodic refresh event";

    "6000" = "Warnings during computer end event";

    "6002" = "Warnings during computer network change event";

    "6004" = "Warnings during  computer manual refresh event";

    "6006" = "Warnings during  computer periodic refresh event";

    }

}

Process{

    $compcount = $Computer.count

    $si=1

    $gpprocessresult = @()

    ForEach ($comp in $Computer)

    {

        If (Test-Connection -ComputerName "$comp" -Count 1 -Quiet)

            {

            $orgCulture = Get-Culture

            [System.Threading.Thread]::CurrentThread.CurrentCulture = New-Object "System.Globalization.CultureInfo" "en-US"

           # variable that holds all user related event IDs

            $ueventids = $ugeventcodes.Keys

            # Get last user GP processing event

            $uevent = Get-WinEvent -ComputerName $Comp -filterHashTable @{

             Providername = "Microsoft-Windows-GroupPolicy"

             ID = $($ueventids)

              } -ErrorAction SilentlyContinue | select -first 1 -ErrorAction SilentlyContinue

            # variable that holds all computer related IDs

            $ceventids = $cgeventcodes.Keys

            # Get last computer GP processing event

            $cevent = Get-WinEvent -ComputerName $Comp -filterHashTable @{

             Providername = "Microsoft-Windows-GroupPolicy"

             ID = $($ceventids)

             } -ErrorAction SilentlyContinue | select -first 1 -ErrorAction SilentlyContinue

            if (-not ([string]::IsNullOrEmpty($uevent)))

            {

                 # create a variable that holds the user event details

                 $ueventXML = [xml]$uevent.ToXml()

                 # Retrieve Event with EventID 5308 to get the domain controller name used when processing the user

                 $Query = ' <QueryList><Query Id="0" Path="Application"><Select Path="Microsoft-Windows-GroupPolicy/Operational">*[System/Correlation/@ActivityID="{CorrelationID}"] and *[System[(EventID="5308")]] </Select></Query></QueryList>'

                 $FilterXML = $Query.Replace("CorrelationID",$uevent.ActivityID)

                 $udc = Get-WinEvent -FilterXml $FilterXML -ComputerName $comp -ErrorAction SilentlyContinue | select -First 1 -ErrorAction SilentlyContinue

                 if (-not ([string]::IsNullOrEmpty($udc)))

                 {$udcevent = [xml]$udc.ToXml()

                 $udcname = $udcevent.event.EventData.Data[0]."#Text"

                 } 

                 # Retrieve Event with Event ID 5314 to get network information when processing user

                 $Query = ' <QueryList><Query Id="0" Path="Application"><Select Path="Microsoft-Windows-GroupPolicy/Operational">*[System/Correlation/@ActivityID="{CorrelationID}"] and *[System[(EventID="5314")]] </Select></Query></QueryList>'

                 $FilterXML = $Query.Replace("CorrelationID",$uevent.ActivityID)

                 $unw = Get-WinEvent -FilterXml $FilterXML -ComputerName $comp -ErrorAction SilentlyContinue | select -First 1 -ErrorAction SilentlyContinue

                 if (-not ([string]::IsNullOrEmpty($unw)))

                 {$unwevent = [xml]$unw.ToXml()

                 $uBandwidthInkbps = $unwevent.event.EventData.Data[0]."#Text"

                 $uIsSlowLink = $unwevent.event.EventData.Data[1]."#Text"

                 } 

            }

            if (-not ([string]::IsNullOrEmpty($cevent)))

            {

                 # create a variable that holds the computer event details

                 $ceventXML = [xml]$cevent.ToXml()

                 # Retrieve Event with EventID 5308 to get the domain controller name when processing the computer

                 $Query = ' <QueryList><Query Id="0" Path="Application"><Select Path="Microsoft-Windows-GroupPolicy/Operational">*[System/Correlation/@ActivityID="{CorrelationID}"] and *[System[(EventID="5308")]] </Select></Query></QueryList>'

                 $FilterXML = $Query.Replace("CorrelationID",$cevent.ActivityID)

                 $cdc = Get-WinEvent -FilterXml $FilterXML -ComputerName $comp -ErrorAction SilentlyContinue | select -First 1 -ErrorAction SilentlyContinue

                 if (-not ([string]::IsNullOrEmpty($cdc)))

                 {$cdcevent = [xml]$cdc.ToXml()

                 $cdcname = $cdcevent.event.EventData.Data[0]."#Text"

                 }

                 # Retrieve Event with EventID 5314 to get network information when processing computer

                 $Query = ' <QueryList><Query Id="0" Path="Application"><Select Path="Microsoft-Windows-GroupPolicy/Operational">*[System/Correlation/@ActivityID="{CorrelationID}"] and *[System[(EventID="5314")]] </Select></Query></QueryList>'

                 $FilterXML = $Query.Replace("CorrelationID",$cevent.ActivityID)

                 $cnw = Get-WinEvent -FilterXml $FilterXML -ComputerName $comp -ErrorAction SilentlyContinue | select -First 1 -ErrorAction SilentlyContinue

                 if (-not ([string]::IsNullOrEmpty($unw)))

                 {$cnwevent = [xml]$cnw.ToXml()

                 $cBandwidthInkbps = $cnwevent.event.EventData.Data[0]."#Text"

                 $cIsSlowLink = $cnwevent.event.EventData.Data[1]."#Text"

                 } 

           }

            $object = New-Object -TypeName PSObject

            $object | Add-Member -MemberType NoteProperty -Name Cmp_ID -Value $cevent.Id

            $object | Add-Member -MemberType NoteProperty -Name Cmp_EventTypeDescription -Value $cgeventcodes["$($cevent.Id)"]

            $object | Add-Member -MemberType NoteProperty -Name Cmp_Message -Value $cevent.Message

            $object | Add-Member -MemberType NoteProperty -Name Cmp_TimeCreated -Value $cevent.TimeCreated

            $object | Add-Member -MemberType NoteProperty -Name Cmp_ActivityID -Value $cevent.ActivityId

            $object | Add-Member -MemberType NoteProperty -Name Cmp_PolicyElaspedTimeInSeconds -Value ($cpe = If ([string]::IsNullOrEmpty($cevent)) {} else {  $ceventXML.Event.EventData.Data[0].'#text'})

            $object | Add-Member -MemberType NoteProperty -Name Cmp_PrincipalSamName -Value ($cpn = If ([string]::IsNullOrEmpty($cevent)) {} else { $ceventXML.Event.EventData.Data[2].'#text' })

            $object | Add-Member -MemberType NoteProperty -Name Cmp_BandwidthInkbps -Value $cBandwidthInkbps

            $object | Add-Member -MemberType NoteProperty -Name Cmp_IsSlowLink -Value $cIsSlowLink

            $object | Add-Member -MemberType NoteProperty -Name Cmp_DomainController -Value $cdcname

            $object | Add-Member -MemberType NoteProperty -Name Usr_ID -Value $uevent.Id

            $object | Add-Member -MemberType NoteProperty -Name Usr_EventTypeDescription -Value $ugeventcodes["$($uevent.Id)"]

            $object | Add-Member -MemberType NoteProperty -Name Usr_Message -Value $uevent.Message

            $object | Add-Member -MemberType NoteProperty -Name Usr_TimeCreated -Value $uevent.TimeCreated

            $object | Add-Member -MemberType NoteProperty -Name Usr_ActivityID -Value $uevent.ActivityId

            $object | Add-Member -MemberType NoteProperty -Name Usr_PolicyElaspedTimeInSeconds -Value ($Upe = If ([string]::IsNullOrEmpty($uevent)) {} else {  $ueventXML.Event.EventData.Data[0].'#text'})

            $object | Add-Member -MemberType NoteProperty -Name Usr_PrincipalSamName -Value ($upn = If ([string]::IsNullOrEmpty($uevent)) {} else { $ueventXML.Event.EventData.Data[2].'#text' })

            $object | Add-Member -MemberType NoteProperty -Name Usr_BandwidthInkbps -Value $uBandwidthInkbps

            $object | Add-Member -MemberType NoteProperty -Name Usr_IsSlowLink -Value $uIsSlowLink

            $object | Add-Member -MemberType NoteProperty -Name Usr_DomainController -Value $udcname

            $gpprocessresult += $object

            }

            Else

            {

                write-output "Client $comp is NOT reachable, skipping"

            }

            Write-Progress -Activity "Processing $comp" -Status "Processing $si of $compcount" -PercentComplete (($si / $compcount) * 100)

            $si++

       }

}

End{

    If ($ShowDetails.IsPresent -eq $false)

        {$gpprocessresult | Select Cmp_PrincipalSamName, Cmp_PolicyElaspedTimeInSeconds,Usr_PolicyElaspedTimeInSeconds}

    Else

        {$gpprocessresult}

    }

}

~Alex

Thank you, Alex, for an excellent post—well done.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

PowerTip: Find Cmdlets that Need TimeSpan Object

$
0
0

Summary: Use Get-Command to find cmdlets that need a TimeSpan object for input.

Hey, Scripting Guy! Question How can I use Windows PowerShell to find which cmdlets will accept a TimeSpan object for input?

Hey, Scripting Guy! Answer Use the ParameterType parameter from the Get-Command cmdlet, for example:

Get-Command -ParameterType timespan

Viewing all 3333 articles
Browse latest View live




Latest Images