How to Pass User Input to a JSON File using powershell - powershell

I am creating a PowerShell script using Convert To-JSON cmd and i achieved that using below
$body = #{
devices = #(
#{
credentials = #(
#{
label = 'username'
value = 'myname'
sensitive = 'false'
},
#{
label = 'Password'
value = 'Password#!'
sensitive = 'true'
}
)
services = #(
#{
name = 'RDP'
url = "https://$inputIpAddress/?pauth=[proxy_token]&data=[connection:$inputUsername]"
instructor = 'false'
},
#{
name = 'HTTPS'
url = "https://$inputIpAddress/?pauth=[proxy_token]&data=[connection:$inputUsername]"
instructor = 'false'
},
#{
name = 'SSH'
url = "https://$inputIpAddress/?pauth=[proxy_token]&data=[connection:$inputUsername]"
instructor = 'false'
}
connections = #(
#{
id = 'myname-rdp'
protocol = 'rdp'
hostname = "192.168.1.6"
port ='3389'
}
)
Parameters = #(
#{
name = 'username'
value = 'myname'
},
#{
name = 'password'
value = 'Password#!'
}
)
}
)
}
i am converting the above powershell to JSON File($body | ConvertTo-Json -Depth 4) and i would like to replace pass the arguments for the Username and IP Address and store it with the username.json every time while converting to JSON.
i have tried the Read-host to get the input from the user but i am facing difficulty to pass that input before printing the output.

For the IP address, you can set the new value by defining the parameter using standard dot-notation.
In the case of username, because Parameters is an array with duplicate object names, doing $body.devices.Parameters.name would return both the username and password objects, so you can filter the array to only select the object where the name is username
$inputUsername = Read-Host "Input Username"
$inputIpAddress = Read-Host "Input IP address"
( $body.devices.Parameters | Where-Object { $_.name -eq 'username' } ).value = $inputUsername
$body.devices.connections.hostname = $inputIpAddress
$body | ConvertTo-Json -Depth 4

As an interpreted language, PowerShell allows you to construct literals based on values that are determined at runtime.
Therefore, simply place your hashtable literal (#{ ... }) after your Read-Host calls, and reference the variables in which you store the Read-Host responses in that literal.
A simplified example:
# Simulate two Read-Host calls (hard-code sample values).
$foo = 42
$bar = 'hi'
# Now define the hashtable literal and reference the variables assigned to above.
# Note: An [ordered] hashtable is used in order to retain the entries
# in definition order.
[ordered] #{
devices = #{
foo = $foo
bar = $bar
}
}
Piping the above to ConvertTo-Json -Depth 4 yields:
{
"devices": {
"foo": 42,
"bar": "hi"
}
}
Note how the values of $foo and $bar were incorporated. You could even use the same technique in a loop, provided the hashtable literal is also in the loop body (after setting the variables it references).

Related

Powershell script output to Discord

removing source for Proprietary reasons
ERROR
Out-String : A positional parameter cannot be found that accepts argument 'System.Object[]'.
At line:176 char:28
content = $summaries | Out-String `
Note: This isn't a complete answer, but it addresses your immediate problem - broken [pscustomobject] literal syntax - and provides some background information.
Format-Table, as all Format-* cmdlets, is only intended to produce output for display as opposed to programmatic processing.
To produce data (objects), use the Select-Object, which uses the same syntax with respect to the -Property parameter as Format-Table, notably including the calculated properties your Format-Table call uses.
Select-Object outputs [pscustomobject] instances that each have the specified properties.
Thus, you may be looking for this:
# Note The ` at the end of the line continues the Select-Object call
# on the next line, and the following lines are an array of
# property names / calculated properties that are passed
# to the positionally implied -Property parameter
$payload = $summaries | Select-Object `
start,
end,
#{ Label = 'issued_amount'; Expression = { '{0:C0}' -f $_.issued_amount }; Align = 'right' },
#{ Label = 'maturing_amount'; Expression = { '{0:C0}' -f $_.maturing_amount }; Align = 'right' },
#{ Label = 'inflation_compensation'; Expression = { '{0:C0}' -f $_.inflation_compensation }; Align = 'right' },
#{ Label = 'secondary_purchased'; Expression = { '{0:C0}' -f $_.secondary_purchased_amount }; Align = 'right' },
#{ Label = 'secondary_sold'; Expression = { '{0:C0}' -f $_.secondary_sold_amount }; Align = 'right' },
#{ Label = 'change'; Expression = { '{0:$#,##0}' -f $_.change }; Align = 'right' }
$payload is now an array of [pscustomobject] instances with the specified properties.
However, it looks like you cannot pass such an array directly to Send-DiscordMessage, except perhaps via the -Text parameter, which requires you to create a formatted string representation via Out-String:
Send-DiscordMessage -Uri $hookUrl -Text ($payload | Out-String)

How do I reverse transversal in a PowerShell array

Given a PowerShell array hashtable1 similar to the following:
$dept= #{
'Sales' = #{
'SAM' = 'Manager'
'SAP' = 'Person'
}
'IT' = #{
'ITM' = 'Manager'
'ITS' = 'Specialist'
'ITT' = 'Technician'
'ITC' = 'Consultant'
}
}
If enter the following in the console:
$dept.it.itc
$dept.sales.sam
I get:
Consultant
Manager
Which is as expected.
However, what I'd like to do is something like
write-host $dept.itc
write-host $dept.sam
and get
IT Consultant
Sales Manager
in return.
I'm looking for a sort function to do a 'reverse traversal' of the array because 'IT', 'Sales' etc are the OU's I need to put new users into. There are many more OU's that I have removed for brevity.
[1] An array is simply a list of values and a hashtable is a collection of key/value pairs similiar to Javascript's JSON or Python's dict.
It is worth noting that your object is not an Array. In PowerShell #{} is a Hashtable. You can read more about working with Hashtables here.
If you have what I am going to call a unique Role Code for each role in your department OU's, all you want to do is match the Key in the nested Hashtables to find your department. It's easiest to create a quick helper function to deal with multiple calls, unless you are just looping through an array or list of strings.
Here is an example of how to extract the string you want: (If you do not have unique keys, then you may need to add additional filtering)
$Departments = #{
'Sales' = #{
'SAM' = 'Manager'
'SAP' = 'Person'
}
'IT' = #{
'ITM' = 'Manager'
'ITS' = 'Specialist'
'ITT' = 'Technician'
'ITC' = 'Consultant'
}
}
function Get-DepartmentOU {
Param (
[CmdletBinding()]
[Parameter(Mandatory = $true)]
[System.String]
$RoleCode
)
# Get the DictionaryEntry in the main Hashtable where the nested Hashtable value matches the role you are looking for.
$Department = $script:Departments.GetEnumerator() | Where-Object { $_.Value.ContainsKey($RoleCode) }
# Print the name of the DictionaryEntry (Your department) and retrieve the value from the Hashtable for the role.
Write-Output ("{0} {1}" -f $Department.Name, $Department.Value[$RoleCode])
}
And then you can get them by running the function and specifying the code.
PS > Get-DepartmentOU -RoleCode ITC
IT Consultant

Array of hash tables not output

This is a basic question but I'm stuck. I have the below code:
$array = #(
$hashtable1 = #{
Name = "Test1"
Path = "C:\Test1"
}
$hashtable2 = #{
Name = "Test1"
Path = "C:\Test1"
}
)
The array is created but empty. I have tried comma separation:
$hashtable1 = #{}, $hashtable2 = #{}
But this did not work. What is wrong?
You are assigning the hashtables as variables. Take out the variable assignment:
$array = #(
#{
Name = "Test1"
Path = "C:\Test1"
},
#{
Name = "Test1"
Path = "C:\Test1"
}
)
gms0ulman's helpful answer provides an effective solution for constructing your array of hashtables.
To provide some background information:
A variable assignment such as $hashtable1 = ... is not an expression, so it produces no output, which is why your $array = assignment ended up containing an empty array, given that #(...) saw no output.
However, you can make assignment statements produce output simply by enclosing them in (...), which turns them into expressions, which allows you to assign to the variable and output the assigned value.
#(...) is not needed to construct arrays; instead, you can use ,, the array-construction operator.
Even though it may not be needed, the following demonstrates how to both construct the array of hashtables and save the individual hashtables in dedicated variables:
$array =
($hashtable1 = #{
Name = "Test1"
Path = "C:\Test1"
}),
($hashtable2 = #{
Name = "Test1"
Path = "C:\Test1"
})

Grab parameters from url and drop them to powershell variables

i have a powershell listener running on my windows-box. Code from Powershell-Gallery: https://www.powershellgallery.com/packages/HttpListener/1.0.2
The "Client" calls the listener with the following example url:
With Powershell i do:
invoke-webrequest -Uri "http://127.0.0.1:8888/Test?id='1234'&param2='##$$'&param3='This is a test!'"
I have no idea, how to drop the parameters from the url to variables with the same name in powershell. I need to bring the parameters to powershellvariables to simply echo them. this is my last missing part. The parameters are separated with & and parameternames are case-sensitive.
To be more detailed, the id from the url should be in a powershell-variable named $id with the value 1234. The Variables can contain spaces, special characters, numbers, alphas. They are case sensitive. The parametervalue could be "My Name is "Anna"! My Pets Name is 'Bello'. " with all the "dirty" Characters like '%$"!{[().
Can someone point me to the right way how to get this solved?
In a valid url, the $ characters should have been escaped to %24
The other 'dirty' character % in Url escaped form is %25
This means the example url is invalid and should be:
$url = "http://127.0.0.1:8888/Test?id='1234'&param2='##%24%24'&param3='This is a test!'"
Then the following does work
$url = "http://127.0.0.1:8888/Test?id='1234'&param2='##%24%24'&param3='This is a test!'"
if ($url -is [uri]) {
$url = $url.ToString()
}
# test if the url has a query string
if ($url.IndexOf('?') -ge 0) {
# get the part of the url after the question mark to get the query string
$query = ($url -split '\?')[1]
# or use: $query = $url.Substring($url.IndexOf('?') + 1)
# remove possible fragment part of the query string
$query = $query.Split('#')[0]
# detect variable names and their values in the query string
foreach ($q in ($query -split '&')) {
$kv = $($q + '=') -split '='
$varName = [uri]::UnescapeDataString($kv[0]).Trim()
$varValue = [uri]::UnescapeDataString($kv[1])
New-Variable -Name $varname -Value $varValue -Force
}
}
else {
Write-Warning "No query string found as part of the given URL"
}
Prove it by writing the newly created variables to the console
Write-Host "`$id = $id"
Write-Host "`$param2 = $param2"
Write-Host "`$param3 = $param3"
which in this example would print
$id = '1234'
$param2 = '##$$'
$param3 = 'This is a test!'
However, I personally would not like to create variables like this, because of the risk of overwriting already existing ones.
I think it would be better to store them in a hash like this:
# detect variable names and their values in the query string
# and store them in a Hashtable
$queryHash = #{}
foreach ($q in ($query -split '&')) {
$kv = $($q + '=') -split '='
$name = [uri]::UnescapeDataString($kv[0]).Trim()
$queryHash[$name] = [uri]::UnescapeDataString($kv[1])
}
$queryHash
which outputs
Name Value
---- -----
id '1234'
param2 '##$$'
param3 'This is a test!'

