Create PowerShell PSObject in C# cmdlet - c#

New to C# but experienced in PowerShell. Taking over someone else's code. Writing a compiled PowerShell module, and trying to figure out how to create an object based on returned data. Right now, code returns a string:
ServerResponse<UCCSiteModel> requestModel = this.MakeRequest("/site/api/", "site", "GET", this.Credentials, queryString);
StringBuilder builder = new StringBuilder();
if (requestModel != null && requestModel.Response != null)
{
builder.AppendLine("SiteID: " + requestModel.Response.SiteID);
builder.AppendLine("Identity: " + requestModel.Response.SiteName);
builder.AppendLine("Site Code: " + requestModel.Response.SiteCode);
builder.AppendLine("Contact Name: " + requestModel.Response.ContactName);
builder.AppendLine("Contact Number: " + requestModel.Response.ContactNumber);
builder.AppendLine("Contact Email Address: " + requestModel.Response.ContactEmailAddress);
builder.AppendLine("Address: " + requestModel.Response.Address);
builder.AppendLine("City: " + requestModel.Response.City);
builder.AppendLine("State: " + requestModel.Response.State);
builder.AppendLine("Post Code: " + requestModel.Response.PostCode);
builder.AppendLine("Time Zone: " + requestModel.Response.Timezone);
builder.AppendLine("Longitude: " + requestModel.Response.longitude);
builder.AppendLine("Latitude: " + requestModel.Response.latitude);
this.WriteResponse(requestModel, builder.ToString());
}
How do I create an object from requestModel.Response to send back to PowerShell instead of the string? When writing PowerShell, I would normally use New-Object PsObject, and then Add-Member. Not sure how to do that in C#, or what it's called (so I can search). Anyone?

You can mirror the behavior of Add-Member simply by calling Add() on the Members property of your PSObject (I would change the property names to CamelCase for ease of accessibility in PowerShell):
if (requestModel != null && requestModel.Response != null)
{
PSObject responseObject = new PSObject();
responseObject.Members.Add(new PSNoteProperty("SiteID", requestModel.Response.SiteID));
responseObject.Members.Add(new PSNoteProperty("Identity", requestModel.Response.SiteName));
// and so on etc...
responseObject.Members.Add(new PSNoteProperty("Latitude", requestModel.Response.latitude));
this.WriteObject(responseObject);
}

Without knowing all the details I can't say this is the best plan, but here is what I would do. You could define a class and then return it. So you would create a new class such as below:
public class RequestResponse {
public int SiteID { get; set;}
public string Identity { get; set; }
other fields...
}
Next, in the code you posted, you would create the object and then fill the properties of the class.
var response = new RequestResponse();
if (requestModel != null && requestModel.Response != null)
{
response.SiteID = requestModel.Response.SiteID;
response.Identity = requestModel.Response.Identity ;
fill in other fields...
this.WriteResponse(requestModel, response);
}
I hope this gets you started in the right direction.
Wade

Related

TypeScript proxy generation with nSwag: Null checks on nullable int

