Powershell convertfrom-json separate two sets of values from JSON - json

There is a JSON URL which produces dynamic content, and there is one particular part of the JSON URL which I am trying to separate two values which have no title or name associated to them other than the parent title (accountUsage) and give them each a unique title, which I can then call upon in PowerShell.
Any ideas how to achieve this?
I need to convert this
accountUsage : #{10.10.2018=5; 09.10.2018=0; 08.10.2018=0; 07.10.2018=0; 06.10.2018=0; 05.10.2018=8; 04.10.2018=1; 03.10.2018=0;
02.10.2018=0; 01.10.2018=0}
Into this:
date
----
10.10.2018
value
----
5
date
----
09.10.2018
value
----
0

$json = '{"accountUsage":{"06.10.2018":0,"09.10.2018":0,"04.10.2018":1,"08.10.2018":0,"02.10.2018":0,"07.10.2018":0,"03.10.2018":0,"05.10.2018":8,"10.10.2018":5,"01.10.2018":0}}'
$data = $json | ConvertFrom-Json
$data.accountUsage | Get-Member -MemberType NoteProperty | ForEach-Object {
$key = $_.Name
[PSCustomObject]#{
date = $key
value = $data.accountUsage.$key
}
}
gives me a list of date/value pairs:
date value
---- -----
06.10.2018 0
09.10.2018 0
04.10.2018 1
08.10.2018 0
02.10.2018 0
07.10.2018 0
03.10.2018 0
05.10.2018 8
10.10.2018 5
01.10.2018 0
See this earlier answer of mine for some more insight into this.

Related

how can I convert normal string to json object in Powershell

I have this table in normal string format ,
I want to convert this string to json object in PowerShell. ConvertTo-Json is not giving in correct format.
The answer depends somewhat on the true format of the table. If I assume this is tab delimited and that each column name doesn't have spaces I could pull it out something like:
$String =
#"
test test2 first others versions
------------------------------------------
Decimal 1 2 5 p
Decimal 1 3 8 p
Decimal 1 2 4 i
Decimal 2 2 6 p
Decimal 5 4 6 k
Decimal 2 5 2 p
"#
$String = $String -split "\r?\n"
$Headers = $String[0] -split "\s"
$Objects =
$String[2..($String.Count -1)] |
ConvertFrom-Csv -Header $Headers -Delimiter "`t" |
ConvertTo-Json
Above, -split the big string into lines, then look at the header line and -split it to get an array of column headers. Now skipping the first 2 elements in the $String array convert the remaining lines to objects using ConvertFrom-Csv and using the previously extracted $Headers array.
Note: This segment may also work and may be preferred for readability:
$Objects =
$String |
Select-Object -Skip 2 |
ConvertFrom-Csv -Header $Headers -Delimiter "`t" |
ConvertTo-Json
Note: Splitting on white space ( "\s" ) may cause issues if the field data may have whitespace itself.
However, given the ambiguity, a more certain approach might be more reliable, I would use the known start and end positions of the table's fields to do this.
Continuing with the above example string:
$String =
#"
test test2 first others versions
------------------------------------------
Decimal 1 2 5 p
Decimal 1 3 8 p
Decimal 1 2 4 i
Decimal 2 2 6 p
Decimal 5 4 6 k
Decimal 2 5 2 p
"#
$String = $String -Split "\r?\n"
$String |
Select-Object -Skip 2 |
ForEach-Object{
[PSCustomObject]#{
test = $_.SubString(0,7)
test2 = $_.SubString(8,1)
first = $_.SubString(14,1)
others = $_.SubString(20,1)
versions = $_.SubString(26,1)
}
}
Again, these positions may change depending if the columns are separated by spaces or tabs. My sample data may not be the same as yours and you may need to play with those positions. That said this is a very useful technique for deal with output from traditional console applications, very much worth knowing...
Note: Thanks Neko Nekoru; I added '?' to the RegEx to accommodate both Unix & Windows line ending styles.

Search Max date in an API call