Save hash table in PowerShell object notation (PSON)

The question Loading a PowerShell hashtable from a file? documents how to load a file that contains a hashtable in PSON format into a variable, but how does one save a hashtable to a file in PSON format?
Hashtable:
#{
"name" = "report 0"
"parameters" = #(
#{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
#{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
)
}
After 5 years, the cmdlet I had pasted in the original answer has undergone so many updates that it has become completely outdated. Therefore I have replaced the code and the ReadMe with a link to the latest version.
ConvertTo-Expression
The ConvertTo-Expression cmdlet can be download from PowerShell Gallery using the command:
Install-Script -Name ConvertTo-Expression
ReadMe
The full ReadMe (and source code) is available from the GitHub
Answer
Below are some possible options to serialize the specific example (assigned to $Craig) in the question:
ConvertTo-Expression $Craig
#{
parameters =
#{
name = 'parameter 0'
default = 1
values =
1,
2,
3,
4
},
#{
name = 'parameter 1'
default = 'A'
values =
'A',
'B',
'C'
}
name = 'report 0'
}
To limit the tree view expansion:
(Expand -0 will output a single line and Expand -1 will remove also the unnecessary spaces)
ConvertTo-Expression $Craig -expand 3
#{
parameters =
#{name = 'parameter 0'; default = 1; values = 1, 2, 3, 4},
#{name = 'parameter 1'; default = 'A'; values = 'A', 'B', 'C'}
name = 'report 0'
}
Preserving the explicit types (strong typed):
ConvertTo-Expression $Craig -expand 3 -Strong
[hashtable]#{
parameters = [array](
[hashtable]#{name = [string]'parameter 0'; default = [int]1; values = [array]([int]1, [int]2, [int]3, [int]4)},
[hashtable]#{name = [string]'parameter 1'; default = [string]'A'; values = [array]([string]'A', [string]'B', [string]'C')}
)
name = [string]'report 0'
}
(Note: As per PowerShell design, HashTables are not in order, but if required you might use the [Ordered] type instead.)
Try the *-CliXml cmdlets. To save the object:
#{
"name" = "report 0"
"parameters" = #(
#{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
#{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
)
} | Export-Clixml -Path c:\hash.xml
To read it back:
Import-Clixml c:\hash.xml
One way would be to put the hashtable definition in a scriptblock:
$hashtable = {
#{
"name" = "report 0"
"parameters" = #(
#{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
#{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
)
}
}
$hashtable.tostring()
#{
"name" = "report 0"
"parameters" = #(
#{"name" = "parameter 0"; "default" = 1; "values"=1,2,3,4},
#{"name" = "parameter 1"; "default" = 'A'; "values" = 'A','B','C'}
)
}
Within the script, you'd need to invoke the script block to instantiate the hashtable:
$hash = .$hashtable
How to use a shorthand "object notation" to generate an object in PowerShell:
$object = New-Object -TypeName PSObject -Property #{name="foo";age=21}
DISCLAIMER: I know this does not answer OP's question directly but it might help folks like me searching for a very similar issue and landing here.