Monthly Archive

Categories

PowerShell

PowerShell version incompatibilities

There are incompatibilities between Powershell versions – you can’t use classes in Windows PowerShell v4 and there are differences between Windows PowerShell v5.1 and v6.x. One way to deal with PowerShell version incompatibilities is described in the recent post from the PowerShell team - https://devblogs.microsoft.com/powershell/using-psscriptanalyzer-to-check-powershell-version-compatibility/

 

I’m not a big fan of tools such as PSScriptAnalyzer as I find them restrictive and they get in the way of doing what I need to do. Having said that the usage described in the article is actually very useful especially the way you can configure which PowerShell versions you need to be worried about.

 

PSScriptAnalyzer is built into VSCode so the availability of the functionality to chaeck PowerShell version incompatibilities actually strengthens the case for using VSCode (I still don’t feel 100% comfortable with it – mainly because it does too much for what I need. The ISE is simpler and suits my needs better).

 

If you need work round PowerShell version incompatibilities in the code you write this may be of great help.

File times

There are three pairs of file times that are available on files on Windows

PS> Get-ChildItem -Path C:\test\Newoutdata01.txt | select *time*

CreationTime : 14/04/2019 17:28:41
CreationTimeUtc : 14/04/2019 16:28:41
LastAccessTime : 14/04/2019 17:28:41
LastAccessTimeUtc : 14/04/2019 16:28:41
LastWriteTime : 25/02/2019 17:42:49
LastWriteTimeUtc : 25/02/2019 17:42:49

 

This is how to modify those times

Get-ChildItem -Path C:\test\*.txt |

ForEach-Object {

$date = (Get-Date).AddMonths( -(Get-Random -Maximum 5 -Minimum 1) )

Set-ItemProperty -Path $_.FullName -Name CreationTime -Value $date

Set-ItemProperty -Path $_.FullName -Name LastAccessTime $date.AddDays((Get-Random -Maximum 5 -Minimum 1))

Set-ItemProperty -Path $_.FullName -Name LastWriteTime $date.AddDays((Get-Random -Maximum 8 -Minimum 2))

}

 

Use Get-ChildItem to iterate through the files. For each file use Set-Property to set the value on the appropriate property. The values I’m using are purely random – you’d normally use a known value.

 

The *Utc version of the properties will be automatically set based on its corresponding property

Get wireless networks

I saw a question on how to get wireless networks which got me thinking about string handling and working with legacy command line utilities. I also wanted to compare the options available in Windows PowerShell and PowerShell Core.

 

First up is a relatively brute force approach. This approach works is relatively easy to understand and maintain but isn’t very elegant.

function get-wlan {
[CmdletBinding()]
param()

$networks = netsh wlan show networks mode=bssid

$networks | Select-Object -Skip 4 |
Where-Object {$_ -ne ''} |
ForEach-Object {

if ($psitem.StartsWith('SSID')) {
$temp = $psitem -split ':'
Write-Verbose -Message $temp[1]
$network = $($temp[1].Trim())
}

if ($psitem.TrimStart().StartsWith('Authentication')){
$temp = $psitem -split ':'
Write-Verbose -Message $temp[1]
$authentication = $temp[1].Trim()
}

if ($psitem.TrimStart().StartsWith('Signal')){
$temp = $psitem -split ':'
Write-Verbose -Message $temp[1]
$signal = $temp[1].Trim()
}

if ($psitem.TrimStart().StartsWith('Radio type')){
$temp = $psitem -split ':'

$props = [ordered]@{
Network = $network
Authentication = $authentication
Type = $temp[1].Trim()
Signal = $signal
}
New-Object -TypeName PSobject -Property $props
}
}
}

 

Start by using netsh to get the wireless networks. Skip the first 4 lines (run the netsh command by itself to see what’s being skipped) and filter out blank lines (empty strings). For each line check if it’s of interest and if so split on the : character and take the data into a variable. On the radio type line create an object and output.

Brackets in file names

If you have brackets – [ or ] – in your file name you can see problems working with the file name. This is how to deal with brackets in file names.

Consider the files:

outdata01.txt
out[data02.txt
out]data03.txt
out]d[ata04.txt

which have a selection of brackets in the file name.

 

If you try something like

Get-ChildItem -Path c:\test | foreach {Rename-Item -Path $_.Fullname -NewName "New$($_.name)"}

You’ll find that two files

outdata01.txt
out]data03.txt

are successfully renamed but the other two fail with an error like

