C# Powershell Pipeline Import Module not working - c#

I am trying to import a Lync module to automatically send a message to a user. my Powershell script is pretty straight forward.
Powershell
$assemblyPath = “C:\Program Files (x86)\Microsoft Office 2013\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Model.DLL”
Import-Module $assemblyPath
$IMType = 1
$PlainText = 0
$cl = [Microsoft.Lync.Model.LyncClient]::GetClient()
$conv = $cl.ConversationManager.AddConversation()
$username = “USER#DOMAIN.com”
$getuser = $cl.ContactManager.GetContactByUri($username)
$null = $conv.AddParticipant($getuser)
$msg = New-Object “System.Collections.Generic.Dictionary[Microsoft.Lync.Model.Conversation.InstantMessageContentType,String]”
$msg.Add($PlainText, “Assistance needed”)
$m = $conv.Modalities[$IMType]
$null = $m.BeginSendMessage($msg, $null, $msg)
And it works flawlessly in Powershell. However when i throw it into C# its failing saying it cannot find the Module.
C#
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.Add("Import-Module \"C:\\Program Files(x86)\\Microsoft Office 2013\\LyncSDK\\Assemblies\\Desktop\\Microsoft.Lync.Model.dll\"");
pipeline.Commands.Add("$IMType = 1 ");
pipeline.Commands.Add("$PlainText = 0 ");
pipeline.Commands.Add("$cl = [Microsoft.Lync.Model.LyncClient]::GetClient() ");
pipeline.Commands.Add("$conv = $cl.ConversationManager.AddConversation() ");
pipeline.Commands.Add("$username = \"USER#DOMAIN.com"\" ");
pipeline.Commands.Add("$getuser = $cl.ContactManager.GetContactByUri($username) ");
pipeline.Commands.Add("$null = $conv.AddParticipant($getuser) ");
pipeline.Commands.Add("$msg = New-Object \"System.Collections.Generic.Dictionary[Microsoft.Lync.Model.Conversation.InstantMessageContentType, String]\" ");
pipeline.Commands.Add("$msg.Add($PlainText, \"Assistance needed with the Virtual Fitting Kiosk(GREEN)\") ");
pipeline.Commands.Add("$m = $conv.Modalities[$IMType] ");
pipeline.Commands.Add("$null = $m.BeginSendMessage($msg, $null, $msg) ");
pipeline.Invoke();
It throws an error
System.Management.Automation.CommandNotFoundException: 'The term 'Import-Module "C:\Program Files(x86)\Microsoft Office 2013\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Model.dll"' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.'
I have been all around google and i cannot find a solution, I have tried throwing it all into one string and adding it to the pipeline.commands. I have split it up line by line like above, I even Made it copy the command out to text so i can copy/paste it into powershell and it works. I must be missing something in setting up Powershell Runspace. Anyone have any ideas? Thanks in advance!

And, Neverminded I figured it out. Multiple things, mainly the way I coded it.
I needed to use Pipeline.Commands.addScript() not just Add. 2. I apparently forgot to put a space in between Files (x86). 100% My error, Enjoy the read and the laugh! :)

Related

Get-ChildItem not working when running PowerShell script from C#

I have a PowerShell script that is using the Get-ChildItem cmdlet to get a list of files from a remote folder (the command taking long time because it a big folder).
all working good when i am running the script on the server
The script:
$serverip = someremoteip
$mainbackuplocation= someremotelocation
$folder = someremotefolder
$remotefolder = Get-ChildItem "\\$serverip\\d$\\$mainbackuplocation\\$folder\\wwwroot" |
Out-File d:\log.txt
But if I am trying to run the script through C# there is no output at all to the file.
SecureString securepassword = String2SecureString(password);
PSCredential credential = new PSCredential(userName, securepassword);
WSManConnectionInfo connectionInfo = new WSManConnectionInfo(target,shell,credential);
Runspace remote = RunspaceFactory.CreateRunspace(connectionInfo);
remote.Open();
PowerShell PowerShellInstance = PowerShell.Create();
PowerShellInstance.Runspace = remote;
PowerShellInstance.AddScript("D:\\backup\\test.ps1");
var result = PowerShellInstance.Invoke();
I can see that the log file is created on the server, so the PowerShell script is running, but the dir command does nothing.
Would like to know what I am doing wrong.
If you're using exactly this code that you write above - there is a small bag.
You have no space after Get-ChildItem - and becouse of this bug - the log.txt file is not created.
Try:
$remotefolder = Get-ChildItem "\\$serverip\\d$\\$mainbackuplocation\\$folder\\wwwroot" | Out-File d:\log.txt

