How to extract json data from the Url using powershell script - json

I want my data from the url and want to filer it accordingly and export that data into the csv file
This is my code
Here $url variable contains the url
$defs = (Invoke-RestMethod -Uri ($url) -Method Get -UseDefaultCredentials)
$json = convertto-Json $defs
$json | Out-File D:\My_scripts\Final.json
$a = Get-Content D:\My_scripts\Final.json -raw | Out-String | ConvertFrom-Json
$arrOutput = #()
foreach($l2 in $a)
{
foreach($l3 in $l2.value)
{
#Write-Host $l3.id
$arr = #{}
$arr.id = $l3.id
$arr.name = $l3.name
$outarray = New-Object Psobject -Property $arr
$arrOutput += $outarray
}
}
$arrOutput | Export-Csv -Path D:\My_scripts\Final.csv -Delimiter "," -NoTypeInformation
But not able to get the values

Related

Adding JSON content to PSCustomObject - The property cannot be found on this object

Quite new to objects in PS.
I'm trying to create pscustomobject, adding JSON contents to it via ConvertFrom-JSON and then I'm trying to get contents from another JSON to be set on one of the properties ( nested hierarchy)
$combinedObject=#()
$props = #{
ServiceDefinitions = #()
DataCenters = #()
}
$combinedObject = New-Object -TypeName PSCustomObject -Property $props
$servicedefinitions = Get-ChildItem -Path .\ServiceDefinitions\ | Select Name
$datacenters = Get-ChildItem -Path .\DataCenters\ | Select Name
$environments = #("Production")
$env="TEST"
Foreach ($datacenter in $datacenters)
{
$datacenterdata = $null
write-host "new run"
write-host $datacenter.Name
$datacentername = $datacenter.Name
$datacenterdata = Get-Content -Path .\DataCenters\$datacentername\config.json -Raw
$datacenterformatteddata = $datacenterdata | ConvertFrom-Json -Depth 5
$combinedObject.DataCenters += $datacenterformatteddata
$combinedObject.DataCenters.$datacentername
}
Foreach ($datacenter in $datacenters)
{
$pods = $null
$datacetnername = $null
$datacentername = $datacenter.Name
$pods = Get-ChildItem -Path .\DataCenters\$datacentername\$env\Pod\ | Select Name
Foreach ($pod in $pods)
{
$podname = $pod.Name
$poddata = Get-Content -Path .\DataCenters\$datacentername\$env\Pod\$podname\config.json -Raw
#echo $combinedObject.DataCenters
write-host $datacentername
$podformatteddata = $poddata | ConvertFrom-Json -Depth 5
$combinedObject.DataCenters.$datacentername.pods += $podformatteddata
}
}
For each loop iterations I receive
The property 'pods' cannot be found on this object. Verify that the property exists and can be set.
I can query the pods but cannot set it, it looks to be of a system type System.Object[] do I need to convert it somehow to PSCustomObject for the contents of the next JSON file to be added to it?
Resolved by changing JSON from
pods:[] to
podlist:{ pods:[]}
and referencing
$combinedObject.DataCenters.$datacentername.podlist.pods
to set the value.

How to create JSON payload using power shell Foreach loop

Requirement: To send E-Mail via send grid account (Send Grid API) by attaching multiple attachments.
Description: I am able to create json payload and able to send with single attachment by hard coding attachment values. I am opening window forms dialog and able to select single/multiple files that needs to be attached.
Code:
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{
InitialDirectory = [Environment]::GetFolderPath('Desktop')
#Filter = 'Documents (*.docx)|*.docx|SpreadSheet (*.xlsx)|*.xlsx'
Filter = 'All files (*.*)| *.*'
Title = 'Select File(s) for Attachments'
Multiselect = $true
}
$FileBrowser.ShowDialog() | Out-Null
$FilesEncodedContents = New-Object System.Collections.ArrayList
$AttachmentsjsonRequest = #()
if ($FileBrowser.FileNames.Count -gt 0) {
foreach ($file in $FileBrowser.FileNames) {
[string] $filerawContent = $null
$filedetails = Get-Item $file
$filerawContent = ConvertToBase64Encode $file
if (![string]::IsNullOrWhitespace($filerawContent)) {
$FilesEncodedContents.Add($filerawContent)
$obj = New-Object -TypeName PSObject
$obj | Add-Member -MemberType NoteProperty -Name filename -Value (Get-Item $file).Name
$obj | Add-Member -MemberType NoteProperty -Name content_id -Value (Get-Item $file).Name
$obj | Add-Member -MemberType NoteProperty -Name content -Value $filerawContent
$obj | Add-Member -MemberType NoteProperty -Name disposition -Value 'attachment'
$AttachmentsjsonRequest += $obj
}
}
}
Write-Host "$AttachmentsjsonRequest"
$headers = #{ }
$headers.Add("Authorization", "Bearer $ApiKey")
$headers.Add("Content-Type", "application/json")
$jsonRequest = [ordered]#{
personalizations = #(#{to = #(#{email = "$MailTo" })
subject = "$Subject"
})
from = #{email = "no-reply#xxx.com" }
attachments = "$AttachmentsjsonRequest"
content = #( #{ type = "text/plain"
value = "Sample Mail Body"
}
)
} | ConvertTo-Json -Depth 100
Write-Host $jsonRequest | ConvertTo-Json -Depth 100
Invoke-RestMethod -Uri "https://api.sendgrid.com/v3/mail/send" -Method Post -Headers
$headers -Body $jsonRequest
Write-Host "Mail Sent"
#region ConvertToBase64Encode
Function ConvertToBase64Encode([string] $AttachementFile) {
[string] $fileContentEncoded = $null
if (Test-Path $AttachementFile -PathType leaf) {
$fileContent = get-content $AttachementFile
$fileContentBytes = [System.Text.Encoding]::UTF8.GetBytes($fileContent)
$fileContentEncoded = [System.Convert]::ToBase64String($fileContentBytes)
$fileContentEncoded | set-content ((Get-Item -Path $AttachementFile).Name + ".b64")
}
else {
$fileContentEncoded = $null
Write-Host "File : $FileAttachment not exists,skipping and continue to add if any other
attachments uploaded"
}
return $fileContentEncoded
}
#endregion
Problem: [UPDATED]
Am getting below error after trying to upload single or multiple attachments
{"errors":[{"message":"Invalid type. Expected: array, given: string.","field":"attachments","help":"http://sendgrid.com/docs/API_Reference/Web_API_v3/Mail/errors.html#message.attachments"}]} .
Reference Links :
Send Grid API Documentation:
https://sendgrid.com/docs/API_Reference/api_v3.html
My advice is to consider not building the JSON as a text, first build a Powshell object that you convert to JSON with ConvertTo-Json.
Using this method, arrays will be correctly represented in JSON. don't forget to set the -DEPTH param.
attachments array[object] An array of objects in which you can specify any attachments you want to include.
So in your Powershell object attachments is going to be a #().
of objects with content, type, filename, disposition, conten_id properties.
I realized error details in depth in late . It was giving hint in JSON payload "attachments" field is showing as string rather than array object which it is fixed by adding #(#()) to attachmentjsonrequest in "$jsonrequest" variable .
In Short: "attachmentjsonrequest is an array object which needs to convert to JSON payload by using #()
Thanks for suggesting to use array object.
attachments = #(#($AttachmentsjsonRequest))

Modifying JSON file using data from CSV in PowerShell

I'm trying to modify some specific values in a .json file based on two columns in a .csv file. If the current value in the .json file is identical to the one in the left column, I want to change it to the one in the right column.
This is my first time with PowerShell though, so I'm struggling to figure out how to go about doing this. I feel like my solution is not only wrong, but is using a double for loop when it might not need to. Here's what I have so far.
$jsonData = Get-Content -Path $jsonFile | ConvertFrom-Json
$csvData = Get-Content -Path $csvFile | Select-Object -Skip 1 # Skipping the header
foreach ($jsonItem in $jsonData.'Placeable List') {
foreach ($csvRow in $csvData) {
$splitRow = $csvRow -split ","
$lCol = $splitRow[0]
$rCol = $splitRow[1]
$currentItem = $jsonItem.'value'.'Appearance'.'value'
if ($currentItem -eq $lCol) {
$currentItem -eq $rCol
}
}
}
I managed to figure it out.
$csvData = Get-Content -Path $csvFile | Select-Object -Skip 1 # Skipping the header
$jsonData = Get-Content -Path $jsonFile -raw | ConvertFrom-Json
foreach($csvRow in $csvData) {
$splitRow = $csvRow -split ","
$lCol = $splitRow[0]
$rCol = $splitRow[1]
foreach($item in $jsonData.'Placeable List'.value) {
$item.Appearance | % {
if ($_.value -eq $lCol) {
$_.value = $rCol
}
}
}
}
$jsonData | ConvertTo-Json -depth 32 | Set-Content $jsonFile

