New to Powershell, never needed it before I started this job. I'm just making an easier way for me to keep our stores pinging and kill some time learning. Some pretext; Our stores are always 4 numbers, so 1096 is 1096 but 704 is 0704.
Here is my current script:
$args.Length;
foreach ($arg in $args) {
Test-Connection $arg'router' }
Write-Host 'Pinging Store #'$arg
if($arg.legnth -lt 4) {
($arg).insert(0,'0')
}
If I execute with the argument 1096 all is well in the world, but if I use 0704 the leading 0 disappears. I've tried a number of potential resolutions, but I've found most are trying to remove trailing zeroes so I've just been trying to reverse engineer their solutions. What is the best way to ensure that the leading 0 isn't removed so the host is able to be found.
0704router exists.
704router doesn't exist.
This looks like an issue of how you call the script. You may be doing something like this:
./MyScript.ps1 1096 0704
Which will give you 2 arguments, but since they are unquoted and contain only digits, they are interpreted as integers, and so you lose leading zeros.
Instead, tell PowerShell you want these as string values by quoting them:
./MyScript.ps1 '1096' '0704'
The [string]$Args[1] worked for me and
it seems like the behavior is changing from version to version - same script worked without conversion with PS 2.0
Hope this helps!
Related
I recently learned that you can use special characters in PowerShell variables, e.g.: ${hello world!}, but then I stumbled across this:
${^}
What does it do? I first thought it referenced the newest created variable, but it does other stuff I haven't really figured out.
The documentation says:
Contains the first token in the last line received by the session.
Examples:
dir c:\windows 🡒 dir
0..9 🡒 0
&{ dir } 🡒 &
It was likely introduced to get the last command used (dir, copy, rm, ...), but in reality that will only work for the most simplest cases, and thus it's not very useful.
The corresponding $$ returns the last token from the last line.
Note: The curly braces {} are only necessary for variable names containing characters which are not allowed in variables, except automatic variables (look here). In this case, you can omit them:
$^
It shows the first word/token in the last executed command.
I'm trying to use [regex]::Replace with a match evaluator to selectively replace parts of a string. I'm writing and debugging the function in PowerShell ISE. What is strange is that running the replacement code causes one machine to output a string that is the content of the match evaluator script block while the other replaces the text correctly. I had no clue this was even possible nor why it is happening.
Given this code (borrowed from another stackoverflow answer):
$global_counter = 0
$callback = {
$global_counter += 1
"string-$($args[0])-" + $global_counter
}
$re = [regex]"match"
$re.Replace('zzz match match xxx', $callback)
Executing it on one machine causes the output (PowerShell Version 5.1.18362.145):
zzz string-match-1 string-match-1 xxx
But on another it outputs (PowerShell Version 5.1.17134.858):
zzz
$global_counter += 1
"string-$($args[0])-" + $global_counter
$global_counter += 1
"string-$($args[0])-" + $global_counter
xxx
Both are running in an x64 PowerShell ISE clean instance directly from reboot. Does anyone know why this is happening?
With debugging help from Jeroen I've managed to figure out why this is happening.
PowerShell has a security feature called Constrained Language Mode that prevents the use of any, but a core set of whitelisted types. What appears to be happening is that I'm defining a scriptblock that in turn is converted to a System.Text.RegularExpressions.MatchEvaluator before being passed to the Replace function. The match evaluator however is outside of this core set of types which means when the PowerShell engine tries to coerce the type onto an overload of Replace the only other valid one is Replace(string, string, string) (thanks Jeroen for pointing this out in the comments). The Replace function does its job, but with a regular string as a replacement thus resulting in the odd behaviour.
I'm not able to alter the language mode of my PowerShell session on the machine I'm currently working with as it is applied through Group Policies, but a workaround for me at least was to use an elevated PowerShell session and ISE to test my script.
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.
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}
This is a very simple task in every language I have ever used, but I can't seem to figure it out in PowerShell. An example of what I'm talking about in C:
abs(x + y)
The expression x + y is evaluated, and the result passed to abs as the parameter... how do I do that in PowerShell? The only way I have figured out so far is to create a temporary variable to store the result of the expression, and pass that.
PowerShell seems to have very strange grammar and parsing rules that are constantly catching me by surprise, just like this situation. Does anyone know of documentation or a tutorial that explains the basic underlying theory of the language? I can't believe these are all special cases, there must be some rhyme or reason that no tutorial I have yet read explains. And yes, I've read this question, and all of those tutorials are awful. I've pretty much been relegated to learning from existing code.
In your case, simply surrounding the expression with parenthesis will allow you to pass it to your function.
You need to do this because PowerShell has more than one parsing mode depending on the beginning of the command.
Expression mode is similar to how most other languages parse - numbers are numbers and strings are quoted.
Command mode treats everything as a string except for variables and parenthesis. Strings here don't need to be quoted.
1+2 Expression mode - starts with number
"string" Expression mode - starts with quote
string Command mode - starts with letter
& "string" Command mode - starts with &
. "string" Command mode - starts with . and a space
.123 Expression mode - starts with . and number (without space)
.string Command mode - starts with a . that is part of a command name
You can mix modes in a single line by enclosing the commands with parenthesis.
You can see this effect if you define function abs in the following way:
function Abs($value)
{
Write-Host $args
if($value -lt 0) { -$value } else { $value }
}
Abs 1 + 2
#Prints: + 2
#Returns: 1
Abs 1+2
#Prints:
#Returns: 1+2
Abs (1 + 2)
#Prints:
#Returns: 3
Abs (1+2)
#Prints:
#Returns: 3
Not sure I follow exactly the problem you are encountering. The following shows that this works as expected in PowerShell:
PS> function abs($val) {Write-Host "`$val is $val"; if ($val -ge 0) {$val} `
else {-$val}}
PS> abs (3+4)
$val is 7
7
As for the best docs on the language, I highly recommend Windows PowerShell in Action by Bruce Payette (he's the guy behind the grammar). If you can wait a few more months (or are OK with an eletronic copy), there is a second edition due out this summer that has been updated for PowerShell 2.0.
You may also find my Effective PowerShell series helpful. Checkout item #10 on PowerShell Parsing Modes.