How can I add a local group to Publishing Point with VBScript? - vbscript

I'm trying to figure out how to add a local group to an (On-Demand) Publishing Point, with vbscript.
The group just needs read access to it. The group has (of course) been created first.
System: Windows Server 2008 R2 x64 with Media Services 2008 (for R2). It's not a Domain Controller, there's no Active Directory.
Context: Running a media server with one Pub. Point per movie, and use the group to allow/deny access to that Pub. Point / movie on a per-user basis.
I can add the group manually, but I would really like to do it with a (vb)script.
To do it manually:
(first create a local group).
In Server Manager, click the on-demand Publishing Point, Properties tab, Authorization, WMS Publishing Points ACL Authorization (which of course has to be enabled), right-click it - choose Properties.
Strangely, Groups are by default not enabled in Object Types, so one has to specifically enable them to be able to add the group.
The closest example I've been able to find is this: (it's in VB.Net)
http://msdn.microsoft.com/en-us/library/dd875036%28v=VS.85%29.aspx
My (almost-working) script so far:
Dim Server
Dim ODPubPoint
Dim Plugin
Dim ACLCheckAdmin
Dim AccessCtrlList
Dim objACE
' Create a new WMSServer object.
Set Server = CreateObject("WMSServer.server","localhost")
' Create a new ODPubPoint object.
Set ODPubPoint = Server.PublishingPoints.Item("supersizeme")
' Retrieve the plug-in to be configured.
Set Plugin = ODPubPoint.EventHandlers.Item("WMS Publishing Points ACL Authorization")
' Retrieve the custom interface of the plug-in.
Set ACLCheckAdmin = Plugin.CustomInterface
' Retrieve the list of access control entries.
Set AccessCtrlList = ACLCheckAdmin.AccessControlList
' Create an object to be able to add to the access control list.
Set objACE = CreateObject("AccessControlEntry")
objACE = AccessCtrlList.Add("MEDIESERVER\hest", 16 )
The group does get added, but the script dies with an error:
ppaddgroup.vbs(27, 2) Microsoft VBScript runtime error: Object doesn't support this property or method.
In the VB.Net example it says WMS_ACCESS_CONTROL.WMS_ACL_ALLOW_ALL which I have no idea how to convert from VB.Net to VBScript. I thought it was just a constant, but apparently not.
(and I just want to allow read access, as in WMS_ACL_ALLOW_READ ).
I found the constants on this page:
http://include.wutils.com/com-dll/constants/constants-WMSServerLib.htm
Can anyone come up with the correct way to add a group to a publishing point?

Per greylion's previous edit:
The last line needs to be:
Set objACE = AccessCtrlList.Add("MEDIESERVER\test", 16 )
For some reason, I was convinced that the final act of adding the
group was not supposed to have a "Set" in front. I thought it was only
for creating or defining objects, but apparently it's also for filling
them with actual data. Annoyingly, it almost worked with "Set"
missing, which led me to think I just had some minor detail wrong, but
no way to know what it was.
Mental note: Filling an object with data is NOT like setting a
variable or constant.

Related

How to set cluster resource "Use Network Name for computer name" checkbox programmatically?

