PowerShell Input Validation - Input should NOT be ALL numbers - validation

I have the following code that works well for validating length...
DO {
$NewID = Read-Host -Prompt " NEW ID NAME of object (8-15 chars) "
} UNTIL ($NewID.Length -gt 7 -and $WS_NewName.Length -lt 16)
How can I include code that ensures input contains either an ALPHA or ALPHANUMERIC string, but NOT a purely NUMERIC one?

This can be easily doable using regular expressions like that:
($NewID -match '^[A-z0-9]*$') -and ($NewID -notmatch '^[0-9]*$')
Short explanation: first expression looks for alpha/alphanumeric string and the second discards purely numeric entries.
By the way, in your example you use $NewID and then $WS_NewName in Until expression, that might be confusing (however, I assume you just forgot to change it while pasting here)

Related

Insert string into multiple filenames

I have multiple files named in this format:
Fat1920OVXPlacebo_S20_R1_001.fastq
Kidney1235SHAM_S65_R1_001.fastq
Kidney1911OVXPlacebo_S94_R2_001.fastq
Liver1289OVXEstrogen_S24_R2_001.fastq
I need to insert the string "L1000_" into their names so that they read
Fat1920OVXPlacebo_S20_L1000_R1_001.fastq
Kidney1235SHAM_S65_L1000_R1_001.fastq
Kidney1911OVXPlacebo_S94_L1000_R2_001.fastq
Liver1289OVXEstrogen_S24_L1000_R2_001.fastq
I apologize but I have absolutely no experience in coding in powershell. The closest thing I could find to do this was a script that renames the entire file:
Set objFso = CreateObject(“Scripting.FileSystemObject”)
Set Folder = objFSO.GetFolder(“ENTER\PATH\HERE”)
For Each File In Folder.Files
sNewFile = File.Name
sNewFile = Replace(sNewFile,”ORIGINAL”,”REPLACEMENT”)
if (sNewFile<>File.Name) then
File.Move(File.ParentFolder+”\”+sNewFile)
end if
Next
however, I just need to insert a string at a specific place in the file's title. I have 257 files and do not want to go 1 by 1. Does anyone have an idea on how to run this in windows?
Use Get-ChildItem to enumerate the files of interest, pipe them to Rename-Item, and use a delay-bind script block ({ ... }) to dynamically determine the new name, via a regex-based -replace operation.
(Get-ChildItem $yourFolder -Filter *.fastq) |
Rename-Item -NewName { $_.Name -replace '(?<=_S\d+_)', 'L1000_' } -WhatIf
Note:
• The -WhatIf common parameter in the command above previews the operation. Remove -WhatIf once you're sure the operation will do what you want.
• Even though not strictly necessary in this case, enclosing the Get-ChildItem command in (...), the grouping operator ensures that already renamed files don't accidentally re-enter the enumeration of files to be renamed - see this answer.
(?<=_S\d+_) uses a positive look-behind assertion ((?<=...)) to match verbatim string _S, followed by one or more (+) digits (\d), followed by verbatim _.
Since the look-behind assertion merely matches a position in the string rather than a substring, the replacement operand, verbatim L1000_ in this case, is inserted at that position in (a copy of) the input string.
For a more detailed explanation of the delay-bind script-block technique, see this answer.
here's one way to do that with PoSh. note that the demo does not handle either the rename or directory related stuff. it ONLY handles generating the new file names.
what it does ...
fakes reading in a list of fileinfo objects
when ready to do this for real, replace the entire #region/#endregion block with a call to Get-ChildItem and save it to $FileList.
sets the text to be inserted
iterates thru the file list
splits the file .Name property on the underscores
saves that to a $Var
adds the 1st two splits, the insertion text, and the last two splits to a new array
joins that array with an underscore as the delimiter
sends the new file name to the $Result collection
displays the list of new names
the code ...
#region - fake reading in a list of files
# in real life, use Get-ChildItem
$FileList = #(
[system.io.fileinfo]'Fat1920OVXPlacebo_S20_R1_001.fastq'
[system.io.fileinfo]'Kidney1235SHAM_S65_R1_001.fastq'
[system.io.fileinfo]'Kidney1911OVXPlacebo_S94_R2_001.fastq'
[system.io.fileinfo]'Liver1289OVXEstrogen_S24_R2_001.fastq'
)
#endregion - fake reading in a list of files
$InsertionText = 'L1000'
$Result = foreach ($FL_Item in $FileList)
{
$FLI_Parts = $FL_Item.Name.Split('_')
($FLI_Parts[0,1] + $InsertionText + $FLI_Parts[2,3]) -join '_'
}
$Result
output ...
Fat1920OVXPlacebo_S20_L1000_R1_001.fastq
Kidney1235SHAM_S65_L1000_R1_001.fastq
Kidney1911OVXPlacebo_S94_L1000_R2_001.fastq
Liver1289OVXEstrogen_S24_L1000_R2_001.fastq
Using PowerShell, you could use a regular expression to rename the files. Example:
Get-ChildItem "C:\foldername\here\*.fastq" | ForEach-Object {
$oldName = $_.Name
$newName = [Regex]::Replace($oldName,'(S\d+)_(R\d+)','$1_L1000_$2')
Rename-Item $_ $newName -WhatIf
}
[Regex] is a PowerShell type accelerator for the .NET Regex class, and Replace is the method for the Regex class that performs text substitutions. The first parameter to the Replace method is the input string (the old filename), the second parameter is the regular expression pattern (run help about_Regular_Rxpressions for more information), and the third parameter is the replacement string pattern, where $1 is the first capture pattern in ( ), and $2 is the second capture pattern in ( )). Finally, the Rename-Item cmdlet renames the files. Remove the -WhatIf parameter if the output looks correct to actually perform the renames.

Find array elements which values are not part of another array PowerShell

I have two arrays
$adg - (A list of AD groups)
$dbs - (A list of database names)
Lets say I use this command
$adg -match $dbs.i
The output will be all the AD groups which have the string $dbs in its name.
However, I am aiming to find the DBs in which are not part of the AD groups array.
Eg:
$adg = #("Dev22_Owner","Test49_Owner","Rocket_Owner")
$dbs = #("Dev22", "Confidential", "InternDB", "Rocket", "Test49")
What approach should I take to get the output:
Confidential
InternDB
I tried $dbs | Where $adg -notmatch $dbs.i but there is no output.
I would first remove the unecessary user part from the ad group:
$groups = $adg | ForEach-Object {
$_ -replace '_.*?$'
}
Then you can use the Where-Object cmdlet with the -notin operator to filter them:
$dbs | Where-Object { $_ -notin $groups }
Output:
Confidential
InternDB
To offer a more concise PSv3+ alternative to Martin Brandl's helpful answer:
PS> (Compare-Object ($adg -replace '_Owner$') $dbs).InputObject
Confidential
InternDB
($adg -replace '_Owner$') returns a new array with copies of the input string that have _Owner suffix stripped from them.
Compare-Object compares the stripped array with the other array and returns objects that represent the differences between the two arrays.
Accessing the .InputObject on the difference objects returns the values that differ.
Note: If $dbs contained items that aren't in the stripped $adg array, the above would return a union of all differing items, irrespective of which side they're unique to; to distinguish the sides / limit to a side, you'd have to use the .SideIndicator property (value => indicates values exclusive to the right side, <= those exclusive to the left side).
As for what you tried:
$adg -match $dbs.i doesn't work as intended and is effectively the same as $adg -match '', which invariably returns all $adg items.
The reason is that array $dbs has no .i property, so the expression evaluates to $null, which on the RHS of match is coerced to a string and therefore is converted to the empty string.
Generally, the RHS of -match does not support arrays - only a single regular expression.
If you do supply an array, it is implicitly converted to a string by joining the elements to form a space-separated list; e.g. array 1, 2 is coerced to '1 2' and '1 2' -match (1, 2) therefore evaluates to $True.

powershell special character user input validation

I am wanting to validate a user's input of special characters and if the characters are not correct, I want it to loop back to the read-host statement. I am unsure what loop type I should use and how to do this. Any and all help would be greatly appreciated.
For example
$Example = Read-Host “Input one of the following symbols
Addition (+)
Subtraction (-)
Multiplication (*)
Division (/)"
Something like this should suit your needs.
do {
$Symbol = Read-Host 'Symbol'
if ($Symbol -match '^(\+|-|\*|/)$'){
$Valid = $true
} else {
Write-Host "'$($Symbol)' is not a valid input, please choose one of +,-,* or /"
$Valid = $false
}
} while (!$Valid)

Validating user entry matches mixed case requirements

I am trying to figure out how to test for mixed case or change the user input to mixed case.
Currently my code consists of:
$Type = Read-Host 'Enter MY, OLD, NEWTest, Old_Tests'
However, I need to validate that the user entered in the exact case, and if they didn't change the case to the correct case. I have reviewed so many different questions on here and other websites, but none seem to really talk about validating mixed case in a way I can understand.
Validate User Entry
Regex to match mixed case words
Validating String User Entry
How to check if a string is all upper case (lower case) characters?
Learn Powershell | Achieve More
How To Validate Parameters in PowerShell
$args in powershell
I am not asking anyone to write code for me. I am asking for some sample code that I can gain an understanding on how to validate and change the entries.
PowerShell performs case-insensitive comparisons by default, so to answer the first part of your question you need to do a case-sensitive comparison which is -ceq.
$Type = Read-Host 'Enter MY, OLD, NEWTest, Old_Tests'
($Type -ceq 'MY' -or $Type -ceq 'OLD' -or $Type -ceq 'NEWTest' -or $Type -ceq 'Old_Tests')
Although a simpler solution to that is to use case-sensitive contains -ccontains:
('MY', 'OLD', 'NEWTest', 'Old_Tests' -ccontains $Type)
Here's one way you might correct the case:
$Type = Read-Host 'Enter MY, OLD, NEWTest, Old_Tests'
If ('MY', 'OLD', 'NEWTest', 'Old_Tests' -cnotcontains $Type){
If ('MY', 'OLD', 'NEWTest', 'Old_Tests' -contains $Type){
$TextInfo = (Get-Culture).TextInfo
$Type = Switch ($Type) {
{$_ -in 'MY','OLD'} { $Type.ToUpper() }
'NEWTest' { $Type.Substring(0,4).ToUpper() + $Type.Substring(4,3).ToLower() }
'Old_Tests' { $TextInfo.ToTitleCase($Type) }
}
} Else {
Write-Warning 'You didnt enter one of: MY, OLD, NEWTest, Old_Tests'
}
}
Write-Output $Type
Explanation:
First we test if the case is correct for the four permitted words (-cnotcontains Case Sensitive Not Contains), if it is we do nothing. If the case is not correct, then we test the text is correct (without caring about case sensitivity -contains).
If the text is correct then we use Switch statement to deal with the different scenarios that we want to adapt the case for:
The first switch test matches the first two words and simply uppercases them with the ToUpper() string method.
The second switch test uses the string method SubString to get a subset of the string starting from the first character (0) and taking 4 characters in length. We uppercase this with ToUpper then we add on the next 3 characters of the string, starting at the 4th character, which we force in to lower case with ToLower().
The final switch test we handle with a .NET method taken from the get-culture cmdlet which allows us to Title Case a string (make the first letter of each word uppercase).
If the inputted text didn't match one of the options we use write-warning (may require PowerShell 4 or above, if you don't have this change it to write-host) to print a warning to the console.
Finally whatever was entered we send to stdout with Write-Output.

What does the "#" symbol do in PowerShell?

I've seen the # symbol used in PowerShell to initialise arrays.
What exactly does the # symbol denote and where can I read more about it?
In PowerShell V2, # is also the Splat operator.
PS> # First use it to create a hashtable of parameters:
PS> $params = #{path = "c:\temp"; Recurse= $true}
PS> # Then use it to SPLAT the parameters - which is to say to expand a hash table
PS> # into a set of command line parameters.
PS> dir #params
PS> # That was the equivalent of:
PS> dir -Path c:\temp -Recurse:$true
PowerShell will actually treat any comma-separated list as an array:
"server1","server2"
So the # is optional in those cases. However, for associative arrays, the # is required:
#{"Key"="Value";"Key2"="Value2"}
Officially, # is the "array operator." You can read more about it in the documentation that installed along with PowerShell, or in a book like "Windows PowerShell: TFM," which I co-authored.
While the above responses provide most of the answer it is useful--even this late to the question--to provide the full answer, to wit:
Array sub-expression (see about_arrays)
Forces the value to be an array, even if a singleton or a null, e.g. $a = #(ps | where name -like 'foo')
Hash initializer (see about_hash_tables)
Initializes a hash table with key-value pairs, e.g.
$HashArguments = #{ Path = "test.txt"; Destination = "test2.txt"; WhatIf = $true }
Splatting (see about_splatting)
Let's you invoke a cmdlet with parameters from an array or a hash-table rather than the more customary individually enumerated parameters, e.g. using the hash table just above, Copy-Item #HashArguments
Here strings (see about_quoting_rules)
Let's you create strings with easily embedded quotes, typically used for multi-line strings, e.g.:
$data = #"
line one
line two
something "quoted" here
"#
Because this type of question (what does 'x' notation mean in PowerShell?) is so common here on StackOverflow as well as in many reader comments, I put together a lexicon of PowerShell punctuation, just published on Simple-Talk.com. Read all about # as well as % and # and $_ and ? and more at The Complete Guide to PowerShell Punctuation. Attached to the article is this wallchart that gives you everything on a single sheet:
You can also wrap the output of a cmdlet (or pipeline) in #() to ensure that what you get back is an array rather than a single item.
For instance, dir usually returns a list, but depending on the options, it might return a single object. If you are planning on iterating through the results with a foreach-object, you need to make sure you get a list back. Here's a contrived example:
$results = #( dir c:\autoexec.bat)
One more thing... an empty array (like to initialize a variable) is denoted #().
The Splatting Operator
To create an array, we create a variable and assign the array. Arrays are noted by the "#" symbol. Let's take the discussion above and use an array to connect to multiple remote computers:
$strComputers = #("Server1", "Server2", "Server3")<enter>
They are used for arrays and hashes.
PowerShell Tutorial 7: Accumulate, Recall, and Modify Data
Array Literals In PowerShell
I hope this helps to understand it a bit better.
You can store "values" within a key and return that value to do something.
In this case I have just provided #{a="";b="";c="";} and if not in the options i.e "keys" (a, b or c) then don't return a value
$array = #{
a = "test1";
b = "test2";
c = "test3"
}
foreach($elem in $array.GetEnumerator()){
if ($elem.key -eq "a"){
$key = $elem.key
$value = $elem.value
}
elseif ($elem.key -eq "b"){
$key = $elem.key
$value = $elem.value
}
elseif ($elem.key -eq "c"){
$key = $elem.key
$value = $elem.value
}
else{
Write-Host "No other value"
}
Write-Host "Key: " $key "Value: " $value
}

Resources