PowerShell: Appending HTML to Property with Multiple Values - powershell

How am I able to append some HTML tags (<td></td>) to an existing property?
I've been stuck on this one for a little while now with no luck...
$teamConfig = #(
[pscustomobject]#{
TeamName = 'Team1'
TeamEmail = 'team1#domain.tld'
}
[pscustomobject]#{
TeamName = 'Team2'
TeamEmail = 'team2#domain.tld'
}
)
$query = "select * from INCAutomation"
$results = Invoke-Sqlcmd -query $query -ServerInstance 'localhost' -Database 'AyushTest'
$teamTickets = foreach($team in $teamConfig){
# Filter tickets based on team name
$ticketIds = $results |Where-Object TeamName -eq $team.TeamName |Select -ExpandProperty TicketID
# Output a single object per team, with all ticket IDs attached
$team |Select TeamName,TeamEmail,#{Name='TicketID';Expression={$ticketIds}}
}
$teamTickets
Output:
TeamName TeamEmail TicketID
-------- --------- --------
Team1 team1#domain.tld {INC0001, INC0002, INC0003, INC0004}
Team2 team2#domain.tld {INC0005, INC0006, INC0007}
Desired output:
TeamName TeamEmail TicketID
-------- --------- --------
Team1 team1#domain.tld {<td>INC0001</td>, <td>INC0002</td>, <td>INC0003</td>, <td>INC0004</td>}
Team2 team2#domain.tld {<td>INC0005</td>, <td>INC0006</td>, <td>INC0007</td>}
Thanks in advance!

I think you should run them through a loop and modify each string to add the desired text. You can do that and add the modified strings to a new object, which you can use to replace the original $ticketIds variable as the Expression in your output.
Here's an example of your code, modified:
$teamConfig = #(
[pscustomobject]#{
TeamName = 'Team1'
TeamEmail = 'team1#domain.tld'
}
[pscustomobject]#{
TeamName = 'Team2'
TeamEmail = 'team2#domain.tld'
}
)
$query = "select * from INCAutomation"
$results = Invoke-Sqlcmd -query $query -ServerInstance 'localhost' -Database 'AyushTest'
$teamTickets = foreach($team in $teamConfig){
# Filter tickets based on team name
$ticketIds = $results |Where-Object TeamName -eq $team.TeamName |Select -ExpandProperty TicketID
# Create an empty array
$ticketIdArray = #()
foreach ($id in $ticketIds) {
# Modify the string to include the desired output
$thisId = '<td>' + "$id" + '</td>'
# Add the modified string to the empty array
$ticketIdArray += $thisId
}
# Output a single object per team, with all ticket IDs attached
$team |Select TeamName,TeamEmail,#{Name='TicketID';Expression={$ticketIdArray}}
}
$teamTickets

Related

Possible to pull info from AdditionalProperties dictionary with Microsoft Graph PowerShell cmdlets?

I am trying to use PowerShell Graph cmdlets instead of the Azure AD module cmdlets. With the Azure AD module, I can do this:
# This is what I want:
get-azureadgroupmember -objectid $GroupID | select-object -property displayname, `
mail, userprincipalname, objectid
DisplayName Mail UserPrincipalName ObjectId
----------- ---- ----------------- --------
John Smith John.Smith#example.org jsmith#example.org 4bae8291-6ec3-192b-32ce-dd21869ef784
(...)
# All of these properties are directly accessible in the returned objects:
$res = get-azureadgroupmember -objectid $GroupID
$res[0] | fl -prop *
# Shows long list of directly accessible properties
I'm trying to figure out the equivalent with PowerShell Graph:
$res = get-mggroupmember -groupid $GroupID
$res[0] | fl -prop *
# Only properties are DeletedDateTime, Id, and AdditionalProperties
# Want to do something like this, but it doesn't work:
get-mggroupmember -groupid $GroupID | select-object -property id, `
additionalproperties['displayName'], additionalproperties['mail'], `
additionalproperties['userPrincipalName']
# This works, but is there a better option???
get-mggroupmember -groupid $GroupID | foreach-object { `
"{0},{1},{2},{3}" -f $_.id, $_.additionalproperties['displayName'], `
$_.additionalproperties['mail'], $_.additionalproperties['userPrincipalName']
}
AdditionalProperties is a dictionary (IDictionary) which contains displayname, mail, and userprincipalname. My thought is there is probably a better way to do this or to get at the information.
There are a few interesting parameters in get-mggroupmember that I'm not clear on including "-expandproperty" and "-property". I've tried playing around with these but haven't had any luck. I'm wondering if there's a way to use these to do what I want.
Suggestions?
Given the following $object, 3 properties and one of them AdditionalProperties is a Dictionary<TKey,TValue>:
$dict = [Collections.Generic.Dictionary[object, object]]::new()
$dict.Add('displayName', 'placeholder')
$dict.Add('mail', 'placeholder')
$dict.Add('userPrincipalName', 'placeholder')
$object = [pscustomobject]#{
DeletedDateTime = 'placeholder'
Id = 'placeholder'
AdditionalProperties = $dict
}
Supposing from this object you're interested in Id, displayName and mail, you could use Select-Object with calculated properties:
$object | Select-Object #(
'Id'
#{
Name = 'displayName'
Expression = { $_.additionalProperties['displayName'] }
}
#{
Name = 'mail'
Expression = { $_.additionalProperties['mail'] }
}
)
However this gets messy as soon as you need to pick more property values from the objects, PSCustomObject with a loop comes in handy in this case:
$object | ForEach-Object {
[pscustomobject]#{
Id = $_.Id
displayName = $_.additionalProperties['displayName']
mail = $_.additionalProperties['mail']
}
}
Both alternatives would output the same "flattened" object that can be converted to Csv without any issue:
As Object
Id displayName mail
-- ----------- ----
placeholder placeholder placeholder
As Csv
"Id","displayName","mail"
"placeholder","placeholder","placeholder"
In that sense, you could construct an array of objects using one of the above techniques, for example:
Get-MgGroupMember -GroupId $GroupID | ForEach-Object {
[pscustomobject]#{
Id = $_.id
displayName = $_.additionalproperties['displayName']
mail = $_.additionalproperties['mail']
userPrincipalName = $_.additionalproperties['userPrincipalName']
}
}
If you're looking for a programmatical way to flatten the object, you can start by using this example, however it's important to note that this can only handle an object which's property is nested only once, in other words, it can't handle recursion:
$newObject = [ordered]#{}
foreach($property in $object.PSObject.Properties) {
if($property.Value -is [Collections.IDictionary]) {
foreach($addproperty in $property.Value.GetEnumerator()) {
$newObject[$addproperty.Key] = $addproperty.Value
}
continue
}
$newObject[$property.Name] = $property.Value
}
[pscustomobject] $newObject
The output from this would become a flattened object like this, which also, can be converted to Csv without any issue:
DeletedDateTime : placeholder
Id : placeholder
displayName : placeholder
mail : placeholder
userPrincipalName : placeholder
It's also worth noting that above example is not handling possible key collision, if there are 2 or more properties with the same name, one would override the others.
Bonus function that should work with the objects returned by the cmdlets from Graph, AzureAD and Az Modules. This function can be useful to flatten their Dictionary`2 property. It only looks one level deep if the property value implements IDictionary so don't expect it to flatten any object. For the given example should work well.
function Select-GraphObject {
[CmdletBinding()]
param(
[parameter(ValueFromPipeline, DontShow)]
[object] $InputObject,
[parameter(Position = 0)]
[string[]] $Properties = '*'
)
begin {
$firstObject = $true
$toSelect = [Collections.Generic.List[object]]::new()
}
process {
if($firstObject) {
foreach($property in $InputObject.PSObject.Properties) {
foreach($item in $Properties) {
if($property.Value -is [Collections.IDictionary]) {
foreach($key in $property.Value.PSBase.Keys) {
if($key -like $item -and $key -notin $toSelect.Name) {
$toSelect.Add(#{
$key = { $_.($property.Name)[$key] }
})
}
}
continue
}
if($property.Name -like $item -and $property.Name -notin $toSelect) {
$toSelect.Add($property.Name)
}
}
}
$firstObject = $false
}
$out = [ordered]#{}
foreach($item in $toSelect) {
if($item -isnot [hashtable]) {
$out[$item] = $InputObject.$item
continue
}
$enum = $item.GetEnumerator()
if($enum.MoveNext()) {
$out[$enum.Current.Key] = $InputObject | & $enum.Current.Value
}
}
[pscustomobject] $out
}
}
Using copies of the $object from above examples, if using the default value of -Properties, the example objects would be flattened:
PS /> $object, $object, $object | Select-GraphObject
DeletedDateTime Id displayName mail userPrincipalName
--------------- -- ----------- ---- -----------------
placeholder placeholder placeholder placeholder placeholder
placeholder placeholder placeholder placeholder placeholder
placeholder placeholder placeholder placeholder placeholder
Or we can filter for specific properties, even Keys from the AdditionalProperties Property:
PS /> $object, $object, $object | Select-GraphObject Id, disp*, user*
Id displayName userPrincipalName
-- ----------- -----------------
placeholder placeholder placeholder
placeholder placeholder placeholder
placeholder placeholder placeholder

