Summary: Richard Siddaway talks about using Windows PowerShell to automate the creation of your server documentation.
Hey, Scripting Guy! I’ve just starting learning Windows PowerShell, and I understand how to use it as a scripting language and shell. But what can I use it for in my environment to make my job easier? Can you give me some suggestions?
—CA
Hello CA,
Honorary Scripting Guy, Richard Siddaway, here today filling in for my good friend, The Scripting Guy.
Richard Siddaway is based out of the UK, and he spends his time automating anything and everything for Kelway Ltd. A Windows PowerShell MVP since 2007. Richard is a prolific blogger, mainly about Windows PowerShell (see Richard Siddaway's Blog: Of PowerShell and Other Things), and a frequent speaker at user groups and Windows PowerShell conferences. He has written a number of Windows PowerShell books: PowerShell in Practice, PowerShell and WMI, PowerShell in Depth (co-author); and PowerShell Dive (co-editor). He is currently finishing Learn Active Directory Management in a Month of Lunches, which features a lot of Windows PowerShell. All of the books are available from Manning Publications Co.
CA, You’re in luck because today I start a new series that explains how to make the jump from knowing some Windows PowerShell to being able to use it to make your life easier as an administrator. You’ve spent some time learning to use Windows PowerShell. You’ve got some scripts that you copied from books or downloaded. But what you really need is an answer to the question, “How do I get started automating my environment?”
As with so many other things, the only correct answer is that it depends. It depends on what are the most pressing issues you need to solve. It depends on what you have in place in terms of monitoring, configuration management, and change control. Most of all, it depends on the time and resources you have available to develop or tailor automation scripts for your environment.
The Windows PowerShell community has been very good at producing material to help explain Windows PowerShell as you go through the learning process. There is also a mass of “how to do X…” materials in the various code repositories—especially in the Windows PowerShell Script Center Repository.
However, there is one big gap that the community hasn’t addressed properly. How do you get started automating your environment after you’ve learned some Windows PowerShell? That’s the question I’m going to start to answer in this series of posts as I talk you through developing some automation processes. These processes aren’t prescriptive or limited to what is explained here. They are simply suggestions that you can use as is—or better still, to spark an idea of your own.
If you have ideas for topics that could be discussed in future posts please leave a comment at the end of this post. No promises though. If a suggestion is adopted depends on a number of factors, including the limitations of my development environment.
Active Directory administration is a common target for automation, and I’ll certainly discuss that later—but I think a better start is documenting your servers. Server documentation is a fact of life. No one likes doing it, and very few organizations find the time to do it—but boy, are you grateful when it’s there.
Creating a server document has two main steps. First, you need to find the information, and then you need to put it into the document. How you write the information into the document depends on the type of document (Word, Excel, or even a web page). I’m going to assume that we are using a Word document for now.
Let’s look at collecting some data. Typically as a starting point, you would want to document:
- Operating system version and Service Pack level
- Hardware (CPU, RAM, disk sizes)
- Network configuration
- Running services
Getting this information is a snap with Windows PowerShell because you can use WMI to pull the information directly from the remote machine—all from the comfort of your own Windows PowerShell prompt.
Note I am assuming throughout this post that you are running Windows PowerShell 3.0 on the local computer and on remote machines.
Starting with the operating system:
Get-CimInstance -ClassName Win32_OperatingSystem |
select Caption, ServicePackMajorVersion, LastBootUpTime
Some of the hardware comes from the Win32_ComputerSystem class:
Get-CimInstance -ClassName Win32_ComputerSystem |
select Manufacturer, Model, NumberOfProcessors, NumberOfLogicalProcessors
The memory could be retrieved from this class, but it may not be accurate because it takes into account memory that is allocated to graphics cards and other peripherals. A better way to get the memory is:
Get-CimInstance -ClassName Win32_PhysicalMemory |
Measure-Object -Property Capacity -Sum |
select -ExpandProperty Sum
We’ll restrict disk sizes to local disks. Life would get very complicated if we included mapped network drives and other options.
Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" |
select DeviceId, VolumeName, Size, FreeSpace
Network data comes in two flavors: data on the hardware and data on the configuration (IP address). The IP address data is a good starting point because we can filter to ensure that only those adapters with TCP/IP enabled will be returned.
Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration `
-Filter "IPEnabled=$true" |
foreach
select -InputObject $psitem -Property Description, IPAddress, IPSubnet,
DefaultIPGateway, DNSServerSearchOrder, MACAddress,
@{Name="Name";
Expression={Get-CimInstance -ClassName Win32_NetworkAdapter `
-Filter "DeviceId=$($_.Index)" | select -ExpandProperty NetConnectionID }}
}
The last part of the information consists of the running services on the server. You could use Get-Service for this, but I’ll stick with WMI. You’ll see why in a minute.
Each time you make a call to a remote machine by using WMI, you have to create, use, and then destroy the connection. One of the coolest parts of Windows PowerShell 3.0 is the ability to create a persistent session to a remote machine for WMI. This is known as a CIM session. You create them like this:
$cimsess = New-CimSession -ComputerName server02
The CIM session is used via the –CIMsession parameter:
Get-CimInstance -ClassName Win32_ComputerSystem -CimSession $CimSession
select Manufacturer, Model, NumberOfProcessors, NumberOfLogicalProcessors
The last piece of the WMI side of the puzzle is using the WMI calls. I put them into their own little functions and then put the functions into a module. That way, I can use the functions interactively in addition to generating the report. It also means I’m dealing with objects until I create the report. Each function is of this form:
function getos {
param (
[Microsoft.Management.Infrastructure.CimSession]
$CimSession
)
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimSession |
select Caption, ServicePackMajorVersion, LastBootUpTime
}
Pass the CIM session as a parameter and output the required data. I deliberately didn’t hyphenate the function names to separate them from other functions.
How do we get the data into a Word document? First we have to create a new Word document. Unfortunately, you don’t have any cmdlets to work with Word documents, but you can fall back on the COM object:
function Add-Text {
param (
[string] $style = "Normal",
[string] $text
)
$paragraph = $doc.Content.Paragraphs.Add()
$range = $paragraph.Range
$paragraph.Range.Text = $Text
$paragraph.Range.Style = $Style
$paragraph.Range.InsertParagraphAfter()
}
$word = New-Object -ComObject "Word.application"
$word.visible = $true
$doc = $word.Documents.Add()
$doc.Activate()
add-text -style "Title" -text "Server02"
add-text -style "Heading 1" -text "Operating System"
add-text -style "Normal" -text "Some old text"
$file = [ref]"C:\Scripts\HSG\testsave.doc"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument97") -as [ref]
$doc.SaveAs($file, $saveformat)
$Word.Quit()
Create a COM object for Word:
$word = New-Object -ComObject "Word.application"
Make Word visible, add a document, and then activate the document for use. The Add-Text function is used to write the data into the Word document. Pass a Word style and the text to be written into the document to the function. Add-Text creates a paragraph, sets the style and text, and adds it to the document.
Saving Word documents in Windows PowerShell 3.0 is a little more complicated because of issues handling [ref], and we need to define the file path, the format in which the document will be saved (in this case, a good old .doc format), and then call the SaveAs() method. The final action is to quit Word.
Putting it all together, we get this:
param (
[string]$computer=$env:COMPUTERNAME
)
function getos {
param (
[Microsoft.Management.Infrastructure.CimSession]
$CimSession
)
Get-CimInstance -ClassName Win32_OperatingSystem -CimSession $CimSession |
select Caption, ServicePackMajorVersion, LastBootUpTime
}
function Add-Text {
param (
[string] $style = "Normal",
[string] $text
)
$paragraph = $doc.Content.Paragraphs.Add()
$range = $paragraph.Range
$paragraph.Range.Text = $Text
$paragraph.Range.Style = $Style
$paragraph.Range.InsertParagraphAfter()
}
$word = New-Object -ComObject "Word.application"
$word.visible = $true
$doc = $word.Documents.Add()
$doc.Activate()
$cimsess = New-CimSession -ComputerName $computer
add-text -style "Title" -text $computer
add-text -style "Heading 1" -text "Operating System"
add-text -style "Normal" -text (getos -CimSession $cimsess | format-list | out-string )
$file = [ref]"C:\Scripts\HSG\testreport.doc"
$saveFormat = [Enum]::Parse([Microsoft.Office.Interop.Word.WdSaveFormat], "wdFormatDocument97") -as [ref]
$doc.SaveAs($file, $saveformat)
$Word.Quit()
$cimsess | Remove-CimSession
The data from our function is formatted into a list (this makes it easier to make sure that it fits on the page), converted to a string, and passed into the Add-Text function. The previous example shows only a single function. The full script is available in the Script Center Repository: Server Report.
This technique works. I’ve used it to prepare the documentation for 150 servers, overnight, in preparation for an audit. Needless to say, we passed the audit!
Ways you could extend this include:
- Test for a version of WSMAN on the remote machine, and build a DCOM link if it is WSMAN 2.0.
- Modify code to deal with a Windows Server 2003 error in reporting processors correctly (or apply the hot fix available in article 932370 in the Microsoft Knowledge Base to your computers running Windows Server 2003).
- Collect more data.
- Create a document template to use for the report.
- Use a fixed width font such as Courier New to improve the formatting.
- Use Word tables to present the data.
- Convert the Word document to a .pdf.
- Use Windows PowerShell workflows to run in parallel on multiple servers.
CA, that is all there is to using Windows PowerShell to document your servers. Next time, I’ll have another idea for you to try as you bring automation into your environment.
Bye for now.
~Richard
Thanks, Richard.
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