How to access WinRM in C# - c#

I'd like to create a small application that can collect system information (Win32_blablabla) using WinRM as opposed to WMI. How can i do that from C#?
The main goal is to use WS-Man (WinRm) as opposed to DCOM (WMI).

I guess the easiest way would be to use WSMAN automation. Reference wsmauto.dll from windwos\system32 in your project:
then, code below should work for you. API description is here: msdn: WinRM C++ API
IWSMan wsman = new WSManClass();
IWSManConnectionOptions options = (IWSManConnectionOptions)wsman.CreateConnectionOptions();
if (options != null)
{
try
{
// options.UserName = ???;
// options.Password = ???;
IWSManSession session = (IWSManSession)wsman.CreateSession("http://<your_server_name>/wsman", 0, options);
if (session != null)
{
try
{
// retrieve the Win32_Service xml representation
var reply = session.Get("http://schemas.microsoft.com/wbem/wsman/1/wmi/root/cimv2/Win32_Service?Name=winmgmt", 0);
// parse xml and dump service name and description
var doc = new XmlDocument();
doc.LoadXml(reply);
foreach (var elementName in new string[] { "p:Caption", "p:Description" })
{
var node = doc.GetElementsByTagName(elementName)[0];
if (node != null) Console.WriteLine(node.InnerText);
}
}
finally
{
Marshal.ReleaseComObject(session);
}
}
}
finally
{
Marshal.ReleaseComObject(options);
}
}
hope this helps, regards

