The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 2,163 other followers

Archive for the ‘PowerShell’ Category

powershell – Format-Table forgets some properties, but Format-List shows them all. Why? – Stack Overflow

Posted by jpluimers on 2020/11/12

Reminder to self: finish the script that initiated this 2013 question (yes ages ago!) [WayBack] powershell – Format-Table forgets some properties, but Format-List shows them all. Why? – Stack Overflow.

The question was based on code I was really happy I saved in the WayBack machine: WayBack: how-to: Print/List installed programs/applications sorted by date | Tech Off | Forums | Channel 9

So here the question and the answer.

Question

Given the below PowerShell 3 script, Format-Table does not list all properties as columns (it skips NoRemove), but Format-List does, and you can force the properties to be there using Select-Object.

Out-GridView behaves the same as Format-Table and also skips NoRemove

Why is that?

Note: this is from a much less restricted Where-Object clause, where it looks like Format-Tabledoes inspect more than just the first object in the array to guess the columns.

The example comes from Channel 9 how-to: Print/List installed ​programs/ap​plications sorted by date which forgot to initialize the first Get-ItemProperty (gp) as an array so you got an error like this:

Method invocation failed because [Microsoft.Win32.RegistryKey] doesn't
contain a method named 'op_Addition'.

Example code:

$nonUninstallableSoftwareRegistryKeys = (@(Get-Item HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*)) + 
(Get-Item HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*) + 
(Get-Item HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*) | 
  Where-Object { $_.ValueCount -eq 1 }

$nonUninstallableSoftwareRegistryKeys.GetType().FullName
$nonUninstallableSoftwareRegistryKeys | Get-Member

$nonUninstallableSoftwareRegistryNameValues = $nonUninstallableSoftwareRegistryKeys | 
  Get-ItemProperty

$nonUninstallableSoftwareRegistryNameValues.GetType().FullName
$nonUninstallableSoftwareRegistryNameValues | Get-Member

$nonUninstallableSoftwareRegistryNameValues |
  Format-Table

$nonUninstallableSoftwareRegistryNameValues |
  Format-List

$nonUninstallableSoftwareRegistryNameValues |
  Select-Object SystemComponent, NoRemove, PSPath, PSParentPath, PSChildName, PSProvider |
  Format-Table

I used GetType().FullName and Get-Member to inspect the underlying types.

$nonUninstallableSoftwareRegistryKeys starts with all installed software (user, system x64 and system x86) filtered by registry keys having only 1 value (empirically those are the ones you cannot uninstall).

The first part of the output shows that $nonUninstallableSoftwareRegistryKeys is a System.Object[] of type Microsoft.Win32.RegistryKey with all the right members. Hence the ability to perform a Where-Object filter on the ValueCount property even though the code-completion does not show that.

$nonUninstallableSoftwareRegistryKeys exposes also a few PowerShell “Extended Type System” NoteProperty properties including Property that contain the registry Name/Value pairs under the key and a bunch of PS* coming from the registry provider.

$nonUninstallableSoftwareRegistryNameValues is also a System.Object[] but now of typeSystem.Management.Automation.PSCustomObject because of the Get-ItemProperty which expands the Name/Value pairs in the Property of each $nonUninstallableSoftwareRegistryKeysitem into properties. For the first item in my output, it adds the SystemComponent property. For the second item it adds NoRemove. And it adds a bunch of PS* coming from the registry provider.

Format-Table output:

SystemComponent PSPath                                                                                                                                    PSParentPath                        
--------------- ------                                                                                                                                    ------------                        
              1 Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager             Microsoft.PowerShell.Core\Registr...
                Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\WIC                            Microsoft.PowerShell.Core\Registr...
              1 Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager Microsoft.PowerShell.Core\Registr...
                Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\WIC                Microsoft.PowerShell.Core\Registr...

Format-List output:

