I am trying to create an app that would setup bitlocker PIN Programmatically.
the app works as well as the PowerShell Command, However, I am unfortunately unable to execute it.
I am getting the following Error when Executing:
"Application Attempted to perform an operation not allowed by the security policy. To grant this application the required permissions, contact your system administrator or use Microsoft .Net Configuration Tool"
private void Submit_Click(object sender, EventArgs e)
{
if (PIN.Text.Length < 20)
{
MessageBox.Show("Passwords must be at least 20 characters long.");
return;
}
else if (PIN2.Text != PIN.Text)
{
MessageBox.Show("Password & Confirmation are not identical, Please ensure that both Passwords are the same");
return;
}
else
{
PowerShell ps = PowerShell.Create();
ps.AddCommand("$PIN = \"" + PIN.Text + "\" | ConvertTo-SecureString -AsPlainText -Force; Enable-BitLocker -MountPoint \"C:\" -PIN $PIN -TPMAndPinProtector -SkipHardwareTest");
ps.Invoke();
MessageBox.Show("Your Pre-Boot PIN has now been Setup - Please reboot after 30 Minutes and login with your PIN");
Application.Exit();
I have set assembly: SecurityRules(SecurityRuleSet.Level1) but issue remains.
is it a GPO that would need to be amended at all? or would i be able to bypass in the App somehow?
Have you tried making an actual PowerShell script file and then running the file?
take a look at this
Related
I'm calling a self-elevating powershell script from C# code. The Script resets DNS Settings.
The script works fine when called from unelevated powershell, but takes no effect when called from C# code with no exceptions thrown.
My Execution policy is temporarily set on unrestricted and I'm running Visual Studio as Admin.
Does anyone know what's wrong?
The C#:
class Program
{
static void Main(string[] args)
{
var pathToScript = #"C:\Temp\test.ps1";
Execute(pathToScript);
Console.ReadKey();
}
public static void Execute(string command)
{
using (var ps = PowerShell.Create())
{
var results = ps.AddScript(command).Invoke();
foreach (var result in results)
{
Console.WriteLine(result.ToString());
}
}
}
}
The script:
# Get the ID and security principal of the current user account
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent();
$myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID);
# Get the security principal for the administrator role
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator;
# Check to see if we are currently running as an administrator
if ($myWindowsPrincipal.IsInRole($adminRole))
{
# We are running as an administrator, so change the title and background colour to indicate this
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)";
$Host.UI.RawUI.BackgroundColor = "DarkBlue";
Clear-Host;
}
else {
# We are not running as an administrator, so relaunch as administrator
# Create a new process object that starts PowerShell
$newProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";
# Specify the current script path and name as a parameter with added scope and support for scripts with spaces in it's path
$newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"
# Indicate that the process should be elevated
$newProcess.Verb = "runas";
# Start the new process
[System.Diagnostics.Process]::Start($newProcess);
# Exit from the current, unelevated, process
Exit;
}
# Run your code that needs to be elevated here...
Set-DnsClientServerAddress -InterfaceIndex 9 -ResetServerAddresses
As you've just determined yourself, the primary problem was that script execution was disabled on your system, necessitating (at least) a process-level change of PowerShell's execution policy, as the following C# code demonstrates, which calls
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass before invoking the script file (*.ps1):
For an alternative approach that uses the initial session state to set the per-process execution policy, see this answer.
The approach below can in principle be used to persistently change the execution policy for the current user, namely by replacing .AddParameter("Scope", "Process") with .AddParameter("Scope", "CurrentUser")
Caveat: When using a PowerShell (Core) 7+ SDK, persistent changes to the local machine's policy (.AddParameter("Scope", "LocalMachine")) - which require running with elevation (as admin) - are seen by that SDK project only; see this answer for details.
Caveat: If the current user's / machine's execution policy is controlled by a GPO (Group Policy Object), it can NOT be overridden programmatically - neither per process, nor persistently (except via GPO changes).
class Program
{
static void Main(string[] args)
{
var pathToScript = #"C:\Temp\test.ps1";
Execute(pathToScript);
Console.ReadKey();
}
public static void Execute(string command)
{
using (var ps = PowerShell.Create())
{
// Make sure that script execution is enabled at least for
// the current process.
// For extra safety, you could try to save and restore
// the policy previously in effect after executing your script.
ps.AddCommand("Set-ExecutionPolicy")
.AddParameter("Scope", "Process")
.AddParameter("ExecutionPolicy", "Bypass")
.Invoke();
// Now invoke the script and print its success output.
// Note: Use .AddCommand() (rather than .AddScript()) even
// for script *files*.
// .AddScript() is meant for *strings
// containing PowerShell statements*.
var results = ps.AddCommand(command).Invoke();
foreach (var result in results)
{
Console.WriteLine(result.ToString());
}
// Also report non-terminating errors, if any.
foreach (var error in ps.Streams.Error)
{
Console.Error.WriteLine("ERROR: " + error.ToString());
}
}
}
}
Note that the code also reports any non-terminating errors that the script may have reported, via stderr (the standard error output stream).
Without the Set-ExecutionPolicy call, if the execution policy didn't permit (unsigned) script execution, PowerShell would report a non-terminating error via its error stream (.Streams.Error) rather than throw an exception.
If you had checked .Streams.Error to begin with, you would have discovered the specific cause of your problem sooner.
Therefore:
When using the PowerShell SDK, in addition to relying on / catching exceptions, you must examine .Streams.Error to determine if (at least formally less severe) errors occurred.
Potential issues with your PowerShell script:
You're not waiting for the elevated process to terminate before returning from your PowerShell script.
You're not capturing the elevated process' output, which you'd have to via the .RedirectStandardInput and .RedirectStandardError properties of the System.Diagnostics.ProcessStartInfo instance, and then make your script output the results.
See this answer for how to do that.
The following, streamlined version of your code addresses the first point, and invokes the powershell.exe CLI via -ExecutionPolicy Bypass too.
If you're using the Windows PowerShell SDK, this shouldn't be necessary (because the execution policy was already changed in the C# code), but it could be if you're using the PowerShell [Core] SDK, given that the two PowerShell editions have separate execution-policy settings.
# Check to see if we are currently running as an administrator
$isElevated = & { net session *>$null; $LASTEXITCODE -eq 0 }
if ($isElevated)
{
# We are running as an administrator, so change the title and background color to indicate this
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)"
$Host.UI.RawUI.BackgroundColor = "DarkBlue"
Clear-Host
}
else {
# We are not running as an administrator, so relaunch as administrator
# Create a new process object that starts PowerShell
$psi = New-Object System.Diagnostics.ProcessStartInfo 'powershell.exe'
# Specify the current script path and name as a parameter with and support for scripts with spaces in its path
$psi.Arguments = '-ExecutionPolicy Bypass -File "{0}"' -f
$script:MyInvocation.MyCommand.Path
# Indicate that the process should be elevated.
$psi.Verb = 'RunAs'
# !! For .Verb to be honored, .UseShellExecute must be $true
# !! In .NET Framework, .UseShellExecute *defaults* to $true,
# !! but no longer in .NET Core.
$psi.UseShellExecute = $true
# Start the new process, wait for it to terminate, then
# exit from the current, unelevated process, passing the exit code through.
exit $(
try { ([System.Diagnostics.Process]::Start($psi).WaitForExit()) } catch { Throw }
)
}
# Run your code that needs to be elevated here...
Set-DnsClientServerAddress -InterfaceIndex 9 -ResetServerAddresses
I am attempting to login into multiple win 10 computers via rdp from a list of computer names then reboot them. From my best knowledge rdp is the way to do this. I am in the beginning stages and I am not able to even connect one machine.
I have attempted and tested code from every resource I could find. I have tested the multiple Microsoft RDP Client Control versions and verified I have version 10 on my Windows 10 Machine. Below is the code I have so far.
private void startBtn_Click(object sender, EventArgs e)
{
try
{
dmain = #"MGROUPNET\";
lines = listBox.Lines;
Server = lines[0];
dmain = dmain + nUser;
//Testing to verify correct details
usernameLabel.Text = dmain;
passLabel.Text = nPass;
serverLabel.Text = Server;
rdp1.Server = Server;
rdp1.UserName = dmain;
rdp1.AdvancedSettings9.NegotiateSecurityLayer = true;
rdp1.AdvancedSettings8.ClearTextPassword = nPass;
rdp1.Connect();
connectLabel.Text = this.rdp1.Connected.ToString();
}
catch (Exception Ex)
{
MessageBox.Show("Error Disconnecting: " + Ex);
}
}
After this code, I get a connection status of 2. This then changes to 0 without displaying anything. Any help or guidance would be appreciated.
I suggest you to use PsExec instead of RDP. You can download it from here:
https://learn.microsoft.com/en-us/sysinternals/downloads/psexec
Now, all you have to do is just open a cmd window with your c# program with the following command:
psexec_path \\target_IPv4 -u local_username -p password shutdown.exe -t 0 -r
If connection is succeed, the device will try restart with the specified user credentials. Make sure that the user has the required permissions to do this (e.g. if you are in a domain).
I have to notice that the connection connection is not secured. Use PsExec v2.1 at least to encrypt your connection.
The following command works when called directly from powershell, but not when called within an ASP.NET application.
Invoke-Command -ComputerName remotesrv -ScriptBlock { 5 }
I suppose, there is some kind of user rights problem, but at this point I am stuck and don't know how to solve this.
The ASP.NET code looks as follows:
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
using (PowerShell powershell = PowerShell.Create())
{
var rs = "-ComputerName remotesrv";
powershell.AddScript("Set-ExecutionPolicy RemoteSigned");
var script = String.Format("Invoke-Command {0} -scriptblock {{ 5 }}", rs);
powershell.AddScript(script);
powershell.InvocationStateChanged += delegate(object sender, PSInvocationStateChangedEventArgs e)
{
if (e.InvocationStateInfo.State == PSInvocationState.Completed)
{
// Clean up
}
};
var output = new PSDataCollection<PSObject>();
output.DataAdded += delegate(object sender, DataAddedEventArgs e)
{
PSDataCollection<PSObject> myp = (PSDataCollection<PSObject>)sender;
Collection<PSObject> results = myp.ReadAll();
foreach (PSObject result in results)
{
if (result.BaseObject is int)
{
// Do something in the database
}
}
};
IAsyncResult asyncResult = powershell.BeginInvoke<PSObject, PSObject>(null, output);
asyncResult.AsyncWaitHandle.WaitOne();
}
}
);
If I don't add -ComputerName remotesrv, the script is executed.
What do you need to do, to be able to call a powershell script remotely from an ASP.NET application?
I would recommend you read through the Powershell remoting requirements specifically the User Permission portion. By default, the account creating the connection must be an administrator on the remote machine. If your web application is running under an identity that is not an administrator on the remote machine, the connection will fail. Note that this is the default behaviour and can be changed by tweaking the session configurations on the remote machine.
I had the same problem, my solution was change the user who execute IIS's application pool.
After set Enable-PsRemoting -Force and Set-ExecutionPolicy Unrestricted, (perhaps is better left ExecutionPolicy RemoteSigned), invoke-command still doesn't work.
Then I went to Task Manager, Process tab and look by w3wp.exe and the User that was executing that process was "DefaultAppPool", I guess that this user have not rights to remote access or execution on PowerShell. (Image shows Administrador because I already change it)
To change the user go to IIS Manager, in application groups, my site's application groups shows in Identity: ApplicationPoolIdentity, Select the application pool and click Advanced Settings, in Process Model, select Identity and click the ellipsis (the button with the three dots). In Personal Account sets an Administrator account with username and password, reboot IIS.
If I look by Task Manager, iis user has changed
I have written an application that installs Windows Roles and Features using the Powershell API. It works just fine in Windows 2008 R2, but nothing happens in Windows 2012; the program just moves on as if everything happened just fine, but nothing is installed.
I've tried making the program .NET v4.5 (it was .NET v2.0), but that didn't help. I've been all over Google about this and I can't find a solution that works. In fact, most say to use the sort of implementation that works in Windows 2008 R2. Here is my code:
public bool runPowerShell(string command, string args)
{
mLogger myLogger = mLogger.instance; //How I log stuff in my application.
bool done = false; //default Return value.
const string path = #"C:\\XMPLogs\\Roles and Features"; //Where Powershell output will go.
//Make sure Powershell log directory is there.
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
//Start a new Powershell instance.
PowerShell powershell = PowerShell.Create();
System.Collections.ObjectModel.Collection<PSObject> output = new System.Collections.ObjectModel.Collection<PSObject>();
StringBuilder strBuilder = new StringBuilder(); //Used to examine results (for testing)
powershell.AddScript(#"Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted");
powershell.AddScript(#"Import-Module ServerManager");
//powershell.Invoke();
powershell.AddScript(command + " " + args);
try
{
output = powershell.Invoke();
// Construct a StringBuilder to examine the output of Invoke()
foreach (PSObject obj in output)
strBuilder.AppendLine(obj.ToString());
// Show the StringBuilder to see results (always empty!)
MessageBox.Show(strBuilder.ToString());
done = true;
}
catch (Exception ex)
{
string test = ex.ToString();
MessageBox.Show(test);
myLogger.output("ERRO", "PowerShell command " + command
+ "failed to run with arguments \"" + args + "\". Message: " + ex.ToString());
done = false;
}
powershell.Dispose();
return done;
}
I would call the method like this:
runPowerShell("add-windowsfeature", "-name FS-FileServer -logpath \"c:\\XMPLogs\\Roles and Features\\File Services.log\"");
The "output" object never has any data in it nor does the log file. So, I have no idea what is going on. I do know if I take the two parameters in the method call and enter them into a Powershell prompt manually, the install runs flawlessly.
Can anyone see what I'm doing wrong with this implementation on Windows Server 2012?
Thank you.
It's hard to know what is the real problem here, without more information. Perhaps you're not running your application as an administrator and therefore aren't allowed to add windows features?
However, PowerShell differs between terminating errors (which would block the execution and throw an exception, which should make your code enter the catch statement) and non-terminating errors (which are just written to the error stream and will not enter your catch statement).
You can read more about this if you run Get-Help Write-Error, Get-Help about_Throw and Get-Help about_Try_Catch_Finally.
I'm guessing your powershell command results in a non-terminating error. To find out whether a non terminating error has occured or not, you could check the powershell.HadErrors property and to get the error messages you can read the powershell.Streams.Error property.
This should probably help you in finding out what errors are occuring and hopefully help you solve your problem.
Problem Summary
When run in batch mode, my user identity is lost but (like a really good cliffhanger) not until the very last moment.
Problem Details
I have a PowerShell script running on WinXpSp3 that runs a script block (via Invoke-Command) on a remote machine as a particular test user (via -Session parameter) in the background (via -AsJob parameter). The session is created with this:
New-PSSession -computername $myServer -credential $myCredential
The script block performs a number of actions, culminating in running the NUnit test framework. The C# code under test records the "myTestUser" username (via Environment.UserName) so the credentials provided by PowerShell are properly received that far. This is further confirmed by Process Explorer: examining properties of nunit-console running the batch tests shows it is owned by myTestUser.
The test includes accessing a Sql Server 2008 R2 database; the connection string is set via a new SqlConnection(connectionString) call. The connection string is set up for Windows Authentication and uses this form:
Data Source=<my_db_server_name>;Initial Catalog=<my_db_name>;Integrated Security=True;Persist Security Info=True
Even though I have conclusively pushed the myTestUser credentials all the way to the C# code under test, the DB access attempt is not seeing these credentials, resulting in this error: Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'
Some supplemental info:
I have confirmed that the test user (myTestUser) has DB permissions and the NUnit test is capable of accessing the DB: When I run the NUnit test manually (via NUnit GUI) logged in as myTestUser, the test works properly and SqlProfiler clearly shows this activity with myTestUser appearing in the NTUserName column.
The same error occurs if I run locally rather than on a remote machine.
The same error occurs if I run as myself on my local machine (i.e. omitting the -credential parameter).
Question
How can I rescue myTestUser from the brink of doom and get him DB access?
2011.05.16 Update
Here is a simplified example exhibiting the same problem.
First, my test program DBFetchVersion that prints the name of the current user and the results of a simple query:
class Program
{
const string connString = ...your connection string here... ;
const string query = "SELECT getdate() [Date], substring(##version,1,charindex('-',##version)-1) +convert(varchar(100),SERVERPROPERTY('edition'))+ ' ' +convert(varchar(100),SERVERPROPERTY('productlevel')) [SQL Server Version], ##servicename [Service Name], ##servername [Server Host], db_name() [Database], user_name() [User], host_name() [Client]";
static void Main(string[] args)
{
DataView dataView;
using (var connection = new SqlConnection(connString))
{
Console.WriteLine("user = " + Environment.UserName);
using (var dataAdapter = new SqlDataAdapter(query, connection))
{
var dataSet = new DataSet();
try
{
connection.Open();
dataAdapter.SelectCommand.CommandType = CommandType.Text;
dataAdapter.Fill(dataSet, query);
}
finally { if (connection.State == ConnectionState.Open) connection.Close(); }
dataView = dataSet.Tables[0].DefaultView;
}
foreach (var item in dataView.Table.Rows[0].ItemArray)
Console.WriteLine(item);
}
}
}
And here is the Powershell script that calls the above program.
$scriptBlock = {
& "...path to my executable...\DBFetchVersion\bin\Debug\DBFetchVersion.exe"
}
$serverName = ... my server name ...
$username = "testuser"
$password = ... my user password ...
$adjPwd = $password | ConvertTo-SecureString -asPlainText -Force
$testCred = (New-Object System.Management.Automation.PSCredential($username,$adjPwd))
$mySession = New-PSSession -computername $serverName -credential $testCred
# Test Scenarios:
Invoke-Command $scriptBlock
#Invoke-Command $scriptBlock -computername $serverName
#Invoke-Command $scriptBlock -computername $serverName -credential $testCred
#Invoke-Command $scriptBlock -Session $mySession
In the list of four test scenarios at the end, the uncommented one works, printing my user name and the results of the query.
DBFetchVersion still reports I am the user with the second line, but the DB connection fails with the " Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON' " error.
The remaining two lines report the "testuser" user name, but both report the same login failure for the DB connection.
What this isolated example tells me is not that I think there is anything buggy about Powershell, .NET, or my code, but there is something with the authentication mechanism that I do not yet understand, since specifying another computer or a session both involve a path that should, in some sense, have stronger protection.
2011.08.03 Update - Eureka!
Well, Matt was correct in identifying the double-hop issue as the culprit and CredSSP authentication as the solution. Unfortunately, as I quickly found out, CredSSP requires Windows 7, so I went about setting up a couple VMs as a sandbox. CredSSP, however, was not one to easily relinquish its secrets (at least to me) as I detailed in this post on ServerFault: Cannot get CredSSP authentication to work in PowerShell
I finally was able to get CredSSP authentication to work so I could then come back to the problem I posed here in this thread. As a test, I used these 3 script blocks plugged into the PowerShell script I provided above:
$scriptBlockA = {
Write-Host ("hello, world: {0}, {1}" -f $env:USERNAME, (hostname))
}
# Simple DB test, but requires SqlServer installed!
$scriptBlockB = {
if (! (Get-PSSnapin | ? { $_.name -eq "SqlServerCmdletSnapin100" } ) )
{ Add-PSSnapin SqlServerCmdletSnapin100; }
Invoke-Sqlcmd -Query "SELECT getdate() as [Now]" -ServerInstance CinDevDB5
}
# Indirect DB test; requires .NET but not SqlServer,
# plus DBFetchVersion in home dir for targeted user.
$scriptBlockC = {
& ".\DBFetchVersion.exe"
}
Block A worked with or without CredSSP, since there is no double-hop. Blocks B and C would only work with CredSSP because they both attempt to access a remote database. QED.
Initially i read this and thought of the "double hop" issue, but the supplemental info maybe me question that though.
When you run it locally (as yourself or the testuser) what commands do you use? this:
& "...path to my executable...\DBFetchVersion\bin\Debug\DBFetchVersion.exe"
also does this work from your local machine (as either yourself or the user):
Add-PSSnapin SqlServerCmdletSnapin100;
Invoke-Sqlcmd -Query "SELECT getdate()" -ServerInstance Server
Also what OS are you using? If it is Windows 2008 and the issue is double hop you may be able to us CredSSP to avoid it.