I've got an article that describes an easy way to run Powershell through WinRM from .NET at http://getthinktank.com/2015/06/22/naos-winrm-windows-remote-management-through-net/.
The code is in a single file if you want to just copy it and it's also a NuGet package that includes the reference to System.Management.Automation.
It auto manages trusted hosts, can run script blocks, and also send files (which isn't really supported but I created a work around). The returns are always the raw objects from Powershell.
// this is the entrypoint to interact with the system (interfaced for testing).
var machineManager = new MachineManager(
"10.0.0.1",
"Administrator",
MachineManager.ConvertStringToSecureString("xxx"),
true);
// will perform a user initiated reboot.
machineManager.Reboot();
// can run random script blocks WITH parameters.
var fileObjects = machineManager.RunScript(
"{ param($path) ls $path }",
new[] { #"C:\PathToList" });
// can transfer files to the remote server (over WinRM's protocol!).
var localFilePath = #"D:\Temp\BigFileLocal.nupkg";
var fileBytes = File.ReadAllBytes(localFilePath);
var remoteFilePath = #"D:\Temp\BigFileRemote.nupkg";
machineManager.SendFile(remoteFilePath, fileBytes);
Hope this helps, I've been using this for a while with my automated deployments. Please leave comments if you find issues.

I would like to note that this shows an interop error by default in Visual Studio 2010.
c.f. http://blogs.msdn.com/b/mshneer/archive/2009/12/07/interop-type-xxx-cannot-be-embedded-use-the-applicable-interface-instead.aspx
There appear to be two ways to solve this. This first is documented in the article listed above and appears to be the correct way to handle the problem. The pertinent changes for this example is:
WSMan wsManObject = new WSMan();
This is in lieu of IWSMan wsman = new WSManClass(); which will throw the error.
The second resolution is to go to the VS2010—>Solution Explorer—>Solution—>Project—>References and select WSManAutomation. Right click or hit Alt-Enter to access the properties. Change the value of the "Embed Interop Types" property of the wsmauto reference.

Related

Fetching more than 1000 rows from Domino LDAP server using .NET Core 5 and Novell.Directory.Ldap.NETStandard

I want to fetch all the users from a large location of our Domino LDAP, around ~2000 users altogether. Since .NET Core sadly doesn't have a platform independent LDAP library, I'm using Novell.Directory.Ldap.NETStandard with this POC:
var cn = new Novell.Directory.Ldap.LdapConnection();
cn.Connect("dc.internal", 389);
cn.Bind("user", "pw");
string filter = "location=MyLoc";
var result = cn.Search("", Novell.Directory.Ldap.LdapConnection.ScopeOne, filter, new string[] { Novell.Directory.Ldap.LdapConnection.AllUserAttrs }, typesOnly: false);
int count = 0;
while (result.HasMore()) {
var entry = result.Next();
count++;
Console.WriteLine(entry.Dn);
}
It prints me a lot of entries, but not all. When count = 1000 I got an Size Limit Exceeded exception. I guess this is because I need to use some kind of pagination, so not all entries woult be returned in a single request. There are different questions like this or this one. Both in Java, the .NET Core API seems somehow different.
Approach 1: Try to find out how LdapSearchRequest works in .NET Core
byte[] resumeCookie = null;
LdapMessageQueue queue = null;
var searchReq = new LdapSearchRequest("", LdapConnection.ScopeOne, filter, new string[] { LdapConnection.AllUserAttrs },
LdapSearchConstraints.DerefNever, maxResults: 3000, serverTimeLimit: 0, typesOnly: false, new LdapControl[] { new SimplePagedResultsControl(size: 100, resumeCookie) });
var searchRequest = cn.SendRequest(searchReq, queue);
I'm trying to figure out how the Java examples can be used in .NET Core. This looks good, however I can't figure out how to fetch the LDAP entries. I only get an message id. By looking into the source it seems that I'm on the right way, but they're using MessageAgent which cannot be used outside since it's internal sealed. This is propably the reason why searching for LdapRearchRequest in the source code doesn't give many results.
Approach 2: Using SimplePagedResultsControlHandler
var opts = new SearchOptions("", LdapConnection.ScopeOne, filter, new string[] { LdapConnection.AllUserAttrs });
// For testing purpose: https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard/issues/163
cn.SearchConstraints.ReferralFollowing = false;
var pageControlHandler = new SimplePagedResultsControlHandler(cn);
var rows = pageControlHandler.SearchWithSimplePaging(opts, pageSize: 100);
This throws a Unavaliable Cricital Extension exception. First I thought that this is an issue of the .NET port, which may doesn't support all the features of the original Java library yet. It seems complete and according to further researches, it looks like to be an LDAP error code. So this must be something which has to be supported by the server, but is not supported by Domino.
I couldn't make at least one of those approachs work, but found another way: Cross platform support for the System.DirectoryServices.Protocols namespace was was added in .NET 5. This was missing for a long time in .NET Core and I guess this is the main reason why libraries like Novell.Directory.Ldap.NETStandard were ported to .NET Core - in times of .NET Core 1.x this was the only way I found to authenticate against LDAP wich works on Linux too.
After having a deeper look into System.DirectoryServices.Protocols, it works well out of the box, even for ~2k users. My basic POC class looks like this:
public class DominoLdapManager {
LdapConnection cn = null;
public DominoLdapManager(string ldapHost, int ldapPort, string ldapBindUser, string ldapBindPassword) {
var server = new LdapDirectoryIdentifier(ldapHost, ldapPort);
var credentials = new NetworkCredential(ldapBindUser, ldapBindPassword);
cn = new LdapConnection(server);
cn.AuthType = AuthType.Basic;
cn.Bind(credentials);
}
public IEnumerable<DominoUser> Search(string filter, string searchBase = "") {
string[] attributes = { "cn", "mail", "companyname", "location" };
var req = new SearchRequest(searchBase, filter, SearchScope.Subtree, attributes);
var resp = (SearchResponse)cn.SendRequest(req);
foreach (SearchResultEntry entry in resp.Entries) {
var user = new DominoUser() {
Name = GetStringAttribute(entry, "cn"),
Mail = GetStringAttribute(entry, "mail"),
Company = GetStringAttribute(entry, "companyname"),
Location = GetStringAttribute(entry, "location")
};
yield return user;
}
yield break;
}
string GetStringAttribute(SearchResultEntry entry, string key) {
if (!entry.Attributes.Contains(key)) {
return string.Empty;
}
string[] rawVal = (string[])entry.Attributes[key].GetValues(typeof(string));
return rawVal[0];
}
}
Example usage:
var ldapManager = new DominoLdapManager("ldap.host", 389, "binduser", "pw");
var users = ldapManager.Search("objectClass=person");
But it's not solved with Novell.Directory.Ldap.NETStandard as the title said
This doesn't solve my problem with the Novell.Directory.Ldap.NETStandard library as the title suggested, yes. But since System.DirectoryServices.Protocols is a official .NET package maintained by Microsoft and the .NET foundation, this seems the better aproach for me. The foundation will take care to keep it maintained and compatible with further .NET releases. When I wrote the question, I was not aware of the fact that Linux support is added now.
Don't get me wrong, I don't want to say that third packages are bad by design - that would be completely wrong. However, when I have the choice between a official package and a third party one, I think it makes sense to prefer the official one. Except there would be a good reason against that - which is not the case here: The official package (which doesn't exist in the past) works better to solve this issue than the third party one.

How to use Google Cloud Speech (V1 API) for speech to text - need to be able to process over 3 hours audio files properly and efficiently

I am looking for documentation and stuff but could not find a solution yet
Installed NuGet package
Also generated API key
However can't find proper documentation how to use API key
Moreover, I want to be able to upload very long audio files
So what would be the proper way to upload up to 3 hours audio files and get their results?
I have 300$ budget so should be enough
Here my so far code
This code currently fails since I have not set the credentials correctly at the moment which I don't know how to
I also have service account file ready to use
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var speech = SpeechClient.Create();
var config = new RecognitionConfig
{
Encoding = RecognitionConfig.Types.AudioEncoding.Flac,
SampleRateHertz = 48000,
LanguageCode = LanguageCodes.English.UnitedStates
};
var audio = RecognitionAudio.FromStorageUri("1m.flac");
var response = speech.Recognize(config, audio);
foreach (var result in response.Results)
{
foreach (var alternative in result.Alternatives)
{
Debug.WriteLine(alternative.Transcript);
}
}
}
}
I don't want to set environment variable. I have both API key and Service Account json file. How can I manually set?
You need to use the SpeechClientBuilder to create a SpeechClient with custom credentials, if you don't want to use the environment variable. Assuming you've got a service account file somewhere, change this:
var speech = SpeechClient.Create();
to this:
var speech = new SpeechClientBuilder
{
CredentialsPath = "/path/to/your/file"
}.Build();
Note that to perform a long-running recognition operation, you should also use the LongRunningRecognize method - I strongly suspect your current RPC will fail, either explicitly because it's trying to run on a file that's too large, or it'll just time out.
You need to set the environment variable before create the instance of Speech:
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "text-tospeech.json");
Where the second param (text-tospeech.json) is your file with credentials generated by Google Api.

AWS Machine Learning RealTimePredictor returns UnknownoperationException in C#

Using Visual Studio, and AWS .NET V 3.0.
I'm trying to perform a real-time Predict operation, and to verify the basic setup works, I first perform a GetMLModel() which works and returns the endpoint (Somewhere in the documentation is was mentioned to use that result as the service endpoint, but it's the same that is listed in the console). Is has status "READY", so far so good.
The exception occurs below on the line below "Prediction P = RTP.Predict(Data)". Data contains a Dictionary with all the prediction values.
Error: Error making request with Error Code UnknownOperationException and Http Status Code BadRequest. No further error information was returned by the service.
public static APIResult GetRealTimePrediction(Dictionary<string, string> Data, string PayloadJSON = null) {
AmazonMachineLearningConfig MLConfig = new AmazonMachineLearningConfig();
MLConfig.RegionEndpoint = Amazon.RegionEndpoint.USEast1;
MLConfig.Validate();
AmazonMachineLearningClient MLClient = new AmazonMachineLearningClient("xxx", "xxx", MLConfig);
GetMLModelResponse MLMOdelResp = MLClient.GetMLModel("xxx"); // <-- WORKS
MLConfig.ServiceURL = MLMOdelResp.EndpointInfo.EndpointUrl;
Console.WriteLine(MLConfig.ServiceURL);
MLConfig.Validate();
Amazon.MachineLearning.Util.RealtimePredictor RTP = new Amazon.MachineLearning.Util.RealtimePredictor(MLClient, "xxx");
Prediction P = RTP.Predict(Data); // <----------------EXCEPTION HERE
}
(Obviously replace xxx with relevant values) :)
It turns out that this line:
MLConfig.ServiceURL = MLMOdelResp.EndpointInfo.EndpointUrl;
cases the MLConfig.RegionEndpoint to be reset. Even though the documentation indicates the RegionEndpoint can be determined from the ServiceURL (I'm pretty sure I read that), the RegionEndpoint needs to be set again before the RTP.Predict(Data) call.
Once I figured that out, I was able to reduce the code to just this, in case anyone else needs help. I guess adding too much information to the Configuration is NOT a good thing, as the AWS. NET library seems to figure all this out on its own.
public static APIResult GetRealTimePrediction(Dictionary<string, string> Data, string PayloadJSON = null) {
AmazonMachineLearningConfig MLConfig = new AmazonMachineLearningConfig();
MLConfig.RegionEndpoint = Amazon.RegionEndpoint.USEast1;
MLConfig.Validate(); // Just in case, not really needed
AmazonMachineLearningClient MLClient = new AmazonMachineLearningClient("xxx", "xxx", MLConfig);
Amazon.MachineLearning.Util.RealtimePredictor RTP = new Amazon.MachineLearning.Util.RealtimePredictor(MLClient, "xxx");
Prediction P = RTP.Predict(Data);
}

LibGit2Sharp 1 conflict prevent from checkout

I currently have the problem, that my application using libgit2sharp always crashs witht the message:
1 conflict prevents from checkout
when trying to call repo.Pull
The curious thing is, if i print the status of the local repository, their are no changes in the repository.
I even tried resetting the repository at first, or checking the files out, but nothing helps. This is my code:
using (LibGit2Sharp.Repository repo = new LibGit2Sharp.Repository(path))
{
var tipId = repo.Head.Tip.Tree;
Log.LogManagerInstance.Instance.Info("HEAD tree id: " + tipId.Id.ToString());
// Pull changes
PullOptions options = new PullOptions();
options.FetchOptions = new FetchOptions();
options.MergeOptions = new MergeOptions();
// ! Only for trying to fix the bug. Should not be here
options.MergeOptions.FileConflictStrategy = CheckoutFileConflictStrategy.Theirs;
repo.Reset(repo.Head.Tip);
// ! --
options.FetchOptions.CredentialsProvider = CredentialsHandler;
Log.LogManagerInstance.Instance.Info("Try pull from remote repository");
// Pull changes from network
var result = repo.Network.Pull(new LibGit2Sharp.Signature(username, mail, new DateTimeOffset(DateTime.Now)), options);
if (result != null && result.Commit != null)
{
Log.LogManagerInstance.Instance.Info("Pulled from remote branch, new tree id: " + result.Commit.Tree.Id.ToString());
// get difference in the git tree (file-system)
var diffs = repo.Diff.Compare<TreeChanges>(tipId, result.Commit.Tree);
MergeTreeChangesToDatabase(diffs, path);
}
else
{
Log.LogManagerInstance.Instance.Info("Local repository is up-to-date with the remote branch");
}
}
Thank you very much.
EDIT
Using the pre release 0.22 seems to solve my problem.
The Version 0.22 fix all problems.

Invalid type(s) error while publishing Activity to WorkflowManager

I've installed Worfklow Manger 1.0. I can use WorkflowManagerClient to browse scopes. But when I try to publish activity I get this error:
System.InvalidOperationException: Microsoft.Workflow.Client.ActivityValidationException: Workflow XAML failed validation due to the following errors: Invalid type(s) 'System.Activities.Expressions.AssemblyReference'.
Activity is an empty activity created from template in VS. There is no custom types used in it. I've found this post and I quess I could create AllowedTypes.xml file but it feels wierd to add types that are used in base empty activity - basically system types (System.Activities.Expressions.AssemblyReference).
Do I need to create allowdtypes file and put System.Activities.Expressions.AssemblyReference as one type ? Did anyone have to do that ?
Edit:
Other types that caus the same error are:
Microsoft.CSharp.Activities.CSharpReference`1
Microsoft.CSharp.Activities.CSharpValue`1
So it turns out that I should've used ExpressionTranslator to translade all activities before publish.
The translation is a step in process of publishing of the Workflow in Workflow Manager. it basically translates all expressions in Workflow Activities in a form
required by XAML, before the workflow is published (installed) to the host.
I've used Workflow Manager tutorial Translate method:
public static XElement Translate(string xamlFile)
{
string translatedWorkflowString = null;
using (XamlReader xamlReader = new XamlXmlReader(xamlFile))
{
TranslationResults result = ExpressionTranslator.Translate(xamlReader);
if (result.Errors.Count == 0)
{
StringBuilder sb = new StringBuilder();
using (XmlWriter xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }))
{
using (XamlXmlWriter writer = new XamlXmlWriter(xmlWriter, result.Output.SchemaContext))
{
XamlServices.Transform(result.Output, writer);
}
}
translatedWorkflowString = sb.ToString();
}
else
{
throw new InvalidOperationException("Translation errors");
}
}
return XElement.Parse(translatedWorkflowString);
}
I don't know if it is too late, but I was having the same issue even with the latest SharePoint Server 2013 upgrade.
What I did is to compare the "workflow.xaml" file from a SharePoint Designer workflow (after having saved it as a template into the Site Assets library) with the "workflow.xaml" generated from within Visual Studio 2013. What I found and what resolved my issue is to add these two attributes as a part of the Activity element.
xmlns:local
="clr-namespace:Microsoft.SharePoint.WorkflowServices.Activities"
xmlns:mwaw
="clr-namespace:Microsoft.Web.Authoring.Workflow;assembly=Microsoft.Web.Authoring"

Categories