Powershell все ошибки в файл

Вы можете использовать простые текстовые лог файлы для контроля запуска и отслеживания всех действий, которые выполняются при запуске PowerShell скриптов. Это удобно при отладке ошибок, для аудита выполненных скриптом действий. В этой статье мы рассмотрим несколько способов ведения текстовых лог-файлов для ваших PowerShell скриптов.

В самом простом случае, если вам нужно записать вывод информационного сообщения или результатов определенной PowerShell команды в текстовый лог файл, вы можете использовать один из следующих форматов перенаправления вывода в txt файл:

Write-Output "Файлы созданы успешно на $env:computername" >> C:PSLogsTestLog.txt

Add-Content -Path C:PSLogsTestLog.txt -Value "Файлы созданы успешно на $env:computername"

"Файлы созданы успешно на $env:computername" | Out-File -FilePath C:PSLogsTestLog.txt –Append

Во всех случаях команды добавляют в указанный текстовый файл новую строку c указанным вами текстом.

Если вам нужно каждый раз перезатирать содержимое ло-файла, используйте Set-Content.

Add-Content запись информации из скрипта powershell в лог

Главный недостаток такого метода – по такому лог файлу нельзя определить, когда была внесена та или иная запись в лог (произошло событие). Вы можете добавить в лог текущую метку даты, времени (timestamp). Это поможет легко идентифицировать время запуска скрипта и конкретного события в нем.

Для удобства можно создать в PowerShell скрипте отдельную функцию, которая будет сохранять переданные ей данные в лог файл и добавлять время записи информации.

Можно сделать функцию:

$Logfile = "C:PSLogsproc_$env:computername.log"
function WriteLog
{
Param ([string]$LogString)

$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
$LogMessage = "$Stamp $LogString"
Add-content $LogFile -value $LogMessage
}

Теперь, чтобы записать что-то в лог файл, вам нужно вызвать функцию WriteLog.

WriteLog "Скрипт запущен”
WriteLog "Выполняю вычисления…."
Start-Sleep 20
WriteLog "Скрипт выполнен успешно"

Теперь в лог файле содержится время, когда была произведена запись.

функция ведения тектового лог файла с меткой времени в powershell

Можете заменить в своем скрипте вызовы Write-host на LogWrite.

В PowerShell также есть встроенная возможность сохранять в текстовый лог файл все команды и результаты, которые выводятся в консоль PS.

Чтобы начать запись текущей PowerShell сессии, используется командлет Start-Transcript.

После запуска этой команды появляется сообщение, в котором указано, в какой файл сохраняются результаты всех команд. По умолчанию лог файл пишется в профиль текущего пользователя:

Transcript started, output file is C:UsersAdministratorDocumentsPowerShell_transcript.DC01.inhP7egx.20210315041442.txt

Можно указать путь к текстовому файлу так:

Start-Transcript -Append C:PSLogsPSScriptLog.txt

Параметр –Append указывает, что нужно дописывать новые сессию в конец лог файла (не перезатирать его).

Выполните несколько PowerShell команд, которые выводят результаты в консоль. Например, выведем список тяжелых запущенных процессов, запущенных служб и состояние репликации в AD:

Get-Process| where-object {$_.WorkingSet -GT 300000*1024}|select processname,@{l="Used RAM(MB)"; e={$_.workingset / 1mb}} |sort "Used RAM(MB)" –Descending
Get-Service | Where-Object {$_.status -eq 'running'}
Get-ADReplicationFailure -Target DC01

Start-Transcript - ведение полного лога действий для powershell скрипта

Завершите запись сессии для текущей сессии:

Stop-Transcript

Теперь откройте текстовый файл с логом.

пример лога всех действий в powershell

Как вы видите, в текстовом логе отображаются вся история PowerShell команд, которые запускались в скрипте и весь вывод, который выводился в консоль.

В лог файл попадают в том числе все ошибки и предупреждения, что бывает крайне удобно при диагностике и отладке сложных PowerShell скриптов.

Вы можете использовать Start-Transcript/Stop-Transcript в своих PowerShell скриптах чтобы нативно логировать все действия и результаты.

С помощью групповой политики Turn on PowerShell Transcription в Computer Configuration –> Administrative Templates –> Windows Components –> Windows PowerShell можно включить автоматическое логирование всех запускаемых PowerShell команд и выводимых результатов на компьютере. После обновления настроек GPO на компьютере, для каждого запущенного процесса powershell.exe будет создаваться отдельный тектовый лог файл, куда будут записываться все PS команды и результаты результаты.

Групповая политика Turn on PowerShell Transcription

Время на прочтение
2 мин

Количество просмотров 41K

Доброго времени суток, $username!

Хочу поделиться с вами функцией, которую я использую вместо обычного вывода информации на экран или только записи в файл.

Функция была написана для того, чтобы информация выводилась и на экран и в лог (текстовый), предназначается для замены стандартного write-host.

Из вкусностей:

  • Точная дата и время события
  • Тип события
  • Подсчет ошибок и предупреждений
  • Вывод информации цветом (в зависимости от типа события)
  • Формат лога совместим с CSV ([TAB] separated)

Функция объявлена глобально, это значит что в пределах одной сессии достаточно один раз ее проиницилизировать — читай запустить файл с ней.

Варианты использования:
write-log "Hello Хабр!"
14.07.2011 00:22:15 info Hello Хабр!
write-log -message "Hello Хабр!" -type warning

write-log -message "Hello Хабр!" -type error -silent

Правда, путь должен существовать:
write-log -message "Hello Хабр!" -type CustomType logfile c:enteryourpathhere.log

Количество ошибок и предупреждений (за всю сессию или до ручного обнуления переменных) хранятся в $errorcount и $warningcount.

Лично у меня эта функция храниться в файле set-functions.ps1, и в скриптах я ее вызываю так:

Cамое начало любого (там где это необходимо) моего скрипта:

$ver="0.1"
$ProgrammName="SomeScriptName"

try
{
	# Функция вывода информации на экран и записи в лог
	./Set-Functions.ps1 #Инициализация функций
	$global:logfilename = "log`"+ $ProgrammName +".log"
	write-log "$ProgrammName (ver $ver) started."
}
catch 
{		
	return "Error loading functions Set-Functions.ps1"
}

Тело функции write-log:

$ver = "0.4"
$dt=Get-Date -Format "dd-MM-yyyy"
New-Item -ItemType directory log -Force | out-null #Создаю директорию для логов

