Pass values in different lines to different variables in Powershell - powershell

I have a text file (file1.txt) with records in different lines
Variable1,2018
Variable2,Jun
Now in my script I would like to store the values in different variables.
Example, I would like my end result to be
Year=2018
Period=Jun
I tried the below logic but it is not solving the purpose as it is storing both values in a single variable.
Get-Content "file1.txt" | ForEach-Object {
$Var=$_.split(",")
$Year=$Var[1]
$Period=$Var[1]
}
Please help.

You can do Something like this, if you want use variable :
$Object=(Get-Content C:\Temp\test.txt).Replace(',', '=') | ConvertFrom-StringData
$Object.Variable1
$Object.Variable2

You could do it using a hash like so:
$h = #{}
Get-Content "file1.txt" | % {
$var = $_.split(",")
$h[$var[0]] = $var[1]
}
$h['Variable1']
Or you could use an object like this:
$o = New-Object psobject
Get-Content "file1.txt" | % {
$var = $_.split(",")
$o | Add-Member -MemberType NoteProperty -Name $var[0] -Value $var[1]
$h[$var[0]] = $var[1]
}
$o.Variable1

Why not use the new-variable cmdlet?
#get content from your file instead
$str = "Variable1,2018","Variable2,Jun"
foreach ($line in $str)
{
$line = $line.split(",")
New-Variable -name $line[0] -Value $line[1]
}

Related

Get VID PID from Device ID in Powershell

I am fairly new to PowerShell and I want for a USB key plugged, to retrieve some info. Right now my script is:
Get-WmiObject win32_diskdrive |
ForEach-Object{
$disk = $_
$_.GetRelated('Win32_PnPEntity')|
ForEach-Object{
$pnp = $_
$_.GetRelated('Win32_USBController') |
ForEach-Object{
$usb = $_
[pscustomobject]#{
SerialNumber = $disk.SerialNumber
Model = $disk.Model
Size = $disk.Size
if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {VID=$matches['vid']; PID=$matches['pid']}
}
}
}
}
The line beginning with
if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {VID=$matches['vid']; PID=$matches['pid']}
does not work. I want to translate deviceid (which I can get by doing USBDeviceID = $usb.DeviceID) ID in PID UID directly.
It throws the following error
Error with code “Missing = operator after key in hash literal" for the statement "if ($usb.DeviceID -match '.* ...
What am I missing ? many thanks for helping me .
Gerald
This is because the way you intend to add properties to the PsCustomObject is wrong.
Either do this:
$result = [PsCustomObject]#{
SerialNumber = $disk.SerialNumber
Model = $disk.Model
Size = $disk.Size
}
# add items to the object if the condition is true
if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {
$result | Add-Member -MemberType NoteProperty -Name 'VID' -Value $matches['vid']
$result | Add-Member -MemberType NoteProperty -Name 'PID' -Value $matches['pid']
}
# output the PsCustomObject
$result
or use a Hashtable as temporary storage:
# create a Hastable to temporarily store results in
$hash = [ordered]#{
SerialNumber = $disk.SerialNumber
Model = $disk.Model
Size = $disk.Size
}
# add items to the hash if the condition is true
if ($usb.DeviceID -match '.*VID_(?<vid>[0-9A-F]{4})&PID_(?<pid>[0-9A-F]{4}).*') {
$hash['VID']=$matches['vid']
$hash['PID']=$matches['pid']
}
# next cast to PsCustomObject and output
[PsCustomObject]$hash

How would I store my search results into a table using a foreach loop in powershell?

Import-Module <JAMS>
$JAMSHistories = Get-JAMSHistory -Server TESTDUMMY2 -StartDate "01/20/2020" -EndDate "01/24/2020"
$historyTable = #()
foreach($JAMSHistory in $JAMSHistories)
{
$row = New-Object -TypeName PSObject
Write-Host $JAMSHistory.FinalSeverity
if($JAMSHistory.FinalSeverity -match 'Success')
{
$row | Add-Member -NotePropertyName JobSeveritySuccess ($JAMSHistory.FinalSeverity)
}
else {
if ($JAMSHistory.FinalSeverity -match 'Error') {
$row | Add-Member -NotePropertyName JobSeverityError ($JAMSHistory.FinalSeverity) }
} $historyTable += $row
}
$historyTable
You can do the following, which will output an array of objects ($historyTable) with a properties called JobSeveritySuccess and JobSeverityError.
$JAMSHistories = Get-JAMSHistory -Server TESTDUMMY2 -StartDate "01/20/2020" -EndDate "01/24/2020"
$historyTable = foreach ($JAMSHistory in $JAMSHistories) {
$row = "" | Select JobSeveritySuccess,JobSeverityError
if ($JAMSHistory.FinalSeverity -match 'Success') {
$row.JobSeveritySuccess = $JAMSHistory.FinalSeverity
}
elseif ($JAMSHistory.FinalSeverity -match 'Error') {
$row.JobSeverityError = $JAMSHistory.FinalSeverity
}
$row
}
# Output
$historyTable
# Output in Table Format
$historyTable | Format-Table
The problem with this approach is that every object will have JobSeveritySuccess and JobSeverityError properties, and they may be empty. The only time both properties will have data is if $JAMSHistory.FinalSeverity contains Error and Success for the same object. There is probably a better way to do your design if provided more requirements.
When doing this type of exercise, there are always some gotchas. Consider creating a new PSObject or PSCustomObject for loop iteration. Then output that object at the end of the loop code. When collecting the foreach loop output, just set a variable equal to the foreach loop. There's rarely a need to use += to build an array of foreach loop output. There could be some exceptions to this, but most of the time they are good things to consider.

Powershell - Exporting Non-string Multivalued Properties

I have the following to dynamically expand properties of objects I feed into the function, but ToString() is often spitting out the property types instead:
Function ExpandMultivaluedProperties
{
Param(
[PSObject]$InputObject
)
$results= $InputObject |
ForEach-Object {
$properties = New-Object PSObject
$_.PSObject.Properties |
ForEach-Object {
$propertyName = $_.Name
$propertyValue = $_.Value
If ($propertyValue -NE $NULL) {
$values = #()
ForEach ($value In $propertyValue) {
$values += $value.ToString()
}
Add-Member -inputObject $properties NoteProperty -name $propertyName -value "$([String]::Join(";",$values))"
} Else {
Add-Member -inputObject $properties NoteProperty -name $propertyName -value $NULL
}
}
$properties
}
return $results
}
ExpandMultivaluedProperties -InputObject (Get-ExchangeCertificate) | Export-CSV -path "Cert.csv" -NoTypeInformation
In particular with the results of Get-ExchangeCertificate, what I end up with is
System.Security.Cryptography.X509Certificates.X500DistinguishedName
as the IssuerName for each certificate.
The code works fine for any string-friendly properties, but I'm aiming for it to be robust enough to handle any property that would normally show up correctly with a | Format-List
Any thoughts on how to print/expand similar properties programmatically without having to use a "Select" expression?
In a string context, the instances of many types default to simply printing their type name - e.g., System.Security.Cryptography.X509Certificates.X500DistinguishedName - which is often not helpful.
However, you can use Out-String instead, which applies PowerShell's default output formatting (the same output format you'd see in the console):
$values += Out-String -InputObject $value
One caveat is that the resulting strings often have leading or trailing empty lines. You can remove leading and/or trailing empty lines with the following variation:
$values += (Out-String -InputObject $value).Trim()
Caveats:
The default width of the output lines for non-string data is based on the PowerShell host, and defaults to the width of the window buffer in the regular console minus 1 (excluding the line break); i.e., 79 in with the default console window size.
Use -Width to specify an output line width (excluding the line break) explicitly.
Longer lines are truncated, i.e., the information is lost.
Note that [string] values are not affected - they are output as-is.
Conversely, if the output is in table format (implicit use of Format-Table), shorter lines are right-padded with spaces to the implied or specified width.
Given that lines can be padded, you shouldn't use something like Out-String -Width ([int]::MaxValue]) to prevent truncation (in fact, you may run out of memory).
Instead, use a reasonably high value such as -Width 255, as #Abraxas000 did in his own answer.
If you wanted to condense the typically multi-line output to a one-liner, use something like the the following, though :
$values += ($value | Out-String).Trim() -replace '\s*\r?\n', '; ' -replace '\s+', ' '
;  was chosen to replace the line breaks here, and line-internal runs of whitespace are normalized to a single space each - whether the results are still readable probably both depends on the specific output format and the eye of the beholder.
To give a concrete example:
> $ht = #{ one = 1; two = 2; three = 3 } # sample hashtable
> $val = "$ht"; "ht: $val" # hashtable is stringified -> type name only
ht: System.Collections.Hashtable
> $val = Out-String -InputObject $ht; "ht: $val" # Out-String creates meaningful representation
ht:
Name Value
---- -----
one 1
two 2
three 3
> ($ht | Out-String).Trim() -replace '\s*\r?\n', '; ' -replace '\s+', ' '
Name Value; ---- -----; one 1; two 2; three 3
#mklement0 Gave me an answer that lead me as close to ideal as I have time for, so go up-vote it!
My code as of posting this:
Function ExpandMultivaluedProperties
{
Param(
[PSObject]$InputObject
)
$results= $InputObject |
ForEach-Object {
$properties = New-Object PSObject
$_.PSObject.Properties |
ForEach-Object {
$propertyName = $_.Name
$propertyValue = $_.Value
If ($propertyValue -NE $NULL) {
$values = #()
ForEach ($value In $propertyValue) {
if (($value.ToString()).StartsWith("System."))
{
$values += (Out-String -InputObject $value -Width 255).Trim()
}
else
{
$values += $value.ToString()
}
}
Add-Member -inputObject $properties NoteProperty -name $propertyName -value "$([String]::Join(";",$values))"
} Else {
Add-Member -inputObject $properties NoteProperty -name $propertyName -value $NULL
}
}
$properties
}
return $results
}
This gives me the one-line value I expect to see for the simpler properties while properly expanding the complex properties.
Even if the property is simple and the value starts with "System.", the data will still be present, just not in the simpler, one-liner format I prefer for CSVs.
Thanks again, #mklement0!

How to get powershell object properties in the same order that format-list does?

I'm writing some reporting scripts in Powershell and collecting up a summary table of items as a blank object with additional properties added one by one:
$cmClusters = #()
foreach ($Cluster in Clusters) {
$cmCluster = New-Object System.Object
$cmCluster | Add-Member -type NoteProperty -Name VC -Value $strVC
$cmCluster | Add-Member -type NoteProperty -Name Name -Value $Cluster.name
# etc...
$cmClusters += $cmCluster;
}
If I just dump $cmClusters at the end of this, I get a format-list output with the properties in the order that I added them.
However, I was hoping to write a generic "dump this collection of objects to an excel tab" function to produce my report, which will be several similar worksheet tabs from different lists of objects.
That looks like this:
function DumpToExcel($workbook, $tabTitle, $list)
{
$sheet = $workbook.worksheets.add()
$sheet.Name = $tabTitle
$col = 1
$row = 1
$fields = $list[0] | Get-Member -MemberType NoteProperty | Select-Object *
Foreach ($field in $fields) {
$sheet.cells.item($row,$col++) = $field.Name
}
$heading = $sheet.UsedRange
$heading.Font.Bold = $True
$row++
Foreach ($cmCluster in $list) {
$col=1
Foreach ($field in $fields) {
$sheet.cells.item($row,$col++) = $cmCluster.($field.Name)
}
$row++
}
$sheet.UsedRange.EntireColumn.AutoFit() | Out-Null
}
which works, but the property names are now in alphabetical order.
What can I use to get my list of properties in the same order that Format-List does?
Try this:
$fields = $list[0].psobject.properties | select name

Format display in powershell

I have a csv file with the following information:
OS Name: Microsoft© Windows Server© 2008 Standard
OS Version: 6.0.6002 Service Pack 2 Build 6002
System Manufacturer: IBM
System Model: IBM 3850 M2 / x3950 M2 -[7233Z1H]-
I need to use powrshell to read and format the display.. My existing code is this:
$Array = #()
Get-Content <txtfilename> | foreach {
$Test = $_
$Title = $Test.split(":")[0]
$Content = $Test.split(":")[1]
$Obj = New-Object System.Object
$Obj | Add-Member -MemberType NoteProperty -value $Title -Name Title
$Obj | Add-Member -MemberType NoteProperty -value $Content -Name Value
$Array += $Obj
}
$Array | Select Title,Value | Export-Csv <csvfilename> -NoTypeInformation
It displays the information as follows listed:
Title Content
OS Name Microsoft? Windows Server? 2008 Standard
OS Version 6.0.6002 Service Pack 2 Build 6002
System Manufacturer IBM
System Model IBM 3850 M2 / x3950 M2 -[7233Z1H]-
I need the information displayed in a single line like this:
ServerName, OS Name , OS Version, System Manufacture, Sytem model,
TestServer1, Microsoft Windows, 6.0.6002 Service Pack 2, IBM, IBM 3850
Thanks
Here's a second answer for the more advanced case, where you don't know how many unique headers you have or what they're called. As long as they're consistently the same and in the same order, the following will work:
$filePath = "C:\users\chris\desktop\info.txt"
$headers = #()
[int]$headerCount = 0
$endUnique = $false
Get-Content $filePath | % {
$header = ($_.split(':')[0] -replace '\s+', ' ').Trim()
if (($headers -notcontains $header) -and (!$endUnique)){
$headers += $header
$headerCount += 1
}
else{
$endUnique = $true
}
}
$headerRow = ""
$headers | % {$headerRow += $_ + ","}
$headerRow = $headerRow.Substring(0,$headerRow.Length-1)
[int]$i = 1
$outString = ""
Get-Content $filePath | % {
$lineContent = ($_.split(':')[1] -replace '\s+', ' ').Trim()
if ($i -lt $headerCount){
$outstring += $linecontent + ','
$i += 1
}
else{
$outstring += $linecontent + "`r`n"
$i = 1
}
}
$outstring = $headerRow+ "`r`n"+$outstring
I'd like to see the other answers from more advanced PowerShell users.
First, just a quick correction. You say you have a CSV. It looks like you have a formatted text file and you want to make a CSV out of it.
Following that assumption, something like this should get you started. It assumes that the text document has either only those 4 items in it, or those 4 items are repeated multiple times - always in the same order, and without a space in between them. Reformatting text files is never fun without a bunch of examples of how they could look.
That being said, the following should get you started.
[int]$i = 1
$outString = ""
Get-Content C:\users\chris\desktop\info.txt | % {
#Take the line, remove the title, remove whitespaces from inside of the line and trim whitespaces from the outside.
$lineContent = ($_.split(':')[1] -replace '\s+', ' ').Trim()
#Chunk them together...
if ($i -lt 4){
$outstring += $linecontent + ','
$i += 1
}
#or insert a return, new line
else{
$outstring += $linecontent + "`r`n"
$i = 1
}
}
#Add a header row. Now $outstring is your CSV formatted text.
$outstring = "OSName,OSVersion,SystemMfg,SystemModel`r`n"+$outstring
$object = New-Object System.Object
Get-Content TestServer1-OSInfo.txt | % {
If($_.Contains(":")){
$Left = $_.split(":")[0].TrimStart().TrimEnd()
$Right = $_.split(":")[1].TrimStart().TrimEnd()
$object | Add-Member -type NoteProperty -name $Left -value $Right
}
}
$object | Export-Csv TestServer1-OSInfo.csv -NoTypeInformation