See PowerShell Verbose output in Visual Studio Code - powershell

I am using Visual Studio Code 1.17.2 with the PowerShell extension (1.4.3). I have Write-Verbose statements in my code. When I run the PowerShell script, the Verbose output doesn't seem to go anywhere. How do I request that output be shown?

The simplest approach is to execute:
$VerbosePreference = 'Continue'
in the integrated PowerShell console before invoking your script (and executing $VerbosePreference = 'SilentlyContinue' later to turn verbose output back off, if needed).
From that point on:
running a script (starting it with (F5) or without (Ctrl+F5) the debugger)
highlighting a section of code and running the selection (F8)
will make Write-Verbose calls produce output.
If you want to preset $VerbosePreference = 'Continue' every time the integrated console starts, put that statement in the $PROFILE file:
If your VS Code-specific $PROFILE file already exists, simply run psedit $PROFILE from the integrated console.
If not, create the file first from the integrated console: New-Item -Type File $PROFILE

Verbose output by default it not shown, you need to declare [CmdletBinding()] in your function or script to enable the -Verbose parameter to be passed through in order have the option to display Verbose output.
You can 'cheat' though and pass -Verbose to Write-Verbose "Hello Verbose" -Verbose itself and that stream will appear in the console.
(Tested with your two matching versions for VSCode and Extension on Mac (PS6 Beta 8) and can see the verbose output).
function Test-Verbose {
# This enables the function to have '-Verbose'.
[CmdletBinding()]
param()
Write-Output "Hello output!"
# Will only be displayed if 'Test-Verbose' is passed '-Verbose'.
Write-Verbose "Hello verbose"
}
Test-Verbose -Verbose

Related

enable Write-Verbose behavior in powershell script

In a powershell script file.ps1, I have
Write-Host "here is a host message"
Write-Verbose "here is a verbose message"
When file.ps1 is run in Windows Terminal using Powershell 7, not all messages are written to the console.
PS> .\file.ps1
here is a host message
I would like to be able to pass -Verbose so Write-Verbose is seen:
PS> .\file.ps1 -Verbose
here is a host message
here is a verbose message
What does script file.ps1 need to enable verbose messages?
You would need to add [cmdletbinding()] to your script to enable CommonParameters:
script.ps1
[cmdletbinding()]
param()
Write-Host "here is a host message"
Write-Verbose "here is a verbose message"
From host:
PS /> ./script.ps1 -Verbose
here is a host message
VERBOSE: here is a verbose message
If you can't edit the script, you can also user set the VerbosePrefrence to Continue in the shell that calls the script.
$VerbosePreference = "Continue"
This will enable Verbose output on all function you are goint to execute.
Check out Microsofts Help about Prefences.
There are many usefull more.
If you ike to enable Verbose Output for only a specific CmdLet, you can use $PSDefaultParameterValues to assign a default Parameter to this function:
$PSDefaultParameterValues.Add("MyCmdLet:Verbose",$true)
this would enable Verbose Output for "MyCmdLet".
However, be carefull when using $PSDefaultParameterValues, since you can really mess things up, especially if you call other script, since the default parameter values will there be affected aswell.

How to generate comprehensive log file from PowerShell script

I am trying to write a migration/deployment script to deploy an application to an environment (DEV, QA, PROD) and I need to be able to fully log all output. This would include any status message I specifically put in the output stream (not a problem) as well as verbose output from all commands. For instance, if I'm calling Copy-Item, I want the full listing of each item copied.
I'm trying to figure out a way to do this throughout the entire script reliably. In other words, I don't want to rely on including -Verbose on every command (as it could be missed when someone else maintains the script in the future). I've been looking at things like $VerbosePreference as well as the possibility of calling my main cmdlet/function using -Verbose, with the hope being that either would apply to the entire script. But that appears to not be the case. While any Write-Verbose commands I use respect either approach, calls to Copy-Item only show the verbose listing if I specifically pass -Verbose to it. I'm really hoping I'm just missing something! Surely this is possible to do what I'm wanting!
Sample code:
function Main () {
[CmdletBinding()]
Param()
Begin {
Copy-Item C:\Temp\src\* -Destination C:\Temp\dest -Recurse -Force
Write-Output 'Main output'
Write-Verbose 'Main verbose'
Child
}
}
function Child () {
[CmdletBinding()]
Param()
Begin {
Copy-Item C:\Temp\src\* -Destination C:\Temp\dest -Recurse -Force
Write-Output 'Child output'
Write-Verbose 'Child verbose'
}
}
$VerbosePreference = 'SilentlyContinue'
Write-Output $VerbosePreference
Main
''
Main -Verbose
''
''
$VerbosePreference = 'Continue'
Write-Output $VerbosePreference
Main
''
Main -Verbose
Produces output:
SilentlyContinue
Main output
Child output
Main output
VERBOSE: Main verbose
Child output
VERBOSE: Child verbose
Continue
Main output
VERBOSE: Main verbose
Child output
VERBOSE: Child verbose
Main output
VERBOSE: Main verbose
Child output
VERBOSE: Child verbose
So, clearly $VerbosePreference and -Verbose are affecting the Write-Verbose, but that's about it. The Copy-Item is not displaying ANY output whatsoever (though it will if I specifically use -Verbose directly on that command).
Any thoughts? Am I going about this all wrong? Please help!
How about leveraging...
Tip: Create a Transcript of What You Do in Windows PowerShell
The PowerShell console includes a transcript feature to help you
record all your activities at the prompt. As of this writing, you
cannot use this feature in the PowerShell application. Commands you
use with transcripts include the following:
https://technet.microsoft.com/en-us/library/ff687007.aspx
... or the approaches provided / detailed here:
Enhanced Script Logging module (automatic console output captured to
file)
Automatically copy PowerShell console output to a log file (from
Output, Error, Warning, Verbose and Debug streams), while still
displaying the output at the console. Log file output is prepended
with date/time and an indicator of which stream originated the line
https://gallery.technet.microsoft.com/scriptcenter/Enhanced-Script-Logging-27615f85
Write-Log PowerShell Logging Function
The Write-Log PowerShell advanced function is designed to be a simple
logger function for other cmdlets, advanced functions, and scripts.
Often when running scripts one needs to keep a log of what happened
and when. The Write-Log accepts a string and a path to a log file and
ap
https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
* Update as per the OP comment*
See this discussion...
Powershell apply verbosity at a global level
where the -verbose flag is not supplied to the ni command. Is there a
way to set the Verbosity at a global PSSession level if I were to run
this script to force verbosity? The reason I ask is that I have a
group of about 60 scripts which are interdependent and none of these
supply -verbose to any commands they issue and I'd like to see the
entire output when I call the main entry point powershell script.
Powershell apply verbosity at a global level
Use PowerShell Default Parameter Values to Simplify Scripts
Changing default parameter values
When I was asked to write about my favorite Windows PowerShell 3.0
feature, my #1 $PSDefaultParameterValues came to mind immediately.
From my point of view, this was something I was looking for, for a
long time.
How does it work? With $PSDefaultParameterValues, you can define
(overwrite) default values of parameters for Windows PowerShell
cmdlets.
https://blogs.technet.microsoft.com/heyscriptingguy/2012/12/03/use-powershell-default-parameter-values-to-simplify-scripts/
See also:
Script Tracing and Logging
While Windows PowerShell already has the LogPipelineExecutionDetails
Group Policy setting to log the invocation of cmdlets, PowerShell’s
scripting language has plenty of features that you might want to log
and/or audit. The new Detailed Script Tracing feature lets you enable
detailed tracking and analysis of Windows PowerShell scripting use on
a system. After you enable detailed script tracing, Windows PowerShell
logs all script blocks to the ETW event log,
Microsoft-Windows-PowerShell/Operational. If a script block creates
another script block (for example, a script that calls the
Invoke-Expression cmdlet on a string), that resulting script block is
logged as well.
Logging of these events can be enabled through the Turn on PowerShell
Script Block Logging Group Policy setting (in Administrative Templates
-> Windows Components -> Windows PowerShell).
https://learn.microsoft.com/en-us/powershell/wmf/5.0/audit_script

Using read-host cmdlet when execute powershell script file in MSBuild

