The Admin’s First Steps: Documenting Servers

The Admin’s First Steps: Documenting Servers

  • Comments 5
  • Likes

Summary: Richard Siddaway talks about using Windows PowerShell to automate the creation of your server documentation.

Hey, Scripting Guy! Question 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

Hey, Scripting Guy! Answer 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 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Topic Suggestion: Best Practices for using Powershell in a distributed, non-active directory environment.

    My company has 50+ independent servers, each behind their own firewalls. Managing them has become difficult as they are not part of a domain or vpn connected. Currently everything is done by remote desktop. What would be a good way to go about handling remote powershell access to these systems? Specifically, I am concerned with keeping track of credentials for remote execution.

  • When you can't use Kerberos authentication for PowerShell Remoting, setting up an HTTPS Listener is your most secure option.  You can modify the TrustedHosts list on your client computer, but this does not authenticate the server; you might be sending usernames and passwords to a malicious computer that's spoofing your intended target.

    As for managing credentials to your workgroup servers, you basically have two options: 1) Save usernames and passwords in some way (as securely as you can accomplish it; there are several options here), or 2) Use digital certificates for authentication (where the certificate's private key is effectively the "password" for the connection.)

  • Hi Derek

    Thanks for reading and taking the time to leave a comment.  Remoting into machines that aren't joined to the domain is quite a big topic and beyond the scope of this series.  The Scripting Guy has graciously agreed to me doing a mini-series on remoting to machines outside your domain.  This will be coming soon.

  • Richard - Great examples in this post. Looking forward to the mini-series on doing the same outside a domain environment.

    Cheers,

    Craig

  • Richard,

    I've just changed jobs last month (September) and on my "new home" I'm currently doing this: documenting servers and network services... This week I was just discussing this subject with my manager and colleagues. This mini series will be of great help to automate the documentation process.

    Looking forward for the next articles.