PowerShell: How can I traverse through registry values named "SQLArg1", "SQLArg2" etc.? - powershell

I am working on a PowerShell function that is supposed to check if two values in the registry named "SQLArg4" and "SQLArg5" (or two other numbers) are set to a certain value content and set them if not.
The problem is I cannot enumerate the values to traverse through them to compare all of them and then add my two value contents if they are not present.
I tried creating a string out of "SQLArg" and a $i index but PowerShell would not allow me to use that string as a field of a variable.
Any ideas?

It sounds like you only need to work with one registry key (no recursion). Try this code. It will get all the values under $key that start with "SQLArgs" and store them in $values. It loops through a number sequence and tests for the existence of the key values named SQLArgs#. When it finds one it will set the key value data.
$key = "HKCU:\Andy"
$values = Get-ItemProperty -Path $key -Name SQLArg*
1..20 | % {
if ($values."SQLArg$_" -ne $null) {
Set-ItemProperty -Path $key -Name "SQLArg$_" -Value "Powershell Rocks"
}
}

Related

Powershell passing multiple parameters from one script to another [duplicate]

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
}

Incrementing variables in powershell

I'm new to PowerShell and am trying to create a script that goes through a csv file (simple name,value csv) and loads each new line in it as a variable and then runs a function against that set of variables.
I've had success at getting it to work for 1 variable by using the following code snippet:
Import-Csv -Path C:\something\mylist.csv | ForEach-Object {
New-Variable -Name $_.Name -Value $_.Value -Force
}
My csv looks like this:
name,value
RegKey1,"Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\LanmanWorkstation"
Basically it's a list of registry keys each named as RegKey# and then the path of that reg key is the intended value of the variable.
I'm currently playing around with the "Test-Path" cmdlet that just prints out true/false if the passed reg-key exists and then just prints out some text based on if it found the reg key or not.
That snippet looks like so:
Test-Path $RegKey1
IF ($LASTEXITCODE=0) {
Write-Output "It worked"
}
else {
Write-Output "It didn't work"
}
This works fine however what I'm trying to achieve is for powershell to run this cmdlet against each of the lines in the csv file - basically checking each reg key in it and then doing whatever specified to it.
What I'm trying to avoid is declaring hundreds of variables for every regkey I plan on using but instead have this one function that just runs through the csv and every time it runs, it increments the number next to the variable's name - RegKey1,RegKey2,RegKey3 etc.
Let me know if there's a way to do this in powershell or a better way of approaching this altogether. I also apologize in advance if I've not provided enough info, please do let me know.
You need to place your if statement in the Foreach-Object loop. This will also only work, if your variable all get the same name of $RegKey. To incriment, you may use the for loop.
Import-Csv -Path C:\something\mylist.csv | ForEach-Object {
New-Variable -Name $_.Name -Value $_.Value -Force
IF (Test-Path $RegKey1) {
Write-Output "It worked"
}
else {
Write-Output "It didn't work"
}
}
The if statement returns a boolean value of $true, or $false. So theres no need to use $LastExitCode by placing the Test-Path as the condition to evaluate for.
Alternatively, you can use the Foreach loop to accomplish the same thing here:
$CSV = Import-Csv -Path C:\something\mylist.csv
Foreach($Key in $CSV.Value){
$PathTest = Test-Path -Path $Key
if($PathTest) {
Write-Output "It worked"
} else {
Write-Output "It didn't work"
}
}
By iterating(reading through the list 1 at a time) through the csv only selecting the value(Reg Path), we can test against that value by assigning its value to the $PathTest Variable, to be evaluated in your if statement just like above; theres also no need to assign it to a variable and we can just use the Test-Path in your if statement like we did above as well for the same results.

Powershell - Iterate through variables dynamically

