Powershell - how to extract a value from Object[] - powershell

I'm trying to figure out how to grab the value associated with AzureWebJobsStorage variable from a Object[] in powershell. Here's the logic so far:
$azAppSettingsOutput = az functionapp config appsettings list --name somename --resource-group myResource --subscription subscription | ConvertFrom-Json
Write-Output $azAppSettingsOutput.GetType().name
Write-Output $azAppSettingsOutput | Get-Member
Write-Output $azAppSettingsOutput.name
This is the output I see:
PS C:\Users\me> .\test.ps1
Object[]
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
name NoteProperty string name=APPINSIGHTS_INSTRUMENTATIONKEY
slotSetting NoteProperty bool slotSetting=False
value NoteProperty string value=asdfasdf-asdf-asdf-asdf-asdf-asdf
APPINSIGHTS_INSTRUMENTATIONKEY
AzureWebJobsStorage
FUNCTIONS_EXTENSION_VERSION
FUNCTIONS_WORKER_RUNTIME
WEBSITE_RUN_FROM_PACKAGE
StorageTableName
PS C:\Users\me\>
I know I can loop through like this:
foreach($setting in $azAppSettingsOutput) {
Write-Output $setting.name
$value = $setting.value
And then I can add an if statement to check if the name matches "AzureWebJobsStorage" but just wondering if there's a simpler way.
Thanks.

Use the Where-Object cmdlet to filter your data:
$azAppSettingsOutput |Where-Object name -eq 'AzureWebJobsStorage'
This will filter out any objects except for those where the name property equals "AzureWebJobsStorage"

Related

Powershell how to find the property type of a registry item property

I've found several examples showing how to get, set, and create registry keys as well as their properties and values. I need to find what property type a registry key property has (DWord, String, Multistring etc.)
If I do Get-ItemProperty I can fetch the values of a property, like so:
PS C:\> Get-ItemProperty "HKLM:\SOFTWARE\MySoftware\MyKey\" -Name MyProperty
MyProperty : MyValue
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\MySoftware\MyKey\
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\MySoftware
PSChildName : MyValue
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
However, this does not tell me if the value of MyProperty is a string, a DWord, a multistring, or whatever else it might be. The only way I've found to get that information is to pipe it to Get-Member, because the Definition tells me what type it is:
PS C:\> Get-ItemProperty "HKLM:\SOFTWARE\MySoftware\MyKey\" -Name MyProperty | Get-Member
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
PSChildName NoteProperty string PSChildName=MyKey
PSDrive NoteProperty PSDriveInfo PSDrive=HKLM
PSParentPath NoteProperty string PSParentPath=Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\MySoftware
PSPath NoteProperty string PSPath=Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\MySoftware\MyKey\
PSProvider NoteProperty ProviderInfo PSProvider=Microsoft.PowerShell.Core\Registry
MyProperty NoteProperty string MyProperty=MyValue
I can then select the property value, split the string and fetch the first object, like so:
PS C:\> ((Get-ItemProperty "HKLM:\SOFTWARE\MySoftware\MyKey\" -Name MyProperty | Get-Member | Where-Object{$_.Name -eq "MyProperty"}).Definition -split " ")[0]
string
I verified that this gives int when I do this with a DWord attribute, but this just doesn't feel like the proper way of finding this information. Is there another, more proper or robust way to find what property type a specific registry key property has?
EDIT: I also just verified that both String and ExpandString return "string" here so there are edge cases where even the above solution does not work.
You can get the type of a property using the .GetType() method:
$value = (Get-ItemProperty 'HKLM:\SOFTWARE\MySoftware\MyKey' -Name MyProperty).MyProperty
$value.GetType().Name # outputs e. g. "String"
To explicitly test for a given type, use the -is operator:
$value -is [string] # outputs True if $value is a string
To see how each registry value type maps to a PowerShell type, I've created a registry key that contains values of all possible types and ran the following script:
$props = Get-ItemProperty "HKCU:\test"
$props.PSObject.Properties.Where{ -not $_.Name.StartsWith('PS') }.ForEach{
[pscustomobject]#{ 'Reg Type' = $_.Name; 'PS Type' = $_.Value.GetType() }
}
Output:
Reg Type PS Type
-------- -------
REG_DWORD System.Int32
REG_SZ System.String
REG_QWORD System.Int64
REG_BINARY System.Byte[]
REG_MULTI_SZ System.String[]
REG_EXPAND_SZ System.String
As you can see both REG_SZ and REG_EXPAND_SZ map to System.String, so you can't differentiate these when you read them using Get-ItemProperty. Instead you would have to use the .NET method RegistryKey.GetValueKind():
$key = Get-Item 'HKLM:\SOFTWARE\MySoftware\MyKey' # $key is of type RegistryKey
$key.GetValue('MyProperty') # Output the value
$key.GetValueKind('MyProperty') # Output the registry type of the value
This outputs "ExpandString" for registry type REG_EXPAND_SZ. For other possible values see RegistryValueKind enum.

Parsing strings before character in Powershell

I want to obtain the environment, project name and location from a string and store it in a variable in Powershell.
The string is in the format of env-project-location. Exampleuat-hrapp-westeurope
How do I filter the string and store the outputs in a variable?
$environment = "uat"
$project = "hrapp"
$location = "westeurope"
You don't need regex for this, assuming the string will always have the same naming convention a simple split would do it:
$environment, $project, $location = 'uat-hrapp-westeurope'.Split('-')
Santiago Squarzon's post got me thinking so I did a little googling and found that you can also use this method if you want a PSCustomObject vs independent variables.
Clear-Host
$Base = "uat-hrapp-westeurope"
$CFSArgs = #{PropertyNames = "Environment", "Project", "Location"
Delimiter = '-'}
$obj = $Base | ConvertFrom-String #CFSArgs
$Obj
Output:
Environment Project Location
----------- ------- --------
uat hrapp westeurope
PS> $obj | gm
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Environment NoteProperty string Environment=uat
Location NoteProperty string Location=westeurope
Project NoteProperty string Project=hrapp

Get upgrade code for product code from registry

I need a hint how to get the upgrade code from an installed MSI out of the registry. Actually I'm having the product code, which can be retrieved from HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\.
Now I want to retrieve the upgrade code (based on the product code) from HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes.
My problem is that the product code is used as value-name, which means I've a REG_SZ where the name is the product code guid and the value is empty.
One way to retrieve the product code might be:
PS HKLM:\SOFTW...Codes> Get-ItemProperty * | select -First 1 | gm
TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
42F79228D77BA4A4EB5150F3DC090CE3 NoteProperty System.String 42F79228D77BA4A4EB5150F3DC090CE3=
...
How can I check if a PSCustomObject has the property 42F79228D77BA4A4EB5150F3DC090CE3?
Does anybody knows if there is a more elegant way?
This is how you can check. Working on that elegant solution...
$properties = Get-ItemProperty * | select -first 1 | Get-Member | Where-object {$_.MemberType -eq "NoteProperty"}
if("42F79228D77BA4A4EB5150F3DC090CE3" -in $properties.Name){
Write-Output "It's in there!"
}
Edit
This is a bit more elegant. It goes to the HKLM path, and checks for a PSChildName (Registry Key) that is the same as the code.
If found, it will return the Name and property. If not found, the variable $codeExists will be $null.
$code = "42F79228D77BA4A4EB5150F3DC090CE3"
$codeExists = Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UpgradeCodes" | Where-Object {$_.PSChildName -eq $code}
if($codeExists){
Write-Output "It's in there!"
}

powershell outputs argument with (#{Name=name}:String)

I'm trying to run the command Get-VMNetworkAdapter on a list of VMs
I'm getting the list with the command:
Get-VM –ComputerName (Get-ClusterNode –Cluster clustername)|select name
and it looks fine, when I'm using
$vmm=Get-VM –ComputerName (Get-ClusterNode –Cluster clustername)|select name
foreach ($item in $vmm)
{Get-VMNetworkAdapter -VMName $item}
it gives me the exception
nvalidArgument: (#{Name=vmname}:String)
like it adds all those symbols..
What is the proper way to lose them?
You need to expand the property. Select doesn't remove the object otherwise:
$vmm = Get-VM –ComputerName (Get-ClusterNode –Cluster clustername) `
| Select-Object -ExpandProperty name
To explain what -ExpandProperty does:
First of all, the drawback of -ExpandProperty is that you can only do it to one property at a time.
Select-Object normally wraps the results in another object so that properties remain properties. If you say $x = Get-ChildItem C:\Windows | Select-Object Name, then you get an object array with one property: Name.
PS C:\> $x = Get-ChildItem C:\Windows | Select-Object Name
PS C:\> $x
Name
----
45235788142C44BE8A4DDDE9A84492E5.TMP
8A809006C25A4A3A9DAB94659BCDB107.TMP
.
.
.
PS C:\> $x[0].Name
45235788142C44BE8A4DDDE9A84492E5.TMP
PS C:\> $x[0].GetType().FullName
System.Management.Automation.PSCustomObject
Notice the header? Name is a property of the object.
Also, the base object with it's type is still kind of there:
PS C:\> $x | Get-Member
TypeName: Selected.System.IO.DirectoryInfo
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Name NoteProperty string Name=45235788142C44BE8A4DDDE9A84492E5.TMP
TypeName: Selected.System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Name NoteProperty string Name=bfsvc.exe
Normally, that's all great. Especially because we normally want multiple properties of the object.
Sometimes, however, not what we want. Sometimes, we want an array that's the same type as the property we selected. When we use it later we want just that property and nothing else and we want it to be the exact same type as the property and nothing else.
PS C:\> $y = Get-ChildItem C:\Windows | Select-Object -ExpandProperty Name
PS C:\> $y
45235788142C44BE8A4DDDE9A84492E5.TMP
8A809006C25A4A3A9DAB94659BCDB107.TMP
.
.
.
PS C:\> $y[0].Name
PS C:\> $y[0]
45235788142C44BE8A4DDDE9A84492E5.TMP
PS C:\> $y.GetType().FullName
System.Object[]
PS C:\> $y[0].GetType().FullName
System.String
Notice there's no header, and any calls to a Name property fail; there is no Name property anymore.
And, there's nothing left over from the original object:
PS C:\> $y | Get-Member
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Clone Method System.Object Clone(), System.Object ICloneable.Clone()
.
.
.
.
Basically, here it's the equivalent of doing this:
$z = Get-ChildItem C:\Windows | ForEach-Object { $_.Name }
Which I think is how you had to do it in PowerShell v1.0 or v2.0... it's been too many years since I've used that to remember right.

Store just the value of an object in a variable

I want to store just the value of a PowerShell object in a variable.
Example
If we run:
$time = Get-Process System | select TotalProcessorTime
$time
This is the current output:
TotalProcessorTime
------------------
00:03:22.8281250
This is the output I would like:
00:03:22.8281250
Discussion
How do we store just the value? If we run $time | Get-Member, we see that PowerShell has stored a Selected.System.Diagnostics.Process that has the following properties:
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
TotalProcessorTime NoteProperty System.TimeSpan TotalProcessorTime=00:03:22.8281250
I have tried getting the value by running both $time.TotalProcessorTime and $time.ToString() without success.
The Object which produces that string "00:03:22.8281250":
(Get-Process System).TotalProcessorTime
The string itself:
(Get-Process System).TotalProcessorTime.ToString()