I run an API call on midnight everyday and I wanted to capture the number of records with maximum date and the number of records can change daily.
$access_token ="Access_Token"
$URI = "https://X1Y2Z3A1"
$headers = #{“authorization” = “Bearer $access_token”}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$result = Invoke-RestMethod -Uri $URI -Headers $headers -ContentType $ContentType |ConvertTo-Json
$a = $Result|ConvertFrom-Json| Select -ExpandProperty Forms
$a
id Date
-------- -----------
A1 15/06/2019 16:25:46
A2 15/06/2019 17:26:22
A3 16/06/2019 13:25:46
A4 17/06/2019 14:21:46
A5 17/06/2019 15:21:46
I want to capture the records with maximum date as shown below:
Desired Result:
id Date
-------- -----------
A4 17/06/2019 14:21:46
A5 17/06/2019 15:21:46
this will get the items with the newest date [excluding the time].
what it does ...
creates the collection to work on
you will normally get this from Import-CSV or from the output of another code call.
sorts by the .Date property, newest 1st
groups by the date part of the .Date property
selects the 1st object from the previous grouping
gets the value in the .Group property of the previous object
puts that into the $NewestDateList variable
displays that $Var
the only likely glitch with this is the way date strings are handled. i suspect that any serious variation in format would require explicitly parsing the dates.
here's the code ...
# fake reading in a CSV file OR getting a array of objects
# in real life, use Import-CSV OR get the array from calling another source
$InStuff = #'
id, Date
A1, 15/06/2019 16:25:46
A2, 15/06/2019 17:26:22
A3, 16/06/2019 13:25:46
A4, 17/06/2019 14:21:46
A5, 17/06/2019 15:21:46
'# | ConvertFrom-Csv
$NewestDateList = ($InStuff |
Sort-Object -Property Date -Descending |
Group-Object -Property {$_.Date.Split(' ')[0]} |
Select-Object -First 1).
Group
$NewestDateList
output ...
id Date
-- ----
A5 17/06/2019 15:21:46
A4 17/06/2019 14:21:46

Piping an empty object has a count of 1

I can't seem to get this function quite right. I want to pass it an object and if the object is empty, return 1, else count items in the object and increment by 1.
Assuming the following function "New-Test":
function New-Test
{
[cmdletbinding()]
Param
(
[Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
[object[]]$Object
#[object]$object
)
Begin
{
$oData=#()
}
Process
{
"Total objects: $($object.count)"
if($Object.count -gt 0)
{
$oData += [pscustomobject]#{
Name = $_.Name
Value = $_.Value
}
}
Else
{
Write-Verbose "No existing object to increment. Assuming first entry."
$oData = [pscustomobject]#{Value = 0}
}
}
End
{
$LatestName = ($oData | Sort-Object -Descending -Property Value | Select -First 1).value
[int]$intNum = [convert]::ToInt32($LatestName, 10)
$NextNumber = "{0:00}" -f ($intNum+1)
$NextNumber
}
}
And the following test hashtable:
#Create test hashtable:
$a = 00..08
$obj = #()
$a | foreach-object{
$obj +=[pscustomobject]#{
Name = "TestSting" + "{0:00}" -f $_
Value = "{0:00}" -f $_
}
}
As per the function above, if I pass it $Obj, I get:
$obj | New-Test -Verbose
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
Total objects: 1
09
Which is as expected. However, if I pass it $Obj2:
#Create empty hash
$obj2 = $null
$obj2 = #{}
$obj2 | New-Test -Verbose
I get:
Total objects: 1
Exception calling "ToInt32" with "2" argument(s): "Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: startIndex"
At line:33 char:9
+ [int]$intNum = [convert]::ToInt32($LatestName, 10)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException
01
I don't understand why $object.count is 1, when there's nothing in the hashtable.
If I change the parameter, $object's type from [object[]] to [object], the empty hashtable test results in:
$obj2 | New-Test -Verbose
Total objects: 0
VERBOSE: No existing object to increment. Assuming first entry.
01
Which is what I'd expect, however, if I run the first test, it results in:
$obj | New-Test -Verbose
Total objects:
VERBOSE: No existing object to increment. Assuming first entry.
Total objects:
VERBOSE: No existing object to increment. Assuming first entry.
This time $objects has nothing in it.
I'm sure it's simple, but I can't fathom this one out. Any help is appreciated.
P.S. PowerShell 5.1
$obj2 is a hashtable, not an array. Hashtables are not enumerated by default, so the hashtable itself is the one object. If you want to loop through an hashtable using the pipeline you need to use $obj2.GetEnumerator().
#{"hello"="world";"foo"="bar"} | Measure-Object | Select-Object Count
Count
-----
1
#{"hello"="world";"foo"="bar"}.GetEnumerator() | Measure-Object | Select-Object Count
Count
-----
2

Replace empty fields in CSV with 0

