PowerShell for Windows Admins


August 15, 2019  1:22 PM

Out-GridView is back

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Out-GridView is finally back in PowerShell core – https://devblogs.microsoft.com/powershell/out-gridview-returns/.

The project is hosted on github – https://github.com/powershell/GraphicalTools

Install the module from the gallery –

PS> Install-Module -Name Microsoft.PowerShell.GraphicalTools

Currently, Out-GridView is the only command in the module though adding Show-Command and Show-Object are planned.

The module works cross-platform not just Windows.

You need PowerShell v6.2 or later to build or presumably run the module.

August 13, 2019  9:22 AM

PowerShell v2

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
PowerShell 2

Just seen a question about PowerShell v2. PowerShell v2 was a huge step forward when it appeared in October 2009 as part of Windows 7 / Server 2008 R2

Windows 7 support finishes 14 January 2020

Windows Server 2008 R2 support finishes 14 January 2020

That’s less than 6 months.

PowerShell v2 isn’t mentioned in the Microsoft documentation which starts at PowerShell v3

If you’re still using PowerShell v2 its beyond time to move to a later version.


August 9, 2019  4:24 AM

Test if a transcript is running

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

PowerShell has the ability to create a transcript of the commands you run at the console and the results displayed in the console. But how can you test if a transcript is running?

It used to be that you could only have a single transcript running but Windows PowerShell v5.1 and PowerShell v6.x and later allow multiple transcripts to be running in the same session.

Only way I can think of testing if transcript has been started is to use

Get-History | where CommandLine -like ‘Start-Transcript*’

that doesn’t tell if its still running for which you need

Get-History | where CommandLine -like ‘Stop-Transcript*’

PS> (Get-History | where CommandLine -like ‘Start-Transcript*’).Count – (Get-History | where CommandLine -like ‘Stop-Transcript*’).Count

should give a result of zero if no transcripts are running. A positive result indicates transcripts are running. A negative result indicates problems.

The test can be wrapped in a function

function test-runningtranscript {
$starts = (Get-History | Where-Object CommandLine -like ‘Start-Transcript*’).Count
$stops = (Get-History | Where-Object CommandLine -like ‘Stop-Transcript*’).Count

$trans = $starts – $stops

switch ($trans){
0 {$false}
{$_ -gt 0} {$true}
{$_ -lt 0} {Throw “Error!!! Can’t have negative transcripts”}
}
}

You’ll get True returned if there is a transcript running and False if there isn’t.


August 5, 2019  10:38 AM

Identifying the host

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Identifying the host in which your PowerShell code is running could be important. For instance you might not want to run some code that takes a long time to complete in VSCode – you may prefer to ensure it runs in the console as it consumes fewer resources.

You can identify the host – most of the time – using $host

For the PowerShell console – Windows PowerShell or PowerShell Core

PS> $host.Name
ConsoleHost

For ISE – Windows PowerShell

PS> $host.Name
Windows PowerShell ISE Host

For VScode – Windows PowerShell or PowerShell Core

PS> $host.Name
Visual Studio Code Host

For the new Windows Terminal – Windows PowerShell or PowerShell Core

PS> $host.Name
ConsoleHost

For you need to differentiate between the traditional PowerShell console and the new Windows terminal you’ll find that the Windows terminal adds an environmental variable

WT_SESSION

which takes a value of the form – 407c1756-556e-4df2-97db-c159a616b237


August 3, 2019  9:20 AM

PowerShell Day UK 2019

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

The PowerShell Day UK 2019 one day conference is on Saturday 28 September 2019 – https://psday.uk/

I’ll be speaking and willing to answer any PowerShell questions that I can during the breaks.

If you have any books of mine that you want signing – bring them along and I’ll be happy to oblige.


July 31, 2019  8:35 AM

Unblock and unzip

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

When you download a zip file from the Internet you have to unblock and unzip the file. I need to do this fairly often so wrote this simple function to perform both actions rather than doing it manually.

function unzipfile {
param (
[string]$path
)
Unblock-File -Path $path
Expand-Archive -Path $path -DestinationPath (Split-Path -Path $path -Parent)
}

The function takes a path and then uses Unblock-File and Expand-Archive. In theory you don’t need to unblock but if you don’t unblock the zip file you’ll have to unblock each and every file expanded from the archive if you want to edit it. Simpler to unblock once.

I’ve used Split-Path to get the folder containing the zip file to use as the destination. if you want to unzip to another folder change the function so destination becomes a second parameter


July 31, 2019  4:50 AM

Variables in scriptblocks

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

I often see questions regarding the use of variables in scriptblocks. Usually a variable will be defined outside the scriptblock and then an attempt will be made to use it in the scriptblock:

PS> $path = ‘C:\test\OldData01.txt’
PS> Start-Job -Name j1 -ScriptBlock {Get-FileHash -Path $path -Algorithm SHA256}

If you look at the output from the job you’ll see this error:

PS> Receive-Job -Name j1
Cannot bind argument to parameter ‘Path’ because it is null.
+ CategoryInfo : InvalidData: (:) [Get-FileHash], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetFileHashCommand
+ PSComputerName : localhost

The problem is that the job is running a different process, therefore a different scope and the variable $path isn’t defined in that scope.

The answer is to either use a param block in your scriptblock or the using scope modifier.

Starting with a param block

PS> Start-Job -Name j2 -ScriptBlock {param ($path) Get-FileHash -Path $path -Algorithm SHA256} -ArgumentList $path

The $path variable from the default scope is passed as an argument into the scriptblock which uses its internal $path variable.

PS> Start-Job -Name j3 -ScriptBlock {Get-FileHash -Path $using:path -Algorithm SHA256}

The using scope tells the script block to use the $path variable from the default scope.

In both cases the results are:

Algorithm : SHA256
Hash : 2B27E4F84D55C62D13C912C5298AA26602D41E90215D437D191E1D625AEB5244
Path : C:\test\OldData01.txt


July 29, 2019  12:59 PM

Test local user doesn’t exist before creating

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

Saw a question asking how to Test local user doesn’t exist before creating. Windows 8 introduced the LocalAccounts module for Windows PowerShell. On Windows 10 1903 it runs in PowerShell v6/7.

There isn’t a Test-Localuser cmdlet but you can attempt to get the user before creation.

function new-user {
[CmdletBinding()]
param (
[string]$username
)
if (-not (Get-LocalUser -Name $username -ErrorAction SilentlyContinue)){
$pwd = Read-Host -Prompt “Password” -AsSecureString
New-LocalUser -Name $username -Password $pwd
}
else {
Write-Warning -Message “User:$username already exists”
}
}

The function takes a username as a parameter. Get-LocalUser is used to test if the user exists. If so the warning message is printed. If the user doesn’t exist you’re prompted for the password and New-LocalUser is used to create the account. You could add parameters for full name and description if required. It’s also possible to do something similar with Get-LocalGroup and New-LocalGroup


July 28, 2019  5:31 AM

Missing verbs?

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

I saw a post that suggested that you can’t use Sort as a verb in your functions. You get a message that sort is an unapproved verb. Are there any other missing verbs?

I started with the object cmdlets as they are probably the most used cmdlets.

Running

Get-Command *-Object |
ForEach-Object {
$v = Get-Verb -Verb $_.Verb

$props = [ordered]@{
Cmdlet = $_.Name
Verb = $_.Verb
AliasPrefix = $v.AliasPrefix
Description = $v.Description
}
New-Object -TypeName PSobject -Property $props
}

against PowerShell v7 preview 2 I found that

Compare, Group, Measure, New and Select are approved verbs

Foreach, Sort, Tee and Where are unapproved verbs

Still trying to think through the logic in those choices


July 27, 2019  12:00 PM

Sddl

Richard Siddaway Richard Siddaway Profile: Richard Siddaway
Powershell

An Sddl is a Security Descriptor Definition Language string – https://docs.microsoft.com/en-us/windows/win32/secauthz/security-descriptor-definition-language – that provides a succinct way to provides the security descriptor of an object as a string. An example Sddl would be

O:BAG:S-1-5-21-437587817-63618879-1935034000-1001D:AI(A;ID;FA;;;SY)(A;ID;FA;;;BA)(A;ID;0x1200a9;;;BU)

Now I’m sure that’s totally clear to everyone but just in case you can’t decode it PowerShell has a cmdlet – ConvertFrom-SddlString – that can help.

(Get-Acl -Path C:\test\erorfile.txt).Sddl | ConvertFrom-SddlString -Type FileSystemRights

If you want the output to be more readable try

((Get-Acl -Path C:\test\erorfile.txt).Sddl |
ConvertFrom-SddlString -Type FileSystemRights |
Select-Object -ExpandProperty DiscretionaryAcl) -split ‘:’

ConvertFrom-Sddl can work with permissions from file system, registry and Active Directory among others


Forgot Password

No problem! Submit your e-mail address below. We'll send you an e-mail containing your password.

Your password has been sent to: