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,357 other followers

Archive for the ‘PowerShell’ Category

Preference variable $ConfirmPreference allows getting more or less PowerShell confirmation prompts

Posted by jpluimers on 2021/05/04

On my list to experiment with are [Wayback] about_Preference_Variables – PowerShell | Microsoft Docs, especially

$ConfirmPreference

Determines whether PowerShell automatically prompts you for confirmation before running a cmdlet or function.

The¬†$ConfirmPreference¬†variable’s valid values are¬†High,¬†Medium, or¬†Low. Cmdlets and functions are assigned a risk of¬†High,¬†Medium, or¬†Low. When the value of the¬†$ConfirmPreference¬†variable is less than or equal to the risk assigned to a cmdlet or function, PowerShell automatically prompts you for confirmation before running the cmdlet or function.

If the value of the $ConfirmPreference variable is None, PowerShell never automatically prompts you before running a cmdlet or function.

To change the confirming behavior for all cmdlets and functions in the session, change¬†$ConfirmPreference¬†variable’s value.

To override the¬†$ConfirmPreference¬†for a single command, use a cmdlet’s or function’s¬†Confirm¬†parameter. To request confirmation, use¬†-Confirm. To suppress confirmation, use¬†-Confirm:$false.

Valid values of $ConfirmPreference:

  • None: PowerShell doesn’t prompt automatically. To request confirmation of a particular command, use the¬†Confirm¬†parameter of the cmdlet or function.
  • Low: PowerShell prompts for confirmation before running cmdlets or functions with a low, medium, or high risk.
  • Medium: PowerShell prompts for confirmation before running cmdlets or functions with a medium, or high risk.
  • High: PowerShell prompts for confirmation before running cmdlets or functions with a high risk.

–jeroen

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

PowerShell: avoid Write-Output, use Return only for ending execution, use $Output variable for returning additional output

Posted by jpluimers on 2021/02/18

Recently, I bumped into [WayBack] Write-Output confusion for the upteenth time.

Luckily I had the below links archived, basically invalidating the use of Write-Output, and invalidating the answer at [WayBack] powershell – What’s the difference between “Write-Host”, “Write-Output”, or “[console]::WriteLine”? – Stack Overflow.

  • [WayBack] Write-Output vs. Return vs. $Output ¬∑ Issue #46 ¬∑ PoshCode/PowerShellPracticeAndStyle ¬∑ GitHub

    Jaykulcommented on Aug 2, 2016

    @maekee to sum up this long thread:

    In other programming languages with a¬†return¬†statement, the¬†return¬†statement is contractual: nothing returns output from a function¬†except¬†the¬†return¬†statement. Thus, for people with experience in other languages, the presence of code like¬†return $output¬†in PowerShell is misleading. They think: “oh, ok, PowerShell has a return statement” and don’t realize that any un-captured result values get output also — and don’t even realize they¬†can¬†output multiple times.

    The reasoning for, and objection to, Write-Output is similar. People like it because:

    … always explicitly sending an object to a stream… makes it easier to understand [the code] at a glance in the future.

    The problem is that this can lead to a¬†false sense of security. If you see¬†Write-Output¬†you assume that output can only come from lines with¬†Write-Output, when in reality it can come from any command or method call. Or at least, any that doesn’t start with an assignment (or¬†[void]¬†cast), or end with out-null …

    So while some people like it because it¬†highlights¬†the spots where you¬†intentionally¬†output something — other people argue it’s presence distracts you from the fact that other lines¬†could¬†output.

    Therefore

    Since¬†return¬†cannot¬†always¬†be used (sometimes you need to write output more than once), you should prefer¬†Write-Output¬†and use¬†return¬†only for ending execution. But since¬†Write-Output¬†can lead to false expectations and in addition is¬†slightly¬†slower, (and worse, can be overwritten by functions or aliases) …

    We recommend:

    Use return only for ending execution.

    Avoid Write-Output (although you may want to use for it’s -NoEnumerate switch). Instead, when you want to make output clearer, just assign output to a relevantly named variable. and put that a variable on a line by itself to signal explicit output.

  • and

    Jaykulcommented 12 hours ago

    TIL¬†Write-Output -NoEnumerate¬†is¬†broken¬†on PowerShell 6 and¬†has been for 16 months or longer¬†— there’s no plan to fix it. In summary:

    DO NOT USE Write-Output — EVER.

  • [WayBack] Write-Output -NoEnumerate outputs PSObject[] rather than Object[] and generally doesn’t respect the input collection type ¬∑ Issue #5955 ¬∑ PowerShell/PowerShell ¬∑ GitHub