SystemComponent : 1
PSPath          : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager
PSParentPath    : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
PSChildName     : Connection Manager
PSProvider      : Microsoft.PowerShell.Core\Registry

NoRemove     : 1
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\WIC
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall
PSChildName  : WIC
PSProvider   : Microsoft.PowerShell.Core\Registry

SystemComponent : 1
PSPath          : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager
PSParentPath    : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
PSChildName     : Connection Manager
PSProvider      : Microsoft.PowerShell.Core\Registry

NoRemove     : 1
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\WIC
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall
PSChildName  : WIC
PSProvider   : Microsoft.PowerShell.Core\Registry

Select-Object output:

SystemComponent NoRemove PSPath                                                                                                                                    PSParentPath               
--------------- -------- ------                                                                                                                                    ------------               
              1          Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager             Microsoft.PowerShell.Cor...
                1        Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\WIC                            Microsoft.PowerShell.Cor...
              1          Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Connection Manager Microsoft.PowerShell.Cor...
                1        Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\WIC                Microsoft.PowerShell.Cor...

Edit: my environment

PS C:\Users\Developer> Get-CimInstance Win32_OperatingSystem | Select-Object Version, Caption | Format-List
$PSVersionTable

Version : 6.2.9200
Caption : Microsoft Windows 8 Pro

Name                           Value                                                                                                                                                          
----                           -----                                                                                                                                                          
PSVersion                      3.0                                                                                                                                                            
WSManStackVersion              3.0                                                                                                                                                            
SerializationVersion           1.1.0.1                                                                                                                                                        
CLRVersion                     4.0.30319.18051                                                                                                                                                
BuildVersion                   6.2.9200.16628                                                                                                                                                 
PSCompatibleVersions           {1.0, 2.0, 3.0}                                                                                                                                                
PSRemotingProtocolVersion      2.2   

These 2 return the same table:

$nonUninstallableSoftwareRegistryNameValues |
  Format-Table

$nonUninstallableSoftwareRegistryNameValues |
  Format-Table *                                                                                                                                                         

Answer 1

If you don’t specify the property names or ‘*’ for all of them, Format-Table will print by default just the first 4 (the default value of $FormatEnumerationLimit), not ure why you get only three in the ft output. Format-List will show all only when the type of objects doesn’t have a format view for Format-List.

Comment

I did a $nonUninstallableSoftwareRegistryNameValues | Format-Table * which also skips NoRemove. Something fishy is going on here.

And if you add -Force?

This also fails: $nonUninstallableSoftwareRegistryNameValues | Format-Table * -Force

I can see all properties when piping to fl (without -force) and with ft *.

What OS and PS version do you run? I’ve added mine to my question.

Answer 2

Did you try the following?

$nonUninstallableSoftwareRegistryNameValues |
  Select-Object SystemComponent, NoRemove, PSPath, PSParentPath, PSChildName, PSProvider |
  Format-Table -Wrap

Comment

That works (it is almost the same as the last entry in my example), but why can’t Format-Table figure this out by itself? Or maybe phrased differently: what criteria does Format-Table to determine which columns to pick?

–jeroen

Posted in .NET, CommandLine, Development, PowerShell, PowerShell, Scripting, Software Development | Leave a Comment »

Installing Windows software with Chocolatey: a few notes

Posted by jpluimers on 2020/10/28

I will limit myself to software that needs Administrative elevation in order to be installed. This is the default use-case for Chocolatey. It is way way easier than installing software all by hand, but there are a few things you need to know, hence these notes.

Administrative elevation

Since the default use case is installing software that requires Administrative elevation during install, Chocolatey needs to run with Administrative privileges in order to perform these installs.

If you were hoping for a way around this (for instance by having a client/service architecture), then just stop here.

Even though such a structure could technically be created, getting it stable and working it correctly with a truckload of software to be installed (much of which not available as packages during Chocolatey development in the first place) is a task too big.

