Richard Siddaway's Blog

VScode improvement

without comments

VScode is the recommended editor for PowerShell Core as its multi-platform. Personally, I’ve preferred the Windows PowerShell ISE as its more closely aligned with the code I create and the work I do. The latest VScode improvement means I’m beginning to question that stance.

 

The latest version of VScode has buttons to run the whole code in the editor window or run selected code. In, and of, itself that’s not a huge improvement but it saves me remembering the specific keystrokes or digging through the menus.

 

So, thankyou for an improvement that makes things easier for me and means I’m more likely to use VScode

Written by richardsiddaway

December 31st, 2019 at 9:13 pm

Posted in PowerShell

Clear the trusted host list

without comments

The final option in administering the trusted host list is to clear the entire list. The following function will clear the trusted host list

function clear-trustedhost {
[CmdletBinding()]
param (
[string]$computername = $env:COMPUTERNAME
)

if (Test-Connection -ComputerName $computername -Quiet -Count 1) {
Set-WSManInstance -ResourceURI winrm/config/client -ComputerName $computername -ValueSet @{TrustedHosts = “”}
}
else {
Write-Warning -Message “$computername is unreachable”
}

}

 

Use Set-WSMANinstance to set the value of trusted hosts to being an empty string.

Written by richardsiddaway

December 31st, 2019 at 4:11 pm

Posted in PowerShell

Remove a trusted host

without comments

Continuing our collection of routines to manage the trusted hosts this time we’ll look at how to remove a trusted host

function remove-trustedhost {
[CmdletBinding()]
param (
[string]$trustedhost,
[string]$computername = $env:COMPUTERNAME
)

if (Test-Connection -ComputerName $computername -Quiet -Count 1) {
$th = Get-WSManInstance -ResourceURI winrm/config/client -ComputerName $computername |
Select-Object -ExpandProperty TrustedHosts

if ($th) {
$ths = $th -split “, |,”, 0, “Regex”

$newth = ($ths -ne $trustedhost) -join “, ”

Set-WSManInstance -ResourceURI winrm/config/client -ComputerName $computername -ValueSet @{TrustedHosts = $newth}

}
else {
Write-Warning -Message “No trusted hosts to remove”
}

}
else {
Write-Warning -Message “$computername is unreachable”
}

}

 

The trick here is to get the current trusted hosts list and split on the commas to create an array. Create a new trusted hosts array that doesn’t contain the one you want to remove then use the join operator to recreate the string. Write that string back to the system.

 

Again this needs to be run with elevated privileges otherwise you’ll get an Access Denied error.

Written by richardsiddaway

December 30th, 2019 at 10:42 am

Posted in PowerShell

Add a trusted host

without comments

Last time I showed how to read the trusted host list – this is how you add a trusted host

function add-trustedhost {
[CmdletBinding()]
param (
[string]$trustedhost,
[string]$computername = $env:COMPUTERNAME
)

if (Test-Connection -ComputerName $computername -Quiet -Count 1) {
$th = Get-WSManInstance -ResourceURI winrm/config/client -ComputerName $computername |
Select-Object -ExpandProperty TrustedHosts

if ($th) {
$newth = $th + “, $trustedhost”
}
else {
$newth = $trustedhost
}

Set-WSManInstance -ResourceURI winrm/config/client -ComputerName $computername -ValueSet @{TrustedHosts = $newth}
}
else {
Write-Warning -Message “$computername is unreachable”
}

}

 

Get the current trusted host list and append the new trusted host name. Use Set-WSManInstance to write back the new trusted host list.

 

The function currently only takes a single new trusted host but you could modify the code to accept an array of computer names and iterate through the array to create the new trusted host list.

 

You need to be running PowerShell with elevated privileges (as administrator) to be able to write the trusted hosts list back to the system.

 

This function and last times get-trustedhost both have a computername parameter (defaults to local computer) so you can use these functions (and the upcoming functions to clear and remove trusted hosts) on the local or remote machines

Written by richardsiddaway

December 29th, 2019 at 11:48 am

Posted in PowerShell

Trusted hosts

without comments

You can use trusted hosts in WSMAN based PowerShell remoting to authenticate computers where Kerberos isn’t available.

The WSMAN configuration is available through the WSMAN PowerShell drive or you can use the WSMANInstance cmdlets – available in Windows PowerShell v5.1, PowerShell 6.2 (Seem to have come back in at PowerShell v6.1) or PowerShell v7

function get-trustedhost {
[CmdletBinding()]
param (
[string]$computername = $env:COMPUTERNAME
)

if (Test-Connection -ComputerName $computername -Quiet -Count 1) {
Get-WSManInstance -ResourceURI winrm/config/client -ComputerName $computername |
Select-Object -ExpandProperty TrustedHosts
}
else {
Write-Warning -Message “$computername is unreachable”
}

}

 

The only non-obvious piece of code is the resource URI which you can work out from the examples in the help file. By contrast using the WSMAN drive you need to access

Get-ChildItem -Path WSMan:\localhost\Client\

Written by richardsiddaway

December 28th, 2019 at 8:14 pm

Posted in PowerShell

Keep it Simple

without comments

One of the principles I’ve always tried to stick with when writing code – in PowerShell or any other language – is Keep it Simple.

 

Keeping code simple makes it easier to understand, easier to debug and easier to maintain. My definition of simple code may not be the same as yours but by and large simple code is easier to work with. When I was judging Scripting Games entries it was always easier to work with answers that were written in a simple manner. That doesn’t mean they were crude or badly written – it means they were written in a manner that was easy to understand.

 

Creating a PowerShell pipeline tends to produce a simple solution – the badly, and incorrectly, named “one-liner”.

 

Complications seem to creep in when solutions start using aspects of the PowerShell language. Loops and simple branching structures (if & switch) should cover most if not all your needs – I’ve seen many complications arise when multiple nested if statements are used or huge conditions used with multiple nested AND/OR statements – try and simplify.

 

Still not convinced for the new language features such as ternary conditional, null coalescing etc but PowerShell is now open source so if you shout loud enough you’ll get it added to the language.

 

Whatever your code, coding standards or goals keeping the code as simple as possible will pay off in the end.

Written by richardsiddaway

December 28th, 2019 at 7:55 pm

Posted in PowerShell

What do you use PowerShell for?

without comments

What do you use PowerShell for?

 

Personally, I’ve always used it as a tool to automate the administration of Windows systems. I’ve created and managed systems. Managed the OS and file system. Administered Exchange, Active Directory and SQL Server amongst other tasks.

 

I’ve also used PowerShell for a wide variety of other tasks – searching emails for information about a particular event; creating server and network documentation for audit purposes – the ability to write output directly to word documents is a huge time saver.

 

I’ve also used PowerShell for other purposes – solving maths puzzles, calculating the effective temperature (wind chill) and the change in temperature with altitude for instance.

 

I’ve seen numerous demos of a GUI front end on PowerShell code though the concept has never really appealed to me.

 

Cross platform administration is potentially in reach with PowerShell 6/7 but what’s the real audience for that?

 

So, what do you use PowerShell for?

Written by richardsiddaway

December 27th, 2019 at 5:16 pm

Posted in PowerShell

Season’s Greetings

without comments

Season’s Greetings from PowerShell

(77,101,114,114,121,32,67,104,114,105,115,116,109,97,115,32,97,110,100,32,97,32,72,97,112,112,121,32,78,101,119,32,89,101,97,114 | foreach {[char][byte]$psitem}) -join ”

Written by richardsiddaway

December 24th, 2019 at 7:45 pm

Posted in PowerShell

PowerShell remoting

without comments

PowerShell remoting must be every administrators favourite feature. The fact that you can connect to to multiple machines and get your tasks done just makes life so much easier.

 

PowerShell remoting originally appeared in PowerShell v2. In v1 Get-WMIObject was the only cmdlet capable of connecting to a remote machine. Remoting used WSMAN for inter-machine connectivity. This has advantages and disadvantages. The advantages are that its router friendly the disadvantage that PowerShell remoting over WSMAN ties authentication to the Kerberos protocol used in Active Directory. This means that remoting is easy within the domain but become harder to work with outside of the domain environment. You should use certificates for authentication outside the domain. There are other ways but you should use certificates for WSMAN remoting authentication outside the domain.

 