Collect Network Card related information

I need a script which extracts me at least Computername, IP Address(es), Description (Alias) and MAC Address for each NIC and export it to csv
I found here this piece of script which covers my needs and some surplus information:
$Data = #()
$NetInfo = Get-NetIPConfiguration -Detailed
foreach ( $nic in $Netinfo) {
foreach ($ip in $nic.IPv4Address) {
$Data += [pscustomobject] #{ Ordinateur=$nic.ComputerName; AliasNIC=$nic.InterfaceAlias;
NetworkcardName=$nic.InterfaceDescription; IP=$ip; MAC=$nic.NetAdapter.MACAddress;
Status=$nic.NetAdapter.Status
}
}
}
$Data | Format-Table #-HideTableHeader
I would like to use export-csv
instead of format-table but for IP address but I get strange outputs below an example for one line of output:
"Client01","Ethernet","Intel(R) Ethernet Connection (10) I219-V","MSFT_NetIPAddress (Name = "";C?8;#B8;AB8?:?55?55;55;"", CreationClassName = """", SystemCreationClassName = """", SystemName = """")","MSFT_NetIPAddress (Name = "";C?8;#B8;AB8?:?55?55;55;"", CreationClassName = """", SystemCreationClassName = """", SystemName = """")","38-F3-AB-85-EC-CF","Up"
Solution from guiwhatsthat (see comments)
$Data = #()
$NetInfo = Get-NetIPConfiguration -Detailed
foreach ( $nic in $Netinfo) {
foreach ($ip in $nic.IPv4Address) {
$Data += [pscustomobject] #{ Ordinateur=$nic.ComputerName; AliasNIC=$nic.InterfaceAlias;
NetworkcardName=$nic.InterfaceDescription; IP=$ip.IPAddress; MAC=$nic.NetAdapter.MACAddress;
Status=$nic.NetAdapter.Status
}
}
}
$Data | Format-Table #-HideTableHeader

Format-Table not taking effect (Exchange - powershell)

