Quick-Hits Friday: The Scripting Guys Respond to a Bunch of Questions (9/10/10)


Summary: The Scripting Guys answer questions about Windows Features, and discuss troubleshooting VBScript scripts and Windows PowerShell.

In this post:


 Converting a VBScript Script to a Windows PowerShell Script

Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to convert one VBScript script to Windows PowerShell. Mostly, it is very easy, but one fragment I cannot reproduce in any way. In this part of the script, I need to create a new WMI class. It might be it is singleton. Whatever it is, I will need to populate its properties. Any Internet searches return only instance creation for existing classes, but that is not what I need. I need to create the entire class. Here is the VBScript code:

Sub PrepareWMI
Dim WMI, wmiObject, wmiCol, wmiItem
Set WMI = GetObject(“winmgmts://./root/CIMv2”)
On Error Resume Next
Set wmiObject = WMI.Get(“PS_Class”)
If Err then
Set wmiObject = WMI.Get
wmiObject.Path_.Class = “PS_Class”
wmiObject.Properties_.Add “TestProp”, 123 ‘CIM_UINT32
wmiObject.Properties_.Add “Name”, 8 ‘
wmiObject.Properties_(“Name”).Qualifiers_.Add “key”, True
End If
On Error Goto 0
Set wmiCol = WMI.ExecQuery(“SELECT * FROM PS_Class”)
For each wmiItem in wmiCol
End Sub

Follow-up: I found a workaround for current task—just creating a subclass of another WMI class, but this is different. This way I get a bunch of unneeded and properties. In VBScript when I create a new class from scratch, by default it contains no properties.

Here is my workaround:

$MSE = [wmiclass]“CIM_ManagedSystemElement”
$PSClass = $MSE.PSBase.Derive(“PS_Class”)
$Inst = $PSClass.psbase.CreateInstance()
$Inst.TestProp = 12345
$Inst.Name = “First instance”

— VG



Hey, Scripting Guy! Answer Hello VG,

That is essentially what I was going to do; you beat me to it. The “unwanted” properties you are getting are system properties that flow through on all WMI classes in Windows PowerShell. You are also getting properties that are inherited from CIM_ManagedSystemElement WMI abstract class from where you derive your new PS_Class WMI class.

All WMI classes in Windows PowerShell have the system properties that are shown here.

__GENUS                  : 2

__CLASS                   : PS_Class

__SUPERCLASS         : CIM_ManagedSystemElement

__DYNASTY                : CIM_ManagedSystemElement

__RELPATH                : PS_Class.Name=“First instance”


__DERIVATION           : {CIM_ManagedSystemElement}

__SERVER                  : MrEd1

__NAMESPACE           : ROOT\cimv2

__PATH                      : \\MrEd1\ROOT\cimv2:PS_Class.Name=“First instance”


The properties that are listed here are inherited.

Caption          : 

Description     : 

InstallDate     : 

Status            : 


The properties seen here are the two properties you created in your script.

Name             : First instance

TestProp        : 12345


Therefore, what you have is not really a “work around” but it is the way that it would be done. The way you can control what is output by default from your WMI class is to modify the format.xml file that is used by Windows PowerShell for your specific WMI class. In this way, using Get-WmiObject on it would only return your specific properties. This is done with win32_bios and other WMI classes. This is shown here:

PS C:\> gwmi win32_bios

SMBIOSBIOSVersion : 7LETB7WW (2.17 )
Manufacturer            : LENOVO
Name                        : Ver 1.00PARTTBLx
SerialNumber            : L3L4518
Version                     : LENOVO  2170

All the system properties and inherited properties are there, but they are hidden by default. By piping the output to the Format-List cmdlet, you can see everything:

PS C:\> gwmi win32_bios | fl *

Status                            : OK
Name                             : Ver 1.00PARTTBLx
Caption                          : Ver 1.00PARTTBLx
SMBIOSPresent              : True
__GENUS                       : 2
__CLASS                        : Win32_BIOS
__SUPERCLASS              : CIM_BIOSElement
__DYNASTY                    : CIM_ManagedSystemElement
__RELPATH                    : Win32_BIOS.Name=”Ver 1.00PARTTBLx”,SoftwareElementID=”Ver 1.00PARTTBLx”,Sof
                                         twareElementState=3,TargetOperatingSystem=0,Version=”LENOVO – 2170″
__DERIVATION              : {CIM_BIOSElement, CIM_SoftwareElement, CIM_LogicalElement, CIM_ManagedSyste
__SERVER                      : MrEd1
__NAMESPACE               : root\cimv2
__PATH                          : \\MrEd1\root\cimv2:Win32_BIOS.Name=”Ver 1.00PARTTBLx”,SoftwareElementID=”
                                       Ver 1.00PARTTBLx”,SoftwareElementState=3,TargetOperatingSystem=0,Version=”L
                                       ENOVO – 2170″
BiosCharacteristics         : {7, 8, 9, 11…}
BIOSVersion                   : {LENOVO – 2170, Ver 1.00PARTTBLx}
BuildNumber                   :
CodeSet                         :
CurrentLanguage           : enUS
Description                     : Ver 1.00PARTTBLx
IdentificationCode          :
InstallableLanguages     : 1
InstallDate                     :
LanguageEdition            :
ListOfLanguages            : {enUS}
Manufacturer                  : LENOVO
OtherTargetOS               :
PrimaryBIOS                   : True
ReleaseDate                   : 20080425000000.000000+000
SerialNumber                  : L3L4518
SMBIOSBIOSVersion       : 7LETB7WW (2.17 )
SMBIOSMajorVersion      : 2
SMBIOSMinorVersion      : 4
SoftwareElementID        : Ver 1.00PARTTBLx
SoftwareElementState   : 3
TargetOperatingSystem : 0
Version                           : LENOVO – 2170
Scope                             : System.Management.ManagementScope
Path                                : \\MrEd1\root\cimv2:Win32_BIOS.Name=”Ver 1.00PARTTBLx”,SoftwareElementID=”
                                         Ver 1.00PARTTBLx”,SoftwareElementState=3,TargetOperatingSystem=0,Version=”L
                                         ENOVO – 2170″
Options                           : System.Management.ObjectGetOptions
ClassPath                       : \\MrEd1\root\cimv2:Win32_BIOS
Properties                       : {BiosCharacteristics, BIOSVersion, BuildNumber, Caption…}
SystemProperties           : {__GENUS, __CLASS, __SUPERCLASS, __DYNASTY…}
Qualifiers                        : {dynamic, Locale, provider, UUID}
Site                                 :
Container                       :


 Using the Add-Windowsfeature Cmdlet to Add the Windows PowerShell ISE to a Remote Server 

Hey, Scripting Guy! Question

Hey, Scripting Guy! Is there way to use the Add-Windowsfeature cmdlet to add the Windows PowerShell ISE to a remote server that does not currently have it installed?

— FR



Hey, Scripting Guy! Answer Hello FR,

But of course. This is one of the awesome things about Windows PowerShell remoting. The Add-WindowsFeature cmdlet is available from the servermanager module. I talked about the servermanager module back in July during Group Policy Week. However, that module is not installed on a Windows 7 machine, even when the RSAT tools are installed. One reason for this is that the Add-WindowsFeature cmdlet “does not remote” because it does not have a –computername parameter. However, using Windows PowerShell remoting, you do not need to have the servermanager module installed on your Windows 7 machine, and you do not need to be able to remote Add-WindowsFeature because the commands will execute on the remote machine. The first thing to do is to use the Enter-PSSession cmdlet to enter a remote Windows PowerShell session on the target server that does not have Windows PowerShell ISE installed on it. After you have entered the remote Windows PowerShell session, import the servermanager module and check on the status of the Windows PowerShell ISE feature. These commands are shown here:

PS C:\> Enter-PSSession -ComputerName hyperv-box
[hyperv-box]: PS C:\Users\ed\Documents> Import-Module *server*
[hyperv-box]: PS C:\Users\ed\Documents> Get-WindowsFeature -Name *ise*

Display                                                                                Name
————                                                                            —-
[ ] Windows PowerShell Integrated Scripting Environm…   PowerShell-ISE

Note that the [ ] box is not checked in the above output. This means the Windows PowerShell ISE is not installed on the remote server.

Because I could use wildcard characters to get the Windows Feature, I decided to try to use a wildcard character to add the Windows Feature. This, however, results in the error shown here:

[hyperv-box]: PS C:\Users\ed\Documents> Add-WindowsFeature -Name *ise*
Add-WindowsFeature : ArgumentNotValid: Invalid role, role service, or feature: ‘*ise
. The name was not found.
+ CategoryInfo : InvalidData: (:) [Add-WindowsFeature], Exception
+ FullyQualifiedErrorId : NameDoesNotExist,Microsoft.Windows.ServerManager.Comm

Success     Restart Needed      Exit Code     Feature Result
——––     ————-               ———        ————–
False          No                          Invali…        {}

When I use the correct name, however, the command comes off without a hitch. The output from Add-WindowsFeature indicates if I need to restart the server or not. If I do, I could use the Restart-Computer cmdlet. When I am done, I use the Exit-PSSession command to exit the remote Windows PowerShell session. These two commands are shown here:

[hyperv-box]: PS C:\Users\ed\Documents> Add-WindowsFeature -Name PowerShell-ISE

Success     Restart Needed     Exit Code       Feature Result
———-     ————–            ———           ————–
True           No                         Success         {Windows PowerShell Integrated Scripting E…

[hyperv-box]: PS C:\Users\ed\Documents> Exit-PSSession
PS C:\>

The following image illustrates using all these commands in a Windows PowerShell session from my Windows 7 desktop to the remote Windows Server 2008 R2 server named hyperv-box.

Image of using these commands in Windows PowerShell session


Troubleshooting a VBScript Script to Find and Replace in SQL Server 2008

Hey, Scripting Guy! Question

Hey, Scripting Guy! I am trying to do a find and replace for a SQL 2008 CreateTables.sql file that I receive from one vendor that I need to run in a SQL 2005 environment as part of a nightly BCP. The problem is that the datatype [date] is not recognized in SQL 2005, so I’d like to search through the 4000+ lines of the CreateTables.sql file and replace [date] with [datetime] through a script.  I have written the VBscript script below; however, when I run the script I wrote, it inserts carriage returns and spaces which render the SQL file useless.  Is there a way I can do this through a Windows PowerShell script or other script?

Const ForReading = 1
Const ForWriting = 2

Set objFSO = CreateObject(“scripting.FileSystemObject”)
Set objFile = objFSO.OpenTextFile(“C:\Scripts\CreateTables.sql”, ForReading)

strText = objFile.ReadAll
strNewText = Replace(strText, “[date]”, “[datetime]”)

Set objFile = objFSO.OpenTextFile(“C:\Scripts\CreateTables.sql”, ForWriting)
objFile.WriteLine strNewText




Hey, Scripting Guy! Answer Hello JD,

I would use write instead of writeline. The code to modify is shown here:

Set objFile = objFSO.OpenTextFile(“C:\Scripts\CreateTables.sql”, ForWriting)
objFile.Write strNewText

Writeline includes vbcrlf (carriage return line feed), and write does not.

You could, of course, write the script in Windows PowerShell, but there is no need to do so when you have a perfectly acceptable VBScript script


Well, this concludes another edition of Quick-Hits Friday. Join us tomorrow for the Weekend Scripter as we delve into the mysteries of the Windows PowerShell ISE.

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



Comments are closed.