Dealing with CimObjects with PowerShell inside C# - c#

I have a snippet that executes a PowerShell script
using (var ps = PowerShell.Create())
{
ps.AddScript("function Test() { return Get-Disk -Number 0 } ");
ps.Invoke();
ps.AddCommand("Test");
var results = ps.Invoke();
var disk = results.First();
MyDisk myDisk = // do something to convert disk to myDisk
}
Debuggin, it get his inside disk:
How I'm supposed to deal with this object (CimObject)? I would like to get the values from the "Name" and "Number" properties.
Just to clarify, the object I'm trying to deal is the same type as this (run into PowerShell as admin)
PS C:\windows\system32> $disk = Get-Disk -Number 0
PS C:\windows\system32> $disk.GetType();
How do I interact with this?
Thank you!

I don't think there is any easy way to convert PowerShell output to an easier to handle format. You need to 'manually' pull out the properties you want. For example, you can get the 'AllocatedSize' value like this:
var allocatedSize = results.First().Members["AllocatedSize"].Value;
If you want your own types based on these values, then you can do something like this:
Define your type (change the properties to suit the ones you want):
public class MyDisk
{
public long AllocatedSize { get; set; }
public string FriendlyName { get; set; }
public bool IsBoot { get; set; }
public int Number { get; set; }
}
Add a helper method that does the conversion:
private static MyDisk ConvertToMyDisk(PSMemberInfoCollection<PSMemberInfo> item)
{
return new MyDisk
{
AllocatedSize = long.Parse(item["AllocatedSize")].Value.ToString()),
FriendlyName = item["FriendlyName"].Value.ToString(),
IsBoot = bool.Parse(item["IsBoot"].Value.ToString()),
Number = int.Parse(item["Number"].Value.ToString())
};
}
You can then convert the return values to your own type with some basic LINQ:
List<MyDisk> myDisks = results.Select(d => ConvertToMyDisk(d.Members)).ToList();

Related

MongoDB run command with json return

My overall goal is to run a query that shows all the collections with the amount of data / counts and so on.
I found the following command/query and try to run it like this:
MongoClient client = new MongoClient(server);
var db = client.GetDatabase(database);
const string mongoQueryA = "var collectionNames = db.getCollectionNames(), stats = []; " +
"collectionNames.forEach(function(n) { stats.push(db[n].stats()); }); " +
"stats = stats.sort(function(a, b) { return b['size'] - a['size']; }); ";
var command = new JsonCommand<BsonDocument>(mongoQueryA);
var test = db.RunCommand<BsonDocument>(command);
And the code fails here. Exceptions:
JSON reader was expecting a value but found 'var'.
My understanding is that this shoul be run as command?
Running the query in Robot T works as expected. Bonus the plan was to return the data in the following format ( Based on Json from running query manualy in Robot T)
class MongoCollectionInfo
{
public string ns { get; set; }
public long size { get; set; }
public long count { get; set; }
public long avgObjSize { get; set; }
public long storageSize { get; set; }
public long nindexes { get; set; }
public long totalIndexSize { get; set; }
}
What you're trying to achieve can be done purely in C# as it looks like what you've attempted to do is send javascript to the server to be executed which is not how commands work.
To start off with we'll need to get a list of all the collections within a database inside the MongoDB instance.
var client = new MongoClient();
var db = client.GetDatabase("test");
var collectionNames = await (await db.ListCollectionNamesAsync()).ToListAsync();
once we've got the collection names (collectionNames) we can then go ask the database for the stats on that collection by issue a command.
var allCollStats = new List<BsonDocument>(collectionNames.Count);
foreach (var name in collectionNames)
{
var collStatsResult = await db.RunCommandAsync(new BsonDocumentCommand<BsonDocument>(new BsonDocument("collStats", name)));
allCollStats.Add(collStatsResult);
}
The allCollStats then will hold all the stats for the collections and we can then use it as we see fit
foreach (var collStats in allCollStats)
{
Console.WriteLine($"ns: {collStats["ns"]}, size: {collStats["size"]}");
}
// ns: test.test, size: 117
// ns: test.people, size: 5092
Also, if you wanted to use a typed result instead of a BsonDocument you can pass this in as the generic agrument to the command.
var collStatsResult = await db.RunCommandAsync(new BsonDocumentCommand<MongoCollectionInfo>(new BsonDocument("collStats", name)));
Console.WriteLine($"ns: {collStatsResult .ns}, size: {collStatsResult .size}");