Via:

[WayBack] Joel Bennett on Twitter: “

Write-Output considered EVEN MORE harmful! Most #PowerShell experts recommend against Write-Output

Now, I find there is a long standing bug in PowerShell 6’s -NoEnumerate switch.¬†

I no longer accept PRs which use Write-Output”

–jeroen

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

Windows command prompt: decrementing loop

Posted by jpluimers on 2020/12/30

I needed a decrementing loop on the Windows command prompt, but that seems very hard from batch files without programming your own kind of while loop:

PowerShell to the rescue to loop back from and including 463 down to and including 290:

PowerShell -Command "for ($i=463; $i -ge 290; $i--) { Write-Host "Value " $i}"

This outputs:

Value 463
Value 462
...
Value 291
Value 290

In a similar way, you can execute a cmd command, but then you need to be careful on how to pass parameters: the \" is important to you can have quotes within quoted strings..

PowerShell -Command "for ($i=463; $i -ge 290; $i--) { & echo \"Value $i\"}"

gives this:

Value 463
Value 462
...
Value 291
Value 290

Read the rest of this entry »

Posted in Batch-Files, CommandLine, Console (command prompt window), Development, PowerShell, PowerShell, Scripting, Software Development, Windows | 1 Comment »

On Windows 7 and 8.x too: Completely disable Windows 10 telemetry collection ‚Äď twm’s blog

Posted by jpluimers on 2020/12/10

From [WayBack] Completely disable Windows 10 telemetry collection ‚Äď twm’s blog:

So I don‚Äôt forget: According to an article in c‚Äôt magazine, disabling the ‚ÄúDiagTrack‚ÄĚ service (‚ÄúConnected User Experience and Telemetry‚ÄĚ) will completely disable user tracking in Windows 10. They also say that they did not see any negative effects.

Source: [WayBack] Telefonierverbot in c’t 01/2019 page 172 (in German)

I saw at least one system where the service is not shown when you run Services.msc: it did not list DiagTrack, nor Connected User Experience and Telemetry. How awful is that!

The service can also be installed non older Windows versions: [WayBack] Just found DiagTrack running in Services РTips and Tricks

Sometimes, it gets re-enabled. I think this happens during major Windows updates.

To inspect, stop and disable

Run all commands from the console the below bold commands. The non-bold text was the output on my system. If instead of the cmd.exe console, you run a PowerShell console, then remove the bits PowerShell -Command " and " at the start and end of each command.

The first command does not require an Administrative (UAC Elevated) command prompt; the last one does.

However, the first command, needs the | Select-Object * bit as otherwise most of the fields will not be displayed, excluding for instance StartType.

powershell -Command "Get-Service -Name DiagTrack | Select-Object *"


Name                : DiagTrack
RequiredServices    : {RpcSs}
CanPauseAndContinue : False
CanShutdown         : True
CanStop             : True
DisplayName         : Connected User Experiences and Telemetry
DependentServices   : {}
MachineName         : .
ServiceName         : DiagTrack
ServicesDependedOn  : {RpcSs}
ServiceHandle       :
Status              : Running
ServiceType         : Win32OwnProcess
StartType           : Automatic
Site                :
Container           :

On an Administrative command-prompt:

powershell -Command "Set-Service -Name DiagTrack -StartUpType Disabled"
powershell -Command "Get-Service -Name DiagTrack | Stop-Service"

Two notes:

Read the rest of this entry »

Posted in Batch-Files, CommandLine, Development, Power User, PowerShell, PowerShell, Scripting, Software Development, Windows | Leave a Comment »

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 »

 
%d bloggers like this: