Given that Find.Execute does not allow for RegEx, is there any COM way to do this besides streaming the paragraphs out and stepping through them one by one?
I need to find a RegEx pattern in a Word document, and preferably return the match. Failing that, find a RegEx in a Word document and at least return $True so I can capture it.
N.B.: I realize that the reason Find.Execute is limited is due to it being a call to the "find text" dialog, but I'm hoping there's some similarly efficient way to search for patterns. Find.Execute is fairly quick, streaming out the text from the document as a range and then searching through that is not.
When exactly did Find.Execute stop allowing for regular expressions?
$wd = New-Object -COM "Word.Application"
...
$fnd = $wd.Selection.Find
$fnd.Text = "..." # replace with your pattern
$fnd.MatchWildcards = True
...
$fnd.Execute
The syntax is just a little different from standard regular expressions.
Related
I'm looking for a regsub example that does the following:
123tcl456TCL789 => 123!tcl!456!TCL!789
This is an Tcl example => This is an !Tcl! example
Yes, I could use string first to find a position and mash things but I saw in past a regsub command that does what I want but I can't recall. What would be the regsub command that allows that? I would guess regsub -all -nocase is a start.
I am bad at regsub and regexps. I wonder if there is a site or tool/script that we can supply a string, the final result and then we get the regsub form.
You're looking at the right tool, but there are various options, depending on exactly what the conditions are when faced with other text. Here's one that wraps each occurrence of "Tcl" (any capitalisation) with exclamation marks:
set inputString "123tcl456TCL789"
set replaced [regsub -all -nocase {tcl} $inputString {!&!}]
puts $replaced
That's using a very simple regular expression with the -nocase option, and the replacement means "put ! on either side of the substring matched".
Another (more generally applicable... perhaps) might be to put ! after any letter or number sequence that is followed by a number or letter.
set replaced [regsub -all {[A-Za-z]+(?=[0-9])|[0-9]+(?=[A-Za-z])} $inputString {&!}]
Note that doing things correctly typically requires understanding the real input data fairly well. For example, whether the numbers include floating point numbers in scientific notation, or whether the substrings to delimit are of fixed length.
This is pretty straightforward. I tried creating a rule in the EAC for sent messages, but it's not working as intended. Basically I need to create a rule that checks if any recipients (To, CC or BCC) are from outside my org. If there are any, append a disclaimer to EVERYONE in the recipients (including inside the org).
Doing this via the EAC doesn't work in the sense that when I specify the rule "If the message... is sent to 'Outside the organization' " it finds ONLY recipients outside the org and appends the disclaimer to them. However, I also need to append it for users inside the org if this condition verifies. Unfortunately doing it like this only recipients from outside the org are receiving the appended disclaimer, but not company workers.
I've been working with PS quite a lot lately and New-TransportRule seems to be the way to go to do this, but reading through the documentation hasn't helped me a lot on how to structure said query to do exactly what I want or even how to only apply it to one person for testing purposes.
Any of you guys worked with this cmdlet before and could give me a quick hand?
Thanks!
It's been some time since I've managed Exchange, but judging from the documentation, I'd say you could probably take advantage of the AnyOfRecipientAddressMatchesPatterns predicate (emphasis added):
-AnyOfRecipientAddressMatchesPatterns
[...]
The AnyOfRecipientAddressMatchesPatterns parameter specifies a
condition that looks for text patterns in recipient email addresses by
using regular expressions. You can specify multiple text patterns by
using the following syntax: "Regular expression1","Regular
expression2",..."Regular expressionN".
A match for this condition applies the rule action to all recipients
of the message. For example, if the action is to reject the message,
the message is rejected for all recipients of the message, not just
for the specified recipients.
So let's start by constructing an appropriate pattern:
# Define internal recipient domains
$internalDomains = 'ress.tld','internal.ress.tld','ress-alias.tld'
# Escape as literal regex pattern
$internalDomains = $internalDomains |ForEach-Object { [regex]::Escape($_) }
# Embed in negative look-behind pattern
$nonInternalDomainPattern = "(?<!#(?:$($internalDomains -join '|')))"
The resulting regex pattern will match any email not having any of the three domains listed:
PS ~> $nonInternalDomainPattern
(?<!#(?:ress\.tld|internal\.ress\.tld|ress-alias\.tld))$
PS ~> 'ress#ress.tld' -match $nonInternalDomainPattern # doesn't match on internal recipients
False
PS ~> 'iisresetme#example.org' -match $nonInternalDomainPattern # but it matches any other address
True
Now you just need to include it in a transport rule:
New-TransportRule "Disclaimer on all external communications" -AnyOfRecipientAddressMatchesPatterns $nonInternalDomainPattern -ApplyHtmlDisclaimerText '<your>html goes here</your>'
PS > function ]{1}
PS > ]
1
PS >
PS
Why does this work?
What else can I name a function? All I've found so far that works is * and ].
You can name it almost anything. You can even include newlines and emoji* in the name.
function Weird`nFunctionの名前😀 { Write-Host hey }
$c = gcm Weird*
$c.Name
& $c
Escaping helps with lots of things like that:
function `{ { Write-Host cool }
`{
function `0 { Write-Host null }
gci function:\?
I'll add that this is true for variables too, and there's a syntax that removes the need to do most escaping in the variable name: ${varname} (as opposed to $varname).
With that, you could easily do:
${My variable has a first name,
it's
V
A
something
R,
whatever I dunno
🤷} = Get-Process
You'll note that if you then start typing like $MyTAB it will tab complete in a usable way.
To (somewhat) answer why this should work, consider that the variable names themselves are just stored in .Net strings. With that in mind, why should there be a limit on the name?
There will be limits on how some of these names can be used in certain contexts, because the parser will not understand what to do with it if the names don't have certain characters escaped, but literal parsing of PowerShell scripts are not the only way to use functions or variables or other language constructs, as I've shown some examples of.
Being less limiting also means being able to support other languages and cultures by having wide support for character sets.
To this end, here's one more thing that might surprise you: there are many different characters to represent the same or similar things that we take for granted in code, like quotation marks for example.
Some (human) languages or cultures just don't use the same quote characters we do in English, don't even have them on the keyboard. How annoying would it be to type code if you have to keep switching your keyboard layout or use ALT codes to quote strings?
So what I'm getting at here is that PowerShell actually does support many quote characters, for instance, what do you think this might do:
'Hello’
Pretty obvious it's not the "right" set of quotes on the right side. But surprisingly, this works just fine, even though they aren't the same character.
This does have important implications if you're ever generating code from user input and want to avoid sneaky injection attacks.
Imaging you did something like this:
Invoke-Expression "echo '$($userMsg -replace "'","''")'"
Looks like you took care of business, but now imagine if $userMsg contained this:
Hi’; gci c: -recurse|ri -force -whatif;'
For what it's worth, the CodeGeneration class is aware of this stuff ;)
Invoke-Expression "echo '$([System.Management.Automation.Language.CodeGeneration]::EscapeSingleQuotedStringContent($userMsg))'"
* PowerShell Console doesn't have good support for Unicode, even though the language does. Use ISE to better see the characters.
As Word does not have a mechanism for searching based on a regular expression, I was trying to write a simple macro that would, in this case, search in my currently active document for a period (.) WITHOUT a space following it. Here is my first pass on this:
Sub TestREG()
'
' TestREG Macro
'
'
Set objRegExp1 = CreateObject("vbscript.regexp")
objRegExp1.Global = True
objRegExp1.IgnoreCase = True
objRegExp1.Pattern = "\.[A-Z]"
MyDOC = ActiveDocument
objRegExp1.Execute (MyDOC)
End Sub
I know that I'm missing a lot here, but was trying to remember how to do this in an open Word doc. Every test I try, as I step through this is returning False.
Could anyone suggest how I might do this?
Looks like Word can do regular expressions since 2007:
Find and replace text by using regular expressions (Advanced)
Does anybody know if it is possible to intend a here-string. Actually I've to write:
$someString = #"
First line
second line
"#
This becomes very ugly if you define a here-string on a deeper indentation level, because the ending "# must be the first character on the line. Additionally somebody might "fix" the missing indentation and break the script ...
Is it possible to define a here-string like:
$someString = #"
First line
second line
"#
Thx
The closing "# must be at the start of the line.
I agree with you that this can make the script file harder to read, but it is the rule, and there is no way around it as far as I know.
You can find a uservoice entry here, and you should vote for it if you feel this is important to you. It does not look like a priority at the moment, with only 3 votes, but the more votes, the higher the priority for the powershell team to look into it.
Late answer (technically "workaround"), I know, but this is currently one of the first search results for "PowerShell here-string indentation".
This becomes very ugly if you define a here-string on a deeper indentation level
I agree. For those of us concerned with the aesthetics of the resulting code, I found the following workaround on this TechNet question.
It's definitely not a here-string (especially since you must still escape embedded quotes), but at least for many multi-line use-cases, it will serve the same purpose, and allow you to keep indenting at the same level as the rest of the code-block:
$somestring = (
"First line",
"Second line"
) -join "`r`n"
To expand upon #NotTheDr01ds's answer, you can make it even more aesthetically pleasing by excluding commas after each item. So long as each item in the array is on its own line:
$HTML = #(
"<h1>OIDC Services are <font style='color:green'>Online</font></h1>"
"<br/><p>Your identity: <ul><li>Username: $($Context.User.Identity.Name)</li></ul></p>"
"<br/><p>Troubleshooting: <ul><li><a href='/restart-service'>Restart Service</a></li></ul></p>"
) -Join "`n"