Deserialize JSON to list with unknown object name in C#

I want to deserialize following JSON.
The problem is that the objects "ANDE" & "DAR" can change.
Means the objects are unknown and change depending on the JSON i wanna deserialize.
About 8000 different objects (ANDE, DAR, ...) need to be deserialized.
{"ANDE":
{"chart":[
{"date":"20180914","minute":"09:30"},{"date":"20180914","minute":"13:30"}]},
"DAR":
{"chart":[
{"date":"20180914","minute":"09:30"},{"date":"20180914","minute":"13:30"}]}}
I get the data by HTTP response and want to put into a List:
HttpResponseMessage response = client.GetAsync(API_PATH).GetAwaiter().GetResult();
List historicalDataList = response.Content.ReadAsAsync<List<HistoricalDataResponse>>().GetAwaiter().GetResult();
The HistoricalDataResponse class looks like:
public class HistoricalDataResponse
{
public string date { get; set; }
public string minute { get; set; }
}
How can i deserialize this kind of JSON with unknown objects in C#?
Any help is highly appreciated.
Then you should use a dynamic variable:
dynamic ReturnValue = JsonConvert.DeserializeObject(jsonstring);
note that as in dynamic objects, properties are determined after being assigned in runtime, so you will not get a drop down menu in design time, and also as its properties are unknown in design time, and property you test in design time even if its not correct, you wont get an error, and you will get the error in runtime when it is assigned.
dynamic ReturnValue = JsonConvert.DeserializeObject(jsonstring);
try
{
var a = ReturnValue.ANDE; // will work if it has ANDE property.
// do what you would do with ANDE
}
catch{}
try
{
var a = ReturnValue.DAR; // will work if it has DAR property.
// do what you would do with DAR
}
catch{}
Use a dictionary with string as key type :
void Main()
{
var client = new HttpClient();
HttpResponseMessage response = client.GetAsync("url").GetAwaiter().GetResult();
var json = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var result = JsonConvert.DeserializeObject<Dictionary<string, DateResponse>>(json);
foreach (var element in result)
{
var key = element.Key; // ANDE
foreach (var item in element.Value.Chart)
{
var date = item.date;
var minute = item.minute;
}
}
}
public class DateResponse{
public List<HistoricalDataResponse> Chart { get; set; }
}
public class HistoricalDataResponse
{
public string date { get; set; }
public string minute { get; set; }
}

How can i see if my JSON contains a certain value and then compare it?

var Name = "Resources.myjson.json";
var NameJSON = new System.IO.StreamReader(typeof(Strings).GetTypeInfo().Assembly.GetManifestResourceStream(Name)).ReadToEnd();
var ParsedBrandJSON = Newtonsoft.Json.JsonConvert.DeserializeObject<TheInfo>(NameJSON);
await JsonCS.LoadJson(ParsedBrandJSON);
And on the page:
static public class TheInfoJSON
{
static public TheInfo Data { get; set; }
static public async Task LoadJson(Data JSON)
{
Data = JSON;
}
}
and
public class TheInfo
{
public List<TheName> TheName { get; set; } = new List<TheName>();
}
My json:
{
"TheInfo":[
{
"TheName": ["Martin", "Jonas", "Alex", "Oscar"]
}
]
}
When i now try to compare how can i see if my JSON contains a certain object and then store that as a single TheName? Is it possible to do it in the same cast?
var TheNameDataFromOtherPage = OtherPage.TheName; //Here i gather the name from another page that i will compare with the JSON
//Wrong syntax
bool DoTheyMatch = TheNameDataFromOtherPage == TheInfoJSON.Data.TheName.Contains("Alex");
This is now wrong syntax because i cant compare the value to a bool. How can i get out the data i find and then instead of having TheInfoJSON.Data.TheName.Contains("Alex"); as a bool, back to a single value of TheName containing "Alex" so I can create a bool out of the two values to see if the JSON has it or not.
I tried to add something along the lines like this after the contains(): as TheInfo.TheName but that isnt the correct syntax either.
bool DoTheyMatch = TheInfoJSON.Data.TheName.Contains(TheNameDataFromOtherPage);

