Why does PowerShell exit unexpected on "Get-Credentials"? - powershell

I am running a PowerShell gui script, I need to hide away the batch script which loads it. (This makes it easier for my team to load it.)
Batch script:
#ECHO OFF
pushd "NETWORK SHARE"
PowerShell.exe -ExecutionPolicy unrestricted -WindowStyle hidden -NoProfile -file .\FileName.ps1
popd
I have gotten it to allow popups to come in by using:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName PresentationFramework
But the following line causes the PowerShell script to freeze & exit unexpected.
$mycredentials = Get-Credential # This is necessary as some people may not use their admin accounts to login
Some of my team members do not login with their administrator accounts and use their standard accounts to sign in and do things. Some sign in with their administrator accounts to do things.

So what I've done is wrote the following code and thrown it into a little bat file to test out the core stuff you are trying to achieve.
powershell.exe -executionpolicy bypass -windowstyle hidden -noprofile -command "Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName PresentationFramework;get-credential;start-sleep 10"
If you have -windowstyle hidden the script will fail because Get-Credential will not trigger a pop up asking for your credentials and just exit (Or maybe it runs but has no credentials).
Once you remove -windowstyle hidden the script will run, create the pop up to grab credentials then hang for 10 seconds before closing.
I also threw in [System.Windows.Forms.Application]::EnableVisualStyles() but that didn't change anything.
Unless you provide a username and password to Get-Credential it will create a pop up. Since you insist on it being hidden, then you will need to manually prompt the user for their Username and Password, or use an extra account with limited permissions. An alternative might be to use a windows form pop up to prompt for a username and password, then use those to generate the credentials rather than Get-Credential
Without more information on your code and what you are trying to achieve with the credentials its impossible to help you anymore. You can always clean your code to remove references to users, servers and other sensitive information. If you want proper help, you need to be willing to share what you have done.

Related

Powershell self-elevate loop