Think of the size of the Windows Installer team at Microsoft to get installers working in the first place, the extra effort needed by Chocolatey volunteers to get the installers working from the console, then another much more complex layer of getting them running from inside a service and communicating everything back and forth to a non-elevated command prompt would be a nightmare.

I won’t even mention the security steps involved to ensure the non-elevated command prompt has enough rights to send installation instructions to the elevated service.

So the first step is to have an elevated command prompt for Chocolatey.

Being elevated, and Chocolatey needing to download installers requires a local temporary place for them.

By default, that place is %Temp%\chocolatey of the administrative user that elevated the Chocolatey command prompt.

This directory can grow quite big, so dir, so – since there is no choco cleanup yet [WayBack] you need to either:

Install Chocolatey itself

Either the direct one below, or the more secure one (so you can inspect the intermediate [WayBackinstall.ps1) at [WayBack] Installation using PowerShell from cmd.exe:

@echo off
SET DIR=%~dp0%
::download install.ps1
%systemroot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "((new-object net.webclient).DownloadFile('https://chocolatey.org/install.ps1','%DIR%install.ps1'))"
::run installer
%systemroot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%DIR%install.ps1' %*"

If you want to get rid of it, use [WayBack] Uninstallation.

Besides the one above and below, there are many more [WayBack] Installation: more install options

Output of direct install as Administrator (disclaimers apply):

C:\WINDOWS\system32>powershell -NoProfile -ExecutionPolicy Bypass -Command "[System.Net.WebRequest]::DefaultWebProxy.Credentials = [System.Net.CredentialCache]::DefaultCredentials; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH="%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
Getting latest version of the Chocolatey package for download.
Getting Chocolatey from https://chocolatey.org/api/v2/package/chocolatey/0.10.11.
Downloading 7-Zip commandline tool prior to extraction.
Extracting C:\Users\JEROEN~1\AppData\Local\Temp\chocolatey\chocInstall\chocolatey.zip to C:\Users\JEROEN~1\AppData\Local\Temp\chocolatey\chocInstall...
Installing chocolatey on this machine
Creating ChocolateyInstall as an environment variable (targeting 'Machine')
  Setting ChocolateyInstall to 'C:\ProgramData\chocolatey'
WARNING: It's very likely you will need to close and reopen your shell
  before you can use choco.
Restricting write permissions to Administrators
We are setting up the Chocolatey package repository.
The packages themselves go to 'C:\ProgramData\chocolatey\lib'
  (i.e. C:\ProgramData\chocolatey\lib\yourPackageName).
A shim file for the command line goes to 'C:\ProgramData\chocolatey\bin'
  and points to an executable in 'C:\ProgramData\chocolatey\lib\yourPackageName'.

Creating Chocolatey folders if they do not already exist.

WARNING: You can safely ignore errors related to missing log files when
  upgrading from a version of Chocolatey less than 0.9.9.
  'Batch file could not be found' is also safe to ignore.
  'The system cannot find the file specified' - also safe.
chocolatey.nupkg file not installed in lib.
 Attempting to locate it from bootstrapper.
PATH environment variable does not have C:\ProgramData\chocolatey\bin in it. Adding...
WARNING: Not setting tab completion: Profile file does not exist at 'C:\Users\jeroenAdministrator\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1'.
Chocolatey (choco.exe) is now ready.
You can call choco from anywhere, command line or powershell by typing choco.
Run choco /? for a list of functions.
You may need to shut down and restart powershell and/or consoles
 first prior to using choco.
Ensuring chocolatey commands are on the path
Ensuring chocolatey.nupkg is in the lib folder

Installing packages

Compressing

If you run out of SSD or VM disk space, you can try compress using compact /c /s *.* in these directories:

  • C:\ProgramData\Package Cache
  • C:\ProgramData\Microsoft\VisualStudio\Packages
  • C:\ProgramData\Microsoft\ClickToRun\ProductReleases

Further reading

–jeroen

PS: always watch the output and logs!

Read the rest of this entry »

Posted in Chocolatey, CommandLine, Conference Topics, Conferences, Development, Event, Power User, PowerShell, PowerShell, Scripting, Software Development, Windows | Leave a Comment »

PowerShell: checking minimum version

Posted by jpluimers on 2020/08/13

Nowadays, often your PowerShell code uses features unavailable in older PowerShell versions. When running it on a version that is too old, you usually get an error message, for instance like this:

Unable to find type [Ordered]: make sure that the assembly containing this type is loaded.

Back in the days, this was a new feature introduced in PowerShell 3.0: [WayBack] Use cases of [ordered], the new PowerShell 3.0 feature – Stack Overflow

It is way friendlier to show a message indicating the version is too old in stead of throwing this error.

That’s where the # Requires Version 3.0 directive comes in: [WayBackabout_Requires | Microsoft Docs.

Adding this line to the top of a script gives output like this on a stock Windows 7 SP1 system that has PowerShell 2.0:

# PowerShell -f List-Delphi-Installed-Packages.ps1
The script ‘List-Delphi-Installed-Packages.ps1’ cannot be run because it contained a “#requires” statement at line 1 for Windows PowerShell version 3.0. The version required by the script does not match the currently running version of Windows PowerShell version 2.0.
+ CategoryInfo : ResourceUnavailable: (List-Delphi-Installed-Packages.ps1:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptRequiresUnmatchedPSVersion

Note that PowerShell 3.0 is also the minimum version for debugging it in Visual Studio Code (which means you do not have to use PowerShell ISE any more; it is still there , but so far behind as a development tool that many prefer Visual Studio Code):

–jeroen

Posted in CommandLine, Development, PowerShell, PowerShell, Scripting, Software Development | Leave a Comment »

PowerShell: finding WSD printer details enumerating through HKLM\SYSTEM\CurrentControlSet\Enum\SWD\DAFWSDProvider

Posted by jpluimers on 2020/08/13

WSD seems the way Microsoft Windows 8+ does printing, which makes it a lot harder to find the IP address of a printer, for instance to configure a Mac to print to it.

The key seems to be enumerating over HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\SWD\DAFWSDProvider.

Some links that should help me doing this:

–jeroen

Posted in Development, PowerShell, Scripting, Software Development | Leave a Comment »

Installing and updating Windows PowerShell – via Microsoft Docs

Posted by jpluimers on 2020/08/11

Since I keep forgetting that PowerShell is part of WMF (Windows Management Framework) and about the compatibility/installation matrix: [WayBack] Installing Windows PowerShell | Microsoft Docs:

The installation package for PowerShell comes inside a WMF installer. The version of the WMF installer matches the version of PowerShell; there’s no stand alone installer for Windows PowerShell.

If you need to update your existing version of PowerShell, in Windows, use the following table to locate the installer for the version of PowerShell you want to update to.

Windows PS 3.0 PS 4.0 PS 5.0 PS 5.1
Windows 10 (see Note1)
Windows Server 2016
installed
Windows 8.1
Windows Server 2012 R2
installed [WayBack] WMF 5.0 [WayBack] WMF 5.1
Windows 8
Windows Server 2012
installed [WayBack] WMF 4.0  [WayBack] WMF 5.0 [WayBack] WMF 5.1
Windows 7 SP1
Windows Server 2008 R2 SP1
[WayBack] WMF 3.0 [WayBack] WMF 4.0 [WayBack] WMF 5.0 [WayBack] WMF 5.1

To upgrade to WMF 5.0 from 4.0 you need to install .net 4.5 or later on your machine first. Then install WMF 5.0 RTM.

–jeroen

Posted in CommandLine, Development, PowerShell, PowerShell, Scripting, Software Development | Leave a Comment »

 
%d bloggers like this: