Capturing output/error when invoking PowerShell script - powershell

I am trying to invoke a PowerShell script from Puppet. The issue is even if the PowerShell script fails on remote box, it still shows successful run as shown below:
Notice: /Stage[main]/Main/Node[dev.abc.com]/Exec[Check UAC]/returns: executed successfully
Content of my node block in site.pp:
exec { 'Check UAC':
command => '& C:\temp\check_uac.ps1',
provider => powershell,
logoutput => 'on_failure',
}
The script failed when I tried running from PowerShell console stating that execution policy was set to Restricted.
PS C:\> C:\temp\check_uac.ps1
C:\temp\check_uac.ps1 : File C:\temp\check_uac.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.
At line:1 char:1
+ C:\temp\check_uac.ps1
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : SecurityError: (:) [], PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess
How can I capture the above error when invoking the script from Puppet to avoid surprises later?

You need to set an exit code to have Puppet pick up failures:
exec { 'Check UAC':
command => '& C:\temp\check_uac.ps1; exit (1 - [int]$?)',
provider => powershell,
logoutput => 'on_failure',
}
However, since the powershell provider should normally bypass execution policies, the error you observed means that the execution policy is enforced via group policy.
A better approach would be to fix the execution policy in your environment, so that it doesn't prohibit script execution, and have your script return an exit code to indicate whether or not UAC is enabled.
If for some obscure reason you cannot fix the actual problem and have to deal with the symptoms instead, you need to exec PowerShell directly, like this:
exec { 'Check UAC':
command => 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -NoProfile -NoLogo -NonInteractive -Command "& {C:\temp\check_uac.ps1; exit (1 - [int]$?)}"',
logoutput => 'on_failure',
}
The powershell provider won't work in this scenario.
If all you want is to determine whether or not execution of PowerShell scripts is restricted, I would consider a dynamic fact a better way to determine that information, e.g. with a batch script in %AllUsersProfile%\PuppetLabs\facter\facts.d:
#echo off
for /f "tokens=* delims=" %%p in (
'powershell -NoProfile -NonInteractive -NoLogo -Command "Get-ExecutionPolicy"'
) do set "policy=%%p"
if /i "%policy%"=="restricted" (
echo ExecutionRestricted=true
) else (
echo ExecutionRestricted=false
)

Related

Set-ExecutionPolicy Error when not being called

