My script is throwing an error like so:
ConvertFrom-StringData : Data item 'a3512c98c9e159c021ebbb76b238707e' in line 'a3512c98c9e159c021ebbb76b238707e = My
Pictures/Tony/Automatic Upload/Tony’s iPhone/2022-10-08 21-46-21 (2).mov' is already defined.
At P:\scripts\code\pcloud_sync.ps1:66 char:179
+ ... ace '^[a-f0-9]{32}( )', '$0= ' -join "`n") | ConvertFrom-StringData
+ ~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [ConvertFrom-StringData], PSInvalidOperationException
+ FullyQualifiedErrorId : InvalidOperation,Microsoft.PowerShell.Commands.ConvertFromStringDataCommand
I want to catch this error by the "is already defined" text and then run a separate command if this is caught before the script reruns the code - possible?
You can use $_.Exception.Message attribute to get the exception message as string and then use -match statement to check if it's follows particular pattern.
$Here = #'
Msg1 = The string parameter is required.
Msg2 = Credentials are required for this command.
Msg1 = The specified variable does not exist.
'#
try {
ConvertFrom-StringData -StringData $Here
} catch {
if($_.Exception.Message -match "is already defined") {
Write-Output "Do Something"
}
}
Related
How do I use FlaUI to set the value in a specific field after clicking the "Save As" button in Paint?
I'm trying to use FlaUI to automate filling a field in Paint after clicking "Save As". The field in question is named "Name:". Here is the code I have so far:
Add-Type -Path C:\Users\sergi\assemblies\bin\Release\net48\publish\FlaUI.UIA3.dll
$windowTitle = 'Untitled - Paint'
$control = 'Name:'
$automation = [FlaUI.UIA3.UIA3Automation]::new()
$process = get-process | Where-Object {$_.MainWindowTitle -match $windowTitle}
$app = [FlaUI.Core.Application]::Attach( $process )
foreach( $wnd in $app.GetAllTopLevelWindows( $automation ) ) {
$myinput = $wnd.FindAllDescendants() | Where-Object { $_.Name -eq $control }
$myinput[0].SetValue('Value Test')
}
After running the code it gives this error:
Method invocation failed because [FlaUI.Core.AutomationElements.AutomationElement] does not contain a method named 'SetValue'.
On line: 11 character: 5
+ $saveButton[0].SetValue('Value Test')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
However, I'm having a hard time finding a way to access this particular field and set its value using FlaUI. Any suggestions on how I can do this?
I have been doing a lot of reading on invoke-expression (also known as iex) and I'm having trouble getting it to work for me.
My understanding is, it will run any powershell code you give to it. However, when I run my tests on it, it does not run the code.
Example:
## testcode.ps1
$myvar = "i am here"
if ($myvar -ne $null) {
"($myvar) variable is Full"
} else {
"($myvar) variable is Empty"
}
Now, if I cat(gc) this file and I pass it to iex, it outputs a bunch of errors. Same thing happens when I save the code into a variable and then feed the variable to iex. Neither works.
Despite the fact that I've tried numerous examples, I feel there's something minor I'm doing wrong that I'm hoping someone can point out for me.
I'm new to Windows scripting, so please bear with me. These are the results of the tests I performed:
First Test:
PS C:\Users\J> gc C:\Users\J\testcode.ps1 | iex
Invoke-Expression : Cannot bind argument to parameter 'Command' because it is an empty string.
At line:1 char:31
+ cat C:\Users\J\testcode.ps1 | iex
+ ~~~
+ CategoryInfo : InvalidData: (:PSObject) [Invoke-Expression], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorEmptyStringNotAllowed,Microsoft.PowerShell.Commands.InvokeExpressionCommand
iex : At line:1 char:23
+ if ($myvar -ne $null) {
+ ~
Missing closing '}' in statement block or type definition.
At line:1 char:31
+ cat C:\Users\J\testcode.ps1 | iex
+ ~~~
+ CategoryInfo : ParserError: (:) [Invoke-Expression], ParseException
+ FullyQualifiedErrorId : MissingEndCurlyBrace,Microsoft.PowerShell.Commands.InvokeExpressionCommand
Second Test:
PS C:\Users\J> $scriptBlock = gc C:\Users\J\testcode.ps1
PS C:\Users\J>
PS C:\Users\J> iex -Command "$scriptBlock"
iex : At line:1 char:23
+ $myvar = "i am here" if ($myvar -ne $null) { "($myvar) variable ...
+ ~~
Unexpected token 'if' in expression or statement.
At line:1 char:1
+ iex -Command "$scriptBlock"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ParserError: (:) [Invoke-Expression], ParseException
+ FullyQualifiedErrorId : UnexpectedToken,Microsoft.PowerShell.Commands.InvokeExpressionCommand
PS C:\Users\J>
I'm aware that I can just run the file containing the code. However, I need help figuring out how iex works and what it is I'm doing wrong.
Please kindly advise.
First things first:
Invoke-Expression should generally be avoided and used only as a last resort, due to its security risks. In short: avoid it, if possible, given that superior alternatives are usually available. If there truly is no alternative, only ever use it on input you either provided yourself or fully trust - see this answer.
For the record: in the case at hand, the superior alternative is to directly invoke the script file:
# Prepend `& `, if the script file path is quoted or references a variable.
C:\Users\J\testcode.ps1
Invoke-Expression (iex) accepts multiple strings via the pipeline, and evaluates each individually, as a self-contained script.
Therefore, you must provide the contents of your script as a whole, as a single string, which is what Get-Content's (gc's) -Raw switch does[1]:
Get-Content -Raw C:\Users\J\testcode.ps1 | Invoke-Expression
Alternatively, pass the script-file contents as an argument:
Invoke-Expression (Get-Content -Raw C:\Users\J\testcode.ps1)
Note that passing the string to evaluate as an argument truly only accepts a single string, so the command would fail without -Raw.
[1] By default, the Get-Content cmdlet reads a file line by line, passing each line through the pipeline as it is being read.
$myvar = "I'm Here"
#Using Invoke-Expression - Accepts a STRING as Input
$SBCode = 'if ($Null -ne $myvar) {"($myvar) variable is Full"}' +
'else {"`$myvar variable is Empty"}'
Clear-Host
"Before Invoke-Expression `$myvar = $myvar"
$Result = Invoke-Expression $SBCode
"Invoke-Expression Returns: $Result"
#Using Invoke-Command - Accepts Script Block as Input
$SBCode = {
if ($myvar -ne $null) {
"($myvar) variable is Full"
}
else {
"`$myvar variable is Empty"
}
} #End $SBCode Script Block
"Before Invoke-Command `$myvar = $myvar"
$Result = Invoke-Command -ScriptBlock $SBCode
"Invoke-Command Returns: $Result"
Results:
Before Invoke-Expression $myvar = I'm Here
Invoke-Expression Returns: (I'm Here) variable is Full
Before Invoke-Command $myvar = I'm Here
Invoke-Command Returns: (I'm Here) variable is Full
# After changing $MyVar = $Null
Before Invoke-Expression $myvar =
Invoke-Expression Returns: $myvar variable is Empty
Before Invoke-Command $myvar =
Invoke-Command Returns: $myvar variable is Empty
HTH
You can use out-string to convert output into string.
cat C:\Users\J\testcode.ps1 | out-string | Invoke-Expression
Line 2 in the script below generates -
"Cannot convert value "System.Object[]" to type
"System.Xml.XmlDocument". Error: "'→', hexadecimal value 0x1A, is an
invalid character. Line 39, position 23."
At line:1 char:8
+ [xml]$x <<<< = Get-Content 4517.xml
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException"
What exception should be specified on line 4 (of the script) to catch the aforementioned error?
try {
[xml]$xml = Get-Content $file # line 2
}
catch [?] { # line 4
echo "XML parse error!"
# handle the parse error differently
}
catch {
echo $error
# some general error
}
Thanks for looking (and answering)
Adrian
Here is a way to discover yourself the full type name of an Exception, the result here gives System.Management.Automation.ArgumentTransformationMetadataException as given by #Adrian Wright.
Clear-Host
try {
[xml]$xml = Get-Content "c:\Temp\1.cs" # line 2
}
catch {
# Discovering the full type name of an exception
Write-Host $_.Exception.gettype().fullName
Write-Host $_.Exception.message
}
System.Management.Automation.ArgumentTransformationMetadataException
I have the csv file with the following values:
User,TimeStamp
Pinky,11/4/2015 5:00
Brain,
Leo,never
Don,unspecified
I want to ensure this file for the TimeStamp column either has a date, or a $null value. To do this I am using the following code:
Function HealthCheckTimeStampColumn
{
Param ($userInputCsvFileWithPath)
Write-Host "Checking if TimeStamp column has invalid values..."
Import-Csv $userInputCsvFileWithPath | %{
if ($_.TimeStamp)
{
Try
{
([datetime]$_.TimeStamp).Ticks | Out-Null
}
Catch [system.exception]
{
$Error.Clear()
$invalidValue = $_.TimeStamp
Write-Error "Invalid Value found `"$_.TimeStamp`"; Value expected Date or `"`""
Exit
}
}
}
Write-Host "All values were found valid."
Write-Host "TimeStamp Healthcheck Column Passed"
Write-Host ""
}
With this code, I get this error:
Invalid Value found "Cannot convert value "never" to type "System.DateTime". Error: "The string was not recognized as
a valid DateTime. There is an unknown word starting at index 0.".TimeStamp"; Value expected Date or ""
At C:\Scripts\Tests\TestTime.ps1:247 char:42
+ Import-Csv $userInputCsvFileWithPath | %{
+ ~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
If I try this line of code Instead:
Write-Error "Invalid Value found `"$invalidValue`"; Value expected Date or `"`""
I get this error:
Invalid Value found ""; Value expected Date or ""
At C:\Scripts\Tests\TestTime.ps1:247 char:42
+ Import-Csv $userInputCsvFileWithPath | %{
+ ~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
The error I am expecting to see is this:
Invalid Value found "never"; Value expected Date or ""
At C:\Scripts\Tests\TestTime.ps1:247 char:42
+ Import-Csv $userInputCsvFileWithPath | %{
+ ~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
Can anyone tell me what I am doing wrong?
You don't really need a try/catch block for this one either. They are good for unexpected and unavoidable errors. However looking about_Type_Operators you will see -as and -is which handle this situation rather gracefully.
-is : Returns TRUE when the input is an instance of the specified .NET Framework type.
-as : Converts the input to the specified .NET Framework type.
When -as encounters a string or something that is not castable to [datetime] it will return a null. More importantly it will not error. I propose that you check all values for non nulls and invalid date times. Capture all of those in a variable. Then check if the variables has any values. Print all at once! and then exit if you want. I also second what user2460798's answer said about the use of exit.
Function HealthCheckTimeStampColumn{
Param ($userInputCsvFileWithPath)
$badRows = Import-Csv $userInputCsvFileWithPath |
Where-Object{-not [string]::IsNullOrEmpty($_.TimeStamp) -and ($_.TimeStamp -as [datetime]) -eq $null}
if($badRows){
$badRows | ForEach-Object{
Write-Host "'$($_.Timestamp)' is not a valid datetime" -ForegroundColor Red
}
Write-Error "$($badRows.Count) Invalid Value(s) found"
} else {
"All values were found valid.","TimeStamp Healthcheck Column Passed","" | Write-Host
}
}
Turning PerSerAl's observation into an answer:
$_ changes meaning from when it is in the foreach-object loop (but outside catch block) to when it is in catchblock. In the first case it is the current object (row), which apparently has the value "never" for its timestamp. But in the catch block it is the errorrecord that was generated as a result of the error. So to fix:
Function HealthCheckTimeStampColumn
{
Param ($userInputCsvFileWithPath)
Write-Host "Checking if TimeStamp column has invalid values..."
Import-Csv $userInputCsvFileWithPath | %{
$row = $_
if ($_.TimeStamp)
{
Try
{
([datetime]$_.TimeStamp).Ticks | Out-Null
}
Catch [system.exception]
{
$Error.Clear()
$invalidValue = $_.TimeStamp
Write-Error "Invalid Value found `"$row.TimeStamp`"; Value expected Date or `"`""
Exit
}
}
}
Write-Host "All values were found valid."
Write-Host "TimeStamp Healthcheck Column Passed"
Write-Host ""
}
BTW, if you want to process the whole file you'll need to remove exit from the catch block.
Line 2 in the script below generates -
"Cannot convert value "System.Object[]" to type
"System.Xml.XmlDocument". Error: "'→', hexadecimal value 0x1A, is an
invalid character. Line 39, position 23."
At line:1 char:8
+ [xml]$x <<<< = Get-Content 4517.xml
+ CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException"
What exception should be specified on line 4 (of the script) to catch the aforementioned error?
try {
[xml]$xml = Get-Content $file # line 2
}
catch [?] { # line 4
echo "XML parse error!"
# handle the parse error differently
}
catch {
echo $error
# some general error
}
Thanks for looking (and answering)
Adrian
Here is a way to discover yourself the full type name of an Exception, the result here gives System.Management.Automation.ArgumentTransformationMetadataException as given by #Adrian Wright.
Clear-Host
try {
[xml]$xml = Get-Content "c:\Temp\1.cs" # line 2
}
catch {
# Discovering the full type name of an exception
Write-Host $_.Exception.gettype().fullName
Write-Host $_.Exception.message
}
System.Management.Automation.ArgumentTransformationMetadataException