Programmatical equivalence of Remove-NetEventSession - c#

Remove-NetEventSession is a powershell cmdlet that removes a network event session.
It's usually used after Stop-NetEventSession and Get-NetEventSession:
$session = Get-NetEventSession
Stop-NetEventSession $session.Name
Remove-NetEventSession $session.Name
Is there a way to achieve the same result using .Net? (Not by executing a powershell script)

Yes, there is.
Using the WMI API for .Net (System.Management) you can manipulate the MSFT_NetEventSession instance.
The following example gets the running session (there can be only one), stops it if it's running and removes it:
var netEventSession = new ManagementClass("/root/standardcimv2:MSFT_NetEventSession").
GetInstances().
Cast<ManagementObject>().
SingleOrDefault();
if (netEventSession != null)
{
if ((byte)netEventSession["SessionStatus"] == 0)
{
netEventSession.InvokeMethod("Stop", null, null);
}
netEventSession.Delete();
}

Related

How to retrieve IVsDebugger from external DTE for automation in Visual Studio 2019

I am trying to write a VSIX for Visual Studio 2019 that controls multiple instances of the Visual Studio IDE. We are working on a networked project that requires some automation to perform testing of multiple users. In the past I would have used DTE in an external tool, but my understanding is that as of VS2017 the COM guids are no longer globally registered, so doing it within the IDE is the only way.
Regardless, I am trying to get the IVsDebugger so I can track events in the debugger. However, I am having no luck. I can get IVsDebugger2, 3, 4, 5 but not IVSDebugger. Here is the general flow of what I am doing:
void CaptureDebugger()
{
DTE dte = GetDTE(GetRemoteProcessID());
ServiceProvider sp = new ServiceProvider((Microsoft.VisualStudio.OLE.Interop.IServiceProvider)dte);
IVsDebugger vsDebugger = sp.GetService(typeof(SVsShellDebugger)) as IVsDebugger;
// vsDebugger is null!
IVsDebugger2 vsDebugger2 = sp.GetService(typeof(SVsShellDebugger)) as IVsDebugger2;
// vsDebugger2 is not null!
}
/// <summary>
/// Gets the DTE object from any devenv process.
/// </summary>
private static EnvDTE.DTE GetDTE(int processId)
{
object runningObject = null;
IBindCtx bindCtx = null;
IRunningObjectTable rot = null;
IEnumMoniker enumMonikers = null;
try
{
Marshal.ThrowExceptionForHR(CreateBindCtx(reserved: 0, ppbc: out bindCtx));
bindCtx.GetRunningObjectTable(out rot);
rot.EnumRunning(out enumMonikers);
IMoniker[] moniker = new IMoniker[1];
IntPtr numberFetched = IntPtr.Zero;
while (enumMonikers.Next(1, moniker, numberFetched) == 0)
{
IMoniker runningObjectMoniker = moniker[0];
string name = null;
try
{
if (runningObjectMoniker != null)
{
runningObjectMoniker.GetDisplayName(bindCtx, null, out name);
}
}
catch (UnauthorizedAccessException)
{
// Do nothing, there is something in the ROT that we do not have access to.
}
Regex monikerRegex = new Regex(#"!VisualStudio.DTE\.\d+\.\d+\:" + processId, RegexOptions.IgnoreCase);
if (!string.IsNullOrEmpty(name) && monikerRegex.IsMatch(name))
{
Marshal.ThrowExceptionForHR(rot.GetObject(runningObjectMoniker, out runningObject));
}
}
}
finally
{
if (enumMonikers != null)
Marshal.ReleaseComObject(enumMonikers);
if (rot != null)
Marshal.ReleaseComObject(rot);
if (bindCtx != null)
Marshal.ReleaseComObject(bindCtx);
}
return runningObject as EnvDTE.DTE;
}
What confuses me is I get get the local IVsDebugger via the call
var MYDEBUGGER = Package.GetGlobalService(typeof(SVsShellDebugger)) as IVsDebugger;
Which I see is using a GlobalService. I don't think there is an equivalent in the DTE I retrieve.
Any insight?
I ran into this issue as well (however in my case, I'm actually trying to retrieve the IVsDebugger in proc rather than what sounds like out of proc); after debugging into how vsdebug!CDebugger::QueryInterface works I determined the actual issue appears to be that the calling thread in your application needs to be STA.
When the calling thread in your application is MTA, while vsdebug!CDebugger::QueryInterface returns with HRESULT 0
This shortly gets turned into 0x80040155 (REGDB_E_IIDNOTREG) by OLE due to CStdWrapper::GetPSFactory failing to find a proxy DLL for this type
This error in turn gets converted by CRemoteUnknown::RemQueryInterface to 0x80004002 (E_NOINTERFACE)
Which is what is reported back to you if you try and Marshal.QueryInterface in C# to see what's going on directly.
If your program contains in-proc components that live inside the remote Visual Studio process (as mine does) you can retrieve and execute your operations against the IVsDebugger on the UI thread. Otherwise, you can potentially create a new Thread and call thread.SetApartmentState(ApartmentState.STA) on it prior to starting it

Automatic Updates setting via WMI

Attempting to pull the automatic update settings from the registry of a remote server. For some reason, it's returning a 0 even though a manual check of the key is 1-4. What am I overlooking? Snippet below:
ManagementScope msAutoUpdateReg = new ManagementScope(#"\\" + remoteServer + #"\root\DEFAULT:StdRegProv", connection);
msAutoUpdateReg.Connect();
ManagementClass ci = new ManagementClass(msAutoUpdateReg, new ManagementPath(#"DEFAULT:StdRegProv"), new ObjectGetOptions());
ManagementBaseObject inParams = ci.GetMethodParameters("GetDWORDValue");
inParams["hDefKey"] = 0x80000002; //HKLM
inParams["sSubKeyName"] = #"Software\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update";
inParams["sValueName"] = "AUOptions";
ManagementBaseObject outParams = ci.InvokeMethod("GetDWORDValue", inParams, null);
UInt32 auValue = (UInt32)outParams["uValue"];
if (auValue.ToString() != "0")
{
if (auValue == 1)
{
string currentSetting = "Keep my computer up to date has been disabled in Automatic Updates.";
}
if (auValue == 2)
{
string currentSetting = "Notify of download and installation.";
}
if (auValue == 3)
{
string currentSetting = "Automatically download and notify of installation.";
}
if (auValue == 4)
{
string currentSetting = "Automatically download and scheduled installation.";
}
}
else
{
string currentSetting = "Unknown";
}
I guess a process of elimination might help here...
1) Is this happening on just one server or are you getting this on all servers? How about on your own local machine? Is it a Windows version thing? For example it seems my Windows 10 box doesn't show the SubKey name you are looking for.
2) Do you also get zero if you change the sValueName to "foo"? Is a value of 0 representing an error?
3) Can you put a watch on outParams and check to see what values have been returned?
4) Are you being blocked by UAC, firewall or other permission issues? Can you execute other WMI commands against this server without any problems? Do you need to Run As Administrator to get this to work?
5) Are you getting an other exceptions or return values? I'm guessing you've posted just a portion of the code here so is this code inside a try/catch block?
Sorry if this sounds either vague or simplistic but I think you may need to look at what does work and what doesn't to see if you can identify a pattern.

