Query Active Directory with PowerShell and Run WMI Commands

Query Active Directory with PowerShell and Run WMI Commands

  • Comments 5
  • Likes


Summary: Use Windows PowerShell to Query Active Directory for computers and then run WMI commands on the remote machines. The Scripting Guys show you how.

 

Hey, Scripting Guy! Question

Hey, Scripting Guy! We have a major problem at my company. We have a standard corporate desktop we are deploying by using the Windows Deployment tool kit. That part is going well, but the problem is that some departments are buying their own computers, and many of those are arriving with Windows 7 ultimate pre-installed. Many of the users simply join the domain and go to work. In addition, some of the new computers arrive with a 32-bit operating system installed, and that does not allow them to access all of the memory. We are standardized on installing 64-bit operating systems where we can do so. Is it possible to get a report that will tell me the version of Windows and the bit width of the operating system?

-- AC

Hey, Scripting Guy! Answer

Hello AC,

Microsoft Scripting Guy Ed Wilson here. I have been busy playing around with Hyper-V on Windows Server 2008 R2 recently. The product is awesome, powerful, and downright fun. There are a number of pretty cool WMI classes that can be used for management. Using a single Hyper-V machine, you can build an entire network. For my test lab it is perfect.

AC, I decided to build upon some of the things we have looked at earlier in the week in developing a solution to gather operating system information. The Get-OsInfoFromAdComputers.ps1 script uses the Get-ADComputersTestConnection function from yesterday’s Hey Scripting Guy! Blog post.

The first thing the Get-OSInfoFromADComputers.ps1 script does is to obtain a listing of all the computers in the domain and to ping them to determine if they are online or not. If they are online, the script uses WMI to connect to them to retrieve the operating system information from them. A sorted listing is produced to the screen, as well as written to a text file. The complete Get-OsInfoFromAdComputers.ps1 script is seen here.

Get-OsInfoFromAdComputers.ps1

Function Get-ADComputersTestConnection
{
Param(
[switch]$showErrors
)
([adsisearcher]"objectcategory=computer").findall() |
ForEach-Object {
try 
{ 
Test-Connection -ComputerName ([adsi]$_.path).cn -BufferSize 16 `
-Count 1 -TimeToLive 1 -EA stop }
Catch [system.exception]
{
if($showErrors)
{ $error[0].tostring() } 
}
} #end foreach-object
} #End function Get-ADComputersTestConnection
Function Get-OsInfo
{
Param(
[string]$computer
)
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computer
} #end function Get-OsInfo
# *** EntryPoint to Script ***
Get-ADComputersTestConnection | 
ForEach-Object {
Get-OsInfo -computer $_.address } |
Sort-Object -Property osarchitecture |
Format-Table -Property @{ Label="name"; Expression={$_.csname} }, 
@{ Label = "os-bits"; Expression = {$_.osArchitecture} }, 
@{ Label = "OsEdition" ; Expression = {$_.caption} } -AutoSize |
Tee-Object -FilePath c:\fso\osreport.txt

The first thing the Get-OsInfoFromAdComputers.ps1 script does is to query Active Directory Domain Services (AD DS) for all the computer objects in the domain. It then uses the Test-Connection cmdlet to send a ping to each computer to see if it is online or not. Keep in mind that by default the Windows Firewall blocks incoming ICMP echo requests (PING), and therefore unless the Windows Firewall has been modified, all the workstations on the network will be deemed to be inaccessible. This is true even if the domain profile has been selected for the active connection.

The Get-AdComputersTestConnection function is shown here:

Function Get-ADComputersTestConnection
{
Param(
[switch]$showErrors
)
([adsisearcher]"objectcategory=computer").findall() |
ForEach-Object {
try 
{ 
Test-Connection -ComputerName ([adsi]$_.path).cn -BufferSize 16 `
-Count 1 -TimeToLive 1 -EA stop }
Catch [system.exception]
{
if($showErrors)
{ $error[0].tostring() } 
}
} #end foreach-object
} #End function Get-ADComputersTestConnection

The results from the Get-ADComputersTestConnection function are piped to the ForEach-Object cmdlet. Inside the Foreach-Object cmdlet, the Get-OsInfo function is called. The Get-OsInfo function is used to retrieve information about the operating system. The computer that is the target of the WMI query is retrieved from the address attribute that is passed down the pipeline from the Get-ADComputersTestConnection function. This portion of the code, which occurs at the entry point to the script, is shown here:

Get-ADComputersTestConnection | 
ForEach-Object {
Get-OsInfo -computer $_.address }

