Connecting to the SMS Namespace
A Microsoft® Systems Management Server (SMS) installation can be configured several ways, which means your connection algorithm must account for this flexibility. For example, the SMS Provider can be located on the local site server or a remote server. The following algorithm ensures the correct connection to the provider for the local site.
Get the site server's name.
Typically, your application will run on the same server that is running the SMS Administrator Console. The console uses the Server registry key to identify the server's name. The key is located at HKEY_LOCAL_MACHINE\Software\Microsoft\SMS\Admin\Connection. If you cannot find the name in the registry, you will have to prompt the user for the name.
Connect to \\<server's name>\Root\Sms
The namespace contains one or more instances of SMS_ProviderLocation.
Query SMS_ProviderLocation for the NamespacePath property where the value for ProviderForLocalSite is TRUE.
The root\sms namespace can contain more than one instance of the SMS_ProviderLocation, but there is only one instance where ProviderForLocalSite is TRUE.
Connect to the NamespacePath property returned from the query.
The NamespacePath property contains a string similar to a universal naming convention (UNC) path: \\<servername>\root\sms\site_<site code>.
If you know the path, you can bypass steps 1 through 3 and connect directly to the namespace. Otherwise, you can use the following example as the baseline for connecting to the provider for the local site.
[C/C++] #define _WIN32_DCOM #include #include #include #include int Init(WCHAR *Server, WCHAR *User, WCHAR *Password, IWbemServices *&rpServices;); main() { IWbemServices* pIWbemServices=NULL; WCHAR *Name=L"USERNAME"; WCHAR *Password=L"PASSWORD"; WCHAR *Server=L"SERVER"; Init (Server,NULL,NULL,pIWbemServices); } // ************************************************************************** // Init : Connect to the local site server // // [in] WCHAR *Server // [in] WCHAR *User (can be null) // [in] WCHAR *Password (can be null) // [out] IWbemServices* &rpWbemServices; (reference to pointer) // Returns: int // 0 Success // 1 CoCreateInstance WbemLocator Failed // 2 Specified Server was not found // 3 Error retrieving NamespacePath // 4 Could not connect to NamespacePath // ************************************************************************** int Init(WCHAR *Server, WCHAR *User, WCHAR *Password, IWbemServices *&rpServices;) { HRESULT hr; _variant_t vLocalNamespace; _bstr_t bstrNamespace; _bstr_t bstrQuery; _bstr_t bstrLocalNamespace; ULONG uReturned; IWbemLocator *pLocator = NULL; IWbemClassObject *pLocation = NULL; IEnumWbemClassObject *pProviderLocations = NULL; // Release and Null pWbemServices if( rpServices ) rpServices->Release(); rpServices = NULL; // Initialize COM to either COINIT_APARTMENTTHREADED or // COINIT_MULTITHREADED depending on your application's design. CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); // Initalize COM security. This defines the default authentication and // impersonation levels for the application. The authentication level // is set to NONE for applications that perform asynchronous calls. // Otherwise, the level depends on your needs. CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0); // Create an instance of IWbemLocator. hr = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (void**) &pLocator;); if( FAILED(hr) ) { CoUninitialize(); return 1; } // Store \\\root\sms bstrLocalNamespace = L"\\\\" + _bstr_t(Server) + L"\\root\\sms"; // Use the IWbemLocator instance to connect to the \\Server\root\sms // namespace using User and Password as the connection credentials. User // and password are only required if you are connecting remotely as a // different user. Otherwise, integrated security is used. hr = pLocator->ConnectServer(bstrLocalNamespace, _bstr_t(User), _bstr_t(Password), NULL, 0, NULL, NULL, &rpServices;); if( FAILED(hr) ) { pLocator->Release(); CoUninitialize(); return 2; } // Create a query to find the SMS_ProviderLocation instance // that contains the namespace path for the local site. bstrQuery = L"SELECT NamespacePath FROM SMS_ProviderLocation " L"WHERE ProviderForLocalSite = True"; // Execute the query hr = rpServices->ExecQuery(_bstr_t(L"WQL"), bstrQuery, WBEM_FLAG_FORWARD_ONLY, NULL, &pProviderLocations;); if( FAILED(hr) ) { rpServices->Release(); pLocator->Release(); CoUninitialize(); return 3; } // Because pProviderLocations did not come from the WbemLocator, // you need to set its security. hr = CoSetProxyBlanket(pProviderLocations, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); if( FAILED(hr) ) { pProviderLocations->Release(); rpServices->Release(); pLocator->Release(); CoUninitialize(); return 3; } // Retrieve next object from pProviderLocations. There should only be // one row returned that matches the criteria. hr = pProviderLocations->Next(WBEM_INFINITE, 1, &pLocation;, &uReturned;); pProviderLocations->Release(); // If there were no objects returned, quit and return an error. if( uReturned != 1 ) { rpServices->Release(); pLocator->Release(); CoUninitialize(); return 3; } // The actual SMS namespace path for the provider is contained in the NamespacePath // property. Use the WMI Get method to get the value from the NamespacePath // property and assign it to the variant vLocalNamespace. hr = pLocation->Get(_bstr_t(L"NamespacePath"), 0, &vLocalNamespace;, NULL, NULL); pLocation->Release(); rpServices->Release(); rpServices = NULL; // MUST be set to NULL if( FAILED(hr) ) { pLocator->Release(); CoUninitialize(); return 3; } // Connect to the true provider location at \\\root\sms\site_ hr = pLocator->ConnectServer(_bstr_t(vLocalNamespace), _bstr_t(User), _bstr_t(Password), NULL, 0, NULL, NULL, &rpServices;); pLocator->Release(); if( FAILED(hr) ) { CoUninitialize(); return 4; } return 0; } [Visual Basic] ' This fragment assumes that the variables ' Server, User and Password have already been obtained. Dim Services As SWbemServices Dim Locator As New SWbemLocator Dim ProviderLoc As SWbemObject Dim ProviderLocSet As SWbemObjectSet Dim SMSProviderServer As String Dim SMSProviderSitecode As String Dim Query As String Query = "SELECT Machine, Sitecode FROM SMS_ProviderLocation WHERE ProviderForLocalSite = TRUE" ' Connect to the \root\sms namespace for the given server. ' User and password are only required if you are connecting remotely as a ' different user. Otherwise, integrated security is used. Set Services = Locator.ConnectServer(Server, "root\sms", User, Password) If Err.Number <> 0 Then ' Display an appropriate message to the user, log an error and exit End If ' Execute the query. Use flag to capture query errors on the call. ' Otherwise, errors are not detected until you access the set. Set ProviderLocSet = Services.ExecQuery(Query, , wbemFlagForwardOnly Or wbemFlagReturnImmediately) If Err.Number <> 0 Then ' Display an appropriate message to the user, log an error and exit End If ' Get the instance from the set. Use the Machine and Sitecode values instead ' of getting the NamespacePath. The scripting ConnectServer method is ' passed the machine name as a separate parameter. Note that you have to use a ' For Each loop because WMI Scripting does not provide a way to index a set. For Each ProviderLoc In ProviderLocSet SMSProviderServer = ProviderLoc.Machine SMSProviderSitecode = ProviderLoc.Sitecode Next ' Set the Services object to Nothing. Get a new Services interface ' using the local SMS namespace path. User and password are only required if you ' are connecting remotely as a different user. Set Services = Nothing Set Services = Locator.ConnectServer(SMSProviderServer, _ "root\sms\site_" & SMSProviderSitecode, _ User, Password) If Err.Number <> 0 Then ' Display an appropriate message to the user, log an error and exit End If ' Set the authentication and impersonation levels for the application Services.Security_.AuthenticationLevel = wbemAuthenticationLevelCall Services.Security_.ImpersonationLevel = wbemImpersonationLevelImpersonate [VBScript] 'This VBScript example uses the WMI moniker to connect to the local site server. Dim Services Dim ProviderLoc Dim Location Set ProviderLoc = GetObject("winmgmts:{impersonationLevel=impersonate}!root/sms:SMS_ProviderLocation") For Each Location In ProviderLoc.Instances_ If Location.ProviderForLocalSite = True Then Set Services = GetObject("winmgmts:" & Location.NamespacePath) Exit For End If Next 'Do something with Services.
You can also use the SWbemLocator object to connect to the local site server. After you create the locator object, the rest of the code is similar to the Visual Basic example.[VBScript]
[VBScript] Dim Locator Set Locator = CreateObject("WbemScripting.SWbemLocator")
In most cases, you can connect to SMS with an impersonation level of identify. However, users from another domain must connect with impersonate as shown in the example. Impersonation lets the Provider determine the full extent of the user's security rights by being able to ask the user's domain controller to which groups the user belongs.
If you launch your application from the console, see Using CommandLine Substitution to Connect to the SMS Namespace.