How Can I Query a Registry Value Remotely?

Hey, Scripting Guy! QuestionI have a simple question: What is the equivalent to querying the MicrosoftIE_Summary WMI class in Windows Vista? I just need to get the version of Internet Explorer. One small problem though: The Windows PowerShell script is being run remotely from Windows Server 2003. I do not believe I can remotely query the registry using Windows PowerShell 1.0, can I? This is being incorporated into an inventory script that runs server side, and it makes WMI queries and modifies a database accordingly. This is the only Windows Vista or Windows XP WMI compatibility issue I have run into.


-- BC

Hey, Scripting Guy! AnswerHello BC,

Use the stdregprov WMI class to query the registry value remotely. Here is a script I wrote for you that illustrates this process.

GetIEVersionWmi.Ps1

# ------------------------------------------------------------------------
# AUTHOR: ed wilson, Microsoft
# DATE: 7/7/2009
#
# KEYWORDS: Registry, WMI, stdregprov
#
# COMMENTS: This script reads the registry by using WMI
# The hklm value comes from SDK and is a number
# The key value DOES NOT get a backslash in front of it!
# The value value is obvious
#
# ------------------------------------------------------------------------
Param([string]$computer = $env:COMPUTERNAME)
$hklm = 2147483650
$key = "SOFTWARE\Microsoft\Internet Explorer"
$value = "Version"
$wmi = [wmiclass]"\\$computer\root\default:stdRegProv"
($wmi.GetStringValue($hklm,$key,$value)).svalue

 

Troubleshooting a Script That Takes Way Too Long to Run

Hey, Scripting Guy! QuestionCan you show me a more expeditious way to gather the data I need? I have a Windows PowerShell script that retrieves PoolPagedBytes data from an array of servers. It invokes Office Excel. It takes about 5 minutes to run.

Get-PoolPagedBytes.ps1

$erroractionpreference = "SilentlyContinue"

$a = New-Object -comobject Excel.Application $a.visible = $True

$b = $a.Workbooks.Add()
$c = $b.Worksheets.Item(1)

$c.Cells.Item(1,1) = "Server"
$c.Cells.Item(1,2) = "PoolPagedBytes"

$d = $c.UsedRange
$d.Interior.ColorIndex = 19
$d.Font.ColorIndex = 11
$d.Font.Bold = $True

$intRow = 2

Foreach ($strComputer in get-content C:\TEMP\Servers.txt) {
$c.Cells.Item($intRow,1) = $strComputer
$PPB = get-wmiobject Win32_PerfFormattedData_PerfOS_Memory -computername $strComputer |
Sort-Object -descending PoolPagedBytes |
ForEach-Object {[math]::truncate($_.poolpagedbytes / 1048576)}

$c.Cells.Item($intRow,2) = $PPB
$intRow = $intRow + 1
}

$d.EntireColumn.AutoFit()
$d.EntireColumn("B:B").HorizontalAlignment = xlCenter
$b.SaveAs("C:\SCRIPTS\PPB.csv")
$a.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($a)
Remove-Variable a

cls

The problem is that I have to run the above script from my laptop, which has to be powered on and logged in. I want to gather the data from an administrative server that is on 24/7. This server does not have Microsoft Excel installed on it and I can’t get a copy, so I cannot run the above script. I created the following script, but it takes hours to run. What can I do to lessen the time this script takes to run?

ThisScriptTakesHoursToRun.ps1

$strComputers = get-content C:\TEMP\Servers.txt 
$poolPagedBytes =  {[math]::truncate($_.poolpagedbytes /1048576)} 
Foreach ($computer in $strComputers)
{
 get-wmiobject Win32_PerfFormattedData_PerfOS_Memory -computername $strComputers | 
Select-Object -Property __SERVER,$PoolPagedBytes |
Sort-object PoolPagedBytes -desc |
export-csv c:\SCRIPTS\PPB-x.csv }

-- MS