I'm one of the IT admins in our company. Lately, cyber-security want to get stricter on how easily users can read and/or write data on USB sticks and external mass storage. In addition all new users getting new Windows notebooks will only have "non admin" permissions. All requests to install software etc must come through the IT desk.
An Active Directory OU has been created and some test notebooks have been assigned to it. My boss would like to me to write and test some Powershell scripts that would allow my colleagues and I (in a screen-sharing session with the user) to temporarily delete the registry keys that control USB storage access (until the next group policy update comes along). The hard part has already been taken care of. The intention is that script will be stored as a Nal-Object on ZenWorks, so the user would not be able to see the source code (kinda similar to an exe file that is just double-clicked on).
The code that is causing hassle...
# self-elevate to admin user - code at the very top of the PS file..
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Start-Process PowerShell -Verb RunAs "-NoProfile -ExecutionPolicy Bypass -Command `"cd '$pwd'; & '$PSCommandPath';`"";
exit;}
# all the main code follows..
Here, if I run the script (in an non-admin account) I am prompted by UAC to enter the name and password of a local (or domain) admin account, a new window/session in PS opens and I can run whatever main commands need running.
The problem however is that is that when prompted for credentials and then type the correct password for a local non-admin account (as some users are inevitably going to do!) a new empty PS window/session just keeps opening indefinitely in a periodic fashion.
I've also tried adding an 'else clause' to the if-statement (to show an alert to the user and/or force quit Powershell, but it never seems to be get executed).
When I test this on a computer is that non part of any domain etc, I just get a "user is not authorised" kind of alert in UAC and no error gets the chance to propagate.
Is there any kind of workaround for this? It would be great too if the UAC prompt just defaulted to the name "ROOT\install". Nobody knows that password to this account except for IT admins.
I've also run Get-ExecutionPolicy -List... MachinePolicy and LocalMachine are "RemoteSigned", everything else is "Undefined".
I don't think execution policy plays a role in this strange loop, but I am open to being wrong. The script I am testing has not been through any signing procedures etc and is just sitting locally on the Desktop of one of the test computers.
Thanks.
Your symptom is mysterious; it implies the following:
The UAC prompt triggered by Start-Process -Verb RunAs mistakenly accepts a NON-admin user's credentials.
On re-entry into the script, the test for whether the session is elevated (!([Security.Principal.WindowsPrincipal] ...) then fails, and Start-Process -Verb RunAs is run again, at which point no UAC prompt is shown, because Start-Process does think the session is elevated and instantly spawns a new window.
The result is an infinite loop of new windows getting opened.
I have no idea what would cause this discrepancy - do tell us if you ever find out.
As workaround, you can try the following approach:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
$passThruArgs = "-NoProfile -ExecutionPolicy Bypass -NoExit -Command `"cd \`"$pwd\`"; & \`"$PSCommandPath\`""
if ([Environment]::CommandLine -match [regex]::Escape($passThruArgs)) {
throw "You entered non-admin credentials. Please try again with admin credentials."
}
Start-Process -Verb RunAs PowerShell $passThruArgs
exit
}
# all the main code follows..
'Now running elevated...'
That is, the on re-entry the process command line is examined for containing the same arguments that were passed on elevated re-invocation. If so, the implication is that even though the UAC prompt accepted the credentials, the new session still isn't elevated, and an error is thrown.
Note that I've added -NoExit to the re-invocation, so that the new window stays open, which allows the results to be examined.

Trying to run "reg import C:\myRegKey.reg" as an admin within a script that runs as a standard user

I am working on a PowerShell script that sets up a user's profile after their Windows Profile has been created. The script performs various functions such as pinning items to the task bar, enabling offline files for the user's personal network drive, etc. I would like to include a reg import for MS Edge that forces the Favorites Bar to be enabled in order for Edge to feel more like IE once favorites have been transferred to the user's machine. I have the reg key created, but I need to apply admin rights to import the reg key.
I would prefer to not grant every user temp admin rights when their machine is built, and I would prefer to not have to manually enter credentials every time I run the script.
I was able to successfully pass my credentials to a PSCredential object, and I was able to run other cmdlets with said credentials. I am simply struggling to pass these credentials to a reg import.
Currently, I have two scripts. The main one that performs the tasks under the user profile, and the secondary one that prompts for admin rights and then performs the reg import. The main script currently calls the second script, which prompts for admin rights and imports the reg key.
Below is the portion of the main script that calls script number 2 to perform the admin task:
$Script = "\\NetworkDrive\Enable_Edge_Favorites_Bar.ps1"
&$Script
Script 2 is below:
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Start-Process powershell.exe "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs; exit }
reg import "\\NetworkDrive\Edge_Favorites_Bar.reg"
While this is functional, I am looking for a way to do this where I do not need to enter a username and password each time. Ideally in a single script, but if someone has a solution that requires multiple scripts, I am willing to work with that as well!
I have tried:
Invoke-Command -Credential $cred -ComputerName $env:COMPUTERNAME -FilePath $Script
as well, but when I do, I receive an access denied error. So it seems that we do not have remote management turned on or at the very least I do not have access to perform remote registry edits.
I feel like I am most certainly just missing something stupid, so any assistance that someone can provide would be greatly appreciated.
Thanks!

How to send keys/ input to a process that is running without a logged in user using powershell?

I'm having an issue with automating part of an application install with powershell.
Part of the install is running a command line tool with parameters and entering credentials to access a database. This is supposed to be done without logging in.
For that purpose I've been using scheduled tasks to start my scripts at system startup.
I've been trying to get this particular step working by using AppActivate and SendWait to send the credentials to the window. This does not work though since there is no interactive window if I use the task scheduler.
This is the current script I've been using. It works if I would use the RunOnce key for example.
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")
powershell.exe add-type -AssemblyName microsoft.VisualBasic
add-type -AssemblyName System.Windows.Forms
$parms = 'create instance'
Start-Process "app.exe" -ArgumentList $parms -WorkingDirectory "C:\app\app.exe"
start-sleep -Milliseconds 1000
[Microsoft.VisualBasic.Interaction]::AppActivate("C:\app\app.exe")
[System.Windows.Forms.SendKeys]::SendWait("username")
start-sleep -Milliseconds 1000
[Microsoft.VisualBasic.Interaction]::AppActivate("C:\app\app.exe")
[System.Windows.Forms.SendKeys]::SendWait("password")
This script is called by another script which is run by the task scheduler.
Right now it fails with:
Exception calling "AppActivate" with "1" argument(s): "Process '{0}' was not found."
and:
Exception calling "SendWait" with "1" argument(s): "Access is denied"
Which is due to not being able to access the window.
Is there any way to send the username and password to the process without requiring an active windows? From what I've seen it doesn't seem to be supported by powershell but I'm still hoping that there is a way. Maybe using Handles? I can not use any applications like AutoHotkey or AutoIt.
Try this,
$proc = Get-process | where {$_.path -eq "C:\app\app.exe"}
[Microsoft.VisualBasic.Interaction]::AppActivate($Proc.id)

How do I run a PowerShell script when the computer starts?

I have a PowerShell script that monitors an image folder. I need to find a way to automatically run this script after the computer starts.
I already tried the following methods, but I couldn't get it working.
Use msconfig and add the PowerShell script to startup, but I cannot find the PowerShell script on that list.
Create a shortcut and drop it to startup folder. No luck.
%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -File "C:\Doc\Files\FileMonitor.ps1"
or
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -File "C:\Doc\Files\FileMonitor.ps1"
Here's my PowerShell script:
$folder = "C:\\Doc\\Files"
$dest = "C:\\Doc\\Files\\images"
$filter = "*.jpg"
$fsw = new-object System.IO.FileSystemWatcher $folder, $filter -Property #{
IncludeSubDirectories=$false
NotifyFilter = [System.IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
Start-Sleep -s 10
Move-Item -Path C:\Doc\Files\*.jpg C:\Doc\Files\images
}
I also tried to add a basic task using taskschd.msc. It is still not working.
Here's what I found, and maybe that will help to debug it.
If I open up a PowerShell window and run the script there, it works. But if I run it in a command prompt,
powershell.exe -File "C:\Doc\Files\FileMonitor.ps1"
It will not work. I am not sure it's a permission problem or something else.
BTW, I have PowerShell 3.0 installed, and if I type $host.version, it will show 3 there. But my powershell.exe seems like it is still v1.0.
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
I finally got my PowerShell script to run automatically on every startup. You will need to create two files: the first is the Powershell script (e.g. script.ps1) and the second is a .cmd file that will contain commands that will run on the command prompt (e.g. startup.cmd).
The second file is what needs to be executed when the computer starts up, and simply copy-pasting the .ps1 to the startup folder won't work, because that doesn't actually execute the script - it only opens the file with Notepad. You need to execute the .cmd which itself will execute the .ps1 using PowerShell. Ok, enough babbling and on to the steps:
Create your .ps1 script and place it in a folder. I put it on my desktop for simplicity. The path would look something like this:
%USERPROFILE%\Desktop\script.ps1
Create a .cmd file and place it in
%AppData%\Microsoft\Windows\Start Menu\Programs\Startup\startup.cmd
Doing this will execute the cmd file every time on startup. Here is a link of how to create a .cmd file if you need help.
Open the .cmd file with a text editor and enter the following lines:
PowerShell -Command "Set-ExecutionPolicy Unrestricted" >> "%TEMP%\StartupLog.txt" 2>&1
PowerShell %USERPROFILE%\Desktop\script.ps1 >> "%TEMP%\StartupLog.txt" 2>&1
This will do two things:
Set the Execution Policy of your PowerShell to Unrestricted. This is needed to run scripts or else PowerShell will not do it.
Use PowerShell to execute the .ps1 script found in the path specified.
This code is specifically for PowerShell v1.0. If you're running PowerShell v2.0 it might be a little different. In any case, check this source for the .cmd code.
Save the .cmd file
Now that you have your .ps1 and .cmd files in their respective paths and with the script for each, you are all set.
You could set it up as a Scheduled Task, and set the Task Trigger for "At Startup"
What I do is create a shortcut that I place in shell:startup.
The shortcut has the following:
Target: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Command "C:\scripts\script.ps1"
(replacing scripts\scripts.ps1 with what you need)
Start In: C:\scripts
(replacing scripts with folder which has your script)
You could create a Scheduler Task that runs automatically on the start, even when the user is not logged in:
schtasks /create /tn "FileMonitor" /sc onstart /delay 0000:30 /rl highest /ru system /tr "powershell.exe -file C:\Doc\Files\FileMonitor.ps1"
Run this command once from a PowerShell as Admin and it will create a schedule task for you. You can list the task like this:
schtasks /Query /TN "FileMonitor" /V /FO List
or delete it
schtasks /Delete /TN "FileMonitor"
This is really just an expansion on #mjolinor simple answer [Use Task Scheduler].
I knew "Task Scheduler" was the correct way, but it took a bit of effort to get it running the way I wanted and thought I'd post my finding for others.
Issues including:
Redirecting output to logs
Hiding the PowerShell window
Note: You must have permission to run script see ExecutionPolicy
Then in Task Scheduler, the most important/tricky part is the Action
It should be Start a Program
Program/Script:
powershell
Add arguments (optional) :
-windowstyle hidden -command full\path\script.ps1 >> "%TEMP%\StartupLog.txt" 2>&1
Note:
If you see -File on the internet, it will work, but understand nothing can be after -File except the File Path, IE: The redirect is taken to be part of the file path and it fails, you must use -command in conjunction with redirect, but you can prepend additional commands/arguments such as -windowstyle hidden to not show PowerShell window.
I had to adjust all Write-Host to Write-Output in my script as well.
Try this: create a shortcut in startup folder and input
PowerShell "& 'PathToFile\script.ps1'"
This is the easiest way.
Prerequisite:
1. Start powershell with the "Run as Administrator" option
2. Enable running unsigned scripts with:
set-executionpolicy remotesigned
3. prepare your powershell script and know its path:
$path = "C:\Users\myname\myscript.ps1"
Steps:
1. setup a trigger, see also New-JobTrigger (PSScheduledJob) - PowerShell | Microsoft Docs
$trigger = New-JobTrigger -AtStartup -RandomDelay 00:00:30
2. register a scheduled job, see also Register-ScheduledJob (PSScheduledJob) - PowerShell | Microsoft Docs
Register-ScheduledJob -Trigger $trigger -FilePath $path -Name MyScheduledJob
you can check it with Get-ScheduledJob -Name MyScheduledJob
3. Reboot Windows (restart /r) and check the result with:
Get-Job -name MyScheduledJob
see also Get-Job (Microsoft.PowerShell.Core) - PowerShell | Microsoft Docs
References:
How to enable execution of PowerShell scripts? - Super User
Use PowerShell to Create Job that Runs at Startup | Scripting Blog
Copy ps1 into this folder, and create it if necessary. It will run at every start-up (before user logon occurs).
C:\Windows\System32\GroupPolicy\Machine\Scripts\Startup
Also it can be done through GPEDIT.msc if available on your OS build (lower level OS maybe not).
Be sure, whenever you want PowerShell to run automatically / in the background / non-interactive, it’s a good idea to specify the parameters
-ExecutionPolicy Bypass to PowerShell.exe
PowerShell.exe -ExecutionPolicy Bypass
I have a script that starts a file system watcher as well, but once the script window is closed the watcher dies. It will run all day if I start it from a powershell window and leave it open, but the minute I close it the script stops doing what it is supposed to.
You need to start the script and have it keep powershell open.
I tried numerous ways to do this, but the one that actually worked was from http://www.methos-it.com/blogs/keep-your-powershell-script-open-when-executed
param ( $Show )
if ( !$Show )
{
PowerShell -NoExit -File $MyInvocation.MyCommand.Path 1
return
}
Pasting that to the top of the script is what made it work.
I start the script from command line with
powershell.exe -noexit -command "& \path\to\script.ps1"
A relatively short path to specifying a Powershell script to execute at startup in Windows could be:
Click the Windows-button (Windows-button + r)
Enter this:
shell:startup
Create a new shortcut by rightclick and in context menu choose menu item: New=>Shortcut
Create a shortcut to your script, e.g:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command "C:\Users\someuser\Documents\WindowsPowerShell\Scripts\somesscript.ps1"
Note the use of -NoProfile
In case you put a lot of initializing in your $profile file, it is inefficient to load this up to just run a Powershell script. The -NoProfile will skip loading your profile file and is smart to specify, if it is not necessary to run it before the Powershell script is to be executed.
Here you see such a shortcut created (.lnk file with a Powershell icon with shortcut glyph):
This worked for me. Created a Scheduled task with below details:
Trigger : At startup
Actions:
Program/script : powershell.exe
Arguments : -file
You can see scripts and more scheduled for startup inside Task Manager in the Startup tab. Here is how to add a new item to the scheduled startup items.
First, open up explorer to shell:startup location via start-button => run:
explorer shell:startup
Right click in that folder and in the context menu select a new shortcut. Enter the following:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile
-Command "C:\myfolder\somescript.ps1"
This will startup a Powershell script without starting up your $profile scripts for faster execution. This will make sure that the powershell script is started up.
The shell:startup folder is in:
$env:APPDATA\Microsoft\Windows
And then into the folder:
Start Menu\Programs\Startup
As usual, Microsoft makes things a bit cumbersome for us when a path contains spaces, so you have to put quotes around the full path or just hit tab inside Powershell to autocomplete in this case.
If you do not want to worry about execution policy, you can use the following and put into a batch script. I use this a lot when having techs at sites run my scripts since half the time they say script didnt work but really it's cause execution policy was undefined our restricted. This will run script even if execution policy would normally block a script to run.
If you want it to run at startup. Then you can place in either shell:startup for a single user or shell:common startup for all users who log into the PC.
cmd.exe /c Powershell.exe -ExecutionPolicy ByPass -File "c:\path\to\script.ps1"
Obviously, making a GPO is your best method if you have a domain and place in Scripts (Startup/Shutdown); under either Computer or User Configurations\Windows Settings\Scripts (Startup/Shutdown).
If you go that way make a directory called Startup or something under **
\\yourdomain.com\netlogon\
and put it there to reference in the GPO. This way you know the DC has rights to execute it. When you browse for the script on the DC you will find it under
C:\Windows\SYSVOL\domain\scripts\Startup\
since this is the local path of netlogon.
Execute PowerShell command below to run the PowerShell script .ps1 through the task scheduler at user login.
Register-ScheduledTask -TaskName "SOME TASKNAME" -Trigger (New-ScheduledTaskTrigger -AtLogon) -Action (New-ScheduledTaskAction -Execute "${Env:WinDir}\System32\WindowsPowerShell\v1.0\powershell.exe" -Argument "-WindowStyle Hidden -Command `"& 'C:\PATH\TO\FILE.ps1'`"") -RunLevel Highest -Force;
-AtLogOn - indicates that a trigger starts a task when a user logs on.
-AtStartup - indicates that a trigger starts a task when the system is started.
-WindowStyle Hidden - don't show PowerShell window at startup. Remove if not required.
-RunLevel Highest - run PowerShell as administrator. Remove if not required.
P.S.
If necessary execute PowerShell command below to enable PowerShell scripts execution.
Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy Unrestricted -Force;
Bypass - nothing is blocked and there are no warnings or prompts.
Unrestricted - loads all configuration files and runs all scripts. If you run an unsigned script that was downloaded from the internet, you're prompted for permission before it runs.
I 'm aware that people around here don't need a tool like this. But I think it will be useful especially for novice users. Auto start tool It is a Portable freeware which designed to simplify the process to automatically launch an App or script when you login to Windows. It offers 3 different options for autostart
Task Scheduler
Startup folder
Registry run key
The best part of the tool is supports powershell scripts (.Ps1) . this means that you can run a Powershell script automatically at system startup with all 3 methods.
Download
https://disk.yandex.com.tr/d/dFzyB2Fu4lC-Ww
Source:
https://www.portablefreeware.com/forums/viewtopic.php?f=4&t=25761
One thing I found. if you are using Write-Host within your PowerShell scripts, and are also using Task Scheduler (as shown in the posts above), you don't get all the output from the command line.
powershell.exe -command C:\scripts\script.ps1 >> "C:\scripts\logfile.log"
In my case, I was only seeing output from commands that ran successfully from the PowerShell script.
My conclusion so far is PowerShell uses Out-File to output to another command or in this case a log file.
So if you use *> instead of >> you get all the output from the CLI for your PowerShell script, and you can keep using Write-Host within your script.
powershell.exe -command C:\scripts\script.ps1 *> "C:\scripts\logfile.log"
https://lazyadmin.nl/powershell/output-to-file/
You can also run the script in the background, regardless of user login.
Within your task in Task Scheduler set "Run whether user is logged on or not", and then in the password prompt type your hostname\username then your password (In my case an account with Admin permissions).
I used Set-ExecutionPolicy RemoteSigned -Scope CurrentUser to get around the script execution problem. I still would have preferred to run it on a per-process basis though. A problem for another time.

