Using a Progress Bar Wisely

PowerShell comes with support for progress bars. Here is a very simple example:

1..100 | ForEach-Object {
  Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $_
  Start-Sleep -Milliseconds 100
}

Using a progress bar can be valuable as long as you don’t call Write-Progress excessively. Especially with long-running loops, it makes no sense to call Write-Progress for each loop iteration. If you do, your scripts become very slow.

Let’s assume for example you have a loop that runs 10000 times. Displaying a progress bar will slow down the script considerably:

$min = 1
$max = 10000

$start = Get-Date

$min..$max | ForEach-Object {
  $percent = $_ * 100 / $max
  Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $percent
}

$end = Get-Date

($end-$start).TotalMilliseconds

This delay is directly related to the number of calls to Write-Progress, so if you change the value for $max to 100000, the script takes 10 times the time, just because Write-Progress is called 10 times more often.

That’s why you should add an intelligent mechanism to limit the number of calls to Write-Progress. The following example updates the progress bar in 0.1% increments:

$min = 1
$max = 10000

$start = Get-Date

# update progress bar every 0.1 %
$interval = $max / 1000

$min..$max | ForEach-Object {
  $percent = $_ * 100 / $max
  
  if ($_ % $interval -eq 0)
  {
    Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $percent
  }
}

$end = Get-Date

($end-$start).TotalMilliseconds

When you increase the number for $max, you will now notice that the script won’t take much longer because the number of calls to Write-Progress stays the same.

Twitter This Tip! ReTweet this Tip!

Bulk Renaming Photos

Here is a quick and fast way to bulk-rename files like photos, or other files. Have a look:

#requires -Version 1.0
$Path = "$homePictures"
$Filter = '*.jpg'

Get-ChildItem -Path $Path -Filter $Filter | 
  Rename-Item -NewName {$_.name -replace 'DSC','TEST'}

Simply adjust the path and the filter to target the files. In the example, all *.jpg files in the pictures folder are checked, and the keyword “DSC” is replaced by “TEST”. Make sure you adjust the script parameters to your needs.

To rename files recursively, add the –Recurse parameter to Get-ChildItem. But, be careful. This small piece of code can rename thousands of files in a blink of an eye.

Twitter This Tip! ReTweet this Tip!

Identifying Locked AD Accounts

When searching for specific AD accounts, you may have used Get-ADUser in the past, and filtered results with a filter parameter. Such filters can grow quite complex, though.

That’s why there is a shortcut for the most common AD searches. Simply use Search-ADAccount:

#requires -Modules ActiveDirectory


Search-ADAccount -AccountDisabled 
Search-ADAccount -AccountExpired
Search-ADAccount -AccountInactive

Search-ADAccount exposes parameters to search for the most common criteria.

Twitter This Tip! ReTweet this Tip!

Exploring Local Account Management Cmdlets

PowerShell 5.1 (shipping with Windows 10 and Server 2016) can now natively manage local accounts. In the previous tip you learned how to use Get-LocalUser.

To explore other cmdlets for local account management, here is how you identify the module that exposes Get-LocalUser, and then list other cmdlets provided by that module:

#requires -Modules Microsoft.PowerShell.LocalAccounts

# find module that defines this cmdlet
$module = Get-Command -Name Get-LocalUser | Select-Object -ExpandProperty Source

# list all cmdlets defined by this module
Get-Command -Module $module

As it turns out, there is a whole bunch of new management cmdlets:

 
CommandType Name                    Version Source                            
----------- ----                    ------- ------                            
Cmdlet      Add-LocalGroupMember    1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Disable-LocalUser       1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Enable-LocalUser        1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Get-LocalGroup          1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Get-LocalGroupMember    1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Get-LocalUser           1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      New-LocalGroup          1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      New-LocalUser           1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Remove-LocalGroup       1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Remove-LocalGroupMember 1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Remove-LocalUser        1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Rename-LocalGroup       1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Rename-LocalUser        1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Set-LocalGroup          1.0.0.0 Microsoft.PowerShell.LocalAccounts
Cmdlet      Set-LocalUser           1.0.0.0 Microsoft.PowerShell.LocalAccounts
 

Twitter This Tip! ReTweet this Tip!

Managing Local Users

PowerShell 5.1 finally ships with cmdlets to manage local user accounts. To get a list of local user accounts, use Get-LocalUser and pipe the result to Select-Object to see all properties:

 
PS C:> Get-LocalUser | Select-Object -Property *


AccountExpires         : 
Description            : Predefined Account to manage computer or domain
Enabled                : False
FullName               : 
PasswordChangeableDate : 
PasswordExpires        : 
UserMayChangePassword  : True
PasswordRequired       : True
PasswordLastSet        : 7/10/2015 2:22:01 PM
LastLogon              : 12/8/2015 5:44:47 AM
Name                   : Administrator
SID                    : S-1-5-21-2012478179-265285931-690539891-500
PrincipalSource        : Local
ObjectClass            : User

AccountExpires         : 
Description            : User Account managed by system
Enabled                : False
FullName               : 
PasswordChangeableDate : 
PasswordExpires        : 
UserMayChangePassword  : True
PasswordRequired       : False
PasswordLastSet        : 
LastLogon              : 
Name                   : DefaultAccount
SID                    : S-1-5-21-2012478179-265285931-690539891-503
PrincipalSource        : Local
ObjectClass            : User

AccountExpires         : 
Description            : Predefined Account for Guest access
Enabled                : False
FullName               : 
PasswordChangeableDate : 
PasswordExpires        : 
UserMayChangePassword  : False
PasswordRequired       : False
PasswordLastSet        : 
LastLogon              : 
Name                   : Guest
SID                    : S-1-5-21-2012478179-265285931-690539891-501
PrincipalSource        : Local
ObjectClass            : User
...
 

Twitter This Tip! ReTweet this Tip!

Getting AD User Attributes

By default, Get-ADUser (provided by ActiveDirectory module which is part of the free Microsoft RSAT tools) retrieves only a few default properties. To get more information, use the –Properties parameter, and specify the properties you are after.

To get a list of all AD users with their notes and description fields, try this:

#requires -Modules ActiveDirectory 
Get-ADUser -Filter * -Properties Description, Info

If you don’t know the names of available properties, use “*” instead to retrieve all available properties.

Twitter This Tip! ReTweet this Tip!