What is the purpose of putting Class after your variable like this ($_.Class)? - powershell

What is the purpose of this string? I am still new to PowerShell and have seen this come up quiet a bit.
$_.Class
Here is an example of how I have seen it used:
$R.AllElements|?{$_.Class -eq "table"}|select innerText
Does this meant that we are applying a class on the $R variable? Or is there a "Class" already for that variable that we are searching for the string "table"? I have looked around but cannot find any explanation.

Here's an example for you to understand the purpose of $_.xxxxx
$Obj = Get-Item -Path 'C:\Program Files'
This would put any information gathered by the Get-Item command and store it in $Obj. If you then show what's in the variable, it will look something like this
If you would then do $obj.xxx where xxx is one of the property names shown above, it will show you the values under that property like this
Another way to get the values of said properties is how you have shown in your post. If you pipe the variable into a where statement like below, it is especially helpful when trying to filter out some text inside a particular variable. This example is looking for the text prog in the Name property of all the items inside of $Obj2
I wish I had time to give more details, I hope this helps you some! PowerShell is one of the best tools for Automation and Administration in a Windows environment so keep on learnin!
Bonus: Here is a link to documentation on PowerShell's pipelines and how it works, I referred to it as 'pipe' in my wordage above

Related

Is there an easy way to have Powershell always show the actual value?

These things drive me nuts:
Is there an easy way to have Powershell just show me the empty string and the list with an empty string in it?
For a while I am maintaining a ConvertTo-Expression which converts an (complex) object into a PowerShell expression which eventually can be used to rebuild most objects. It might useful in situations as comparing test results but also to reveal objects. For details see: readme.
Source and installation
The ConvertTo-Expression script can be installed from the PowerShell Gallery:
Install-Script -Name ConvertTo-Expression
As it concerns a standalone script, installation isn't really required. If you don't have administrator rights, you might just download the script (or copy it) to the required location. You might than simply invoke the script using PowerShell dot sourcing:
. .\ConvertTo-Expression.ps1
Example
The following command outputs the same expression as used to build the object:
$Object = [Ordered]#{
'Null' = $Null
'EmptyString' = ''
'EmptyArray' = #()
'SingleItem' = ,''
'EmptyHashtable' = #{}
}
ConvertTo-Expression $Object
Note the comment from #Mathias there's no functional difference between "one string" and "an array of one string", the pipeline consumes 1 string either way. PowerShell is not node which is described here: PowerShell enumerate an array that contains only one inner array. Some objects might be really different than you expect.
See also: Save hash table in PowerShell object notation (PSON)
This is PowerShell, not Node. So it's not JavaScript or JSON. Also, PowerShell is not Bash or CMD any other regular text-based shell. PowerShell works with objects. .NET objects, in particular. And how objects are represented as text is ... quite a matter of taste. How to represent null? Of course: nothing. How to represent an empty string? Nothing, either. An empty array ... you get my point.
All pipeline output is by default send to Out-Default. In general, the way objects are represented can be controlled by format files: about_Format.ps1xml and about_Types.ps1xml. From PowerShell 6 upwards, the default formats are compiled into the source code, but you can extend them. How you do so, depends on your personal taste. Some options were already mentioned ConvertTo-Json "", ConvertTo-Json #("")), but this would be veryyy JSON-specific.
tl;dr Don't care too much about how objects are represented textually. As you see, there are many possible ways to do so, and also some others. Just make sure your scripts are always object-oriented.
You mean like Python's repr() function? A serialization? "Give me a canonical representation of the object that, when property evaluated, will return an object of the type originally passed?" No, that's not possible unless you write it yourself or you serialize it to XML, JSON, or similar. That's what the *-CliXml and ConvertTo-*/ConvertFrom-* commands are for.
On Powershell 7:
PS C:\> ''.Split(',') | ConvertTo-Json -Compress -AsArray
[""]
PS C:\> '1,2,3,,5'.Split(',') | ConvertTo-Json -Compress -AsArray
["1","2","3","","5"]
The closest would be the ToString() common method. However, that's intended for formatting output and typecasting, not canonical representations or serializations. Not every object even has a string representation that can be converted back into that object. The language isn't designed with that in mind. It's based on C#, a compiled language that favors binary serializations. Javascript requires essentially everything to have a string serialization in order to fulfill it's original design. Python, too, has string representations as fundamental to it's design which is why the repr() function is foundational for serialization and introspection and so on.
C# and .Net go the other way. In a .Net application, if you want to specify a literal empty string you're encouraged to use String.Empty ([String]::Empty in Powershell) because it's easier to see that it's explicit. Why would you ever want a compiled application to tell the user how the canonical representation of an object in memory? You see why that's not a useful thing for C# even if it might be for Powershell?

How to get the target path to a lnk-file with powershell [duplicate]

