Finding Unapproved Verbs

Cmdlets and functions should use only approved verbs to make it easier on user to find commands, and improve consistency.

Here is quick audit code that shows all commands not adhering to this rule:

$approved = Get-Verb | Select-Object -ExpandProperty Verb

Get-Command -CommandType Cmdlet, Function |
  Where-Object { $approved -notcontains $_.Verb }

Any cmdlet and function returned here uses non-approved or no verbs at all.

Twitter This Tip! ReTweet this Tip!

Most Popular Verbs

Let’s explore which command verbs are most popular in your PowerShell:

Get-Command -CommandType cmdlet, function | 
Group-Object -Property Verb | 
Sort-Object -Property Count -Descending

Here is the result on our system:

 
Count Name                      Group                                            
----- ----                      -----                                            
  456 Get                       {Get-AppBackgroundTask, Get-AppvVirtualProcess...
  210 Set                       {Set-AssignedAccess, Set-AutologgerConfig, Set...
  120 Remove                    {Remove-AutologgerConfig, Remove-BCDataCacheEx...
  102 New                       {New-AutologgerConfig, New-DAEntryPointTableIt...
   72 Enable                    {Enable-BCDistributed, Enable-BCDowngrading, E...
   70                           {A:, ABC, AfterAll, AfterAll...}                 
   67 Add                       {Add-BCDataCacheExtension, Add-BitLockerKeyPro...
   65 Disable                   {Disable-BC, Disable-BCDowngrading, Disable-BC...
   28 Start                     {Start-Animation, Start-AppBackgroundTask, Sta...
   26 Update                    {Update-Disk, Update-DscConfiguration, Update-...
   24 Clear                     {Clear-AssignedAccess, Clear-BCCache, Clear-Bi...
   22 Export                    {Export-Application, Export-BCCachePackage, Ex...
   22 Invoke                    {Invoke-AsWorkflow, Invoke-Background, Invoke-...
   20 Import                    {Import-BCCachePackage, Import-BCSecretKey, Im...
   19 Stop                      {Stop-DscConfiguration, Stop-Dtc, Stop-DtcTran...
   19 Rename                    {Rename-DAEntryPointTableItem, Rename-MaskingS...
   19 Test                      {Test-Ancestor, Test-Descendent, Test-Dtc, Tes...
   16 Register                  {Register-ClusteredScheduledTask, Register-Dns...
   15 ConvertTo                 {ConvertTo-DataTemplate, ConvertTo-GridLength,...
   14 Write                     {Write-DtcTransactionsTraceSession, Write-Prin...
   14 Show                      {Show-Clock, Show-Details, Show-NetFirewallRul...
   14 Reset                     {Reset-BC, Reset-DAClientExperienceConfigurati...
   13 Unregister                {Unregister-AppBackgroundTask, Unregister-Clus...
   11 Out                       {Out-GridViewVertical, Out-Notepad, Out-Voice,...
   11 Copy                      {Copy-DependencyProperty, Copy-NetFirewallRule...
    9 Send                      {Send-EtwTraceSession, Send-PSCONFConfirmation...
    9 Find                      {Find-Command, Find-DscResource, Find-Module, ...
    9 ConvertFrom               {ConvertFrom-SddlString, ConvertFrom-TypeToScr...
    7 Save                      {Save-Module, Save-NetGPO, Save-NetworkSwitchC...
    7 Repair                    {Repair-FileIntegrity, Repair-VirtualDisk, Rep...
    7 Debug                     {Debug-FileShare, Debug-MMAppPrelaunch, Debug-...
    7 Format                    {Format-Hex, Format-Volume, Format-Custom, For...
    6 Suspend                   {Suspend-BitLocker, Suspend-PrintJob, Suspend-...
    6 Install                   {Install-Dtc, Install-ISEPreviewShortcut, Inst...
    6 Publish                   {Publish-BCFileContent, Publish-BCWebContent, ...
    6 Resume                    {Resume-BitLocker, Resume-PrintJob, Resume-Bit...
    6 Move                      {Move-Control, Move-SmbWitnessClient, Move-App...
    5 Restore                   {Restore-DscConfiguration, Restore-NetworkSwit...
    5 Restart                   {Restart-NetAdapter, Restart-PcsvDevice, Resta...
    5 Select                    {Select-Date, Select-UIType, Select-Object, Se...
    5 Mount                     {Mount-DiskImage, Mount-AppvClientConnectionGr...
    4 Uninstall                 {Uninstall-Dtc, Uninstall-Module, Uninstall-Sc...
    4 Disconnect                {Disconnect-IscsiTarget, Disconnect-VirtualDis...
    4 Connect                   {Connect-IscsiTarget, Connect-VirtualDisk, Con...
    4 Receive                   {Receive-DtcDiagnosticTransaction, Receive-Job...
    4 Unblock                   {Unblock-FileShareAccess, Unblock-SmbShareAcce...
    4 Assert                    {Assert-MockCalled, Assert-MockCalled, Assert-...
    4 Wait                      {Wait-Debugger, Wait-Event, Wait-Job, Wait-Pro...
    3 Complete                  {Complete-BitsTransfer, Complete-DtcDiagnostic...
    3 Resize                    {Resize-Partition, Resize-StorageTier, Resize-...
    3 Optimize                  {Optimize-StoragePool, Optimize-Volume, Optimi...
    3 Initialize                {Initialize-Disk, Initialize-EventHandler, Ini...
    3 Expand                    {Expand-Archive, Expand-WindowsCustomDataImage...
    3 Dismount                  {Dismount-DiskImage, Dismount-AppxVolume, Dism...
    3 Close                     {Close-Control, Close-SmbOpenFile, Close-SmbSe...
    3 Convert                   {Convert-Alias, Convert-Path, Convert-String}    
    2 Use                       {Use-Transaction, Use-WindowsUnattend}           
    2 Undo                      {Undo-DtcDiagnosticTransaction, Undo-Transaction}
    2 Trace                     {Trace-Command, Trace-SteroidsOutput}            
    2 Split                     {Split-Path, Split-WindowsImage}                 
    2 Resolve                   {Resolve-DnsName, Resolve-Path}                  
    2 Measure                   {Measure-Command, Measure-Object}                
    2 Join                      {Join-DtcDiagnosticResourceManager, Join-Path}   
    2 Exit                      {Exit-PSHostProcess, Exit-PSSession}             
    2 Read                      {Read-PrinterNfcTag, Read-Host}                  
    2 Block                     {Block-FileShareAccess, Block-SmbShareAccess}    
    2 Enter                     {Enter-PSHostProcess, Enter-PSSession}           
    2 Revoke                    {Revoke-FileShareAccess, Revoke-SmbShareAccess}  
    2 Do                        {Do-Something, Do-SomethingWeird}                
    2 Sync                      {Sync-NetIPsecRule, Sync-AppvPublishingServer}   
    2 Edit                      {Edit-StringList, Edit-CIPolicyRule}             
    2 Hide                      {Hide-UIElement, Hide-VirtualDisk}               
    2 Grant                     {Grant-FileShareAccess, Grant-SmbShareAccess}    
    1 Unlock                    {Unlock-BitLocker}                               
    1 Unpublish                 {Unpublish-AppvClientPackage}                    
    1 Unprotect                 {Unprotect-CmsMessage}                           
    1 Open                      {Open-NetGPO}                                    
    1 Lock                      {Lock-BitLocker}                                 
    1 Tee                       {Tee-Object}                                     
    1 Switch                    {Switch-Certificate}                             
    1 Sort                      {Sort-Object}                                    
    1 Backup                    {Backup-BitLockerKeyProtector}                   
    1 Protect                   {Protect-CmsMessage}                             
    1 Compress                  {Compress-Archive}                               
    1 Pop                       {Pop-Location}                                   
    1 Merge                     {Merge-CIPolicy}                                 
    1 Encrypt                   {Encrypt-Text}                                   
    1 Limit                     {Limit-EventLog}                                 
    1 Group                     {Group-Object}                                   
    1 ForEach                   {ForEach-Object}                                 
    1 Confirm                   {Confirm-SecureBootUEFI}                         
    1 Decrypt                   {Decrypt-Text}                                   
    1 Compare                   {Compare-Object}                                 
    1 Checkpoint                {Checkpoint-Computer}                            
    1 Push                      {Push-Location}                                  
    1 Where                     {Where-Object}
 

What’s even more interesting, here are the top 6 PowerShell cmdlet verbs:

 
PS C:> Get-Command -CommandType cmdlet, function  | 
Group-Object -Property Verb | 
Sort-Object -Property Count -Descending |
Where-Object { $_.Name } |
Select-Object -First 6 -Property Count, Name

Count Name  
----- ----  
  456 Get   
  210 Set   
  120 Remove
  102 New   
   72 Enable
   67 Add
 

So these top six verbs account for just 6% of all verbs, but for more than 60% of all commands.

Twitter This Tip! ReTweet this Tip!

Safely Encrypting and Decrypting Text

When you encrypt secret information, the challenge is to find a good secret. One particular safe secret would be your Windows identity, paired with your computer’s identity. This can be used to encrypt sensitive personal information on a particular computer.

Here are two functions that illustrate how it’s done:

function Decrypt-Text
{
  
  param
  (
    [String]
    [Parameter(Mandatory,ValueFromPipeline)]
    $EncryptedText
  )
  process
  {
    $secureString = $EncryptedText | ConvertTo-SecureString
    $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString)
    [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
  }
}

function Encrypt-Text
{
  
  param
  (
    [String]
    [Parameter(Mandatory,ValueFromPipeline)]
    $Text
  )
  process
  {
     $Text | 
       ConvertTo-SecureString -AsPlainText -Force | 
       ConvertFrom-SecureString
  }
}

'PowerShell Rocks' | Encrypt-Text 
'Hello, World!' | Encrypt-Text | Decrypt-Text

You can safely save the encrypted text to a file. Only you will be able to read in and decrypt that text again, and only if it is done on the computer used to encrypt the data.

Twitter This Tip! ReTweet this Tip!

Watch Out When Combining -Force and -WhatIf!

The -WhatIf common parameter turns on simulation mode, so a cmdlet won’t change anything and instead report what it “would have” changed. This works perfectly well, unless a developer fails to implement -WhatIf correctly.

This is rare, but there is a pattern: when you specify -Force and -WhatIf, the right thing would be to let -WhatIf win. Some developers are so focused on -Force that they let -Force win. Try it with Remove-SmbShare, for example.

Twitter This Tip! ReTweet this Tip!

Creating File Shares

In Server 2012 R2 and Windows 8.1, there are many useful new modules with cmdlets such as New-SmbShare which creates new file shares easily.

If you don’t have these cmdlets, you can often use WMI instead. That requires more investigation and googling, but once you have a code template, it works well.

To create new file shares as an Administrator, for example, try this:

$share = [wmiclass]"Win32_Share" 
$path = 'c:logs'
$name = 'LogShare'
$maxallowed = 10
$description = 'Place log files here'

$share.Create( $path, $name, 0, $maxallowed,$description,$null,$null)

Twitter This Tip! ReTweet this Tip!

Using Custom Scopes to Discard Any Output

Yesterday we looked at custom scopes to automatically restore variables and clean up behind your code.

Custom scopes can also be used to discard any output emitted by any part of code inside your scope. To do that, use this structure: $null = . { [code] }. Whatever you execute in the braces will run, and all variables and functions you might create will work outside of the scope, but there will not be any output.

Let’s look at this function:

function Out-Voice ($Text)
{
  $sapi = New-Object -ComObject Sapi.SpVoice
  $sapi.Speak($Text)
}

Out-Voice -Text 'Hello, Dude.'

When you run it, it makes Windows speak, but also outputs the number “1”. As it turns out, the method Speak() does this, and when you consider larger and more complex portions of code, there are many places where you’d produce data that you really don’t need.

Here is a fool-proof “diaper” function building that does the exact same, but is guaranteed to not return any value:

function Out-Voice ($Text)
{
  $null = . {
      $sapi = New-Object -ComObject Sapi.SpVoice
      $sapi.Speak($Text)
    }
}

Out-Voice -Text 'Hello, Dude.'

Twitter This Tip! ReTweet this Tip!