When I run any script from a .ps1 file on my server I receive an error about the Set-ExcutionPolicy being successful but being overridden by a higher scope.
However none of the code I am running has anything to do with execution policies or changing them. Any Idea why I'm getting this error?
This is on a Windows 2012 R2 server where execution policy for all levels is set to remote signed. I'm running on PowerShell V4.0
If I open PowerShell or the ISE and type in the command it completes without showing the error it only occurs when I try and run a script from a .ps1 file.
This is the error:
Set-ExecutionPolicy : Windows PowerShell updated your execution policy
successfully, but the setting is overridden by a policy defined at a more
specific scope. Due to the override, your shell will retain its current
effective execution policy of RemoteSigned. Type "Get-ExecutionPolicy -List"
to view your execution policy settings. For more information please see
"Get-Help Set-ExecutionPolicy".
At line:1 char:46
+ if((Get-ExecutionPolicy ) -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied: (:) [Set-ExecutionPolicy], SecurityException
+ FullyQualifiedErrorId : ExecutionPolicyOverride,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand
The "Run with PowerShell" context menu entry for .ps1 files invokes the following commandline:
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "if((Get-ExecutionPolicy ) -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & '%1'"
It's stored in the registry key HKCU\Microsoft.PowerShellScript.1\Shell\0\Command. Since you have the execution policy defined via Group Policy, setting a conflicting execution policy in the Process scope whenever you're running a PowerShell script via its context menu causes the error you observed.
Change the commandline in the registry to something like this:
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -File "%L"
and the error will disappear.

How to properly quote a PowerShell command path when used from CMD

Baseline command that works properly:
The following command is being executed in CMD prompt and runs successfully.
"C:\Program Files\PowerShell\6.0.4\pwsh.exe" -NoLogo -NoProfile -NonInteractive -Command "&{D:\FooBar\myscript.ps1 -DependentAssembliesDirectoryPath 'D:\FooBar' -OutputPath 'D:\Baz Qux\output' -DocumentVersion 'whatever' -VisualStudioXmlDocumentationPaths 'D:\Baz Qux\input\my.xml' -AssemblyPaths 'D:\Baz Qux\input\my.exe','D:\Baz Qux\input\my1.dll','D:\Baz Qux\input\my2.dll','D:\Baz Qux\input\my3.dll' -MajorOpenApiSpecificationVersion 3 -MinorOpenApiSpecificationVersion 0 -Format YAML -DocumentDescriptionFilePath 'D:\Baz Qux\input\my.md'}; EXIT $LASTEXITCODE"
However, when a space is introduced to the path of myscript.ps1, the command no longer works. This is expected since I need to properly quote the path. I cannot figure out the proper way of quoting though.
Invalid attempt at quoting the command:
I thought this would have worked based on the technique of quoting other paths in my command, but this doesn't work.
"C:\Program Files\PowerShell\6.0.4\pwsh.exe" -NoLogo -NoProfile -NonInteractive -Command "&{'D:\Foo Bar\myscript.ps1' -DependentAssembliesDirectoryPath 'D:\Foo Bar' -OutputPath 'D:\Baz Qux\output' -DocumentVersion 'whatever' -VisualStudioXmlDocumentationPaths 'D:\Baz Qux\input\my.xml' -AssemblyPaths 'D:\Baz Qux\input\my.exe','D:\Baz Qux\input\my1.dll','D:\Baz Qux\input\my2.dll','D:\Baz Qux\input\my3.dll' -MajorOpenApiSpecificationVersion 3 -MinorOpenApiSpecificationVersion 0 -Format YAML -DocumentDescriptionFilePath 'D:\Baz Qux\input\my.md'}; EXIT $LASTEXITCODE"
This command results in a bunch of errors like,
At line:1 char:119
+ ... ionsDocumentGeneration.ps1' -DependentAssembliesDirectoryPath 'D:\Ope ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token '-DependentAssembliesDirectoryPath' in expression or statement.
At line:1 char:153
+ ... rectoryPath 'D:\Foo Bar' -OutputPath ...
+ ~~~~~~~~~~~~
Unexpected token ''D:\Foo Bar'' in expression or statement.
Again, since it can be a little hard to see the difference, the delta from the baseline command that works and the second command is that &{D:\FooBar\myscript.ps1 changed to &{'D:\Foo Bar\myscript.ps1' to introduce a space in the path and attempt quoting.
Please Note
I cannot invoke the command in PowerShell because it is out of my control. It must be invoked in cmd.exe prompt.
The problem is that you need to use & in PowerShell in order to invoke a command name / executable file path that is quoted and/or specified via a variable:
Therefore, replace:
"&{'D:\Foo Bar\myscript.ps1' ... }; exit $LASTEXITCODE"
with:
"& { & 'D:\Foo Bar\myscript.ps1' ... }; exit $LASTEXITCODE"
That said, there's no reason to wrap the invocation of your *.ps1 script in a script-block invocation (& { ... }), so you can simplify your command to:
"& 'D:\Foo Bar\myscript.ps1' ...; exit $LASTEXITCODE"

Unable to install Just In Time Debugger on Windows 2012 R2

I have a clean Windows 2012 R2 with SharePoint 2016. Installed Visual Studio Community 2017, when I try to install the JustInTime Debugger using the VS update I get the following error:
The product failed to install the listed workloads and components due to one or more package failures.
Incomplete components
Just-In-Time debugger (Microsoft.VisualStudio.Component.Debugger.JustInTime,version=15.0.26208.0)
You can search for solutions using the information below, modify your selections for the above workloads and components and retry the installation, or remove the product from your machine.
Following is a collection of individual package failures that led to the incomplete workloads and components above. To search for existing reports of these specific problems, please copy and paste the URL from each package failure into a web browser. If the issue has already been reported, you can find solutions or workarounds there. If the issue has not been reported, you can create a new issue where other people will be able to find solutions or workarounds.
Package 'Microsoft.VisualStudio.Debugger.JustInTime,version=15.0.26424.2' failed to install.
Search URL: https://aka.ms/VSSetupErrorReports?q=PackageId=Microsoft.VisualStudio.Debugger.JustInTime;PackageAction=Install;ReturnCode=1
Impacted components
Just-In-Time debugger (Microsoft.VisualStudio.Component.Debugger.JustInTime,version=15.0.26208.0)
Log
C:\Users\Administrator\AppData\Local\Temp\dd_setup_20170622105625_003_Microsoft.VisualStudio.Debugger.JustInTime.log
Details
Command executed: "c:\windows\syswow64\\windowspowershell\v1.0\powershell.exe" -ExecutionPolicy Bypass -InputFormat None -NoLogo -NonInteractive -NoProfile -Command "$ErrorActionPreference="""Stop""";$VerbosePreference="""Continue""";$Action="""Modify""";$AppId="""9180617e""";$Packages="""Microsoft.VisualStudio.Component.CoreEditor,Microsoft.VisualStudio.Component.NuGet,Microsoft.Net.Component.4.6.1.SDK,Microsoft.VisualStudio.Component.TypeScript.2.2,Microsoft.VisualStudio.Component.JavaScript.TypeScript,Component.WebSocket,Microsoft.VisualStudio.Component.JavaScript.Diagnostics,Microsoft.VisualStudio.Component.Roslyn.Compiler,Microsoft.VisualStudio.Component.Static.Analysis.Tools,Microsoft.VisualStudio.Component.Roslyn.LanguageServices,Microsoft.VisualStudio.Component.PortableLibrary,Microsoft.VisualStudio.Component.SQL.CLR,Microsoft.VisualStudio.Component.VisualStudioData,Microsoft.VisualStudio.Component.AppInsights.Tools,Microsoft.Component.ClickOnce,Microsoft.Net.Component.4.5.TargetingPack,Microsoft.VisualStudio.Component.Debugger.JustInTime,Microsoft.Component.MSBuild,Microsoft.Net.Component.4.6.1.TargetingPack,Microsoft.Net.ComponentGroup.DevelopmentPrerequisites,Microsoft.VisualStudio.Component.TextTemplating,Microsoft.VisualStudio.Component.ManagedDesktop.Core,Microsoft.Net.Component.4.TargetingPack,Microsoft.Net.Component.4.5.2.TargetingPack,Microsoft.VisualStudio.Component.IISExpress,Microsoft.VisualStudio.Component.WebDeploy,Microsoft.VisualStudio.Component.SQL.NCLI,Microsoft.VisualStudio.Component.SQL.LocalDB.Runtime,Microsoft.VisualStudio.Component.SQL.ADAL,Microsoft.VisualStudio.Component.Common.Azure.Tools,Microsoft.VisualStudio.Component.SQL.CMDUtils,Microsoft.VisualStudio.Component.SQL.SSDT,Microsoft.VisualStudio.Component.SQL.DataSources,Microsoft.VisualStudio.Component.Web""";[io.file]::ReadAllText("""C:\ProgramData\Microsoft\VisualStudio\Packages\Microsoft.VisualStudio.Debugger.JustInTime,version=15.0.26424.2\RegisterJustInTimeDebugger.ps1""") | Invoke-Expression; if (!$?) { exit 1603 } elseif ($LastExitCode) { exit $LastExitCode }"
Return code: 1
Return code details: Incorrect function.
In the log:
[10c8:002a][2017-06-22T10:32:43] c:\windows\syswow64\\windowspowershell\v1.0\powershell.exe -ExecutionPolicy Bypass -InputFormat None -NoLogo -NonInteractive -NoProfile -Command "$ErrorActionPreference="""Stop""";$VerbosePreference="""Continue""";$Action="""Modify""";$AppId="""9180617e""";$Packages="""Microsoft.VisualStudio.Component.CoreEditor,Microsoft.VisualStudio.Component.NuGet,Microsoft.Net.Component.4.6.1.SDK,Microsoft.VisualStudio.Component.TypeScript.2.2,Microsoft.VisualStudio.Component.JavaScript.TypeScript,Component.WebSocket,Microsoft.VisualStudio.Component.JavaScript.Diagnostics,Microsoft.VisualStudio.Component.Roslyn.Compiler,Microsoft.VisualStudio.Component.Static.Analysis.Tools,Microsoft.VisualStudio.Component.Roslyn.LanguageServices,Microsoft.VisualStudio.Component.PortableLibrary,Microsoft.VisualStudio.Component.SQL.CLR,Microsoft.VisualStudio.Component.VisualStudioData,Microsoft.VisualStudio.Component.AppInsights.Tools,Microsoft.Component.ClickOnce,Microsoft.Net.Component.4.5.TargetingPack,Microsoft.VisualStudio.Component.Debugger.JustInTime,Microsoft.Component.MSBuild,Microsoft.Net.Component.4.6.1.TargetingPack,Microsoft.Net.ComponentGroup.DevelopmentPrerequisites,Microsoft.VisualStudio.Component.TextTemplating,Microsoft.VisualStudio.Component.ManagedDesktop.Core,Microsoft.Net.Component.4.TargetingPack,Microsoft.Net.Component.4.5.2.TargetingPack,Microsoft.VisualStudio.Component.IISExpress,Microsoft.VisualStudio.Component.WebDeploy,Microsoft.VisualStudio.Component.SQL.NCLI,Microsoft.VisualStudio.Component.SQL.LocalDB.Runtime,Microsoft.VisualStudio.Component.SQL.ADAL,Microsoft.VisualStudio.Component.Common.Azure.Tools,Microsoft.VisualStudio.Component.SQL.CMDUtils,Microsoft.VisualStudio.Component.SQL.SSDT,Microsoft.VisualStudio.Component.SQL.DataSources,Microsoft.VisualStudio.Component.Web""";[io.file]::ReadAllText("""C:\ProgramData\Microsoft\VisualStudio\Packages\Microsoft.VisualStudio.Debugger.JustInTime,version=15.0.26424.2\RegisterJustInTimeDebugger.ps1""") | Invoke-Expression; if (!$?) { exit 1603 } elseif ($LastExitCode) { exit $LastExitCode }"
[10c8:002a][2017-06-22T10:32:43] Error: Invoke-Expression : The term 'Invoke-Expression' 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.
At line:1 char:1812
+ ... bugger.ps1") | Invoke-Expression; if (!$?) { exit 1603 } elseif ($LastExitCode) ...
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Invoke-Expression:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : CommandNotFoundException
It seems that Invoke-Expression is not recognized....how is it possible?

jenkins cannot execute powershell under program files

I am using Jenkins for deployment. I wanted to run a powershell script that copies some files. I have installed "Windows Powershell" plugin for jenkins that will execute the powershell script. My Powershell script looks like below
param (
[string] $targetEnvironment,
[switch] $WhatIf,
[switch] $Compare)
try
{
#do smething here
}
catch
{
}
This script is working fine when i execute it manually. However when run the script using the following command in plugin's input window i get error
Note that, if i copied the "deploymentscript" folder to "C:\deploymentscript" and then change the path in plugin's window then the job runs fine.
It doesnt work when its executing under program files
The error im getting is
First time build. Skipping changelog.
[workspace] $ powershell.exe -NonInteractive -ExecutionPolicy ByPass "& 'C:\Users\CODESC~1\AppData\Local\Temp\hudson2119904511537985474.ps1'"
At C:\Users\username\AppData\Local\Temp\hudson2119904511537985474.ps1:1 char:119
+ ... etaTaskar.ps1' -targetEnvironment demo
+ ~~~~~~~~~~~~~~~~~~
Unexpected token '-targetEnvironment' in expression or statement.
At C:\Users\username\AppData\Local\Temp\hudson2119904511537985474.ps1:1 char:138
+ ... getEnvironment demo
+ ~~~~
Unexpected token 'demo' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParseException
+ FullyQualifiedErrorId : UnexpectedToken
Build step 'Windows PowerShell' marked build as failure
Finished: FAILURE
EDIT1
#petrik You are right, the space in the "Program Files (x86)" folder causing the issue. The solution is to use the following foormat
&("C:\Program Files (x86)\Jenkins\jobs\MyJob\workspace\crconfig\deploymentscript\Deploy.ps1") -targetEnvironment demo
and that works.
Now based on the article here if the powershell scrit fails i want the Jenkin's job to fail too,
So i have tell Hudson to call the powershell script form a windows batch task.
powershell "& {&('C:\Program Files (x86)\Jenkins\jobs\MyJob\workspace\crconfig\deploymentscript\Deploy.ps1') -targetEnvironment $Env:EnvironmentParam; exit $lastexitcode }"
I am not sure if i really need to this in my case ??
So in this case the problem is caused by the fact that the 'Program Files' path has spaces in it. Putting the path to the script into a variable which can then be executed using the call operator.
In order to ensure that Jenkins fails the build if the Powershell script fails several steps need to be taken.
Use the Jenkins powershell plugin. It will pass the powershell exit code on to Jenkins
Set the $ErrorActionPreference to 'Stop' as early as possible. This forces Powershell to halt when exceptions are thrown. The default behaviour is to report the error but then continue.
The script in the Jenkins configuration could look like this:
$ErrorActionPreference = 'Stop'
$scriptPath = 'c:\Program Files (x86)\Jenkins\jobs\MyJob\workspace\crconfig\deploymentscript\deploy.ps1'
& $script -targetEnvironment 'demo'
This should make Jenkins run the script correctly and report an error and stop the build if the script fails.
I did two things to resolve issue:
1) Appended the path to powerscript "c:\Users\\Documents\WindowsPowerShell\profile.ps1" to path variable of system properties.
2) Opened Powershell with administrative permissions and executed: "Set-ExecutionPolicy Unrestricted"
Then restarted windows machine. When i reconnected it to jenkins, my powershell just worked fine.

Batch Script with admin rights Calling PowerShell ends in Error

Currently, I have a Batch Script which has several functions, one among them is to invoke a PowerShell script. The PS_script basically reads & filters mails from outlook and stores certain data into an excel file.
Certain functions in the BS needs admin rights to run successfully. Whenever the PS_Script is invoked with BS with elevated access it gives error.
new-object : Retrieving the COM class factory for component with CLSID {...} failed due to following error: 8008005 Server execution failed {......
Is there anyway to invoke PS_script from BS without elevated access even if the BS is run with admin rights ?
Currently, i use following command in my BS to invoke the PS_script Test.PS1 :
Powershell.exe -ExecutionPolicy RemoteSigned -File C:\Users\%UserName%\Desktop\Test.PS1
If you are sure your problem comes from admin rights you can try to run your powershell script with the username your are executing the script from (or any other user that has the rigths you need)
RunAs /u:domain/username "Powershell.exe -File C:\Users\%UserName%\Desktop\Test.PS1"
Seems that runas doesn't accept the password. But there are other utilites to do that:
Unable to supply password to runas from commandline
Here's what I've got so far.
Wscript.Shell's .ShellExecute method would let you prompt for UAC elevation. If you could break your admin-dependent functions into helper scripts and stick this BatchGotAdmin code at the top of each, that would let you run the rest in the context of a normal user; but it'd still require the user to click "Allow" for each helper script run.
On the opposing side of the coin, using Wscript.Shell's .Exec method to do:
runas /env /netonly /noprofile %userdomain%\%username% "command to run"
... results in bypassing the password and prompt, resulting in the command to be run unauthenticated. This is very interesting and unexpected behavior. Because the "Enter password" prompt is bypassed but the command runs in a separate console anyway, I think it runs as a normal user. However, I haven't found any worthwhile tests with which to confirm.
The problem I've run into with this is that runas called in this way seems to be non-blocking, so it's hard to deal with the output and timing. In case it helps, I'm including my scratch pad test broken code at the bottom of this answer.
Another alternative would be to create a Scheduled Task to run your PowerShell snippet un-elevated.
There's also Wscript.Shell's .Run method that would let you .SendKeys the password which would let you get around the UAC prompt, but it doesn't block either, and requires you to store a password in your script.
I'm afraid I've applied all my ingenuity to the problem but haven't found any solution which doesn't create another problem -- other than possibly the Scheduled Task solution.
Here's the incomplete WshShell.Exec solution referenced in item 2 above:
#if (#CodeSection==#Batch) #then
#echo off
setlocal
call :runAsNonAdmin "cmd /c dir"
goto :EOF
:runAsNonAdmin <command to run>
setlocal enabledelayedexpansion
cscript /nologo /e:JScript "%~f0" "%userdomain%\%username%" "%~1"
endlocal & goto :EOF
#end // end batch / begin JScript chimera
var args = {
user: WSH.Arguments(0),
cmd: WSH.Arguments(1)
},
runas = 'runas /env /netonly /noprofile /user:' + args.user + ' "' + args.cmd + '>stdout 2>stderr"',
osh = WSH.CreateObject('wscript.shell'),
fso = WSH.CreateObject('scripting.filesystemobject'),
proc = osh.Exec(runas),
read = '', file, out = ['stdout','stderr'];
// note: proc.StdOut and proc.StdErr refer *only* to the runas command itself,
// not to the command spawned by it. The spawned command is essentially sandboxed.
while (!proc.Status || !proc.StdErr.AtEndOfStream || !proc.StdOut.AtEndOfStream) {
if (!proc.StdErr.AtEndOfStream) {
WSH.StdErr.WriteLine(proc.StdErr.ReadLine());
} else if (!proc.StdOut.AtEndOfStream) {
WSH.StdOut.Write(proc.StdOut.Read(1));
}
}
for (var i in out) {
if (fso.fileExists(out[i])) {
if (fso.GetFile(out[i]).Size) {
file = fso.OpenTextFile(out[i], 1);
WSH[out[i]].Write(file.ReadAll());
file.Close();
}
var del = osh.Exec('cmd /c del ' + out[i]);
while (!proc.Status) WSH.Sleep(10);
}
}
WSH.Echo(proc.ProcessID + ': status ' + proc.Status + '; exit ' + proc.ExitCode);
WSH.Quit(0);
// Inactive code. Since .exec skips authentication, the following code results in a broken pipe error.
while (!proc.Status || !proc.StdErr.AtEndOfStream || !proc.StdOut.AtEndOfStream) {
if (!proc.StdOut.AtEndOfStream) {
read += proc.StdOut.Read(1);
if (/Enter the password for .*?:/.test(read)) {
proc.StdIn.WriteLine(args.pass);
}
} else if (!proc.StdErr.AtEndOfStream) WSH.Echo(proc.StdErr.ReadLine());
else WSH.Sleep(10);
}