Foreach loop Cannot convert char to System.Management.ManagementObject? - c#

I have a foreach loop that loops through all WMI services which only looks for certain services that contains specific key words to include and exclude. Therefore you can stop certain services that contains the included and excluded words. Unfortunately I'm receiving this error on the foreach loop that states Cannot convert type 'char' to 'System.Management.ManagementObject'. Hopefully you guys know. Thanks for the help.
public static void Test()
{
string include = "SQL";
string exclude = "EXPRESS, Writer";
string[] includeArray = include.Split(',');
string[] excludeArray = exclude.Split(',');
ConnectionOptions options = new ConnectionOptions();
//Scope that will connect to the default root for WMI
ManagementScope theScope = new ManagementScope(#"root\cimv2");
//Path created to the services with the default options
ObjectGetOptions option = new ObjectGetOptions(null, TimeSpan.MaxValue, true);
ManagementPath spoolerPath = new ManagementPath("Win32_Service");
ManagementClass servicesManager = new ManagementClass(theScope, spoolerPath, option);
using (ManagementObjectCollection services = servicesManager.GetInstances())
{
foreach (ManagementObject item in services.ToString().Where(x => includeArray.ToList().Any(a => x.ToString().Contains(a)) && !excludeArray.Any(a => x.ToString().Contains(a))))
{
if (item["Started"].Equals(true))
{
item.InvokeMethod("StopService", null);
}
}
}
}

You can't use Linq on WMI objects like that.
What you can do is loop over the services and check the name: note also I removed the extra space in the exclude variable.
void Main()
{
string include = "SQL";
string exclude = "EXPRESS,Writer";
string[] includeArray = include.Split(',');
string[] excludeArray = exclude.Split(',');
ConnectionOptions options = new ConnectionOptions();
//Scope that will connect to the default root for WMI
ManagementScope theScope = new ManagementScope(#"root\cimv2");
//Path created to the services with the default options
ObjectGetOptions option = new ObjectGetOptions(null, TimeSpan.MaxValue, true);
ManagementPath spoolerPath = new ManagementPath("Win32_Service");
ManagementClass servicesManager = new ManagementClass(theScope, spoolerPath, option);
using (ManagementObjectCollection services = servicesManager.GetInstances())
{
foreach (ManagementObject item in services)
{
var serviceName = item["Name"];
if (includeArray.Any(a => serviceName.ToString().Contains(a)) && !excludeArray.Any(a => serviceName.ToString().Contains(a)))
{
if (item["Started"].Equals(true))
{
item.InvokeMethod("StopService", null);
}
}
}
}
}

If you want to work with Collections so you can use Linq easily, you can user ORMi
var list = helper.Query("select * from Win32_Service").ToList().Where(p => p.Contains("reserverWord"));

Related

Why is PropertyDataCollection object persisting multiple records to database

I have a utility that reads the status of MicrosoftBizTalk Server resources .. specifically the ReceiveLocation component. My problem is that the program is submitting multiple entries of each item i.e each item in the data returned is being multiplied by 25 such that instead of persisting only 5 rows the data being persisted is 125. So for example instead of having just 1 row for my first row returned i have 25.
This is my program :
public List<BizTalk> GetBizTalkServicesStatistics()
{
List<BizTalk> model = new List<BizTalk>();
try
{
//Create the WMI search object.
ManagementObjectSearcher Searcher = new ManagementObjectSearcher();
ConnectionOptions options = new ConnectionOptions
{
Username = "+username+",
Password = "+password+",
Authority = "+domain+"
};
var server = "+server+";
// create the scope node so we can set the WMI root node correctly.
ManagementScope Scope = new ManagementScope("\\\\" + server + "\\root\\MicrosoftBizTalkServer", options);
Searcher.Scope = Scope;
// Build a Query to enumerate the MSBTS_ReceiveLocation instances if an argument
// is supplied use it to select only the matching RL.
//if (args.Length == 0)
SelectQuery Query = new SelectQuery();
Query.QueryString = "SELECT * FROM MSBTS_ReceiveLocation";
// else
//Query.QueryString = "SELECT * FROM MSBTS_ReceiveLocation WHERE Name = '" + args[0] + "'";
// Set the query for the searcher.
Searcher.Query = Query;
// Execute the query and determine if any results were obtained.
ManagementObjectCollection QueryCol = Searcher.Get();
// Use a bool to tell if we enter the for loop
// below because Count property is not supported
bool ReceiveLocationFound = false;
// Enumerate all properties.
foreach (ManagementBaseObject envVar in QueryCol)
{
// There is at least one Receive Location
ReceiveLocationFound = true;
PropertyDataCollection envVarProperties = envVar.Properties;
foreach (PropertyData envVarProperty in envVarProperties)
{
BizTalk bizTalk = new BizTalk();
bizTalk.Name = Convert.ToString(envVar["Name"]);
bizTalk.TransportType = Convert.ToString(envVar["AdapterName"]);
bizTalk.Uri = Convert.ToString(envVar["InboundTransportURL"]);
bizTalk.Status = Convert.ToString(envVar["Name"]);
bizTalk.ReceiveHandler = Convert.ToString(envVar["HostName"]);
bizTalk.ReceivePort = Convert.ToString(envVar["ReceivePortName"]);
bizTalk.RunDate = DateTime.Now;
bizTalk.ApplicationId = 24;
bizTalk.ServerId = 8;
bizTalk.InstanceName = "FBCZOP";
model.Add(bizTalk);
}
}
if (!ReceiveLocationFound)
{
Console.WriteLine("No receive locations found matching the specified name.");
}
}
catch (Exception excep)
{
ExceptionLogger.SendErrorToText(excep);
}
return model;
}
Save Function
public void SaveStatistics(BizTalk entity)
{
List<BizTalk> ServerInfo = new List<BizTalk>();
ServerInfo = GetBizTalkServicesStatistics();
foreach (var di in ServerInfo)
{
entity.RunDate = di.RunDate;
entity.Name = di.Name;
entity.Status = di.Status;
entity.Uri = di.Uri;
entity.InstanceName = di.InstanceName;
entity.ReceivePort = di.ReceivePort;
entity.TransportType= di.TransportType;
entity.RunDate = DateTime.Now;
entity.ReceiveHandler = di.ReceiveHandler;
entity.ServerId = entity.ServerId;
entity.ApplicationId = entity.ApplicationId;
appEntities.BizTalk.Add(entity);
appEntities.SaveChanges();
}
}
When i step through the code variable envVarProperties shows record count as 125 under envVarProperties << ResultsView :
Link 1
whilst QueryCol variable shows count of 5 :
Link 2
It looks like you're iterating an extra time in your GetBizTalkServicesStatistics() method.
Remove the foreach loop that starts with foreach (PropertyData envVarProperty in envVarProperties). This is looping through each property the object has (All 25 properties) for each instance (5 instances)... 25 * 5 = 125 values you are retrieving. You only want to iterate through your instances and pull the properties you want. That way you end up with 5 objects in your model object.
I'd suggest maybe something like this (untested because I don't have BizTalk)
public List<BizTalk> GetBizTalkServicesStatistics()
{
List<BizTalk> model = new List<BizTalk>();
try
{
//Create the WMI search object.
ConnectionOptions options = new ConnectionOptions
{
Username = "+username+",
Password = "+password+",
Authority = "+domain+"
};
var server = "+server+";
// create the scope node so we can set the WMI root node correctly.
ManagementScope Scope = new ManagementScope("\\\\" + server + "\\root\\MicrosoftBizTalkServer", options);
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, new ObjectQuery("SELECT * FROM MSBTS_ReceiveLocation"));
// Enumerate all properties.
foreach (ManagementObject instance in Searcher.Get())
{
{
BizTalk bizTalk = new BizTalk();
bizTalk.Name = instance.Properties["Name"]?.Value?.ToString();
bizTalk.TransportType = instance.Properties["AdapterName"]?.Value?.ToString();
bizTalk.Uri = instance.Properties["InboundTransportURL"]?.Value?.ToString();
bizTalk.Status = instance.Properties["Name"]?.Value?.ToString();
bizTalk.ReceiveHandler = instance.Properties["HostName"]?.Value?.ToString();
bizTalk.ReceivePort = instance.Properties["ReceivePortName"]?.Value?.ToString();
bizTalk.RunDate = DateTime.Now;
bizTalk.ApplicationId = 24;
bizTalk.ServerId = 8;
bizTalk.InstanceName = "FBCZOP";
model.Add(bizTalk);
}
}
// Determine
if (model.Count == 0)
{
Console.WriteLine("No receive locations found matching the specified name.");
}
}
catch (Exception excep)
{
ExceptionLogger.SendErrorToText(excep);
}
return model;
}
Also, this can be simplified more if you remove the connectionoptions (unless you are hard coding credentials which is highly advised against). If you are just using the identity of the executing user, that data is not needed.
-Paul
You are adding the same entity 25 times and overwrite its properties by reference. You need to initialize a new entity inside your loop:
foreach (var di in ServerInfo)
{
var entity = new BizTalk();
entity.RunDate = di.RunDate;
entity.Name = di.Name;
entity.Status = di.Status;
entity.Uri = di.Uri;
entity.InstanceName = di.InstanceName;
entity.ReceivePort = di.ReceivePort;
entity.TransportType= di.TransportType;
entity.RunDate = DateTime.Now;
entity.ReceiveHandler = di.ReceiveHandler;
entity.ServerId = entity.ServerId;
entity.ApplicationId = entity.ApplicationId;
appEntities.BizTalk.Add(entity);
appEn.SaveChanges();
}
}
As you don't show the code where "SaveStatistics" is called it's not sure this will fix your complete problem, but it's at least one method that does not do what you expect it to do.