C# Security Exception

When running this program I keep receiving the error:
An unhandled exception of type 'System.Security.SecurityException' occured
Additional Information: ECall methods must be packaged into a system module.
class Program{
public static void Main()
{
Brekel_ProBody2_TCP_Streamer s = new Brekel_ProBody2_TCP_Streamer();
s.Start();
s.Update();
s.OnDisable();
}
}
How can I fix this?
The important part of the Brekel library is as follows:
//======================================
// Connect to Brekel TCP network socket
//======================================
private bool Connect()
{
// try to connect to the Brekel Kinect Pro Body TCP network streaming port
try
{
// instantiate new TcpClient
client = new TcpClient(host, port);
// Start an asynchronous read invoking DoRead to avoid lagging the user interface.
client.GetStream().BeginRead(readBuffer, 0, READ_BUFFER_SIZE, new AsyncCallback(FetchFrame), null);
Debug.Log("Connected to Brekel Kinect Pro Body v2");
return true;
}
catch (Exception ex)
{
Debug.Log("Error, can't connect to Brekel Kinect Pro Body v2!" + ex.ToString());
return false;
}
}
//===========================================
// Disconnect from Brekel TCP network socket
//===========================================
private void Disconnect()
{
if (client != null)
client.Close();
Debug.Log("Disconnected from Brekel Kinect Pro Body v2");
}
public void Update()
{
// only update if connected and currently not updating the data
if (isConnected && !readingFromNetwork)
{
// find body closest to the sensor
closest_skeleton_ID = -1;
closest_skeleton_distance = 9999999f;
for (int bodyID = 0; bodyID < skeletons.GetLength(0); bodyID++)
{
if (!skeletons[bodyID].isTracked)
continue;
if (skeletons[bodyID].joints[(int)brekelJoint.waist].position_local.z < closest_skeleton_distance)
{
closest_skeleton_ID = bodyID;
closest_skeleton_distance = skeletons[bodyID].joints[(int)brekelJoint.waist].position_local.z;
}
}
// apply to transforms (cannot be done in FetchFrame, only in Update thread)
for (int bodyID = 0; bodyID < skeletons.GetLength(0); bodyID++)
{
for (int jointID = 0; jointID < skeletons[bodyID].joints.GetLength(0); jointID++)
{
// only apply if transform is defined
if (skeletons[bodyID].joints[jointID].transform != null)
{
// apply position only for waist joint
if (jointID == (int)brekelJoint.waist)
skeletons[bodyID].joints[jointID].transform.localPosition = skeletons[bodyID].joints[jointID].position_local;
// always apply rotation
skeletons[bodyID].joints[jointID].transform.localRotation = skeletons[bodyID].joints[jointID].rotation_local;
}
}
}
It appears you are using a Unity library but trying to run it as a standalone application?
This error means you are calling a method that is implemented within the Unity engine. You can only use the library from within Unity.
If you want to use it standalone, you'll need to compile the library without referencing any Unity libraries, which probably means you'll need to provide implementations for anything the library is using (such as MonoBehaviour
http://forum.unity3d.com/threads/c-error-ecall-methods-must-be-packaged-into-a-system-module.199361/
http://forum.unity3d.com/threads/security-exception-ecall-methods-must-be-packaged-into-a-system-module.98230/
Additionally,
If your only problem is Debug.Log() throwing an exception, you could use reflection to plant your own Logger instance instead of Unity's one.
Step 1: Create "MyLogHandler" that will do your actual logging(write to file or to console or do nothing). Your class needs to implement "ILogHandler" interface.
Step 2: Replace unity default one with new one.
var newLogger = new Logger(new MyLogHandler());
var fieldInfo = typeof(Debug).GetField("s_Logger", BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Static);
fieldInfo.SetValue(null, newLogger);
Note: Keep in mind that reflection accesses field by name and if Unity decide to change it in future, you will not get compile error - exception will be thrown in run-time.
I know this is old, but I came across a way to unit test Unity assemblies from within Visual Studio just by toggling a symbol definition from the Unity build settings. As long as you're OK with only being either able to either run tests or have the testable components usable in unity at one time, you can toggle unit testing mode and unity mode like this (images follow):
Make your unity component a partial class. Have one file where you declare that the partial class extends MonoBehaviour and put any stuff that has to actually use unity assemblies in there. This will not be tested by the unit tests but everything else will.
Use conditional compilation to make that file's contents only compile when a specific symbol is defined during the build. I used UNIT_TEST_NO_UNITY_INTEGRATION in my case.
When you want to run the unit tests from Visual Studio, update the build settings to define that symbol. This will exclude the Unity specific stuff from step 1 from the build and allow Visual Studio to be able to run your unit tests.
When you are finished testing, edit the build settings again and remove that symbol definition. Now your unit tests won't be able to run but your assemblies will work within Unity again.

How to close a file in Autocad using C# keeping acad.exe running?

I am using visual studio 2010 and I am having a .DWG file which I want to open in autocad. Till now I have used this.
Process p = new Process();
ProcessStartInfo s = new ProcessStartInfo("D:/Test File/" + fileName);
p.StartInfo = s;
p.Start();
But what I want is to close the file inside the Autocad but not the autocad itself. (Means atocad.exe should be kept running).
Till now I hve used this but its closing the acad.exe not the file.
foreach (Process Proc in Process.GetProcesses())
{
if (Proc.ProcessName.Equals("acad"))
{
Proc.CloseMainWindow();
Proc.Kill();
}
}
Take the Autocad .NET libraries from Autodesk Sites (http://usa.autodesk.com/adsk/servlet/index?id=773204&siteID=123112)
Then you will be able to use Application and Document classes.
They will give you full control over opening and closing documents within the application.
You can find many articles on that, and can ask further questions.
AutoCAD does have an api. there are 4 assemblys. Two for in-process and two for COM.
inprocess :
acdbmgd.dll
acmgd.dll
COMInterop :
Autodesk.Autocad.Interop.dll
Autodesk.Autocad.Interop.Common.dll
this is a method that will open a new instance of AutoCAD or it will connect to an existing running instance of AutoCAD.
you will need to load these .dlls into your project references.
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
namespace YourNameSpace {
public class YourClass {
AcadApplication AcApp;
private const string progID = "AutoCAD.Application.18.2";// this is AutoCAD 2012 program id
private string profileName = "<<Unnamed Profile>>";
private const string acadPath = #"C:\Program Files\Autodesk\AutoCAD 2012 - English\acad.exe";
public void GetAcApp()
{
try
{
AcApp = (AcadApplication)Marshal.GetActiveObject(progID);
} catch {
try {
var acadProcess = new Process();
acadProcess.StartInfo.Arguments = string.Format("/nologo /p \"{0}\"", profileName);
acadProcess.StartInfo.FileName = (#acadPath);
acadProcess.Start();
while(AcApp == null)
{
try { AcApp = (AcadApplication)Marshal.GetActiveObject(progID); }
catch { }
}
} catch(COMException) {
MessageBox.Show(String.Format("Cannot create object of type \"{0}\"",progID));
}
}
try {
int i = 0;
var appState = AcApp.GetAcadState();
while (!appState.IsQuiescent)
{
if(i == 120)
{
Application.Exit();
}
// Wait .25s
Thread.Sleep(250);
i++;
}
if(AcApp != null){
// set visibility
AcApp.Visible = true;
}
} catch (COMException err) {
if(err.ErrorCode.ToString() == "-2147417846"){
Thread.Sleep(5000);
}
}
}
}
}
closeing it is as simple as
Application.Exit();
and forgive the code. its atrocious, this was one of my first methods when i just started developing...
I doubt you will be able to do this unless AutoCAD has an API that you can hook into and ask it to close the file for you.
Your c# app can only do things to the process (acad.exe) , it doesn't have access to the internal operations of that process.
Also, you shouldn't use Kill unless the process has become unresponsive and certainly not immediately after CloseMainWindow.
CloseMainWindow is the polite way to ask an application to close itself. Kill is like pulling the power lead from the socket. You aren't giving it the chance to clean up after itself and exit cleanly.
There is one other possibility - this will only work if your C# code is running on the same machine as the AutoCAD process and it is not really recommended, but, if you are really stuck and are prepared to put up with the hassle of window switching you can send key strokes to an application using the SendKeys command.
MSDN articles here:
http://msdn.microsoft.com/EN-US/library/ms171548(v=VS.110,d=hv.2).aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx
Using this you could send the key strokes to simulate the user using the menu commands to close the file.
To perform the closing of file, best way out is to follow the steps at this ObjectARX SDK for c# and change the following code with the below code.
[CommandMethod("CD", CommandFlags.Session)]
static public void CloseDocuments()
{
DocumentCollection docs = Application.DocumentManager;
foreach (Document doc in docs)
{
// First cancel any running command
if (doc.CommandInProgress != "" &&
doc.CommandInProgress != "CD")
{
AcadDocument oDoc =
(AcadDocument)doc.AcadDocument;
oDoc.SendCommand("\x03\x03");
}
if (doc.IsReadOnly)
{
doc.CloseAndDiscard();
}
else
{
// Activate the document, so we can check DBMOD
if (docs.MdiActiveDocument != doc)
{
docs.MdiActiveDocument = doc;
}
int isModified =
System.Convert.ToInt32(
Application.GetSystemVariable("DBMOD")
);
// No need to save if not modified
if (isModified == 0)
{
doc.CloseAndDiscard();
}
else
{
// This may create documents in strange places
doc.CloseAndSave(doc.Name);
}
}
}

How to start an Amazon EC2 instance programmatically in .NET

I have been attempting to start an instance of EC2 in C# without luck.
When passing in an instance id to start the instance I get an error that the instance cannot be found despite that I am passing in an instance ID that I have obtained from the object property.
Amazon made huge efforts to integrate its AWS Cloud .Net SDK To VS2008 & VS 2010
1 - Download and Install the AWS SDK msi
2 - Create an AWS Console project, enter your credentials (available from your AWS Console under your login name menu on the top right corner)
3 - Add the following code (see below images).
4 - Your're done. It's very straightforward. You can check the programmatic start/stop success by refreshing your AWS Console Screen.
AmazonEC2 ec2 = AWSClientFactory.CreateAmazonEC2Client();
//Start Your Instance
ec2.StartInstances(new StartInstancesRequest().WithInstanceId("i-00000000"));
//Stop it
ec2.StopInstances(new StopInstancesRequest().WithInstanceId("i-00000000"));
You just need to replace "i-00000000" by your instance Id (available in your AWS Management Console)
Hope this helps those googling this and stumbling upon this question (as I did myself) start off quickly. Following these simple steps via these wizards will spare you considerable headaches.
Try something like this with the AWSSDK to start new instances of an "image id":
RunInstancesResponse response = Client.RunInstances(new RunInstancesRequest()
.WithImageId(ami_id)
.WithInstanceType(instance_type)
.WithKeyName(YOUR_KEYPAIR_NAME)
.WithMinCount(1)
.WithMaxCount(max_number_of_instances)
.WithUserData(Convert.ToBase64String(Encoding.UTF8.GetBytes(bootScript.Replace("\r", ""))))
);
(Note: The .WithUserData() is optional and is used above to pass a short shell script.)
If the call is successful the response should contain a list of instances. You can use something like this to create a list of "instance ids":
if (response.IsSetRunInstancesResult() && response.RunInstancesResult.IsSetReservation() && response.RunInstancesResult.Reservation.IsSetRunningInstance())
{
List<string> instance_ids = new List<string>();
foreach (RunningInstance ri in response.RunInstancesResult.Reservation.RunningInstance)
{
instance_ids.Add(ri.InstanceId);
}
// do something with instance_ids
...
}
Be mindful that Amazon AWS instances exist only in one region. If your instance id i-12345 is in the EU-West-1 region, and you just make a new EC2Client and tell the client to start i-12345 it may well complain that it cannot find that instance, because the client started up in the us-east-1 region, which does not have i-12345 instance.
Your call that creates the client should specify the region, if it is not the default region (I've no idea which AWS region is default, so I specify every time):
AmazonEC2 ec2 = AWSClientFactory.CreateAmazonEC2Client(
new Amazon.EC2.AmazonEC2Config().WithServiceURL("https://eu-west-1.ec2.amazonaws.com")
);
Ok, this is the FULL, end-to-end instructions.
1. Install AWSSDK.Core and AWSSDK.EC2 using Nuget Package Manager.
2. Then copy this whole class to your project. AccessKey and Secret are obtained in AWS IAM. You will need to ensure the user you create has "AmazonEC2FullAccess" (You can probably use a lower-level permission policy, I am just lazy here :D). region is your AW S EC2 instance region. and Instance ID can be found in the EC2 dashboard list. Simple, works perfectly... You can also write extra code to manage the response object.
3. Be mindful if you are behind a proxy, you will have to configure it (I havent included code here).
public class AWSClass : IDisposable
{
Amazon.EC2.AmazonEC2Client _client;
public AWSClass(string region, string AccessKey, string Secret)
{
RegionEndpoint EndPoint = RegionEndpoint.GetBySystemName(region);
Amazon.Runtime.BasicAWSCredentials Credentials = new Amazon.Runtime.BasicAWSCredentials(AccessKey, Secret);
_client = new AmazonEC2Client(Credentials, EndPoint);
}
public void Dispose()
{
_client = null;
}
public void StopInstance(string InstanceID)
{
StopInstancesResponse response = _client.StopInstances(new StopInstancesRequest
{
InstanceIds = new List<string> {InstanceID }
});
//Can also do something with the response object too
}
public void StartInstance(string InstanceID)
{
StartInstancesResponse response = _client.StartInstances(new StartInstancesRequest
{
InstanceIds = new List<string> { InstanceID }
});
}
}
try this.
var startRequest = new StartInstancesRequest
{
InstanceIds = new List<string>() { instanceId }
};
bool isError = true;
StartInstancesResponse startInstancesResponse = null;
while (isError)
{
try
{
startInstancesResponse=amazonEc2client.StartInstances(startRequest);
isError = false;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
isError = true;
}
}

Categories

Resources