$global:logfilename="log"+$dt+"_LOG.log"
[int]$global:errorcount=0 #Ведем подсчет ошибок
[int]$global:warningcount=0 #Ведем подсчет предупреждений

function global:Write-log	# Функция пишет сообщения в лог-файл и выводит на экран.
{param($message,[string]$type="info",[string]$logfile=$global:logfilename,[switch]$silent)	
	$dt=Get-Date -Format "dd.MM.yyyy HH:mm:ss"	
	$msg=$dt + "`t" + $type + "`t" + $message #формат: 01.01.2001 01:01:01 [tab] error [tab] Сообщение
	Out-File -FilePath $logfile -InputObject $msg -Append -encoding unicode
	if (-not $silent.IsPresent) 
	{
		switch ( $type.toLower() )
		{
			"error"
			{			
				$global:errorcount++
				write-host $msg -ForegroundColor red			
			}
			"warning"
			{			
				$global:warningcount++
				write-host $msg -ForegroundColor yellow
			}
			"completed"
			{			
				write-host $msg -ForegroundColor green
			}
			"info"
			{			
				write-host $msg
			}			
			default 
			{ 
				write-host $msg
			}
		}
	}
}

У этого примера есть только один недостаток — она «синхронная», то есть не обрабатывает проблемы одновременной записи в лог-файл. Кто знает как это изменить, прошу в комменты.

PowerShell has several redirection operators that can be used to redirect specific type of output to a file. For example, if you want to redirect all errors produced by different cmdlet in your script to a text file, you can use Error redirection to do so.

It is particularly helpful when you want to hide errors from appearing on the screen but need them to identify any possible issues and improving the script. Sometimes, when you have a script deployed in production, you can ask users (who are using your script) for the error redirection file to troubleshoot the script.

To send errors to specified file, use 2> file.name

To append errors to a specified file, use 2>> file.name

Following examples attempts to delete files from c:temp folder and redirects any errors to c:errors.txt file.

PS C:> Get-ChildItem -Path c:temp

Directory: C:temp

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         4/24/2016   2:45 PM        972 errors.txt
-a---         4/24/2016   2:48 PM      21085 ex2.docx
-a---         4/24/2016   2:49 PM        274 test.txt
-a---         4/24/2016   2:47 PM       8008 test.xlsx
-a---         4/24/2016   2:49 PM        289 test2.ps1

PS C:> Get-ChildItem -Path C:temp | Remove-Item 2> C:errors.txt
PS C:>

If above command has not resulted in any error, you will not see c:errors.txt or anything in the file. if the command produced any errors, it will be there in the error file. In example above, two documents were open and they were not deleted. notice how errors were not shown on the console but they were redirected to given error file:

PS C:> get-content C:errors.txt
Remove-Item : Cannot remove item C:tempex2.docx: The process cannot access the file 'C:tempex2.docx' because it is being used by another
process.
At line:1 char:31
+ Get-ChildItem -Path C:temp | Remove-Item 2> c:errors.txt
+                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : WriteError: (C:tempex2.docx:FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item C:temptest.xlsx: The process cannot access the file 'C:temptest.xlsx' because it is being used by
another process.
At line:1 char:31
+ Get-ChildItem -Path C:temp | Remove-Item 2> c:errors.txt
+                               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : WriteError: (C:temptest.xlsx:FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
PS C:> Get-ChildItem C:temp

Notice that the error message redirected to the file is same as you would see on the console when not handling (by means of  -ErrorAction, Try/Catch etc.). It shows line number that has thrown the error and helps in troubleshooting the script/code.

2> c:errors.txt in Remove-Item cmdlet in the pipeline is used to direct the errors to given text file (here c:errors.txt). If you need to append to a file instead of overwriting/creating a new one (2> c:errors.txt creates the file if does not exist or overwrites it if it exist), use append operator (2>> c:errors.txt):

PS C:> Get-ChildItem -Path C:temp | Remove-Item 2>> c:errors.txt

One important point to note is, you shouldn’t always be just redirecting errors. There are times when you need to handle errors in a script and take appropriate action. In those cases, its better to use error handling (using try/catch, -ErrorAction parameter of supported cmdlets etc.) to handle the error appropriately.

Error Handling is a very important concept in every programming language including PowerShell which gives us several possibilities to manage errors in code.

In this article, I will try to cover as many as possible error handling concepts with examples from my practice and one of the important concepts is writing errors in external Error Log text file.

Why Should We Bother Handling Errors In PowerShell

It is no fun to run any code or application full of errors and bugs as the matter a fact it is quite annoying so in order for users to have a pleasant experience handling the errors is one of the essentials in programming.

PowerShell is no exception to that way of thinking and programming ethics although it can take some additional coding and effort but trust me it is always worth it.

I would be more than happy to share my experience with error handling and even more satisfied if I can hear your tips from the field so we can all enrich our knowledge on this very important subject.

Here is a general approach to error handling and logging errors into the external text file. I have an example in the next subheading that further explain each step so everything is much more understandable.

  1. Identify which Commands need Error Handling in your Function, CmdLet or Script.
  2. Set the ErrorAction parameter to value Stop for the command that needs Error Handling. This will stop executing the command when an error occurs and it will show the error message. Basically, we are making non-terminating errors into terminating in order to be able to handle the error in the catch block.
  3. Command that has ErrorAction parameter set to value Stop is wrapped in Try { } block. So when Error occurs handling of the code will jump from the Try block to Catch block.
  4. In Catch { } block that immediately follows after Try {} block, the error is handled by writing to the error log file on the disk.
  5. We use our own Write-ErrorLog CmdLet inside Catch{ } block to write the error in a text file on the disk. (See the explanation and code here)
  6. We have an additional switch error parameter to decide whether we want to write an error in the log file or not. This is totally optional.
  7. Use the Finally { } block if needed.
  8. Test the whole setup by intentionally breaking the code while in the development phase.
  9. Since some of the CmdLets calls are Scheduled we have routine to check external Error Log text file at least once a week and investigate errors that are caught. This step is part of improving the overall quality of the written code.

Example Of PowerShell Error Handling

To show you Error Handling and implement previously defined steps I will use my own Get-CPUInfo CmdLet which is in the Common module of the Efficiency Booster PowerShell Project. Efficiency Booster PowerShell Project is a library of CmdLets that help us IT experts in day to day IT tasks.

In order to follow me along, I highly encourage you to download the zip file with the source code used in this example.

Here is the location of Get-CPUInfo script:
…[My] DocumentsWindowsPowerShellModules3common

Get-CPUInfo CmdLet script location

Let’s use steps defined in the previous subheading to this example.

Step 1. I have identified the command that needs Error Handling in Get-CPUInfo CmdLet and that is a call to Get-CimInstance CmdLet.

Get-CimInstance @params 

Step 2. So I have set up the ErrorAction parameter to the value ‘Stop‘ for Get-CimInstance CmdLet in order to force non-terminating errors into terminating and then to be able to handle such errors.

INFO: I use parameter splatting when running CmdLet. If you want to know more about parameter splating please read this article.

            $params = @{ 'ComputerName'=$computer;
                         'Class'='Win32_Processor';
                         'ErrorAction'='Stop'}
            $CPUInfos = Get-CimInstance @params | 
                            Select-Object   @{label="ServerName"; Expression={$_.SystemName}}, 
                                            @{label="CPU"; Expression={$_.Name}}, 
                                            @{label="CPUid"; Expression={$_.DeviceID}}, 
                                            NumberOfCores, 
                                            AddressWidth

Step 3. Wrap up the call to Get-CimInstance CmdLet into the Try Block in order to be able to handle the error in a catch block that follows.

         try {
            Write-Verbose "Start processing: $computer - $env - $logicalname"
            Write-Verbose "Start Win32_Processor processing..."
            $CPUInfos = $null
            $params = @{ 'ComputerName'=$computer;
                         'Class'='Win32_Processor';
                         'ErrorAction'='Stop'}
            $CPUInfos = Get-CimInstance @params | 
                            Select-Object   @{label="ServerName"; Expression={$_.SystemName}}, 
                                            @{label="CPU"; Expression={$_.Name}}, 
                                            @{label="CPUid"; Expression={$_.DeviceID}}, 
                                            NumberOfCores, 
                                            AddressWidth           
            Write-Verbose "Finish Win32_Processor processing..."                    
            foreach ($CPUInfo in $CPUInfos) {
                Write-Verbose "Start processing CPU: $CPUInfo"
                $properties = @{ 'Environment'=$env;
                                 'Logical name'=$logicalname;
                                 'Server name'=$CPUInfo.ServerName;
            	                 'CPU'=$CPUInfo.CPU;
            	                 'CPU ID'=$CPUInfo.CPUid;
            	                 'Number of CPU cores'=$CPUInfo.NumberOfCores; 
                                 '64 or 32 bits'=$CPUInfo.AddressWidth;
                                 'IP'=$ip;
                                 'Collected'=(Get-Date -UFormat %Y.%m.%d' '%H:%M:%S)}
                $obj = New-Object -TypeName PSObject -Property $properties
                $obj.PSObject.TypeNames.Insert(0,'Report.CPUInfo')
                Write-Output $obj
                Write-Verbose "Finish processing CPU: $CPUInfo"
            }
 Write-Verbose "Finish processing: $computer - $env - $logicalname"                       
        }

Step 4. When the error occurs in the try block it is handled in the Catch Block.
It is important to notice following in the catch block of code:

  • Get-CPUInfo CmdLet switch parameter $errorlog has been used to decide whether to log the errors in an external text file or not. This is completely optional.
  • Certain Error properties are collected using an automatic variable $_ ($PSItem is another name for the same variable). If you want to know more about which properties we collect please read here.
  • Collected data about the error that will be handled has been passed to another CmdLet Write-ErrorLog that will write the data in an external text log file. Please read here about Write-ErrorLog CmdLet.
catch {
            Write-Warning "Computer failed: $computer - $env - $logicalname CPU failed: $CPUInfos"
            Write-Warning "Error message: $_"
            if ( $errorlog ) {
                $errormsg = $_.ToString()
                $exception = $_.Exception
                $stacktrace = $_.ScriptStackTrace
                $failingline = $_.InvocationInfo.Line
                $positionmsg = $_.InvocationInfo.PositionMessage
                $pscommandpath = $_.InvocationInfo.PSCommandPath
                $failinglinenumber = $_.InvocationInfo.ScriptLineNumber
                $scriptname = $_.InvocationInfo.ScriptName
                Write-Verbose "Start writing to Error log."
                Write-ErrorLog -hostname $computer -env $env -logicalname $logicalname -errormsg $errormsg -exception $exception -scriptname $scriptname -failinglinenumber $failinglinenumber -failingline $failingline -pscommandpath $pscommandpath -positionmsg $pscommandpath -stacktrace $stacktrace
                Write-Verbose "Finish writing to Error log."
            }
        }

Step 5. I have already mentioned that Write-ErrorLog CmdLet has been used to write the error data into an external text log file. Read more about this CmdLet here.

Step 6. I did not need Finally { } block for this example.

Step 7. In the development phase, I was intentionally breaking Get-CPUInfo CmdLet to test my error handling code.

Step 8. If Get-CPUInfo CmdLet is part of the scheduled code I would look regularly Error log file and work on correcting all the bugs in the code produced by Get-CPUInfo CmdLet.

Chain Of Events When PowerShell Error Occurs

Let’s talk a little bit about what is happening when an error occurs in PowerShell and which events are triggered one after another.

  • Call to CmdLet is failing and error has just occurred.
  • Since we have ErrorAction parameter set to value Stop our non-terminating error has forced into terminating error so the execution of code stops.
  • The error that is failing in the CmdLet is written in the $Error automatic variable by the PowerShell.
  • We have forced the error to be terminating in order to be able to handle with try catch finally block of error handling.
  • Since our CmdLet call is wrapped in Try block and error is terminating PowerShell can trigger error handling looking for a Catch block.
  • We can have several Catch blocks for one try block. If we have a Catch block that handles the actual error number that block is executed.
  • Otherwise, PowerShell will look Catch block that handles all error numbers.
  • Optionally in the Catch block, we can have code that will write the error in the external text Error log file.
  • We can use the automatic variable $Error or $_ object to read Error data and write them in the external file.
  • If there is no Catch block PowerShell will look for Catch block in parent call if we have nested calls.
  • If there are no further Catch block or no Catch block at all that will handle error then PowerShell looks for Finally block to execute which is used to clean up resources as needed.
  • After executing Finally block error message will be sent to the error stream for further processing.

In further sections of this article, you can read in more detail about the many terms mentioned (ErrorAction, $Error, Try Catch Finally, Terminating, Non-Terminating, etc ) in this bulleted list in order to better understand them.

How To Write PowerShell Errors Into The External Log File

Here I will explain the code of Write-ErrorLog CmdLet that writes error data that occurs in CmdLets and handle the error data into an external text file.

Error data are written in the file named Error_Log.txt in folder PSlogs.

Location and name of external error text log file
Example of error logged in an external text file

Write-ErrorLog CmdLet is part of the Efficiency Booster PowerShell Project and if you want to download the source code of this CmdLet please click here.

Here is the location of Write-ErrorLog script which is part of the Utils module:
…[My] DocumentsWindowsPowerShellModules2utils

Write-ErrorLog CmdLet script location

Write-ErrorLog CmdLet Code

Here is the code of the whole Write-ErrorLog CmdLet.

<#
.SYNOPSIS
Writes errors that occur in powershell scripts into error log file.
.DESCRIPTION
Writes errors that occur in powershell scripts into error log file.
Error log file and error log folder will be created if doesn't exist.
Error log file name is Error_Log.txt and it has been saved into ..DocumentsPSlogs

.PARAMETER hostname
Name of the computer that is failing.

.PARAMETER env
Environment where computer is located. For example: Production, Acceptance, Test, Course etc.

.PARAMETER logicalname
Type of the server that is failing. For example: Application, Web, Integration, FTP, Scan, etc. 

.PARAMETER errormsg
Error message.

.PARAMETER exception
Error number.

.PARAMETER scriptname
Name of the powershell script that is failing.

.PARAMETER failinglinenumber
Line number in the script that is failing.

.PARAMETER failingline
Content of failing line.

.PARAMETER pscommandpath
Path to the powershell command.

.PARAMETER positionmsg
Error message position.

.PARAMETER stacktrace
Stack trace of the error.

.EXAMPLE
Write-ErrorLog -hostname "Server1" -env "PROD" -logicalname "APP1" -errormsg "Error Message" -exception "HResult 0789343" -scriptname "Test.ps1" -failinglinenumber "25" -failingline "Get-Service" -pscommandpath "Command pathc." -positionmsg "Position message" -stacktrace "Stack trace" 

.EXAMPLE
Help Write-ErrorLog -Full

.LINK 
Out-File
#>
Function Write-ErrorLog {
[CmdletBinding()]
param (

    [Parameter(Mandatory=$false,
                HelpMessage="Error from computer.")] 
    [string]$hostname,

    [Parameter(Mandatory=$false,
                HelpMessage="Environment that failed. (Test, Production, Course, Acceptance...)")] 
    [string]$env,

    [Parameter(Mandatory=$false,
                HelpMessage="Type of server that failed. (Application, Web, Integration...)")] 
    [string]$logicalname,
    
    [Parameter(Mandatory=$false,
                HelpMessage="Error message.")] 
    [string]$errormsg,
    
    [Parameter( Mandatory=$false,
                HelpMessage="Exception.")]
    [string]$exception,
    
    [Parameter(Mandatory=$false, 
                HelpMessage="Name of the script that is failing.")]
    [string]$scriptname,
     
    [Parameter(Mandatory=$false,
                HelpMessage="Script fails at line number.")]
    [string]$failinglinenumber,

    [Parameter(Mandatory=$false,
                HelpMessage="Failing line looks like.")]
    [string]$failingline,
    
    [Parameter(Mandatory=$false,
                HelpMessage="Powershell command path.")]
    [string]$pscommandpath,    

    [Parameter(Mandatory=$false,
                HelpMessage="Position message.")]
    [string]$positionmsg, 

    [Parameter(Mandatory=$false,
                HelpMessage="Stack trace.")]
    [string]$stacktrace
)
BEGIN { 
        
        $errorlogfile = "$homeDocumentsPSlogsError_Log.txt"
        $errorlogfolder = "$homeDocumentsPSlogs"
        
        if  ( !( Test-Path -Path $errorlogfolder -PathType "Container" ) ) {
            
            Write-Verbose "Create error log folder in: $errorlogfolder"
            New-Item -Path $errorlogfolder -ItemType "Container" -ErrorAction Stop
        
            if ( !( Test-Path -Path $errorlogfile -PathType "Leaf" ) ) {
                Write-Verbose "Create error log file in folder $errorlogfolder with name Error_Log.txt"
                New-Item -Path $errorlogfile -ItemType "File" -ErrorAction Stop
            }
        }
}
PROCESS {  

            Write-Verbose "Start writing to Error log file. $errorlogfile"
            $timestamp = Get-Date 
            #IMPORTANT: Read just first value from collection not the whole collection.
            "   " | Out-File $errorlogfile -Append
            "************************************************************************************************************" | Out-File $errorlogfile -Append
            "Error happend at time: $timestamp on a computer: $hostname - $env - $logicalname" | Out-File $errorlogfile -Append
            "Error message: $errormsg" | Out-File $errorlogfile -Append
            "Error exception: $exception" | Out-File $errorlogfile -Append
            "Failing script: $scriptname" | Out-File $errorlogfile -Append
            "Failing at line number: $failinglinenumber" | Out-File $errorlogfile -Append
            "Failing at line: $failingline" | Out-File $errorlogfile -Append
            "Powershell command path: $pscommandpath" | Out-File $errorlogfile -Append
            "Position message: $positionmsg" | Out-File $errorlogfile -Append
            "Stack trace: $stacktrace" | Out-File $errorlogfile -Append
            "------------------------------------------------------------------------------------------------------------" | Out-File $errorlogfile -Append                   
            
            Write-Verbose "Finish writing to Error log file. $errorlogfile"
}        
END { 

}
}
#region Execution examples
#Write-ErrorLog -hostname "Server1" -env "PROD" -logicalname "APP1" -errormsg "Error Message" -exception "HResult 0789343" -scriptname "Test.ps1" -failinglinenumber "25" -failingline "Get-Service" -pscommandpath "Command pathc." -positionmsg "Position message" -stacktrace "Stack trace" -Verbose
#endregion

Write-ErrorLog CmdLet Explained

Let’s make our hand’s a little bit “dirty” and dive into PowerShell code.

In the BEGIN block we:

  • Check if folder PSlogs exist in the (My) Documents folder of the current user.
    • If the PSlogs folder doesn’t exist then create the folder.
  • Check if file Error_Log.txt exists in the folder PSlogs.
    • If Error_Log.txt doesn’t exist then create the file.
  • Now we can move on to PROCESS block code.
BEGIN { 
        
        $errorlogfile = "$homeDocumentsPSlogsError_Log.txt"
        $errorlogfolder = "$homeDocumentsPSlogs"
        
        if  ( !( Test-Path -Path $errorlogfolder -PathType "Container" ) ) {
            
            Write-Verbose "Create error log folder in: $errorlogfolder"
            New-Item -Path $errorlogfolder -ItemType "Container" -ErrorAction Stop
        
            if ( !( Test-Path -Path $errorlogfile -PathType "Leaf" ) ) {
                Write-Verbose "Create error log file in folder $errorlogfolder with name Error_Log.txt"
                New-Item -Path $errorlogfile -ItemType "File" -ErrorAction Stop
            }
        }
}

In the PROCESS block:

  • We format the line of text that we want to write into the log file.
  • Then we pipe formatted text to Out-File CmdLet with the Append parameter to write that line of text in the file.
  • We repeat the process of formatting the line of text and appending of that line to the Error log file.
PROCESS {  

            Write-Verbose "Start writing to Error log file. $errorlogfile"
            $timestamp = Get-Date 
            #IMPORTANT: Read just first value from collection not the whole collection.
            "   " | Out-File $errorlogfile -Append
            "************************************************************************************************************" | Out-File $errorlogfile -Append
            "Error happend at time: $timestamp on a computer: $hostname - $env - $logicalname" | Out-File $errorlogfile -Append
            "Error message: $errormsg" | Out-File $errorlogfile -Append
            "Error exception: $exception" | Out-File $errorlogfile -Append
            "Failing script: $scriptname" | Out-File $errorlogfile -Append
            "Failing at line number: $failinglinenumber" | Out-File $errorlogfile -Append
            "Failing at line: $failingline" | Out-File $errorlogfile -Append
            "Powershell command path: $pscommandpath" | Out-File $errorlogfile -Append
            "Position message: $positionmsg" | Out-File $errorlogfile -Append
            "Stack trace: $stacktrace" | Out-File $errorlogfile -Append
            "------------------------------------------------------------------------------------------------------------" | Out-File $errorlogfile -Append                   
            
            Write-Verbose "Finish writing to Error log file. $errorlogfile"
} 

$PSItem or $_

$PSItem contains the current object in the pipeline object and we use it to read Error properties in this case.

Just a quick explanation of each Error property from the $_ ($PSItem) automatic variable that we collect and write in Logfile:

  • $_.ToString() – This is Error Message.
  • $_.Exception – This is Error Exception.
  • $_.InvocationInfo.ScriptName – This the PowerShell script name where Error occurred.
  • $_.InvocationInfo.ScriptLineNumber – This is line number within the PowerShell script where Error occurred.
  • $_.InvocationInfo.Line – This is the line of code within PowerShell script where Error occurred.
  • $_.InvocationInfo.PSCommandPath – This is the path to the PowerShell script file on the disk.
  • $_.InvocationInfo.PositionMessage – This is a formatted message indicating where the CmdLet appeared in the line.
  • $_.ScriptStackTrace – This is the Trace of the Stack.

As you can see on the screenshot below we collect really useful information about the Error that we handle in the Logfile. The pieces of information are presented in very neatly fashion so we can immediately see:

  • which error occurred,
  • what were the message and exception,
  • where the error occurred (script name, script location, line number and line of the code in the script)
  • even the call stack is shown if needed.

Here are the final result and an example of one formatted error logged in Error_Log.txt file.

************************************************************************************************************
Error happend at time: 09/11/2019 18:20:41 on a computer: APP01 -  - 
Error message: The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. You can get more information about that by running the following command: winrm help config.
Error exception: Microsoft.Management.Infrastructure.CimException: The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting. Use winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. You can get more information about that by running the following command: winrm help config.
   at Microsoft.Management.Infrastructure.Internal.Operations.CimAsyncObserverProxyBase`1.ProcessNativeCallback(OperationCallbackProcessingContext callbackProcessingContext, T currentItem, Boolean moreResults, MiResult operationResult, String errorMessage, InstanceHandle errorDetailsHandle)
Failing script: C:UsersdekibDocumentsWindowsPowerShellModules3commonGetCPUInfo.ps1
Failing at line number: 214
Failing at line:             $CPUInfos = Get-CimInstance @params | 

Powershell command path: C:UsersdekibDocumentsWindowsPowerShellModules3commonGetCPUInfo.ps1
Position message: C:UsersdekibDocumentsWindowsPowerShellModules3commonGetCPUInfo.ps1
Stack trace: at Get-CPUInfo, C:UsersdekibDocumentsWindowsPowerShellModules3commonGetCPUInfo.ps1: line 214
at , : line 1
------------------------------------------------------------------------------------------------------------

TIP: If your scripts are scheduled in Task Manager the best practice is to have a routine of regularly checking the Error Log file and investigate the errors that occurred since the last check. I am doing this once a week.

Errors In PowerShell

There are two types of Errors in PowerShell:

  • Terminating
  • Non-Terminating

Terminating Errors

Here are the important features of Terminating errors:

  • terminates execution of command or script
  • triggers Catch block and can be error handled by the Catch block.

Examples are syntax errors, non-existent CmdLets, or other fatal errors

Non-Terminating Errors

Here are important features of Non-Terminating Error:

  • A non-fatal error.
  • Allows execution to continue despite the failure that just occurred.
  • It doesn’t trigger the Catch block and cannot be Error Handled in the Catch block by default.

Examples are permission problems, file not found, etc.

How To Force Non-Terminating Errors Into Terminating

Use the ErrorAction parameter with value Stop to force non-terminating error into terminating as in the following example. The reason why we want to make non-termination error into terminating one is to be able to catch the error when occurs.

$AuthorizedUser = Get-Content .DocumentsWindowsPowerShellProfile.ps1 -ErrorAction Stop 

Basically, the workflow is as follows.

  • When an error occurs,
  • a non-terminating error has changed into terminating one since we have Stop value on ErrrorAction parameter,
  • then since terminating error has occurred try block will send the error handling to catch block where error can be processed and
  • optionally written to the external log,
  • optionally error handling can continue in the final block.

NOTE: ErrorAction parameter overrides temporarily ErrorActionPreference variable while the call to CmdLet has been processed.

How To Treat All Errors As Terminating

We use the ErrorActionPreference variable to treat all errors as terminating by setting to the value Stop in the:

  • script
  • or session

Write the following line of code at the begging of the script to treat all errors as terminating.

$ErrorActionPreference = Stop

Type in Windows PowerShell Console the same command to setup terminating errors for the session.

ErrorAction Common Parameter

ErrorAction parameter belongs to the set of common parameters that we can use with any CmdLet. If we set CmdLetBinding on Advanced Functions than PowerShell automatically makes common parameters available for that command.

This is a parameter that I always use with CmdLets that need error handling since the ErrorAction Parameter determines how the CmdLet responds to a non-terminating error. It has several values that we will talk about in a minute but the value that I like to use is Stop and it is used to make non-terminating errors into terminating errors as written in previous sections.

The ErrorAction parameter overrides the value of the $ErrorActionPreference variable when applied to the specific command.

Here are valid values:

  • Continue (Default)
    • This is the default setting. Display error then continues execution.
  • Stop
    • Display error, and stop the execution.
  • Inquire
    • Displays error message and the user is asked to continue with execution.
  • SilentlyContinue
    • No error message is displayed and execution is continued. However, the error message is added to the $Error automatic variable.
  • Ignore
    • The same as SilentlyContinue, No error message is displayed and execution is continued. However, Ignore does not add an error message to the $Error automatic variable.
  • Suspend
    • This one is for workflows. A workflow job is suspended to investigate what happened, then the workflow can be resumed.

$ErrorActionPreference Preference Variable Explained

$ErrorActionPreference preference variable determines how Windows PowerShell responds to a non-terminating error (an error that does not stop the cmdlet processing) in a script, cmdlet or at the command line

If we want to override the value of the ErrorActionPreference preference variable for the specific command we use the ErrorAction common parameter as explained here.

The valid values for $ErrorActionPreference preference variable are:

  • Continue (Default)
    • This is the default setting. Display error then continues execution.
  • Stop
    • Display error message, and stop the execution.
  • Inquire
    • Displays error message and the user is asked to continue with execution.
  • SilentlyContinue
    • No error message is displayed and execution is continued. However, the error message is added to the $Error automatic variable.
  • Suspend
    • This one is for workflows. A workflow job is suspended to investigate what happened, then the workflow can be resumed.

Error Handling With Try/Catch/Finally Blocks

Try, Catch, and Finally, blocks are used to handle terminating errors in the scripts, functions, and CmdLets. A non-terminating error does not trigger Try block and Windows PowerShell will not look for Catch block to handle the error. So we need to force a non-terminating error to become terminating error using ErrorAction parameter with value Stop whenever we call some CmdLet or Advanced function.

Try block is used as part of the code that PowerShell will monitor for errors. The workflow in the Try block is as follows:

  • Try block is the section of code that will be monitored for errors by Windows PowerShell.
  • When the error occurs within Try block the error is saved to $Error automatic variable first.
  • Windows PowerShell searches for a Catch block to handle the error if the error is terminating. If the Catch block has not been found in current scope Windows PowerShell will search for catch block in parent scopes for nested calls.
  • Then the Finally block is run if exists.
  • If there is no Catch block than the error is not handled and the error is written to the error stream.

One Try block can have several Catch Blocks that will handle different error types.

Catch block usually handles the error.

The Finally block is optional and can be only one. Usually, it is used to clean up and free the resources.

The syntax for Try, Catch, and Finally block:

try { } 
catch [],[]
   { } 
catch { } 
finally { }

Getting Error Information With $Error Automatic Variable

$Error automatic variable is an array of error objects (both terminating and the non-terminating) that occurred in the current PowerShell session. The most recent error that occurred is written with index 0 in the array as $Error[0]. If we have just opened the Windows PowerShell session the $Error variable is an empty array and ready to be used.

Check the number of Errors in $Error variable with the following code:

$Error.Count

To prevent the error from being written in $Error automatic variable set ErrorAction parameter to value Ignore.

$Error variable is a rich object that has many useful properties worth reading and helpful for further understanding of the error that just occurred.

Let’s see some useful properties and in section Write-ErrorLog CmdLet Explained I have explained to you some useful examples of properties that are interesting to be written in an external log file.

$error[0] | Get-Member
Methods and Properties of the Error object
$Error.CategoryInfo | Get-Member
Methods and Properties of CategoryInfo object
$Error[0].Exception
The exception of the error that occurred.
$Error.InvocationInfo | Get-Member
Methods and Properties of InvocationInfo object

Write-Error CmdLet

Write-Error CmdLet writes an object to the error stream.

Please read this article from Microsoft PowerShell documentation regarding this CmdLet.

Handling Errors from non-PowerShell processes

We can run applications from PowerShell script like for example, PsExec.exe or robocopy.exe and they are external processes for PowerShell. Since it is an external process, errors from it will not be caught by our try/catch blocks in PowerShell script. So how we will know whether our external process was successful or not.

Well, we can use the $LastExitCode PowerShell automatic variable.

PowerShell will write the exit code to the $LastExitCode automatic variable when the external process exits. Check the external tool’s documentation for exit code values but usually, 0 means success and 1 or greater values mean a failure.

Useful PowerShell Error Handling Articles

Here are some useful articles and resources:

  • Windows PowerShell Error Reporting
  • About Try Catch Finally
  • About CommonParameters
  • About Automatic Variables
  • About Preference Variables
  • Write-Error
  • About Throw
  • About Break
  • About Continue

Вы можете использовать простые текстовые файлы логов для контроля работы и отслеживания всех действий в ваших скриптах PowerShell. Это полезно при отладке ошибок или при аудите действий скрипта. В этой статье мы покажем некоторые способы использования ведения журнала в скриптах PowerShell путём записи вывода в текстовые файлы журнала.

В простейшем случае, если вы хотите записать вывод информационного сообщения или результат команды PowerShell в текстовый файл журнала, вы можете использовать один из следующих форматов для перенаправления вывода PowerShell в текстовый файл:

Write-Output "Файлы успешно созданы в $env:computername" >> C:PSLogsTestLog.txt

Смотрите также: Аналог echo в PowerShell

Или:

Add-Content -Path C:PSLogsTestLog.txt -Value "Файлы успешно созданы в $env:computername"

Смотрите также: Командлеты Set-Content и Add-Content для обработки строк

Или:

"Файлы успешно созданы в $env:computername" | Out-File -FilePath C:PSLogsTestLog.txt -Append

Смотрите также: Как в PowerShell сохранить вывод в файл (аналоги > и »)

Во всех случаях команды добавляют новую строку в текстовый файл с указанным вами текстом.

Если вы хотите каждый раз перезаписывать содержимое файла журнала, используйте командлет Set-Content.

Основным недостатком этого метода является то, что вы не можете определить, когда запись была записана в журнал (произошло событие). Вы можете добавить текущую метку времени в файл журнала. Это поможет определить время, когда скрипт был запущен и произошло конкретное событие.

Чтобы сделать ведение логов более удобным, вы можете создать отдельную функцию в своём скрипте PowerShell, которая будет записывать полученные данные в файл журнала и добавлять временную метку для каждого события.

Вы можете создать функцию, как показано ниже:

$Logfile = "C:PSLogsproc_$env:computername.log"
function WriteLog
{
	Param ([string]$LogString)
	$Stamp = (Get-Date).toString("yyyy/MM/dd HH:mm:ss")
	$LogMessage = "$Stamp $LogString"
	Add-content $LogFile -value $LogMessage
}

Затем вызовите функцию WriteLog, если хотите что-то записать в журнал.

WriteLog "Скрипт запущен”
WriteLog "Вычисление…."
Start-Sleep 20
WriteLog "Скрипт успешно выполнен"

Теперь вы можете видеть время каждой записи в файле журнала.

В своём скрипте вы можете заменить вызовы Write-Host вызовами LogWrite.

PowerShell имеет встроенную функцию транскрипции для сохранения всех команд и выходных данных, отображаемых в консоли PS, в текстовый файл журнала.

Для регистрации текущего сеанса PowerShell используется командлет Start-Transcript.

После выполнения команды появляется сообщение, показывающее файл, в который записываются выходные данные всех команд. По умолчанию файл журнала находится в текущем профиле пользователя:

Transcript started, output file is C:UsersuserDocumentsPowerShell_transcript.DESKTOP-P2FHTKQ.+IzDgZiN.20210908163729.txt

Вы можете указать путь к текстовому файлу следующим образом:

Start-Transcript -Append C:PSLogsPSScriptLog.txt

Параметр -Append указывает, что новые сеансы будут записываться в конец файла (без его перезаписи).

Выполните несколько команд PowerShell, которые выведут результаты на консоль. Например, давайте отобразим список запущенных процессов, служб и статус репликации AD:

Get-Process | Where-Object {$_.WorkingSet -GT 500000*1024} | select processname,@{l="Used RAM(MB)"; e={$_.workingset / 1mb}} | sort "Used RAM(MB)" -Descending
Get-Service | Where-Object {$_.status -eq 'Running'}
Get-ADReplicationFailure -Target mun-dc01

Остановить ведение журнала для текущего сеанса PowerShell:

Stop-Transcript

Затем откройте файл журнала транскрипции (стенограммы).

Как видите, в журнале отображается вся история команд PowerShell, которые были запущены в консоли, и весь их вывод.

Все ошибки и предупреждения также регистрируются, что чрезвычайно удобно при отладке сложных скриптов PowerShell.

Вы можете использовать командлеты Start-Transcript и Stop-Transcript в своих скриптах PowerShell для естественного протоколирования всех действий и выходных данных.

Используя параметр групповой политики «Включить транскрипции PowerShell» (в английской версии Windows он называется Turn on PowerShell Transcription) вы можете включить автоматическое ведение журнала всех выполняемых команд PowerShell и их вывода на компьютер. После обновления настроек GPO на компьютере для каждого запущенного процесса powershell.exe будет создан отдельный текстовый файл журнала, и будут регистрироваться все команды PS и их выходные данные.

Чтобы открыть редактор локальной групповой политики выполните:

GPEDIT

Вы найдёте этот пораметр по пути Конфигурация компьютера → Административные шаблоны → Компоненты Windows → Windows PowerShell, или для английской версии по пути Computer Configuration → Administrative Templates → Windows Components → Windows PowerShell.

После актуализации настроек GPO на компьютере для каждого запущенного процесса powershell.exe будет создан отдельный текстовый файл журнала, и будут регистрироваться все команды PS и их выходные данные.

Связанные статьи:

  • Как в PowerShell сохранить вывод в файл (аналоги > и >>) (100%)
  • Аналог echo в PowerShell (100%)
  • Как в PowerShell менять набор выводимых по умолчанию данных (100%)
  • Как выводить данные без таблицы в PowerShell (100%)
  • В PowerShell таблица не помещается на экран — как исправить (РЕШЕНО) (100%)
  • Фильтрация свойств объектов в PowerShell (RANDOM — 100%)

Всем привет.

В предыдущих двух постах были подробно изложены методы отлова критических и некритических ошибок при работе с PowerShell. Но я решил что будет несправедливым не отметить самые основные моменты, которые возникают в работе если что-то пошло не так. Т.е. переменные и обьекты в PowerShell которые содержат первичную информацию о работе нашего скрипта. Речь пойдет об объекте ErrorRecord, о переменной $Error, о мониторинге возникновения ошибки c помощью переменной $? и кодов возврата, а также упомянем командлет Set-PSDebug и точки прерывания. Поможет нам в этом замечательная книга Попова А. В. «Введение в Windows PowerShell» — СПб.: БХВ-Петербург, 2009.

Поехали.

1. Объект ErrorRecord и поток ошибок.

В PowerShell информация о возникающих ошибках записывается в поток ошибок, который по умолчанию отображается на экране, например:
PS C:> dir «C:Folder doesn’t exist»
Get-ChildItem : Не удается найти путь «C:Folder doesn’t exist»,
так как он не существует.
В строка:1 знак:4
+ dir <<<< «C:Folder doesn’t exist»

Поток ошибок можно перенаправить в текстовый файл с помощью специального оператора 2>, например:
PS C:> dir «C:Folder doesn’t exist» 2>err.txt

Проверим теперь содержимое файла err.txt:
PS C:> Get-Content err.txt
Get-ChildItem : Не удается найти путь «C:Folder doesn’t exist»,
так как он не существует.
В строка:1 знак:4
+ dir <<<< «Folder doesn’t exist» 2> err.txt
Как видите, в файл err.txt полностью записалось сообщение об ошибке, однако никакой дополнительной информации не появилось.

Где произошла ошибка смотрим так
PS C:> $err.InvocationInfo
MyCommand : Get-ChildItem
ScriptLineNumber : 1
OffsetInLine : -2147483648
ScriptName :
Line : $err = dir «C:Folder doesn’t exist» 2>&1
PositionMessage :
 В строка:1 знак:11
 + $err = dir <<<< «C:Folder doesn’t exist» 2>&1
InvocationName : dir
PipelineLength : 1
PipelinePosition : 1
Хотя этот вывод даст нам место скрипта(или непсредственного ввода)
где ошибку интепретирует сама PowerShell, истинное место проблемы надо будет
искать самим.

2. Специальная переменная $Error.

В PowerShell имеется специальная переменная $Error, которая содержит коллекцию (массив) объектов ErrorRecord, соответствующих ошибкам, возникавшим в текущем сеансе работы. Максимальное количество элементов в данной коллекции задается значением переменной $MaximumErrorCount (по умолчанию это 256):
PS C:> $MaximumErrorCount
256

После заполнения массива $Error объекты для вновь возникающих ошибок будут заменять объекты, соответствующие старым ошибкам. Возникновение каждой новой ошибки приводит к смещению элементов в массиве $Error: объект для последней ошибки хранится в первом элементе ($Error[0]), объект для предыдущей ошибки — во втором элементе ($Error[1]) и т. д.
Убедимся, что элемент $Error[0] имеет тип ErrorRecord, и выведем содержимое этого элемента:
PS C:> $Error[0].GetType().FullName
System.Management.Automation.ErrorRecord

PS C:> $Error[0]
Get-ChildItem : Не удается найти путь «C:Несуществующий каталог»,
так как он не существует.
В строка:1 знак:4
+ dir <<<< «Несуществующий каталог»
Естественно, мы можем обращаться ко всем свойствам объекта ErrorRecord:

PS C:> $Error[0].Exception
Не удается найти путь «C:Несуществующий каталог», так как он не существует.

Повторим вывод свойства InvocationInfo
PS C:> $Error[0].InvocationInfo
MyCommand : Get-ChildItem
ScriptLineNumber : 1
OffsetInLine : -2147483648
ScriptName :
Line : $err = dir «C:Folder doesn’t exist» 2>&1
PositionMessage :
 В строка:1 знак:11
 + $err = dir <<<< «C:Folder doesn’t exist» 2>&1
InvocationName : dir
PipelineLength : 1
PipelinePosition : 1

3. Мониторинг возникновения ошибки переменной $?.

В PowerShell имеется логическая переменная $?, которая равна $True, если последняя выполняемая операция завершена успешно, и $False, если во время выполнения последней
операции возникла ошибка. Такая же существует и в Linux.) Например, если выполнить командлет Get-Item для заведомо существующего каталога, то значение переменной $? будет равно $True:
PS C:> Get-Item С:
Каталог:
Mode LastWriteTime Length Name
—- ————- —— —-
d—hs 21.03.2016 12:00 C:

PS C:> $?
True

Если же выполнить этот же командлет для несуществующего каталога, то значение переменной $? будет равно $False:
PS C:> Get-Item С:321
Get-Item : Не удается найти путь «C:321», так как он не существует.
В строка:1 знак:9
Глава 9. Обработка ошибок и отладка 183
+ Get-Item <<<< С:321
PS C:> $?
False

4. Мониторинг возникновения ошибки по коду возврата.

Для внешних команд Windows и сценариев PowerShell определено понятие кода возврата (напомним, что для сценариев PowerShell этот код можно установить с помощью инструкции Exit). В операционной системе код возврата последней команды доступен через переменную среды %ERRORLEVEL%; в оболочке PowerShell данный код возврата хранится в специальной переменной $LASTEXITCODE. При этом, если код возврата равен нулю, то переменной $? присваивается значение $True. Если же код возврата не равен нулю, то считается, что при выполнении данной команды произошла ошибка, и переменной $? присваивается значение $False.

В качестве примера выполним команду интерпретатора cmd.exe, которая устанавливает нулевой код возврата. Для этого можно запустить cmd.exe с ключом /c (выполнить команду и завершить работу интерпретатора) и указать для исполнения команду exit 0:
PS C:> cmd /c exit 0

Проверим значения переменных $LASTEXITCODE и $?:
PS C:> $LASTEXITCODE
0
PS C:> $?
True
Теперь выполним команду интерпретатора cmd.exe с ненулевым кодом возврата (пусть, например, код возврата равен 10):
PS C:> cmd /c exit 10
Вновь проверим переменные $LASTEXITCODE и $?:
PS C:> $?
False
PS C:> $LASTEXITCODE
10

5. Командлет Set-PSDebug и точки прерывания.

Процесс поиска ошибок в сценариях неразрывно связан с отладкой. Поэтому нам стоит упомянуть что основным встроенным инструментом для отладки сценариев является командлет Set-PSDebug. Параметры этого командлета позволяют включить режимы трассировки и пошагового выполнения команд, а также режим обязательного объявления переменных:
-Trace 0 Отключение трассировки
-Trace 1 Включение основного режима трассировки
-Trace 2 Включение полного режима трассировки
-Step Включение режима пошагового выполнения
-Strict Включение режима обязательного объявления переменных
-Off Отключение всех механизмов отладки.

Примеры приводить не буду, назначение ключей очевидно из их названия. Самым интересным является режим пошагового выполнения -Step, который позволяет в любой момент вызвать вложенную командную строку для анализа или изменения состояния интерпретатора. Однако отлаживать более-менее большие сценарии с помощью данного метода часто оказывается неудобно, так как для запуска вложенного сеанса в определенной строке сценария придется каждый раз добираться до этой строки с самого начала сценария (каждую команду при этом
нужно выполнять, нажимая клавишу <A>).

Гораздо удобнее было бы использовать точки прерывания, позволяющие запускать сценарий в автоматическом режиме и приостанавливать выполнение на нужной команде. В PowerShell аналогом установки точки прерывания можно считать вызов метода $Host.EnterNestedPrompt(), например:
PS C:> for ($i=0; $i -lt 10; $i++) {
>> «i = $i»
>> if ($i -eq 5) {
>> «Моя точка прерывания»
>> $Host.EnterNestedPrompt()
>> }
>> }
>>
i = 0
i = 1
i = 2
i = 3
i = 4
i = 5
Моя точка прерывания
PS C:>>>

В данном примере на пятой итерации цикла выводится строка «Моя точка прерывания» и вызывается метод $Host.EnterNestedPrompt(). В результате выполнение цикла приостанавливается, и мы попадаем во вложенную командную строку (вид приглашения изменяется на >>>).

Выход из вложенного сеанса с помощью инструкции Exit:
PS C:>>> Exit
PS C:>

Вот так вот.

Понравилась статья? Поделить с друзьями:
  • Prinfix ошибка файл не найден обратитесь к администратору
  • Prince of persia warrior within ошибка русский язык ввода
  • Prince of persia the warrior within синтаксическая ошибка
  • Prince of persia the sands of time ошибка
  • Prince of persia the forgotten sands выдает ошибку