How can I find the 'sub properties' of an object in powershell? - powershell

I guess I just don't know the proper name of whatever I'm looking for, but this was probably asked a thousand times before.
I started PowerShell not long ago, and I'm struggling to understand where I can find the 'sub properties'(if you can call it those) of an object.
For instance, I was using the VMware PowerCLI, and was tried to figure out how I can find the IP address of a VM.
So for example, I was using the Get-VM command, and when I piped it into get member, I got the following:
PS C:\Users\eitan.rapaport> get-vm "*VRA*" | gm
TypeName: VMware.VimAutomation.ViCore.Impl.V1.VM.UniversalVirtualMachineImpl
Name MemberType Definition
---- ---------- ----------
ConvertToVersion Method T VersionedObjectInterop.ConvertToVersion[T]()
Equals Method bool Equals(System.Object obj)
GetClient Method VMware.VimAutomation.ViCore.Interop.V1.VIAutomation VIObjectCoreInterop.GetClient()
GetConnectionParameters Method VMware.VimAutomation.ViCore.Interop.V1.VM.RemoteConsoleVMParams RemoteConsoleVMIn..
GetHashCode Method int GetHashCode()
GetType Method type GetType()
IsConvertableTo Method bool VersionedObjectInterop.IsConvertableTo(type type)
LockUpdates Method void ExtensionData.LockUpdates()
ObtainExportLease Method VMware.Vim.ManagedObjectReference ObtainExportLease.ObtainExportLease()
ToString Method string ToString()
UnlockUpdates Method void ExtensionData.UnlockUpdates()
CoresPerSocket Property int CoresPerSocket {get;}
CustomFields Property System.Collections.Generic.IDictionary[string,string] CustomFields {get;}
DatastoreIdList Property string[] DatastoreIdList {get;}
DrsAutomationLevel Property System.Nullable[VMware.VimAutomation.ViCore.Types.V1.Cluster.DrsAutomationLevel] ..
ExtensionData Property System.Object ExtensionData {get;}
Folder Property VMware.VimAutomation.ViCore.Types.V1.Inventory.Folder Folder {get;}
FolderId Property string FolderId {get;}
Guest Property VMware.VimAutomation.ViCore.Types.V1.VM.Guest.VMGuest Guest {get;}
GuestId Property string GuestId {get;}
HAIsolationResponse Property System.Nullable[VMware.VimAutomation.ViCore.Types.V1.Cluster.HAIsolationResponse]..
HardwareVersion Property string HardwareVersion {get;}
HARestartPriority Property System.Nullable[VMware.VimAutomation.ViCore.Types.V1.Cluster.HARestartPriority] H..
Id Property string Id {get;}
MemoryGB Property decimal MemoryGB {get;}
MemoryMB Property decimal MemoryMB {get;}
Name Property string Name {get;}
Notes Property string Notes {get;}
NumCpu Property int NumCpu {get;}
PersistentId Property string PersistentId {get;}
PowerState Property VMware.VimAutomation.ViCore.Types.V1.Inventory.PowerState PowerState {get;}
ProvisionedSpaceGB Property decimal ProvisionedSpaceGB {get;}
ResourcePool Property VMware.VimAutomation.ViCore.Types.V1.Inventory.ResourcePool ResourcePool {get;}
ResourcePoolId Property string ResourcePoolId {get;}
Uid Property string Uid {get;}
UsedSpaceGB Property decimal UsedSpaceGB {get;}
VApp Property VMware.VimAutomation.ViCore.Types.V1.Inventory.VApp VApp {get;}
Version Property VMware.VimAutomation.ViCore.Types.V1.VM.VMVersion Version {get;}
VMHost Property VMware.VimAutomation.ViCore.Types.V1.Inventory.VMHost VMHost {get;}
VMHostId Property string VMHostId {get;}
VMResourceConfiguration Property VMware.VimAutomation.ViCore.Types.V1.VM.VMResourceConfiguration VMResourceConfigu..
VMSwapfilePolicy Property System.Nullable[VMware.VimAutomation.ViCore.Types.V1.VMSwapfilePolicy] VMSwapfile..
As you can see, nothing mentions anything about IP.
I was researching this online, and have found that I should run the following command:
Get-VM | Select Name, #{N="IP Address";E={#($_.guest.IPAddress[0])}}
Which leads me to my question. How can I find the properties under a certain member/property of a command? How could I research the 'sub properties' of 'guest' in that example?

