I use Invoke-ASCmd in PowerShell right now to create a database in SQL Server, like this:
Invoke-ascmd -Query $MyScript -Server $ASServer
Where $MyScript is a string holding the contents of an .xmla file that I read in previously.
This works great. Now I need to do something similar in C#, but am unable to find a simple solution like the one that exists in PowerShell.
I see some people using a Microsoft DLL called Microsoft.AnalysisServices.XMLA.dll, but it's not supported, and the class in question is "internal", so I can't even reference it.
I found this DLL Microsoft.AnalysisServices.AdomdClient.dll while searching around, but don't see any of the classes being relevant to what I need: https://learn.microsoft.com/en-us/dotnet/api/microsoft.analysisservices.adomdclient?view=analysisservices-dotnet
using Microsoft.AnalysisServices.AdomdClient;
try
{
var xmlaFileContents = File.ReadAllText("path/to/your/file.xmla");
using (AdomdCommand cmd = conn.CreateCommand())
{
cmd.CommandText = xmlaFileContents;
cmd.ExecuteNoQuery();
}
}
catch(Exception)
{
}
** please note that I have not run this code **
As the AdomdConnection is inherited from IDbConnection, it's pretty similar to how the SqlConnection works, and therefor, similar syntax can be used, as #jogi presented for you.
I wrote a PS function a few years back which we use in TFS builds. It uses the .NET assemblies rather than the PS layer, so I figured since you seem savvy in PS, you can perhaps get something out of it. Still essentially the same as what #jogi wrote, only wrapped in PS.
function Invoke-XmlaScript {
[CmdletBinding()] param (
[Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$ServerInstance,
[Parameter(Mandatory=$true)][ValidateNotNullOrEmpty()][string]$XmlaScript
)
process {
$connection = New-Object Microsoft.AnalysisServices.AdomdClient.AdomdConnection("Data Source=$ServerInstance;Provider=MSOLAP.4;Integrated Security=SSPI;Impersonation Level=Impersonate;")
$connection.Open()
try {
$command = $connection.CreateCommand()
$command.CommandTimeout = 20000
$command.CommandType = [System.Data.CommandType]::Text
$command.CommandText = $Xmla
$reader = $command.ExecuteXmlReader()
if($reader.Read()) {
Write-Output $reader.ReadOuterXml()
}
}
catch { }
$connection.Dispose()
}
}
Related
Is there a way to find functions that were imported into an InitialSessionState using ImportPSModule()?
I have this wrapper around PowerShell to run scripts self-hosted by my applicaton (comments and error checking removed for brevity)
public class Engine
{
private readonly InitialSessionState sessionState;
public Engine(string initializationModulePath)
{
this.sessionState = InitialSessionState.CreateDefault();
this.sessionState.LanguageMode = PSLanguageMode.FullLanguage;
this.sessionState.AuthorizationManager = null;
// New functionality - allow an initialization file.
this.sessionState.ImportPSModule(new[] { initializationModulePath });
}
public void AddCommand(String name, Type implementingType) => this.sessionState.Commands.Add(
new SessionStateCmdletEntry(
name,
implementingType,
null));
public void RunScript(string script, string scriptComment)
{
using (PowerShell powerShellCommand = PowerShell.Create())
{
powerShellCommand.AddScript(script);
using (powerShellCommand.Runspace = RunspaceFactory.CreateRunspace(this.sessionState))
{
powerShellCommand.Runspace.Open();
Collection<PSObject> results = powerShellCommand.Invoke();
// Results processing omitted.
}
}
}
// Testing - I see things added via AddCommand() but not anything imported via ImportPSModule
public void ListCommands()
{
foreach (SessionStateCommandEntry commandEntry in this.sessionState.Commands)
{
Console.WriteLine($"Command: {commandEntry.Name}, Type: {commandEntry.CommandType}");
}
}
}
When I add types using engine.AddCommand(), they show up in engine.ListCommands() as expected. I now want to allow users to have a custom set of functions they've predefine which I'll import via ImportPSModule(). Finally, I'd like to be able to list out those commands in the UI as commands that are available.
I created a really simple module (init.psm1)
function Add-Number {[CmdletBinding()] param ([int]$a, [int]$b) $a + $b }
function Subtract-Number {[CmdletBinding()] param ([int]$a, [int]$b) $a - $b }
and tested importing it, but the functions don't show up as available commands. (Though user scripts can use them just fine.)
I looked at System.Management.Automation.Language.Parser.ParseFile based on this question and could check for tokens after {function}, but it seems like a round-about way to do it. (Currently, this is the best option I have.)
I considered running a little script with Get-ChildItem function:, but Get-ChildItem is not available when using InitialSessionState.CreateDefault() (I do not want to use InitialSessionState.Create(). My scenario requires the engine to be more locked down than that.)
Is there another option I can use to get the list of user-defined functions? Importing them in another manner is acceptable so long as users can provide them as powershell code.
Thanks!
Edit
Re-reading the documentation, it seems I had missed this very important line:
Add a list of modules to import when the runspace is created.
So I'll update the question a little to be "Is there an way to create a SessionStateCommandEntry() from a script file that can be added to initialSessionState.Commands?"
I am currently calling the following com object using Powershell but am having trouble converting the code over to c#. I know this should be pretty straightforward and may be a dumb question, so I apologize if I look like a moron.
Powershell:
$nDeviceId=517
$wug = New-Object -ComObject CoreAsp.EventHelper
$wug.SendChangeEvent(2,$nDeviceId,1)
Current C# Attempt:
Type type = TypeDelegator.GetTypeFromProgID("CoreAsp.EventHelper");
Object application = Activator.CreateInstance(type);
pplication.GetType().InvokeMember("SendChangeEvent", BindingFlags.InvokeMethod, null, application, new object[]{2,517,1});
I appreciate any help!
Update:
When I run the c# code I do not receive any errors.
If you're using .NET 4 and don't mind late-binding (no intellisense, ...), you could use a dynamic object:
Type type = Type.GetTypeFromProgID("CoreAsp.EventHelper");
dynamic application = Activator.CreateInstance(type);
application.SendChangeEvent(...);
I'm not familiar with that COM-object, but in general COM-components are accessed by adding them as a reference in your c# project (select the com-tab in the add reference-dialog) and by using the classes they provide.
Best way to access COM objects from C#
Working off of Frode's answer, I found a DLL named CoreASP.dll and tried to import this into my project but received an error that the library was invalid.
I was able to use the "Type Library Importer" tool in visual studio to convert the COM type library into equivalent definitions.
command: tlbimp.exe CoreAsp.dll\1
This created another DLL "CoreAspiLib.dll" that I was able to import into my Visual Studio project.
Thank you Frode for leading me in the right direction.
Update:
So this method SOMETIMES works, it seems like I would have to call the command 3-4 times to get it to work as expected. To avoid the headache I ended up calling powershell from c#, making sure to hold the runspace open so that I don't have to reload it for subsequent commands (I may be calling this function 50+ times per minute).
Example of calling the script 1000 times:
Runspace runspace = RunspaceFactory.CreateRunspace();
string scriptText =
"$wug = New-Object -ComObject CoreAsp.EventHelper;" +
"$wug.SendChangeEvent(2,519,1)";
runspace.Open();
for (int x = 0; x < 1000; x++)
{
Console.WriteLine("Running Event "+(x+1).ToString());
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(scriptText);
pipeline.Commands.Add("Out-String");
pipeline.Invoke();
Thread.Sleep(1000);
}
runspace.Close();
This seems to work 100% of the time.
Joe I also tried your method and ended up with the same result as my first test, no errors but the function did not run as expected.
I was wondering if there is an online tool that can convert c# code to powershell cmdlet code. I have following code that i need to have it powershell. I dont have visual studio to turn this into an exe or dll. any help or ideas would be great.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
namespace CopyUsersBetweenGroupsInSharepointByRR
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("This tool will copy the users from one group to another group");
Console.WriteLine("Please enter the URL of the site where your groups are available");
String siteUrl = Console.ReadLine();
using (SPSite site = new SPSite(siteUrl))
{
try
{
SPWeb web = site.OpenWeb();
Console.WriteLine("Please enter the name of the source group");
String sourceGroupName = Console.ReadLine();
Console.WriteLine("Please enter the name of the destination group");
String destinationGroupName = Console.ReadLine();
SPGroup sourceGroup = web.Groups[sourceGroupName];
SPGroup destinationGroup = web.Groups[destinationGroupName];
SPUserCollection sourceUsers = sourceGroup.Users;
SPUserInfo[] sourceUserInfoArray = new SPUserInfo[sourceUsers.Count];
for (int i = 0; i < sourceUsers.Count; i++)
{
sourceUserInfoArray[i] = new SPUserInfo();
sourceUserInfoArray[i].LoginName = sourceUsers[i].LoginName;
sourceUserInfoArray[i].Name = sourceUsers[i].Name;
}
destinationGroup.Users.AddCollection(sourceUserInfoArray);
destinationGroup.Update();
web.Update();
Console.WriteLine("Operation Completed Successfully");
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadLine();
}
}
}
}
}
It's comments like those above that are turning people away from SO in droves. The OP's question was unambiguous and displayed genuine need.
There are several ways to achieve this. Rewriting your entire C# code repository is not one of them.
As already discussed, as of PS 2 you are able to either run C# (or most any other language) inline, or refer to well-formed external file. I've had mixed success with this and I don't believe it's what the OP was really after.
If you genuinely want to convert code (particularly compiled assemblies) then a decompiler like Reflector is able to do this and - with the PowerShell addon - is also able to convert it on-the-fly.
http://blog.lekman.com/2011/10/converting-c-to-powershell.html
If you want your input and output to take place within the PS console then you'd still have to perform some obvious re-writes. But this method has proved incredibly useful to me.
The fastest way to do it is to write the PowerShell code yourself.
Below is how the code will look in PowerShell, i would say that most C# developers should be able to grasp the concepts of converting C# code to PowerShell in a very short time.
Functions can be a little odd at the beginning, since the usual PS syntax is
myFunction Parameter1 Parameter2
Also you really should install PowerShell 3.0 and use the Windows PowerShell ISE tool to develop the code.
Anyways it should not take you more than 1-2 hours to get your C# code running along in PowerShell.
[System.Reflection.Assembly]::LoadWithPartialName(”Microsoft.SharePoint”)
Write-Host "This tool will copy the users from one group to another group"
Write-Host "Please enter the URL of the site where your groups are available"
[string] $siteUrl = [Console]::ReadLine()
$site = new-object Microsoft.SharePoint.SPSite($siteUrl)
try
{
$web = $site.OpenWeb()
Write-Host "Please enter the name of the source group"
[string] $sourceGroupName = [Console]::ReadLine()
Write-Host "Please enter the name of the destination group"
[string] $destinationGroupName = [Console]::ReadLine()
$sourceUsers = $web.Groups[$sourceGroupName]
(and so on)
}
catch
{
Write-Error ("Failed to copy sharepoint users." + $_)
}
I doubt there is anything remotely like that, however Visual Studio is not required to compile c# code. You could compile an exe without VS. The compiler (csc.exe) and msbuild are included as part of framework. They are located in C:\Windows\Microsoft.NET\Framework\{version}.
If you really want to call this from powershell, have a look at the Add-Type cmdlet. You provide it the source code and it will compile the source on the fly, then load the assembly into your session.
Not sure about online tools, but download the free Visual Studio Express & follow this tutorial should have you creating a cmdlet in no time
Is it possible to retrieve data from chrome/firefox local storage using C#?
Disclaimer: I have tested this on my Windows 7 x64 running Google Chrome 13.0.782.220 at the moment. The information provided here is a result of my own research and is not any official way or API to retrieve this information. Use at your own risk. Also the technique presented here might break with any future release if Chrome changes the way to store this information.
So, Google Chrome uses SQLite to persist local storage data. You could use the System.Data.SQLite managed driver to read it from your .NET application. If you are running on Windows 7 (don't know for others as that's the one I have and can test), you will have the following folder:
c:\Users\SOMEUSERNAME\AppData\Local\Google\Chrome\User Data\Default\Local Storage\
This folder will contain multiple files with the .localstorage extension. Each file is for different site. For example for StackOverflow I have http_stackoverflow.com_0.localstorage but of course this naming is totally arbitrary and you cannot rely upon it. Each file represents a SQLite database.
I have noticed that this database contains a table called ItemTable with 2 string columns called key and value.
So to read the values it's a simple matter of sending a SQL query:
class Program
{
static void Main()
{
using (var conn = new SQLiteConnection("Data Source=http_stackoverflow.com_0.localstorage;Version=3;"))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "SELECT key, value FROM ItemTable";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine(
"key: {0}, value: {1}",
reader.GetString(reader.GetOrdinal("key")),
reader.GetString(reader.GetOrdinal("value"))
);
}
}
}
}
}
When using Chromium Embedded Framework I found that the above solution has many limitations. It seems like Chromium have moved to using leveldb instead.
I ended up with a solution where I inject JS code that modify local storage in FrameLoadStart. (it should be easy to read values as well - JavascriptResponse.Result can be casted to a IDictionary when using this script: "window.localStorage;" instead)
// writing local storage in FrameLoadStart
foreach (var entry in LocalStorage)
{
script += $"window.localStorage.{entry.Key} = '{entry.Value}';";
}
IFrame frame = chromeBrowser.GetMainFrame();
var result = await frame.EvaluateScriptAsync(script , frame.Url, 0);
if(!result.Success)
{
throw new Exception(result.Message);
}
How to delete a file from a SFTP server using Tamir Gal's SharpSSH? I have been able to accomplish other functionality but deletion.
The SshExec class didn't work for me, but a little Reflection magic worked:
var prop = sftp.GetType().GetProperty("SftpChannel", BindingFlags.NonPublic | BindingFlags.Instance);
var methodInfo = prop.GetGetMethod(true);
var sftpChannel = methodInfo.Invoke(sftp, null);
((ChannelSftp) sftpChannel).rm(ftpPath);
To accomplish this you will need to modify the SharpSSH assembly to expose the functionality you require.
Obtain the source code and open $\SharpSSH-1.1.1.13.src\SharpSSH\Sftp.cs
Insert the following lines of code before the end of the class:
public void Delete(string path)
{
SftpChannel.rm(path);
}
Recompile and reference the recompiled DLL in your project. You will now be able to delete files on the SFTP server.
Well you can also use SshExec class and then execute the "rm" command using "RunCommand" method. This way you wont have to recompile and build a new dll.
Using Tamir's dll I would suggest to delete using the below code. In this way, you need not modify Tamir's dll, whereas the below code can be written in your class.
string fromFile = "/a/b/MyFile.txt"
SshExec se = new SshExec(host, username, password);
se.Connect(port);
se.RunCommand("rm " + fromFile);