c# how to import a powershell module from a string - c#

I'm using c# and I want to use import-module to import a powershell script. However I don't want to have a .psm1 file on disk. I want to have it hardcoded on my code, like in a string and then import it.
Is that possible?
All the example I can find are something like:
pipeline.Commands.Add("Import-Module");
var command = pipeline.Commands[0];
command.Parameters.Add("Name", #"G:\PowerShell\PowerDbg.psm1")
or something like:
var ps = PowerShell.Create(myRS);
ps.Commands.AddCommand("Import-Module").AddArgument(#"g:\...\PowerDbg.psm1")
ps.Invoke()
However as I said above I don't want to read a file from disk. I want it hardcoded to avoid multiple files. I want everything on an exe and that's it. I couldn't find a way, any help is appreciated.
The reason I want to use import-module is because after importing the module I want to do something like:
get-command -module <whatever>
and get a list of all its functions.
Any other way to list functions from a script might be helpful too.
Thanks.

You're looking for New-Module; it does exactly what you're asking for.
From the TechNet page (paraphrased):
New-Module -ScriptBlock {
$SayHelloHelp="Type 'SayHello', a space, and a name."
function SayHello ($name) {
"Hello, $name"
}
Export-ModuleMember -function SayHello -Variable SayHelloHelp
} -Name PowerDbg
C# Example (not tested):
string moduleContents = #"...";
pipeline.Commands.Add("New-Module");
var command = pipeline.Commands[0];
command.Parameters.Add("ScriptBlock", moduleContents);
command.Parameters.Add("Name", "PowerDbg");
pipeline.Invoke();

Related

Save file on server using powershell

I am trying to create xml file in C# and save that newly created file in local machine using powershell. new file is created at local but content is not saved.
I am creating simple xml file in C# as follows
XDocument doc = new XDocument(new XElement("body",
new XElement("level1",
new XElement("level2", "text"),
new XElement("level2", "other text"))));
and I am passing "doc" as parameter to powershell script and invoke powershell as follows
Dictionary<string, XDocument> parameters = new Dictionary<string, XDocument>() { { "VMConfigFile", doc } };
powershell.AddCommand("PowershellFunc").AddParameters(parameters);
Collection<PSObject> results = powershell.Invoke();
Collection<ErrorRecord> errors = powershell.Streams.Error.ReadAll();
powershell function as
function PowershellFunc
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true,
Position=0,
HelpMessage='Please Provide Config File')]
[ValidateNotNullOrEmpty()]
[xml]$VMConfigFile
)
try
{
$txt = $VMConfigFile
$Session = New-PSSession 127.0.0.1
Invoke-Command -Session $Session -ScriptBlock { Param($Txt) New-Item -Path c:\test\newFile.xml -Value $txt } -ArgumentList $txt
#Get-PSSession | Remove-PSSession
Write-Output "`file save successfully."
}
catch
{
Throw $_.exception.message
}
}
file is created after script run but it contains namespace("System.Xml.XmlDocument") only not file content.
I have also, tried to find out question related to my problem but most questiones are belong to read xml file from given path.
Question :-
How to pass xml file as parameter to powershell?(What I have did is it right?)
How to get that file in $txt(in powershell variable)? (I thing i am wrong here but i am not sure how to do that)
Is there any better way to do this?(best practices)
Since you're getting the Namespace as the output, it looks like the document is making it to Powershell fine.
New-Item just calls the ToString method of the variable and sticks that into the file. For a lot of objects in Powershell, that's just the type or namespace of the object. Only really simple objects will actually output the way you expect. You should use the .Save() method within the XMLDocument type to export it properly. Export-Clixml is an option too.
XMLDocument .Save(): https://learn.microsoft.com/en-us/dotnet/api/system.xml.xmldocument.save?view=netcore-3.1#System_Xml_XmlDocument_Save_System_String_
Export-Clixml Docs: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/export-clixml?view=powershell-7
It's not detailed here why you're starting with C# and then switching to Powershell, but the two are very closely intertwined and System.Xml.XmlDocument is a .Net namespace that's accessible in both languages. Unless there is a necessary reason, it might be easier to keep all of this in just one language.

Call specific function from perl module from PowerShell or C#