first of all sorry if my english is not the best. but ill try to explain my issue with as much detail as i can
Im having an issue where i cant get Format-Table to effect the output i give it.
below is the part im having issues with atm.
cls
$TotalSize = $($mailboxes. #{name = ”TotalItemSize (GB)”; expression = { [math]::Round((($_.TotalItemSize.Value.ToString()).Split(“(“)[1].Split(” “)[0].Replace(“,”, ””) / 1GB), 2) } });
$UserN = $($mailboxes.DisplayName)
$itemCount = $($mailboxes.ItemCount)
$LastLogonTime = $($mailboxes.ItemCount)
$allMailboxinfo = #(
#lager dataen som skal inn i et objekt
#{Username= $UserN; ItemCount = $itemCount; LastLogonTime = $($mailboxes.ItemCount); Size = $TotalSize}) | % { New-Object object | Add-Member -NotePropertyMembers $_ -PassThru }
$Table = $allMailboxinfo | Format-Table | Out-String
$Table
the output of this gives me what almost looks like json syntax below each title of the table.
Username LastLogonTime ItemCount Size
-------- ------------- --------- ----
{username1, username2,username3,userna...} {$null, $null, $null, $null...} {$null, $null, $null, $null...} {$null, $null, $null, $null...}
running the commands by themselves seem to work tho. like $mailboxes.DisplayName gives the exact data i want for displayname. even in table-format.
the reason im making the table this way instead of just using select-object, is because im going to merge a few tables later. using the logic from the script below.
cls
$someData = #(
#{Name = "Bill"; email = "email#domain.com"; phone = "12345678"; id = "043546" }) | % { New-Object object | Add-Member -NotePropertyMembers $_ -PassThru }
$moreData = #(
#{Name = "Bill"; company = "company 04"}) | % { New-Object object | Add-Member -NotePropertyMembers $_ -PassThru }
$Merge = #(
#plots the data into a new table
#{Name = $($someData.Name); e_mail = $($someData.email); phone = $($someData.phone); id = $($someData.id); merged = $($moreData.company) }) | % { New-Object object | Add-Member -NotePropertyMembers $_ -PassThru }
#formatting table
$Table = $Merge | Format-Table | Out-String
#print table
$Table
if you are wondering what im doing with this.
My goal, all in all. is a table with using the info from Exchange;
DisplayName, TotalItemSize(GB), ItemCount, LastLogonTime, E-mail adress, archive + Maxquoata, Quoata for mailbox.
You're creating a single object where each property holds an array of property values from the original array of mailbox objects.
Instead, create 1 new object per mailbox:
# construct output objects with Select-Object
$allMailBoxInfo = $mailboxes |Select #{Name='Username';Expression='DisplayName'},ItemCount,#{Name='LastLogonTime';Expression='ItemCount'},#{Name='Size';Expression={[math]::Round((($_.TotalItemSize.Value.ToString()).Split("(")[1].Split(" ")[0].Replace(",", "") / 1GB), 2) }}
# format table
$Table = $allMailBoxInfo | Format-Table | Out-String
# print table
$Table

How to join and group 2 tables with a comma list in Powershell?

I have two array which have the following objects:
$dataset1 = #(
#{
MachineName = "AAA"
ID = "111"
},
#{
MachineName = "BBB"
ID = "222"
},
#{
MachineName = "CCC"
ID = "111"
},
#{
MachineName = "DDD"
ID = "333"
},
#{
MachineName = "EEE"
ID = "111"
}
)
$dataset2 = #(
#{
ID = "111"
TagName = "ALPHA2"
},
#{
ID = "222"
TagName = "ALPHA0"
},
#{
ID = "333"
TagName = "ALPHA8"
},
#{
ID = "444"
TagName = "ALPHA29"
},
)
Now I want to create an array which have an object of TagName and for each object of TagName it should contain a list of MachineNames separated by comma so something like this:
TagName | MachineName
ALPHA2 AAA,CCC,EEE
ALPHA0 BBB
ALPHA8 DDD
This is the code that I have tried:
$Joined= Foreach ($row in $dataset1)
{
[pscustomobject]#{
ID = $row.ID
MachineName = $row.MachineName -join ','
TagName = $dataset2 | Where-Object {$_.ID -eq $row.ID} | Select-Object -ExpandProperty TagName
}
}
But it is not generating a comma list of Machine names instead it is printing individual rows for each machine name.
I would iterate $dataset2 instead of $dataset1.
$joined = foreach($row in $dataset2){
[PSCustomObject]#{
TagName = $row.tagname
MachineName = ($dataset1 | Where-Object id -eq $row.id).MachineName -join ','
}
}
If you're trying to exclude those entries in $dataset1 that don't have a corresponding entry in $dataset2, change to this.
$joined = foreach($row in $dataset2 | Where-Object id -in $dataset1.id){
[PSCustomObject]#{
TagName = $row.tagname
MachineName = ($dataset1 | Where-Object id -eq $row.id).MachineName -join ','
}
}
it is not generating a comma list of Machine names instead it is printing individual rows for each machine name.
That's actually a great starting point!
Just pipe the resulting objects to Group-Object and extract the machine names from each resulting group:
$joined |Group-Object TagName |Select Name,#{Name='Machines';Expression = {$_.Group.MachineName -join ','}}
Which should give you something like:
Name Machines
---- --------
ALPHA2 AAA,CCC,EEE
ALPHA0 BBB
ALPHA8 DDD

