Monthly Archive

Categories

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

PowerShell 7

A recent post - https://devblogs.microsoft.com/powershell/the-next-release-of-powershell-powershell-7/ – on the PowerShell team blog states that the next release of PowerShell Core won’t be 6.3 as expected but will be PowerShell 7

 

PowerShell 7 will be tied to .NET Core 3.0 and should bring more compatibility for Windows users. The graphic on the post shows Linux usage outstrips Windows usage of PowerShell Core by at least 5 to 1.

 

The lifecycle will change to align more closely with .NET Core with Long Term Servicing releases and non-LTS releases.

 

PowerShell 7 will eventually ship side-by-side with Windows PowerShell 5.1 but update process hasn’t been finalised.

 

Terminology changes are in the offing as PowerShell core is dropped for just PowerShell. This is a mistake as it takes away the use of PowerShell as a generic term that covers all versions.

 

The reasons for the change aren’t fully explained in the post but I suspect are linked to the very poor level of take up of PowerShell Core on Windows.

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.

PSCommandNotFoundSuggestion

PowerShell v6.2 contains a number of experimental features including PSCommandNotFoundSuggestion

The idea of experimental features is to make the use of new features – especially those that may cause breaking changes optional. Feedback can be obtainied and the experimental features can be modified, moved out of the experimental state into the full release or even removed.

Use

Enable-ExperimentalFeature –Name PSCommandNotFoundSuggestion

to enable the feature. Then restart PowerShell.

 

Trying the new feature gave these results

PS> Get-Srvice

Suggestion [4,General]: The most similar commands are: Get-Service, Set-Service, New-Service, Get-PSDrive.

I expected Get-Service so that worked

 

Likewise

PS> Get-prcss

Suggestion [4,General]: The most similar commands are: Get-Process, Get-Alias, Get-Host, Get-Acl.

Looking for Get-Process – some of the other choices are very odd

 

Moving to native utilities

PS> pong

Suggestion [4,General]: The most similar commands are: popd, copy, move, ni, nv, oh, rni, rnp, sort, man.

I’d have expected to see ping in that list!

 

PS> Get-NtAdter

gives

Suggestion [4,General]: The most similar commands are: Get-NetAdapter, Set-NetAdapter, Get-Counter, Get-Item, Get-Date, Get-Member.

Expected Get-NetAdapter so that counts as a success.

 

Looking at aliases

PS> seloct

Suggestion [4,General]: The most similar commands are: select, sort, set, del, clc, sal, sl, sleep, start, sls.

PS> stv

Suggestion [4,General]: The most similar commands are: sv, stz, clv, ft, gpv, gv, nv, rv.

Needed to see select and stz respectively so that’s good.

 

One last utility

PS> ipconfog

Suggestion [4,General]: The most similar commands are: ipmo, ipcsv, ipconfig.exe, inmo.

ipconfig fits the bill.

 

For the most part the suggested commands seem to be reasonable and reasonably accurate.

Tab completion probably removes some of the usefulness of this option but I’d recommend enabling it and giving it a try

PowerShell v6.2 experimental features

I’ve mentioned the PowerShell v6.2 experimental features before.

 

This blog post from the PowerShell team https://devblogs.microsoft.com/powershell/general-availability-of-powershell-core-6-2/

gives a good overview of the available experimental features.

 

I’ve already covered the use of the temp drive. The command not found suggestions and implicit remoting batching look like they could be useful.  The abbreviation expansion could make interactive use more efficient

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

PowerShell v6.2 release

The Powershell v6.2 release has just been made available on github - https://github.com/PowerShell/PowerShell/releases

 

The full release notes aren’t available on the Microsoft documentation yet – they should appear in the What’s New section of https://docs.microsoft.com/en-us/powershell/scripting/overview?view=powershell-6

 

The release notes on github indicate only one breaking change  - around the –NoEnumerate behaviour in Write-Output

 

There are some relatively minor cmdlet updates and fixes – nothing leaps out as a major issue.

 

You have six months to upgrade to v6.2 before the v6.1 support stops

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.