Handling hash tables in custom objects - powershell

Our monitoring system has a REST API that I am trying to retrieve properties from, then output them to a custom object. A couple of the property values are hash tables.
In addition to keeping the custom objects for use in Powershell, I would like to export them to CSV, so I need those hash tables to be something else, so I don't end up with Syste.Object[] in those columns.
The object returned from the API looks like this (truncated):
$allServices[0]
alertStatus : none
ignoreSSL : True
description : Test service
stopMonitoring : False
stopMonitoringByFolder : False
useDefaultLocationSetting : False
serviceProperties : {}
transition : 1
alertStatusPriority : 100000
serviceFolderId : 1
script :
disableAlerting : False
individualAlertLevel : warn
checkpoints : {#{id=1; geoInfo=Overall; smgId=0}, #{id=2; geoInfo=US - Los Angeles; smgId=1}, #{id=3; geoInfo=US - Washington DC; smgId=2}, #{id=4; geoInfo=US - San Francisco; smgId=3}...}
pageLoadAlertTimeInMS : 30000
sdtStatus : none-none-none
serviceStatus : alive
method : tabledriven
id : 1
Then checkpoints looks like this:
$allServices[0].checkpoints
id geoInfo smgId
-- ------- -----
1 Overall 0
2 US - Los Angeles 1
3 US - Washington DC 2
4 US - San Francisco 3
5 Europe - Dublin 4
6 Asia - Singapore 5
What is the best way to deal with the checkpoints property?
Thanks.

Convert checkpoints (and possibly serviceProperties) to a JSON string.
$allServicesCSV = foreach ($srv in $allServices) {
$srv = $srv.PSObject.Copy() # shallow copy
$srv.checkpoints = ConvertTo-Json $srv.checkpoints -Compress
$srv
}

Well, the requirements changed, so I only need to output to json/XML and not to CSV, making this much easier. Thanks.

Related

Powershell script : Service now

I have got the response from the service now api
enter code here
$geturl = $ParentURL + "/table/sc_req_item?
sysparm_query=number="+$RITMNumber+"&sysparm_display_value=all&sysparm_fields=number,short_description,requested_for.first_name,requested_for.last_name,requested_for.user_name"
number : #{display_value=RITM2519394; value=RITMXXXX}
short_description : #{display_value=Login As ABC xyz on 19 Feb. Creating ticket for tracking purposes.; value=Login As ABC xyz on 19 Feb. Creating ticket for tracking purposes.}
requested_for.first_name : #{display_value=abc; value=abc}
requested_for.user_name : #{display_value=Exxxx; value=Exxxx}
requested_for.last_name : #{display_value=xyz; value=xyz}
I am able to display get the short description using $ShortDescription = $($response.result.short_description.value)
Login As ABC xyz on 19 Feb. Creating ticket for tracking purposes.
But when I m trying to get the requested for first name and last name I m getting blank
$RequestFor = $($response.result.requested_for.first_name)
could you please help me in sorting out

Read in a *HUGE* CSV file, export specific columns based on column name in header, output comma delimited data

So, I know I can read in a csv file using import-csv like so:
$test = import-csv BPUSAUV20FARS-1000.csv
I found another stack overflow question which gave me some code to decipher column names, like so:
$columns = $test[0].psobject.properties.name
I found a reddit post that helped me find a way to extract multiple columns using select-object like so:
$properties = #('Index', 'Year', 'Day', 'Time', 'Line', 'Beam', 'Pos TPU', 'Depth TPU', 'Status')
$test |Select-Object $properties
But the output from the above command likes like this:
Index : 1
Year : EM2040-0073-1000-20200224-222235
Day : 25
Time : Accept
Line : 0.648
Beam : 24-FEB-2020:22:22:34.98
Pos TPU : 4.617
Depth TPU : 1124834.70
Status : 10247261.01
Index : 2
Year : EM2040-0073-1000-20200224-222235
Day : 26
Time : Accept
Line : 0.749
Beam : 24-FEB-2020:22:22:34.98
Pos TPU : 4.617
Depth TPU : 1124834.73
Status : 10247261.76
Index : 3
Year : EM2040-0073-1000-20200224-222235
Day : 27
Time : Accept
Line : 0.624
Beam : 24-FEB-2020:22:22:34.98
Pos TPU : 4.617
Depth TPU : 1124834.76
Status : 10247263.05
And what I need is this:
1,EM2040-0073-1000-20200224-222235,25,Accept,0.648,24-FEB-2020:22:22:34.98,4.617,1124834.70,10247261.01
I also need to be able to perform these actions on a few hundred files with several million lines each. The smallest file is about 2.4 million lines.
As for...
I also need to be able to perform these actions on a few hundred files
with several million lines each. The smallest file is about 2.4
million lines.
... dealing with large files in general --- (too long for just a comment)
As per MSDN
[IO.File]::OpenText and as noted in another Q&A
The Get-Content cmdlet does not perform as well as a StreamReader when
dealing with very large files. You can read a file line by line using
a StreamReader like this:
$path = 'C:\A-Very-Large-File.txt'
$r = [IO.File]::OpenText($path)
while ($r.Peek() -ge 0) {
$line = $r.ReadLine()
# Process $line here...
}
$r.Dispose()
Some performance comparisons:
Measure-Command {Get-Content .\512MB.txt > $null}
Total Seconds: 49.4742533
Measure-Command {
$r = [IO.File]::OpenText('512MB.txt')
while ($r.Peek() -ge 0) {
$r.ReadLine() > $null
}
$r.Dispose()
}
Total Seconds: 27.666803

print strings and variables in powershell for loop

I need to extract an alerts from rest api and sent it to a file with powershell
I was able to extract the alerts outputs looping the xml file:
foreach ($c in $temp){$c.timeOfAlertFormatted,$c.parent,$c.child,$c.category,$c.servicePlanDisplayName,$c.message}
Thu 09/19/2019 12:00:19 AM
IL
Servername
Phase Failure
Gold
One or more source luns do not have a remote target specified/mapped.
Wed 09/18/2019 02:18:25 PM
IL
Server2
Phase Failure
Gold
One or more source luns do not have a remote target specified/mapped
I am new to PS , what i want to achieve is to add descriptive string
to each filed, i.e:
Time: Thu 09/19/2019 12:00:19 AM
Country: IL
Server: servername
etc ,the rest of the fields.
i tried :
foreach ($c in $temp){Write-Host "Time : $($c.timeOfAlertFormatted)"}
Time :
Time :
Time :
Time :
Time :
Time :
Time :
Time :
Time :
Time :
Time :
Time :
Time : Thu 09/19/2019 12:00:19 AM
its printing empty "Time" fields
here is example of the xml:
It looks like you have already loaded the xml and filtered out the properties you need in a variable $temp.
I think what you want can be achieved by doing:
$temp | Select-Object #{Name = 'Time'; Expression = {$_.timeOfAlertFormatted}},
#{Name = 'Country'; Expression = {$_.parent}},
#{Name = 'ServerName'; Expression = {$_.child}},
Category,ServicePlanDisplayName, Message
The above should output something like
Time : Thu 09/19/2019 12:00:19 AM
Country : IL
ServerName : Servername
Category : Phase Failure
ServicePlanDisplayName : Gold
Message : One or more source luns do not have a remote target specified/mapped.
Time : Wed 09/18/2019 02:18:25 PM
Country : IL
ServerName : Server2
Category : General Failure
ServicePlanDisplayName : Gold
Message : One or more source luns do not have a remote target specified/mapped.
If your variable $temp is NOT what I suspect it to be, please edit your question and show us the XML aswell as the code you use to extract the alerts from it.

powershell listing Ram information

I am trying to find out what type of RAM is in a computer. I'd like to know whether the modules are UDIMM, RDIMM, LRDIMM or any other type. This would be very useful so I can plan what modules are going into what servers at the data center.
This is what I have so far:
Get-WmiObject Win32_PhysicalMemory |
Select-Object PSComputerName, DeviceLocator, Manufacturer, PartNumber,
#{ label = "Size/GB"; expression = { $_.Capacity / 1GB } },
Speed, Datawidth, TotalWidth |
Format-Table -AutoSize
This is useful information but I'd like a column that tells me the type (UDIMM, RDIMM, LRDIMM) and a way to list the DIMMS that are empty as it will make it easier to see what DIMM is full/empty (but this isn't a huge problem).
this is not a duplicate as i am looking for the type of Ram that is stored on the servers so i know what Ram to buy and put in without having to travel a long way to find out i got the wrong type
The Win32_PhysicalMemory class documentation contains a reference for translating the MemoryType value to the type of memory module. Turn it into a hashtable for easy access:
$MemoryTypeMap = #{
"0" = 'Unknown'
"1" = 'Other'
"2" = 'DRAM'
"3" = 'Synchronous DRAM'
"4" = 'Cache DRAM'
"5" = 'EDO'
"6" = 'EDRAM'
"7" = 'VRAM'
"8" = 'SRAM'
"9" = 'RAM'
"10" = 'ROM'
"11" = 'Flash'
"12" = 'EEPROM'
"13" = 'FEPROM'
"14" = 'EPROM'
"15" = 'CDRAM'
"16" = '3DRAM'
"17" = 'SDRAM'
"18" = 'SGRAM'
"19" = 'RDRAM'
"20" = 'DDR'
"21" = 'DDR2'
"22" = 'DDR2 FB-DIMM'
"24" = 'DDR3'
"25" = 'FBD2'
}
Get-WmiObject Win32_PhysicalMemory |Select #{Label = 'Type';Expression = {$MemoryTypeMap["$($_.MemoryType)"]}}
You can see which memory devices are in which slots by using the WMI class of CIM_PhyicalMemoryArray and CIM_MemoryDeviceLocation. I've used WBEMTest and Get-CimInstance, however, and it doesn't seem that Windows reports on which memory slots are open on the motherboard.
My best guess? You'll need to use the Win32_Baseboard class to report on the model of the motherboard, and do some legwork manually to see how many slots each model has. You can then use the data from CIM_MemoryDeviceLocation to determine how many slots are open.
An approach to do so might look like this.
$memorySlots = Get-CimInstance Win32_MemoryDeviceLocation
$motherBoard = Get-CimInstance win32_baseboard
switch ($motherBoard.Product){
#find the motherboard models for the most common models and populate manually w/ count of ram slots
"0TM99H" {$Totalslots = 2}
Default {$Totalslots = 4}
}
Get-WmiObject Win32_PhysicalMemory |
Select-Object PSComputerName, DeviceLocator, Manufacturer, PartNumber,
#{ label = "Size/GB"; expression = { $_.Capacity / 1GB } },
Speed, Datawidth, TotalWidth, #{ label ="FreeSlots";exp={$Totalslots-$memorySlots.Count}}
It would look something like this:
PSComputerName : SLVER
DeviceLocator : DIMM A
Manufacturer : Elpida
PartNumber : 8KTS51264HDZ-1G6E1
Size/GB : 4
Speed : 1600
Datawidth : 64
TotalWidth : 64
FreeSlots : 0
PSComputerName : SLVER
DeviceLocator : DIMM B
Manufacturer : Elpida
PartNumber : 8KTS51264HDZ-1G6E1
Size/GB : 4
Speed : 1600
Datawidth : 64
TotalWidth : 64
FreeSlots : 0
Finally, you asked about memory type present, that also doesn't seem to be info that we know of, from a WMI perspective. Or rather, if WMI does know about it, I couldn't find it anywhere.
I think you'll need to do some manual work too there, gathering the memory part number, then manually research to determine what type of RAM it is, then finally add that info to the output by adding another Switch statement, as shown.
switch ($memorySpecs.PartNumber){
"8KTS51264HDZ-1G6E1" {$RAMType='SoDimm'}
Default {$RAMType="Unknown, research $($memorySpecs.PartNumber)"}
}
Update
Mathias provided an excellent method to look up RAM if the BIOS on that PC reports it to Windows. I've tested on a few systems, some report their RAM Type while others don't. For those that don't, you can reference the partNumber property as I've demoed above to manually look it up. After a few iterations, you should be able to gather the data and program your own exceptions, and wrap up this task.

How to display matlab content into columns using fprintf

I'm looking to display data in two columns. The first column will have a movies name and the second a rating out of 5. I want the data to be displayed in such a way that the ratings, regardless of the length of the movie title all display in on vertical line. I currently have:
Toy Story (1995) : 4
GoldenEye (1995) : 3
Seven (Se7en) (1995) : 4
Braveheart (1995) : 1
Bad Boys (1995) : 3
Batman Forever (1995) : 2
Star Wars (1977) : 5
Shawshank Redemption, The (1994) : 5
Ace Ventura: Pet Detective (1994) : 3
Aladdin (1992) : 3
I'm using the following code:
fprintf('%s : \t %d\n', movieList{i},user_ratings(i));
where the above line is obviously in a loop. I tried using a tab to see if things would line up but clearly not much luck. Any ideas on how I could achieve this?
If you would like to keep things simple and your loop, you may try this -
lens = cellfun(#numel,movieList);
pdlens = max(lens) - lens;
for k = 1:numel(movieList)
fprintf('%s%s :\t%d\n', movieList{k},repmat(' ',1,pdlens(k)),user_ratings(k))
end
Output -
Toy Story (1995) : 4
GoldenEye (1995) : 3
Seven (Se7en) (1995) : 4
Braveheart (1995) : 1
Bad Boys (1995) : 3
Batman Forever (1995) : 2
Star Wars (1977) : 5
Shawshank Redemption, The (1994) : 5
Ace Ventura: Pet Detective (1994) : 3
Aladdin (1992) : 3
Alternate solution based on arrayfun -
spc = repmat(' ',numel(movieList),1)
pdc = arrayfun(#(x,t) repmat(x,1,t),spc,pdlens,'uni',0) %//pdlens is from earlier code
spcell = repmat(cellstr({' '}),numel(movieList),1)
out = strcat(movieList,pdc,':',spcell,num2str(user_ratings')) %//'
char(out) %// Display the text
You can try this, it really not beautifull but :
maxVal = 0
[~,nbMovie] = size(movieList);
for i = 1:nbMovie
maxVal = max(maxVal,length(movieList{i}))
end
wordPrint = strcat('%',int2str(maxVal),'s');
totalPrint = strcat(wordPrint,' : %f\n');
for i = 1:nbMovie
fprintf(totalPrint ,movieList{i},user_ratings(i));
end
EDIT
And for a left align for the word use the symbol '-' before the number, like this :
wordPrint = strcat('%-',int2str(maxVal),'s');