I have just started PowerShell today
I have this type of log files with any number of tests:
Plan test.pln - 1 error
[#VERSION-TestPlanGenerator#]3.8.0.0018
HW# VS4_1
[#TC#] test 1
\\APPS-EUAUTO1\C$\...\Temp\FXSAPIDebugLogFile.txt - The process cannot access the file because it is being used by another process.
[APPS-EUAUTO1] [prep] Setting agent options and random seed...
[APPS-EUAUTO1] [info] Initial Seed : 124426621
[APPS-EUAUTO1] [info] Current seed : 96010
[APPS-EUAUTO1] [info] rt1 t1
[APPS-EUAUTO1] [debug] rt1 t1
[#WARNING#][APPS-EUAUTO1] [warning] rt1 t1 ( Screen shot : D:\...\[APPS-EUAUTO1] 03-28-14 11-29-22.png)
[#WARNING#][APPS-EUAUTO1] [warning] Unhandled error detected ! ( Screen shot : D:\...\[APPS-EUAUTO1] 03-28-14 11-29-22.png)
[#ERROR#][APPS-EUAUTO1] [error] rt1 t1 ( Screen shot : D:...\[APPS-EUAUTO1] 03-28-14 11-29-22.png)
Occurred in fnMsg at ..\functions\f_common.inc(456)
Called from t1 at test.t(10)
Called from rt1 at test.t(5)
[#TC#] test 2
[APPS-EUAUTO1] [prep] Setting agent options and random seed...
[APPS-EUAUTO1] [info] Current seed : 177041
[APPS-EUAUTO1] [info] rt2 t2
[APPS-EUAUTO1] [debug] rt2 t2
I need to get all the tests in an array in witch each element will have:
a string Name ( ex: test 1)
a boolean Error (ex: true for test 1 because there is a [#WARNING#]
or a [#ERROR#] message present)
a array Messages with all the messages (ex: for test 2 all 4
messages)
and at the end I will like to export this array to a html file.
All tests begins with [#TC#].
I'm having problems with the reading part.
I have tried a couple of things from different sites but, it doesn't not seem to work for me :
Function Import-MyLog1 {
# -----------------------------------------------------------------------
Function Get-Log {
# Reads the log file into memory.
Try {
Get-Content -path "res.txt" -ErrorAction Stop -Delimiter "[#TC#]"
}
Catch {
Write-Error "The data file is not present"
BREAK
}
} # End: Function Get-Log
# -----------------------------------------------------------------------
Function Get-Record {
Param ($Log)
for ($i=1; $i -lt $Log.Length; $i++) { # ignore the header
$Testcase = $Log[$i]
New-Object PSobject -Property #{
Name = $Testcase[0]
Data = $Testcase[3..6]
}
}
} # End: Function Get-Record
# Load the log into memory
$Log = Get-Log
$Records = Get-Record -Log $Log
$Records # Added only to see the current progress.
} #End: Function Import-MyLog1
clear
Import-MyLog1
this is the final code for who might need a example :
Function Get-TxtLog {
Param ($File)
# Reads the log file into memory.
Try {
Get-Content -path $File -ErrorAction Stop -Delimiter "[#TC#]"
} Catch {
Write-Error "The data file is not present"
BREAK
}
} # End: Function Get-TxtLog
# -----------------------------------------------------------------------
Function Get-Testcase {
Param ($TxtLog)
for ($i=1; $i -lt $TxtLog.Count; $i++) { # $i=1 to ignore the header
$Testcase = $TxtLog[$i].split("`n")
$Output = New-Object PSobject -Property #{
Name = $Testcase[0].Trim()
Messages = $Testcase[1..($Testcase.count)] | ?{!($_ -match "\[#TC#]")} | ForEach-Object -process {$_.Trim()}
}
$Error = $( if($Output.Messages -match ("\[#ERROR#]|\[#WARNING#]")) {$true} else {$false} )
$Output|Add-Member -MemberType NoteProperty -Name "Error" -value $Error
$Output|Add-Member -MemberType NoteProperty -Name "Runtime" -value $null # will be added later
$Output|Add-Member -MemberType NoteProperty -Name "Data" -value $null # will be added later
$Output # to pipe the object
}
} # End: Function Get-Testcase
# -----------------------------------------------------------------------
# Load the log into memory
$TxtLog = Get-TxtLog -file "D:\XHostMachine\Results\res.txt"
$Records = Get-Testcase -TxtLog $TxtLog
$Records | Format-Table
If you just started PowerShell today then I can only imagine what you'll be doing with it in a year's time... You have started very well in my opinion.
Now, you seem to want to make everything into a function, which I suppose there is little harm in, but personally it seems overkill. When I pasted your test code into my ISE the first thing I did was comment out the first line and 28th line through the end of it. There just doesn't seem to be a need for all that.
Next I added a parameter to the Get-Log function so that a path can be provided if desired, and if excluded it will default to your res.txt file.
Function Get-Record {
Param ($Log)
for ($i=1; $i -lt $Log.Count; $i++) { # ignore the header
$Testcase = $Log[$i].split("`n")
$Output = New-Object PSobject -Property #{
Name = $Testcase[0]
Data = $Testcase[3..($Testcase.count)]|?{!($_ -match "\[#TC#]")}
}
$Output|Add-Member -MemberType NoteProperty -Name "Error" -value $(if($Output.data -match "^.+?(\[#ERROR#]|\[#WARNING#])"){$true}else{$false})
$Output
}
} # End: Function Get-Record
After that I looked at the value of $Log once it was gotten. You end up with an array with 3 strings in it. That's all fine and good, but what you really want is an array with 3 arrays in it if you ask me. Right now $Log[0] is a string with 4 lines of text, and you'd be better off with an array of 4 strings... so let's go that route first. I modified your Get-Record to accomplish that.
Function Get-Record {
Param ($Log)
for ($i=1; $i -lt $Log.Count; $i++) { # ignore the header
$Testcase = $Log[$i].split("`n")
You'll notice the split is done on n which is the powershell NewLine character. Then I updated the object you created to exclude the [#TC#] which was used as a delimiter, and assigned it a variable instead of just outputting it. Once I had that $Output variable I tested it for[#ERROR#]and[#WARNING#]` using a regex match and added a new Error property to the object depending on if an error was found or not.
$Output = New-Object PSobject -Property #{
Name = $Testcase[0]
Data = $Testcase[3..($Testcase.count)]|?{!($_ -match "\[#TC#]")}
}
$Output|Add-Member -MemberType NoteProperty -Name "Error" -value $(if($Output.data -match "^.+?(\[#ERROR#]|\[#WARNING#])"){$true}else{$false})
$Output
}
} # End: Function Get-Record
Then I pretty much passed the rest off as is except added my path to the log that I made from your example text.
# Load the log into memory
$Log = Get-Log c:\temp\test.log
$Records = Get-Record -Log $Log
$Records # Added only to see the current progress.
#} #End: Function Import-MyLog1
#
#clear
#Import-MyLog1
Now, you could clean it up a bit I suppose by trimming blank space from the beginning of lines if you wanted, but that's just a matter of taste. But it gives you 2 entries in $Records each with the name you wanted, and the data lines, and a boolean Error property.
Related
As some background, this should take an excel file, and convert it to PDF (and place the PDF into a temporary folder).
E.g. 'C:\Users\gjacobs\Desktop\test\stock.xlsx'
becomes
'C:\Users\gjacobs\Desktop\test\pdf_merge_tmp\stock.pdf'
However, the new file path does not return correctly.
If I echo the string $export_name from within the function, I can see that it has the correct value: "C:\Users\gjacobs\Desktop\test\pdf_merge_tmp\stock.pdf".
But once $export_name is returned, it has a different (incorrect value): "C:\Users\gjacobs\Desktop\test\pdf_merge_tmp C:\Users\gjacobs\Desktop\test\pdf_merge_tmp\stock.pdf".
function excel_topdf{
param(
$file
)
#Get the parent path
$parent = Split-Path -Path $file
#Get the filename (no ext)
$leaf = (Get-Item $file).Basename
#Add them together.
$export_name = $parent + "\pdf_merge_tmp\" + $leaf + ".pdf"
echo ($export_name) #prints without issue.
#Create tmp dir
New-Item -Path $parent -Name "pdf_merge_tmp" -ItemType "Directory" -Force
$objExcel = New-Object -ComObject excel.application
$objExcel.visible = $false
$workbook = $objExcel.workbooks.open($file, 3)
$workbook.Saved = $true
$xlFixedFormat = “Microsoft.Office.Interop.Excel.xlFixedFormatType” -as [type]
$workbook.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $export_name)
$objExcel.Workbooks.close()
$objExcel.Quit()
return $export_name
}
$a = excel_topdf -file 'C:\Users\gjacobs\Desktop\test\stock.xlsx'
echo ($a)
The issue you're experiencing is caused by the way how PowerShell returns from functions. It's not something limited to New-Item cmdlet. Every cmdlet which returns anything would cause function output being altered with the value from that cmdlet.
As an example, let's take function with one cmdlet, which returns an object:
function a {
Get-Item -Path .
}
$outputA = a
$outputA
#### RESULT ####
Directory:
Mode LastWriteTime Length Name
---- ------------- ------ ----
d--hs- 12/01/2021 10:47 C:\
If you want to avoid that, these are most popular options (as pointed out by Lasse V. Karlsen in comments):
# Assignment to $null (or any other variable)
$null = Get-Item -Path .
# Piping to Out-Null
Get-Item -Path . | Out-Null
NOTE: The behavior described above doesn't apply to Write-Host:
function b {
Write-Host "bbbbbb"
}
$outputB = b
$outputB
# Nothing displayed
Interesting thread to check if you want to learn more.
So I'm trying to create a "download" function that uses a piped object property to determine a download method (sftp or http). Then either create an sftp script for putty/winscp or curl the http url. I am defining objects as follows:
#WinSCP
$winscp = new-object psobject
$winscp | add-member noteproperty name "WinSCP"
$winscp | add-member noteproperty dltype "http"
$winscp | add-member noteproperty file "winscp.exe"
$winscp | add-member noteproperty url "https://cdn.winscp.net/files/WinSCP-5.17.8-Setup.exe"
$winscp | add-member noteproperty path "$env:ProgramFiles(x86)\WinSCP"
$winscp | add-member noteproperty install 'msiexec /i "$DataPath\$winscp.file" /quiet /norestart'
#Database
$db = new-object psobject
$db | add-member noteproperty name "Client Database"
$db | add-member noteproperty dltype "sftp"
$db | add-member noteproperty file "database_"
$db | add-member noteproperty ver "check"
$db | add-member noteproperty ext ".csv"
$db | add-member noteproperty dir "db"
#DatabaseVersion
$db_ver = new-object psobject
$db_ver | add-member noteproperty name "Database Version File"
$db_ver | add-member noteproperty dltype "sftp"
$db_ver | add-member noteproperty file "current_version.txt"
$db_ver | add-member noteproperty dir "db"
Currently I'm having issues with the $Input variable within the function. It can only be used once and does not translate into an if statement. Since it contains an object with multiple properties, it needs converted to a new object within the function first I think. I'm new to powershell and haven't found a way of doing this yet. Here is the function I made and am trying to use:
function Download () {
#HTTP Download Method
if ($input.dltype -eq "http") {
curl $input.url -O $DataPath\$input.file
#HTTP Success or Error
$curlResult = $LastExitCode
if ($curlResult -eq 0)
{
Write-Host "Successfully downloaded $input.name"
}
else
{
Write-Host "Error downloading $input.name"
}
pause
}
#SFTP Download Method
if ($input.dltype -eq "sftp") {
sftpPassCheck
#Detect if version required
if ($input.ver = "check") {
#Download the objects version file
"$+$Input+_ver" | Download
#Update the object's ver property
$input.ver = [IO.File]::ReadAllText("$DataPath\current_version.txt")
#Build the new filename
$input.file = "$input.file"+"$input.ver"+"$input.ext"
#Delete the version file
Remove-Item "$DataPath\current_version.txt"
}
& "C:\Program Files (x86)\WinSCP\WinSCP.com" `
/log="$DataPath\SFTP.log" /ini=nul `
/command `
"open sftp://ftpconnector:$script:sftp_pass#$input.ip/ -hostkey=`"`"ssh-ed25519 255 SETvoRlAT0/eJJpRhRRpBO5vLfrhm5L1mRrMkOiPS70=`"`" -rawsettings ProxyPort=0" `
"cd /$input.dir" `
"lcd $DataPath" `
"get $input.file" `
"exit"
#SFTP Success or Error
$winscpResult = $LastExitCode
if ($winscpResult -eq 0)
{
Write-Host "Successfully downloaded $input.name"
}
else
{
Write-Host "Error downloading $input.name"
}
}
}
I'm probably missing something simple but I'm clueless at this point. Oh usage should be:
WinSCP | download
The proper way to bind input from the pipeline to a function's parameters is to declare an advanced function - see about_Functions_Advanced_Parameters and the implementation in the bottom section of this answer.
However, in simple cases a filter will do, which is a simplified form of a function that implicitly binds pipeline input to the automatic $_ variable and is called for each input object:
filter Download {
if ($_.dltype -eq "http") {
# ...
}
}
$input is another automatic variable, which in simple (non-advanced) functions is an enumerator for all pipeline input being received and must therefore be looped over.
That is, the following simple function is the equivalent of the above filter:
function Download {
# Explicit looping over $input is required.
foreach ($obj in $input) {
if ($obj.dltype -eq "http") {
# ...
}
}
}
If you do want to turn this into an advanced function (note that I've changed the name to conform to PowerShell's verb-noun naming convention):
function Invoke-Download {
param(
# Declare a parameter explicitly and mark it as
# as pipeline-binding.
[Parameter(ValueFromPipeline, Mandatory)]
$InputObject # Not type-constraining the parameter implies [object]
)
# The `process` block is called for each pipeline input object
# with $InputObject referencing the object at hand.
process {
if ($InputObject.dltype -eq "http") {
# ...
}
}
}
mklement0 is spot on - $input is not really meant to used directly, and you're probably much better off explicitly declaring your input parameters!
In addition to the $InputObject pattern shown in that answer, you can also bind input object property values to parameters by name:
function Download
{
param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('dltype')]
[string]$Protocol = 'http'
)
process {
Write-Host "Choice of protocol: $Protocol"
}
}
Notice that although the name of this parameter is $Protocol, the [Alias('dltype')] attribute will ensure that the value of the dltype property on the input object is bound.
The effect of this is:
PS ~> $WinSCP,$db |Download
Choice of protocol: http
Choice of protocol: sftp
Keep repeating this pattern for any required input parameter - declare a named parameter mapped to property names (if necessary), and you might end up with something like:
function Download
{
[CmdletBinding()]
param(
[Parameter(ValueFromPipelineByPropertyName = $true)]
[ValidateSet('sftp', 'http')]
[Alias('dltype')]
[string]$Protocol,
[Parameter(ValueFromPipelineByPropertyName = $true)]
[Alias('dir')]
[string]$Path = $PWD,
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('url','file')]
[string]$Uri
)
process {
Write-Host "Downloading $Uri to $Path over $Protocol"
}
}
Now you can do:
PS ~> $WinSCP,$db |Download
Downloading https://cdn.winscp.net/files/WinSCP-5.17.8-Setup.exe to C:\Program Files(x86)\WinSCP over http
Downloading database_ to db over sftp
We're no longer dependent on direct access to $input, $InputObject or $_, nice and clean.
Please see the about_Functions_Advanced_Parameters help file for more information about parameter declaration.
I have the following code:
$html = New-Object -ComObject "HTMLFile"
$source = Get-Content -Path $FilePath -Raw
try
{
$html.IHTMLDocument2_write($source) 2> $null
}
catch
{
$encoded = [Text.Encoding]::Unicode.GetBytes($source)
$html.write($encoded)
}
$t = $html.getElementsByTagName("table") | Where-Object {
$cells = $_.tBodies[0].rows[0].cells
$cells[0].innerText -eq "Name" -and
$cells[1].innerText -eq "Description" -and
$cells[2].innerText -eq "Default Value" -and
$cells[3].innerText -eq "Release"
}
The code works fine on Windows Powershell 5.1, but on Powershell Core 7 $_.tBodies[0].rows returns null.
So, how does one access the rows of an HTML table in PS 7?
PowerShell (Core), as of 7.3.1, does not come with a built-in HTML parser - and this may never change.
You must rely on a third-party solution, such as the PowerHTML module that wraps the HTML Agility Pack.
The object model works differently than the Internet Explorer-based one available in Windows PowerShell; it is similar to the XML DOM provided by the standard System.Xml.XmlDocument type ([xml])[1]; see the documentation and the sample code below.
# Install the module on demand
If (-not (Get-Module -ErrorAction Ignore -ListAvailable PowerHTML)) {
Write-Verbose "Installing PowerHTML module for the current user..."
Install-Module PowerHTML -ErrorAction Stop
}
Import-Module -ErrorAction Stop PowerHTML
# Create a sample HTML file with a table with 2 columns.
Get-Item $HOME | Select-Object Name, Mode | ConvertTo-Html > sample.html
# Parse the HTML file into an HTML DOM.
$htmlDom = ConvertFrom-Html -Path sample.html
# Find a specific table by its column names, using an XPath
# query to iterate over all tables.
$table = $htmlDom.SelectNodes('//table') | Where-Object {
$headerRow = $_.Element('tr') # or $tbl.Elements('tr')[0]
# Filter by column names
$headerRow.ChildNodes[0].InnerText -eq 'Name' -and
$headerRow.ChildNodes[1].InnerText -eq 'Mode'
}
# Print the table's HTML text.
$table.InnerHtml
# Extract the first data row's first column value.
# Note: #(...) is required around .Elements() for indexing to work.
#($table.Elements('tr'))[1].ChildNodes[0].InnerText
A Windows-only alternative is to use the HTMLFile COM object, as shown in this answer, and as used in your own attempt - I'm unclear on why it didn't work in your specific case.
[1] Notably with respect to supporting XPath queries via the .SelectSingleNode() and .SelectNodes() methods, exposing child nodes via a .ChildNodes collection, and providing .InnerHtml / .OuterHtml / .InnerText properties. Instead of an indexer that supports child element names, methods .Element(<name>) and .Elements(<name>) are provided.
I used the answer above for my solution. I installed PowerHTML.
I wanted to extract the datatable from https://www.dicomlibrary.com/dicom/dicom-tags/ and convert them.
From this:
<tr><td>(0002,0000)</td><td>UL</td><td>File Meta Information Group Length</td><td></td></tr>
To this:
{"00020000", "ULFile Meta Information Group Length"}
$page = Invoke-WebRequest https://www.dicomlibrary.com/dicom/dicom-tags/
$htmldom = ConvertFrom-Html $page
$table = $htmlDom.SelectNodes('//table') | Where-Object {
$headerRow = $_.Element('tr') # or $tbl.Elements('tr')[0]
# Filter by column names
$headerRow.ChildNodes[0].InnerText -eq 'Tag'
}
foreach ($row in $table.SelectNodes('tr'))
{$a = $row.SelectSingleNode('td[1]').innerText.Trim() -replace "`n|`r|\s+", " " -replace "\(",'{"' -replace ",","" -replace "\)",'",'
$c = $row.SelectSingleNode('td[3]').innerText.Trim() -replace "`n|`r|\s+", " "
$b=$row.seletSingleNode('td[2]').innerText.Trim() -replace "`n|`r|\s+", ""; $c = '"'+$b+$c+'"},'
$row = New-Object -TypeName psobject
$row | Add-Member -MemberType NoteProperty -Name Tag -Value $a
$row | Add-Member -MemberType NoteProperty -Name Value -Value $c
[array]$data += $row
}
$data | Out-File c:\scripts\dd.txt
I've decided it makes sense that functions being called by a Powershell script should
Log the same output to both a log file and to the console and
should return a status indicating success/failure.
I found a way to do this but it seems ridiculously cumbersome and backwards (illustrated below). I'm thinking this is such a basic and essential capability for any scripting language and that I must be really lost and confused to be doing something in such a backwards way. I'm pretty new to PowerShell but come from a C# background.
I ended up adding -PassThru to every Add-Content statement in the function so the log entry will be coming back in the pipeline as item of an Object[] collection. I then am passing back a final boolean item in the Object[] collection which is the status of the function.
# Main script c:\temp\test1.ps1
Function Write-FunctionOutputToConsole {
Param ([Object[]] $FunctionResults)
foreach ($item in $FunctionResults) {
if ($item -is [System.Array]) {
Write-Host $($item)
}
}
}
Function Get-FunctionReturnCode {
Param ([Object[]] $FunctionResults)
if ($FunctionResults[-1] -is [System.Boolean]) {
Return $FunctionResults[-1]
}
}
. c:\temp\test2.ps1 #pull in external function
$LogFile = "c:\temp\test.log"
$results = FunctionThatDoesStuff -LogFile $LogFile -DesiredReturnValue $true
Write-FunctionOutputToConsole -FunctionResults $results
$FunctionReturnCode = Get-FunctionReturnCode -FunctionResults $results
Add-Content -Path $LogFile -Value "$(Get-Date -Format G) Logging in Main: returnValue=$FunctionReturnCode" -PassThru
# Do some logic based on $FunctionReturnCode
External function
# c:\temp\test2.ps1
function FunctionThatDoesStuff {
Param(
[string] $LogFile,
[bool] $DesiredReturnValue
)
Add-Content -Path $LogFile -Value "-----------------------------------------" -PassThru
Add-Content -Path $LogFile -Value "$(Get-Date -Format G) returnValue=$DesiredReturnValue" -PassThru
Add-Content -Path $LogFile -Value "$(Get-Date -Format G) line 1 being logged" -PassThru
Add-Content -Path $LogFile -Value "$(Get-Date -Format G) line 2 being logged" -PassThru
return $DesiredReturnValue
}
Console Output:
PS C:\Temp> c:\temp\test1.ps1
-----------------------------------------
7/19/2018 3:26:28 PM returnValue=True
7/19/2018 3:26:28 PM line 1 being logged
7/19/2018 3:26:28 PM line 2 being logged
7/19/2018 3:26:28 PM Logging in Main: returnValue=True
Log File
PS C:\Temp> get-content c:\temp\test.log
-----------------------------------------
7/19/2018 3:29:59 PM returnValue=True
7/19/2018 3:29:59 PM line 1 being logged
7/19/2018 3:29:59 PM line 2 being logged
7/19/2018 3:29:59 PM Logging in Main: returnValue=True
As you can see this results in the identical information in the Console and logging file.
I think you're misunderstanding how PowerShell works. For one thing, the information whether or not the last command was successful is automatically stored in the automatic variable $?. In case of an error cmdlets will throw an exception that can be caught for error handling (see also). There is no need to signal success or error status with a return value. Also, PowerShell by default returns all uncaptured output from a function. The return keyword is just for control flow.
I would implement a logging function somewhat like this:
function Write-LogOutput {
[CmdletBinding()]
Param(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
[string[]]$Message,
[Parameter(Position=1, Mandatory=$false)]
[ValidateScript({Test-Path -LiteralPath $_ -IsValid})]
[string]$LogFile = '.\default.log',
[Parameter(Mandatory=$false)]
[switch]$Quiet,
[Parameter(Mandatory=$false)]
[switch]$PassThru
)
Process {
$Message | ForEach-Object {
$msg = "[{0:yyyy-MM-dd HH:mm:ss}]`t{1}" -f (Get-Date), $_
if (-not $Quiet.IsPresent) {
$msg | Out-Host
}
$msg
} | Add-Content $LogFile
if ($PassThru.IsPresent) {
$Message
}
}
}
and then use it like this:
function FunctionThatDoesStuff {
# ...
# something that should be logged, but not returned
'foo' | Write-LogOutput -LogFile 'C:\path\to\your.log'
# something that should be logged and returned by the function
'bar' | Write-LogOutput -LogFile 'C:\path\to\your.log' -PassThru
# something that should be returned, but not logged
'baz'
# ...
}
$result = FunctionThatDoesStuff
# Output:
# -------
# [2018-07-19 23:44:07] foo
# [2018-07-19 23:44:07] bar
$result
# Output:
# -------
# bar
# baz
Here is my script which returns a boolean
param($fileName, $path, $contextMenuItem, $automationDLLPath)
function CloseWindowsExplorer()
{
(New-Object -comObject Shell.Application).Windows() | foreach-object {$_.quit()}
}
Try
{
Import-Module $automationDLLPath
# Open the explorer window in a maximized form
Start-Process explorer $path -WindowStyle Maximized
Start-Sleep 1
Get-UIAActiveWindow
# Get the "Items View" in Explorer to go through all the lements
$list = Get-UIAList -Name 'Items View' -TimeOut 30000;
# Get the file specified in the feature file from the Items View
# Added a sleep because the VM takes time to perform the functions
Start-Sleep 1
$file = $list | Get-UIAListItem -Name $fileName;
# Perform a single click on the file to invoke a right click on it
Invoke-UIAListItemSelectItem -InputObject $file -ItemName $fileName;
# Added a sleep because the VM takes time to perform the functions
Start-Sleep 1
# Invoke the right click on the selected file
$menu = Invoke-UIAControlContextMenu -InputObject $file;
Start-Sleep 1
# select our context menu item
$menuItem = Get-UIAMenuItem -InputObject $menu $contextMenuItem -TimeOut 30000;
# Display error if the required item in the context menu is not found
if( $null -eq $menuItem){
%{ Write-Host 'cannot find menuItem' }
}
# Invoke the item if found in the context menu
else{
Invoke-UIAMenuItemClick -InputObject $menuItem
}
# close the windows explorer and return true
CloseWindowsExplorer
Write-Output "true"
}
Catch
{
# close the explorer window as a part of teardown and return false to reflect test failure
Write-Output "false"
CloseWindowsExplorer
}
I want the script to print the exact exception that was caught as well as return a boolean but in this case it is just returning false when the script fails. Any help is appreciated
Basically I need to print the exception as if the try catch block does not exist.
You need to use the special variable $_
This small example shows how it works:
try {
testmenow
} catch {
Write-Host $_
}
$_ is an object so you can do
$_|gm
in the catch block in order to see the methods you can call.