Approaching cmdlets in a conceptual way,
How are they made? Are they compiled?
Is it the equivalent of a batch file for PowerShell? Is it a script or a binary?
What is the structure used for storing these cmdlets?
A PowerShell cmdlet is a compiled piece of .NET code, more precisely a single class if I am not mistaken. Cmdlets are kind of the "native" commands in PowerShell land, being able to handle object input and output as well as usually playing nice and well with the (object-based) pipeline.
Cmdlets have no direct representation in the file system, as they are not programs or similar. They exist solely within PowerShell. You can use the Get-Command cmdlet to query all available cmdlets, functions, etc.
You can write cmdlets with a .NET language, such as C#. With PowerShell v2 there is also the possibility to write so-called advanced functions which behave similarly to cmdlets and have comparable capabilities but are interpreted PowerShell code, instead of compiled classes. This may incur a run-time overhead.
This link may help in understanding powershell cmdlet:
http://www.powershellpro.com/powershell-tutorial-introduction/tutorial-powershell-cmdlet/
See Scripting with Windows PowerShell.
A PowerShell cmdlet is a user-created extension to the PowerShell scripting language. The Cmdlet itself is a .NET class extending from PSCmdlet. Usually, additional components are included with the cmdlet to provide help and registering the cmdlet.
A cmdlet allows you to access to all functions accessible through the .NET virtual machine. This can range from simple script aids to fully functional programs.
Related
9/10 times if you are trying to use the Invoke-Expression cmdlet, there is a better way. Building the arguments to a command dynamically? Use an array of arguments. Building the arguments to a cmdlet? Use splatting with an array or hashtable. Your command has a space in the path to it? Use the call operator (&).
This might seem open ended, but Invoke-Expression is an easily accessible cmdlet where the answer is almost always to never use it. But the cmdlet exists for a reason, is not deprecated, and most criticisms of its use state something similar to, "it's almost never the right answer", but never states when it is acceptable to use it. In what case is it acceptable to use Invoke-Expression? Or to word it a bit less openly, how was Invoke-Expression designed to be used?
To quote from a PowerShell team blog post titled Invoke-Expression considered harmful (emphasis added):
The bottom line: Invoke-Expression is a powerful and useful command for some scenarios such as creating new scripts at runtime, but in general, if you find yourself using Invoke-Expression, you should ask yourself, or maybe a respected colleague if there is a better way.
EBGreen notes:
Or to phrase it another way, It [Invoke-Expression] is ok to use as long as a user is never involved in any part of generating the string that will be invoked. But even then, not using it will enforce better habits than using it would.
In short:
As a matter of habit, always consider a different (usually more robust and secure) solution first.
If you do find that Invoke-Expression is your only choice, carefully consider the security implications: if a string from an (untrusted) outside source (e.g., user input) is passed directly to Invoke-Expression, arbitrary commands may be executed.
Therefore: Only use Invoke-Expression if you fully control or implicitly trust the input.
Note: As of Windows PowerShell v5.1 / PowerShell Core v6.1.0, the official Invoke-Expression help topic doesn't provide such guidance; this GitHub issue suggests rectifying that.
Rare examples of justified (safe) use of Invoke-Expression:
Creating PSv5+ custom classes dynamically:
so that the class can be used in a remote session.
so that the set of properties can be created based on conditions at runtime.
Using Invoke-Expression in combination with Write-Output:
to parse a string with embedded quoting, with extra precautions.
to parse command lines stored in a file, if trusted.
Using Invoke-Expression for nested property access:
via a property path stored in a string.
I've been trying to work with an API that only accepts raw text or base64 encoded values in a JSON object. The content I'm POSTing is data from an XML file. So I used Powershell's Get-Content cmdlet (without -Raw) to retrieve the data from the .xml and then base64 encode it and sent it to the API. The API then decodes it, but the XML formatting was lost.
I found a SO post about using the -Raw switch on Get-Content, but it seems like the documentation for this switch is vague. When I used the -Raw switch, encoded it and sent it back to the API, the formatting was good.
briantist's helpful comment on the question sums up the answer succinctly (in his words; lightly edited, emphasis added):
Get-Content [by default] reads a file line by line and returns an array of the lines. Using -Raw reads the entire contents of the file as a single string.
The name -Raw is tad unfortunate, because it mistakenly suggests reading raw bytes, whereas -Raw still detects encodings and ultimately reads everything into a .NET [string] type.
(By contrast, you need either -Encoding Byte (Windows PowerShell) or -AsByteStream (PowerShell Core) to read a file as a byte array.)
Given -Raw's actual purpose, perhaps something like -Whole would have been a better name, but that ship has sailed (though adding an alias name for a parameter is still an option).
Let's take a look at why this information may currently be difficult to discover [Update: It no longer is]:
[Update: This section is now OBSOLETE, except the link to the PowerShell documentation GitHub repository, which welcomes contributions, bug reports, suggestions]
A Tale of PowerShell Documentation Woes
The central conflict of this tale is the tension between the solid foundation of PowerShell's potentially great help system and its shoddy current content.
As is often the case, third parties come to the rescue, as shown in gms0ulman's helpful answer.
As briantist also points out, however, PowerShell's documentation is now open-source and welcomes contributions; he states:
"I will direct your attention to the Edit link
[for the Get-Content help topic on GitHub] [...] so you can actually fix it up and submit something better
(including examples). I have done it before; they do accept pull
requests for it."
The caveat is that while future PowerShell Core versions will benefit from improvements, it's not clear whether improvements will make their way back into Windows PowerShell.
Let's ask PowerShell's built-in help system, accessible via the standard Get-Help cmdlet (the content for which may not be preinstalled; install when prompted, or run Update-Help from an elevated session):
Get-Help Get-Content -Parameter Raw
Note how you can conveniently ask for help on a specific parameter (-Parameter Raw).
On Windows PowerShell v5.1, this yields:
-Raw
Ignores newline characters and returns the entire contents of a file in one string.
By default, the contents of a file is returned as a array of strings that is delimited
by the newline character.
Raw is a dynamic parameter that the FileSystem provider adds to the Get-Content cmdlet.
This parameter works only in file system drives.
This parameter is introduced in Windows PowerShell 3.0.
Required? false
Position? named
Default value
Accept pipeline input? false
Accept wildcard characters? false
That is indeed what we were looking for and quite helpful (leaving the awkward phrasing "delimited by the newline character" aside and that on Windows a newline is a character sequence).
On Powershell Core v6.0.2, this yields:
-Raw
Required? false
Position? Named
Accept pipeline input? false
Parameter set name (All)
Aliases None
Dynamic? true
While the meta-data is more detailed - including a hint that the parameter is dynamic (see below) - it is crucially missing a description of the parameter.
Some provider-cmdlet parameters are dynamic, in that they are specific to a given provider, so there is a mechanism to specify the target provider when asking for help, by passing a provider-specific example path to the -Path parameter.
In the case at hand, let's therefore try (PowerShell Core on Windows):
Get-Help Get-Content -Parameter Raw -Path C:\
Sadly, the result is the same unhelpful response as before.
Note that, as long as you're invoking the command from a filesystem location, explicit use of -Path should not be necessary, because the provider underlying the current location is implicitly targeted.
Now let's take a look at the online versions of PowerShell's help topics:
As it turns out, a given provider cmdlet can have multiple documentation pages:
A generic one that applies to all providers.
Provider-specific pages that document provider-exclusive behavior and parameters, such as -Raw for the filesystem provider.
Sadly, the generic topics make no mention of the existence of the provider-specific ones, making them hard to discover.
Googling Get-Content takes you to https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content, the generic topic, which contains the following misleading statement: This parameter is not supported by any providers that are installed with Windows PowerShell.
This is not only unhelpful, but actively misleading, because the PowerShell file-system provider clearly is installed with PowerShell and it does support -Raw.
[Drive] providers are PowerShell's generalization of the filesystem drive metaphor to support targeting other [typically hierarchical] storage systems with a unified set of cmdlets. For instance, Windows PowerShell also ships with the registry drive provider, which allows managing the registry as if it were a drive.
The -Online switch for Get-Help conveniently allows opening the online version of the requested topic in the browser; so let's try that (Get-Help Get-Content -Online):
Windows PowerShell v5.1: Takes you a 404 page(!) related to v4.
PowerShell Core v6.0.1: Takes you to the same generic topic that googling does.
There's a sliver of hope, however: The aforementioned 404 page offers a link to the filesystem-provider-specific topic:
Get-Content for FileSystem
It is there that we finally discover the online version of the truly relevant, provider-specific information, which is the same that Get-Help Get-Content -Parameter Raw provides locally, but - as stated - only in Windows PowerShell.
As per Kory Gill's comment and your own, the built-in Get-Help and MSDN documentation should be your first port of call. But you've already RTFM!
When that fails, ss64 is great reference for Powershell documentation and additional examples.
Get-Content page here. It has this to say about -Raw:
Return multiple lines as a single string (PowerShell 3.0)
In PowerShell 2.0 use the static method: [System.IO.File]::ReadAllText(string path)
While I did find a lot of information on how to name Cmdlets and functions in the Cmdlet Development Guidelines I did not find any information on whether functions should be named in upper or in lower case.
What is the convention here?
(I do understand that Cmdlets themselves are generally named in upper case, even though they are not case-sensitive when it comes to executing.)
Naming convention can be tricky. While a fixed naming convention may provide aesthetics or simplified usage, it is not required to be followed. In general, a naming convention that I advocate for is the one that is used already in Powershell. As functions are created on verb-noun base, each word starts with a capital letter or if it is an abbreviation - all capitals, or if it is a proprietary - then as it is accordingly.
I have, for example, created some functions for myself:
Get-ServerDiag
Mount-TrueCryptVolumes
Start-RDP
Generate-RandomPassword
Nuke-Environment
You can imagine what these functions do, it is rather clear, straightforward and compliant with built-in Powershell functions. I do however have exceptions which come from "importing" a several Unix commands to Powershell (like killall, pidof etc...) You can always use a Set-Alias if you prefer to write something else.
This question, however important, is discussable as there does not seem to be the 'one, best way'. It is all, in the end, up to personal preferences.
A function is mostly a script-based cmdlet. A cmdlet is written in ex. C#, while a function is written as a script. Because of this similarity, I recommend using the same style as cmdlets for my "standalone-functions" so that it blends in with the other PowerShell cmdlets. Ex. I had a filecount(per folder)-function that I used often. I called it Get-FileCount.
However, I usually name helper functions(functions you only use in other functions) using a simpler name like convertsidtousername etc.
You could use aliases to create short names for a function.
Is there any builtin functionality with Powershell that allows you to examine system processes in great detail, and view/manipulate its I/O stream? Are there any community modules? Has anybody worked with process streams and know of any good references for such work?
The standard cmdlets provided by powershell allows you basic operations on processes. Get-Process cmdlet returns all running processes objects with detailed information about the process. You can also get the modules that the process loaded using the parameter -Module. You can use start/stop process cmdlets to manage the list of running processes.
However, the returned objects give you all information you may search for. Get-Process returns objects as System.Diagnostics.Process, while Get-Process -Module returns objects as System.Diagnostics.ProcessModule.
Reading the Microsoft documentation for creating PowerShell Cmdlets, I notice there is no example code for F#; instead, there is a message saying that "This language is not supported or no code example is available.".
Is F# not supported for creating Cmdlets, or aren't there any examples in F#?
Take a look at this:
Writing PowerShell Cmdlets in F#. Not exactly a complete example of how to do this but it certainly seems to be possible to write cmdlets in F#.
EDIT:
There is a more extensive example here but the contextual information is a little bit out of date. Actually the contextual information is a bit out of date on both links but the first link is more recent.