PowerShell nested property iteration - powershell

Looking for some input on the scripts below. Essentially I'm retrieving some json data with Invoke-WebRequest. I needed to export many of the properties to CSV. The data returned from Invoke-WebRequest is contained in an array: $devicedetails. This script works for outputting to CSV.
& {
Foreach ($PC in $DeviceDetails)
{
Foreach ($AppName in $PC.categories)
{
ForEach ($App in $AppName.apps)
{
ForEach($Status in $App.health_status)
{
[pscustomobject] #{
"Device ID" = $PC.device_id
"Device Type" = $PC.device_type
"Device Name" = $PC.device_name
Nickname = $PC.nick_name
Last_Seen = $PC.last_seen
Compliance_Category_Status = $Appname.issue
Compliance_Category = $Appname.category_id
Product_Name = $App.name
Product_Vendor = $App.vendor
Product_Version = $App.version
Product_Health_Item = $Status.status
Product_Health_Status = $Status.issue
}
}
}
}
}
} | Export-CSV -PAth $Outfile -NoTypeInformation
Curious if this is the best way to output properties to CSV. Additionally, I now have the need to do some additional processes on the custom object I'm creating but if I assign a variable to that custom object as shown below, it takes several minutes to complete whereas just exporting to CSV takes 12-13 seconds. Why is the performance so bad?
$DeviceOutput= #()
Foreach ($PC in $DeviceDetails)
{
Foreach ($AppName in $PC.categories)
{
ForEach ($App in $AppName.apps)
{
ForEach($Status in $App.health_status)
{
$DeviceOutput += [pscustomobject] #{
"Device ID" = $PC.device_id
"Device Type" = $PC.device_type
"Device Name" = $PC.device_name
"Nickname" = $PC.nick_name
Compliance_Category_Status = $Appname.issue
Compliance_Category = $Appname.category_id
Product_Name = $App.name
Product_Vendor = $App.vendor
Product_Version = $App.version
Product_Health_Item = $Status.status
Product_Health_Status = $Status.issue
}
}
}
}
}

Related

JSON Nested Array to CSV

I have a Json file that I need to convert to CSV file using Powershell.
Can somebody please help me out?
The input file containing the Json data is called "data.json" and I would like the CSV output file to be called "dataout.csv"
Thanks for any help you can provide.
Cheers
As per comment:
If I understand your question correctly, you want to $usagetype for each $productName.lines and you want to do that for each $cloudaccount.lines...
This means that the foreach ( $usagetype in $productName.lines ) { ... loop should go inside the foreach ( $productName in $cloudaccount.lines ) { ... loop and the output [pscustomobject] #{ should go inside that inner loop: foreach ( $productName in $cloudaccount.lines ) { ...
In other words, if you need to read a JSON Nested Array, you will need to nest your loops. Thus:
$Data = $json | ConvertFrom-Json
$output = foreach ( $customer in $data ) {
$customerName = "$($customer.entity.company) ($($customer.entity.name))"
foreach ( $cloudAccount in $customer.lines ) {
$cloudAccountNumber = $cloudAccount.entity.id
# Continue to nest down to get out all colums data
foreach ( $productName in $cloudaccount.lines ) {
$cloudproductname = $productName.entity.id
foreach ( $usagetype in $productName.lines ) {
$cloudusagetype = $usagetype.entity.id
$cloudprice = $usagetype.data.price
$cloudcost = $usagetype.data.cost
$cloudusage = $usagetype.data.usage
# output the result
[pscustomobject] #{
"Customer Name" = $customerName
"Cloud Account Number" = $cloudAccountNumber
"Product Name" = $cloudproductname
"Usage Type" = $cloudusagetype
"Price" = $cloudprice
"Cost" = $cloudcost
"Usage" = $cloudusage
}
}
}
}
}
# Convert to csv
$output | Export-Csv -Path myfil.csv

How can I run compare content in a Variable against a hashtable on PowerShell

I have a hashtable as below:
$ProjectType = #{
CSharp = 'FAE04EC0-301F-11D3-BF4B-00C04F79EFBC'
Web_Application = '349C5851-65DF-11DA-9384-00065B846F21'
Windows_Communication_Foundation = '3D9AD99F-2412-4246-B90B-4EAA41C64699'
Windows_Presentation_Foundation = '60DC8134-EBA5-43B8-BCC9-BB4BC16C2548'
Test = '3AC096D0-A1C2-E12C-1390-A8335801FDAB'
Silverlight = 'A1591282-1198-4647-A2B1-27E5FF5F6F3B'
}
I want to run the hashtable against contents in a variable $file, and get a return of the projecttype name from the hashtable if the value (guid) is found in $file.
You most likely want to reverse the order of your Keys and Values on your Hash Table:
$ProjectType = #{
'FAE04EC0-301F-11D3-BF4B-00C04F79EFBC' = 'CSharp'
'349C5851-65DF-11DA-9384-00065B846F21' = 'Web_Application'
'3D9AD99F-2412-4246-B90B-4EAA41C64699' = 'Windows_Communication_Foundation'
'60DC8134-EBA5-43B8-BCC9-BB4BC16C2548' = 'Windows_Presentation_Foundation'
'3AC096D0-A1C2-E12C-1390-A8335801FDAB' = 'Test'
'A1591282-1198-4647-A2B1-27E5FF5F6F3B' = 'Silverlight'
}
# using this as example
$exampleFile = #'
349C5851-65DF-11DA-9384-00065B846F21
60DC8134-EBA5-43B8-BCC9-BB4BC16C2548
A1591282-1198-4647-A2B1-27E5FF5F6F3B
00000000-1198-4647-A2B1-27E5FF5F6F3B
'# -split '\r?\n'
foreach($line in $exampleFile)
{
if($val = $ProjectType[$line])
{
"$line => $val"
continue
}
"$line => could not be found on reference table."
}
Flip the keys and values around so that the reference GUIDs are the keys:
$ProjectType = #{
'FAE04EC0-301F-11D3-BF4B-00C04F79EFBC' = 'CSharp'
'349C5851-65DF-11DA-9384-00065B846F21' = 'Web_Application'
'3D9AD99F-2412-4246-B90B-4EAA41C64699' = 'Windows_Communication_Foundation'
'60DC8134-EBA5-43B8-BCC9-BB4BC16C2548' = 'Windows_Presentation_Foundation'
'3AC096D0-A1C2-E12C-1390-A8335801FDAB' = 'Test'
'A1591282-1198-4647-A2B1-27E5FF5F6F3B' = 'Silverlight'
}
Now you can easily look up any value:
$file = '3AC096D0-A1C2-E12C-1390-A8335801FDAB'
if($ProjectType.ContainsKey($file)){
Write-Host "Found project type guid for '$($ProjectType[$file])'"
}

How to iterate through an array of objects in Powershell

I'm doing some basic validation on form fields. What's the correct way to iterate through an array of objects to validate them? When I try the below I get
The property 'BackColor' cannot be found on this object. Verify that the property exists and can be set.
I guess what I'm missing is a way of telling Powershell these are references to other variables, rather than variables themselves.
$MandatoryFields = #(
'txtUsername',
'txtFirst',
'txtLast',
'txtEmail',
'ComboLicense'
)
ForEach ($Field in $MandatoryFields) {
If ([string]::IsNullOrWhitespace($Field.text)) {
$Validation = "failed"
$Field.BackColor = "red"
}
}
EDIT: Okay, what I needed was the actual variables in the array, like so:
$MandatoryFields = #(
$txtUsername,
$txtFirst,
$txtLast,
$txtEmail,
$ComboLicense
)
Try adding your objects to an array like below
$objects = [System.Collections.ArrayList]#()
$myObject = [PSCustomObject]#{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$objects.add($myObject)
$myObject1= [PSCustomObject]#{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$objects.add($myObject1)
foreach($obj in $objects){
$obj.firstname
}
I'm assuming your using System.Windows.Forms to create your form. If that's the case when adding controls you should assign a name to the control. Then you can loop through your controls and check if the control name matches your list of mandatory controls and then execute your check.
$MandatoryFields = #(
'txtUsername',
'txtFirst',
'txtLast',
'txtEmail',
'ComboLicense'
)
$Controls = MyForm.controls
ForEach ($c in $Controls) {
ForEach ($Field in $MandatoryFields) {
if ($c.Name -eq $Field) {
If ([string]::IsNullOrWhitespace($c.text)) {
$Validation = "failed"
$c.BackColor = "red"
}
}
}
}