I am trying to replace null values in a certain column to 0 using PowerShell.
I have the CSV in this format:
test test2 test3 test4
---- ----- ----- -----
blah fsds 4 45645
bla1 fsds1 45645
blah2 fsds2 4 34322
blah3 fsds3 4 67544
blah4 fsds4 3432432
so I want to go through the null values in "test3" and replace to 0.
I have this, but it doesn't work:
$inFilePath = "G:\powershell\excel\test.csv"
$csvColumnNames = (Get-Content $inFilePath | Select-Object -First 1).Split(",")
foreach ($row in $inFilePath) {
if ($row.test3 -eq $null) {
$row.test3 = 0
Write-Host "updating value in excel"
}
}
$csvColumnNames | Export-Csv "G:\powershell\excel\replaced2.csv" -NoTypeInformation
you are on the right track with foreach and if.Try this:
foreach($row in $inFilePath)
{
if (-not $row.test3)
{
$row.test3= 0
}
}
to get the column headers:
$inFilePath | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name
Use Import-Csv for reading and Export-Csv for writing CSV files.
$inFilePath = "G:\powershell\excel\test.csv"
$outFilePath = "G:\powershell\excel\replaced2.csv"
Import-Csv $inFilePath | % {
if (-not $_.test3) { $_.test3 = 0 }
$_ # echo all records, so they can be exported back to a file
} | Export-Csv $outFilePath -NoType

PowerShell Build a 2D HTML table

In my script I've collected all the data I want to report in different variables. Now I'm trying to generate an HTML-table so I can send this by mail.
What I would like to achieve is HTML-code that generates this:
OU | Logon scripts incorrect | Name incorrect | No description
\\Domain\NLD Users | 2 | 6 | 2
\\Domain\FRA users | 5 | 7 | 0
\\Domain\BEL users | 6 | 1 | 1
TOTAL USERS: 2048 | 13 | 14 | 3
I'm a bit confused on what would be the best approach for this (array, psobject, hashtable, ..). Because I'm not going to work with a foreach loop, the data would be static.
What I tried so far but isn't quite giving the desired result:
$Table = #( ('OU', 'Logon scripts incorrect', 'Name incorrect', 'No description'),
('\\Domain\NLD Users','2','6','2' ),
('\\Domain\FRA Users','5','7','0' ),
('\\Domain\BEL Users','6','1','1' ),
('TOTAL USERS: 2048','13','14','3' )
)
$Table | ConvertTo-Html -As Table -Fragment
It feels like I'm over-complicating things.
convertto-html is waiting for a psobject as its input.
What you can do is pass your data as csv then use convertfrom-csv to tansform it to psobject the run convertto-html :
$Table = #"
'\\Domain\NLD Users','2','6','2'
'\\Domain\FRA Users','5','7','0'
"#
$Table | ConvertFrom-Csv -Header 'OU', 'Logon scripts incorrect', 'Name incorrect', 'No description' | ConvertTo-Html -Fragment -As Table
#( ('OU', 'Logon scripts incorrect', 'Name incorrect', 'No description'),
('\\Domain\NLD Users','2','6','2' ),
('\\Domain\FRA Users','5','7','0' ),
('\\Domain\BEL Users','6','1','1' ),
('TOTAL USERS: 2048','13','14','3' )
) | Select-Object -Skip 1 | ForEach-Object{
[PSCustomObject]#{
OU = $_[0]
"Logon scripts incorrect" = $_[1]
"Name incorrect" = $_[2]
"No Description" = $_[3]
}
} | ConvertTo-Html -As Table -Fragment
From what i have read ConvertTo-Html takes .Net Objects and not arrays to convert to html. I converted your static table to a custom object which then was exported. This might look more to your liking.
You're creating an array of arrays with your statement, which looks neat, but isn't something ConvertTo-Html can handle. Create new objects instead (this is for v3):
$x = #(
([pscustomobject] #{
"OU" = "\\Domain\NLD Users";
"Logon scripts incorrect" = 2;
"Name incorrect" = 6;
"No description" = 2;
}),
([pscustomobject] #{
"OU" = "\\Domain\FRA Users";
"Logon scripts incorrect" = 5;
"Name incorrect" = 7;
"No description" = 0;
})
# ...and so on, or more realistically, constructed using Foreach-Object
)
$x | convertto-html -fragment
If you're confined to PowerShell v2, you can use new-object -type psobject -prop instead, but then the properties are not ordered so you will need an explicit Select.