Visual Studio Code: Powershell Greenhorn - powershell

My Code:
$a = $env:Path
$b = $a.Split(";")
Write-host $b
$a
$b
The automatic Help in Powershell advises me to
Surround with Enum, funtion ....
What am I advised to do ?
An explanation, some sample code could help
Thx in advance

VSCode suggests that you should surround $b[3] with a function because this is stuff that on first glance isn't that maintainable. I see you want the 3rd path of the path variable but don't know what exactly you are looking for, neither does anyone that will potentially maintain the script so you should wrap this line into something meaningfull.
Take this as an example:
function Get-VSCodePath
{
$paths = ($env:Path).Split(';')
$vsCodePath = $paths | Where-Object { ($_.Contains("VS Code") -eq $true) }
Write-Output $vsCodePath
}
$vscodePath = Get-VSCodePath
Write-Host $vscodePath
i wrapped my search for a specific path into a function with meaningfull name so whoever maintains the script will know what i searched for

It's not obvious from your screenshot, but the crucial aspect is that you've selected $b[3].
Whenever you select a multi-character range, Visual Studio's PowerShell extension offers you potentially useful actions, indicated by and accessible via the lightbulb icon:
You can click on the icon or use Control-. (period) to invoke the menu of available actions.
Actions of a general nature that are always presented pertain to surrounding (enclosing) the selected text with various constructs, such as shown in your screenshot.
This is a convenient way to make the selected text part of a larger language construct, such as an if statement or a function definition.
These actions are not prescriptive, i.e. it is up to you to decide whether any of the actions presented make sense in the context of what you're trying to do.

Related

How can I change the PowerShell prompt color?

I often find myself lost in a plethora of lines all looking the same. It's hard for me to tell the beginning of the output of my most recent commmand from the output of previous commands.
So, I'd like to change the color of my PowerShell prompt permanently from white text on black background to something else. How can I do this?
From my perspective, the prompt consists of two parts:
path
command
How can I change the color of any of both, but not changing the command's output color?
Alternatively, I'd also very much like to see the path part getting underlined. This would also help in finding my previous commands among lines of other output in order to see where the corresponding other output started. Is this possible?
EDIT
Some comments requested some elaboration on my question, so here's two screenshots depicting the actual/expected situation (note the red line):
actual
expected
I'd like to get this for PowerShell 5.x and Core.
So, do you think this is rather a feature request than a query for an existing feature?
After posting my question to the PowerShell team at GitHub, here's the answer to my question:
https://github.com/PowerShell/PowerShell/issues/11136
There's a prompt() hook function available that can be used to customize the prompt.
I found out that if you use Powershell 5.1, you could use some escaping characters from ASCII table in order to get underlined output:
Write-Host "Hello $([char]27)[4mWorld$([char]27)[24m"
Since Im hesitant that this works perfect, the best solution to underline specific text might be this way:
function Write-Underlined-Host([string]$text,[boolean]$ispath)
{
if ($ispath -eq $false)
{
Write-Host $text
}
else
{
$underline = '-'
$underline_count = $underline * $text.Length
Write-Host -Object $text
Write-Host -Object $underline_count
}
}
$my_path = 'c:\users\jime\desktop'
Write-Underlined-Host -text $my_path -ispath $true
If you look to change your powershell script editor colors (For example if you use ISE), you could change the color of all types.
In ISE:
Tools>Options>Script Pane Tokens: (See my attached picture)

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

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

Add auto complete features for switch in powershell

I am attempting to add auto-complete features in powershell. In this case I would like to be able to type "test" in my console. After that to be able to type Get-Se[TAB] to auto complete to Get-Search using TAB Expansion.
PS > Get-Se[TAB]
PS > Get-Search
function test
{
[CmdletBinding()]
param()
# label the while loop "outer"
:outer while($true){
$x = Read-Host
# split $x into two parts
$first,$second = $x -split '\s',2
# switch evaluating the first part
switch($first){
Get-Search {
# Searching
}
default {
Write-Host "False"
}
}
}
}
Additional Information:
Goal:
I'd like to be able to use arguments that look like cmdlets to have the Powershell feel.
About the original script:
I have created a script to automate queries from several API's, for many different users. What I have right now for search is "s" and I'd like it to be "Get-Search" So Read-Host waits for an input, the user would type "Get-Search 'value'" and a formatted JSON returns.
PS > Get-Search foobar
#Returns JSON
I had a hard time understanding your intention at first, but I think I get it now.
You want to implement tab completion (tab expansion) inside the Read-Host prompt.
Unfortunately, there is no way to do that.
If you share why you want this, there may be better ways to achieve your ultimate goal.
Based on your additional information, I have a different approach.
Create actual functions for each of your queries, like Get-Search, etc. You can even add aliases for them so that s corresponds directly if you want.
Wrap all of these functions in a proper module, so that you can import them (see next step).
Create a constrained runspace that only allows the user to execute the specific functions and aliases you want (this is easier with a module, but the module is not a requirement).
What this can do is give your end users access (even remotely) to a PowerShell session which can only use the functions you've created and allowed to be executed. Other cmdlets/functions and even language features like using variables will be restricted and unavailable.
That way, you get true PowerShell tab expansion and semantics, and you end up with a real set of functions that be used in an automated way as well.
You don't have to write any prompting or parsing.
Further, the session can be secured, allowing only specific users and groups to connect to it.

Finding the index of a key and value within an array using a wildcard in Powershell

I have been working on an issue and I was able to get done what I need to get done in a relatively decent and acceptable way but I am curious as to why I ran into some of the problems I did.
I'm not too savvy with PowerShell or C# but I have some experience with Java, C++, and a few others. So, if I overlook something really simple, you'll have to forgive me. I'm not looking for a critique of my solution, just some insight into some of the blockades I came across.
What I needed to do was use Powershell to query an LDAP setting. I needed to know MaxConnIdleTime and I needed that either assigned to a variable or accessible through a subroutine [sic] (ex $ldapPolicies.MaxConnIdleTime) so that I could run it through a conditional statement.
Here is how I accomplished it:
$ldap = Get-ADObject -SearchBase "CN=Query-Policies,CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=$ENV:COMPUTERNAME,DC=$dc" -Filter 'ObjectClass -like "queryPolicy"' -Properties ldapadminlimits
$ldap = #($ldap.ldapadminlimits)
$ldap | %{
if($_.startswith("MaxConnIdleTime")) {
$match = $_
}
}
I tried NTDSUtil.exe, however, I couldn't redirect the "Show Values" to a text file to read from later and I couldn't write it to a variable in PowerShell.
I tried Start-Transcript and then ran NTDSUtil but it only recorded what occurred within PowerShell and not what happened in NTDSUtil.
Also, I tried giving all of the commands to NTDSUtil at once (NTDSUtil "ldap policies" "connections" "connect to server $ENV:COMPUTERNAME" q "Show Values") but PowerShell doesn't show anything in the console and I have press the exit sequence to return back to PS>.
I know that I could use LDP but I'm not too familiar with ADSI. Research appeared to say that going about attempting to get an LDPdump is a bit antiquated and I pretty much abandoned that attempt.
One of the issues that I had that caused me a small bit of frustration (and the reason I am asking this question) is why can I not search an array and find the index of an item using a wildcard? I tried doing this:
$ldap.IndexOf("MaxConnIdleTime*")
AND
$ldap.IndexOf($ldap -like "MaxConnIdleTime*")
but it always returned -1.
It would work correctly if I tried:
$ldap.IndexOf("MaxConnIdleTime=100")
given that the value was indeed 100. But I am validating that the value was correct.
I know that I could just do something like this:
if($ldap -contains "MaxConnIdleTime=100") {
DO SOMETHING...
} else {
DO SOMETHING ELSE...
}
Why is it that I can't search an array using a wildcard operator? There was no ambiguity, so, it should have worked, right?
I'm not looking for a critique of how I accomplished this, I'm just wanting to understand why it behaved like it did.
Thanks.
I don't think there's a straightforward "search an array by wildcard and return an index" cmdlet, method, statement, etc. in PowerShell.
.IndexOf is not designed to work with a wildcard.
When you used the -like operator on the array, you likely found only a single matching object, but -like returns an array of matches when used on an array.
Passing the array into .IndexOf() then looks for an array element that is itself an array, even if that array only has one object.
This would work:
$ldap.IndexOf(($ldap -like "MaxConnIdleTime*")[0])
As long as you always wanted to find the first one.

Indent output from private functions in Powershell

I have a bunch of functions that I call that produce output that is displayed to the console. Functions might look something like the following:
exec { & .\xunit.console.clr4 tests.xunit }
#or
exec { & .\nuget.exe pack $source_dir\ZocMonLib\NuSpec\ZocMon.nuspec -OutputDirectory $build_dir\local -Symbols -Version $version }
Now I know I could do something like powershell indentation but that only works if I control the output.
How do I do the indenting of output for these private functions?
Ok, I wrote a version that does the line wrapping right. But it's slightly complicated. I posted it on PoshCode http://poshcode.org/3386
That should work for Write-Host or Write-Verbose, but it will not work if those functions are actually outputting objects -- you'd have to pipe to Write-Host.
The function on PoshCode will (optionally) auto-indent based on the stack depth, but also allow you to specify -Pad 5 or something to manually indent, so you can call nuget.exe ... | write-host -pad 5 or just stick | Write-Host wherever you need it, and then set $WriteVerboseAutoIndent = $true ...
Hope that helps -- it does do manual line wrapping on the output of exes, so it should work.
There's not a great solution, because PowerShell doesn't always run in the console window. Other hosting applications might or might not support tab characters, and might not even support Write-Host. If your goal is strictly to support console display, consider writing a "Format-Console" function.
nuget list NuGetPowerTools | Format-Console
Inside that function, you can capture the pipeline input (which I presume would be strings since this is an external command). Each line of output would be a single String object, so...
Write-Host " $x"
Would display that indented by four spaces.
function Format-Console {
[CmdletBinding()]
param([Parameter(ValueFromPipeline=$True)][string[]]$inputObject)
PROCESS { Write-Host " $inputObject" }
}
That's kinda quick and dirty, but assuming you only ever pipe strings to it, it'll work. Building this as a function lets it be more reusable; using the Format- verb cues other users that the output of this isn't intended to be consumable. It technically isn't a true "Format" cmdlet since it doesn't output internal formatting directives, but it's consistent with the usage pattern for
Can't you assign the result of your private functions to a string and "tab" that string?
$x = nuget list NuGetPowerTools
Write-Host "`t`t$x"