Windows PowerShell v3-v5.1 saw many cmdlets have a computername parameter added – for instance the Process and Service cmdlets. In these cases DCOM/RPC is used for the connectivity. This can have problems with routers and firewalls. Individual cmdlet remoting has been removed in PowerShell v6/v7 so isn’t recommended.

 

PowerShell v6 saw the introduction of SSH based remoting for connecting to non-Windows machines – it also works Windows to Windows. WSMAN is available on Linux but isn’t fully supported and isn’t recommended. SSH isn’t easy to set up. Its getting better but still not as straight forward as WSMAN. Use SSH remoting for Windows – Linux. SSH is also great in a non-domain scenario.

 

Windows 10 / Server 2016 saw the introduction of PowerShell Direct (Windows PowerShell and PowerShell core both support PowerShell Direct). If your local machine is the Hyper-V host you can remote over the VMbus to virtual Windows machines on the host.

 

Lots of options for remoting. Recommendations:

Windows-Windows within the domain – use WSMAN

Windows-Linux (or vice versa) or Windows to Windows outside the domain use SSH

If you’re on the Hyper-V host use PowerShell direct for Windows VMs

Written by richardsiddaway

December 24th, 2019 at 6:30 pm

Posted in PowerShell

PowerShell cmdlets

without comments

Continuing my series of the features in PowerShell we shouldn’t forget – we get to PowerShell cmdlets.

 

The PowerShell cmdlet ecosystem has grown from the 137 cmdlets in PowerShell v1 to who knows how many are available to windows PowerShell v5.1, PowerShell v6.x and PowerShell v7 – certainly in the thousands.

 

A cmdlet is a small piece of code that does one job. The PowerShell concept is that cmdlets are linked into a pipeline to perform a particular task. PowerShell cmdlets emit .NET objects which are passed between cmdlets on the pipeline.

 

So far so good. More cmdlets available means more tasks can be performed with a single command. When I wrote PowerShell in Practice (v1/v2 times) there wasn’t such great cmdlet coverage so you had to resort to scripting. These days many, if not most, of things we had to write scripts for can now be done with cmdlets.

 

Cmdlets come from a number of sources:

– In the box with PowerShell

– Cmdlets provided by other Microsoft teams that ship in Windows

– Cmdlets provided by other Microsoft products

– Cmdlets provided by third party software vendors

– Cmdlets from public sources such as the PowerShell gallery

 

Some of the PowerShell v6/v7 is being provided through the gallery or being trialled in the gallery before, possibly, moving into the product.

So far so good.

 

On Windows we have a huge set of cmdlets such that I can say I’ve been using PowerShell since it was still Monad (much cooler name) and there are cmdlets I’ve not had reason to use.

 

This was true as of Windows PowerShell v5.1. PowerShell v6 was initially disappointing because it couldn’t utilise a significant set of the existing cmdlets suite. Porting of cmdlets to run under PowerShell v6 and the WindowsCompatibility module (a delicious irony that Windows needs a compatibility module to enable the use of functionality developed for Windows) whose functionality has since moved into Windows v7 have done much to address the issue. The vast majority of the functionality available under Windows PowerShell v5.1 is now available under PowerShell v7 though gaps still exist.

 

On Linux and mac the picture isn’t so rosy. There are the cmdlets that are available in the PowerShell v6/v7 install and as far as I’m aware that’s about it. Roughly back to where we were with PowerShell v1/v2. With Windows PowerShell we had the capability of falling back to CIM (WMI), COM or .NET to get things done. CIM and COM aren’t available on non-Windows and PowerShell v6/v7 are built on .NET core which introduces some limitations. To me if PowerShell is to be a true cross-platform administration tool I need to be able to issue the same command – irrespective of platform – and get the job done. Until we get cmdlets to work with storage, network adapters, IP addresses etc etc etc we’re not really in a cross-platform scenario.

 

Cmdlets are good. More cmdlets are better. Cross-platform cmdlets would be ideal.

Written by richardsiddaway

December 19th, 2019 at 8:16 pm

Posted in PowerShell