Add values to PS object from other PS command

I created the following object:
$PSOhash = #{
ConnectedNode = $ConnectedNode
ConnectedNodeDeviceNumber = $ConnectedNodeDeviceNumber
Serialnumber = $Serialnumber
ProductId = $ProductId
}
$ClusterNodeSSDs = New-Object PSObject -Property $PSOhash
and want to add values from the following command into it:
$SSDModel = "xyz123"
$ClusterNode = "Node1"
gwmi -Namespace root\wmi ClusPortDeviceInformation| select ConnectedNode,ConnectedNodeDeviceNumber, Serialnumber, ProductId | sort ConnectedNodeDeviceNumber | where {($_.ConnectedNode -eq $ClusterNode) -and ($_.ProductId -match "$SSDModel")}
which returns the proper informations, but need them as properties in the object for further processing.
If you want to add a set of property-value pairs to an already existing PSObject ($MyObject in this example) that currently does not have those properties, you can use the Add-Member command for this:
$PSOhash = #{
ConnectedNode = $ConnectedNode
ConnectedNodeDeviceNumber = $ConnectedNodeDeviceNumber
Serialnumber = $Serialnumber
ProductId = $ProductId
}
$MyObject = $MyObject | Add-Member -NotePropertyMembers $PSOHash
Explanation:
The -NotePropertyMembers parameter allows you do add a hash table of property-value pairs to a custom object.
Optionally, you can use a combination of Add-Member's -NotePropertyValue and -NotePropertyName to add properties one at a time.
If you want to update one object's property values with property values (same property names) from another object, you can just use direct assignment and the member access operator (.).
$SSDModel = "xyz123"
$ClusterNode = "Node1"
$WmiObjects = Get-WmiObject -Namespace root\wmi ClusPortDeviceInformation |
Select-Object ConnectedNode,ConnectedNodeDeviceNumber, Serialnumber, ProductId |
Sort-Object ConnectedNodeDeviceNumber |
where {($_.ConnectedNode -eq $ClusterNode) -and ($_.ProductId -match "$SSDModel")}
$ClusterNodeSSDs = foreach ($WmiObject in $WmiObjects) {
$PSOhash = #{
ConnectedNode = $WmiObject.ConnectedNode
ConnectedNodeDeviceNumber = $WmiObject.ConnectedNodeDeviceNumber
Serialnumber = $WmiObject.Serialnumber
ProductId = $WmiObject.ProductId
}
[pscustomobject]$PSOhash
}
Explanation:
Note the use of the foreach loop here because the Get-WmiObject will likely return a collection. So you will need to iterate all of them to create custom objects. However, it just seems that you can just use the Get-WmiObject | Select-Object output to perform the same thing.