I have a bunch of .lnk files and need to treat them differently depending on the target that the shortcut points to. I've found very little of how to this with other languages, but nothing about doing this with powershell.
I've tried this:
$sh = New-Object -COM WScript.Shell
$target = $sh.CreateShortcut('<path>').Target
But this returns an empty string even though I can see in the .lnk properties that the Target is specified.
Any idea on how to accomplish this?
You have made an error in the property; as wOxxOm suggests, you should be using TargetPath rather than Target:
$sh = New-Object -ComObject WScript.Shell
$target = $sh.CreateShortcut('<full-path-to-shortcut>').TargetPath
Google and MSDN were indeed helpful here; additionally, piping objects to Get-Member can often be useful and educational. This question also shows how to manipulate shortcuts using PowerShell, and uses the same technique as seen here.
If you want the arguments to the executable as well, those are stored separately:
$arguments = $sh.CreateShortcut('<full-path-to-shortcut>').Arguments
Again, piping objects to Get-Member - in this case, the object returned by WScript.Shell.CreateShortcut() - provides useful information.
It should be noted that there are issues with using this technique and these calls when the path contains Unicode emoji characters; there is a workaround for this case in this StackOverflow question.
It may seem obvious to experts but to us simpletons there seems to be a key lightbulb moment here:
<full-path-to-shortcut> = the Full Name! Doh!
Make sure you use .FullName if you use Get_ChildItem | ForEach-Object, etc. with the Shell .CreateShortcut call if you want the current target of a shortcut. For me:
.CreateShortcut($_.FullName) returned an appropriate value; whereas
.CreateShortcut($_) returned 'null'

Get all references to a given PowerShell module

Is there a way to find a list of script files that reference a given module (.psm1)? In other words, get all files that, in the script code, use at least 1 of the cmdlets defined in the module.
Obviously because of PowerShell 3.0 and above, most of my script files don't have an explicit Import-Module MODULE_NAME in the code somewhere, so I can't use that text to search on.
I know I can use Get-ChildItem -Path '...' -Recurse | Select-String 'TextToSearchFor' to search for a particular string inside of files, but that's not the same as searching for any reference to any cmdlet of a module. I could do a search for every single cmdlet in my module, but I was wondering if there is a better way.
Clarification: I'm only looking inside of a controlled environment where I have all the scripts in one file location.
Depending on the scenario, the callstack could be interesting to play around with. In that case you need to modify the functions which you want to find out about to gather information about the callstack at runtime and log it somewhere. Over time you might have enough logs to make some good assumptions.
function yourfunction {
$stack = Get-PSCallStack
if ($stack.Count -gt 1) {
$stack[1] # log this to a file or whatever you need
}
}
This might not work at all in your scenario, but I thought I throw it in there as an option.

How to change default output Formatting of Powershell to use Format-Table -autosize?

How can I enforce powershell to use
Format-Table -auto
as a default formatting when writing a returned array of objects to the console?
Thanks
If you are OK calling the cmdlet every time and if you have at least PowerShell v3.0 then you can set a $PSDefaultParameterValues which you can read more about at about_Parameters_Default_Values.
The syntax that would satisfy your need would be:
$PSDefaultParameterValues=#{"<CmdletName>:<ParameterName>"="<DefaultValue>"}
So we add in the switch by setting it to $true.
$PSDefaultParameterValues = #{"Format-Table:Autosize"=$true}
To remove this you would have to do it much the same as you would a hashtable element
$PSDefaultParameterValues.Remove("Format-Table:Autosize")
From the aforementioned article here is some pertinent information as to how to deal with these.
$PSDefaultParameterValues is a preference variable, so it exists only in the session
in which it is set. It has no default value.
To set $PSDefaultParameterValues, type the variable name and one or more key-value pairs
at the command line.
If you type another $PSDefaultParameterValues command, its value replaces the original
value. The original is not retained.
To save $PSDefaultParameterValues for future sessions, add a $PSDefaultParameterValues
command to your Windows PowerShell profile. For more information, see about_Profiles.
Outside of that I am not sure as it would be difficult to change in a dynamic sense. You would want to be sure that data sent to the stream appears on screen in the same way that format-table -auto does but you would have to make sure that it does not affect data so that you could not capture it or send it down the pipe.
You are looking at creating custom output format files, like Frode F. talks about, then you would need to consider looking at about_Format.ps1xml but you would need to configure this for every object that you would want to display this way.
FileSystem.format.ps1xml, for example, would govern the output from Get-ChildItem. Format-Table is more dynamic and I don't think you can say just use Format-Table in that file.

Question about $profile.psextended

I found a powershell tip regarding $profile.psextended that returns all of the various Powershell profiles and their locations. Having never see that before I ran ($profile | get-member). psextended was not in the list of results.
Having access to some very helpful MVPs on another site I asked how the psextended property was found. Within minutes I got a reply that using ($profile | gm -View all) should do the trick. I tried this and still had no results matching what I was looking for. If you enter $profile. and keep hitting the tab button it scrolls through the possible matches. psextended is nowhere to be found. Am I losing my mind or just plain blind?
Any help would be appreciated as I do not want to frustrate or annoy the guy trying to help me.
Thanks.
--
Eric
Every object, once assigned to a variable, is wrapped in a special semi-transparent object called a PSObject. This is powershell's way of trying to level the playing field for the different types of things that be assigned to a variable. There are four "special" properties exposing different things for any given variable in powershell:
ps> $o = 1
ps> $o.psobject
...
ps> $o.psadapted
...
ps> $o.psextended
...
ps> $o.psbase
...
You can read about these properties over on:
Link
Sorry. This was answered by Shay Levy (http://blogs.microsoft.co.il/blogs/ScriptFanatic/) on another service. Posted here to close the topic.
$profile | get-member -Force
lists the result I was looking for and several more for me to check out.