Importing a CDATA string literal from a JSON array into PowerShell

So I have a XML value extractor for a large rule database.
I stored the values in a Json file with sections for each file and then the values tied to their names.
However some of the values are a CDATA Snippet.
I can pull the CDATA as a string literal to store in the Json but I CANNOT seem to find a way to get power shell to let me put it back into the XML.
Cannot set "Value" because only strings can be used as values to set XmlNode properties.
At C:\Users\vagrant\Desktop\RuleSetter.ps1:24 char:21
+ $rule.value = $ruleFileSet. ($singleRuleXmlFile.directory.nam ...
+
+ CategoryInfo : NotSpecified: (:) [], SetValueException
+ FullyQualifiedErrorId : XmlNodeSetShouldBeAString`
The Getter looks like this
$directories = Get-ChildItem -dir -path C:\inetpub\wwwroot\
foreach($instName in $directories){
if($instName -notlike 'client' -and $instName -notlike 'bin'-and $instName -notlike 'aspnet_client'-and $instName -notlike 'AccessLibertyLogs'){
$obj = [hashtable]#{}
$head = [hashtable]#{Institution = $instName}
$obj.Add('head',$head)
$files = Get-ChildItem C:\inetpub\wwwroot\$instName\filepath -Include Rules.XML -Recurse
$files |
ForEach-Object {
[xml]$temp = Get-Content -path $_.FullName
[string]$title = $_.Directory.name
[hashtable]$output = #{}
foreach($rule in $temp.RuleCollection.Rules.Rule){
$t = ""
if($rule.value -isnot [string]){
$t = $rule.value.innerXml
}else{
$t = $rule.value
}
$output.Add($rule.name,$t)
}
$obj.Add($title,$output)
}
$transfer = New-Object -TypeName PSObject -Property $obj
$location = "C:\Users\vagrant\desktop\json\" + $instName + ".Json"
$transfer | ConvertTo-Json -Compress | Out-file -FilePath $location
}
}
And the Setter like this
Param(
[string]$location,
[string]$ruleConfigFileLocation)
$allInstConfigFiles = Get-ChildItem -Path C:\Users\vagrant\Desktop\json\
foreach($singleInstFile in $allInstConfigFiles) {
$instaName = $singleInstFile.BaseName
$allRuleXmlFileList = Get-ChildItem C:\inetpub\wwwroot\$instaName\Liberty \Applications\Origination\Configuration -Include Rules.XML -Recurse
ForEach($singleRuleXmlFile in $allRuleXmlFileList) {
[xml]$singleRuleXmlFileContents = Get-Content -path $singleRuleXmlFile.FullName
$singleInstFileContent = Get-Content $singleInstFile.FullName | ConvertFrom-Json
foreach($ruleFileSet in $singleInstFileContent){
foreach($rule in $singleRuleXmlFileContents.RuleCollection.Rules.Rule){
#write-host $ruleFileSet.($singleRuleXmlFile.directory.name).($rule.name)
if($ruleFileSet.($singleRuleXmlFile.directory.name).($rule.name) -as [xml])
{
$rule.value = $ruleFileSet.($singleRuleXmlFile.directory.name).($rule.name).OuterXml
write-host 'skipped'
}else{
write-host 'not skipped'
$rule.value = $ruleFileSet.($singleRuleXmlFile.directory.name).($rule.name)
}
}
}
}
}

Issue in export Array to CSV file

I have list of machine in text file and I am trying to get the details of physical drives, OS architecture and physical memory. With the help of Matt (SO user) here is the powershell script.
$server = Get-Content .\Server.txt
#$infoObject11 = #{}
$infoObject11 = #{}
foreach ($server in $servers) {
# Gather all wmi drives query at once
$alldisksInfo = Get-WmiObject -Query "SELECT * FROM Win32_DiskDrive" -ComputerName $server -ErrorAction SilentlyContinue | Group-Object __Server
# Figure out the maximum number of disks
$MaximumDrives = $alldisksInfo | Measure-Object -Property Count -Maximum | Select-Object -ExpandProperty Maximum
# Build the objects, making empty properties for the drives that dont exist for each server where need be.
$server | ForEach-Object {
# Clean the hashtable
$infoObject1 = #{}
# Populate Server
$infoObject1.Server = $server
$HOSTNAME = Get-WMIObject -Query "Select * from Win32_OperatingSystem" -ComputerName $infoObject1.Server
# Add other simple properties here
$infoObject1.PhysicalMemory = (Get-WmiObject Win32_PhysicalMemory -ComputerName $infoObject1.Server | Measure-Object Capacity -Sum).Sum/1gb
$infoObject1.OSarchitecture =$HOSTNAME.osarchitecture
# Add the disks information from the $diskInfo Array
$serverDisksWMI = $alldisksInfo | Where-Object{$_.Name -eq $infoObject1.Server} | Select-Object -ExpandProperty Group
for ($diskIndex =0; $diskIndex -lt $MaximumDrives;$diskIndex++) {
$infoObject1."PhysicalDisk$diskIndex" = [Math]::Round(($serverDisksWMI | Where-Object{($_.DeviceID -replace "^\D*") -eq $diskIndex} | Select -Expand Size)/1GB)
}
}
# Create the custom object now.
New-Object -TypeName psobject -Property $infoObject1 | Export-Csv -path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
}
Problem is in the CSV file I am getting single machine details but in server.txt file there are more than 1 machine. If I print $infoObject1 before New-Object then I can see there are details of multiple machine. It seems like some issue with array and I am not able to export it in CSV.
Can anybody please suggest on this.
It looks like you are having issues integrating my code. You have added a second loop that should not be there. Also as other users pointed out you are not creating the per server object outside the loop. The answer, from where your code comes from, has that part correct. I had even showed you where to put the Export-CSV.
$servers = Get-Content .\Server.txt
# Gather all wmi drives query at once
$alldisksInfo = Get-WmiObject -Query "SELECT * FROM Win32_DiskDrive" -ComputerName $servers -ErrorAction SilentlyContinue | Group-Object __Server
# Figure out the maximum number of disks
$MaximumDrives = $alldisksInfo | Measure-Object -Property Count -Maximum | Select-Object -ExpandProperty Maximum
# Build the objects, making empty properties for the drives that dont exist for each server where need be.
$servers | ForEach-Object {
# Clean the hashtable
$infoObject1 = #{}
# Populate Server
$infoObject1.Server = $_
# Add other simple properties here
$infoObject1.PhysicalMemory = (Get-WmiObject Win32_PhysicalMemory -ComputerName $infoObject1.Server | Measure-Object Capacity -Sum | Select-Object -ExpandProperty Sum)/1GB
$infoObject1.OSarchitecture = Get-WMIObject -Query "Select * from Win32_OperatingSystem" -ComputerName $infoObject1.Server | Select-Object -ExpandProperty OSArchitecture
# Add the disks information from the $diskInfo Array
$serverDisksWMI = $alldisksInfo | Where-Object{$_.Name -eq $infoObject1.Server} | Select-Object -ExpandProperty Group
for ($diskIndex =0; $diskIndex -lt $MaximumDrives;$diskIndex++) {
$infoObject1."PhysicalDisk$diskIndex" = [Math]::Round(($serverDisksWMI | Where-Object{($_.DeviceID -replace "^\D*") -eq $diskIndex} | Select-Object -ExpandProperty Size)/1GB)
}
# Create the custom object now for this pass in the loop.
New-Object -TypeName psobject -Property $infoObject1
} | Export-Csv -path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
foreach ($server in $servers) {
...
New-Object -TypeName PSObject -Property $infoObject1 |
Export-Csv -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
}
You're exporting inside the loop without using the parameter -Append (available in PowerShell v3 and newer). That overwrites your output file with each iteration, leaving you with just the data of the last server.
Either use the parameter -Append (if you have PowerShell v3 or newer):
foreach ($server in $servers) {
...
New-Object -TypeName PSObject -Property $infoObject1 |
Export-Csv -Append -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
}
or move Export-Csv outside the loop (works with all PowerShell versions):
(foreach ($server in $servers) {
...
New-Object -TypeName PSObject -Property $infoObject1
}) | Export-Csv -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation
Note that you need to run the loop in parentheses for this to work, as foreach loops don't output to the pipeline.
You could also replace the foreach loop with ForEach-Object if you want to feed the pipeline directly:
Get-Content .\Server.txt | ForEach-Object {
$server = $_
...
New-Object -TypeName PSObject -Property $infoObject1
} | Export-Csv -Path .\Server_Inventory_$((Get-Date).ToString('MM-dd-yyyy')).csv -NoTypeInformation