Getting culture (locale) independent WMI property

I need to get the power settings for a machine using WMI. I am using the MSDN Link to get the required values. I need specific values from the list returned. The following C# code does this:
string NamespacePath = #"root\cimv2\power";
string powerPlanClass = "Win32_powerplan";
string powerSettingClass = "Win32_PowerSettingDataIndex";
ManagementClass powerPlanManagementClass = new ManagementClass(NamespacePath + ":" + powerPlanClass);
ManagementObject powerPlanManagementObject = null;
foreach (ManagementObject managementObject in powerPlanManagementClass.GetInstances())
{
if (managementObject["IsActive"] != null && Boolean.Parse(managementObject["IsActive"].ToString()))
{
powerPlanManagementObject = managementObject;
}
}
Dictionary<string, PowerSetting> powerItems = new Dictionary<string, PowerSetting>()
{
{"AC", new PowerSetting() },
{"DC", new PowerSetting() }
};
foreach (ManagementObject oObject in powerPlanManagementObject.GetRelated(powerSettingClass))
{
var instanceId = oObject["instanceId"];
string[] powerSourceSettings = instanceId.ToString().Split(new string[] { #"\" }, StringSplitOptions.RemoveEmptyEntries);
var powerSourceType = powerSourceSettings[2];
ManagementObjectCollection managementObjects = oObject.GetRelated("Win32_PowerSetting");
var elementName = string.Empty;
foreach (var managementObject in managementObjects)
{
elementName = managementObject["ElementName"].ToString();
}
var indexValue = uint.Parse(oObject["settingindexvalue"].ToString());
if (elementName.Equals("Hibernate after",StringComparison.OrdinalIgnoreCase))
{
if (powerSourceType.Equals("AC", StringComparison.Ordinal))
{
powerItems["AC"].HibernateAfter = indexValue;
}
}
}
Note the match to the string "Hibernate after". This works on a machine with locale en-us but does not work with a different locale. Is there any other way to get the WMI property independent of the machine's locale?
Probably you can use GUID in the InstanceID of Win32_PowerSetting class instead of ElementName. In my machine, it is Microsoft:PowerSetting\{9d7815a6-7ee4-497e-8888-515a05f02364}. Although I couldn't find official document, this GUID, 9d7815a6-7ee4-497e-8888-515a05f02364 seems to be common for some Windows versions and locales as the identifier for "hibernate after" or "hibernate idle".

Sharepoint get content from list

Hi i try to write a little application for sharepoint 2013 where we can backup our projects on an SQL Server. Now i try to loop trough all projects on sharepoint so i can get the content of the fields. Like country = austria.
I tried to follow this guide but had no luck: https://msdn.microsoft.com/en-us/library/office/fp179912.aspx
Here is that what i got:
//Loads only a Projeclist from sharepoint
public SPpowerPlantList loadProjectFromSharePoint()
{
SPpowerPlantList pplist = new SPpowerPlantList();
ClientContext context = new ClientContext(powerPlantSite);
Web web = context.Web;
context.Load(web.Lists);
context.ExecuteQuery();
foreach (List list in web.Lists)
{
SPpowerPlant pp = new SPpowerPlant();
//Stuff like this one should work but dont....
pp.country = list.country
}
return pplist;
}
Any advice would be great and sorry for my english
EDIT: SPpowerPlantList should be a List of all Projects of the Project-List from Sharepoint. And the loadProjectsFromSharepoint is supposed to get a list of Projects wich the i can start to add the values to the sql Server. Stuff like SQL Table value = Sharepoint Field Value.
EDIT2 So the access to the files now work for a few fields but know i get an The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested exeption.
Here is the new code: (some fields work like currency)
//Loads only a Projeclist from sharepoint
public SPpowerPlantList loadProjectFromSharePoint()
{
SPpowerPlantList powerPlantList = new SPpowerPlantList();
ClientContext context = new ClientContext(powerPlantSite);
List powerPlantsList = context.Web.Lists.GetByTitle("Power Plants");
CamlQuery query = CamlQuery.CreateAllItemsQuery();
query.ViewXml = #"<View><Query> </Query></View>";
ListItemCollection items = powerPlantsList.GetItems(query);
context.Load(items);
context.ExecuteQuery();
foreach (ListItem listItem in items)
{
SPpowerPlant powerPlant = new SPpowerPlant();
powerPlant.projectName = listItem["Project"].ToString();
powerPlant.location = listItem["Loacation"].ToString();
powerPlant.country = listItem["Country"].ToString();
powerPlant.currency = listItem["Currency"].ToString();
powerPlant.shortName = listItem["Short Name"].ToString();
powerPlant.spaceUrl = listItem["Space"].ToString();
powerPlant.numberOfWtgs = Convert.ToInt32(listItem["Number of WTGs"]);
powerPlant.mwWtg = Convert.ToDouble(listItem["MW WTG"]);
powerPlant.mwTotal = Convert.ToDouble(listItem["MW Total"]);
powerPlant.projectShareWeb = Convert.ToDouble(listItem["Project Share "]);
powerPlant.mwWeb = Convert.ToDouble(listItem["MW "]);
powerPlant.phaseDescription = listItem["Phase Description"].ToString();
powerPlant.projectProgress = Convert.ToDouble(listItem["Project Progress"]);
powerPlant.mwDeveloped = Convert.ToDouble(listItem["MW developed"]);
powerPlant.possibleWtgTypes = listItem["Possible WTG Types"].ToString();
powerPlant.hubHeight = listItem["Hub Height"].ToString();
powerPlant.allPermits = Convert.ToDateTime(listItem["All Permits"]);
powerPlant.cod = Convert.ToDateTime(listItem["COD"]);
powerPlant.projectManager = listItem["Project manager"].ToString();
powerPlant.technology = listItem["Technology"].ToString();
powerPlant.state = listItem["State"].ToString();
powerPlant.stateSince = Convert.ToDateTime(listItem["State since"]);
powerPlant.visibility = listItem["Visibillity"].ToString();
powerPlant.phase = listItem["Phase"].ToString();
powerPlant.phaseNumber = listItem["Phase Number"].ToString();
//Console.WriteLine(listItem["Currency"]);
powerPlantList.Add(powerPlant);
}
return powerPlantList;
}
I tied it with an lambda expression but no success.
Well the problem was that my listitem["names"] where not correct.
To get that stuff to work you need to go to the sharepoint site and look at the link when you sort it there you see the right name for the listitem.
New and working form:
//Loads only a Projeclist from sharepoint
public SPpowerPlantList loadProjectFromSharePoint()
{
SPpowerPlantList powerPlantList = new SPpowerPlantList();
ClientContext context = new ClientContext(powerPlantSite);
List powerPlantsList = context.Web.Lists.GetByTitle("Power Plants");
CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
//query.ViewXml = #"<View><Query> </Query></View>";
ListItemCollection items = powerPlantsList.GetItems(query);
//context.Load(web.Lists,
// lists => lists.Include(list => list.Title, // For each list, retrieve Title and Id.
// list => list.Id,
// list => list.Description));
context.Load(items);
context.ExecuteQuery();
foreach (ListItem listItem in items)
{
SPpowerPlant powerPlant = new SPpowerPlant();
powerPlant.projectName = listItem["Title"].ToString();
powerPlant.location = listItem["Location"].ToString();
powerPlant.country = listItem["Country"].ToString();
powerPlant.currency = listItem["Currency"].ToString();
powerPlant.shortName = listItem["Short_x0020_Name"].ToString();
powerPlant.spaceUrl = listItem["Space"].ToString();
powerPlant.numberOfWtgs = Convert.ToInt32(listItem["Number_x0020_of_x0020_WTGs"]);
//Console.WriteLine(listItem[""]);
//powerPlantList.Add(powerPlant);
}
return null;
}

How would i assign only DisplayName and Name from PrincipalSearcher to List?

I have the following sample code:
namespace DirectorySearcher
{
class Program
{
static void Main(string[] args)
{
using (var context = new PrincipalContext(ContextType.Domain, "bobo.net"))
{
using (var searcher = new PrincipalSearcher(new UserPrincipal(context) { Enabled = true }))
{
List<Principal> results = new List<Principal>();
results.AddRange(searcher.FindAll());
//foreach (var result in searcher.FindAll())
//{
//Console.WriteLine("displayName : " + result.DisplayName);
//Console.WriteLine("name : " + result.Name);
//Console.WriteLine();
//}
}
}
Console.WriteLine("Done");
Console.ReadLine();
}
}
}
how would I assign only the result.DisaplayName and result.Name to the results list?
can you configure the PrincipalSearcher to only pull back those two values to start with
like you can do with PowerShell ie:
Get-ADUser -Properties DisplayName,Name
Thanks
var list = searcher.FindAll().Select(s => new {name = s.Name, displayName = s.DisplayName});
The above creates a List of anonymous objects, that contains name and displayname.
You could create a poco class to hold the name and display name instead
For limiting the properties of the response
look at this question

Check if a location is indexed in Windows Search

How to check if a location is indexed or not? I found following code to index a location in Windows which works fine but I want to check if it is indexed or not before I make it indexed.
Uri path = new Uri(location);
string indexingPath = path.AbsoluteUri;
CSearchManager csm = new CSearchManager();
CSearchCrawlScopeManager manager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager();
manager.AddUserScopeRule(indexingPath, 1, 1, 0);
manager.SaveAll();
Guys i have found a way to check if the location has been included for indexing by using IncludedInCrawlScope.
CSearchManager csm = new CSearchManager();
CSearchCrawlScopeManager manager = csm.GetCatalog("SystemIndex").GetCrawlScopeManager();
if (manager.IncludedInCrawlScope(indexingPath) == 0)
{
manager.AddUserScopeRule(indexingPath, 1, 1, 0);
manager.SaveAll();
}
But it only checks if it has been added for indexing, not if the indexing is complete.Since i will be querying on the SystemIndex, i need to make sure that the location is indexed.
I ran into a similar need and this is what I came up with. In my case I have certain file extensions that are going to end up being sent to a document management system.
I have two methods one uses the System.IO to get a list of the files in the directory that contain the extension from the list.
public IEnumerable<string> DirectoryScan(string directory)
{
List<string> extensions = new List<string>
{
"docx","xlsx","pptx","docm","xlsm","pptm","dotx","xltx","xlw","potx","ppsx","ppsm","doc","xls","ppt","doct","xlt","xlm","pot","pps"
};
IEnumerable<string> myFiles =
Directory.GetFiles(directory, "*", SearchOption.AllDirectories)
.Where(s => extensions.Any(s.EndsWith))
.ToList();
return myFiles;
}`
The second method uses the windows index search Microsoft.Search.Interop
public IEnumerable<string> QueryWindowsDesktopSearch(string directory)
{
List<string> extensions = new List<string>
{ "docx","xlsx","pptx","docm","xlsm","pptm","dotx","xltx","xlw","potx","ppsx","ppsm","doc","xls","ppt","doct","xlt","xlm","pot","pps"};
string userQuery = "*";
Boolean fShowQuery = true;
List<string> list = new List<string>();
CSearchManager manager = new CSearchManager();
CSearchCatalogManager catalogManager = manager.GetCatalog("SystemIndex");
CSearchQueryHelper queryHelper = catalogManager.GetQueryHelper();
queryHelper.QueryWhereRestrictions = string.Format("AND (\"SCOPE\" = 'file:{0}')", directory);
if (extensions != null)
{
queryHelper.QueryWhereRestrictions += " AND Contains(System.ItemType,'";
bool fFirst = true;
foreach (string ext in extensions)
{
if (!fFirst)
{
queryHelper.QueryWhereRestrictions += " OR ";
}
queryHelper.QueryWhereRestrictions += "\"" + ext + "\"";
fFirst = false;
}
queryHelper.QueryWhereRestrictions += "') ";
}
string sqlQuery = queryHelper.GenerateSQLFromUserQuery(userQuery);
using (OleDbConnection connection = new OleDbConnection(queryHelper.ConnectionString))
{
using (OleDbCommand command = new OleDbCommand(sqlQuery, connection))
{
connection.Open();
OleDbDataReader dataReader = command.ExecuteReader();
while (dataReader.Read())
{
var file = dataReader.GetString(0);
if (file != null)
{
list.Add(file.Replace("file:", ""));
}
}
}
}
return list;
}
I call both of these methods from another methods that takes the two results and compares them and returns a Boolean value indicating if they two list match. If they do not match then the folder has not been indexed fully.
If you call the QueryWindowsDesktopSearch on a folder that has not been indexed it returns zero files. You could use this as an indication that the folder isn't in the index bt its possible that the file has been added to the index but the file indexing is stopped.
You could check the status by calling something like this
CSearchManager manager = new CSearchManager();
CSearchCatalogManager catalogManager = manager.GetCatalog("SystemIndex");
_CatalogPausedReason pReason;
_CatalogStatus pStatus;
catalogManager.GetCatalogStatus(out pStatus, out pReason);
That may return something like pStatus = CATALOG_STATUS_PAUSED and pReason = CATALOG_PAUSED_REASON_USER_ACTIVE
You would know that the index is not running. Another thing you could do is call the following
int incrementalCount, notificationQueue, highPriorityQueue;
catalogManager.NumberOfItemsToIndex(out incrementalCount, out notificationQueue, out highPriorityQueue);
This is going to return the in plIncrementalCount value which would list the number of file that the entire SystemIndex has queued for indexing.
Check this implementation from a document management system:
https://code.google.com/p/olakedms/source/browse/SearchEngine/CSearchDAL.cs?r=171

Categories

Resources