Best way to group strings according to action

With "Best Way" I mean, maybe, without many If, clean code.
I have a function that receives as parameters (string currentVersion, string action)
and it should return a string versionToBe = "";
For action = "installOldVersion"
-------------if "currentVersion"----------------: -------------OldversionToInstall--------------
"windows10(pro)", "windows10(pro)(education)" : "windows81(pro)"
"windows10(enterprise)", "windows10(enterpise)(lstb)" : "windows81(enterprise)"
"windows7(home)", "windows7(home)(basic)", "windows7(basic)", "windows7": "windowsVista(starter)"
"windowsXP(starter)", "windowsXP(starter)(home)", "windowsXP(home)", "windowsXP": "windows2000(professional)"
"windowsNT(workstation)", "windowsNT": "windows95(sp1)"
For action = "installNewVersion"
-------------if "currentVersion"----------------: -------------NewVersionToInstall--------------
"windows81(pro)", "windows81(pro)(education)" : "windows10(pro)"
"windows81(enterprise)", "windows81(enterprise)(education)" : "windows10(enterprise)"
"windowsVista(starter)", "windowsVista(starter)(package)", "windowsVista(package)", "windowsVista": "windows7(home)"
"windowsVista(starter)", "windowsVista(starter)(praok)", "windowsVista(praok)", "windowsVista": "windowsXP(starter)"
"windows95(sp1)", "windows95(sp1)(versionE)", "windows95": "windowsNT(workstation)"
So,for example, everytime the string name comes like: "windows10(pro)" or "windows10(pro)(education)" it should return: "windows81(pro)".
I know this can get done with lots of if like:
if (version.Equals("windows10(pro)") || version.Equals("windows10(pro)(education)"))
{
versionToBe = "windows81(pro)";
}
and the same for the rest of them, anding with 10 If statements in Total.
But If there's a better way to do it, I'd want to know.
Another restriction, or other thing to consider:
if the action is "installOldVersion", versionToBe is OldversionToInstall,
and if the action is "installNewVersion", versionTobe would be NewVersionToInstall.
You could create a list of objects with CurrentVersion, Old Version and New Version and then extract the one you want from the list.
Example Instruction Class Definition
public class VersionInformation
{
public string CurrentVersion {get; set;}
public string NewVersion {get; set;}
public string OldVersion {get; set;}
}
then in your program, have a list of them, either hard coded or loaded from file or whatever datastore you want and do your version check as follows:
private List<VersionInformation> _versionInformation = //Load your list from wherever;
public void DoVersionCheck(string version)
{
var currentversionInfo = _versionInformation.Single(x=> x.CurrentVersion == version);
//Do Whatever you want with the upgrades and downgrades here based on whatever action you are doing
}
Set yourself up a dictionary and perform a lookup.
As an exercise for the reader:
You could drive the dictionary contents from some configuration or other...even from a database if you want.
You'd presumably want to set up your dictionary as a static and initialize it only once.
You'll want some handling for when there is no dictionary entry - you don't specify a default in your question.
Dictionary, string> ActionMatrix = new Dictionary, string>();
ActionMatrix.Add(Tuple.Create ("windows10(pro)", "installOldVersion"), "windows81(pro)");
ActionMatrix.Add(Tuple.Create ("windows10(pro)(education)", "installOldVersion"), "windows81(pro)");
ActionMatrix.Add(Tuple.Create ("windows10(enterprise)", "installOldVersion"), "windows81(enterprise)");
ActionMatrix.Add(Tuple.Create ("windows10(enterpise)(lstb)", "installOldVersion"), "windows81(enterprise)");
// etc
ActionMatrix.Add(Tuple.Create("windows81(pro)", "installNewVersion"), "windows10(pro)");
ActionMatrix.Add(Tuple.Create("windows81(pro)(education)", "installNewVersion"), "windows10(pro)");
ActionMatrix.Add(Tuple.Create("windows81(enterprise)", "installNewVersion"), "windows10(enterprise)");
ActionMatrix.Add(Tuple.Create("windows10(enterpise)(education)", "installNewVersion"), "windows10(enterprise)");
// etc
public string VersionToBe (string currentVersion, string action)
{
return ActionMatrix[Tuple.Create(currentVersion, action)];
}
A simple object with it's own list should do the trick and is visually better to follow.
public class VersionData
{
private static List<VersionData> VersionDatas { get; set; } = new List<VersionData>()
{
new VersionData( "OldversionToInstall", new [] {"windows10(pro)", "windows10(pro)(education)" }.ToList(), "windows81(pro)" ),
new VersionData( "OldversionToInstall", new [] {"windows10(enterprise)", "windows10(enterpise)(lstb)" }.ToList(), "windows81(enterprise)" )
};
public string Action { get; set; } = "";
public List<string> CurrentVersions { get; set; } = new List<string>();
public string Version { get; set; } = "";
public VersionData(string action, List<string> currentVersions, string version)
{
Action = action;
CurrentVersions = currentVersions;
Version = version;
}
public static string GetVersion(string action, string currentVersion)
{
return VersionDatas.FirstOrDefault(o => o.Action == action && o.CurrentVersions.Any(x => x == currentVersion)).Version;
}
}
and to call it's as simple as :
var oldVersion = VersionData.GetVersion("OldversionToInstall", "windows10(enterpise)(lstb)");

