Unblock and unzip

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

Advertisements
Posted in Powershell | Leave a comment

Variables in scriptblocks

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

Posted in Powershell | Leave a comment

Test local user doesn’t exist before creating

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

Posted in Powershell | Leave a comment

Missing verbs?

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

Posted in Powershell | Leave a comment

Sddl

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

Posted in Powershell | Leave a comment

Sort direction

By default Sort-Object uses an ascending sort direction.

Get-Command | Sort-Object -Property Source

will sort the commands based on the Source (module) in ascending Source order.

If you use multiple properties

Get-Command | Sort-Object -Property Source, Name, Version

Your output is sorted by Source, by Name within Source and by Version within Name.

All of these sorts are ascending sorts – A-Z or 1-9 etc

You can change the sort direction to Descending by using the Descending switch. If you have multiple properties involved in the sort they’ll be be sorted in a descending direction.

If you want some properties to be sorted ascending and some descending you need to explicitly specify the sort direction.

Get-Command | Sort-Object -Property @{Expression = ‘Source’; Ascending = $true}, @{Expression = ‘Name’; Ascending = $true}, @{Expression = ‘Version’; Descending = $true}

A hash table is used to specify the property (Expression) and the sort direction.

Posted in Powershell | Leave a comment

Volume friendly name

When you use Get-Volume one of the properties displayed is the friendly name

PS> Get-Volume -DriveLetter C

DriveLetter FriendlyName FileSystemType
———–     ————          ————–
C                                                NTFS

In this case its blank because I haven’t set a volume label.

If you try to access the FriendlyName property

PS> (Get-Volume ).FriendlyName

You’ll get nothing returned.

The actual property is FileSystemLabel

PS> (Get-Volume ).FileSystemLabel

FriendlyName is an alias for FileSystemLabel created in the CDXML that is used to create the storage module and in the formating system for display.

Use

PS> Get-Volume -DriveLetter C | Format-List *

and

PS> Get-Volume -DriveLetter C | Get-Member

to view the properties on the object

Posted in PowerShell and CIM | Leave a comment