Powershell -match operator issue - powershell

I've written a script that compares two strings, both of which are path names. The first is the full path to a file and the second is a higher level path. I've replaced spaces and backslashes with underscores.
The variables are assigned correctly such as
$full = "__server_department_project_file.txt"
$part = "__server_department_"
The script uses
$testformatch = $full -match $part
In one of my environments this works perfectly (returning TRUE when appropriate). In another completely separate environment this fails constantly (always returns FALSE).
In the failing domain, when I type these things out manually it returns TRUE as expected, but the script always returns FALSE. I've added a testing line that displays the comparisons, copied those results dumped to the screen and manually cut and pasted them into variables in ps command line directly - and those return TRUE.
I'm at a complete loss for what might be causing this. Are there special characters or rules about -match that may be coming into play? Any ideas would be greatly appreciated. Thanks!

Related

Parsing "" - Unrecognized escape sequence \T

I am trying to modify .config file. this line of code is only meant to be repleced in this file and few others with a new one from xml file but that goes later in code, currently I have issue with this line as I am not able to pass it to variable in a way that it will be treated as a regular string, will not be changed it in any way and will not throw "Parsing "" - Unrecognized escape sequence \T" exeption
I have always been doing it in this way if I don't need to use variables inside:
$oldValueSU = '<add key="splunk_username" value="${(splunk_username=D:\Tools\localtokens.xml)}"/>'
I also tried in this way
$oldValueSU = "<add key=""splunk_username"" value='`${(splunk_username=D:\Tools\localtokens.xml)}'/>"
None of these options work I am still receiving error "parsing "[Path I provided above]" - Unrecognized escape sequence \T."
How Script works:
The script works in a way that it takes that variable and looks through the whole file in order to find a mathing one of it does then it takes a path to that file and adds it to other variable and then changes it's value to a diffrent string.
If more information is needed I will be happy to provide it
Alright I found the issue and solution in my code
The issue was while trying to check if content of a file matches given string
if (($file -match $oldValueSU) -and ($file -match $oldValueSP))
It was using -match which uses Regex which was cousing the exeption I changed it to:
if (($file -like "*$oldValueSU*") -and ($file -like "*$oldValueSP*"))
After that in a part where in my code I was using -replace (which also uses Regex):
$fileContentPathTemp -replace "*$oldValueSU*", $newValueSU
I changed it to .Replace which works directly on String and it solved the issue:
$fileContentPathTemp.Replace($oldValueSU,$newValueSU)
So the whole issue was based on using Regex this solution is more like a workaround which just does not use it at all
I hope this solution will help somebody in the future, I am sorry for not providing all of the nececary information at the beggining. Thanks everyone for spending time on my issue

PowerShell safe expansion of non printing characters in arbitrary strings