Getting list of attributes for all methods in class

I'm attempting to use a custom attribute to generate a list of commands (string) that a user would issue into my console application and the corresponding method will be executed. I'm currently stuck, my command list is always empty.
Here's my attribute:
public class ImporterAttribute : Attribute
{
public string Command { get; set; }
}
Here's the class:
public class DataProcessor
{
public List<ImporterAttribute> Commands { get; set; }
public DataProcessor()
{
//Use reflection to collect commands from attributes
Commands = GetCommands(typeof(DataProcessor));
}
public static List<ImporterAttribute> GetCommands(Type t)
{
var commands = new List<ImporterAttribute>();
MemberInfo[] MyMemberInfo = t.GetMethods();
foreach (MemberInfo member in MyMemberInfo)
{
var att = (ImporterAttribute)Attribute.GetCustomAttribute(member, typeof(ImporterAttribute));
if (att == null) continue;
var command = new ImporterAttribute();
command.Command = att.Command;
commands.Add(command);
}
return commands;
}
[Importer(Command = "?")]
private string Help()
{
return "Available commands: " + (from c in Commands select c.Command).Aggregate((a, x) => a + " " + x);
}
[Importer(Command = "Q")]
private void Quit()
{
Environment.Exit(0);
}
}
Then I use a switch statement to check user input against the command list and run the requested method. So my question is: why is my command list always null? I imagine I just misunderstood something in the docs.
Bonus question: does anyone have a better/more practical approach that they use/have used to tackle this feature?
The problem with your code is that your methods are private. GetMethods by default only retrieve public methods, so if you change your Help and Quit method signature to public, you'll get 2 commands.
If you want to keep them private,you can use BindingFlags like this:
t.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance);

Categories