Why datatype of psobject element is being lost?

I am trying to create resources such as volumes and volcoll on storage array and then after all operation is over they will be deleted . The setup creation will be done in queue order and deletion will be happening in stack order.
Below is my code
function Setup-ArrayResource
{
$Array = [pscustomobject]#{
Array = "ArrayV4"
UserName = "admin"
Password ="Password"
}
$Resources = [System.Collections.ArrayList]#()
$volumes = #([pscustomobject]#{Name ="Vol1"; size = 100gb },
[pscustomobject]#{Name ="Vol2"; size = 200gb }
)
$Resources.Add($volumes) | out-null
return [pscustomobject] #{
Array= $Array
Resources = $Resources
}
}
function TearDown-Resources
{
param(
$Setup
)
$Array = $Setup.Array
$Resources = $Setup.Resources
#$Resources
$REsources.Reverse()
foreach($r in $Resources)
{
"Deleting $R"
}
}
$SetupObj = Setup-ArrayResource
TearDown-Resources -Setup $SetupObj
The result is expected as below
Deleting {Name =vol2 size = 214748364800 }
Deleting {Name =vol1 size = 107374182400}
But nothing is getting displayed.
It simply displayed as Deleting
when i debug it, the ResourceQueue collection is no more collections.Arraylist. It is considered as psobject. Seems the datatype of ResourceQueue is getting lost when it is getting assigned to Setupobject.
Is this the designed behavior? If so How to get the resourcequeue and Groupconfig from Setup-Arrayresources without losing it's datatype?

How do I create an exclusion into query results?

Forgive me for I am relatively new to PowerShell. I have an issue were we need to log off all disconnected users with the exception of one ID. I found this script which does a great job logging off the disconnected users. My question is how would I modify this section to ignore one or more specified users from the query results?
function Get-Sessions
{
$queryResults = query session
$starters = New-Object psobject -Property #{"SessionName" = 0; "UserName" = 0; "ID" = 0; "State" = 0; "Type" = 0; "Device" = 0;}
foreach ($result in $queryResults)
{
try
{
if($result.trim().substring(0, $result.trim().indexof(" ")) -eq "SESSIONNAME")
{
$starters.UserName = $result.indexof("USERNAME");
$starters.ID = $result.indexof("ID");
$starters.State = $result.indexof("STATE");
$starters.Type = $result.indexof("TYPE");
$starters.Device = $result.indexof("DEVICE");
continue;
}
New-Object psobject -Property #{
"SessionName" = $result.trim().substring(0, $result.trim().indexof(" ")).trim(">");
"Username" = $result.Substring($starters.Username, $result.IndexOf(" ", $starters.Username) - $starters.Username);
"ID" = $result.Substring($result.IndexOf(" ", $starters.Username), $starters.ID - $result.IndexOf(" ", $starters.Username) + 2).trim();
"State" = $result.Substring($starters.State, $result.IndexOf(" ", $starters.State)-$starters.State).trim();
"Type" = $result.Substring($starters.Type, $starters.Device - $starters.Type).trim();
"Device" = $result.Substring($starters.Device).trim()
}
}
catch
{
$e = $_;
Write-Log "ERROR: " + $e.PSMessageDetails
}
}
}
Thank you for any input you may have.
So you want to omit certain results? You are using PowerShell objects so this should be easy with Where-Object
$omissions = "user1","user2"
foreach ($result in $queryResults)
{
# Stuff inside the loop
} | Where-Object{$omissions -notcontains $_.Username}
Tack on the where-object and we use -notcontains to see if a given user is not in the array of $omissions. Which is of course a list of users.
Caveat
You might have issues with the output of that foreach construct. I have seen this in PowerShell versions earlier than 3.0. If that does happen you could just capture the New-Objects into an array to later filter or use ForEach-Object.