Okay, found it.
In that instance it would be get-vm "*VRA*" | select -ExpandProperty guest | gm

I've been dealing with this for the last two days, so I figured I'd share my solution:
First, I'm saving the VM object to a variable to make it easy to access without searching every time.
$vm = Get-vm -Name steve
To get all the properties of the VM Object
$vm | Select-Object *
If you just want to get the Name you can access it like this:
$vm.Name
If you want to get the Properties of the Guest Object (which is a property of the VM object):
$vm.Guest | Select-Object *
You can access the Properties of the Guest Object through the VM Object like this:
$vm.Guest.VmName
Want the IP addresses of the guest?
$vmip = $vm.Guest.IPAddress
And, because this took me a while to figure out, if that returns ipv4 and ipv6, and you want to filter out the ipv6:
$vmip = $vm.Guest.IPAddress | ?{$_ -notmatch ':'}

Another method of introspection in PowerShell is to just get the class name and then look it up in the API.
PS C:\> $Files = Get-ChildItem *.* -File
PS C:\> $Files[0].GetType().FullName
System.IO.FileInfo
You can then search for that class with either C# or PowerShell to find the API listing.
You can do a similar thing with the VMWare PowerCLI doc. The "all types" list on the left is a list of all the classes used by the module.

Related

Power Shell Output filter

I'm using the comand Get-AzresourceGroup. The ouput of that command is information about ResourID, Tags, Resource group name etc. of all resource groups in Azure. I want to store in a variable all the names of the resource groups, I do not need the other information. Is there a way I can do that?
Thank you!
Comand Output
From the Get-AzResourceGroup documentation, you can simply reference only the Resource Group Name :
$groups = (Get-AzResourceGroup).ResourceGroupName
Or using the CLI, and extracting from the JSON:
$group = az group list | ConvertFrom-Json
$group | Select-Object -Property Name
Try piping the output from Get-AzResourceGroup to Select-Object and use the -Property parameter to specify the property/properties to select.
$rgs = Get-AzResourceGroup | Select-Object -Property ResourceGroupName
Your will results should look something like this.
$rgs
ResourceGroupName
-----------------
ddo-06212021-1
ddo-06212021-2
ddo-06212021-3
cloud-shell-storage-eastus
If you're unsure what properties are available to select from the results of Get-AzResourceGroup, you can first pipe the output to Get-Member, and view the available properties.
Get-AzResourceGroup | Get-Member
TypeName: Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels.PSResourceGroup
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Location Property string Location {get;set;}
ManagedBy Property string ManagedBy {get;set;}
ProvisioningState Property string ProvisioningState {get;set;}
ResourceGroupName Property string ResourceGroupName {get;set;}
ResourceId Property string ResourceId {get;set;}
Tags Property hashtable Tags {get;set;}
TagsTable Property string TagsTable {get;}
Links
Select-Object - learn.microsoft.com
Get-Member - learn.microsoft.com

Powershell Get-EventLog find event with the matching string in its message

