Clear Powershell Streams in C# - c#

I have 3 commands for powershell:
shell.AddScript("Exit-PSSession");
shell.AddScript("Invoke-Command -ComputerName something -ScriptBlock {some command}");
shell.AddScript("Invoke-Command -ComputerName something -ScriptBlock {another command}");
Now I don't need any response from the first two, but I need the error log from the third one. Because I can't foresee how many errors may occur, I want to clear the shell from at least all error messages, better would be a complete empty shell.
My solution was this:
shell.AddScript("Exit-PSSession");
shell.AddScript("Invoke-Command -ComputerName something -ScriptBlock {some command}");
shell.Invoke();
shell.Streams.ClearStreams();
shell.AddScript("Invoke-Command -ComputerName something -ScriptBlock {another command}");
But somehow ClearStreams does nothing at all, shell still knows all old errors and the two previous commands.
The Microsoft sides don't give any more informati0on, than that this method exists and should clear out the shell. (Microsoft Help for ClearStreams) or Microsoft Help for streams in general
Did I miss something, or am I misunderstanding what they
(Powershell is Version 5.0) and C# runs 4.6 NET Framework
Thanks for help in advance.

you can use this:
powershell.Streams.Error();
Sample:
PowerShell powershell = PowerShell.Create();
powershell.Runspace = CreateRunSpace.runspace;
var exec = "Set-Mailbox -Identity John -DeliverToMailboxAndForward $true -ForwardingSMTPAddress 'manuel#contoso.com'";
powershell.AddScript(exec);
powershell.Streams.Error.Clear();
powershell.Streams.Warning.Clear();
var result = powershell.Invoke();
MessageBox.Show(powershell.Streams.Error.Count().ToString()+" error counts");
foreach (var errorRecord in powershell.Streams.Error)
{
MessageBox.Show(errorRecord.ToString()+"first - error");
}
Requesting you to post the full script. What kind of object shell is. I think it will have a method as .Clear()
NOte: I got this :
sh.Commands.AddScript("Add-PSSnapin
Microsoft.SystemCenter.VirtualMachineManager"); sh.Invoke();
sh.Commands.Clear();
Could you please check that

Related

run Powershellscript to enable exchange mailbox from c#

I have been working on this for days now and didn´t find a solution.
I´m trying to write a little programm to create some AD-User with attributes provided by a csv file.
Creating the AD-User itself works fine, but when it comes to the activation of the exchange mailbox, it fails.
The mailbox should be enabled with the samaaccountname. The database should be found and set by the manager mailadress. (The new mailbox schould be placed in the same database as the one from the managers).
When I run the script from the Powershell itself, it runs without any errors and does exactly what it is supposed to do. But wen called from my c# program, nothing happens.
My Powershellscript looks like this:
Param(
[string] $manager,
[string] $sam
)
$session = New-Pssession -ConfigurationName Microsoft.Exchange -ConnectionURI http://<FQDN>/Powershell/ -Authentication Kerberos
Import-Pssession $session -WarningAction:Ignore -disablenamechecking |out-null
$mb = get-mailbox $manager
Enable-Mailbox $sam -Database $mb.Database
and its called by this c# method:
public void mail_Box(string sam, string manager)
{
try
{
RunspaceConfiguration runconf = RunspaceConfiguration.Create();
Runspace run = RunspaceFactory.CreateRunspace(runconf);
run.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = run;
ps.AddScript("<pathToSkript>").AddParameter("manager", manager).AddParameter("sam", sam);
ps.Invoke();
}
catch (Exception e)
{
popup(e.Message);
}
}
And at this point I´m totaly stuck.
I tried to "build" the script within c# with preloaded exchange-powershell-module
PSSnapInException PSException = null;
PSSnapInInfo info = runconf.AddPSSnapIn("Microsoft.Exchange.Management.PowerShell.SnapIn", out PSException);
with the AddCommand and AddParameter methodes but this gave me snapin registration errors, or in case of using
AddScript(". $env:ExchangeInstallPath\\bin\\RemoteExchange.ps1")
i got errors like "Enable-Mailbox" is not a Cmdlet.
As you may see I´m not a developer, just a sysadmin trying to get things automated.

EnumerateFiles Method, UnauthorizedAccessException, and compiling C# in PowerShell [duplicate]

This works to count *.jpg files.
PS C:\> #([System.IO.Directory]::EnumerateFiles('C:\Users\Public\Pictures', '*.jpg', 'AllDirectories')).Count
8
How can an -ErrorAction Continue be applied to this?
PS C:\> #([System.IO.Directory]::EnumerateFiles('C:\Users', '*.jpg', 'AllDirectories')).Count
An error occurred while enumerating through a collection: Access to the path 'C:\Users\Administrator' is denied..
At line:1 char:1
+ #([System.IO.Directory]::EnumerateFiles('C:\Users', '*.jpg', 'AllDire ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I don't think you can. Unless you want to implement directory traversal yourself you're probably stuck with something like this:
Get-ChildItem 'C:\Users' -Filter '*.jpg' -Recurse -Force -ErrorAction SilentlyContinue
Ansgar Wiechers' helpful answer shows a workaround using Get-ChildItem, which is necessary when using the full, Windows-only .NET Framework (FullCLR), on which Windows PowerShell is built.
By contrast, .NET Core v2.1+ - on which PowerShell Core is built - does offer a solution:
#([System.IO.Directory]::EnumerateFiles(
'C:\Users',
'*.jpg',
[System.IO.EnumerationOptions] #{
IgnoreInaccessible = $true
RecurseSubDirectories = $true
}
)).Count
Note that this is the equivalent of -ErrorAction Ignore, not Continue (or SilentlyContinue), in that inaccessible directories are quietly ignored, with no way to examine which of them were inaccessible afterwards.
The solution above is based on this System.IO.Directory.EnumerateFiles() overload, which offers a System.IO.EnumerationOptions parameter.
The above answers work around the issue. They donnot appy the error action.
To realy catch the error action in the .net call, I'm using the $ErrorActionPreference variable in Windows PowerShell, as descirbed in https://devblogs.microsoft.com/scripting/handling-errors-the-powershell-way/:
# Store $ErrorActionPreference
$OldErrorActionPreference = $ErrorActionPreference
# Set $ErrorActionPreference for .net action
# see https://devblogs.microsoft.com/scripting/handling-errors-the-powershell-way/ for other values
$ErrorActionPreference = 'SilentlyContinue'
# .net call
#([System.IO.Directory]::EnumerateFiles('C:\Users\Public\Pictures', '*.jpg', 'AllDirectories')).Count
# restore origional $ErrorActionPreference
$ErrorActionPreference = $OldErrorActionPreference