We are using a .net core WebAPI backend and use nSwag to generate TypeScript proxies to be used in the frontend. This is the backend/C# code:
public class MyDto
{
public MyDto() { }
public int Id { get; set; }
public int? OtherObject { get; set; }
}
and the controller method
[Route("SaveEditedDto")]
[HttpPost]
public EditResultDto SaveEditedDto(MyDto dto)
The generated TypeScript for the "save" method looks like this:
saveEditedDto(id: number | undefined, otherObject: number | undefined): Observable<EditResultDto> {
let url_ = this.baseUrl + "/api/MyDomain/SaveEditedDto?";
if (oid === null)
throw new Error("The parameter 'oid' cannot be null.");
else if (oid !== undefined)
url_ += "Oid=" + encodeURIComponent("" + oid) + "&";
if (otherObject === null)
throw new Error("The parameter 'otherObject' cannot be null.");
else if (otherObject !== undefined)
url_ += "OtherObject=" + encodeURIComponent("" + otherObject) + "&";
url_ = url_.replace(/[?&]$/, "");
I have actually two questions about this:
Why is the a null check on the OtherObject parameter? It doesn't make any sense to me, because the field in the DTO is nullable.
More important: How do I get nSwag not to put the null check in?
I believe, what you want to achieve is not get rid of the null check itself, but dodge it. Looks like nswag generated code to me. It is clearly depicted here:
else if (oid !== undefined)
url_ += "Oid=" + encodeURIComponent("" + oid) + "&";
...
else if (otherObject !== undefined)else if (otherObject !== undefined)
url_ += "OtherObject=" + encodeURIComponent("" + otherObject) + "&";
that all you might need to do is pass undefined rather than null as parameters oid and otherObject.
This hint is given by the creator himself, as well here:
https://github.com/RicoSuter/NSwag/issues/1067

C# - Visual Studio - 'object' does not contain a definition for 'ExecuteQuery'

I am trying to add code to an existing project that will check for existence of a device in SCCM and delete it if it does exist. I seem to be missing something, in that particular block of code. I get an error - 'object' does not contain a definition for 'ExecuteQuery' and no extension method 'ExecuteQuery' accepting a first argument of type 'object' could be found.
Here is the C# code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Net.NetworkInformation;
using SupportToolkit.Models;
using SupportToolkit.WindowsAutomationServices;
using NLog;
using System.Text;
using System.DirectoryServices;
using System.DirectoryServices.AccountManagement;
using System.Management;
namespace SupportToolkit.Controllers
{
public class TPOSRecordDeletionController : Controller
{
private static Logger recordDeletionLogger = LogManager.GetCurrentClassLogger();
[Authorize(Roles = #"nor\NST_RIT_Users,nor\NST_STM_Users,nor\NST_Admin_Users,nor\NST_CORP_Users")]
// GET: TPOSRecordDeletion
public ActionResult Index(TPOSRecordDeletionModel model)
{
if (model.ComputerName != null)
{
}
if (ModelState.IsValid)
{
if (!(string.IsNullOrEmpty(model.btnDeleteRecord)))
{
InvokeRecordDeletion(model);
}
}
return View(model);
}
[Authorize(Roles = #"nor\NST_RIT_Users,nor\NST_STM_Users,nor\NST_Admin_Users,nor\NST_CORP_Users")]
public string InvokeRecordDeletion(TPOSRecordDeletionModel model)
{
model.Status = "Running Service";
var windowsAutomationService = new WindowsAutomationServicesClient();
string shortServiceOutput;
var serviceAction = "Remove-TPOSRecords";
var SCCMServer = "server.nor.net";
var siteCode = "PO60";
string[] recordDeletionArguments = new string[1];
recordDeletionArguments[0] = model.ComputerName;
model.Status = "Processing" + model.ComputerName;
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
// Use the default Ttl value which is 128,
// but change the fragmentation behavior.
options.DontFragment = true;
// Create a buffer of 32 bytes of data to be transmitted.
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
PingReply reply = pingSender.Send(model.ComputerName, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
model.Status = model.ComputerName + "is currently online and will not be removed!";
}
else
{
// set up domain context
using (var ctx = new System.DirectoryServices.AccountManagement.PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Domain))
{
// find a computer
ComputerPrincipal computer = ComputerPrincipal.FindByIdentity(ctx, model.ComputerName);
if (computer == null)
{
model.Status = model.ComputerName + "does not exist in Active Directory.";
}
else
{
computer.Delete();
model.Status = model.ComputerName + "successfully removed from Active Directory!";
}
//insert code here for checking for existence of computer in SCCM and removing from SCCM if exists
SmsNamedValuesDictionary namedValues = new SmsNamedValuesDictionary();
WqlConnectionManager connection = new WqlConnectionManager(namedValues);
connection.Connect("s0319p60.nordstrom.net");
foreach (IResultObject computerobject in connection.QueryProcessor.ExecuteQuery("Select ResourceID From SMS_R_System Where Name ='" + model.ComputerName + "'"))
{
if (computerobject == null)
{
model.Status = model.ComputerName + "does not exist in SCCM.";
}
else
{
computerobject.Delete();
model.Status = model.ComputerName + "successfully removed from SCCM!";
}
}
}
var userName = User.Identity.Name;
var serviceOutput = windowsAutomationService.RunAutomationService(serviceAction, userName, recordDeletionArguments);
recordDeletionLogger.Info(userName + " is attempting to remove the record " + model.ComputerName);
if (serviceOutput.Length >= 7)
{
shortServiceOutput = serviceOutput.Substring(0, 7);
shortServiceOutput = shortServiceOutput.ToLower();
}
else
{
shortServiceOutput = serviceOutput;
shortServiceOutput = shortServiceOutput.ToLower();
}
if (shortServiceOutput == "success")
{
model.Status = "Successfully removed " + model.ComputerName + " from SCCM and Active Directory";
recordDeletionLogger.Info(userName + " successfully removed " + model.ComputerName + " from SCCM and Active Directory");
return "Success";
}
else
{
model.Status = "Failure removing " + model.ComputerName + " from SCCM and Active Directory. Unknown Error";
recordDeletionLogger.Info(userName + " failed to remove " + model.ComputerName + " from SCCM and Active Directory");
return "Failure";
}
}
}
}
internal interface IResultObject
{
//void Delete();
void Delete();
}
internal class WqlConnectionManager
{
private SmsNamedValuesDictionary namedValues;
public WqlConnectionManager(SmsNamedValuesDictionary namedValues)
{
this.namedValues = namedValues;
}
public object QueryProcessor { get; internal set; }
internal void Connect(string v)
{
throw new NotImplementedException();
}
public object ExecuteQuery { get; internal set; }
}
internal class SmsNamedValuesDictionary
{
public SmsNamedValuesDictionary()
{
}
}
Well - after a few days of searching, I FINALLY figured out the issue.
The entire block of code at the end, was not necessary. The issue was that there were missing assembly references and using statements in the code. Specifically:
using Microsoft.ConfigurationManagement.ManagementProvider;
using Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine;
The corresponding DLLs also needed to be added to the project as references.
I hope this helps someone who runs into similar issues and is not versed in C# coding. I myself am only versed in PowerShell, so figuring this out took a lot of work for me. Thanks.
You create a custom "connection" object:
WqlConnectionManager connection = new WqlConnectionManager(namedValues);
Then call a method on one of its properties:
connection.QueryProcessor.ExecuteQuery("...")
But what is that QueryProcessor property?...
public object QueryProcessor { get; internal set; }
It's an object. As the error states, object doesn't have a method called ExecuteQuery. (It doesn't have very many methods or properties at all, really.)
I can't really tell from this code (maybe I'm missing something?) what specific type you're expecting QueryProcessor to be, but it should definitely be something more specific than object. Something analogous to a SQLCommand object, perhaps? Essentially, whatever type would have that ExecuteQuery method.
If there's a compelling reason in the existing codebase for this to be of type object, you'd need to determine what that reason is. There seems to be a lot of use of object here, which smells of some bad design choices from before you got there.

Not all code paths return a value. I was just wondering what was the fix to this?

When I hover over the Index it has a red line underneath and says
'UnauthEnquiryController.index(UnauthenticatedEnquiryViewModel)': not all code paths return a value.
I was just wondering what was the fix to this?
[HttpPost]
public ActionResult Index(UnauthenticatedEnquiryViewModel unauthenticatedEnquiryViewModel)
{
//unauthenticatedEnquiryViewModel.EnquiryType;
//NEED TO ADD A METHOD THAT SENDS FILE TO CRM HERE
if (ModelState.IsValid)
{
if (1 == 0) //take off
{
string fromAddress = WebConfigurationManager.AppSettings["FromEmail"]; //gets email from web.config file
//var toAddress = new MailAddress(); //need to get this from crm
var enquiry = DataAccessEnquiry.GetEnquiryCategoryEmail(unauthenticatedEnquiryViewModel.EnquiryType); //gets the to address based on CRm
string UnauthEmailSubject = WebConfigurationManager.AppSettings["UnauthEmailSubject"]; //gets subject from web.config file
MailMessage mailMessage = new MailMessage(fromAddress, enquiry.Email); //put to address frrom variable declared above
mailMessage.Subject = UnauthEmailSubject;
StringBuilder mailbuilder = new StringBuilder();
mailbuilder.AppendLine("First name: " + unauthenticatedEnquiryViewModel.FirstName);
mailbuilder.AppendLine("Last name: " + unauthenticatedEnquiryViewModel.LastName);
mailbuilder.AppendLine("Communication: " + unauthenticatedEnquiryViewModel.CCommmunication);
mailbuilder.AppendLine("Email: " + unauthenticatedEnquiryViewModel.Email);
mailbuilder.AppendLine("Confiirmation of email: " + unauthenticatedEnquiryViewModel.ConfirmEmailAddress);
mailbuilder.AppendLine("Mobile telephone No: " + unauthenticatedEnquiryViewModel.MobileTelephoneNo);
mailbuilder.AppendLine("Confiirmation of mobile telephone no: " + unauthenticatedEnquiryViewModel.ConfirmMobileTelephoneNo);
mailbuilder.AppendLine("Alternative telephone no: " + unauthenticatedEnquiryViewModel.AlternativeTelephoneNo);
mailbuilder.AppendLine("Confiirmation of alternative telephone no: " + unauthenticatedEnquiryViewModel.ConfirmAlternativeTelephoneNo);
mailbuilder.AppendLine("I am a: " + unauthenticatedEnquiryViewModel.Profession);
mailbuilder.AppendLine("Enquiry Type: " + unauthenticatedEnquiryViewModel.EnquiryType);
mailbuilder.AppendLine("Your message: " + unauthenticatedEnquiryViewModel.YourMessage);
if (unauthenticatedEnquiryViewModel.File != null) // this finds overall null
{
foreach (var file in unauthenticatedEnquiryViewModel.File) // loop through every File
{
if (file != null) //Finds induvidual null
{
var extension = new FileInfo(file.FileName).Extension.ToUpper();
mailMessage.Attachments.Add(new Attachment(file.InputStream, file.FileName));
}
}
}
mailMessage.Body = mailbuilder.ToString();
SmtpClient smtpClient = new SmtpClient();
smtpClient.Send(mailMessage);
}
return View("Unauthsuccess", unauthenticatedEnquiryViewModel);
}
unauthenticatedEnquiryViewModel.Professions = DataAccessEnquiry.GetProfessionUnauthenticated();
unauthenticatedEnquiryViewModel.EnquiryTypes = new List<EnquiryType>();
}
[HttpPost]
public ActionResult Index(UnauthenticatedEnquiryViewModel unauthenticatedEnquiryViewModel)
{
//unauthenticatedEnquiryViewModel.EnquiryType;
//NEED TO ADD A METHOD THAT SENDS FILE TO CRM HERE
if (ModelState.IsValid)
{
...
return View("Unauthsuccess", unauthenticatedEnquiryViewModel);
}
unauthenticatedEnquiryViewModel.Professions = DataAccessEnquiry.GetProfessionUnauthenticated();
unauthenticatedEnquiryViewModel.EnquiryTypes = new List<EnquiryType>();
//THIS path doesn't return value.
//HERE return somethig
}
You return value only if if (ModelState.IsValid) is true but what want you return if this is false?
Here you have created a condition,
if(ModelState.Isvalid)
{
{// LOTS OF CODE}
return View(....);
}
But if
ModelState.Isvalid == false
is true then the function wouldn't return anything
You are returning value in if condition only that's way its saying. You must have to return after if condition as well

Deviare v2 C# Hook API Call and read param

I'm trying to figure out how I can read a param. I got the hook working, only thing is that whenever I do this, it crashes:
private void onFuncCall(NktHook hook, NktProcess process, NktHookCallInfo hookCallInfo)
var paramsEnum = hookCallInfo.Params();
if (hook.FunctionName.Equals("getPlayerPtr"))
{
INktParam p;
p = paramsEnum.First();
Debug.WriteLine(p.Value);//This line cause a crash
return;
}
}
getPlayerPtr definition:
UINT64 *getPlayerPtr(int Id);
This code should print all parameters values:
private void OnFunctionCalled(NktHook hook, NktProcess process, NktHookCallInfo hookCallInfo)
{
Output(hook.FunctionName + "( ");
bool first = true;
foreach (INktParam param in hookCallInfo.Params())
{
if (first)
first = false;
else
{
Output(", ");
}
Output(param.Name + " = " + param.Value.ToString());
}
Output(" )" + Environment.NewLine);
}
It it doesn't work means that the hooked function isn't in Deviare Database. If that's the situation you should create a custom database:
http://forum.nektra.com/forum/viewtopic.php?f=9&t=7130

Compile C# Roslyn

I'm using Roslyn to try and compile and run code at runtime. I've ysed some code I found online and have it somewhat working.
public Type EvalTableScript(string Script, CRMMobileFramework.EnbuUtils EnbuUtils, CRMMobileFramework.Includes.DBAdapter dbConn)
{
var syntaxTree = SyntaxTree.ParseText(Script);
var compilation = Compilation.Create("EnbuScript.dll",
options: new CompilationOptions(outputKind: OutputKind.DynamicallyLinkedLibrary),
references: new[]
{
new MetadataFileReference(typeof(object).Assembly.Location),
new MetadataFileReference(typeof(EnbuUtils).Assembly.Location),
new MetadataFileReference(typeof(DBAdapter).Assembly.Location),
MetadataFileReference.CreateAssemblyReference("System.Data"),
MetadataFileReference.CreateAssemblyReference("System.Linq"),
MetadataFileReference.CreateAssemblyReference("System"),
MetadataFileReference.CreateAssemblyReference("System.XML")
},
syntaxTrees: new[] { syntaxTree });
var diagnostics = compilation.GetDiagnostics();
foreach (var diagnostic in diagnostics)
{
Console.WriteLine("Error: {0}", diagnostic.Info.GetMessage());
}
Assembly assembly;
using (var stream = new MemoryStream())
{
EmitResult emitResult = compilation.Emit(stream);
assembly = Assembly.Load(stream.GetBuffer());
}
Type ScriptClass = assembly.GetType("EnbuScript");
// Pass back the entire class so we can call it at the appropriate time.
return ScriptClass;
}
Then I'm trying to call this:
string Script = #"
using System;
using System.Data;
using System.IO;
using System.Linq;
public class EnbuScript
{
public string PostInsertRecord(CRMMobileFramework.EnbuUtils EnbuUtils,CRMMobileFramework.Includes.DBAdapter dbConn)
{
string ScriptTable = ""QuoteItems"";
DataSet EntityRecord = dbConn.FindRecord(""*"", ScriptTable, ""QuIt_LineItemID='"" + EnbuUtils.GetContextInfo(ScriptTable) + ""'"", """", 1, 1, false);
string OrderId = EntityRecord.Tables[""item""].Rows[0][""QuIt_orderquoteid""].ToString();
string UpdateOrderTotalCommand = ""UPDATE Quotes SET Quot_nettamt = (select SUM(QuIt_listprice * quit_quantity) from QuoteItems where quit_orderquoteid = "" + OrderId + "" ) where Quot_OrderQuoteID = "" + OrderId;
dbConn.ExecSql(UpdateOrderTotalCommand);
return ""Complete"";
}
}";
Type EnbuScript = EnbuUtils.EvalTableScript(Script, EnbuUtils, dbConn);
MethodInfo methodInfo = EnbuScript.GetMethod("InsertRecord");
object[] parameters = { EnbuUtils, dbConn };
string InsertRecordResult = methodInfo.Invoke(null, parameters).ToString();
As you can see I've been messing around with trying to pass parameters to the compilation.
Basically I've got 4 functions I need to support, that will come in as a string. What I'm trying to do is create a class for these 4 functions and compile and run them. This part works.
What I now need to be able to do is pass class instances to this. In the code you'll see a dbConn which is basically my database connection. I need to pass the instance of this to the method I'm calling at runtime so it has it's correct context.
I have another implementation of this where I'm using the Roslyn session. I originally tried to use this and override my function at runtime but that didn't work either. See below what I tried:
public static void EvalTableScript(ref EnbuUtils EnbuUtils, DBAdapter dbConn, string EvaluateString)
{
ScriptEngine roslynEngine = new ScriptEngine();
Roslyn.Scripting.Session Session = roslynEngine.CreateSession(EnbuUtils);
Session.AddReference(EnbuUtils.GetType().Assembly);
Session.AddReference(dbConn.GetType().Assembly);
Session.AddReference("System.Web");
Session.AddReference("System.Data");
Session.AddReference("System");
Session.AddReference("System.XML");
Session.ImportNamespace("System");
Session.ImportNamespace("System.Web");
Session.ImportNamespace("System.Data");
Session.ImportNamespace("CRMMobileFramework");
Session.ImportNamespace("CRMMobileFramework.Includes");
try
{
var result = (string)Session.Execute(EvaluateString);
}
catch (Exception ex)
{
}
}
I tried to call this using:
string PostInsertRecord = "" +
" public override void PostInsertRecord() " +
"{ " +
" string ScriptTable = \"QuoteItems\"; " +
"DataSet EntityRecord = dbConn.FindRecord(\"*\", ScriptTable, \"QuIt_LineItemID='\" + EnbuUtils.GetContextInfo(ScriptTable) + \"'\", \"\", 1, 1, false); " +
"string OrderId = EntityRecord.Tables[\"item\"].Rows[0][\"QuIt_orderquoteid\"].ToString(); " +
"string UpdateOrderTotalCommand = \"UPDATE Quotes SET Quot_nettamt = (select SUM(QuIt_listprice * quit_quantity) from QuoteItems where quit_orderquoteid = \" + OrderId + \" ) where Quot_OrderQuoteID = \" + OrderId; " +
"dbConn.ExecSql(UpdateOrderTotalCommand); " +
"} ";
The function is declared as a public virtual void in the EnbuUtils class but it says it doesn't have a suitable method to override.
Safe to say, I'm stumped!
Any help appreciated!
Thanks
I got this in the end - this first method was very close to what I actually needed. Changed the method to static and had to add a few references including the full namespace.

Categories