I need to look through eventLog security ID 4648, and find the last time the user connected to the machine.
Currently this is my code:
$Values = invoke-command -ComputerName $ComputerName {Get-EventLog -LogName Security -InstanceID 4648 | Select-Object -ExpandProperty Message| ForEach-Object {if($_.Log -match "$String2"){
$_
Break }}}
$Values
The aim was to go through each log until a log where the message has the previously defined username is found, and then stop going through EventLog and return that log.
This is working well, except its not matching the correct log with the specified string.
Is there a way to improve how the matching works? So it actually finds the correct log with the specified user?
# Fill in the regex for the userName
$userName = "userName"
$Values = #(invoke-command -ComputerName $ComputerName {
Get-EventLog -LogName Security -InstanceID 4648 | Where-Object { $_.message -match $Using:userName } | Select-Object -First 1)
}
Your above sample won't work since message is of type string, therefore it doesn't have a Log property. Since we want $userName to be avaiable for read access on the remote machine we can use the $Using: syntax. To break the pipeline "iteration" I'm using Select-Object -First 1 which will return the first object passing the Where-Objectclause.
Resulting from that $Values points to a collection of (deserialized) objects (using the #() operator) of type:
TypeName: System.Diagnostics.EventLogEntry#Security/Microsoft-Windows-Security-Auditing/4648
Which means you can change the -First parameter to e.g. 10 and sort the result on the client machine:
$Values | sort TimeGenerated -Descending
If you want to know which properties are available you can use:
> $Values | gm
TypeName: System.Diagnostics.EventLogEntry#Security/Microsoft-Windows-Security-Auditing/4648
Name MemberType Definition
---- ---------- ----------
Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs)
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
Dispose Method void Dispose(), void IDisposable.Dispose()
Equals Method bool Equals(System.Diagnostics.EventLogEntry otherEntry), bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetObjectData Method void ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
ToString Method string ToString()
Category Property string Category {get;}
CategoryNumber Property int16 CategoryNumber {get;}
Container Property System.ComponentModel.IContainer Container {get;}
Data Property byte[] Data {get;}
EntryType Property System.Diagnostics.EventLogEntryType EntryType {get;}
Index Property int Index {get;}
InstanceId Property long InstanceId {get;}
MachineName Property string MachineName {get;}
Message Property string Message {get;}
ReplacementStrings Property string[] ReplacementStrings {get;}
Site Property System.ComponentModel.ISite Site {get;set;}
Source Property string Source {get;}
TimeGenerated Property datetime TimeGenerated {get;}
TimeWritten Property datetime TimeWritten {get;}
UserName Property string UserName {get;}
EventID ScriptProperty System.Object EventID {get=$this.get_EventID() -band 0xFFFF;}
Hope that helps.

Trying to combine two cmdlets and output to an excel spreadsheet