Rename-Item : Cannot retrieve the dynamic parameters for the cmdlet. The specified wildcard character pattern is not valid: out[data02.txt

 

Notice its the two files with left hand brackets that fail.

 

Its because PowerShell its treating the bracket as the opening of a wildcard / regex pattern.

 

The easiest way round this problem is to use –Literalpath instead of –Path

Get-ChildItem -Path c:\test | foreach {Rename-Item -LiteralPath $_.Fullname -NewName "New$($_.name)"}

 

And you’ll find all of the files rename successfully.

 

LiteralPath treats what ever its given literally – it doesn’t do the interpretation that Path attempts.

If you think you’re going to have odd characters in your file names then remember to use literalpath – you’ll find it as an alternative on all the core cmdlets that accept paths

Pro Microsoft Hyper-V 2019

I’ve always maintained that the most important thing about PowerShell is what you can do with it. This is brought out in my book - Pro Microsoft Hyper-V 2019 - https://www.apress.com/gb/book/9781484241158 .

 

My co-author and I describe how to create and manage a hyper-V environment. We use many PowerShell examples but they’re all in the context of getting your job done.

 

PowerShell is an important tool for administering your environment but at the end of the day remember the job is administration not fancy code. Your code should be good enough to get the job done and then move to the next task. You can always revisit code and polish it later.

Copy-Item

Copy-Item seems to cause problems for many users.

 

I’ve written an article on the use of Copy-Item that you may find useful - https://searchwindowsserver.techtarget.com/tip/PowerShell-commands-to-copy-files-Basic-to-advanced-methods

Read-Host

Read-Host enables you to prompt for input for your functions and scripts. For instance I see a lot of examples of this sort of code:

$group = Read-Host -Prompt 'Group Name'
Get-ADGroupMember -Identity $group

You should only use Read-Host as a last resort. The correct way to pass data into scripts and functions is by parameters. You can create a param() block in a script!

function Get-Members {
param (
[string]$group
)
Get-ADGroupMember -Identity $group
}

Use the function as:

Get-Members -group finance

The other advantage of parameters is that you do lots of clever validation on the values.

So, stop using Read-Host and use parameters – you know you want to.

PowerShell interviews

Following my last post about sample questions for PowerShell interviews that I’d stumbled across I’ve been asked what sort of questions I’d ask – given my statement that many of the question sets were out of date.

 

I’ve thought about it and decided I’ll run an occasional series of questions and the information I’d expect.

 

Before I start that I’ve thought some more around the whole issue of PowerShell interviews and there are some things to think about before jumping into performing an interview.

 

The most important thing is what are you interviewing for. What exactly does the role entail? There are a number of possibilities:

 

You want a PowerShell developer – the person will spend all of their time writing and maintaining code. Requirements and and specifications will be given to them. for this sort of role you’ll need to be mixing developer technique questions in with the powershelll questions.

 

You want someone to automate your administrative processes. Again development techniques ae going to feature alongside PowerShell questions. Ideally, you’d also want some one who would question the processes because automating what you have now is necessarily the best thing. I can remember being asked to generate a report about some products when I worked for a financial services organisation. Easy enough to do. I then asked 1 question – what was the report used for. It turned out that the data on the report was keyed into another system. The job then became extract data from system a and feed into system b and produce a report of what happened. That single question saved the users a bunch of time, effort and reduced errors from the re-keying of data.

 

You want an administrator who can also automate the administration of some or all of your environment. At this point you’re looking for someone who can administer X (or a bunch of Xs) and write PowerShell code that’ll make that job easier. You need to ensure that the person actually understand the system[s] as well as PowerShell.

 

Once you know the sort of person you want its time to think about the questions to ask. I’m going to assume that any other questions and just concentrate on questions about PowerShell from a theoretical and practical perspective. If you can sit the candidate down and make them write some code for you – but we’ll get to that another time.

PowerShell interview questions

For some bizarre reason I ended up looking at various sets of PowerShell interview questions and answers.

 

For the most part they scared me – due to their outdated nature.

 

Many, if not most, of the question sets hadn’t been brought up to date for PowerShell v5.1 and very few even mentioned v6.x. The remoting and CIM answers were often misleading.

 

And that’s just what I picked up on a quick scan through.

 

Bottom line is that if you need to prepare for an interview and you’re going to get PowerShell questions then make sure that you actually know the subject and don’t rely on dubious online sources.

Execution policy

PowerShell gives you a number of options regarding execution policy. You use one of the following options with Set-Execution policy:

Restricted – won’t run scripts or profiles. This is the default execution policy

Allsigned – only scripts (and profiles) signed with a trusted certificate can run. This includes anything you create on local machine.

RemoteSigned – Scripts (and profiles) on local drives will run. Scripts downloaded from Internet or from network drives are blocked

Unrestricted – anything runs though you are prompted before a downloaded unsigned script is run. This setting is what’s generally called a bad idea as its too permissive.

Bypass – everything runs without warnings or prompts. In most cases a worse idea than unrestricted

Undefined – removes currently assigned execution policy from the current scope though it won’t work if policy set by GPO

 

Just to add to the fun you have to think about the scope as well:

Process – only the current PowerShell process

CurrentUser –only the current user

LocalMachine – all users on the computer. This is the default setting.

 

I normally use RemoteSigned as it offers the best choice between ease of use and security. For an organisation that makes extensive use of PowerShell I’d recommend Allsigned with the code signing certificate only available to a small number of users who were responsible for performing quality assurance checks on the code.