How to validate azure resource naming conventions using PowerShell - azure

I want to check the name (for example azure vnet) provided in script to validate for azure vnet naming convention (Like it should not have any special character and length 2-64)
I am using below code but it is not working if string $name has special character in it.
It is working only for 0-9 and a-z.
$name = "zzz"
$name -cmatch "^[0-9a-z]*$"
Need a code to check a string which has for special character.
If it has special character it should return true.

Try :
$name = "hello#"
if($name -match '[^a-zA-Z0-9]')
{
Write-Host "special character found"
}
else
{
Write-Host "special character not found"
}

Try this one, if there is a special character in name, it will return true.
$name = "_"
$name -notmatch "[0-9a-zA-Z]"

Related

Regex, PowerShell, How can I get this to show up in PowerShell?

In using the following PowerShell Script with Regex.
THE PROBLEM: I don't get any data returned for the Filename.
CURRENT RESULTS IN POWERSHELL:
EXPECTED RESULTS IN POWERSHELL:
This Regex Demo is doing what I would think it should be doing in Regex. (Originating from this question.)
POWERSHELL SCRIPT:
$InStuff = #('111111_SMITH, JIM_END TLD 6-01-20 THR LEWISHS.pdf','222222_JONES, MIKE_G URS TO 7.25 2-28-19 SA COOPSHS.pdf')
switch -Regex ($instuff) {
'^(^.{0,6})*|(?!.*_).*(?=\.)'{
[pscustomobject]#{
EmployeeID = $matches.1
FileName = $matches.2
}
}
}
QUESTION:
What do I need to change to get the filename to show up in the PowerShell results?
Seems like a simple .Split() can achieve what you're looking for. The method will split the string into 3 tokens which then get assigned to $a for the EmployeeID, $null for the User (we use $null here to simply ignore this token since you have already stated it was not of interest) and $b for the FileName. In PowerShell, this is known as multiple assignment.
To remove the extension from the $b token, as requested in your comment, regex is also not needed, you can use Path.GetFileNameWithoutExtension Method from System.IO.
$InStuff = #(
'111111_SMITH, JIM_END TLD 6-01-20 THR LEWISHS.pdf'
'222222_JONES, MIKE_G URS TO 7.25 2-28-19 SA COOPSHS.pdf'
)
foreach($i in $InStuff) {
$a, $null, $b = $i.Split('_')
[pscustomobject]#{
EmployeeID = $a
FileName = [System.IO.Path]::GetFileNameWithoutExtension($b)
}
}
Which results in:
EmployeeID FileName
---------- --------
111111 END TLD 6-01-20 THR LEWISHS
222222 G URS TO 7.25 2-28-19 SA COOPSHS

Why is this condition being met when verifying parameters using the -notMatch condition?

I am validating parameters passed into a release pipeline with Powershell. The parameter I am passing as a pipeline variable is val1. Here is my code below:
if ("$(Value)" -notMatch "val1" -or "$(Value)" -notMatch "val2"){
Write-Host "$(Value) must be val1 || val2"
Write-Host "Value of param: "$(Value)""
exit 1
}
When I print my value is states val1. Why is this condition being met? I thought perhaps it was because its case sensitive however even when I modify the condition to catch the exact case, it's still being met.
If your variable should have only val1 or val2, you have to use -and instead -or.
if ("$(Value)" -notMatch "val1" -and "$(Value)" -notMatch "val2"){
Write-Host "$(Value) must be val1 || val2"
Write-Host "Value of param: "$(Value)""
exit 1
}
Change it to
if ("$(Value)" -notMatch "val1" -and "$(Value)" -notMatch "val2"){
Write-Host "$(Value) must be val1 || val2"
Write-Host "Value of param: "$(Value)""
exit 1
}
Note: $(Value) in the question as well as in the code below is an Azure pipeline macro, not a PowerShell variable reference such as $Value. Since such a macro is expanded to its value before PowerShell sees it, enclosing it in "..." - again, as in the question and in the code below - ensures that no syntax error occurs if the value happens to contain spaces or other PowerShell metacharacters.
The Shamrai Aleksander's helpful answer explains the logic error, but there may be an additional problem:
-match (and its -notmatch variant), the regular-expression matching operator, matches substrings by default, so that "$(Value)" expanding to aval1, for instance, would mistakenly pass the test as well.
for literal, whole-value comparisons against a collection, you can use the -in operator (note that -contains serves the same purpose only with the operands reversed) and its variants, notably -notin in this case; use -cnotin for case-sensitive comparisons.
# Note: `$(Value)` is an *Azure pipeline macro (variable)*, which is expanded
# *before* PowerShell sees the code.
# In pure PowerShell code, the equivalent would be just `$Value`
if ("$(Value)" -notin 'val1', 'val2') {
Write-Error '$(Value) must be val1 || val2'
exit 1
}
I thought perhaps it was because its case-sensitive however
Note that all PowerShell operators are case-insensitive by default (when they operate on text); PowerShell is case-insensitive by default in most respects.
Case-sensitive operation requires use of the c prefixed variants, such as -cmatch.
Optionally, to signal the intent more clearly, you can signal case-insensitive operation by using the i-prefixed variants, such as -imatch (all i-prefixed variants behave like their non-prefixed base forms).

In PowerShell how do I load multiple values into a variable?

I have a requirement at work to check several registry key values and I want to automate this process using PowerShell. One of the registry keys that I check has 3 values and I am not able to successfully check it using my PowerShell script.
I do not believe I am correctly loading the $value variable so that it can be compared to the value of $path.
$path = (Get-ItemProperty HKLM:\System\CurrentControlSet\Services\LanManServer).NullSessionPipe
$value = “netlogon samr lsarpc”
if ($path -ne $value) {
Write-Host “Value is incorrect or missing.”
} else {
Write–Host “Config is correct.”
}
I expect the output to be
Config is correct.
Instead I get
Value is incorrect or missing.
Using Regedit I can see that the key has the correct values.
NullSessionPipe apparently is a REG_MULTI_SZ, meaning that the data is returned as an array of strings. You could do "$path" -ne $value to mangle the array into a flat string, but that would imply that the order of the substrings is identical in both strings. A better approach is to compare arrays via Compare-Object.
$path = (Get-ItemProperty HKLM:\...).NullSessionPipe
$value = 'netlogon', 'samr', 'lsarpc'
if (Compare-Object $path $value) {
'arrays differ'
} else {
'arrays are equal'
}
#Ansgar, After some experimenting I was able to get the script to work. I deleted the blank spaces and added a carriage return after netlogon and samr. It works perfectly!!!
$path = (Get-ItemProperty HKLM:\System\CurrentControlSet\Services\LanManServer).NullSessionPipe
$value = 'netlogon',
' samr',
' lsarpc'
if (Compare-Object $path $value) {
'arrays differ'
} else {
'arrays are equal'
}

How to compare strings that have an ampersand in them in PowerShell

I am using PowerShell to compare two strings that have an ampersand (&) in them (i.e. the string "Policies & Procedures").
No matter what I try, I cannot get these strings to match. I have tried trimmed the strings to get rid of an extra white spaces. I have tried wrapping the the string in both single and double quotes (and a combination of both):
"Policies & Procedures"
'Policies & Procedures'
"'Policies & Procedures'"
The code I am using to compare the strings is:
if ($term1 -eq $term2) {
do something
}
Inspecting the strings visually - they are identical, however the if statement never evaluates to true. Is there a way to compare these two strings so that it does evaluate to true?
EDIT
The context in which I am doing this string compare is looking for a term name in a taxonomy for a SharePoint site. Here is the code I am using:
function getTerm($termName) {
foreach($term in $global:termset.Terms) {
$termTrimmed = $term.Name.trim()
Write-Host "term name = $termTrimmed" -foregroundcolor cyan
if ($termTrimmed -eq $termName) {
return $term
}
}
return null
}
I have printed both term.Name and termName to the screen and they are identical. If there is no ampersand in the string, this function works. If there is an ampersand this function fails. This is how I know the ampersand is the problem.
This is a known quirk:
There are two types of ampersands that you need to be aware of when
playing with SharePoint Taxonomy
Our favorite and most loved
& ASCII Number: 38
And the impostor
& ASCII Number: 65286
After reading this article by Nick Hobbs, it became apparent
that when you create a term it replaces the 38 ampersand with a
65286 ampersand.
This then becomes a problem if you want to do a comparison with your
original source (spreadsheet, database, etc) as they are no longer the
same.
As detailed in Nick’s article, you can use the
TaxonomyItem.NormalizeName method to create a "Taxonomy" version of
your string for comparison:
Try this (not tested on real SharePoint):
function getTerm($termName)
{
foreach($term in $global:termset.Terms) {
$termNormalized = [Microsoft.SharePoint.Taxonomy.TaxonomyItem]::NormalizeName($term.Name)
if ($termNormalized -eq $termName) {
return $term
}
}
return null
}
After converting both strings to char arrays and comparing the unicode value of the ampersands the problem is revealed. The ampersand used in the search string has a value of 38 while the ampersand returned from the SharePoint term store has a value of 65286 (called a full ampersand although looks identical to a regular ampersand on screen).
The solution was to write my own string comparison function and take into account the differences in the ampersand values. Here is the code:
function getTerm($termName) {
$searchChars = $termName.toCharArray()
$size = $searchChars.Count;
foreach($term in $global:termset.Terms) {
$match = $True
$chars = $term.Name.trim().toCharArray()
if ($size -eq $chars.Count) {
for ($i = 0; $i -lt $size; $i++) {
if ($searchChars[$i] -ne $chars[$i]) {
# handle the difference between a normal ampersand and a full width ampersand
$charCode1 = [int] $searchChars[$i]
$charCode2 = [int] $chars[$i]
if ((($charCode1 -eq 38) -or ($charCode1 -eq 65286 )) -and (($charCode2 -eq 38) -or ($charCode2 -eq 65286 ))) {
continue
} else {
$match = $False
break
}
}
}
} else {
$match = $False
}
if ($match -eq $True) {
return $term
}
}
return $null
}

How do I delay expansion of variables in PowerShell strings?

Whatever you want to call it, I'm trying to figure out a way to take the contents of an existing string and evaluate them as a double-quoted string. For example, if I create the following strings:
$string = 'The $animal says "meow"'
$animal = 'cat'
Then, Write-Host $string would produce The $animal says "meow". How can I have $string re-evaluated, to output (or assign to a new variable) The cat says "meow"?
How annoying...the limitations on comments makes it very difficult (if it's even possible) to include code with backticks. Here's an unmangled version of the last two comments I made in response to zdan below:
----------
Actually, after thinking about it, I realized that it's not reasonable to expect The $animal says "meow" to be interpolated without escaping the double quotes, because if it were a double-quoted string to begin with, the evaluation would break if the double quotes weren't escaped. So I suppose the answer would be that it's a two step process:
$newstring = $string -replace '"', '`"'
iex "`"$string`""
One final comment for posterity: I experimented with ways of getting that all on one line, and almost anything that you'd think works breaks once you feed it to iex, but this one works:
iex ('"' + ($string -replace '"', '`"') + '"')
Probably the simplest way is
$ExecutionContext.InvokeCommand.ExpandString($var)
You could use Invoke-Expression to have your string reparsed - something like this:
$string = 'The $animal says `"meow`"'
$animal = 'cat'
Invoke-Expression "Write-Host `"$string`""
Note how you have to escape the double quotes (using a backtick) inside your string to avoid confusing the parser. This includes any double quotes in the original string.
Also note that the first command should be a command, if you need to use the resulting string, just pipe the output using write-output and assign that to a variable you can use later:
$result = Invoke-Expression "write-output `"$string`""
As noted in your comments, if you can't modify the creation of the string to escape the double quotes, you will have to do this yourself. You can also wrap this in a function to make it look a little clearer:
function Invoke-String($str) {
$escapedString = $str -replace '"', '`"'
Invoke-Expression "Write-Output `"$escapedString`""
}
So now it would look like this:
# ~> $string = 'The $animal says "meow"'
# ~> $animal = 'cat'
# ~> Invoke-String $string
The cat says "meow"
You can use the -f operator. This is the same as calling [String]::Format as far as I can determine.
PS C:\> $string = 'The {0} says "meow"'
PS C:\> $animal = 'cat'
PS C:\> Write-Host ($string -f $animal)
The cat says "meow"
This avoids the pitfalls associated with quote stripping (faced by ExpandString and Invoke-Expression) and arbitrary code execution (faced by Invoke-Expression).
I've tested that it is supported in version 2 and up; I am not completely certain it's present in PowerShell 1.
Edit: It turns out that string interpolation behavior is different depending on the version of PowerShell. I wrote a better version of the xs (Expand-String) cmdlet with unit tests to deal with that behavior over here on GitHub.
This solution is inspired by this answer about shortening calls to object methods while retaining context. You can put the following function in a utility module somewhere, and it still works when you call it from another module:
function xs
{
[CmdletBinding()]
param
(
# The string containing variables that will be expanded.
[parameter(ValueFromPipeline=$true,
Position=0,
Mandatory=$true)]
[string]
$String
)
process
{
$escapedString = $String -replace '"','`"'
$code = "`$ExecutionContext.InvokeCommand.ExpandString(`"$escapedString`")"
[scriptblock]::create($code)
}
}
Then when you need to do delayed variable expansion, you use it like this:
$MyString = 'The $animal says $sound.'
...
$animal = 'fox'
...
$sound = 'simper'
&($MyString | xs)
&(xs $MyString)
PS> The fox says simper.
PS> The fox says simper.
$animal and $sound aren't expanded until the last two lines. This allows you to set up a $MyString up front and delay expansion until the variables have the values you want.
Invoke-Expression "`"$string`""

Resources