Thursday, November 19, 2015

Working with registry values in PowerShell 5

Working with the registry in PowerShell has always kind of sucked. Now, in PowerShell 5, it’s, well, different, a little.

It’s mostly the same, but there is one new command, which does nothing new, but does it in a new way. I guess that’s progress.

To get a registry key, you still use Get-Item.

001
$Key = Get-Item HKLM:\SOFTWARE\7-zip

To get a registry value, you still use Get-ItemProperty to get all of the values in a key, and pipe them to Select-Object to get just the value you want, in this case, a value named “Path”.

001
$Value = Get-ItemProperty HKLM:\SOFTWARE\7-zip | Select Path

That results in a custom object with a property named Path. So if what you really need to work with the Data in the Value (stupid registry terminology), you would previously use this.

001
$Data = Get-ItemProperty HKLM:\SOFTWARE\7-zip | Select -ExpandProperty Path

Or this.

001
$Data = (Get-ItemProperty HKLM:\SOFTWARE\7-zip).Path

In PowerShell 5, you can now also do it this way.

001
$Data = Get-ItemPropertyValue HKLM:\SOFTWARE\7-zip -Name Path

Wednesday, November 18, 2015

Native zip commands in PowerShell 5

PowerShell 5 includes native commands for working with zip files. Woohoo!

They haven’t given us full functionality yet, but it’s definitely better than nothing.

We can create a zip file from a selection of files or folders using Compress-Archive.

001
Get-Item D:\test | Compress-Archive -DestinationPath D:\test2\TestArchive.zip

We can overwrite it with a new .zip file by using the –Force switch.

We can add or modify files in an existing .zip file using the –Update switch.

001
Get-Item D:\TCPSU | Compress-Archive -DestinationPath D:\test2\TestArchive.zip -Update

We unzip the .zip file using Expand-Archive.

001
Expand-Archive -Path D:\test2\TestArchive.zip -DestinationPath D:\test4

Use the –Force switch to overwrite files.

You can set the –CompressionLevel to Fastest instead of the default Optimal. Theoretically this will compress faster, but result in larger files. In my testing, there was no significant difference in either stat. Your mileage may vary depending on your specific files.

You can also set the –CompressionLevel to NoCompression. This can be useful if most of your files are already compressed; for example, .jpg, .msi, or .xlsx files. This allows you to combine them into a single package without wasting time trying to compress things that aren’t compressible.

What’s missing in this version

You can’t look at a .zip file and know what’s in it without unzipping it.

You can’t extract less than everything in the zip file.

You can’t use any archive type other than .zip.

The drive to get this command set into this version of PowerShell was the ability to use it with DSC. As a result, the features they focused on were the ones that are used within DSC. They did not have time to finish some of the features that would be useful in other scenarios. For those use cases, you will still have to use .Net 4.5 objects (or third party tools links 7-zip if you don’t have .Net 4.5).

Tuesday, November 17, 2015

Write-Host is not as bad in PowerShell 5

We have been saying for years that Write-Host is bad. Never use it. Jeffrey Snover has said that one of his biggest regrets about PowerShell was Write-Host.

But nobody listens to me. And some people don’t even listen to Jeffrey. Write-Host continues to exist in a bazillion old and many new scripts. So the PowerShell team decided to fix it. Or make it less bad.

The problem with Write-Host was that it bypassed the output stream (and all of the other streams), and sent data directly to the “host” to be displayed on the screen. This meant that you couldn’t redirect the result and you couldn’t capture it in a variable. If you moved code whose only output was Write-Host into a function, you found it didn’t work, because only the streams are returned to the calling script. Plus, sometimes code runs in an environment where there is no host, at least not one that can understand what to do with Write-Host, so these scripts just fail.

The PowerShell team introduced a new stream in version 5, named Information, which comes with a Write-Information command (the analog to Write-Output, Write-Verbose, Write-Error, etc.). They decided to leverage this to redesign Write-Host, and rewrote is as a wrapper for Write-Information.

So now in PowerShell 5, Write-Host writes to the Information stream, which by default goes to the host and nowhere else.

There is still almost no reason to ever use Write-Host. It’s pretty useless. Usually writing to the Output stream is preferred or adequate, as it by default writes to the screen as well. And you can do that easily by just outputting something. “Message” does what you thought you were doing with Write-Host “Message”.

And if you do want to write to the Information stream instead of the Output stream, use Write-Information; that’s what it’s for.

The one thing that Write-Host can do that Write-Information can’t, is to write to the screen in pretty colors. Personally, I would prefer to enhance my scripts in other ways, like automatically handling extreme conditions, or using pretty reports where needed, or adding a GUI, or whatever, but if you want to write text to the screen in pretty colors, you now more safely use Write-Host for that.