running a command on a remote windows using winrm in C#

I have a simple way to connect to a remote windows machine from a local windows machine using winrm.
Here is the powershell code that is working:
Set-Item WSMan:\localhost\Client\TrustedHosts -Value $ip -Force
$securePassword = ConvertTo-SecureString -AsPlainText -Force 'mypass'
$cred = New-Object System.Management.Automation.PSCredential 'Administrator', $securePassword
$cmd = {ls C:\temp}
Invoke-Command -ComputerName $ip -Credential $cred -ScriptBlock $cmd
I want to figure out how to do the exact thing in c#.
Also, it would be additionally helpful if someone tell me whether there is a method to send files in c# winrm.
Note: the is only a c# code needed on my local machine. The remote machine is already setup.
well, I figured out one way as I shall post below, but while it works fine on windows 8, it encounters the error "Strong name validation failed" on windows 7 so I should keep looking into this.
Still please feel free to post other ideas.
--> add System.Management.Automation.dll to your project.
WSManConnectionInfo connectionInfo = new WSManConnectionInfo();
connectionInfo.ComputerName = host;
SecureString securePwd = new SecureString();
pass.ToCharArray().ToList().ForEach(p => securePwd.AppendChar(p));
connectionInfo.Credential = new PSCredential(username, securePwd);
Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo);
runspace.Open();
Collection<PSObject> results = null;
using (PowerShell ps = PowerShell.Create())
{
ps.Runspace = runspace;
ps.AddScript(cmd);
results = ps.Invoke();
// Do something with result ...
}
runspace.Close();
foreach (var result in results)
{
txtOutput.AppendText(result.ToString() + "\r\n");
}
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);
Please mark as answer if this helps. I've been using this for a while with my automated deployments. Please leave comments if you find issues.

How to use ActiveDirectory module (RSAT tools) in c#

I want to use specific command that are provided by the "Active Directory Administration with Windows PowerShell". So I installed this module on my server.
Now, I want to use these commands in my code. My project is in c# - ASP.NET.
Here's the code I use to call traditional "cmdlet" command (New-Mailbox, Set-User, ...) :
string runasUsername = #"Mario";
string runasPassword = "MarioKart";
SecureString ssRunasPassword = new SecureString();
foreach (char x in runasPassword)
ssRunasPassword.AppendChar(x);
PSCredential credentials =
new PSCredential(runasUsername, ssRunasPassword);
// Prepare the connection
var connInfo = new WSManConnectionInfo(new Uri("MarioServer"),
"http://schemas.microsoft.com/powershell/Microsoft.Exchange",credentials);
connInfo.AuthenticationMechanism =
AuthenticationMechanism.Basic;
connInfo.SkipCACheck = true;
connInfo.SkipCNCheck = true;
// Create the runspace where the command will be executed
var runspace = RunspaceFactory.CreateRunspace(connInfo);
//Params
....
// create the PowerShell command
var command = new Command("New-Mailbox");
command.Parameters.Add("Name", name);
....
// Add the command to the runspace's pipeline
runspace.Open();
var pipeline = runspace.CreatePipeline();
pipeline.Commands.Add(command);
// Execute the command
var results = pipeline.Invoke();
if (results.Count > 0)
System.Diagnostics.Debug.WriteLine("SUCCESS");
else
System.Diagnostics.Debug.WriteLine("FAIL");
runspace.Dispose();
This code work perfectly ! Great ! But let say I want to use "Set-ADUser", this command is from ActiveDirectory module (RSAT tools).
Given that all is set on the server (the module is installed), I tried to simply change "New-Mailbox" for "Set-ADUser" :
var command = new Command("Set-ADUser");
When I run the code, I have this error :
The term 'Set-ADUser' is not recognized as the name of a cmdlet, function, script file, or operable program.
So, that's my question :
How can we run command from the ActiveDirectory module (RSAT tools) in c# ? (Im using VS 2010).
As #JPBlanc pointed out in the comments section, you will need to ensure that the ActiveDirectory PowerShell module is loaded. PowerShell version 3.0 and later have module auto-loading enabled by default (it can be disabled), but if you're still targeting PowerShell 2.0, then you must first call:
Import-Module -Name ActiveDirectory;
.. before you can use the commands inside the module.
For the purposes of validation, you can use the Get-Module command, to ensure that the ActiveDirectory module has been imported.
Get-Module -Name ActiveDirectory;
If the above command returns $null, then the module is not imported. To verify that PowerShell can "see" the ActiveDirectory module, without actually importing it, run this command:
Get-Module -Name ActiveDirectory -ListAvailable;