I am programmatically setting up a cluster resource (specifically, a Generic Service), using the Windows MI API (Microsoft.Management.Infrastructure).
I can add the service resource just fine. However, my service requires the "Use Network Name for computer name" checkbox to be checked (this is available in the Cluster Manager UI by looking at the Properties for the resource).
I can't figure out how to set this using the MI API. I have searched MSDN and multiple other resources for this without luck. Does anybody know if this is possible? Scripting with Powershell would be fine as well.
I was able to figure this out, after a lot of trial and error, and the discovery of an API bug along the way.
It turns out cluster resource objects have a property called PrivateProperties, which is basically a property bag. Inside, there's a property called UseNetworkName, which corresponds to the checkbox in the UI (and also, the ServiceName property, which is also required for things to work).
The 'wbemtest' tool was invaluable in finding this out. Once you open the resource instance in it, you have to double-click the PrivateProperties property to bring up a dialog which has a "View Embedded" button, which is then what shows you the properties inside. Somehow I had missed this before.
Now, setting this property was yet another pain. Due to what looks like a bug in the API, retrieving the resource instance with CimSession.GetInstance() does not populate property values. This misled me into thinking I had to add the PrivateProperties property and its inner properties myself, which only resulted in lots of cryptic errors.
I finally stumbled upon this old MSDN post about it, where I realized the property is dynamic and automatically set by WMI. So, in the end, all you have to do is know how to get the property bag using CimSession.QueryInstances(), so you can then set the inner properties like any other property.
This is what the whole thing looks like (I ommitted the code for adding the resource):
using (var session = CimSession.Create("YOUR_CLUSTER", new DComSessionOptions()))
{
// This query finds the newly created resource and fills in the
// private props we'll change. We have to do a manual WQL query
// because CimSession.GetInstance doesn't populate prop values.
var query =
"SELECT PrivateProperties FROM MSCluster_Resource WHERE Id=\"{YOUR-RES-GUID}\"";
// Lookup the resource. For some reason QueryInstances does not like
// the namespace in the regular form - it must be exactly like this
// for the call to work!
var res = session.QueryInstances(#"root/mscluster", "WQL", query).First();
// Add net name dependency so setting UseNetworkName works.
session.InvokeMethod(
res,
"AddDependency",
new CimMethodParametersCollection
{
CimMethodParameter.Create(
"Resource", "YOUR_NET_NAME_HERE", CimFlags.Parameter)
});
// Get private prop bag and set our props.
var privProps =
(CimInstance)res.CimInstanceProperties["PrivateProperties"].Value;
privProps.CimInstanceProperties["ServiceName"].Value = "YOUR_SVC_HERE";
privProps.CimInstanceProperties["UseNetworkName"].Value = 1;
// Persist the changes.
session.ModifyInstance(#"\root\mscluster", res);
}
Note how the quirks in the API make things more complicated than they should be: QueryInstances expects the namespace in a special way, and also, if you don't add the network name dependency first, setting private properties fails silently.
Finally, I also figured out how to set this through PowerShell. You have to use the Set-ClusterParameter command, see this other answer for the full info.

vb.net data set not working

I am using two different datasets to populate datagridview my project using visual studio using vb.net. It is windows forms application which is used to display information from the database based on user inputs. Once the information is displayed the user can save the information into a table specifically created to store the report information in order for it to be recalled at a later date. I am now trying to recall this information so have created my dataset in the same way as before and am now trying to invoke a new occurrence of it and this is where the probelm begins. The code is below.
Dim dv2 As New System.Data.DataView
dv2 = New System.Data.DataView(DataSet2.Tables(0), "Status <> ''", "",
DataViewRowState.CurrentRows)
DataTable2TableAdapter.fill(DataSet2.DataTable2, f5.ComboBox2.SelectedValue)
I am getting two issues.
For DataSet2.Tables(0): Reference to a non-shared member requires an object reference
For DataTable2TableAdapter: ’DataTable2TableAdapter’ is not declared. It may be inaccessible due to its protection level.
I dont know why this is happening as I have written the same code here as for my previous data set other than changing the SQL statement behind the dataset at set up. Any thoughts would be welcome as I am totally out of ideas. All questions are welcomed.
Thanks
Try the following code to fix your error number 1....
Dim tablezero as System.Data.DataTable
'
tablezero = DataSet2.Tables(0)
The reason your getting the error is because you are trying to access an object (Table(0)) and it is not visible to the code that is trying to access it, if it was SHARED then it would be visible.
So you can resolve it by defining and object instance/reference to it and then accessing that reference, which in this case i have called "tablezero" (or by making table(0) SHARED - usually not the best bet unlessits neccesary - no point in having something accessible to the whole class it is declared in unless absolutelty neccessary)
It is quite possible the second error may dissapear after just fixing above, then again its difficult to tell without your code for Dataset2
Hope it helps.

How to implement custom resource provider dependent on different criteria than UI culture?

I am working on .NET 4.0 MVC3 web application. The application is all in English and allows users to fill information regarding different regions. For simplicity let's say we have two regions: United States and Western Europe.
Now in the view I present a string let's say Project opening, but if the user works on region United States I would like it to read Project initiation.
When I think about this functionality I immediately think about resource files for different regions, but independent from the UI culture.
Does anyone have a recipe how to achieve what I want?
Would be also nice, if in the future I could make it read e.g. ExtendedDisplayAttribute(string displayName, int regionId) placed over properties of my ViewModels.
EDIT
I am already at the stage where I can access region information in a helper that should return the string for this region. Now I have a problem with the resource files. I want to create multiple resource files with failover mechanism. I expected there would be something working out of the box, but the ResourceManager cannot be used to read resx files.
Is there any technique that will allow me to read the values from specific resource files without some non-sense resgen.exe?
I also do not want to use System.Resources.ResXResourceReader, because it belongs to System.Windows.Forms.dll and this is a Web app.
Just in case someone wants to do the same in the future. This article turned out to be really helpful: http://www.jelovic.com/articles/resources_in_visual_studio.htm
The piece of code that I use (VB) is:
<Extension()>
Public Function Resource(Of TModel)(ByVal htmlHelper As HtmlHelper(Of TModel), resourceKey As String) As MvcHtmlString
Dim regionLocator As IRegionLocator = DependencyResolver.Current.GetService(GetType(IRegionLocator))
Dim resources = New List(Of String)
If Not String.IsNullOrEmpty(regionLocator.RegionName) Then
resources.Add(String.Format("Website.Resources.{0}", regionLocator.RegionName))
End If
resources.Add("Website.Resources")
Dim value = String.Empty
For Each r In resources
Dim rManager = New System.Resources.ResourceManager(r, System.Reflection.Assembly.GetExecutingAssembly())
rManager.IgnoreCase = True
Try
value = rManager.GetString(resourceKey)
If Not String.IsNullOrEmpty(value) Then
Exit For
End If
Catch
End Try
Next
Return New MvcHtmlString(value)
End Function

Get a list of Active Directory Users along with their Full Name and Email

I need to retrieve a list of Active Directory users and their attributes using Delphi 2010.
I've seen a few similar questions on SO (e.g. Delphi - Find primary email address for an Active Directory user), but they all seem to require the user name before any additional information can be retrieved.
I had written an article for [The Delphi Magazine] way back when..... if you have access to a backlog of those magazines, it's in issue no. 62 (October 2000) - unfortunately, it seems those back issues aren't available for purchase anymore :-(
It's too long of an article and a code sample to post here.... basically it's about wrapping the IDirectorySearch interface in a nicer Delphi-like shell. You pass in a base container where to search, you define an LDAP filter, and you define a set of attributes you're interested in - then you search and get back basically an enumerator for the results, which you can get one by one.
In the end, I discovered TJvObjectPickerDialog, part of JVCL. It wraps the Windows Select Object dialog and does everything I need with very little coding. Just set the required properties and call execute. The selected user objects are returned along with the attributes that you set in the 'Attributes' property.

Easy recreation of "Shared, Desktop Private on 1st use" views

I have some views that uses #UserName in the selection formula. For working that, the view must be "Shared, Desktop Private on 1st use". That is no problem.
But this views are going to be redesigned quiet often.
As this is a bunch of views it is very uncomfortable for the user to delete each of this views to recreate from scratch with design changes.
I try different things to get that done with an agent but no one is fool-proof and give some strange results (sometimes even do not update the design).
Best result so far is to delete the icon from the workspace and open the application again. That works (until now) always. But this is so annoying for end users to reopen the app from the (deep leveled) server folders.
Any other method to update the design of "private on 1st use" views ?
As you noticed, private views are a pain to maintain. Why not go a different way to solve your problem?
Create a categorized view, where the first, categorized column contains the field you compare the username in your current solution to.
Than embed that view into a form as a "single category embedded view" and use #username as the category.
Presto. Now you have a view that only shows documents for the current user and you can change the design whenever you like.
Mick Moignard has a good article on that topic online: Dynamic view filtering in Notes.
See also the Lotus Domino Designer Help, Topic "To show a single category in embedded views"
I have tried to solve the same problem and ended up doing two things - (1) automatically send the user an email with a link to the database and ask them to remove the database icon so that the private views get deleted and (2) alert the user when the design of a private view has changed.
The first part was fairly simple - I wrote a LotusScript function that would send the current user an email message containing a link to the current database (the one that contains the private views), along with some meaningful text and database information. All the user had to do then was exit the database, remove the database icon, open the email they just received and open the database again using the link. No need to navigate the server folders or wonder which server to go to. This can be used on its own, e.g. in a button, but I ended up combining it with something a little more tricky.
The second part was devising a way to alert the user that the design of the view they are opening is outdated. The tricky part was detecting that the design of the view has changed. What made this possible was what actually caused the problem in the first place - the fact that Notes caches the private view. When caching the private view, Notes also caches constants that the script in the view events refer to, that are part of LotusScript libraries the view uses.
Here's a description of the design I used:
Let the view use shared script library, PrivateViewsCode.
In PrivateViewsCode's (Declarations) declare Const DESIGN_VERSION = "1.0".
In PrivateViewsCode declare function myQueryopen. One of the parameters myQueryopen receives is string designVersion.
In the private view's Queryopen event call myQueryopen, passing DESIGN_VERSION to designVersion. Since this code is in the view that is cached, DESIGN_VERSION will contain the constant value as it were in the moment the view design was cached (when the user first opened it), in this case - "1.0".
In myQueryopen compare designVersion to DESIGN_VERSION.
Dim designChanged As Integer
designChanged = (designVersion <> DESIGN_VERSION)
Since myQueryopen is part of PrivateViewsCode script library, here you actually compare the DESIGN_VERSION (as cached in the private view and then passed to myQueryopen) to DESIGN_VERSION from PrivateViewsCode, which is always current.
The only thing left is to be sure to recompile the views (Tools\Recompile all LotusScript) after changing DESIGN_VERSION.
I hope this explains the design, here is how it works:
After making changes to private views design you change the version:
DESIGN_VERSION = "1.1"
Recompile all LotusScript.
Refresh the database design.
Users open any private view that uses this functionality.
They get a message saying they will receive link to the database and that they have to remove the icon from the workspace and open it again using the provided link.
The user closes the database and removes the icon - private views are deleted.
The user opens the database link in the email, the next time they open one of the private views, the new design is cached along with the new value of DESIGN_VERSION (here, "1.1").
The comparison (designVersion <> DESIGN_VERSION) now yields false. Everything is back to normal until the next update.
Ken's way of handling this has the major advantage of not involving the users at all. This wasn't an option for me because of the frequency with which I made changes to the views (the application was just deployed and I had many requests for changes to the views) as well as the big number of private views in the application.
(Edit)
I assumed you had a specific reason to use private views, but I used the "Show Single Category" in an embedded view (just as leyrer suggests) ever since it became available and was quite happy with it. If you see any limitations to using the "Show Single Category" option, I'll try to help you with that.
I found a way that moves the pain from the end user to the developer. I designed the navigation to use outlines so I can control where the user goes when they navigate to a view. Notes outline entries can be changed without the user needing to go through the delete-icon-then-reopen-database hassle.
When I need to update the design of the private view, I rename it as well and also update the reference to it in the notes outline entry. At the users desktop, when they next open the database, a new private view will be created for them. Most (or all) of my users never noticed anything, at least they never mentioned it!
The process is fairly easy for the developed but also fairly easy to forget. Also, the user's workspace will end up having a lot of references to old unused private views, which if they are large in size might become a problem down the line. If you change the view twenty times, or change twenty views, for example, it may be time to delete the icon to clear them out. For me the changes were rare enough for this not to matter.
The solution to your dilemma is not too hard to solve, but a little tedious. There is a technote on simply removing private views programmatically. It is a common design issue for developers.
I have had to take the following approach to manage multiple private views which were all going through multiple versions at any one time.
The secret is to do a check on the DatabaseOpen event, as it's a view held on the local client so you need to do this through user's UI activity. As long as your Lotus Notes client fleet is at running version 6.5.x you could try the following. To be concise, I have outlined what you need to do.
Name your private view "yourPrivateViewName_1.0|yourPrivateViewName"
Note the use of an alias. This is so you can reference the view in an outline or code, no matter how many versions you use.
This can also be a multi-valued field if you have more than one private view to manage.
Create a database profile document that has a field with the current private view name, eg "youPrivateViewName_1.1"
On DatabaseOpen loop through the views, finding the private view(s) then compare the name to the one in the database profile. The naming convention is designed to make it possible to do a version check. If the versions don't match, remove the view. When the user opens that view the next time it should grab the current version you have released.
There are other ways as well, like checking the timestamps on the private view and the template, but it still requires a way to single out the private view. But I found this way easy enough to manage.
Thank you all !
I finally ended up with the following:
Create an Agent running from menus that close the database
Sub Initialize
Dim s As New NotesSession
s.SetEnvironmentVar "remove-"+s.CurrentDatabase.ReplicaID,"1"
Dim ws As New NotesUIWorkspace
ws.CurrentDatabase.Close
End Sub
In the database close event mail a database link and send keys to remove from workspace
Declare Sub keybd_event Lib "user32.dll" (Byval bVk As Integer, Byval
bScan As Integer, Byval dwFlags As Integer,Byval dwExtraInfo As Integer)
Sub Queryclose(Source As Notesuidatabase, Continue As Variant)
Dim s As New NotesSession
x = s.GetEnvironmentString("remove-"+s.CurrentDatabase.ReplicaID)
s.SetEnvironmentVar "remove-"+s.CurrentDatabase.ReplicaID,""
If x="" Then Exit Sub
Dim ws As New NotesUIWorkspace
Call ws.AddDatabase( s.CurrentDatabase.Server,s.CurrentDatabase.FilePath)
Dim m As New NotesDocument(s.CurrentDatabase)
m.From = s.CurrentDatabase.Title
m.SendTo = s.CommonUserName
m.Subject = "Link to open " + s.CurrentDatabase.Title
Dim rt As New NotesRichTextItem(m,"Body")
rt.AppendText s.CurrentDatabase.Title
rt.AppendText " -> "
rt.AppendDocLink s.CurrentDatabase,"Open Application"
m.Send False
Delete m
keybd_event &h2e,0,0,0 ' Del key down
keybd_event &h2e,0,2,0 ' Del key up
keybd_event &h0D,0,0,0 ' Y key down
keybd_event &h0D,0,2,0 ' Y key up
End Sub
(You all got your upvotes but a i mark as answer for the lowest rep. points user.)

Resources