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

Weekend Scripter: Use PowerShell to Set Word Document Time Stamps

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to set the time stamps on Microsoft Word document files.

Microsoft Scripting Guy, Ed Wilson, is here. It is Saturday here in Charlotte, and the sunshine continues to make its presence known. It seems that the sun gets up rather early during the summer, and retires in the evening rather late. It is just around 6:00 in the morning, and I am sitting on the lanai drinking a cup of English breakfast tea with a cinnamon stick and about a half spoonful of hibiscus flower in the tea. The hibiscus flower gives the tea a nice citrus flavor without all the carbs. I have one of my Windows 8 laptops with me in the swing and am checking my email. I really love Windows 8, and I cannot wait until I can buy the Scripting Wife a Microsoft Surface. She has been begging for one since she saw one at the Atlanta TechStravaganza. (United States FTC Disclaimer: I work for the Microsoft Corporation, and Microsoft provides me my laptop and the Windows 8 bits for my laptop. They did not build my lanai, nor do they provide me with English breakfast tea at home. However, when I am in the Microsoft office, they do provide me with English breakfast tea.)

The problem with file time stamps

A few months ago, I wrote a function that uses Windows PowerShell to modify file access time stamps. In the Hey, Scripting Guy! Blog where I discussed this technique, I envisioned creating a single DateTime object and using that to set all three of the file access time stamps. I even discussed my use case scenario, which was to use the technique as a sort of cheap versioning system while I was working on the Windows 7 Resource Kit.