run powershell from c# application

Hello a have a file with 21 lines of code in power shell. I need a way to run this file with a button in c#. I use c# in Visual Studio 2010. Please let me know if there is a way to achieve.
// Powershell
$Proc = Get-Process | Sort-Object CPU -Descending
$cores = Get-WmiObject Win32_processor
$memory = Get-WmiObject Win32_OperatingSystem
$Total = 10
$num = 1
Clear-Content c:\scripts\prueba.txt
foreach ($objItm in $Proc) {
If ($num -gt $Total) {
break #break the loop
}
[string] $strID=[System.Convert]::ToString($objItm.ID)
[string] $strProcessName=[System.Convert]::ToString($objItm.ProcessName)
[string] $strCPU=[System.Convert]::ToString($objItm.CPU)
[string] $strNUM=[System.Convert]::ToString($num)
$info=$strNUM+"-"+$strID+"-"+$strProcessName+"-"+$strCPU
$num += 1
$info|Add-Content c://scripts/prueba.txt
}
//Code c#
RunspaceConfiguration runspaceConfiguration = RunspaceConfiguration.Create();
Runspace runspace = RunspaceFactory.CreateRunspace(runspaceConfiguration);
runspace.Open(); RunspaceInvoke scriptInvoker = new RunspaceInvoke(runspace);
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.Add(scriptFile)
Execute PowerShell script results = pipeline.Invoke();
I need for example press a button and make the script happens
You can use PS2EXE by Ingo Karstein
This creates a c# executable with it's own powershell host and with your script embedded.
I have a c# project which takes the c# code in PS2EXE, adds ability to read the contents of an encrypted powershell script, decrypt it and run it.
some tips that works for me . My application is already working
Run Visual Studio with permissions of Administrator this to avoid get a error with the Hkey_Local...
In power shell run this get-executionpolicy to view the policy and set unregistered with set-executionpolicy unregistered. This avoid any restriction by the OS.
And with the code write above the app work. Get ready and test !!!

The term ' ' is not recognized as the name of a cmdlet,

I have a PowerShell script stored in a file, MergeDocuments.ps1. When I run the script from the Windows PowerShell command prompt it runs fine
.\MergeDocuments.ps1 1.docx 2.docx merge.docx
Calling the script from a Windows console application also runs fine.
When I tried calling the script from an Asp.Net web service, I faced some issues regarding registry access. I used impersonation and gave permission to Network Service account to the registry key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell to solve this problem
Next I faced issue about PowerShell being unable to create objects of type OpenXmlPowerTools.DocumentSource[], so I added the following to my script
Add-Type -Path "C:\Users\Administrator\Documents\WindowsPowerShell\Modules\OpenXmlPowerTools\OpenXmlPowerTools.dll"
Import-Module OpenXmlPowerTools
Now the current problem is that I am getting the error "The term 'Merge-OpenXmlDocument' is not recognized as the name of a cmdlet, ..."
How can I solve that?
PowerShell Script
Add-Type -Path "C:\Users\Administrator\Documents\WindowsPowerShell\Modules\OpenXmlPowerTools\OpenXmlPowerTools.dll"
Import-Module OpenXmlPowerTools
# The last argument is the path of the merged document
$noOfSourceDocs = ($($args.length) - 1)
# Create an array to hold all the source documents
[OpenXmlPowerTools.DocumentSource[]] $docs = New-Object OpenXmlPowerTools.DocumentSource[] $noOfSourceDocs
for ($i = 0; $i -lt $noOfSourceDocs; $i++)
{
$docs[$i] = New-Object -TypeName OpenXmlPowerTools.DocumentSource -ArgumentList $args[$i]
$docs[$i].KeepSection = 1
}
Merge-OpenXmlDocument -OutputPath $args[-1] -Sources $docs
Webservice .Net Code
using (new Impersonator(username, domain, password))
{
// create Powershell runspace
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
RunspaceInvoke invoker = new RunspaceInvoke(runspace);
invoker.Invoke("Set-ExecutionPolicy Unrestricted");
// create a pipeline and feed it the script file
Pipeline pipeline = runspace.CreatePipeline();
Command command = new Command(ConfigurationManager.AppSettings["PowerShellScript"]);
foreach (var file in filesToMerge)
{
command.Parameters.Add(null, file);
}
command.Parameters.Add(null, outputFilename);
pipeline.Commands.Add(command);
pipeline.Invoke();
runspace.Close();
}
Can you just try to install OpenXmlPowerTools module in the PowerShell System module path :
C:\Windows\system32\WindowsPowerShell\v1.0\Modules

Categories

Resources