I am picking information from CSV file and i have mentioned tags like #{"R"="red";"B"="Blue"}.
when i am assigning tags value to variable , it is printing on same format but while adding tags to vm i am getting below error ,
Set-AzResource : Cannot bind parameter 'Tag'. Cannot convert the "System.Collections.Hashtable" value of type "System.String" to
$tags| convertfrom-stringdata
but the problem is after running add tag command for Vm , it is adding tag like below
#{"r : ="red";"B"="Blue"}
How can i add both tag as a separate like
r:red b:blue
$rss = Import-csv "C:\abc\VijayGupta\Desktop\Vm_build_azure.csv"
$tag = $rss.vmtags
$tags = $tag | ConvertFrom-StringData
$vms=Get-AzResource -Name abc -ResourceGroupName Southindia
Set-AzResource -ResourceId $vms.Id -Tag $tags -Force
If I understand the question, in your CSV file, there is a column called vmtags. The values in that column are strings in the form of #{"R"="red";"B"="Blue"}.
The Get-AzResource cmdlet wants a Hashtable object for its -Tags parameter. I think you took the description MS gives: Key-value pairs in the form of a hash table. For example: #{key0="value0";key1=$null;key2="value2"} a bit too literal there and now you need to create an actual Hashtable object from its string representation.
To create a Hashtable from a string like that you can use
# create a scriptblock using the string
$scriptBlock = [scriptblock]::Create('#{"R"="red";"B"="Blue"')
# execute it to create the hashtable
$tags = (& $scriptBlock)
$tags is now a Hashtable containing
Name Value
---- -----
R red
B Blue
If you need to create a Hashtable from multiple strings, do something like
$vmtags = '#{"R"="red";"B"="Blue"}', '#{"G"="green";"A"="Alpha"}'
# first loop creates the hashtables from the individual strings
$arr = $vmtags | ForEach-Object {
$scriptBlock = [scriptblock]::Create($_)
& $scriptBlock
}
# the second loop merges all Hashtables in the array into one
$tags = #{}
$arr | ForEach-Object {
foreach ($key in $_.Keys) {
$tags[$key] = $_.$key
}
}
$tags is now a Hashtable containing
Name Value
---- -----
R red
B Blue
A Alpha
G green
Related
I'm running the Test-AdfsServerHealth (Ref.)
The problem is, one of the output values (value name Output) is an array that shows up as System.Collection.Hashtable and I'm trying to find a way to get this in a neat Excel format.
For instance, this is one of the actual values on the CSV when I export:
Name Result Detail Output
TestServiceAccountProperties Pass "" System.Collections.Hashtable
But PowerShell displays:
Name : TestServiceAccountProperties
Result : Pass
Detail :
Output : {AdfsServiceAccount, AdfsServiceAccountDisabled, AdfsServiceAccountLockedOut,
AdfsServiceAccountPwdExpired...}
ExceptionMessage :
The actual command I'm running is:
$ServerResult = Test-AdfsServerHealth
tl;dr:
Test-AdfsServerHealth |
Select-Object Name, Result, Detail, #{
n='Output'
e={ $_.prop2.GetEnumerator().ForEach({ '{0}={1}' -f $_.Key, $_.Value }) -join ' ' }
} | ExportTo-Csv out.csv
The above serializes each .Output hashtable's entries into single-line string composed of space-separated <key>=<value> pairs (PSv4+ syntax) that should work reasonably well in CSV output.
Since CSV is a text format, PowerShell serializes objects to be exported by calling their .ToString() method.
Complex objects such as [hashtable] instances often yield just their full type name (System.Collections.Hashtable) for .ToString(), which isn't useful in a CSV.
A simplified example (I'm using ConvertTo-Csv, but the example applies analogously to Export-Csv):
# Create a custom object whose .col2 property is a hashtable with 2
# sample entries and convert it to CSV
PS> [pscustomobject] #{ prop1 = 1; Output = #{ name='foo'; ID=666 } } | ConvertTo-Csv
"prop1","Output"
"1","System.Collections.Hashtable"
If all output objects from Test-AdfsServerHealth had the same hashtable structure in their .Output property, you could try to flatten the hashtable by making its entries columns in their own right, but it sounds like that is not the case.
You must therefore manually transform the hashtable into a text representation that fits into a single CSV column:
You can do this with Select-Object and a calculated property that performs the transformation for you, but you need to decide on a text representation that makes sense in the context of a CSV file.
In the following example, a single-line string composed of space-separated <key>=<value> pairs is created (PSv4+ syntax).
[pscustomobject] #{ prop1 = 1; Output = #{ name='foo'; ID=666 } } |
Select-Object prop1, #{
n='Output'
e={ $_.prop2.GetEnumerator().ForEach({ '{0}={1}' -f $_.Key, $_.Value }) -join ' ' }
} | ConvertTo-Csv
For an explanation of the hashtable format that creates the calculated prop2 property, see this answer of mine.
The above yields:
"prop1","prop2"
"1","ID=666 name=foo"
Note, however, that if the values in your hashtables are again complex objects that serialize to their type name only, you'd have to apply the approach recursively.
Optional reading: Flattening a hashtable property into individual columns
If the hashtable-valued properties of the objects to export to a CSV file all have the same structure, you can opt to make the hashtable entries each their own output column.
Let's take the following sample input: a collection of 2 custom objects whose .prop2 value is a hashtable with a uniform set of keys (entries):
$coll = [pscustomobject] #{ prop1 = 1; prop2 = #{ name='foo1'; ID=666 } },
[pscustomobject] #{ prop1 = 2; prop2 = #{ name='foo2'; ID=667 } }
If you know the key names (of interest) up front, you can simply use an explicit list of calculated properties to create the individual columns:
$coll | select prop1, #{ n='name'; e={ $_.prop2.name } }, #{ n='ID'; e={ $_.prop2.ID } } |
ConvertTo-Csv
The above yields the following, showing that the hashtable entries became their own columns, name and ID:
"prop1","name","ID"
"1","foo1","666"
"2","foo2","667"
More advanced techniques are required if you do not know the key names up front:
# Create the list of calculated properties dynamically, from the 1st input
# object's .prop2 hashtable.
$propList = foreach ($key in $coll[0].prop2.Keys) {
# The script block for the calculated property must be created from a
# *string* in this case, so we can "bake" the key name into it.
#{ n=$key; e=[scriptblock]::Create("`$_.prop2.$key") }
}
$coll | Select-Object (, 'prop1' + $propList) | ConvertTo-Csv
This yields the same output as the previous command with the fixed list of calculated properties.
This won't be significantly difficult, just going to be annoying to do. The reason you are getting "System.collections.hashtable" is because is unable to display everything in that property in a single format like that, there is way to much information. You will have to create another object and put whatever information you want in there.
This prob won't work exactly like you want, but with some tweaking it should get you there.
$ServerResult = Test-ADFSServerHealth
$Object = New-PSObject -Property #{
'Name' = $ServerResult.name
'Result' = $ServerResult.Result
'Detail' = $ServerResult.Detail
'Output' = ($ServerResult.Output | out-string -stream)
'ExceptionMessage' = $ServerResult.ExceptionMessage
}
If your interested, here are the resources I used to find this answer.
Converting hashtable to array of strings
https://devops-collective-inc.gitbooks.io/the-big-book-of-powershell-gotchas/content/manuscript/new-object_psobject_vs_pscustomobject.html
How do I get properties that ONLY have populated values?
So for example if I run
Get-QADUser -Identity "SomeOne" -IncludeAllProperties
the output would of course include.. all properties, including those with and those without values. I want a listing of properties with values only. How is it done generally speaking?
This wouldn't be restricted to Quest Cmdlets, I only use Get-QADUser as an example.
You could try using the built-in (hidden) property of PowerShell objects called PSObject, which includes a property called Properties, i.e. a list of all properties on the parent object.
Maybe easier with an example. Take Get-Process... a process can have many attributes (properties) with or without values. In order to get just the ones with values you do this:
(Get-Process | Select -First 1).PSObject.Properties | ?{$_.Value -ne $null} | FT Name,Value
Note that I limited this to just the first process returned by Get-Process. We then get all the properties defined on that object, filtering where Value is not null and then displaying just the Name and Value for those properties.
To complement Charlie Joynt's helpful answer:
Below is convenience function Remove-NullProperties, which creates custom-object copies of its input objects populated with only the non-$null properties of the input objects.
Example use:
# Sample input collection, with 2 objects with different $null-valued
# properties.
$coll = [pscustomobject] #{ one = 'r1c1'; two = $null; three = 'r1c3' },
[pscustomobject] #{ one = 'r2c1'; two = 'r2c2'; three = $null }
# Output copies containing only non-$null-valued properties.
# NOTE: The `ForEach-Object { Out-String -InputObject $_ }` part is solely
# there to ensure that *all* resulting properties are shown.
# With the default output, only the properties found on the FIRST
# input object would be used in the output table.
$coll | Remove-NullProperties |
ForEach-Object { Out-String -InputObject $_ }
This yields the following - note how the respective null-valued properties were removed:
one three
--- -----
r1c1 r1c3
one two
--- ---
r2c1 r2c2
Remove-NullProperties source code:
<#
.SYNOPSIS
Removes properties with $null values from custom-object copies of
the input objects.
.DESCRIPTION
Note that output objects are custom objects that are copies of the input
objects with copies of only those input-object properties that are not $null.
CAVEAT: If you pipe multiple objects to this function, and these objects
differ in what properties are non-$null-valued, the default output
format will show only the non-$null-valued properties of the FIRST object.
Use ... | ForEach-Object { Out-String -InputObject $_ } to avoid
this problem.
.NOTES
Since the output objects are generally of a distinct type - [pscustomobject] -
and have only NoteProperty members, use of this function only makes sense
with plain-old data objects as input.
.EXAMPLE
> [pscustomobject] #{ one = 1; two = $null; three = 3 } | Remove-NullProperties
one three
--- -----
1 3
#>
function Remove-NullProperties {
param(
[parameter(Mandatory,ValueFromPipeline)]
[psobject] $InputObject
)
process {
# Create the initially empty output object
$obj = [pscustomobject]::new()
# Loop over all input-object properties.
foreach($prop in $InputObject.psobject.properties) {
# If a property is non-$null, add it to the output object.
if ($null -ne $InputObject.$($prop.Name)) {
Add-Member -InputObject $obj -NotePropertyName $prop.Name -NotePropertyValue $prop.Value
}
}
# Give the output object a type name that reflects the type of the input
# object prefixed with 'NonNull.' - note that this is purely informational, unless
# you define a custom output format for this type name.
$obj.pstypenames.Insert(0, 'NonNull.' + $InputObject.GetType().FullName)
# Output the output object.
$obj
}
}
These answers didn't work for me in the case of importing an object from an Infoblox csv file. Some values were the empty string, but not null. Testing whether a property is true or not, seems to work better for me. And the result is an object.
$a = [pscustomobject]#{one='hi';two='';three='there'}
$prop = $a.psobject.Properties | where value | foreach name
$a | select $prop
one three
--- -----
hi there
You first get its properties (since Get-QADUser depends on AD schema, the properties list is dynamic) with get-member -type property, then filter out those that don't have \{.*(get).*\} in its definition (that is, they are not "gettable"), then enumerate the resultant list by name and filter out nulls.
$someone=Get-QADUser -Identity "SomeOne" -IncludeAllProperties
$members=$someone|get-member -type property| where {$_.definition -match '\{.*(get).*\}'}
foreach ($member in $members) {
if ($someone[$member.name] -ne $null) {
write-host $member.name $someone[$member.name]
}
}
I'm running the Test-AdfsServerHealth (Ref.)
The problem is, one of the output values (value name Output) is an array that shows up as System.Collection.Hashtable and I'm trying to find a way to get this in a neat Excel format.
For instance, this is one of the actual values on the CSV when I export:
Name Result Detail Output
TestServiceAccountProperties Pass "" System.Collections.Hashtable
But PowerShell displays:
Name : TestServiceAccountProperties
Result : Pass
Detail :
Output : {AdfsServiceAccount, AdfsServiceAccountDisabled, AdfsServiceAccountLockedOut,
AdfsServiceAccountPwdExpired...}
ExceptionMessage :
The actual command I'm running is:
$ServerResult = Test-AdfsServerHealth
tl;dr:
Test-AdfsServerHealth |
Select-Object Name, Result, Detail, #{
n='Output'
e={ $_.prop2.GetEnumerator().ForEach({ '{0}={1}' -f $_.Key, $_.Value }) -join ' ' }
} | ExportTo-Csv out.csv
The above serializes each .Output hashtable's entries into single-line string composed of space-separated <key>=<value> pairs (PSv4+ syntax) that should work reasonably well in CSV output.
Since CSV is a text format, PowerShell serializes objects to be exported by calling their .ToString() method.
Complex objects such as [hashtable] instances often yield just their full type name (System.Collections.Hashtable) for .ToString(), which isn't useful in a CSV.
A simplified example (I'm using ConvertTo-Csv, but the example applies analogously to Export-Csv):
# Create a custom object whose .col2 property is a hashtable with 2
# sample entries and convert it to CSV
PS> [pscustomobject] #{ prop1 = 1; Output = #{ name='foo'; ID=666 } } | ConvertTo-Csv
"prop1","Output"
"1","System.Collections.Hashtable"
If all output objects from Test-AdfsServerHealth had the same hashtable structure in their .Output property, you could try to flatten the hashtable by making its entries columns in their own right, but it sounds like that is not the case.
You must therefore manually transform the hashtable into a text representation that fits into a single CSV column:
You can do this with Select-Object and a calculated property that performs the transformation for you, but you need to decide on a text representation that makes sense in the context of a CSV file.
In the following example, a single-line string composed of space-separated <key>=<value> pairs is created (PSv4+ syntax).
[pscustomobject] #{ prop1 = 1; Output = #{ name='foo'; ID=666 } } |
Select-Object prop1, #{
n='Output'
e={ $_.prop2.GetEnumerator().ForEach({ '{0}={1}' -f $_.Key, $_.Value }) -join ' ' }
} | ConvertTo-Csv
For an explanation of the hashtable format that creates the calculated prop2 property, see this answer of mine.
The above yields:
"prop1","prop2"
"1","ID=666 name=foo"
Note, however, that if the values in your hashtables are again complex objects that serialize to their type name only, you'd have to apply the approach recursively.
Optional reading: Flattening a hashtable property into individual columns
If the hashtable-valued properties of the objects to export to a CSV file all have the same structure, you can opt to make the hashtable entries each their own output column.
Let's take the following sample input: a collection of 2 custom objects whose .prop2 value is a hashtable with a uniform set of keys (entries):
$coll = [pscustomobject] #{ prop1 = 1; prop2 = #{ name='foo1'; ID=666 } },
[pscustomobject] #{ prop1 = 2; prop2 = #{ name='foo2'; ID=667 } }
If you know the key names (of interest) up front, you can simply use an explicit list of calculated properties to create the individual columns:
$coll | select prop1, #{ n='name'; e={ $_.prop2.name } }, #{ n='ID'; e={ $_.prop2.ID } } |
ConvertTo-Csv
The above yields the following, showing that the hashtable entries became their own columns, name and ID:
"prop1","name","ID"
"1","foo1","666"
"2","foo2","667"
More advanced techniques are required if you do not know the key names up front:
# Create the list of calculated properties dynamically, from the 1st input
# object's .prop2 hashtable.
$propList = foreach ($key in $coll[0].prop2.Keys) {
# The script block for the calculated property must be created from a
# *string* in this case, so we can "bake" the key name into it.
#{ n=$key; e=[scriptblock]::Create("`$_.prop2.$key") }
}
$coll | Select-Object (, 'prop1' + $propList) | ConvertTo-Csv
This yields the same output as the previous command with the fixed list of calculated properties.
This won't be significantly difficult, just going to be annoying to do. The reason you are getting "System.collections.hashtable" is because is unable to display everything in that property in a single format like that, there is way to much information. You will have to create another object and put whatever information you want in there.
This prob won't work exactly like you want, but with some tweaking it should get you there.
$ServerResult = Test-ADFSServerHealth
$Object = New-PSObject -Property #{
'Name' = $ServerResult.name
'Result' = $ServerResult.Result
'Detail' = $ServerResult.Detail
'Output' = ($ServerResult.Output | out-string -stream)
'ExceptionMessage' = $ServerResult.ExceptionMessage
}
If your interested, here are the resources I used to find this answer.
Converting hashtable to array of strings
https://devops-collective-inc.gitbooks.io/the-big-book-of-powershell-gotchas/content/manuscript/new-object_psobject_vs_pscustomobject.html
How do I get properties that ONLY have populated values?
So for example if I run
Get-QADUser -Identity "SomeOne" -IncludeAllProperties
the output would of course include.. all properties, including those with and those without values. I want a listing of properties with values only. How is it done generally speaking?
This wouldn't be restricted to Quest Cmdlets, I only use Get-QADUser as an example.
You could try using the built-in (hidden) property of PowerShell objects called PSObject, which includes a property called Properties, i.e. a list of all properties on the parent object.
Maybe easier with an example. Take Get-Process... a process can have many attributes (properties) with or without values. In order to get just the ones with values you do this:
(Get-Process | Select -First 1).PSObject.Properties | ?{$_.Value -ne $null} | FT Name,Value
Note that I limited this to just the first process returned by Get-Process. We then get all the properties defined on that object, filtering where Value is not null and then displaying just the Name and Value for those properties.
To complement Charlie Joynt's helpful answer:
Below is convenience function Remove-NullProperties, which creates custom-object copies of its input objects populated with only the non-$null properties of the input objects.
Example use:
# Sample input collection, with 2 objects with different $null-valued
# properties.
$coll = [pscustomobject] #{ one = 'r1c1'; two = $null; three = 'r1c3' },
[pscustomobject] #{ one = 'r2c1'; two = 'r2c2'; three = $null }
# Output copies containing only non-$null-valued properties.
# NOTE: The `ForEach-Object { Out-String -InputObject $_ }` part is solely
# there to ensure that *all* resulting properties are shown.
# With the default output, only the properties found on the FIRST
# input object would be used in the output table.
$coll | Remove-NullProperties |
ForEach-Object { Out-String -InputObject $_ }
This yields the following - note how the respective null-valued properties were removed:
one three
--- -----
r1c1 r1c3
one two
--- ---
r2c1 r2c2
Remove-NullProperties source code:
<#
.SYNOPSIS
Removes properties with $null values from custom-object copies of
the input objects.
.DESCRIPTION
Note that output objects are custom objects that are copies of the input
objects with copies of only those input-object properties that are not $null.
CAVEAT: If you pipe multiple objects to this function, and these objects
differ in what properties are non-$null-valued, the default output
format will show only the non-$null-valued properties of the FIRST object.
Use ... | ForEach-Object { Out-String -InputObject $_ } to avoid
this problem.
.NOTES
Since the output objects are generally of a distinct type - [pscustomobject] -
and have only NoteProperty members, use of this function only makes sense
with plain-old data objects as input.
.EXAMPLE
> [pscustomobject] #{ one = 1; two = $null; three = 3 } | Remove-NullProperties
one three
--- -----
1 3
#>
function Remove-NullProperties {
param(
[parameter(Mandatory,ValueFromPipeline)]
[psobject] $InputObject
)
process {
# Create the initially empty output object
$obj = [pscustomobject]::new()
# Loop over all input-object properties.
foreach($prop in $InputObject.psobject.properties) {
# If a property is non-$null, add it to the output object.
if ($null -ne $InputObject.$($prop.Name)) {
Add-Member -InputObject $obj -NotePropertyName $prop.Name -NotePropertyValue $prop.Value
}
}
# Give the output object a type name that reflects the type of the input
# object prefixed with 'NonNull.' - note that this is purely informational, unless
# you define a custom output format for this type name.
$obj.pstypenames.Insert(0, 'NonNull.' + $InputObject.GetType().FullName)
# Output the output object.
$obj
}
}
These answers didn't work for me in the case of importing an object from an Infoblox csv file. Some values were the empty string, but not null. Testing whether a property is true or not, seems to work better for me. And the result is an object.
$a = [pscustomobject]#{one='hi';two='';three='there'}
$prop = $a.psobject.Properties | where value | foreach name
$a | select $prop
one three
--- -----
hi there
You first get its properties (since Get-QADUser depends on AD schema, the properties list is dynamic) with get-member -type property, then filter out those that don't have \{.*(get).*\} in its definition (that is, they are not "gettable"), then enumerate the resultant list by name and filter out nulls.
$someone=Get-QADUser -Identity "SomeOne" -IncludeAllProperties
$members=$someone|get-member -type property| where {$_.definition -match '\{.*(get).*\}'}
foreach ($member in $members) {
if ($someone[$member.name] -ne $null) {
write-host $member.name $someone[$member.name]
}
}
I'm trying to use PowerShell Invoke-RestMethod on a ticketing system's API and then convert the output into a PowerShell object.
As an example when I use Invoke-RestMethod to get the properties of a ticket I get this.
$object = Invoke-RestMethod '[URI here]'
$object.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.Object
$object
EWREST_supported_user0='Yes';
EWREST_updater_team='Support Team';
EWREST_eng_id='CLT';
EWREST_testlabelsub='Test Label';
EWREST_time_created='17:21:03';
EWREST_cr_conversion_related_to='Support Case';
EWREST__1901_full_name='secuser Testuser1';
EWREST_summary='Ticket Title';
EWREST_i_would_like_to_reopen_my_ticket='No';
EWREST_assigned_team_leader='Agiloft Admin';
EWREST_id='183255';
EWREST_severity='Sev 4';
EWREST_problem_description='<div>This is an example of a ticket note that takes up multiple lines when read via API<\/div><div> <\/div><div>Example note info here<\/div><div> <\/div>
<div>Additional example note info here<\/div><div> <\/div><div>Even more note info here<\/div>';
EWREST_demo_data='No';
What I would like to be able to do is manipulate $object as an object by doing things like $object.EWREST_category and get "Networking". So I have been trying to figure out how to maniuplate $object which is just a string of attributes to a traditional PowerShell object with properties.
Can someone offer some pointers on how to go about that?
Since you already have a string with key/value pairs I'd just do a little cleanup (remove the single quotes and the semicolons), convert the string to a hashtable, then build a custom object from that:
$response = Invoke-RestMethod '[URI here]'
$props = $response -replace "'" -replace ';' | ConvertFrom-StringData
$object = New-Object -Type PSObject -Property $props
Edit: To mangle the multiline value into one line you can use another replacement with a negative lookbehind assertion ((?<!...)) that removes newlines only if they're not preceded by a single quote followed by a semicolon. However, since that same property contains other semicolons you also need to modify the semicolon replacement, so that it only removes semicolons if they're followed by a newline or the end of the string (using a positive lookahead assertion, (?=...)).
$props = $response -replace "(?<!';)`n" -replace "'" -replace ";(?=`n|`$)" |
ConvertFrom-StringData
Maybe next naive script could suffice?
$ob= "EWREST_supported_user0='Yes';
EWREST_category='Networking';
EWREST_updater_team='Admin Team';
EWREST_time_created='12:56:53';
EWREST_cr_conversion_related_to='Support Case';
" # this is that string
# transform string to an array:
$oba = $ob.Split("`r`n", [System.StringSplitOptions]::RemoveEmptyEntries)
$obah=#{} # create empty hash table
# and fill it from array then:
$oba | ForEach-Object {
$aux=$_.split('=;') # key / value pair
$obah[$aux[0]] = $aux[1] } # hash[key] = value
$obah.Keys # display hash table keys (only debug)
$obah.EWREST_time_created # hash table item use (example: property)
$obah['EWREST_category'] # hash table item use (another approach: index)