All , I am trying to execute a external power shell script file in the MSBuild. But every time when PS run the cmdlet Read-Host. The MSBuild seems stop. and doesn't prompt me to input . I don't know what happen to it . Seems the console is in deadlock..thanks.
The testloop.ps1 code is shown below.
$ErrorActionPreference = 'Stop'
$error.clear()
function GetAzureSubScription()
{
read-host "please input something :"
}
write-host "Get into script"
GetAzureSubScription
The MSBuild code is below (wrapped for clarity):
<Exec WorkingDirectory="$(MSBuildProjectDirectory)"
Command="$(windir)\system32\WindowsPowerShell\v1.0\powershell.exe -f
E:\Work\AutoDeploy\testloop.ps1" />
So yes, the console (just a minor point - powershell.exe does not run under cmd.exe - they are separate processes, but they both use a console window) window is hidden so it will appear to freeze when prompting for input. The simplest option here is to override the read-host function with a version that will prompt using a graphical window. Add the start of your script, add the following function:
# override the built in prompting, just for this script
function read-host($prompt) {
$x = 0; $y = 0;
add-type -assemblyname microsoft.visualbasic
[Microsoft.VisualBasic.Interaction]::InputBox($prompt,
"Interactive", "(default value)", $x, $y)
}
Now your script will be able to prompt for values. Also, you should run powershell.exe with the -noninteractive argument to catch any other places where you are accidentally calling interactive host functions. It will not stop the above function from working though.
The MSBuild Exec tasks starts cmd.exe and let that execute the command. MSbuild has to channel the writes to the console through since the cmd.exe window itself is invisible. It seems the writes do get through, but the reads do not. You can see the same effect if instead of calling powershell you exec a command like "del c:\temp\somefile.txt /p" which asks for confirmation. Although that way it doesn't block, but there is also no way of giving an answer.
That it does not handle reads properly is not that strange. It is a build script, so it should just build and not ask questions. My advice is to have the MSBuild script run without asking questions. If you really need to ask questions, then ask them before calling MSBuild.

PowerShell 2.0 - Running scripts for the command line call vs. from the ISE

After writing deployment scripts from within the ISE, we need our continuous integration (CI) server to be able to run them automatically, i.e. from the command line or via a batch file.
I have noticed some significant differences between the following calls:
powershell.exe -File Script.ps1
powershell.exe -Command "& '.\Script.ps1'"
powershell.exe .\Script.ps1
Some simple examples:
When using -File, errors are handled in the exact same way as the ISE.
The other two calls seem to ignore the $ErrorActionPreference variable, and do not catch Write-Error in try/catch blocks.
When using pSake:
The last two calls work perfectly
Using the ISE or the -File parameter will fail with the following error:
The variable '$script:context' cannot be retrieved because it has not been set
What are the implications of each syntax, and why they are behaving differently? I would ideally like to find a syntax that works all the time and behaves like the ISE.
Not an answer, just a note.
I searched for explanation of -file parameter. Most sources say only "Execute a script file.". At http://technet.microsoft.com/en-us/library/dd315276.aspx I read
Runs the specified script in the local scope ("dot-sourced"), so that the functions
and variables that the script creates are available in the current session. Enter
the script file path and any parameters.
After that I tried to call this:
powershell -command ". c:\temp\aa\script.ps1"
powershell -file c:\temp\aa\script.ps1
powershell -command "& c:\temp\aa\script.ps1"
Note that first two stop after Get-Foo, but the last one doesn't.
The problem I describe above is related to modules -- if you define Get-Foo inside script.ps1, all the 3 calls I described stop after call to Get-Foo.
Just try to define it inside the script.ps1 or dotsource the file with Get-Foo and check it. There is a chance it will work :)
Here is a concrete example of the behaviour I described.
MyModule.psm1
function Get-Foo
{
Write-Error 'Failed'
}
Script.ps1
$ErrorActionPreference = 'Stop'
$currentFolder = (Split-Path $MyInvocation.MyCommand.Path)
Import-Module $currentFolder\MyModule.psm1
try
{
Get-Foo
Write-Host "Success"
}
catch
{
"Error occurred"
}
Running Script.ps1:
From the ISE, or with the -File parameter
will output "Error occurred" and stop
From the command line without the -File parameter
will output "Failed" followed by "Success" (i.e. not caught)

Powershell window disappears before I can read the error message

