Can anyone recommend a short and efficient way of validating the contents of the variable $name, so that it will conform with the following:
Only English alphanumeric characters
Dots "." are allowed
Dashes "-" are allowed
Length should not exceed 10 characters
I can think of long, cumbersome ways of doing that, but I would much rather use an elegant implementation. Something like preg_match in php.
I'll be running it with PowerShell on Windows 2012 Server.
Thank you!
try this:
$string="tEst-.gg"
If ($string -match '^[a-z0-9.-]{1,10}$')
{
"OK"
}
If you want autorise empty string, replace {1,10} by {0,10}
Related
I recently discovered that you can get powershell's functions by reference using the modifier $function:. But I noticed a strange problem...
By convention, POSH uses a {Verb}-{Noun} convention for function names, where {Verb} is part of aproved POSH verb names. For instance: Get-Member or Invoke-WebRequest.
The thing is, that calling $function:Get-Member, for example, is not valid because of the hyphen; it works just fine if you declare a function like ShowMessage and calls: $fn = $function:ShowMessage. So I'd like to know if there's a way to escape this call.
PS.: I do know of another option, but is much much more verbose:
function Show-Message { Write-Host "Foo"; }
$fn = (Get-Item "function:Show-Message").ScriptBlock;
$fn.Invoke();
Update: Although #PetSerAl was very helpfull and explained the problem, I'll mark #Ansgar Wiechers's response as the answer because it's better documented.
function: is a PSDrive, not a (scope)modifier. As for using it with variable-like notation ($function:name): the rules for variable names with special characters apply here as well.
From the documentation:
VARIABLE NAMES THAT INCLUDE SPECIAL CHARACTERS
Variable names begin with a dollar sign. They can include alphanumeric characters and special characters. The length of the variable name is limited only by available memory.
Whenever possible, variable names should include only alphanumeric characters and the underscore character (_).Variable names that include spaces and other special characters, are difficult to use and should be avoided.
To create or display a variable name that includes spaces or special characters, enclose the variable name in braces. This directs PowerShell to interpret the characters in the variable name literally.
Your notation should thus look like this:
${function:Show-Message}
It can be invoked like this:
& ${function:Show-Message}
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.
I have a restriction of not being able to encode my Powershell script file in any of the following formats
Unicode
Unicode big endian
UTF-8
I need to create some files with some non-english characters in their names.
I have found a way to achieve this.
$op = [char]24555,[char]36895,[char]30340,[char]26837,[char]33394,[char]29392,[char]29432,[char]36339,[char]36807,[char]20102,[char]25042,[char]29399
"Write some necessary information to file" | Out-File "$op"
The output here is a file named "快 速 的 棕 色 狐 狸 跳 过 了 懒 狗" with "Write some necessary information to file" as its content
There are two problems with this approach
I find my script rather awkward looking since the script can look ungainly as the value of $op gets larger. Is there any simpler way of just storing the ASCII values and then converting them to characters on the fly. I would like to avoid having to cast all those numbers to [char] individually in the array.
The name should be 快速的棕色狐狸跳过了懒狗 without the empty spaces in between.
Any easy way to achieve this ?
For the first one, you can cast the entire list to a [char[]]:
$op = [char[]]#(24555,36895,30340,26837,33394,29392,29432,36339,36807,20102,25042,29399)
To avoid the white space between characters, either change the output field separator prior to creating the string:
$OFS = ''
"$op"
or use the -join operator:
$op -join ''
Problem
I am working on a script that has a user provide a specific IP address and I want to mask this IP in some fashion so that it isn't stored in the logs. My problem is, that I can easily do this when I know what the first three values of the IP typically are; however, I want to avoid storing/hard coding those values into the code to if at all possible. I also want to be able to replace the values even if the first three are unknown to me.
Examples:
10.11.12.50 would display as XX.XX.XX.50
10.12.11.23 would also display as XX.XX.XX.23
I have looked up partial string replacements, but none of the questions or problems that I found came close to doing this. I have tried doing things like:
# This ended up replacing all of the numbers
$tempString = $str -replace '[0-9]', 'X'
I know that I am partway there, but I aiming to only replace only the first 3 sets of digits so, basically every digit that is before a '.', but I haven't been able to achieve this.
Question
Is what I'm trying to do possible to achieve with PowerShell? Is there a best practice way of achieving this?
Here's an example of how you can accomplish this:
Get-Content 'File.txt' |
ForEach-Object { $_ = $_ -replace '\d{1,3}\.\d{1,3}\.\d{1,3}','xx.xx.xx' }
This example matches a digit 1-3 times, a literal period, and continues that pattern so it'll capture anything from 0-999.0-999.0-999 and replace with xx.xx.xx
TheIncorrigible1's helpful answer is an exact way of solving the problem (replacement only happens if 3 consecutive .-separated groups of 1-3 digits are matched.)
A looser, but shorter solution that replaces everything but the last .-prefixed digit group:
PS> '10.11.12.50' -replace '.+(?=\.\d+$)', 'XX.XX.XX'
XX.XX.XX.50
(?=\.\d+$) is a (positive) lookahead assertion ((?=...)) that matches the enclosed subexpression (a literal . followed by 1 or more digits (\d) at the end of the string ($)), but doesn't capture it as part of the overall match.
The net effect is that only what .+ captured - everything before the lookahead assertion's match - is replaced with 'XX.XX.XX'.
Applied to the above example input string, 10.11.12.50:
(?=\.\d+$) matches the .-prefixed digit group at the end, .50.
.+ matches everything before .50, which is 10.11.12.
Since the (?=...) part isn't captured, it is therefore not included in what is replaced, so it is only substring 10.11.12 that is replaced, namely with XX.XX.XX, yielding XX.XX.XX.50 as a result.
I'm trying to write a script that that will remove everything except text contained in quotation marks from a result-set generated by a SQL query. Not sure whether trim or -replace will do this.
Here is a sampling of the result-set:
a:5:{s:3:"Client Service";a:4:{s:15:"Client Training";b:0;s:11:"Payer
Error";
I would like it to end up looking like this:
Client Service
Client Training
Payer Error
I've tried everything I know to do in my limited PowerShell and RegEx familiarity and still haven't been able to figure out a good solution.
Any help would be greatly appreciated.
$s = 'a:5:{s:3:"Client Service";a:4:{s:15:"Client Training";b:0;s:11:"Payer Error";'
Replace the start of string up to the first quote, or the last quote up to the end of string. Then what you're left with is:
Client Service";a:4:{s:15:"Client Training";b:0;s:11:"Payer Error
Now the bits you don't want are "in quotation marks" and that's easy to match with ".*?" so replace that with a space.
Overall, two replaces:
$s -replace '^[^"]*"|"[^"]*$' -replace '".*?"', ' '
Client Service Client Training Payer Error
Here's a version that uses Regex to capture the strings including their quotes in to an array and then removes the quote marks with -replace:
$text = 'a:5:{s:3:"Client Service";a:4:{s:15:"Client Training";b:0;s:11:"Payer Error";'
([regex]::matches($Text, '(")(.*?)(")')).value -replace '"'
There's without a doubt a regex to get the strings without their quotes in the first place but i'm a bit of a regex novice.