I have data in an XML file, that will eventually be used as a Registry path, which MAY contain non printing characters (for example when copying the path from a web site into the XML). I want to validate the data and throw a specific error if non printing characters are found.
In Powershell, if I define a variable with non printing characters in single quotes and then test-Path it tests as a valid path as the non printing character is handled as a literal.
Test-Path 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n#microsoft.com/GENUINE\#microsoft.com/GENUINE' -isValid
The same thing with double quotes will "expand" the non printing characters and return false, which is what I need.
Test-Path "HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n#microsoft.com/GENUINE\#microsoft.com/GENUINE" -isValid
I have found reference to [string]::Format(() being used to expand the non printing characters, but
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n#microsoft.com/GENUINE\#microsoft.com/GENUINE'
[string]::Format("{0}",$invalidPath)
does not expand the non printing character as expected.
I have also seen reference to using Invoke-Expression but that is NOT safe, and not an option.
Finally I found $ExecutionContext.InvokeCommand.ExpandString(), which seems to work,
$ExecutionContext.InvokeCommand.ExpandString('HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n#microsoft.com/GENUINE\#microsoft.com/GENUINE')
returns a multiline string to the console, while
$ExecutionContext.InvokeCommand.ExpandString('Write-Host "Screwed"') returns the actual string to the console, rather than actually executing the Write-Host and only returning Screwed to the console.
Finally,
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n#microsoft.com/GENUINE\#microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid
returns false as expected. Which has me thinking this is the correct approach to pursue, but given all the gotchas elsewhere, I want to be 100% sure there is no way for this approach to be used as a security weak point. Am I on the right track, or are there gotchas my Google-Fu hasn't turned up yet?
Like Invoke-Expression, $ExecutionContext.InvokeCommand.ExpandString() is vulnerable to injection of unwanted commands, except that in the latter case such commands are only recognized if enclosed in $(...), the subexpression operator, as that is the only way to embed commands in expandable strings (which the method's argument is interpreted as).
For instance:
$ExecutionContext.InvokeCommand.ExpandString('a $(Write-Host -Fore Red Injected!) b')
A simple way to prevent this is to categorically treat all embedded $ chars. verbatim, by escaping them with `:
'a $(Write-Host -Fore Red Injected!) b',
'There''s no place like $HOME',
'Too `$(Get-Date) clever by half' |
ForEach-Object {
$ExecutionContext.InvokeCommand.ExpandString(($_ -replace '(`*)\$', '$1$1`$$'))
}
Note: It is sufficient to escape verbatim $ in the input string. A Unicode escape-sequence representation of $ (or ( / )) (`u{24} (or `u{28} / `u{29}), supported in PowerShell (Core) v6+ only), is not a concern, because PowerShell treats the resulting characters verbatim.
Of course, you may choose to report an error if there's a risk of command (or variable-value) injection, which can be as simple as:
$path = 'There''s no place like $HOME'
if ($path -match '\$') { Throw 'Unsupported characters in path.' }
However, this also prevents legitimate use of a verbatim $ in paths.
Taking a step back:
You state that the paths may have been copy-pasted from a web site.
Such a pasted string may indeed contain (perhaps hidden) control characters, but they would be contained verbatim rather than as PowerShell_escape sequences.
As such, it may be sufficient to test for / quietly remove control characters from the string's literal content (before calling Test-Path -IsValid):
# Test for control characters.
if ($path -match '\p{C}') { throw 'Path contains control characters.' }
# Quietly remove them.
$sanitizedPath = $path -replace '\p{C}'
I was initially running PS Version 7.1.3, in which all of these methods bore the same results.
When I ran:
$invalidPath = 'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n#microsoft.com/GENUINE\#microsoft.com/GENUINE'
Test-Path ($ExecutionContext.InvokeCommand.ExpandString($invalidPath)) -isValid
True is returned
Same as:
Test-Path ([regex]::Escape($invalidPath)) -IsValid
As well as the other methods you mentioned.
In testing in 5.1 I saw the same results as you.
In your XML, would you be seeing something like `n or \n or the actual non-printing characters? IE
'HKEY_LOCAL_MACHINE\SOFTWARE\Test\`n#microsoft.com/GENUINE\#microsoft.com/GENUINE'
OR
'HKEY_LOCAL_MACHINE\SOFTWARE\Test\
#microsoft.com/GENUINE\#microsoft.com/GENUINE'
If the latter is true you should be able to just pass the string to test-path in a variable like Test-Path "$invalidPath" -IsValid to get what you're looking for. In 7.1.3 (maybe earlier) it seems that PS is smart enough to parse those escape sequences and such -- or there is no simple way of doing what you're looking for that I can find.

Do chained powershell replace commands execute one after the other?

This would likely be a non-issue with expert regex comprehension. And only matters because I am running multiple chained replace commands that affect some of the same text in a text file. I also imagine partitioning the txt files based on how delimiter words --that are requiring multiple replaces-- are used, before replace, would help. With that said basic structural knowledge of powershell is useful and I have not found many great resources (open to suggestions!).
The question: Do chained powershell replace commands execute one after the other?
-replace "hello:","hello " `
-replace "hello ","hello:"
} | out-file ...
Would this silly example above yield hello:'s where there were initially hello:'s?
From working through some projects I gather that the above works most of the time. Yet there always seem to be some edge cases. Is this another aspect of the script or is the order that chained commands (decent number of them) execute in never variable?
What you have there are operators, not commands.
I say that not to be pedantic, but because "command" has a specific meaning in PowerShell (it is a general name encompassing functions, cmdlets, aliases, applications, filters, configurations (this is a DSC construct), workflows, and scripts), and because the way they can be used together is different.
Most operators are reserved words that begin with - (but other things count as operators, like casting), and you can indeed use them chained together. They also execute in order.
I need to clarify; they don't necessarily execute in the order given when you mix operators. Multiple of the same operator will because they all have the same precedence, but you should check about_Operator_Precedence to see the order that will be used when you combine them.
Note that some operators can "short-circuit" (which may sound like a malfunction, but it isn't), that is the result of certain boolean operators will not evaluate later operations if the boolean result can not change.
For example:
$true -or $false
In this example, the $false part of the expression will never actually be evaluated. This is important if the next part of the expression is complex or even invalid. Consider these:
$true -or $(throw)
$false -or $(throw)
The first will return $true because (presumably) nothing in the coming expression could make it $false.
The second line must evaluate the second expression, and in doing so it throws an exception, halting the program.
So, aside from that aside, yes, you can continue to chain your operators. You also don't need a line continuation character (backtick `) at the end of the line if the operator itself is at the end. More useful with boolean operators:
$a -and
$b -or
$c -xor
$false
A little awkward with something like replace:
'apple' -replace
'p',
'z'
Regarding this:
And only matters because I am running multiple chained replace
commands that affect some of the same text in a text file.
These operators aren't touching anything in a file, they are working with data in memory, as literals or variables in your script (what you do with it then, like writing to a file is your business).
Further, even then it doesn't change any values already in variables, it returns new ones, which you may assign to a variable or use in any other way.
$var = 'apple'
$var -replace 'p','Z'
$var
The value of the replacement will be returned, but nothing was done with it so it went out to the console. Then you can see that $var was not modified at all, as opposed to:
$var = 'apple'
$var = $var -replace 'p','Z'
$var
Where the value of $var was overwritten.
If there are edge cases, it's likely to be a misunderstanding of something in the sequence of events (an incorrect regular expression, not assigning or using a value, incorrect logic, etc.), as the order of operations will be consistent. If you have any such edge cases, please post them!

powershell -match Unexpect Results

i've written a simple PowerShell script that is designed to take a file name and then move the file into a particular folder.
The files in question are forms scanned in as PDF documents.
Within the file name, I have defined a unique string of characters used to help identify which form it is and then my script will sort the file into the correct folder.
I've captured the file name as a string variable.
I am using -match to evaluate the file name string variable and my issue is that match is acting like...well -like.
For example, my script looks for (F1) in the string and if this returns true my script will move the file into a folder named IT Account Requests.
This all works well until my script finds a file with (F10) in the name, as 'match' will evaluate the string and find a match for F1 also.
How can I use 'match' to return true for an exact string block?
I know this may sound like a fairly basic newbie question to ask, but how do I use -match to tell the different between the two file types?
I've scoured the web looking to learn how to force -match to do what I would like but maybe I need a re-think here and use something other than 'match' to gain the result I need?
I appreciate your time reading this.
Code Example:
$Master_File_name = "Hardware Request (F10).pdf"
if ($Master_File_name -match "(F1)"){Write-Output "yes"}
if ($Master_File_name -match "(F10)"){Write-Output "yes"}
Both if statements return 'yes'
-match does a regular expression based match against your string, meaning that the right-hand side argument is a regex pattern, not a literal string.
In regex, (F1) means "match on F and 1, and capture the substring as a separate group".
To match on the literal string (F1), escape the pattern either manually:
if($Master_File_Name -match '\(F1\)'){Write-Output 'yes'}
or have it done for you automatically using the Regex.Escape() method:
if($Master_File_Name -match [regex]::Escape('(F1)')){Write-Output 'yes'}

Iteration over inline-initialized array?

I'm new to PowerShell, and have stumbled across some behavior I can't explain while trying to do something fairly straightforward. I have a few variables containing paths within the file system, and I want to make sure that they all have trailing slashes (and add them if they're missing).
# append trailing slash if not present
$engineXCopyPath, $engineXBackupPath, $enlistmentBuildTargetPath | ForEach-Object
{
Write-Host "hi" #where I would check the last character and add a \ if it weren't
}
When running my script, this code keeps prompting for Process[_n_] until I give it no input, in which case it prints the entire contents of the line rather than executing it.
As far as I know, it should be iterating over the three items fed to it, printing "hi" for each one. I'm not sure why it's prompting for any input (not to mention why it stops when I give it blank input), nor do I know why it's printing "Write-Host "hi" #where I would check the last character and add a \ if it weren't" instead of just "hi".
Thanks for your help!
You need to include the opening brace on the same line as ForEach-Object:
$engineXCopyPath, $engineXBackupPath, $enlistmentBuildTargetPath | ForEach-Object {
Write-Host "hi" #where I would check the last character and add a \ if it weren't
}
Otherwise, PowerShell is prompting you for the Process input scriptblocks that are required for ForEach-Object. Then it is interpreting the braces as the creation of a ScriptBlock and printing the contents.