When I call a Powershell script, how can I keep the called script from closing its command window. I'm getting an error and I'm sure I can fix it if I could just read the error.
I have a Powershell script that sends an email with attachment using the .NET classes. If I call the script directly by executing it from the command line or calling it from the Windows Scheduler then it works fine. If I call it from within another script (IronPython, if that matters) then it fails. All scenarios work fine on my development machine. (I really do have to get that "Works on My Machine" logo!) I've got the call to Powershell happening in a way that displays a command window and I can see a flicker of red just before it closes.
Sorry: Powershell 1.0, IronPython 1.1
Solution: powershell -noexit d:\script\foo.ps1
The -noexit switch worked fine. I just added it to the arguments I pass from IronPython. As I suspected, it's something that I can probably fix myself (execution policy, although I did temporarily set as unrestricted with no effect, so I guess I need to look deeper). I'll ask another question if I run into trouble with that.
Thanks to all for the help. I learned that I need to investigate powershell switches a little more closely, and I can see quite a few things that will prove useful in the future.
Try with the -noexit switch:
powershell -noexit d:\script\foo.ps1
You basically have 3 options to prevent the PowerShell Console window from closing, that I describe in more detail on my blog post.
One-time Fix: Run your script from the PowerShell Console, or launch the PowerShell process using the -NoExit switch. e.g. PowerShell -NoExit "C:\SomeFolder\SomeScript.ps1"
Per-script Fix: Add a prompt for input to the end of your script file. e.g. Read-Host -Prompt "Press Enter to exit"
Global Fix: Change your registry key to always leave the PowerShell Console window open after the script finishes running.
Here are the registry keys to modify for option #3:
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Applications\powershell.exe\shell\open\command]
#="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -NoExit \"& \\\"%1\\\"\""
[HKEY_CLASSES_ROOT\Microsoft.PowerShellScript.1\Shell\0\Command]
#="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -NoExit \"-Command\" \"if((Get-ExecutionPolicy ) -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & \\\"%1\\\"\""
See my blog for more information and a .reg file that will apply these registry changes automatically.
I've needed this before and usually I didn't want to modify the script (typically for scripts fired off from the Task Scheduler). I just wanted to see what was spit out to console.
All you need to do is just append a Read-Host command after the script invocation e.g.:
PowerShell.exe -command { .\foo.ps1; read-host "Press enter key to continue" }
BTW the problem with using Start-Transcript is that it doesn't capture EXE output. And any form of attempted logging in V1 and even V2 with the standard host will not capture the verbose, debug, progress or warning streams. You can only see these by viewing the associated host window.
One cheesy but effective way to capture all script output (stdout, stderr, verbose, warning, debug) is to use another host like cmd.exe e.g.:
cmd.exe /c powershell.exe "$pwd\foo.ps1" > foo.log
I am generaly fine with scripts autoclosing except when an error occurs, where I need to see the error. Assuming you have not changed $ErrorActionPreference away from the default 'Continue', then for the behaviour I described do this at the end of you script
if ($Error)
{
Pause
}
There is no ordinary Try...Catch construction in Powershell; however you can trap exceptions instead and react properly.
I.E:
Function Example() {
trap [Exception] {
write-host "We have an error!";
write-error $("ERROR: " + $_.Exception.Message);
sleep 30;
break;
}
write-host "Hello world!";
throw "Something very bad has happened!";
}
You can also simulate Try...Catch construction:
Function Example2() {
${
write-host "Our try clause...";
throw "...caused an exception! It hurts!";
}
trap [Exception] {
write-error $_.Exception.Message;
sleep 30;
continue;
}
Of course as soon as you will trap an exception, you can log it, sleep, or whatever you want with the error message. My examples just sleep, allowing you to read what happened, but it's much better to log all the errors. (The simplest way is to redirect them with >>).
Look also at:
http://huddledmasses.org/trap-exception-in-powershell/
A quick and dirty solution is to use CTRL+S to halt the scrolling of the display and CTRL+Q to resume it.
You have three options:
Do a catch in the script (if using
Powershell V2)
Write a dummy
script which catches and redirects
stdout which you can then access as a
variable from your IronPython script.
VBS/Wscript Intro An addition to
this is just liberally drop
Read-Host commands everywhere,
and hit return to page through.
Rather than outputting anything to the shell, wrap your powershell script in a second script that redirects all output to a log file.
PS C:> myscript.ps1 |Out-File myscript.log
Create run_ps_script.bat file containing
#PowerShell.exe -command "try { %1 } finally { read-host 'Press ENTER...' }"
and make it default program to open PowerShell scrips.
My solution was to execute the script with a command line from the console window instead of right-clicking the file -> execute with powershell.
The console keeps displaying the error messages,
even though the execution of the script ended.
Have you thought about redirecting stdout and stderr to a file ex:
./ascript.ps1 >logs 2>&1
Note: You can create wrapper script in powershell that calls your powershell script with all necessary redirections.
My .PS1 script ran fine from the Powershell console but when "double-clicking" or "right-click open with powershell" it would exhibit the 'open/close' problem.
The Fix for me was to rename the script folder to a Name Without Spaces.
Then it all worked - Windows couldn't deal with
"C:\This is my folder\myscript.ps1" but
"C:\This_is_my_folder\myscript.ps1" worked just fine
A couple more ideas...You could use the start-sleep cmdlet at the end of you script to give you enough time to review the error.
You might also be able to use start-transcript to record the session to a text file.