I am using this code to load XML that has the potential for errors (human edited).
$xmlReaderSettings = [System.Xml.XmlReaderSettings]::new()
$xmlReaderSettings.CloseInput = $True
$xmlReaderSettings.IgnoreWhitespace = $True
$xmlReaderSettings.IgnoreComments = $True
try {
$xmlReader = [System.Xml.XmlReader]::Create("$xmlPath\$file", $xmlReaderSettings)
$tempXml = [System.Xml.XmlDocument]::new()
$tempXml.Load($xmlReader)
} catch [System.Management.Automation.ItemNotFoundException] {
Write-PxLog "*_Cannot find '$($file.Name)'"
} catch {
Write-PxLog "*_Malformed XML in '$($file.Name)'"
Write-PxLog "*_$($PSItem.Exception.Message)"
$proceed = $false
} finally {
$xmlReader.Close()
}
This seems to catch all errors except errors related to comments. Specifically, Autodesk uses arguments like --trigger_point system for their uninstalls, and I have that in the XML. If that XML get's commented there is a problem, because a comment can't contain --. Unfortunately, the code above completely misses that error. I can use
if ($tempXml.DocumentElement) {
# continue with validating loaded XML
} else {
# report generic error here
}
I would prefer to provide a more detailed error message, ideally with line numbers. But I would have expected $xmlReaderSettings.IgnoreComments = $True would have solved the issue, as the comments get ignored, and the error is in the comments. If I output the XML again, the comments are missing, but it would seem that IgnoreComments really means IgnoreWellFormedComments, and I have to deal with the issue some other way?
Is there a way to actually ignore malformed comments? And if not, why am I not seeing an exception caught? And is there a better answer than "Something happened and it might be a problem in a comment but I can't tell you where, thanks Microsoft." ?
Related
So I have an issue that has been bugging me for a few hours now.
I have two functions, Write-Log, and LogProfileRemoval. In Write-Log, I pass in the two arguments as shown here.
LogProfileRemoval('$LogEventDetail', 100000)
But when I check the variables of LogProfileRemoval they are shown like this
$LogEventDetail = '$LogEventDetail' 100000
$LogMethod = $null
I am aware that I have quotes around the variable $LogEventDetail, that was part of my testing to figure this out. Really that variable could be anything and it still concats those two variables into one and leaves the 2nd parameter as a null value.
What am I doing wrong here.
Thanks
function LogProfileRemoval($LogEventDetail, $LogMethod)
{
Switch ($LogMethod)
{
'EventLog' {LogToEventLog($LogEvent)}
}
}
function Write-Log($logDetail, $logEvent=2)
{
$LogEventDetail = New-Object EventLog -Property #{EventTimeStamp=(Get-Date);EventType=$logEvent;EventDetail=$logDetail}
$LogMethod = 1
LogProfileRemoval('$LogEventDetail', 100000)
}
So by not following best practices, was the issue. Weird becuase I have always wrote my powershell scripts like this. Always been a not fan of the Param way of doing it. I changed it to best practice way (sorta) and it worked great.
I would like to know why it didn't work though but overall It just goes to show me to quick being lazy and do it the right way.
Code working shown below
function LogProfileRemoval
{
param(
$LogEventDetail,
$LogMethod
)
Switch ($LogMethod)
{
'EventLog' {LogToEventLog($LogEvent)}
}
}
function Write-Log($logDetail,$logEvent=2)
{
$LogEventDetail = New-Object EventLog -Property #{EventTimeStamp=(Get-Date);EventType=$logEvent;EventDetail=$logDetail}
$LogMethod = 1
LogProfileRemoval -LogEventDetail $LogEventDetail -LogMethod 'EventLog'
}
I know, there are hundreds of pages that address the -in my opinion- strange way that Powershell handles return values from functions, and I must have visited about half of them ;=)
This particular one drives me nuts.
Consider the following:
I'm doing a call to a function with one parameter (call is not done from within another function):
$result = getVMinfo($vm)
The function getVMinfo looks like this :
function getVMinfo {
param (
[string]$vm
)
try {
Get-WmiObject -Class Win32_DiskDrive -Computername $vm -ErrorAction Stop
}
catch {
$ErrorReturn = $_.Exception.Message
}
if ($ErrorReturn) {
Write-Host "Error =" $ErrorReturn
return $ErrorReturn
}
}
Looks simple enough, and other functions do work when returning a value in this way.
Now, if I run the script, The write-Host bit in the catch does show me that $ErrorReturn is filled with a string (tested that with $ErrorReturn.GetType() ).
However, $result in the calling statement is always empty.
I have tried many suggestions, like creating an array, and use the .Add() to add the errorstring to the array, and then return the array. Nothing seems to work.
I am really at a loss here. Don't understand what I am doing wrong.
Please, help me !
I use if else in my powershell script.
if ($match.Groups.Count) {
while ($match.Success) {
Write-Host ("Match found: {0}" -f $match.Value)
$match = $match.NextMatch()
}
}
else {
Write-Host "Not Found"
}
in the if side, it works, but in the else side, It cannot return "Not Found" . It does not show any error.
PetSerAl, as countless times before, has provided the crucial pointer in a comment:
Perhaps surprisingly, the [System.Text.RegularExpressions.Match] instance returned by the static [regex]::Match() method (or its instance-method counterpart) contains 1 element in its .Groups property even if the matching operation didn't succeed[1], so that, assuming an instance stored in $match, $match.Groups.Count always returns $true.
Instead, use the .Success property to determine if a match was found, as you already do in the while loop:
if ($match.Success) {
while ($match.Success) {
"Match found: {0}" -f $match.Value
$match = $match.NextMatch()
}
} else {
"Not Found"
}
Note that I've removed the Write-Host calls, because Write-Host is generally the wrong tool to use, unless the intent is explicitly to write to the display only, thereby bypassing PowerShell's output streams and thus the ability to send the output to other commands, capture it in a variable or redirect it to a file.
[1] [regex]::Match('a', 'b').Groups.Count returns 1, even though the match clearly didn't succeed.
I need an example that use try..catch..finally clause where the finally is NECESSARY vs try..catch clause where finally is optional. The example below only demonstrated that finally is optional because with or without it, it won't make any different to my output.
My Example (note: $ErrorActionPreference is Continue):
try {
$value = 5 / 0
} catch {
Write-Output "illegal operation"
}
$t = Get-Date
Write-Output ("operation is done at " + "$t")
The reason is I need to know where finally clause become necessary vs just put finally clause no matter what.
A finally clause is just a logical construct saying "this statement or group of statements should always be run at the end of the try block, regardless of whether there was an error or not". It tells people reading the code that there is a logical connection between the code in the try and finally blocks (e.g. opening and closing a database connection). However, beyond that there is no essential difference between
try {
5 / 0
} catch {
'illegal operation'
}
'continued'
and
try {
5 / 0
} catch {
'illegal operation'
} finally {
'continued'
}
You can find some discussion of the subject here.
I think the only way it would make a difference is if you return or exit in the try block:
try {
'foo' # <-- displayed
exit
} finally {
'bar' # <-- displayed
}
'baz' # <-- not displayed
but maybe something like that is just bad design.
I am trying to add custom error message to my file element validator. It is working for all the elements, BUT file. Kindly point out where am I going wrong. I know similar question has been asked before but I want to know what is the problem with this code?
$file= new Zend_Form_Element_File('albumcover');
$file->setAttrib('size',35)
->removeDecorator('label')
->removeDecorator('htmlTag');
$file->setRequired(true)
->addValidator('Size',true,'1MB')
->addValidator('Count',true,1)
->addValidator('IsImage',true,'jpg,jpeg,png');
$file->addErrorMessage("Upload 'jpg,jpeg or png' file of less than 1MB in size");
It shows predefined errors not the error message that I have set
You may want to do this in the controller to check if the element has an error and print a specific error message.
$form = My_Form_File();
...
if ($form->isValid()) {
...
} else {
if ($form->getElement('albumcover')->hasErrors()) {
$form->getElement('albumcover')->addError("Upload 'jpg,jpeg or png' file of less than 1MB in size");
}
}
Though I would recommend letting the user know in the description with
$file->setDescription("Upload 'jpg,jpeg or png' file of less than 1MB in size");