I'm new to this forum and I apologize if I may have left anything out.
I'm trying to combine two cmdlets(Get-cdmGroupProfile and get-adgroupmember) and get the results(Get-cdmGroupProfile(returns groups from an application called Centrify ) and Get-adgroupmember(which gets group members from the from the cmdlets exported to an excel spreadsheet.
From what I have read ,not all cmdlets can be accept piped input and that is where the need for calculated properties comes in.
I have done this a couple times before( included script at the very bottom of the posting) where I created a calculated property and
was able to get the exported results in an Excel spreadsheet.
However when I tried the code I used before ,it didn't give me the results I was looking for.
After doing some more research I tried to use the calculated properties as such below and then pass it to the select object.
The script just keeps running and doesn't appear to stop. I removed the result variable that I assigned the foreach loop to and removed it the result from being piped into the excel spreadsheet and noticed the results weren't exactly what I wanted.
I was hoping to maybe find a more efficient way of doing this.
I was able to get it exported to an excel spreadsheet ,but it just shows the results from the array which repeats the values ,but doesn't list them like I would like.
I would like the following script to output the following information below
Zonename AD Linux Group Centrify group
PROD ZONE Group1 Group A
PROD ZONE Group2 Group B
TEST ZONE GROUP5 GROUP D
$list = Import-Csv C:\Users\User1\Desktop\Centrify\Inputpega.csv
$result = foreach($item in $list) {
$adgroupmember = Get-ADGroupMember -Identity $item.Group
$centrifygprofile = Get-CdmGroupProfile -Zone $item.DistinguishedName
Get-CdmGroupProfile -Zone $item.DistinguishedName |%{
Get-ADGroupmember -identity $item.Group
$Properties = #(
#{Name='ZoneName';Expression={$centrifygprofile.Zone}},
#{Name=' Centrify Group';Expression={$centrifygprofile.name}},
#{Name='AD Linux GROUP' ;Expression={$adgroupmember.name}},
)
$result | Export-Csv C:\Users\User1\Desktop\Results\results4.csv -
NoTypeInformation
Results that I'm getting -
ZoneName : {OU=TEST ZONE ,OU=TEST Zone
One,OU=Zones,OU=TEST,DC=TEST,DC=com,OU=PROD ZONE,OU=PROD Zone
One,OU=Zones,OU=PROD,DC=PROD,DC=com,
OU=PROD ZONE,OU=PROD Zone
One,OU=Zones,OU=PROD,DC=PROD,DC=com,OU=Unix,DC=PRODk,DC=com, OU=PROD
ZONE,OU=PROD Zone One,OU=Zones,OU=PROD,DC=PROD,DC=com...}
Centrify Group : {group1#prod.com, group2#prod.com, group3#prod.com,
group4#prod.com...}
PROD_GROUPS,OU=Zones,OU=PROD,OU=PROD,OU=PROD,DC=PROD,DC=com
AD Linux Group : {group6, group7, group8, group9...
ZoneName : {OU=TEST ZONE ,OU=TEST Zone
One,OU=Zones,OU=TEST,DC=TEST,DC=com,OU=PROD ZONE,OU=PROD Zone
One,OU=Zones,OU=PROD,DC=PROD,DC=com,
OU=PROD ZONE,OU=PROD Zone
One,OU=Zones,OU=PROD,DC=PROD,DC=com,OU=Unix,DC=PRODk,DC=com, OU=PROD
ZONE,OU=PROD Zone One,OU=Zones,OU=PROD,DC=PROD,DC=com...}
Centrify Group : {group1#prod.com, group2#prod.com, group3#prod.com,
group4#prod.com...}
PROD_GROUPS,OU=Zones,OU=PROD,OU=PROD,OU=PROD,DC=PROD,DC=com
AD Linux Group : {group6, group7, group8, group9...
This is a script I have used multiple before where I was able to combine multiple commands and export the data I wanted to an excel spreadsheet by using calculated properties.
$list = Import-Csv C:\Users\user\Desktop\dn2.csv
$finalzpa = Foreach($item in $list){
$zonezpa = Get-CdmZpaSetting -Zone $item.DistinguishedName
$zoneset = Get-CdmZone -dn $item.DistinguishedName
Get-CdmZone -Dn $item.DistinguishedName | %{
Get-CdmZpaSetting -Zone $item.DistinguishedName |
Select-Object #{Name='Userenabled';Expression={$zonezpa.UserEnabled}},
#{Name='Provisioning Groups enabled';Expression=
{$zonezpa.GroupEnabled}},
#{Name='ZoneName' ;Expression={$zoneset.Name}},
#{Name='User Source';Expression={$zonezpa.UserSource}},
#{Name='Group Source';Expression={$zonezpa.GroupSource}},
#{Name='Distinguished Name';Expression=
{$item.DistinguishedName}}
}}
$finalzpa | Export-Csv -Append -NoTypeInformation
C:\Users\Desktop\zonesautoinfo.csv
$adgroupmember | gm
TypeName: Microsoft.ActiveDirectory.Management.ADPrincipal
Name MemberType Definition
---- ---------- ----------
Contains Method bool Contains(string propertyName)
Equals Method bool Equals(System.Object obj)
GetEnumerator Method System.Collections.IDictionaryEnumerator
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Item ParameterizedProperty
Microsoft.ActiveDirectory.Management.ADPropertyValueCollection Item(string
propertyName) {get;}
distinguishedName Property System.String distinguishedName
{get;set;}
name Property System.String name {get;}
objectClass Property System.String objectClass {get;set;}
objectGUID Property System.Nullable`1[[System.Guid,
mscorlib, Version=4.0.0.0, Culture=neutral,
objectGUID {get;set;}
SamAccountName Property System.String SamAccountName
{get;set;}
SID Property
System.Security.Principal.SecurityIdentifier SID {get;set;}
$centrifygprofile | gm
TypeName: Centrify.DirectControl.PowerShell.Types.CdmGroupProfile
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
CanonicalName Property string CanonicalName {get;}
Computer Property
Centrify.DirectControl.PowerShell.Types.CdmManagedComputer Computer {get;}
Domain Property string Domain {get;}
Gid Property System.Nullable[long] Gid {get;}
Group Property
Centrify.DirectControl.PowerShell.Types.CdmGroup Group {get;}
IsHierarchical Property bool IsHierarchical {get;}
IsMembershipRequired Property System.Nullable[bool] IsMembershipRequired
{get;}
IsOrphan Property bool IsOrphan {get;}
IsSfu Property bool IsSfu {get;}
Name Property string Name {get;}
PreferredServer Property string PreferredServer {get;}
Zone Property
Centrify.DirectControl.PowerShell.Types.CdmZone Zone {get;}

FilterScript in PowerShell

I'm using Windows Server 2012 R2 with PowerShell v5 and I've stumbled on some PowerShell behaviour I don't understand.
The following line working correctly and returning results as expected:
Get-WindowsFeature | where -Property "InstallState" -eq "Installed"
This working correctly and returning results as previous:
Get-WindowsFeature | where {$_.Installed}
The following is NOT working, even though it should:
Get-WindowsFeature | where {$_.Available}
But this one is working:
Get-WindowsFeature | where -Property "InstallState" -eq "Available"
I've seen the same behaviour with PowerShell v3 on Windows 7 as well.
Please explain it to me.
Get-WindowsFeature | Get-Member -MemberType Property
TypeName: Microsoft.Windows.ServerManager.Commands.Feature
Name MemberType Definition
---- ---------- ----------
AdditionalInfo Property hashtable AdditionalInfo {get;}
BestPracticesModelId Property string BestPracticesModelId {get;}
DependsOn Property string[] DependsOn {get;}
Depth Property int Depth {get;}
Description Property string Description {get;}
DisplayName Property string DisplayName {get;}
EventQuery Property string EventQuery {get;}
FeatureType Property string FeatureType {get;}
Installed Property bool Installed {get;}
InstallState Property Microsoft.Windows.ServerManager.Commands.InstallState InstallState {get;}
Name Property string Name {get;}
Notification Property Microsoft.Windows.ServerManager.ServerComponentManager.Internal.Notification[] Notification {g...
Parent Property string Parent {get;}
Path Property string Path {get;}
PostConfigurationNeeded Property bool PostConfigurationNeeded {get;}
ServerComponentDescriptor Property psobject ServerComponentDescriptor {get;}
SubFeatures Property string[] SubFeatures {get;}
SystemService Property string[] SystemService {get;}
There is no "Available" property.

How do you add a property to a function object on the PowerShell PSDrive "function:"?

I've attempted using the $function:foo value and get-item function:foo. All attempts succeed in modifying the temporary function object, but the additional property is missing when reassigned to the stored function (either through $function:foo = ... or set-item function:foo ...).
Here are the results of my attempts (all fail):
Setup
$=>function foo { "foo" }
$=>$f = $function:foo
$=>$f = $f | add-member noteproperty bar BARvalue -pass
$=>$f | gm b*
TypeName: System.Management.Automation.ScriptBlock
Name MemberType Definition
---- ---------- ----------
bar NoteProperty System.String bar=BARvalue
#1
$=>set-item function:f $f -force
$=>$function:foo | gm b*
>
#2
$=>$function:f = $f
$=>$function:foo | gm b*
>
#3
$=>$f = get-item function:foo
$=>$f | gm
TypeName: System.Management.Automation.FunctionInfo
Name MemberType Definition
---- ---------- ----------
Equals Method System.Boolean Equals(Object obj)
GetHashCode Method System.Int32 GetHashCode()
GetType Method System.Type GetType()
ToString Method System.String ToString()
PSDrive NoteProperty System.Management.Automation.PSDriveInfo PSDrive=Function
PSIsContainer NoteProperty System.Boolean PSIsContainer=False
PSPath NoteProperty System.String PSPath=Microsoft.PowerShell.Core\Function::foo
PSProvider NoteProperty System.Management.Automation.ProviderInfo PSProvider=Microsoft....
CmdletBinding Property System.Boolean CmdletBinding {get;}
CommandType Property System.Management.Automation.CommandTypes CommandType {get;}
DefaultParameterSet Property System.String DefaultParameterSet {get;}
Definition Property System.String Definition {get;}
Description Property System.String Description {get;set;}
Module Property System.Management.Automation.PSModuleInfo Module {get;}
ModuleName Property System.String ModuleName {get;}
Name Property System.String Name {get;}
Options Property System.Management.Automation.ScopedItemOptions Options {get;set;}
Parameters Property System.Collections.Generic.Dictionary`2[[System.String, mscorli...
ParameterSets Property System.Collections.ObjectModel.ReadOnlyCollection`1[[System.Man...
ScriptBlock Property System.Management.Automation.ScriptBlock ScriptBlock {get;}
Visibility Property System.Management.Automation.SessionStateEntryVisibility Visibi...
$=>$f = $f | add-member noteproperty bar barValue -pass
$=>$f | gm b*
TypeName: System.Management.Automation.FunctionInfo
Name MemberType Definition
---- ---------- ----------
bar NoteProperty System.String bar=barValue
$=>set-item function:foo $f
$=>$function:foo | gm b*
>
Not sure what I'm doing wrong. It seems like the properties are being stripped out when reassigned. Is that correct? the defined behavior? I haven't seen any documentation saying that FunctionInfo objects or ScriptBlocks are treated unusually. Is this some esoteric corner of the language?
My first thought is when you are attaching this property to an object, you are attaching it to a specific instance of that object. When your variable losses the reference to that object, any knowledge of that new property is lost.
My guess is the next time you get that item, you are creating a new FunctionInfo object with foo's properties (as stored in the function provider).
When you call Get-Item or Get-ChildItem, it returns object references to the .NET types that represent the underlying items. Those items do not exist in memory indefinitely (imagine a FileInfo object for every file on every local drive and every mapped drive living in memory.. ouch). Since PowerShell is creating a new instance every time you call Get-Item, you are getting the basic FunctionInfo object.
If you want to add a property to all items of a particular type, you can with PowerShell's extensible type system. You can create a custom .ps1xml file and load that into a PowerShell session that can add a property to every instance of a type. Some great examples on the PowerShell Team Blog are here -> Hate Add-Member and Leveraging the PowerShell Type Extensions to Get Documentation.
EDIT (addressing comment): I understand what you are trying to do, but the failure is due to the new property being "grafted" on to a PSObject wrapper that allows for the on-the-fly addition of properties. The new property is never really part of that FunctionInfo object that you are retrieving from the PSDrive.
In addition, the function provider (the function: psdrive), does not have a mechanism for storing that additional property. It knows and works with FunctionInfo objects. When you ask for an item from the Function: PSDrive, the Function provider returns a FunctionInfo object. When you save a function to the Function: PSDrive, the provider can only store values for properties it knows how to handle. One could write a custom provider that would handle new properties from the PSObject wrapper, but that is not part of the default functionality in this provider.
EDIT #2: Ok, this has been bugging me. I blogged about a workaround.