Troubleshooting the Use of a WMI Class

Hey, Scripting Guy! QuestionHey, Scripting Guy! When we try to work with the Win32_OperatingSystem WMI class on either Windows Server 2008 or Windows Vista, we run into a problem with our WMI script because of the way we were connecting to the instance of the class by using the key. When we open the class in WbemTest, there is no key for the class. It appears, therefore, that the WMI class is corrupt or there is a bug in Windows Server 2008 or Windows Vista. Can you confirm the bug for us and talk to the appropriate people? Thank you.

-- KZ

Hey, Scripting Guy! AnswerHello KZ,

You do not see the key for the Win32_OperatingSystem WMI class because the class was converted to a singleton. This means that there is only one instance of the WMI class. The advantage of a singleton WMI class is that it allows you to work directly with the members and to not worry about it returning a collection. This change, as you indicated, came about in Windows Server 2008 and Windows Vista. You can easily identify a WMI singleton class by looking for the singleton qualifier on the class when you open it in the Windows Management Instrumentation Tester (WbemTest) utility. This is seen here:

Image of snigleton WMI class

 

How Can I Create a Local Account on a Server and Add It to the Local Administrators Group?

Hey, Scripting Guy! Question

 

 

Hey, Scripting Guy! I am trying to create a function that creates a local account on a server and then adds that newly created account to the local administrators group. I have been fighting with this thing for two days because I keep getting the following error.

Exception calling "Create" with "2" argument(s): "An invalid directory pathname was passed
"
At :line:69 char:22
+   $user = $comp.Create <<<< ("User", $accountName)

Here is my function that is generating the error.

CreateUserFunction—DoesNotWork.ps1

Function create-account ([string]$accountName = "$localuser1") {
  $hostname = $strComputer
  $comp = [adsi] "WinNT://$hostname"
  $user = $comp.Create("User", $accountName)
  $user.SetPassword("Pass1")
  $user.SetInfo()
     
      $objUser = [ADSI]("WinNT://$strcomputer/$localuser1")
      $objGroup = [ADSI]("WinNT://$strcomputer/Administrators")
      $objGroup.PSBase.Invoke("Add",$objUser.PSBase.Path)

-- JP

 

Hey, Scripting Guy! Answer

Hello JP,

The first thing I notice is that you have a dollar sign in front of the localuser1 name in your parameter declaration. This is seen here.

Function create-account ([string]$accountName = "$localuser1")

When you get to the create method, it will try to expand the value of a variable $localuser1 instead of creating a user named localuser1.

The next thing I notice is you assign the value of the variable $strComputer to a variable called $hostname, but you never use the variable $hosthame. Also you never pass the variable $strComputer to the function, so I am afraid your script does not know where to connect. This is seen here:

$hostname = $strComputer

When you connect to the local computer, you use the $localuser1 variable that you assigned to the $accountName variable. But as we have seen earlier, this appears to be confusing as well:

$user = $comp.Create("User", $accountName)

Other than that, your script looks like it would work fine. I took the liberty of rewriting it a little. A couple of things to note:

·         I moved the parameter declaration inside the function. This provides a cleaner approach when using more than two or three parameters.

·         I have the group hard-coded to administrators (your requirement), but exposed the group to the parameters. This gives you more flexibility to add users to other groups.

·         I moved the computer name to the parameter, but assigned it to the computername environmental variable. This adds flexibility while maintaining ease of use.

·         I moved the password to a parameter to avoid hard-coding it in the script.

·         I use class hints in the WinNT calls for group and for user.

CreateUserFunction-Works.ps1

Function create-account
{
Param(
   [string]$user,
   [string]$group = "Administrators",
   [string]$computer = $env:computername,
   [string]$password
) #end param

  $comp = [adsi] "WinNT://$computer"
  $user = $comp.Create("User", $user)
  $user.SetPassword($password)
  $user.SetInfo()
     
      $objUser = [ADSI]("WinNT://$computer/$user,user")
      $objGroup = [ADSI]("WinNT://$computer/Administrators,group")
      $objGroup.PSBase.Invoke("Add",$User.PSBase.Path)
} #end function create-account


 

Troubleshooting a Windows PowerShell Script That Works with WMI Information

Hey, Scripting Guy! Question

Hey, Scripting Guy! I am not sure if I am doing something wrong or if Windows PowerShell is not working the way I had planned. I am looking to extract information from WMI and to run some true/false queries on it. Here is an example of what I am trying to do:

$me = get-wmiobject -class Win32_ComputerSystem -namespace "Root\CIMV2"
If ($me.DomainRole = 5) {echo True}

The problem is that it will always echo true, even when domain role does not equal 5. Is this a problem with the WMI output or am I just doing something wrong? Thanks in advance.

-- MA

 

Hey, Scripting Guy! AnswerHello MA,

The answer is yes, you are doing something wrong. Actually, what you are doing is correct according to syntax (and is actually pretty cool), but it is not giving you the desired results. This is called a logic error. Logic errors are some of the hardest types of errors to spot because they do not generate errors. They can absolutely drive you bonkers. What you are doing is assigning the value of 5 the domainrole property. You will notice that the first two value assignments work and the string is displayed. On the third line, we create a readonly variable. When we attempt to assign a value to the $readonly variable, an error is generated. This proves that you are assigning a value to the variable. This is illustrated here:

PS C:\> if($a=5) { "a is five" }
a is five
PS C:\> if($a=3) { "a is five" }
a is five
PS C:\> New-Variable -Name readonly -Option readonly
PS C:\> if($readonly=12) { "readonly is 12" } else { "unable to modify readonly" }
Cannot overwrite variable readonly because it is read-only or constant.
At line:1 char:13
+ if($readonly <<<< =12) { "readonly is 12" } else { "unable to modify readonly" }
    + CategoryInfo          : WriteError: (readonly:String) [], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : VariableNotWritable

The cool thing is that you can use the if statement to verify that your value assignment succeeds, which is a pretty neat trick. What you want to do is use the equality operator and not the assignment operator. The equality operator is –eq and the assignment operator as you have seen is the equals sign (=). Your script threw me at first, because I do not use the echo alias for the Write-Output cmdlet. In fact, I very seldom use the Write-Output cmdlet. One thing that is neat about the Write-Output cmdlet is that the quotation marks are not required around the True. Here is an example of using the equality operator in your script:

$me = get-wmiobject -class Win32_ComputerSystem -namespace "Root\CIMV2"
If ($me.DomainRole -eq 5) {echo True}


 

How Do I Enable the Windows Scripting Host?

Hey, Scripting Guy! Question

Hey, Scripting Guy! I was going to try some scripting with WScript and I keep getting this error:

CScript Error: Windows Script Host access is disabled on this machine. Contact your administrator for details.

 I am on my home computer and I am on the administrator account, so I guess this means I am the administrator. How can I contact myself for details when I have no idea what is going on! I have been trying to look around the Internet to see how I may enable it, but never really found anything yet. How can I enable WScript on my computer so that I can use the scripts I have found on the Script Gallery?

-- NK

 

Hey, Scripting Guy! Answer

Hello NK,

It is unusual that the scripting host would be disabled. It is not disabled by default, so I suspect that some software package (antivirus or other security software) has disabled it on your computer. This was rather rude of them, and they should have asked! The error you are getting is seen here:

 Image of Windows Script Host disabled

Never fear, Microsoft Scripting Guys to the rescue! The execution of VBScripts is controlled by the registry setting that is seen here:

 Image of registry setting that controls execution of VBScripts

Change the Enabled value from 0 to 1 and your scripts will work. This does not require a reboot. Keep in mind that there could also be a similar entry in a similar location in HKEY_LOCAL_MACHINE. A detailed discussion of this procedure is in the Microsoft Press book, Microsoft VBScript Step by Step.

 

Thank you everyone for all your interesting questions this week. It seems like forever since we have had a Quick-Hits Friday because we spent the last two weeks reviewing the 2009 Summer Scripting Games. If you want to keep up with what’s happening on the Script Center, follow us on Twitter, or Facebook. If you would like to share scripting experiences with others (ask questions, answer questions, and get into interesting discussions), check out the Official Scripting Guys Forum. You can always contact us at scripter@microsoft.com. Make sure you check out the new Script Gallery. Until next week, take care.  

Ed Wilson and Craig Liebendorfer, Scripting Guys