Hey, Scripting Guy! AnswerHello MS,

I believe I see your problem. You are reading the contents of text file servers.txt and storing the listing of computer names in the $strComputers variable. This is seen here:

$strComputers = get-content C:\TEMP\Servers.txt 

Next you use Foreach to walk through a collection (array) of computer names that is stored in the $strComputers variable:

Foreach ($computer in $strComputers)

Now you come to your major problem. When you use the Get-WmiObject cmdlet, you need to realize that it will accept an array of computer names for the -computername parameter. So what you are actually doing here is querying each of the computers that is stored in your $strComputers variable in this one line of code. You are using the $strComputers variable, and not the $computer variable that was declared in your foreach statement. This is seen here:

Get-wmiobject Win32_PerfFormattedData_PerfOS_Memory -computername $strComputers

However, do not forget about the foreach statement, because Windows PowerShell has not forgotten about it. If your servers.txt file contains 100 server names, your Get-WmiObject line queries all 100 servers:

Get-wmiobject Win32_PerfFormattedData_PerfOS_Memory -computername $strComputers

The foreach statement will also execute the above command 100 times (once for each of the 100 servers in the servers.txt file). Therefore, you are querying the 100 servers, and writing the information to the CSV file by using the Export-CSV cmdlet. After you have queried the 100 servers and written the data to the CSV file, you do it again. One hundred servers queried 100 times is a grand total of 10,000 queries. This is why it is taking hours to complete.

Now for the truly evil part: The reason you did not notice the results of 10,000 queries in your CSV file is that by default the Export-CSV cmdlet will overwrite any previously existing CSV file with the same name. Therefore, you are also creating and deleting the PPB-x.csv file 100 times. If you want to control this behavior and ensure that the CSV file is appended to, you use the -noclobber switch. I took the liberty of revising your script.

ThisScriptTakesMinutesToRun.ps1

$poolPagedBytes =  {[math]::truncate($_.poolpagedbytes /1048576)} 

 get-wmiobject Win32_PerfFormattedData_PerfOS_Memory -computername $strComputers | 
 Select-Object -Property __SERVER,$PoolPagedBytes |
 Sort-object PoolPagedBytes -desc |
 Export-Csv c:\fso\PPB-x.csv -NoTypeInformation



How Do I Fix a Corrupted Windows Scripting Host?

Hey, Scripting Guy! Question

Somehow, in my ignorance I have corrupted Windows Scripting Host. I am now getting the error message seen here:

Image of error message displayed


I am using neither Norton nor Symantec, so I discounted that portion of the error message. Oh, yes, this just started occurring last night. After getting this error, I ran a program that stated that WSH is enabled. Nevertheless, I continue to get this error message. Can you direct me to a download that will reinstall Windows Scripting Host? Alternatively, do you have another suggestion?


-- EF

Hey, Scripting Guy! AnswerHello EF,

Bummer. I am not a desktop support person, so I am probably not the best person for this question. Because you are running Windows Vista, several items come to mind:

·   Some antivirus products disable scripting or hijack the script CLSIDS in ways that break. Go buy a better antivirus product (if you can find it).

·   There are policy settings that disable script execution.

·   There are bad installers that misreregister the script DLLs, install old versions, or commit other chicanery.

Windows Script Host 5.7 (WSH 5.7) is built into Windows Vista, and is not an optional feature. Therefore, there is no package or feature user interface for it. You can neither uninstall nor re-install WSH 5.7. One thing you might do is Run regsvr32.exe on vbscript.dll and jscript.dll (run it elevated, for both 32-bit and 64-bit versions if on 64-bit operating system). This often fixes things up.


How Can I Check if a User Has an SIP Account in Active Directory?

Hey, Scripting Guy! QuestionHow I could check via script if a user has an SIP account in Active Directory?


-- JD

Hey, Scripting Guy! AnswerHello JD,

You can use an LDAP query string something like this:

(objectCategory=user)(msRTCSIP-PrimaryHomeServer=CN=LC
Services,CN=Microsoft,CN=GRPSAMOKR009,CN=Pools,CN=RTC
Service,CN=Microsoft,CN=System,DC=mycompany,DC=com)

Unfortunately, this particular attribute does not permit wildcarding, so you will have to point it to the full path.


From the Command Line, Can I Set the Domain Controller I Use to Change Passwords?

Hey, Scripting Guy! Question

If I use this script to change a user's AD password…


Set objUser = GetObject("LDAP://cn=KenMyer,ou=Finance,dc=fabrikam,dc=com")
objUser.SetPassword("i5A2sj*!")

…does it change it against the DC I have chosen in ADUC or the DC I have authenticated against? Is there a way I can set which DC I use to change passwords from the command line?


-- LH

Hey, Scripting Guy! AnswerHello LH,

It will, more than likely, use whatever domain controller (DC) is in your site. When it makes the request, the first DC to respond is the one that handles the request. It may be the one that authenticated you, because that information is stored in the registry, but is not guaranteed (for example, the DC could be busy or down) at which time it will then request from another DC in your site, or failing that, do a general lookup from DNS to see who will respond.

To use a specific server to respond to the request, you can try something like this (in this sample, Berlin is the name of the DC you wish to use to respond to the request):

Set objUser = GetObject("LDAP://Berlin/cn=KenMyer,ou=Finance,dc=fabrikam,dc=com")
objUser.SetPassword("i5A2sj*!")

 

How Can I Retrieve a List of Installed Programs from Remote Computers?

Hey, Scripting Guy! Question

I am trying to get the list of installed programs from Add/Remove Programs on remote computers, but I keep running into problems. Here is my script.

ReadTextAndQueryForInstalledSoftware.ps1

$a = get-content C:\myscripts\computers.txt
foreach ($z in $a) {
$computername = $z
write-host $computername
get-wmiobject -class "Win32_Product"  -computername "$computername" |
format-table __server, name, decsription, identifyingnumber |
out-file C:\myscripts\ok.txt -append
}

I am new to Windows PowerShell and am trying to learn by trial and error, but I keep being held up with the remote part. The script works on the local computer, but it will not run on the remote computer. This is the error that I receive:


159**********
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT:
0x800706BA)
At C:\myscripts\software.ps1:7 char:14
+ get-wmiobject <<<<  -class "Win32_Product"  -computername "$computername" |
format-table __server, name, decsription, identifyingnumber |
out-file C:\myscripts\ok.txt -append


-- JM

Hey, Scripting Guy! AnswerHello JM,


There are a few things that could be going on:

·   The MSI WMI Provider is not installed on the server operating system by default. It must be added.

·   The WMI installation on the remote computer could be corrupted. You may need to do some troubleshooting

·   There could be a rights issue. You must be a member of the local administrators group on the remote computer by default.

The specific error you are getting is not actually a WMI error but rather a DCOM error. This is because WMI remoting relies upon DCOM. The error number 0x800706BA means that DCOM is not able to make a remote connection because of the RPC server being unavailable. One quick thing to check is the status of the Windows Firewall.

Here are some resources that may be of interest: We have a couple of good webcasts on the Script Center WMI hub. Do not forget about WMI troubleshooting in the TechNet Library and the WMI team blog.


This brings us to the end of another Quick-Hits Friday article and the end of another exciting week of articles on the Script Center. We do not know about you (although we will if you email scripter@microsoft.com), but we feel this week’s Hey, Scripting Guy! articles have been extremely cool. At least we had fun writing them. If you want to be the one who is in the know at work, follow us on Twitter. We promise no spam, no advertisingjust salient information regarding the Script Center. You can also join our group on Facebook. Do not forget about the Official Scripting Guys Forum; there is a lot of good information exchanged over there, too. Have a great weekend, and join us on Monday (Tuesday in Australia) for the beginning of another awesome week on the Script Center. Until then, take care.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys