Instantiate empty csv variable - powershell

I'm using methods to pick records from different csv files and I want to know how to create an empty variable that would act like a csv file. For Example...
an empty array would be $array = #()
an empty hash table would be $hashTable = #{}
a non-empty csv object would be $csvFileRecords = Import-Csv $someFileName
an empty csv object would be ????
What would the syntax be?

A "CSV object" is actually just an array (of psobjects).
$csvFileRecords = #()
To add new records to that array, you just need to add psobjects with appropriate attributes corresponding to the desired columns. One way to create a psobject with desired properties is from a hash table.
$obj = new-object psobject -property #{fname="Fiddle";lname="Freak"}
$csvFileRecords += $obj

Well, CSV's can't created from $null, but you could do something like this:
PS C:\> New-Object -TypeName System.Object | ConvertTo-Csv
#TYPE System.Object
But your challenge is that this doesn't work back and forth. For example:
PS U:\> ((New-Object -TypeName System.Int32 ) | ConvertTo-Csv).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
means that the output of ConvertTo-CSV is not null, but this shows where you've lost the pipeline:
PS U:\> ((New-Object -TypeName System.Int32 ) | ConvertTo-Csv | ConvertFrom-csv).GetType()
You cannot call a method on a null-valued expression.
At line:1 char:1
+ ((New-Object -TypeName System.Int32 ) | ConvertTo-Csv | ConvertFrom-c ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
The help says:
Inputs
System.Management.Automation.PSObject
You can pipe any object that has an Extended Type System (ETS) adapter to ConvertTo-CSV.
So I bet your issue is that $null or blank doesn't have an ETS Adapter.
Here's some more reading on this: https://blogs.msdn.microsoft.com/besidethepoint/2011/11/22/psobject-and-the-adapted-and-extended-type-systems-ats-and-ets/

Related

Make the contents of a .md file the body of an email for outlook using powershell

I want to take the contents of an .md file and have it appear in the body of a generated email for outlook. I can generate the email just find but the body gives the following error and I have yet to find a work around.
Error:
The object does not support this method.
At line:6 char:1
+ $new.HTMLBody = $a
+ ~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
Code:
$out= New-Object -comObject Outlook.Application
# $sign= Get-Content "C:\Users\Roaming\Microsoft\Signatures\sign.htm"
$recipient= "user#.com"
$new= $out.CreateItem(0)
$new.Subject = "Meeting details"
$a = Get-Content -Path "c:\temp\file.md"
$new.HTMLBody = $a
$new.Recipients.Add($recipient)
$new.save()
# $new.HTMLBody += $sign
$display= $new.GetInspector
$display.Display()
To get around the error message you posted, you need to read your file as a string rather than an array of strings. The reason is because $new.Body expects a string. By default, Get-Content returns an array with each line of a file being an element of that array. You can change this behavior with the -Raw switch, which will read the contents as one string.
$a = Get-Content -Path "c:\temp\file.md" -Raw
If the -Raw switch changes the newline formatting, you can always just join the default Get-Content array with newline characters of your choosing.
$a = Get-Content -Path "c:\temp\file.md"
$new.HTMLBody = $a -join "`r`n"
You can see the type differences in your original code using the GetType() method available to PowerShell objects.
$a.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
$new.Body.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object

getting property value in powershell when running convertto-html

I'm still new to powershell, and recently i came to know about get-member properties. However when i pipe the command to convertto-html the value disappear.
i have a data which is called link.csv and below is the content of the file
Target Node Address Status
------ ---- ------- ------
server01 0:2:3 20230002AC0153AF Up
server01 0:2:4 20240002AC0153AF Up
server01 1:2:3 21230002AC0153AF Up
server01 1:2:4 21240002AC0153AF Up
I'm able to get the property value as per below.
PS C:\Report\script\Temp> $a= Import-Csv .\link.csv | select Target,Node,Address,Status
PS C:\Report\script\Temp> $a.Node[1]
0:2:4
PS C:\Report\script\Temp> $a.Status[1]
Up
PS C:\Report\script\Temp> $a.Target[1]
server01
However when i output it to Convertto-Html
PS C:\Report\script\Temp> $a= Import-Csv .\link.csv | select Target,Node,Address,Status | ConvertTo-Html -Fragment -PreContent "<font color=`"Black`"><H4>Remote Copy Group - $b</H4></font> "
PS C:\Report\script\Temp> $a.Target[1]
Cannot index into a null array.
At line:1 char:1
+ $a.Target[1]
+ ~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray
How can i get the property value while running convertto-html command.
Hope you can help me with the issue.
Thank You in advance.
If you want to capture intermediate results in the pipeline, use the -OutVariable / -ov common parameter with a variable name in order to store these results in that variable:
$html = Import-Csv .\link.csv |
Select-Object Target, Node, Address, Status -OutVariable a |
ConvertTo-Html -Fragment -PreContent "<font color=`"Black`"><H4>Remote Copy Group - $b</H4></font> "
$a.Target[1]
Note how the pipeline overall returns HTML (as an array of lines), whereas the intermediate custom objects filtered from the CSV input are stored in variable $a via -OutVariable, for later use - note how you must pass just the variable name to -OutVariable, without the $ sigil, i.e., just a rather than $a.

PowerShell Convert output to hashtable array (data type conversion)

This a data type conversion issue.
I am trying to get the names of computers out of SCCM and feed it into SCCM Report. The report commandlet receives hashtable where the variable must be named "Computer Name". The value is the computer name.
ex. $computer = #{"Computer Name" = "MyComp01"}
Outputing Commandlet example (get computer names from SCCM) This works.
$unknownoutputtype = Get-CMDevice -CollectionName "My Collection Computers" | select #{N="Computer Name";E={$_.Name}}
--Output--
Computer Name
-------------
MyComp01
MyComp02
MyComp03
MyComp04
MyComp05
MyComp06
PS> $unknownoutputtype.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
Recieving Commandlet example (process the query) This works:
$computer = #{"Computer Name" = "MyComp01"}
invoke-cmreport -ReportPath "Software - Companies and Products/Software registered in Add Remove Programs on a specific computer" -reportparameter $Computer -OutputFormat excel
I need the "Get-CMDevice" line to output as the type below.
PS> $Computer.gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Hashtable System.Object
My failed attempt
PS> Get-CMDevice -CollectionName "My Collection Computers" |select #{N="Computer Name";E={$_.Name}} | Foreach-object {invoke-cmreport -ReportPath "Software - Companies and Products/Software registered in Add Remove Programs on a specific computer" -SiteCode "MySite" -reportparameter $_ -OutputFormat Excel}
Error output:
Invoke-CMReport : Cannot bind parameter 'ReportParameter'. Cannot convert value "#{Computer Name=MyComp01}" to type "System.Collections.Hashtable". Error: "Cannot convert the "#{Computer Name=MyComp01}" value of type
"Selected.Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine.WqlResultObject" to type "System.Collections.Hashtable"."
At line:1 char:280
+ ... s on a specific computer" -SiteCode "{removed}" -reportparameter $_ -Output ...
+ ~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-CMReport], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.ConfigurationManagement.Cmdlets.Reporting.Commands.InvokeReportCommand
Select-Object will always output a PSCustomObject, not a hashtable.
Just construct the hashtable inside the ForEach-Object body before calling Invoke-CMReport:
Get-CMDevice -CollectionName "My Collection Computers" |Select-Object -ExpandProperty Name | Foreach-object {
$ReportParameter = #{ 'Computer Name' = $_ }
invoke-cmreport -ReportPath "Software - Companies and Products/Software registered in Add Remove Programs on a specific computer" -SiteCode "MySite" -reportparameter $ReportParameter -OutputFormat Excel
}

Using a Powershell noteproperty as a text string in a variable

I've used Invoke-Restmethod to download some data, which Powershell stores in a PSCustomObject, in a property called data.
I need to use the value of one of the items in the returned data as a variable for another command. I have managed to select-object -expand my way down to the following output from Get-Member:
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
id NoteProperty System.Int32 id=999
What I need to do is grab the value of the ID noteproperty - 999 - and pass that as part of a string to a new variable, eg:
$newVar = "sometext" + 999 + "moretext"
No amount of select-string or out-string etc is helping. Scripting is not exactly my strong point so I'm not sure I'm even articulating what I want properly - apologies if this is the case!
Any assistance much appreciated
I'm not sure exactly what your code and looks like, so I created the following static approximation from the description:
$data = New-Object PSCustomObject
$data | Add-Member -Type NoteProperty -Name Id -Value 999
$restResponse = New-Object PSCustomObject
$restResponse | Add-Member -Type NoteProperty -Name data -Value $data
Please clarify if this is not a match. You can get the Id value as follows
$restResponse.data.Id
Assign it to another variable
$newVar = "sometext" + $restResponse.data.Id + "moretext"
$newVar
And if your REST response is a collection of data objects, iterate through them
$restResponse.data | Foreach-Object { "sometext" + $_.Id + "moretext" }
I would go for for using $output | select *,#{n='test';e={[string]$_.test}} -exclude properties test
if the exclude is not active it will complain about it already exists. Mostly I use the select expression to manipulate data realtime instead of psCustomObject for such simple task

Printing object properties in Powershell

When working in the interactive console if I define a new object and assign some property values to it like this:
$obj = New-Object System.String
$obj | Add-Member NoteProperty SomeProperty "Test"
Then when I type the name of my variable into the interactive window Powershell gives me a summary of the object properties and values:
PS C:\demo> $obj
SomeProperty
------------
Test
I basically want to do just this but from within a function in a script. The function creates an object and sets some property values and I want it to print out a summary of the object values to the Powershell window before returning. I tried using Write-Host within the function:
Write-Host $obj
But this just output the type of the object not the summary:
System.Object
How can I have my function output a summary of the object's property values to the Powershell window?
Try this:
Write-Host ($obj | Format-Table | Out-String)
or
Write-Host ($obj | Format-List | Out-String)
My solution to this problem was to use the $() sub-expression block.
Add-Type -Language CSharp #"
public class Thing{
public string Name;
}
"#;
$x = New-Object Thing
$x.Name = "Bill"
Write-Output "My name is $($x.Name)"
Write-Output "This won't work right: $x.Name"
Gives:
My name is Bill
This won't work right: Thing.Name
To print out object's properties and values in Powershell. Below examples work well for me.
$pool = Get-Item "IIS:\AppPools.NET v4.5"
$pool | Get-Member
TypeName: Microsoft.IIs.PowerShell.Framework.ConfigurationElement#system.applicationHost/applicationPools#add
Name MemberType Definition
---- ---------- ----------
Recycle CodeMethod void Recycle()
Start CodeMethod void Start()
Stop CodeMethod void Stop()
applicationPoolSid CodeProperty Microsoft.IIs.PowerShell.Framework.CodeProperty
state CodeProperty Microsoft.IIs.PowerShell.Framework.CodeProperty
ClearLocalData Method void ClearLocalData()
Copy Method void Copy(Microsoft.IIs.PowerShell.Framework.ConfigurationElement ...
Delete Method void Delete()
...
$pool | Select-Object -Property * # You can omit -Property
name : .NET v4.5
queueLength : 1000
autoStart : True
enable32BitAppOnWin64 : False
managedRuntimeVersion : v4.0
managedRuntimeLoader : webengine4.dll
enableConfigurationOverride : True
managedPipelineMode : Integrated
CLRConfigFile :
passAnonymousToken : True
startMode : OnDemand
state : Started
applicationPoolSid : S-1-5-82-271721585-897601226-2024613209-625570482-296978595
processModel : Microsoft.IIs.PowerShell.Framework.ConfigurationElement
...
Tip #1
Never use Write-Host.
Tip #12
The correct way to output information from a PowerShell cmdlet or function is to create an object that contains your data, and then to write that object to the pipeline by using Write-Output.
-Don Jones: PowerShell Master
Ideally your script would create your objects ($obj = New-Object -TypeName psobject -Property #{'SomeProperty'='Test'}) then just do a Write-Output $objects. You would pipe the output to Format-Table.
PS C:\> Run-MyScript.ps1 | Format-Table
They should really call PowerShell PowerObjectandPipingShell.
Some general notes.
$obj | Select-Object ⊆ $obj | Select-Object -Property *
The latter will show all non-intrinsic, non-compiler-generated properties. The former does not appear to (always) show all Property types (in my tests, it does appear to show the CodeProperty MemberType consistently though -- no guarantees here).
Some switches to be aware of for Get-Member
Get-Member does not get static members by default. You also cannot (directly) get them along with the non-static members. That is, using the switch causes only static members to be returned:
PS Y:\Power> $obj | Get-Member -Static
TypeName: System.IsFire.TurnUpProtocol
Name MemberType Definition
---- ---------- ----------
Equals Method static bool Equals(System.Object objA, System.Object objB)
...
Use the -Force.
The Get-Member command uses the Force parameter to add the intrinsic members and compiler-generated members of the objects to the display. Get-Member gets these members, but it hides them by default.
PS Y:\Power> $obj | Get-Member -Static
TypeName: System.IsFire.TurnUpProtocol
Name MemberType Definition
---- ---------- ----------
...
pstypenames CodeProperty System.Collections.ObjectModel.Collection...
psadapted MemberSet psadapted {AccessRightType, AccessRuleType,...
...
Use ConvertTo-Json for depth and readable "serialization"
I do not necessary recommend saving objects using JSON (use Export-Clixml instead).
However, you can get a more or less readable output from ConvertTo-Json, which also allows you to specify depth.
Note that not specifying Depth implies -Depth 2
PS Y:\Power> ConvertTo-Json $obj -Depth 1
{
"AllowSystemOverload": true,
"AllowLifeToGetInTheWay": false,
"CantAnyMore": true,
"LastResortOnly": true,
...
And if you aren't planning to read it you can -Compress it (i.e. strip whitespace)
PS Y:\Power> ConvertTo-Json $obj -Depth 420 -Compress
Use -InputObject if you can (and are willing)
99.9% of the time when using PowerShell: either the performance won't matter, or you don't care about the performance. However, it should be noted that avoiding the pipe when you don't need it can save some overhead and add some speed (piping, in general, is not super-efficient).
That is, if you all you have is a single $obj handy for printing (and aren't too lazy like me sometimes to type out -InputObject):
# select is aliased (hardcoded) to Select-Object
PS Y:\Power> select -Property * -InputObject $obj
# gm is aliased (hardcoded) to Get-Member
PS Y:\Power> gm -Force -InputObject $obj
Caveat for Get-Member -InputObject:
If $obj is a collection (e.g. System.Object[]), You end up getting information about the collection object itself:
PS Y:\Power> gm -InputObject $obj,$obj2
TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
...
If you want to Get-Member for each TypeName in the collection (N.B. for each TypeName, not for each object--a collection of N objects with all the same TypeName will only print 1 table for that TypeName, not N tables for each object)......just stick with piping it in directly.
The below worked really good for me. I patched together all the above answers plus read about displaying object properties in the following link and came up with the below
short read about printing objects
add the following text to a file named print_object.ps1:
$date = New-Object System.DateTime
Write-Output $date | Get-Member
Write-Output $date | Select-Object -Property *
open powershell command prompt, go to the directory where that file exists and type the following:
powershell -ExecutionPolicy ByPass -File is_port_in_use.ps1 -Elevated
Just substitute 'System.DateTime' with whatever object you wanted to print. If the object is null, nothing will print out.
# Json to object
$obj = $obj | ConvertFrom-Json
Write-host $obj.PropertyName