SVS, WMI and .Net
A few weeks ago I wrote about using SVS's WMI provider and what you could do with it. All of these examples were done with VBscript and while there are a lot of people using scripting, it may not offer you the solution you need. This is where .Net comes in handy -- especially if you want to write tools for the Juice.
There's a lot you can do with SVS via .Net using the WMI provider, however, there are some differences between using WMI in VBscript and .Net which I'll cover in this article. As with my previous article I'll provide you with some sample functions for doing work, except this time I've included a class that has most of the functions you'll want to use with WMI. I'll also go over how we use this class to build a simple tool: SVSDriveSwitch.
I'm not going to repost any of the class and method information for SVS's WMI provider so you might want to open up my previous article for reference.
SVSWMI.cs
SVSWMI.cs contains a class I wrote that I use for all my WMI-based tests. By providing it, most of the work is already done for you so you can start building SVS apps fast.
Usage
There's no default namespace for SVSWMI. You can add one if you want. Nor do any of the classes handle exceptions -- though there is some simple error handling on the ones that need it -- because I know everyone has their own way of dealing with exceptions and errors. I felt it best to leave this up to each individual user. That being said, this class can be used as is without adding any additional code. You'll need to use the System.Management namespace as well as add it as a reference to use any of these methods.
For VirtualSoftwarePackage Class methods all names are the same as described in the table in my previous article except I use camel hump notation so the first letter is never capitalized unless it's an abbreviation.
SVSWMI.reset(myGuid, true);
SVSWMI.setAutoActivate(myGuid, true);
Import
Import requires some special attention. Like VBscript, to import you need Backup and Restore permissions which can be done in C# but unlike VBscript you don't have a choice about what permissions are granted. It's either all or nothing.
Also note the out, in the example below, since by default the WMI returns a SVS error code on completion—0 for success or a different number on fail -- you get the Guid from the import (needed for all other functions). Uou have to use the method like this:
String myGuid ="" String myResult = SVSWMI.import(out myGuid, myFile, false);
Import, Deactivate, and Reset all have overloads that allow you to get the GUID or process id back the same way if you want.
Properties
For properties I add either is or get depending on what the property returns. Is properties return true and all others return strings (though that can be changed since many are supposed to be ints).
SVSWMI.isActive(myGuid) (returns true/false) SVSWMI.getCreatedTime(myGuide) (returns string of the time) SVSWMI.getRestTime(myGuid) (returns string if rest time, null if none)
Sublayers
VirtualSoftwareSubLayer Class properties follow the same get label system used above but also add the word sub into the mix. The reason is there's one property named the same and I didn't want to place this in a different class.
So SVSWMI.getSubId(myGuid)
Instead of SVSWMI.getId(myGuid)
To make getting sublayer information easier I've created a method that will return sublayer GUIDS named getSubLayerGuids. Like Import it returns a success (true in this case) as well as GUIDs, the variables meant to hold the write and read sublayer GUIDS need to be defined before calling the function like so:
string myWriteGuid=""; string myReadGuid = ""; bool result = SVSWMI.getSubLayerGuids(out myWriteGuid, out myReadGuid, myLayerGuid);
After getting a sublayer Guid you can pass it into a sublayer method:
String myRedirectPath= SVSWMI.getSubFileRedirectPath(myWriteGuid);
WMI and .Net
WMI isn't quite as easy to use with .Net as it is with VBscript, partly because the documentation on how to do so isn't very good on MSDN, and also because of the lack of ways to grant needed permissions without having to grant them all.
For reference sake, and so you can change the SVSWMI class if you need to, I'll go over a few methods I wrote so you can see what I did.
Methods
public static string activate(string myGuid) {
string ObjectPath = string.Format(@"root\default:VirtualSoftwarePackage.Id='{0}'", myGuid);
ManagementObject SVSClass = new ManagementObject(ObjectPath);
ManagementBaseObject inParams = SVSClass.GetMethodParameters("Activate");
ManagementBaseObject outParams = SVSClass.InvokeMethod("Activate", inParams, null);
string myResult = outParams["ReturnValue"].ToString();
SVSClass.Dispose();
return myResult;
}
The main class/object you'll be using is ManagementObject, this is used for all the SVSWMI methods but Import which needs ManagementClass instead. The main difference is ManagementObject binds to a specific WMI object, in this case an SVS layer; while ManagementClass binds to a WMI class, in this case VirtualSoftwarePackage class. You can see this in the above Activate example where I have a specific "Object Path" pointing to a layer by GUID and then binding it to an object in the next line.
Next you have to get the parameters that need to be passed in via the GetMethodParameters method and save them into a ManagementBaseObject, with Activate you don't have to pass anything else in so you then invoke the method and save the results into a second ManagementBaseObject from which we pull the result. Pretty straight forward and many of the methods in SVSWMI use this model.
Methods 2
public static string import(out string myGuid, string myFile, bool overWrite) {
ConnectionOptions options =
new ConnectionOptions();
options.Impersonation =
System.Management.ImpersonationLevel.Impersonate;
options.EnablePrivileges = true;
ManagementScope scope =
new ManagementScope(
"\\\\.\\root\\default", options);
scope.Connect();
ManagementPath myPath = new ManagementPath("VirtualSoftwarePackage");
ManagementClass SVSClass = new ManagementClass(scope, myPath, null);
ManagementBaseObject inParams = SVSClass.GetMethodParameters("Import");
inParams["Filename"] = myFile;
inParams["Overwrite"] = overWrite;
ManagementBaseObject outParams = SVSClass.InvokeMethod("Import", inParams, null);
myGuid = outParams["PackageId"].ToString();
string myResult = outParams["ReturnValue"].ToString();
SVSClass.Dispose();
return myResult;
}
Import is a little different (so is export). In .Net you have a scope and a path to a WMI class or object. The scope is pretty much where it is, so in this case \\.\root\default and the path is the class name. With Activate and other methods I combined these into one string and passed them in, which is fine in most cases, but with Import we need to set some permissions and that's done at the scope level. As you can see at the top of the code we declare a ConnectionOptions. This is used for remote WMI but can be used locally too, which is the class that allows you to set permissions then we declare a new scope that uses the ConnectionOptions we just defined. Lastly we connect to the scope and declare our path.
The next part should look a familiar, we take the scope and class we just made and bind them to a Class (you could use this method for a ManagementObject too) and then get the in parameters. Next we have to set some parameters, because we're not bound to an existing object) so we set the file name (remember to use \\ ) and overwrite (Boolean) values and then invoke the method. You could use this for any method as well, passing in the GUID this way and binding to class but it's easier to bind to the layer itself since it's less code. Lastly we save the PackageId to myGuid and return that and the result.
Properties
public static string getName(string myGuid) {
ManagementPath myPath = new ManagementPath(
"root\\default:VirtualSoftwarePackage.Id='" + myGuid + "'");
ManagementObject myObject = new ManagementObject(myPath);
return myObject["Name"].ToString();
}
Properties are similar to methods but less work is required to get the information, basically we're binding to an object via a GUID and then have access to all the properties. In this example we're only returning the Name property of a layer be we could write something that lists them all.
WMI Querying
ManagementScope ms = new ManagementScope(
"\\\\.\\root\\default");
ms.Connect();
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(
"SELECT * FROM VirtualSoftwarePackage");
searcher.Scope = ms;
foreach (ManagementObject layer in searcher.Get()) {
string myName = layer.GetPropertyValue("Name").ToString();
}
Querying is similar to the previous sections, you first have to define a ManagementScope (like with Import and Export) and then connect to that scope. Once that's done you create an ManagementObjectSearcher (which is pretty much your query line) and attach the scope to it One note is that there are several query string syntaxes for .Net and I'm just using the method that's similar to VBscript's.
The key part of the next line is searcher.Get() that's in the foreach statement. That's the actual call that makes the query and since we're looking for ManagementObjects we're having to use ToString() on the object to get it to display.
Putting it to use
So now we know how to use SVSWMI Class and how to use WMI with .NET so lets make a quick app. One tool I recently updated from a batch file to a .NET app was SVSDriveSwitch which moves the redirect folder (FSLRDR directory) from one location to another. This is a really simple app because it just queries all the layers in SVS, deactivates them if active then exports them, changes a registry key then imports them. Since we'll be modifying a regkey we'll need to add System.Security to the reference and ask the assembly to give us permission to do so.
The following code shows how you can do most of this, I'm not bothering with giving all the code because it's not needed so you'd need to add argument processing, maybe something to validate a drive and so fourth.
ManagementScope ms = new ManagementScope(
"\\\\.\\root\\default");
ms.Connect();
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(
"SELECT * FROM VirtualSoftwarePackage");
searcher.Scope = ms;
foreach (ManagementObject layer in searcher.Get()) {
string myGuid = layer.GetPropertyValue("Id").ToString();
string myName = layer.GetPropertyValue("Name").ToString();
string myVSAPath = myPath + "\\" + myName+".vsa";
//check to see if the layer is active'
Console.WriteLine("Running operations on: " + myName);
if (service.GetPropertyValue("Active").ToString() == "True") {
Console.WriteLine("Deacvitaving Layer");
SVSWMI.deactivate(myGuid,true);
}
Console.WriteLine("Exporting Layer: "+myVSAPath +" " + myGuid);
string result = SVSWMI.export(myGuid, myVSAPath, true);
if (result != "0") {
Console.WriteLine("export fail: " + result);
}
else {
SVSWMI.delete(myGuid);
}
}
//change the FSLRDR
RegistryKey myKey = Registry.LocalMachine.OpenSubKey("SYSTEM", true).OpenSubKey("Altiris", true).OpenSubKey("FSL", true);
string currentLocation = (string)myKey.GetValue("DefaultFileRedirect");
myKey.SetValue("DefaultFileRedirect",myPath);
string[] dirs = Directory.GetFiles(myPath, "*.vsa");
foreach (string myVSA in dirs) {
Console.WriteLine("Importing " + "\"" + myVSA + "\"");
SVSWMI.import(myVSA, true);
}
Console.WriteLine("finished, please restart the system for the changes to take effect.");
}
Conclusion
There's a lot you can do with SVS and WMI and SVSWMI Class has already done a lot of the work so you can start working on that SVS tool you've been wanting to make but didn't want to have to deal with the mess that is marshaling in unmanaged code.
| Attachment | Size |
|---|---|
| SVSWMI.zip | 1.77 KB |
- Login or register to post comments
- 1834 reads
- Printer-friendly version
















Remote enabled version
Check out this download by Screenbert for the C# class with remoting enabled.
I'm thinking of a new version of SVSdriveSwith that does copying between computers and imports the layers...sweet.