I am importing a CSV file with two records per line, "Name" and "Path".
$softwareList = Import-Csv C:\Scripts\NEW_INSTALLER\softwareList.csv
$count = 0..($softwareList.count -1)
foreach($i in $count){
Write-Host $softwareList[$i].Name,$softwareList[$i].Path
}
What I am trying to do is dynamically assign the Name and Path of each record to a WPFCheckbox variable based on the $i variable. The names for these checkboxes are named something such as WPFCheckbox0, WPFCheckbox1, WPFCheckbox2 and so on. These objects have two properties I planned on using, "Command" to store the $SoftwareList[$i].path and "Content" to store the $SoftwareList[$i].Name
I cannot think of a way to properly loop through these variables and assign the properties from the CSV to the properties on their respective WPFCheckboxes.
Any suggestions would be very appreciated.
Invoke-Expression is one way, though note Mathias' commented concerns on the overall approach.
Within your foreach loop, you can do something like:
invoke-expression "`$WPFCheckbox$i`.Command = $($SoftwareList[$i].Path)"
invoke-expression "`$WPFCheckbox$i`.Content= $($SoftwareList[$i].Name)"
The back-tick ` just before the $WPFCheckBox prevents what would be an undefined variable from being immediately evaluated (before the expression is invoked), but the $I is. This gives you a string with your $WPFCheckbox1, to which you then append the property names and values. The $SoftwareList values are immediately processed into the raw string.
The Invoke-Expression then evaluates and executes the entire string as if it were a regular statement.
Here's a stand-alone code snippet to play with:
1..3 |% {
invoke-expression "`$MyVariable$_` = New-Object PSObject"
invoke-expression "`$MyVariable$_` | add-member -NotePropertyName Command -NotePropertyValue [String]::Empty"
invoke-expression "`$MyVariable$_`.Command = 'Path #$_'"
}
$MyVariable1 | Out-String
$MyVariable2 | Out-String
$MyVariable3 | Out-String
As a side note (since I can't comment yet on your original question,) creating an array just to act as iterator through the lines of the file is really inefficient. There are definitely better ways to do that.

Dynamic Variable & Objects

Trying to create a script that will read the contents of a directory containing a number of "paired" datasets containing customer data, for each customer there will be 2 datasets with the naming convention appearing consistently in the form: CustomerNo_DataType.csv where CustomerNo will always be numerical string value.
I've already written a crude version of this script with the customer numbers hard-coded so now I'm trying to improve on that - here's what I've got so far:
$files = Get-ChildItem "Path-to-data-files"
$files = $files.FullName
for ($i=0; $i -le $files.Count; $i++){
$thisFile = $files[$i].Split("\")
This leaves me with an array with the full pathname broken down into components so I grab the filename from the last position in the array
$thisFile = $thisFile[$thisFile.Count - 1]
...
}
I want to use the customer no to create a hashtable, so if the customer no in the filename was 12345 then I want to create a hashtable named $12345 - I'm not having any issues accessing the value, just not sure how to use it to name something.
Use Split-Path to get the file element of a path:
$file = Split-Path 'C:\path\to\some\file.txt' -Leaf
Use New-Variable if for some reason you need to define a variable name from a variable.
$customerNo = '12345'
New-Variable -Name $customerNo -Value #{}
However, I wouldn't recommend creating a bunch of dynamically named variables. It's usually a lot easier to handle if you create a "parent" hashtable for the dynamic names. You can have nested hashtables inside it if you need that:
$customerNo = '12345'
$customers = #{}
$customers[$customerNo] = #{}

How do I retrieve a HashTable key from a value?

I have a PowerShell HashTable that contains a set of key-value pairs (naturally). All of the HashTable values are unique.
I would like to retrieve a HashTable key, based on a value that I specify, using PowerShell.
Another options:
to iterate over the HashTable keys and find a key that contains the
value:
$HashTable.Keys |? { $HashTable[$_] -eq $Val }
to iterate using GetEnumerator() function:
$HashTable.GetEnumerator() | ?{ $_.Value -eq $Val } | %{ $_.Key }
You can use PowerShell 4.0's Where method syntax to achieve this. The Where method accepts a PowerShell ScriptBlock to find objects matching the specified criteria. We can iterate over the HashTable keys and find a key that contains the desired value.
In case you do have a scenario where you have duplicate HashTable values, you can optionally specify a second parameter, of type WhereOperatorSelectionMode, that specifies which objects should be returned by the call to the Where method. By specifying First for the second method parameter, we can ensure that only a single HashTable key is ever returned.
All of the supported values for the second parameter are as follows:
Default
First
Last
SkipUntil
Until
Split
$HashTable = #{
1 = 10;
2 = 20;
3 = 30;
}
$Val = 30;
$HashTable.Keys.Where({ $HashTable[$PSItem] -eq $Val; }, [System.Management.Automation.WhereOperatorSelectionMode]::First);