The Get-OsInfo function uses Windows Management Instrumentation (WMI) to retrieve information about the operating system. Two things are sought: Is the OS 32 bit or 64 bit? And what version of the operating system is installed? For example, is the edition of Windows 7 the Ultimate edition or the Enterprise edition?

When querying WMI in Windows PowerShell, in general one will be using the Get-WmiObject cmdlet. The class that is queried is the Win32_operatingsystem WMI class. On Windows Vista and later, the osArchitecture property will tell you if the installed operating system is 64 bit or 32 bit. On Windows 2003 and earlier, you will need to use other methods, such as querying the PROCESSOR_ARCHITECTURE environmental variable. (A good article about environmental variables is The Scripting Wife Learns About Environmental Variables that was written in preparation for the 2010 Scripting Games. The complete Get-OsInfo function is shown here:

Function Get-OsInfo
{
Param(
[string]$computer
)
Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computer
} #end function Get-OsInfo

One of the nice things about the pipeline is that you can continue to pile commands on. For example, to sort the output from the previous two functions, add in the Sort-Object cmdlet. I decided I wanted to sort by osArchitecture, but you could just as easily sort by the computer name. Here is the Sort-Object command:

Sort-Object -Property osarchitecture |

Next, I would like to have a nice table for my output. To create a table in Windows PowerShell is trivial, use the Format-Table cmdlet. However, if you want to add custom labels to the table, it is not trivial—it requires a hash table for each column head that requires a custom label.

A hash table is created by specifying a key and a value. The ampersand and a pair of curly brackets tell Windows PowerShell that you are going to create a hash table. Semicolons separate the key/value pairs. The example hash table shown here contains two keys and two values for those keys. In many respects the Windows PowerShell hash table can be compared to the dictionary object used in VBScript.

PS C:\> $hash = @{"key" = "value"; "mykey" = "myvalue"}

PS C:\> $hash

Name Value

---- -----

mykey myvalue

key value

PS C:\>

To create custom table headings using the hash table for the Format-Table cmdlet, two predefined keys are used. The first key is Label and the second one is Expression. The value associated with each key is then assigned. The semicolon is used to separate these two keys. Here is the hash table for the first custom table property:

@{ Label="name"; Expression={$_.csname} }

One thing that can be a bit confusing: When using the Format-Table cmdlet to display property values, you do not normally use the $_ automatic variable when choosing the properties to display. However, the use of the automatic $_ variable is a requirement in the script block associated with the expression portion of the hash table. Also, keep in mind that the hash table itself requires a set of curly brackets, as does the expression script block. Therefore, at the end of the expression, there are two curly brackets. The complete Format-Table command is shown here:

Format-Table -Property @{ Label="name"; Expression={$_.csname} }, 

@{ Label = "os-bits"; Expression = {$_.osArchitecture} }, 

@{ Label = "OsEdition" ; Expression = {$_.caption} } -AutoSize |

I thought it would be useful to have both a visual display and a printed report file. The easiest way to configure a display on the screen and to write data to a file is to use the Tee-Object cmdlet. This is shown here:

Tee-Object -FilePath c:\fso\osreport.txt

The output inside the Windows PowerShell ISE is shown in the following image.

Image of output inside Windows PowerShell ISE

The report that is written to the osreport.txt file in my FSO directory is shown in the following image.

Image of report written to osreport.txt file

AC, that is all there is to using the [adsisearcher] type accelerator to search AD DS and call a WMI command. It also concludes Searching Active Directory Domain Services Week. Join us tomorrow for Quick-Hits Friday. We would love for you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • I can't get this script to run in powershell

    Chip Timm

    www.trtechit.com

  • Get this error when it runs???? Access denied? Cmon, I am an Enterprise Admin running this.


    Get-WmiObject : Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
    At line:24 char:1
    + Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computer
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [Get-WmiObject], UnauthorizedAccessException
    + FullyQualifiedErrorId : System.UnauthorizedAccessException,Microsoft.PowerShell.Commands.GetWmiObjectCommand

  • So now I rerun the script and no Access Denied. However, the scripts run and displays errors on all the system that cannot be contacted and then quits leaving no file, let alone anything in one. So now what?

  • thanks

  • Sorry I am new with powershell .........I copy the code and ran it with below error .............

    Can anyone help?

    Missing expression after unary operator '-'.
    At C:\Users\hkitedith\Desktop\Get-OsInfoFromAdComputers.ps1:11 char:2
    + - <<<< Count 1 -TimeToLive 1 -EA stop }
    + CategoryInfo : ParserError: (-:String) [], ParseException
    + FullyQualifiedErrorId : MissingExpressionAfterOperator