How do I run powershell scripts without admin rights?

If I try to change the execution policy, I get a message that says I can't modify the registry because I'm not an administrator.
It seems like this should be possible, since I can run batch files and other .exe and .com programs.
If your domain administrator hasn't forbidden it, you can do this:
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser
This changes the default execution policy for PowerShell sessions run under the current user, rather than setting it for all users on the machine.
If you instead want to change the execution policy for just the current PowerShell session, you can use this command:
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
However, if your domain administrator is using the "Turn on Script Execution" group policy, you will not be able to change your execution policy at all. The group policy setting makes the Set-ExecutionPolicy cmdlet ineffective.
You can try and set the policy of the process itself.
powershell.exe -ExecutionPolicy bypass
if you want to have an easy way to run a script myscript.ps1 from the windows shell then all you need is a bat Runmyscript.bat with the following contents:
type myscript.ps1 | powershell -
So simple it makes me wonder why you can't just run the ps1 in the first place, but there we go.
A generic version that prompts for userinput to type the name of the script would be:
set /p filename="Type name of script here: "
type %filename% | powershell -
I suppose if you wanted to, you could also write a generic vbscript script that opens any file in powershell using a dialogue box using this http://todayguesswhat.blogspot.co.uk/2012/08/windows-7-replacement-for.html
how about
$script = Get-Content .\test.ps1
Invoke-Expression $script
This works for me. Try this: cmd /min /C "set __COMPAT_LAYER=RUNASINVOKER && start "" %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
The third technique I've found elsewhere on the internet is to use
powershell.exe -EncodedCommand XXXXXXX
where XXXXXXX is the result of
$code = {
#powershell script goes here.
}
}
[convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($code))
Ref:
http://dmitrysotnikov.wordpress.com/2008/06/27/powershell-script-in-a-bat-file/