Why am I not getting any verbose output in my C# PowerShell streams?

I have instantiated a C# PowerShell object and added scripts like so:
var ps = PowerShell.Create();
ps.AddScript(#"& ""filename.ps1"" ""machine5"" ""stop"" ");
Collection<PSObject> results = ps.Invoke();
For reference, here are the contents of filename.ps1:
param([string] $middleTier, [string] $mode)
Write-Verbose "This does appear"
if($mode -eq "stop") {
Invoke-Command -ComputerName $middleTier -ScriptBlock {
Write-Verbose "This does not appear"
Stop-Service -Name "ARealService" -Force -Verbose
}
iisreset $middleTier /stop
}
However, after a call to ps.Invoke(), all of my ps.Streams collections are empty. I know for a fact that this script writes to the verbose stream when run, but the C# Powershell object does not seem to capture any of it. What am I doing wrong?
Edit: I have added some explicit calls to Write-Vebose to show what does and does not get captured. It is clear that there is a problem with getting the stream output from the Invoke-Command block.
Your script block has its own verbose preference ($VerbosePreference). Set it to Continue inside script block then it should work.

Using C# to Call a PowerShell Script to Execute the Windows 'djoin' Command

I have the following Windows batch command that works successfully from the Command Prompt: djoin /provision /domain /machineou /machine /savefile
I have been able to wrap this Windows command in a PowerShell command: Invoke-Expression [djoin command] and it works well when running it locally using PowerShell.
I am failing when I try to take the script in Step #2 and call it from a C# web application. I'm trying the following:
PowerShell ps = PowerShell.Create();
ps.addCommand("Invoke-Expression");
ps.AddArgument("<djoin command>");
The web page doesn't give me any errors and I'm stuck on this. Please let me know if you have any questions and thank you for your help.
If you really want to use the PowerShell engine to execute this, then do it this way:
using (var ps = PowerShell.Create())
{
ps.AddScript("djoin /provision /domain /machineou /machine /savefile");
var results = ps.Invoke();
foreach (var r in results)
{
// do something with r
}
}
Note: the use of Invoke-Expression is unnecessary. Also, as MethodMan suggests in his comment, you could just use System.Diagnostics.Process.Start().

Powershell SQLPS module not importing within C#

I'm attempting to execute a SQL Query from within Powershell, within C#. I have been successful in doing so with ActiveDirectory cmdlets and wanted to take it one step further.
My first issue is while the following format works with ActiveDirectory (and in the ISE) it fails in C#:
using (PowerShell pS = PowerShell.Create())
{
pS.AddCommand("import-module");
pS.AddArgument("sqlps");
pS.Invoke();
}
I've long since had the security set to Unrestricted, but the error I'm getting is:
CmdletInvocationException was unhandled
File C:\Program Files (x86)\Microsoft SQL Server\110\Tools\PowerShell\Modules\sqlps\Sqlps.ps1 cannot be loaded because running scripts is disabled on this system. For more information, see about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.
However, if I run like this I get no error, though a later "Get-Module -all" call shows no sign of the module:
using (PowerShell pS = PowerShell.Create())
{
pS.AddScript("Import-Module sqlps");
pS.Invoke();
}
If I then try importing the ActiveDirectory module and calling Get-Module, it shows nothing.
What's going on here?
I'm not that great with C sharp but when calling scripts from outside of powershell there is a flag when executing the program to bypass the execution policy, i.e.
powershell.exe -executionpolicy bypass -command "& '\\somepath\somescript.ps1' "
This allows remote scripts to be called, as even with unrestricted set I still found that it wanted to prompt for the execution of some scripts so for instance in the task scheduler it would simply fail to run.
Also when importing SQLPS I've also found it's useful to add the -DisableNameChecking flag, you may also want to push your location beforehand and pop it afterwards otherwise you will end up in the SQLPS PSdrive with no access to local locations if you need it.
Did you try something like this?
PowerShell ps = PowerShell.Create();
ps.AddScript("set-executionpolicy unrestricted -scope process");
ps.AddScript("import-module sqlps");
ps.AddScript("get-module sqlps");
var m = ps.Invoke();
foreach (var mm in m.Select(x => x.BaseObject as PSModuleInfo))
Console.WriteLine(new { mm.Name, mm.Version });
I had a similar issue with the sqlServer ps module. Looks like when executing from C# you need to load the modules manually into the runspace in order for this to work.
string scriptText = File.ReadAllText("yourScript.ps1");
//This is needed to use Invoke-sqlcommand in powershell. The module needs to be loaded into the runspace before executing the powershell.
InitialSessionState initial = InitialSessionState.CreateDefault();
initial.ImportPSModule(new string[] { #"SqlServer\SqlServer.psd1" });
Runspace runspace = RunspaceFactory.CreateRunspace(initial);
runspace.Open();
using (PowerShell psInstance = PowerShell.Create())
{
psInstance.Runspace = runspace;
psInstance.AddScript(scriptText);
var PSOutput = psInstance.Invoke();
}
Also add all the references located in the SqlServer.psd1. This file is usually found in "C:\Program Files\WindowsPowerShell\Modules\SqlServer". I added to folder to my solution to be able to execute on remote servers.
You need to add Microsoft.SqlServer.BatchParser.dll reference in order to execute invoke-sqlcommand from the Powershell.
You should be able to do the same for sqlps module. Rather use SqlServer as it is newer.

Categories