This week, however, as I began working with the Word documents stored on my computer for all of the Hey Scripting Guy! Blogs I have written, I came up with another use for the function−to correct time stamps that are modified through various means (such as backup and restore from a network SAN and modifications created to Microsoft Word built-in properties). Luckily, all of my Hey, Scripting Guy! Blogs have a file name based on the date in which the blog appears. For example, the file for today’s Weekend Scripter is: WES-8-4-12.docx. I am assured the file names are consistent because I have a Windows PowerShell script that creates all of the 365 files I need each year (the script also creates folders for each week of the year, and folders for each year.

With a file name of WES-8-4-12 or HSG-8-2-12, it is really easy to find the date portion of the file name. All I need to do is to retrieve the item (by using Get-Item or Get-ChildItem). WhenI have the FileInfo object, I use the BaseName property to obtain only the file name without the path or the file extension. Therefore, in my example, HSG-7-23-12 returns the following.

PS C:\> $a = Get-Item C:\fso\HSG-7-23-12.docx

PS C:\> $a.basename

HSG-7-23-12

When I have a value such as HSG-7-23-12, I can easily convert that value to provide me with a DateTime object. To do this, I first remove the HSG- portion of the filename. This technique is shown here.

PS C:\> $a = Get-Item C:\fso\HSG-7-23-12.docx

PS C:\> $a.basename

HSG-7-23-12

PS C:\> $a.BaseName.Substring(4)

7-23-12

Now, all I need to do is to cast that value to a datetime object and I am finished. This appears here.

PS C:\> $a = Get-Item C:\fso\HSG-7-23-12.docx

PS C:\> $a.basename

HSG-7-23-12

PS C:\> $a.BaseName.Substring(4)

7-23-12

PS C:\> [datetime]$a.BaseName.Substring(4)

Monday, July 23, 2012 12:00:00 AM

The commands and the output associated with the commands are shown in the figure that follows.

Image of command output

Interestingly enough, it is possible to do this all on a single line. This technique is shown here.

PS C:\> [datetime](Get-Item C:\fso\HSG-7-23-12.docx).basename.substring(4)

Monday, July 23, 2012 12:00:00 AM

Expanding the technique a bit

Now that I know I can create a DateTime object from the base file name, it is a simple matter of replacing Get-ChildItem for Get-Item, and looping through the returned files. I talked about filtering files on Monday of this week and on Tuesday of the week.

Because Microsoft Word changed the file extension during the four years that I have been writing the Hey, Scripting Guy! Blog, I decided to use a wild card character in the extension property. To see how many of each type of files I have, I used the following command where I group by the extension. The command and the output associated with the command are shown here (gci is an alias for the Get-ChildItem cmdlet).

PS C:\> Get-ChildItem -Recurse -Path C:\data\ScriptingGuys -Include HSG*.doc*,WES*.doc* | group

 extension

 

Count Name                      Group

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

  731 .docx                     {C:\data\ScriptingGuys\2008\hsg_11_17_08\HSG_QHF_...

  359 .Doc                      {C:\data\ScriptingGuys\2009\HSG_10_12_09\HSG-10-1...

To pick up the date from the file names as they cross the pipeline, I use the Foreach-Object cmdlet and a version of the command I derived earlier in this blog. The command is shown here.

Get-ChildItem -Recurse -Path C:\data\ScriptingGuys -Include HSG*.doc*,WES*.doc*  |

foreach-object {[datetime]$_.basename.substring(4)}

Adding in the function and changing all the time stamps

I decided to make a few changes to the Set-FileTimeStamps function from the previous blog posting. There are two reasons. The first is that I want to pass a System.Io.FileInfo object to the function instead of a path. Secondly, the Path parameter in the original function uses a string, and passing a FileInfo object to the function automatically casts the object to a string. When this happens, the $doc variable no longer contains a FileInfo object, but rather it contains a string. This generates an error stating that the object does not contain a property named CreationTime or any of the other properties. The modified Set-FIleTimeStamps function is shown here.

Function Set-FileTimeStamps

{

 Param (

    [Parameter(mandatory=$true)]

    [system.io.fileinfo]$doc,

    [datetime]$date = (Get-Date))

    ForEach-Object {

     $doc.CreationTime = $date

     $doc.LastAccessTime = $date

     $doc.LastWriteTime = $date }

} #end function Set-FileTimeStamps

 

The script parameters must reside at the top of the script. The parameters section has not changed from any of the other scripts used this week. It is shown here.

Param(

  $path = "C:\fso",

  [array]$include = @("HSG*.docx","WES*.docx"))

The entry point to the script, accepts the command line parameters, and uses Get-ChildItem to find all of the files. It then walks through the collection of FileInfo objects, creates the time stamp from the file name, and calls the Set-FileTimeStamps function. This is shown here.

## entry point to script

$docs = Get-childitem -path $Path -Recurse -Include $include

Foreach($doc in $docs)

 {

  Try

     {

       $date = [datetime]$doc.BaseName.Substring(4)

       Set-FileTimeStamps -Doc $doc -date $date

     }

  Catch [System.Exception] {"Error occurred setting date for $doc"}

 }

When the script runs, it finds all of the appropriate files and makes the requisite changes to the file time stamps. One such file is shown in the image that follows.

Image of command output

I uploaded the complete script to the Scripting Guys Script Repository.

Well, that is all for today. Join me tomorrow when I have a new PowerTip and I introduce the “love-o-matic.” It is cool, and is the latest Scripting Guys “o-matic” tool.

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: Finding the Type of an Object

$
0
0

Question: What .NET Framework class is leveraged by the Get-EventLog cmdlet?

Answer: System.Diagnostics.EventLogEntry

Question: How would I find the above information?

Answer: Get-EventLog application | get-member

 

Weekend Scripter: Introducing the Scripting Guys PowerShell LoveOmatic

$
0
0

Summary: Microsoft Scripting Guy Ed Wilson shows how to use Windows PowerShell to send random email messages at random times.

Microsoft Scripting Guy, Ed Wilson, is here. It is Sunday in Charlotte, North Carolina in the deep south of the United States. This morning I am reflecting on a conversation I had with Ashley McGlone, a Microsoft PFE and my mentee. I had just finished hearing him make his first ever presentation at TechReady, and I was evaluating his performance (he did an awesome job, by the way). Somehow, I got off on a tangent (if you have ever talked to me, you will realize immediately how rare of an occurrence this is), and I began discussing a script I wrote when I was teaching a VBScript class based on my VBScript Step-by-Step book from Microsoft Press.

I called the script the LoveOmatic (basing the title on the famous series of Scripting Guys tools–including my own PowerShell ScriptOmatic tool). When I used to travel every week teaching scripting workshops around the world, I would send short email messages to Teresa at various times of the day (generally when the students were working on their labs, in addition to before class, after class, after dinner, and so on). In class one day, a student mentioned that I could write a script to do that, and the LoveOmatic was born.

First get rid of “magic numbers”

In my Windows PowerShell 2.0 Best Practices book, I talk at great length about the importance of readability for your Windows PowerShell code. One thing that destroys readability is the presence of “magic numbers.” A magic number is a number that appears in a script with very little context. It simply appears in the script. One generally has to look up the value to see what the script is doing. I like to assign values to well named variables, and then use the variable in my code. It promotes readability and facilitates modification of the script. The following code illustrates my point. 

$numberOfEmails = 6

$oneHour = 3600

$threeHours = 10800

Create an array of strings

Now, I need to create an array of messages. I create five different strings, and then I assign the variables that contain the strings into an array as shown here.

$message1 = "I am thinking of you."

$message2 = "You are the sunshine of my life."

$message3 = "You walk in beauty like the night."

$message4 = "I am glad I met you."

$message5 = "My life is richer with you part of it."

 

$message = $message1,$message2,$message3,$message4,$message5

All the normal email stuff

I use four variables to store the usual email stuff. The four essential email fields are from, to, subject, and the name of the mail server. The following four variables illustrate the technique.

$from = "edwilson@nwtraders.msft"

$to = "ScriptingWife@nwtraders.msft"

$subject = "I am thinking of you"

$smtpServer = "smtphost.nwtraders.msft"

Sending random mail messages at random times

The heart of the LoveOmatic uses the following Windows PowerShell cmdlets:

  • Get-Random
  • Send-MailMessage
  • Get-Random
  • Start-Sleep

Because of these cmdlets, the actual code to send email messages is very simple. I use a for statement to send a specific number of mail messages. The for statement counts up to the value stored in the $numberOfEmails variable. This is shown in the code that follows.

For($i=0; $i -le $numberOfEmails; $i++)

Now, I need to generate a random number that goes from 0 to the number of messages I have stored in my $message array. I keep the returned random number in the $rnd variable. One thing to keep in mind when you use the Get-Random cmdlet, is that the maximum number is never reached. Therefore, the command that is shown here creates random numbers between 0 and 4. It will never return a random number equal to 5.

$rnd = Get-Random -Minimum 0 -Maximum 5

The following command sends the email message. It uses the $to variable and the values contained in $from and $subject. Because the $message variable is an array of message strings, I use the random number stored in the $rnd variable, and then index into the collection of messages. This permits selecting a random mail message to send. For more randomness, the same technique could be applied to the subject field. Here is the code that sends the email.

Send-MailMessage -to $to -body $message[$rnd] `

  -from $from -subject $subject `

  -smtpServer $smtpServer 

I display a message to the console just for status updates as the script runs. This is shown here.

"message: $($message[$rnd]) sent at $((get-date).tostring())"

Now I need to pause the script. I pause it a random amount between 1 hour and 3 hours. To do this, I use the seconds parameter from the Start-Sleep cmdlet, and I choose a random number between 3600 and 10,800. But rather than listing these numbers directly, I store them in variables to make the code easier to read. The Start-Sleep cmdlet is shown here.

Start-Sleep -Seconds (Get-Random -Minimum $oneHour -Maximum $threeHours)

When the script runs, output similar to the one shown in the following image appears.

Image of command output 

I uploaded the complete script to the Scripting Guys Script Repository.

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

 Windows PowerShell, Scripting Guy!, Weekend Scripter, Messaging & Communication, SMTP Mail, Sending email

 

PowerTip: Switch and Other Things

$
0
0

Summary: Learn to post powerful Windows PowerShell command and other things.

Question: What is the most powerful command in PowerShell?

Answer:  Switch

Question: What is `t used for?

Answer: Tab

Community: All about PowerShell Saturday

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about the Windows PowerShell community involvement with PowerShell Saturday.

Microsoft Scripting Guy, Ed Wilson, is here. One of the great things about Windows PowerShell is the strength of our community. Let’s face it, Windows PowerShell is not exactly the easiest technology to learn how to use. In some respects, it is more difficult to learn that VBScript, Perl, or any other scripting language. Oh, I know anyone can learn how to open a Windows PowerShell console and type the letters gps to return a list of processes, but I am talking about really learning Windows PowerShell.

One reason for the complexity is due to the sheer enormity of information available. To truly master Windows PowerShell is to master everything that is documented on MSDN, and a lot of stuff that is not mentioned on MSDN. I learn new things about Windows PowerShell every single day−and I have been using Windows PowerShell since before it was called Windows PowerShell.

The other day I spent nearly 12 hours working on a certain Windows PowerShell script. It was also the day of the Charlotte Windows PowerShell User Group. To be honest, I thought about skipping the user group meeting because I wanted to complete the script. I knew the Scripting Wife would not let me skip the meeting; and besides, when I work from home, getting out to user group meetings is a great bit of social interaction. One of the members of the user group saw me working on the script and asked me if I needed help. I showed him the script, and talked my way through the script in explaining it to him. He made a couple of really great suggestions that enabled me to complete the script. If I had not gone to the meeting, I might still be working on the script.

So what is PowerShell Saturday?

PowerShell Saturday is a community-driven event that is modeled after the very successful SQL Saturday and SharePoint Saturday events. The emphasis is on bringing together local experts and local people who are interested in a specific technology. For this reason, the event happens in conjunction with the local Windows PowerShell User Uroup. The first PowerShell Saturday was held in Columbus, Ohio, and it was sponsored by the Central Ohio PowerShell User Group. I was fortunate to speak at that event. The cool thing is that the event sold out in 13 days, and twice as many tickets could have been sold as evidenced by the wait list for the event.

The great thing about a PowerShell Saturday event is that it provides a chance for local Windows PowerShell users to work on their speaking skills, and as a result, the content tends to be tailored to the specific audience. In addition, nationally recognized experts also present at the event. Because it is a community event, the scalability of the event is unlimited. The events take place during a time when people are able to attend, and a nominal cost helps to defray the cost of food for the event.

PowerShell Saturday in Charlotte, North Carolina

The Charlotte Windows PowerShell User Group decided to host their Windows PowerShell Saturday on September 15, 2012, and it will be the second such event. In the time since the first Windows PowerShell User Group, a domain name has been registered by the community, and a professional website created. PowerShellSaturday.com is now the hub for all future PowerShell Saturday events. The Charlotte PowerShell Saturday site contains the complete speakers list, the abstracts of all sessions, and registration information. I will be making two presentations at the event; and a number of Microsoft premier field engineers, PowerShell MVPs, and community experts will also be speaking. See the speakers site for a biography about each speaker. There are three tracks: a beginner track, an advanced track, and an applied track. See the presentations for more information.

A PowerShell Saturday is about more than 15 PowerPoint presentations−it is about community. Therefore, it provides an excellent chance to see friends and to meet people who are as passionate about Windows PowerShell as you are. I know the Scripting Wife always looks forward to these types of events because it provides her with a chance to see people who she has been tweeting with and to make new friends. In fact, this year we are hosting the speakers dinner at the house that Script built (we are also having a slumber party for many of the out of town visitors, but that is a different story).

The three different tracks are really strong, with a number of excellent nationally known speakers in attendance. If you are in the area, you should register and plan to attend.

Up next, PowerShell Saturday in Atlanta, Georgia

Approximately six weeks after the Charlotte Windows PowerShell Saturday is the Atlanta PowerShell Saturday event. It also is attracting a strong slate of speakers. I know a large number of people who are planning to attend both events. I will also be speaking at the Atlanta PowerShell Saturday event. It will provide me a chance to stop by my favorite computer store while I am in the area. (The Scripting Wife is also planning a stop at the Microsoft Retail Store to see if she can purchase a Surface device.)

After Atlanta, where will PowerShell Saturday be?

I have been talking to a number of people about hosting PowerShell Saturday events 004 and 005. If it works out, the locations will be really cool, as will be the presentations (because I know some of the local experts in each potential location). It also remains to be seen whether I will be able to speak at those events. The great thing about community is that it is not up to one company, one individual, or one user group. Although, when we have a PowerShell Saturday event in Hawaii, I think I will make every attempt to speak at that event.

Bookmark the PowerShell Saturday website, and check it frequently for information about upcoming events.

Join me tomorrow when I will talk about 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: Using Tabs in PowerShell

$
0
0

Summary: Learn about creating tabs in Windows PowerShell by using the `t.

Question: How would I use the `t in a script to produce a tab?

Answer: "`thi"

Question: That syntax above is ugly. What happens if I put a space in it like this: “`t hi”?

Answer: If you include a space in the line like “`t hi”, then you will tab over one tab stop and one additional space.

Question: Is the `t command such as “`thi” case sensitive?

Answer: Yes. It is one of the few things that are case sensitive in Windows PowerShell. If you use the `t as follows, you produce Thi on the line: “`Thi”.

Use PowerShell to Create an HTML Uptime Report

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to create and display an HTML server uptime report.

Hey, Scripting Guy! Question Hey, Scripting Guy! I have a rather unusual request. I need to create a server uptime report at work. But my boss wants me to create the report in HTML so the page can display on one of our intranet servers. I guess the idea is that the boss can go to this web page and see the current uptime of the servers when he wants to do so. I think this is more of a web developer kind of task (I do not know anything about HTML), but my boss is not the sort of person you say “No” to—people never seem to get a chance to say “No” to him twice anyway. Can you help me? I have seen all sorts of VBScript types of articles that seem to do what I want, but my boss also said we are moving away from VBScript, and we are now doing all new projects in Windows PowerShell—so help! By the way, if you are ever in Chicago, look me up and I will buy you and the Scripting Wife a pizza (you have saved me so many times, and I feel you will come through once again).

—RE

Hey, Scripting Guy! Answer Hello RE,

Microsoft Scripting Guy, Ed Wilson, is here. It is a little more than a month away, but the Charlotte PowerShell Saturday registration site is registering people at a really good clip. If you want to attend this all-star event, you should make your registration before it is too late. With three different tracks and a star-studded slate of speakers, this is going to be a major Windows PowerShell event. Due to technical considerations, the sessions will not be broadcast via Live Meeting (or Lync), so you will need to be in Charlotte on September 15, 2012 to see the sessions.

RE, a free pizza? Dude, how can I refuse—even better, Chicago pizza? Oh dude, I am all ears (just as Bugs Bunny once said to Elmer Fudd).

First obtain the server up time

The first thing that needs to be done is to obtain the uptime of the server. There are all sorts of things involved in this. (I even wrote a pretty involved article about this very subject for TechNet magazine: Calculating Server Uptime.) For the sake of argument, and for simplicity, I am going to use the LastBootupTime property from the Win32_OperatingSystem WMI class. When querying the value of that property, the number returned is not very easy to understand. This is shown here.

PS C:\> (gwmi win32_operatingsystem).lastbootuptime

20120806121018.496471-240

Luckily, WMI objects in Windows PowerShell have a method called ConvertToDateTime that knows how to convert the WMI time to a normal DateTime object. Therefore, all that needs to occur is to store the returned WMI object in a variable, and call the method. This technique is shown here.

PS C:\> $wmi = gwmi win32_operatingsystem

 

PS C:\> $wmi.ConvertToDateTime($wmi.LastBootUpTime)

 

Monday, August 6, 2012 12:10:18 PM

Because I am going to use this information later, I want to create a custom object that returns only the computer name and the uptime. I could use the Select-Object cmdlet to do this, but today I feel like I will use the New-Object cmdlet and create a new psobject. This code is shown here.

     $os = Get-WmiObject -class win32_OperatingSystem -cn $s

     New-Object psobject -Property @{computer=$s;

       uptime = (get-date) - $os.converttodatetime($os.lastbootuptime)}

I put all of this information into a function, and I configure it to accept an array of strings for the input. Here is the Get-UpTime function.

Function Get-UpTime

{ Param ([string[]]$servers)

  Foreach ($s in $servers)

   {

     $os = Get-WmiObject -class win32_OperatingSystem -cn $s

     New-Object psobject -Property @{computer=$s;

       uptime = (get-date) - $os.converttodatetime($os.lastbootuptime)}}}

Creating an HTML report from within PowerShell

The entry point to the script contains two variables. These variables are exposed as command-line parameters to the script. You can modify the default values, and simply run the script as you wish. Here are the command-line parameters.

Param(

  [string]$path = "c:\fso\uptime.html",

  [array]$servers = @("dc1","dc3","ex1","hyperv1","hyperv2","hyperv3")

)

The part that creates the HTML report is really simple. It uses the ConvertTo-HTML cmdlet. Here is the cool part of the script. I call the Get-UpTime function and pass the servers from the command-line parameter, $servers. I pipe the custom PSObject that returns from the Get-Uptime function to the ConvertTo-HTML cmdlet, and I create a table. The only HTML code I use is to tell the Server Uptime Report to display as an H1 heading. It is larger and bolder than using the –title parameter. Also, by placing it in the body of the cmdlets, I can control the way everything displays a bit better. I use a subexpression to return the current date and time, and I redirect the HTML output to file specified by the $path parameter. If the file does not exist, it is created. To display it, I use the Invoke-Item cmdlet and pass the path. Here is the main portion of the script.

Get-UpTime -servers $servers |

ConvertTo-Html -As Table -body "

  <h1>Server Uptime Report</h1>

  The following report was run on $(get-date)" >> $path

 Invoke-Item $path 

I upload the complete HTML_UptimeReport.ps1 script to the Scripting Guys Script Repository. You can obtain the script from this location.

When the script runs, it displays the output shown here.

Image of command output

RE, that is all there is to using Windows PowerShell to create an HTML uptime report. Join me tomorrow for more Windows PowerShell cool 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: Run a PowerShell Script with Space in the Path

$
0
0

Summary: Learn how to run a script with a space in the path.

Question: How do I run a script with a space in the path?

Answer 1: PS > c:\my`folder\myscript.ps1

Answer 2: PS> &(“c:\my  folder\myscript.ps1”)

Question: What is the easiest way to create an array?

Answer 1: $array = “1”,”2”,”3”,”4”

Answer 2: $array = 1..4


Use PowerShell to Create a Report Displaying Free Disk Space

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to create a report that displays free disk space on servers.

Hey, Scripting Guy! Question Hey, Scripting Guy! I know it may be hard to believe in today’s era of multiterabyte disks on laptops, but our servers are constantly running out of disk space. Part of the problem is that they were built several years ago, and with all of the patches, service packs, software installed and uninstalled, registry bloat, and whatever else, we are constantly running out of disk space. We are a small shop, and we do not have a network monitoring program such as System Center. What we do have is a CIO who has no clues about how computers work, and who goes herbitile when any server is down for even five seconds, not to mention when a server is down for a couple of days and we have to order a new drive and restore things from tape to rebuild the system drive. I need something that will produce a daily report letting me know the amount of free disk space on each of the drives. Can you help me out? I have seen some scripts on the Script Repository, but nothing that creates a very nice report.

—DV

Hey, Scripting Guy! Answer Hello DV,

Microsoft Scripting Guy, Ed Wilson, is here. Today it is cool down here in Charlotte, North Carolina in the southern portion of the United States. It is because the skies are cloudy and it is threatening thunder storms. But hey, it is cooler than it has been in a week, so we will accept any temperature relief offered.

DV, because it is a nice cool day down here, I am going to cheat a bit and use the report and the same basic script I wrote yesterday. What I will do is add free disk space to the report—that should work for you.

First find the information

Note   This is the second blog in a series that discusses creating an HTML report that contains server status information. You should read yesterday’s blog, Use PowerShell to Create an HTML Uptime Report, prior to reading today’s.

The WMI class Win32_Volume (in the operating system since Windows Server 2003) contains a property named freespace. Unfortunately, this property displays in bytes, which means that the numbers are rather large and difficult to comprehend. A generic query to Win32_Volume returns the CD-ROM drive, mapped network drives, and other things you may not be interested in receiving. However, a drive type of 3 is a fixed local disk, and it is the information you want to receive. To fix the output requires a couple of things. First, it requires converting the free space from bytes to gigabytes. To do this, I divide by the GB admin constant. I add it to a custom object, and I create a custom label. This technique is shown here.

PS C:\> gwmi win32_volume -Filter 'drivetype = 3' | select driveletter, label, @{LABE

L='GBfreespace';EXPRESSION={$_.freespace/1GB} }

 

driveletter                  label                                       GBfreespace

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

                             System Reserved                       0.106239318847656

C:                                                                  60.1407623291016

Unfortunately, the output is still a bit difficult to read due to the great amount of precision following the decimal. I now use a format specifier to change the way the numbers display. This is shown here.

PS C:\> gwmi win32_volume -Filter 'drivetype = 3' |

select driveletter, label, @{LABEL='GBfreespace';EXPRESSION={"{0:N2}" -f ($_.freespace/1GB)} }

 

driveletter                  label                       GBfreespace

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

                             System Reserved             0.11

C:                                                       60.14

Break up the report

Unfortunately, I cannot just add the disk information as an additional property on the custom object and have it unravel onto the report. This is because all the servers have multiple drives, and I therefore end up with an array of disk objects that I must report. The solution is to break-up the report a bit, and report the information in fragments. Therefore, I go back to my code from yesterday, and modify it just a little so that instead of writing directly to the report, I create a fragment and store the returned fragment in a variable. Also note that you cannot use the fragment and the body parameters together. I decide to change the report title from <h1> to <h2> because I am going to use a different report heading. <h2> as you might imagine is a bit smaller than <h1>.

$upTime = Get-UpTime -servers $servers |

ConvertTo-Html -As Table -Fragment -PreContent "

  <h2>Server Uptime Report</h2>

  The following report was run on $(get-date)" | Out-String

Add the new function and call the function

I now create a function to gather the disk space information. The function contains the essential code that I created at the Windows PowerShell console, but wrapped as a function. 

Function Get-DiskSpace

{

 Param ([string[]]$servers)

  Foreach ($s in $servers)

   {

     Get-WmiObject -Class win32_volume -cn $s |

       Select-Object @{LABEL='Comptuer';EXPRESSION={$s}},

         driveletter, label,

         @{LABEL='GBfreespace';EXPRESSION={"{0:N2}" -f ($_.freespace/1GB)}}

    } #end foreach $s

} #end function Get-DiskSpace

I copy the same essential code that I used to create the Uptime fragment to create the disk space fragment. I use the <h2> tag as a table header to let me know which section of the report appears.

$disk = Get-DiskSpace -servers $servers |

ConvertTo-Html -As Table -Fragment -PreContent "

  <h2>Disk Report</h2> "| Out-String   

Create the new report

Now I need to create the report. First, I add precontent. This content appears at the top of the report. I use the same type of <h1> tag that I used yesterday for the report title. Now the post content consists of the two HTML fragments that I created via the two functions. Instead of converting the entire thing to a string, I write it out to the file, and then I use the Invoke-Item cmdlet to launch the report. This code is shown here.

$disk = Get-DiskSpace -servers $servers |

ConvertTo-Html -As Table -Fragment -PreContent "

  <h2>Disk Report</h2> "| Out-String 

  

ConvertTo-Html -PreContent "<h1>Server Uptime and Disk Report</h1>" `

  -PostContent $upTime, $disk >> $path

 Invoke-Item $path 

The completed report appears in the following image.

Image of command output

I uploaded the complete HTML_UptimeFreeSpaceReport.ps1 script to the Scripting Guys Script Repository.

DV, that is all there is to using Windows PowerShell to create an HTML free disk space report. 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: Creating a Custom Number Display

$
0
0

Summary: Learn how to create a custom number display.

Question: How do I display a “calculated value” (megabytes instead of bytes) from a WMI query when piping data into a Format-Table cmdlet?

Answer: Create a hash table where you want to display the data, and perform the calculation inside curly brackets, and then assign the results to the expression parameter as shown here:

gwmi win32_logicaldisk -Filter "drivetype=3" | ft -Property name, @{ Label="freespace"; expression={$_.freespace/1MB}}

Use PowerShell to Create a Color Server Uptime Report

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to create a color HTML server uptime report.

Hey, Scripting Guy! Question Hey, Scripting Guy! I hope you do not mind me writing to you—I have a rather unusual request. I like the server uptime report that you created the other day, but when I showed it to my boss, all he said was “Its rather plain, isn’t it?” I mean, how shallow. But that is another story. Personally, I thought the uptime report listed what was required, and showed it in a way that was easy to understand, but my boss thought it was plain. So, can you go back to that script and jazz it up a bit? Maybe add a little color? It would be great if you could do that. I tried, but do not see any color parameter for the ConvertTo-HTML cmdlet.

—VC

Hey, Scripting Guy! Answer Hello VC,

Microsoft Scripting Guy, Ed Wilson, is here. This morning I am listening to a German radio station. I checked the Windows 8 app store, and found a web radio app. It provided a list of radio stations, and I chose one from Germany. The Scripting Wife and I are getting ready for our trip in the fall when we are heading to Germany and other countries. We will be visiting a number of Windows PowerShell MVPs, winners of past Scripting Games, guest bloggers, and of course, many of our friends who we made when I used to teach a lot of scripting workshops in Germany and other places. Besides, the weather forecast for Munich is a lot better than the weather forecast for Charlotte, North Carolina—unless of course you like hot and humid weather—really hot and really humid weather.

VC, your request is not strange. After more than 30 years working in corporate America, I have come to realize that some bosses are sort of like ravens—attracted to anything that is bright and shiny. So to make sure your report gets their attention, you need to add a splash of color.

The secret to adding color to the Convertto-HTML cmdlet

Note   This is the third blog in a series about using the Convertto-HTML cmdlet. The first blog talked about creating an HTML uptime report, the second one used Windows PowerShell to create a report that displays disk space in addition to uptime. Today’s blog discusses adding color and stuff to the uptime report. You should read the two previous blogs prior to today’s.

VC, you are right, there is no color parameter for the Convertto-HTML cmdlet. In fact, there is a lack of a lot of stuff for the cmdlets. However, what it does is make it really easy to use HTML. The problem is that, unfortunately, when you get beyond the real basics, you need to know HTML. If you want to add some color, you need to add some style. The easiest way to do this is to create a here-string so that you do not need to worry about concatenation, quoting, and other things.

Add the sections for the style

To begin, the style section begins and ends with a style tag. The opening of the style tag is shown here.

<style>

Here is the closing of the style tag.

</style>

Inside this style section, I add information for the BODY, TABLE, the table head (TH), and the table detail (TD) portions. For the BODY, I add the background color and set it to a color from this Colors by Name MSDN page. This site on MSDN is great because it illustrates the color of each color, and it lists the name and the hex value of the color. For my sample script, I decide to make the background color AntiqueWhite. The code is shown here.

$style = @"

 <style>

 BODY{background-color:AntiqueWhite;}

Now I want to set the borders for the table. This single line of code accomplishes this task. (Note that the line may wrap on your page, but it is a single line of code, and I have added no line continuation marks.)

TABLE{border-width: 1px;border-style: solid;border-color: Black;border-collapse: collapse;}

Now, I need to set the information for the table header. I decide to make it a DarkSalmon color, but I do not change the border colors. This is shown here (once again, this is a single line).

TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:DarkSalmon}

Each row in the table is an instance of a table detail (TD), so I can use the following code to change the color of the individual rows in the table. I make it Bisque so we have a little contrast. I then close the Style  tag, and end the here-string. (The TD line of code is a single line of code.)

TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:Bisque}

 </style>

"@

There was one problem with the original script. It did not handle servers that are not online. To rectify that situation, I use the Test-Connection cmdlet to determine if the server is online. If the server is online, I obtain the uptime. When you run the Test-Connection cmdlet with the quiet switch, the cmdlet returns a Boolean value True/False, enabling a quick test case.

In addition, to ensure that the cmdlet works quickly, I change the buffersize from the default 32 bytes to 16 bytes, and I change the count from a default of 4 pings to only 1. On a well-connected network, these changes work fine. On a network with potential connectivity issues, you will need to play with the defaults. The changes in speed are significant as shown here.

PS C:\> measure-command {Test-Connection dc1 -Quiet}

 

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 3

Milliseconds      : 61

Ticks             : 30619743

TotalDays         : 3.54395173611111E-05

TotalHours        : 0.000850548416666667

TotalMinutes      : 0.051032905

TotalSeconds      : 3.0619743

TotalMilliseconds : 3061.9743

  

PS C:\> measure-command {Test-Connection dc1 -Quiet -BufferSize 16 -Count 1}

  

Days              : 0

Hours             : 0

Minutes           : 0

Seconds           : 0

Milliseconds      : 13

Ticks             : 130932

TotalDays         : 1.51541666666667E-07

TotalHours        : 3.637E-06

TotalMinutes      : 0.00021822

TotalSeconds      : 0.0130932

TotalMilliseconds : 13.0932

The revised foreach loop is shown here.

Foreach ($s in $servers)

   {

     if(Test-Connection -cn $s -Quiet -BufferSize 16 -Count 1)

       {

        $os = Get-WmiObject -class win32_OperatingSystem -cn $s

        New-Object psobject -Property @{computer=$s;

        uptime = (get-date) - $os.converttodatetime($os.lastbootuptime)} }

      ELSE

       { New-Object psobject -Property @{computer=$s; uptime = "DOWN"} }

    } #end foreach S

To incorporate the new style into the Convertto-HTML cmdlet involves only adding the $style variable to the head parameter. This is shown here.

Get-UpTime -servers $servers |

ConvertTo-Html -head $style -As Table -body "

  <h1>Server Uptime Report</h1>

  The following report was run on $(get-date)" >> $path

 Invoke-Item $path 

The script produces a report similar to the one shown here when it runs.

Image of command output

I uploaded the complete HTML_ColorUptimeReport.ps1 script to the Scripting Guys Script Repository. You can copy the complete script there.

VC, that is all there is to fixing up the uptime report and adding a bit of color. Join me tomorrow for more Windows PowerShell cool 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: Using Parameters with the Get-WmiObject PowerShell Cmdlet

$
0
0

Summary: Use parameters with the Get-WmiObject cmdlet

Question: Which parameter of the Get-WMIObject cmdlet takes the place of a WQL where clause?

Answer: The filter parameter takes the place of the WQL where clause as shown here: 
Get-wmiobject win32_logicaldisk –filter “drivetype  =  3”

Question: Which parameter of the Get-WMIObject cmdlet takes the place of a WQL select statement?

Answer: The property parameter takes the place of the WQL select statement as shown here: 
Get-WmiObject  win32_bios -Property name, version

Question: Which parameter of the Get-WmiObject cmdlet permits you to use a native WQL query?

Answer: The query parameter of the Get-WmiObject cmdlet accepts a native WQL query as shown here:
Get-WmiObject -Query "Select name, version from win32_bios"

Use Background Jobs to Run a PowerShell Server Uptime Report

$
0
0

Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use background jobs to run a Windows PowerShell script that produces a server uptime report.

Hey, Scripting Guy! Question Hey, Scripting Guy! I like your script to get uptime and to get free disk space, but I cannot be responsible for running it on a regular basis. In addition, keep in mind we have a very large network, and the script will take a long time to run. Is there a command to make this run in the background?

—RE

Hey, Scripting Guy! Answer Hello RE,

Microsoft Scripting Guy, Ed Wilson, is here. PowerShell Saturday in Charlotte, North Carolina is a little more than a month away (September 15, 2012), and we have all the sponsors and all the speakers lined up, the agendas posted, and nearly half of the tickets are already sold. If you want to attend, you need to get your reservations placed before the tickets are all gone. There will be 200 people attending, and it will be a tremendous day of learning delivered by some “rock star” trainers!  There are three different tracks (Beginner, Advanced, and Applied), so there will be something for anyone who uses or anticipates using Windows PowerShell.

Use Start-Job to run the report

Note   This is the fourth blog in a series about using the Convertto-HTML cmdlet and creating a HTML server uptime report. The first blog talked about creating an HTML uptime report, the second one used Windows PowerShell to create a report that displays disk space in addition to uptime, the third discusses adding color and stuff to the uptime report. You should read the three previous blogs prior to reading today’s.

If you have a large network, it can take a very long time to reach out and touch every server on the network and to bring back the information to a central location. One thing that can help is to run the script as a background job. Using jobs, Windows PowerShell will run the script in the background. You then have the option of using the Wait-Job cmdlet to pause the Windows PowerShell console until the script completes, or you can allow the job to complete. At any rate, it is not really necessary to use the Receive-Job cmdlet to receive the job because the HTML page creates it as part of the script, and not as part of the job itself. The command shown here creates a job and runs the script.

Start-Job -FilePath C:\fso\HTML_Uptime_FreespaceReport.ps1

To receive the job, use the following commands.

Get-Job | Receive-Job

When you have done this, you may want to remove the job. This command accomplishes that task.

Get-Job | Remove-Job

Use Invoke-Command to multithread the job

Using Start-Job on the local computer does not really do much in the way of speeding up things—it simply hides how long the script takes by placing it in the background. If you have a large network, use the Invoke-Command to run the commands against remote machines. Windows PowerShell automatically determines the best number of concurrent connections (by default 32). To use the Invoke-Command cmdlet effectively requires a few changes to the HTML_UptimeReport.ps1 script. The changes involve removing the hard-coded list of servers in the param portion of the script. This first change is shown here.

Param([string]$path = "c:\fso\uptime.html")

The next change involves removing the servers parameter from the call to the Get-UpTime function as shown here.

Get-UpTime |

The next change I make changes the servers parameter on the Get-UpTime function. This change is shown here.

Function Get-UpTime

{ Param ([string]$servers = $env:COMPUTERNAME)

The last change removes the Invoke-Item command that displayed the completed HTML report. This will not work remotely anyway, and it is therefore unnecessary.

I leave the foreach command because I do not want to make more changes to the function than required. The revised HTML_UptimeReport.ps1 is shown here as Invoke_HTML_UptimeReport.ps1.

Invoke_HTML_UptimeReport.ps1

Param([string]$path = "c:\fso\uptime.html")

 

Function Get-UpTime

{ Param ([string]$servers = $env:COMPUTERNAME)

  Foreach ($s in $servers)

   {

     $os = Get-WmiObject -class win32_OperatingSystem -cn $s

     New-Object psobject -Property @{computer=$s;

       uptime = (get-date) - $os.converttodatetime($os.lastbootuptime)}}}

 

# Entry Point ***

 

Get-UpTime |

ConvertTo-Html -As Table -body "

  <h1>Server Uptime Report</h1>

  The following report was run on $(get-date)" >> $path 

I now open my Windows PowerShell console, and I retrieve and store a credential object to be used when making the remote connections. Next, I provide an array of server names. Finally, I call the Invoke-Command cmdlet and specify the computer names and the credentials. I use the FilePath parameter to point to a script that exists on my local computer. Next I use the AsJob parameter to run the command as a job. Finally, I specify a friendly name for the job. This command permits up to 32 simultaneous remote connections to obtain the information. The commands I type are shown here.

$credential = Get-Credential -Credential iammred\administrator

$servers = @("dc1","dc3","ex1","sql1")

Invoke-Command -ComputerName $servers -Credential $credential -FilePath C:\fso\Invoke_HTML_UptimeReport.ps1 -AsJob -JobName uptime

There is one problem with this command. The c:\fso\uptime.html command refers to a folder (c:\fso), which must exist on the remote server. Actually, several of my remote servers have a c:\fso folder, but the ones that do not will generate an error when I receive the job. The commands and associated output are shown in the following image.

Image of command output

To override the default value that is contained in the script, I supply a value for the args parameter of the Invoke-Command cmdlet. The values for the args parameter must appear in the same order that the script declares the parameters.

If I run the command and do not make provisions for multiple file access, file locking issues arise. There are two easy ways to deal with this issue. The first is to dial down the ThrottleLimit value to 1. Doing this, however, does no more than allow for a single connection at a time. This is the same thing the original script accomplished; and therefore, it is not a great solution. A better approach is to modify the output file name, to include the server name. Doing this permits simultaneous file access. Here is a modification to the code.

>> ("{0}{1}_Uptime.html" -f $path, $env:COMPUTERNAME) 

When I use Invoke-Command now, I do not include the file name, but only the \\dc1\share path. This command is shown here.

Invoke-Command -ComputerName $servers -Credential $credential -FilePath C:\fso\Invoke_HTML_UptimeReport.ps1 -AsJob -JobName uptime -args "\\dc1\share\"

RE, that is all there is to using jobs to run a Windows PowerShell script and produce an uptime report. Join me tomorrow for more Windows PowerShell cool 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: Specifying PowerShell Error Actions

$
0
0

Summary: Specify Windows PowerShell error actions.

Question: Which command when typed at the beginning of a script will cause Windows PowerShell to ignore errors and continue executing the code?

Answer: $erroractionpreference=SilentlyContinue

Question: How can I ignore errors for a single command instead of for the entire script?

Answer: Use the ErrorAction parameter and specify one of the following values: SilentlyContinueStopContinueInquire, or Ignore.

Question: That is a lot of typing. Is there an easier way to specify the ErrorAction for a single command?

Answer: Yes. You can use the parameter alias EA and use a number value for the action. For example, 0 is SilentlyContinue.

Weekend Scripter: Use the Windows Task Scheduler to Run a Windows PowerShell Script

$
0
0

Summary: Create a scheduled job to run a Windows PowerShell script that creates an HTML Server uptime report

Microsoft Scripting Guy, Ed Wilson, is here. The amount of emails that are generated when attempting to organize and to arrange an event such as PowerShell Saturday is amazing. Every day, it seems, there are nearly a dozen email messages about one detail or another. Windows PowerShell Microsoft MVP, Jim Christopher, is doing an excellent job of keeping things on track, and the Scripting Wife and Brian Wilhite have been hanging right in there with the work. The event truly will be a major big deal, and it will be fun as well as educational. It will be worth the time to register and to attend this event if you are in the Charlotte, North Carolina area on September 15, 2012.

Creating a Scheduled task to run a PowerShell script

The first thing I need to create a scheduled task to run a Windows PowerShell script is the command line that I will execute. The easy way to find this is to use the Run command. At times, I need to know what the command-line switches are for PowerShell.exe. To see these, I open Windows PowerShell and type powershell /? and then I examine the output that displays. The command and the output from the command are shown here.

Image of command output

When I know which switches to use, I practice my command via Run. The following image illustrates using Run to launch Windows PowerShell and to run a Windows PowerShell script. Keep in mind that this will open, and close Windows PowerShell, which is fine for a script producing a report. In testing, I often use the –noexit switch to see any errors arising from the operation.

Image of message

When I know the command line, I use the Task Scheduler tool, and create a new basic task. First, I need to assign a name and a description. I find it useful to provide a good description as well as a decent name because it facilitates performing maintenance on the task.

Image of menu

The next pane is the Task Trigger pane. It is pretty basic, and self-explanatory. Because I want to create a daily task, I leave that selected. After it is created, it is easy to edit the scheduled task to make it run the task more often, such as every hour if that is the need. One reason I use the Basic Task Wizard is that it is easy to get through the steps needed to create the basic task. I always edit stuff later. The Task Trigger pane is shown here.

Image of menu

Now it is time to set the schedule for the task. In this example, the task runs every morning at 7:00 AM beginning on August 11, 2012.

Image of menu

In the Action pane that follows, I select that we want the scheduled task to Start a program, and then click Next.

Image of menu

In the Start a Program pane, I cheat by placing the command I tested previously from the Run box into the Program/script box. I then click Next. The Start a Program pane is shown here.

Image of menu

Here is where the cheating part comes in to play. I used, directly, the command I tested in the Run box for my program. Rather than attempting to break things up, I simply copied the entire line. The Scheduled Task Wizard is smart enough to know what I wanted to do. It prompts, but it knows. The prompt appears here.

Image of message

When I have completed the Create Basic Task Wizard, I want to open the task and make a couple of additional changes. The easy way to do this is to select the Open the Properties dialog for this task when I click Finish, as shown here.

Image of menu

Because the task runs on a server, and because one might not be logged on to the server at the time the task is to run, it makes sense to tell the task to run whether or not the user is logged on. This opens a credential dialog, and allows me to set the password for the task. This option appears on the General tab of the scheduled job as shown in the image here.

Image of menu

When I have completed configuring the scheduled task, I always right-click the job and select Run. Then I examine the job history to ensure that the task completed properly. The History tab of the scheduled job is shown here.

Image of menu

Well, that is about all there is to creating a scheduled job to run a Windows PowerShell script. In Windows 8 and Windows Server 2012, there are Windows PowerShell cmdlets to create the scheduled job and to create the job triggers and actions—but that will be the subject of a later Hey, Scripting Guy! Blog post.

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: Displaying Only the Current Year in PowerShell

$
0
0

Summary: Learn how to display only the current year.

Hey, Scripting Guy! QuestionHow can I use Windows PowerShell to display only the current year?

Hey, Scripting Guy! Answer

  1. get-date -Format yyyy

  2. get-date –format yy

  3. get-date –f yyyy

  4. (Get-Date).year

  5. Get-Date -UFormat %Y

  6. Get-Date -UFormat %

Use PowerShell to create a Green Red uptime report

$
0
0

Summary: Microsoft Scripting Guy Ed Wilson shows a script that produces red for down and green for up

Weekend Scripter: Color coded uptime report

Microsoft Scripting Guy, Ed Wilson, is here. Well, I have been playing around with this script off and on all week. Last night, my old high school friend John called to discuss plans for our upcoming Kentucky trip – I am teaching a Windows PowerShell class in Georgetown Kentucky, and  I am speaking at the first ever Cincinnati Windows PowerShell User Group. The cool thing about the Cincinnati Windows PowerShell User Group is the Scripting Wife talked to Mike (who is starting the group) when we were in Columbus Ohio during the PowerShell Saturday event. We are both looking forward to helping to launch the Cincinnati Windows PowerShell User Group.

Frankenscript --- for sure – but it works

NOTE: This is the fifth article in a series of articles about using the Convertto-HTML cmdlet and creating a HTML server uptime report. The first article talked about creating an HTML Uptime Report, the second one used PowerShell to create a report that displays disk space as well as uptime. The third article discusses adding color and stuff to the uptime report. The forth article talks about creating a scheduled job to run the script. You should read the three previous articles prior to today’s article.

I will admit it; I am not a web developer. Today’s script will prove that beyond any shadow of a doubt. The script works, but it is not pretty, and I am certain there has to be a better way. In fact, I toyed with adding a bit of J script to the page to do some logic, but that did not work really well because Internet Explorer blocks active content by default, and it was an extra step. In the end, the script I came up with does not display properly in Internet Explorer any way … at least not in the beta version in my version of Windows 8. But the code works, because the page does display properly in Microsoft Word --- strange. Oh well.

 The entry point to the script uses two here strings to build the style and the precontent. I left the TD style (for the table detail) because I add that line based upon whether the server is up or not. The code appears here.

$style = @"

 <style>

 BODY{background-color:AntiqueWhite;}

 TABLE{border-width: 1px;border-style: solid;border-color: Black;border-collapse: collapse;}

 TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:DarkSalmon}

"@

  $precontent = @"

  <h1>Server Uptime Report</h1>

 <h2>The following report was run on $(get-date)</h2>

"@

 $i = 0

 For each server that is passed to the script, I call the Get-Uptime function and store the returned object in a $uptime variable. I also create a variable named after the server and an incremental number. I use the passthru parameter to return the variable that I create. This variable will hold the HTML fragment for later use. The code appears here.

Foreach( $server in $servers)

  {

    $uptime = Get-UpTime -servers $server

    $rtn = New-Variable -Name "$server$i" -PassThru

  

Now if the uptime property is equal to down I create add the TD style with the color of red to my style and I create a HTML fragment using that style, and the information returned from the Get-Uptime function. I store the returned HTML fragment in the value property of the variable created with the Server name and the fragment number. This code appears here.

if ($uptime.uptime -eq "DOWN")

      {

        $upstyleRed = $style + "`r`nTD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:Red} </style>"

        $rtn.value = $uptime | ConvertTo-Html -As Table -Fragment  -PreContent $upstyleRed | Out-String

        } 

  

If the server is up, I add a TD element to the style with a Green background, and create a HTML fragment from the Get-Uptime results and store it in the variable created with the Server name and the fragment number.

  else

     { 

        $upstyleGreen = $style + "`r`nTD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:Green} </style>"

        $rtn.value = $uptime | ConvertTo-Html -As Table -Fragment  -PreContent $upstyleGreen | Out-String

        } 

 

I now add the HTML fragment to the array of fragments as seen here.

  [array]$frags+=$rtn.Name

     $i++

  

I now need to take the array of fragment names, and expand the value property from the variables. I store the returned HTML code in the $fragments variable.

$fragments = foreach($f in $frags) { Get-Variable $f | select -ExpandProperty value }

 

I now use the fragments stored in the $fragments variable and the precontent created earlier and pass it all to the Convertto-HTML cmdlet. This code is similar to code we used earlier in the week.

ConvertTo-Html -PreContent $precontent -PostContent $fragments >> $path

Invoke-Item $path 

 

As I mentioned at the beginning of the article, it does not display properly in Internet Explorer, but it does display properly in Microsoft Word. Strange, but oh well. It was a fun script to write, and I hope you enjoy playing around with it.

 Keep in mind, the <style> tags are being dropped right now by the Script Repository in the code. So you will need to add them in manually – until we can get the bug fixed. Hope you have a great week.

 I uploaded the complete script to the Script Repository. You can obtain the script from there.

 

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: Define PowerShell in Thirty Words or Less

$
0
0

 Summary: Microsoft Scripting Guy, Ed Wilson, offers a quick thirty-word description of Windows PowerShell, and he proves it.

  What is Windows PowerShell in thirty words or less?

 Windows PowerShell is the next generation cmd prompt and scripting language from Microsoft. It can be a replacement for vbscript and for the cmd prompt in most circumstances.

   How can you be sure that was thirty words or less?

   By using the following code:

$a = "Windows PowerShell is the next generation cmd prompt and scripting language from Microsoft. It can be a replacement for vbscript and for the cmd prompt in most circumstances."

  Measure-Object -InputObject $a -Word

 

Use PowerShell to Search AD DS and Produce an Uptime Report

$
0
0

Summary: Learn how to use Windows PowerShell to Search Active Directory Domain Services for servers and produce an uptime report.

Hey, Scripting Guy! Question Hey, Scripting Guy! I enjoyed your series of blogs last week, and I consider uptime reports to be a vital topic. In fact, this was the very task I was assigned to do in my new job—write a script to obtain an uptime report and a free disk space report. I tried in VBScript and it was too complicated. Eventually, I hit upon your blog. The problem is that we have a large domain, and creating a list of servers is not practical. I looked at using other tools to query Active Directory, but they bring back too much garbage. I need an easier solution. Can you help?

—BB

Hey, Scripting Guy! Answer Hello BB,

Microsoft Scripting Guy, Ed Wilson, is here. There are many ways to searchActive Directory Domain Services (AD DS) from within Windows PowerShell. The techniques range from downloading and installing non-Microsoft tools, to installing the admin tools and quering a Windows Server 2008 R2 domain controller, to installing the Active Directory Management Service, to another technique. In fact, there are at least four ways to query AD DS without installing anything. Today I am going to look at using the ADSISearcher to search Active Directory and return only servers. I will then use this technique with the uptime report from last week.

Using the ADSISearcher

To bring back a listing of all computers in Active Directory, I use a command similar to the one here.

([adsisearcher]"objectcategory=computer").findall()

The command can be broken into several pieces, but I often type it as a single command for simplicities sake. The command is three parts:

The adsi searcher:

[adsisearcher]

The filter:

"objectcategory=computer"

The command to find all matches:

findall()

The object returning from the findall method is a DirectorySearches.SearchResult object. It contains two properties: the path and the properties properties. An example of the command and the associated output are shown in the image that follows.

Image of command output

To find the names of the computers, I use the path property with the [adsi] type accelerator, and I retrieve the cn property. An example of such a command is shown here.

([adsisearcher]"objectcategory=computer").findall() | ForEach {([adsi]$_.path).cn}

To find the operating system, I use the OperatingSystem property from Active Directory. I can see the OperatingSystem information by using a command such as the one shown here.

([adsisearcher]"objectcategory=computer").findall() | ForEach {([adsi]$_.path).operatingsystem}

The results from the previous command appear in the following image.

Image of command output

All of the Server operating systems contain the word server in the name. Therefore, I can use a compound LDAP query and filter out computers that contain the name server in the name. The command is shown here.

([adsisearcher]"(&(objectcategory=computer)(OperatingSystem=*server*))").findall()

To retrieve only the server names from the previous command, I pipe the results to the ForEach-Object cmdlet, use the [adsi] type accelerator, and select the cn property. This command is shown here.

([adsisearcher]"(&(objectcategory=computer)(OperatingSystem=*server*))").findall() | 

Foreach-Object {([adsi]$_.path).cn}

I store the retrieved servers in an array as shown here.

[array]$servers = ([adsisearcher]"(&(objectcategory=computer)(OperatingSystem=*server*))").findall() |

      foreach-object {([adsi]$_.path).cn}

When I run the script, the report in the image that follows appears.

Image of command output

I uploaded the complete script to the Scripting Guys Script Repository. You can refer to that script for more details.

 BB, that is all there is to using Windows PowerShell to query Active Directory and to produce an uptime and disk free space report. Join me tomorrow for more Windows PowerShell cool stuff tomorrow.

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: Querying Active Directory via PowerShell

$
0
0

Summary: Learn how to query Active Directory via Windows PowerShell.

Hey, Scripting Guy! Question Can you name five ways to query Active Directory from within Windows PowerShell?

Hey, Scripting Guy! Answer

  1. Use ADO and perform an LDAP dialect query.
  2. Use ADO and perform an SQL dialect query.
  3. Use the Get-ADOObject cmdlet from the Active Directory module.
  4. Use DSQuery.
  5. Use the [ADSISearcher] type accelerator.

Viewing all 3333 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>