I've a perl script file (.pm) which has many functions like below
sub check_row {
my ($class, %args) = #_;
.......
sub find_value {
my ($class, %args) = #_;
.......
Is there any way I can call specific function either via C# or Powershell? I am not allowed to make any change in the .pm file. I am clueless as the tutorial I see on internet talks only about running perl module but not calling any specific function and passing and retrieving value.
You can't use Perl modules (your_module.pm) directly from PowerShell or C#. You need to run a Perl script (your_script.pl) that uses the module:
#!/usr/bin/env perl
use strict;
use warnings;
use Your::Module qw(find_value);
find_value ...;
or at least pass the code string as a commandline argument to the Perl interpreter, as Mathias R. Jessen pointed out in the comments:
perl.exe -w -MYour::Module -e 'find_value ...;'
For further research you might have a look at Win32-PowerShell-IPC-0.02. The documentation states the following:
This module fires up a captive child PowerShell process to which you can submit commands, and receive the results. It's all text for now, but Perl excels at messy stuff like this.

How to read powershell manifest file (.psd1) using c#

I am trying to access manifest details for a custom PowerShell module that has the manifest file stored along with the module(psm1) file in my directory structure.
What is the best way to access the manifest details like Description, GUID etc?
A psd1 file is a valid PowerShell script, so it's best to let PowerShell parse the file.
The simplest way is to use the Test-ModuleManifest cmdlet. From C#, that would look something like:
using (var ps = PowerShell.Create())
{
ps.AddCommand("Test-ModuleManifest").AddParameter("Path", manifestPath);
var result = ps.Invoke();
PSModuleInfo moduleInfo = result[0].BaseObject as PSModuleInfo;
// now you can look at the properties like Guid or Description
}
Other approaches cannot handle the complexities of parsing PowerShell, e.g. it would be easy to incorrectly handle comments or here strings when trying to use a regex.
Add a reference to System.Management.Automation. Then, use the following code to get a Hashtable from the .psd1 file.
static void Main(string[] args)
{
PowerShell ps = PowerShell.Create();
string psd = "C:\\Users\\Trevor\\Documents\\WindowsPowerShell\\Modules\\ISESteroids\\ISESteroids.psd1";
ps.AddScript(String.Format("Invoke-Expression -Command (Get-Content -Path \"{0}\" -Raw)", psd));
var result = ps.Invoke();
Debug.WriteLine(((Hashtable)result[0].ImmediateBaseObject)["Description"]);
}

system() to c# without calling cmd.exe

how to translate system("") to C# without calling cmd.exe?
edit: i need to throw something like "dir"
If I correctly understood your question, you're looking for Process.Start.
See this example (from the docs):
// Opens urls and .html documents using Internet Explorer.
void OpenWithArguments()
{
// url's are not considered documents. They can only be opened
// by passing them as arguments.
Process.Start("IExplore.exe", "www.northwindtraders.com");
// Start a Web page using a browser associated with .html and .asp files.
Process.Start("IExplore.exe", "C:\\myPath\\myFile.htm");
Process.Start("IExplore.exe", "C:\\myPath\\myFile.asp");
}
Edit
As you said you needed something like the "dir" command, I would suggest you to take a look at DirectoryInfo. You can use it to create your own directory listing. For example (also from the docs):
// Create a DirectoryInfo of the directory of the files to enumerate.
DirectoryInfo DirInfo = new DirectoryInfo(#"\\archives1\library");
DateTime StartOf2009 = new DateTime(2009, 01, 01);
// LINQ query for all files created before 2009.
var files = from f in DirInfo.EnumerateFiles()
where DirInfo.CreationTimeUtc < StartOf2009
select f;
// Show results.
foreach (var f in files)
{
Console.WriteLine("{0}", f.Name);
}
As other folks noted, it's Process.Start. Example:
using System.Diagnostics;
// ...
Process.Start(#"C:\myapp\foo.exe");
I need to throw something like "dir"
If you need to run DIR, then you need to call cmd.exe as dir is internal to cmd.exe
Not sure if I understand your question. Are you looking for Process.Start?
Do you actually want the equivalent? You may not depending on what exactly you're trying to do.
For example calling copy from the command line has a C# equivalent itself, File.Copy, for dir there's a whole Directory class for getting info (these are a quick 2 out of thousands of examples). Depending on what you're after, C# most likely has a library/function for the specific command you're trying to run, usually a more robust method as well, instead of a global handler.
If the global "invoke this" is what you're after, then as the other answers suggest, using the System.Diagnostics.Process class is your best bet.
If you want to execute a command-line (cmd.exe) command, such as "dir" or "time" or "mkdir", pass the command as an argument to cmd.exe with the flag /C.
For example,
cmd.exe /C dir
or
cmd.exe /C mkdir "New Dir"

Watin: Search in children of an element

I want to do a "two step" search using Watin. For example I would like to search for a ul-tag having class "abc". Then I would like to search for a certain li-tag inside that element. The code might look like this:
ie.ElementWithTag("ul", Find.ByClass("abc")).ElementsWithTag("li", Find.ByXYZ());
But Element does not have an ElementWithTag method. Any hint how to do that with Watin?
The authors of Watin told me that this will be supported in the next version. At the moment this can be done using filter and lambdas.
UPDATE
Actually I just saw info that there is ie.ElementWithTag now, look at this question.
So maybe rest of this post won't be that helpful
Don't have ready solution for you, but maybe a starting point.
Some (long) time ago I was writing some automation script for one page. I used powershell but it should be easy to migrate to C# (which I assume you use).
So in this part of script I' searching on page element that has tag input and is named Save Changes.
#getting property from com object::IHTMLDOMAttribute
function getProperty ([System.__ComObject] $obj, [string] $prop)
{
[System.__ComObject].InvokeMember($prop, [System.Reflection.BindingFlags]::GetProperty, $null, $obj, $null)
}
$ie = new-object -com "InternetExplorer.Application";
$ie.visible = $true;
$ie.navigate("http://mytestpage.com");
$doc = $ie.Document;
$saveButton = $null;
$inputElts = $null;
$inputElts = $doc.getElementsByTagName('input')
foreach ($elt in $inputElts)
{
$a = $elt.getAttributeNode('value')
if ($a -and (getProperty $a 'nodeValue') -eq 'Save changes')
{
$saveButton = $elt;
break;
}
}
So If you would replace part in loop that looks for Save Changes property of element (and delete getProperty declaration) with check for proper class than it should do the trick.
Implemented in their new version 2.0.50.11579.
Watin 2.0.50.11579

Categories