Create ASCII Art

It’s amazing how versatile PowerShell is: with just a couple of lines of code, you can turn any photo and image into a piece of ASCII art. PowerShell simply loads the image, then scans it line by line and row by row, and replaces each pixel with an ASCII character, based on the pixel brightness.

Here is the function:

 function Convert-ImageToAsciiArt
{
  param(
    [Parameter(Mandatory)][String]
    $Path,
    
    [ValidateRange(20,20000)]
    [int]$MaxWidth=80,
    
    # character height:width ratio
    [float]$ratio = 1.5
  )

  # load drawing functionality
  Add-Type -AssemblyName System.Drawing
  
  # characters from dark to light
  $characters = '$#[email protected]*+;:-,. '.ToCharArray()
  $c = $characters.count
  
  # load image and get image size
  $image = [Drawing.Image]::FromFile($path)
  [int]$maxheight = $image.Height / ($image.Width / $maxwidth)/ $ratio
  
  # paint image on a bitmap with the desired size
  $bitmap = new-object Drawing.Bitmap($image,$maxwidth,$maxheight)
  
  
  # use a string builder to store the characters
  [System.Text.StringBuilder]$sb = ""
  
  # take each pixel line...
  for ([int]$y=0; $y -lt $bitmap.Height; $y++){
    # take each pixel column...
    for ([int]$x=0; $x -lt $bitmap.Width; $x++){
      # examine pixel
      $color = $bitmap.GetPixel($x,$y)
      $brightness = $color.GetBrightness()
      # choose the character that best matches the
      # pixel brightness
      [int]$offset = [Math]::Floor($brightness*$c)
      $ch = $characters[$offset]
      if (-not $ch){ $ch = $characters[-1] }      
      # add character to line
      $null = $sb.Append($ch)
    }
    # add a new line
    $null = $sb.AppendLine()
  }

  # clean up and return string
  $image.Dispose()
  $sb.ToString()
}

And this is how you can use it:

$Path = "C:UsersTobiasDesktopSomepic.jpg"
$OutPath = "$env:tempasciiart.txt"

Convert-ImageToAsciiArt -Path $Path -MaxWidth 150 |
  Set-Content -Path $OutPath -Encoding UTF8 


Invoke-Item -Path $OutPath 

Just make sure you adjust the paths in the code. The ASCII art opens in your default text editor. Make sure you disable line wrap, choose a fixed-width font and a small-enough font size!

                                                                                                    
                                                                                                                            
                                         ;@[email protected][email protected]+-                                           
                                       :@&&&&&&&&&&&&&&&&&&:.                                       
                                     ,&&&&&&&&&&&&&&&&&&&&&&&&&&*                                   
                                  [email protected]&&&&&&&&&&&HHHHHH&&&&&&&&&&&&&*                                 
                               :[email protected]                               
                              *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&,                             
                             :&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-                            
                            *&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&*                           
                           &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&                          
                          @&&&&&&&&H&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&-                        
                         [email protected];:+&&&&&&&*-....,:@[email protected]                       
                        &&&&&&&&H&&;........................*&&&&&&&H&&&&&&&&&.                     
                      .&&&&&&&&&H;...........................&&&&&&&&H&&&&&&&&&-                    
                     ;&&&&&&&&&&:[email protected]@&&&&&&H&&&&&&&&&&                    
                    &&&&&&&&&&&.+...........................-.;[email protected]                   
                   *&H&&&&&&&&;;[email protected]+&&HH&&&&&&&&&&&&                   
                   ;[email protected]*.&&&H&&&&&&&&&&&&:                  
                   :&H&&&&&&&*...............................:*[email protected]                  
                   ,[email protected][email protected],&&&&&&&&&&&&&&&&&,                 
                   ,&&&&&&:+....................................+*.;:&&&&&&&&&&&&&&                 
                   [email protected]*@+&&&&&&&&&,                
                   &&&&&&;............................................,-..-+&&&&&&&                 
                  :[email protected]:&&&&&,                
                  &&&&&&&.....................................................&&&&&-                
                  &&&&&&+.....................................................&&&&&,,               
                  :&&&&&;.....................................................&&&H&                 
                   &&&&&;.......................................,.,[email protected]               
                  *-&&&&:...*[email protected]*,.............-*&&&&&&&&&&&&:[email protected]&&&&+                
                    &&&&:.+&&HHHHHHHHHHHHH&&&&..........+&&&&HHHHHHHHHHHHH*[email protected]                
                   ,###H*+;;:,...........-;*&&##########&&&*:..........:;*@:;*&###H:                
                   :##H*.......................#@;---+#;[email protected]###.                
                  ,@###+............+HH&+.....-&......-*......;&H&*............&##:.                
                   ,&&#-...........HHH&+H;[email protected];......,#[email protected];[email protected]&-.                
                   ..;#,...........HHHHHH+....#........H,....&HHHHH&..........-#&:-                 
                   ...H*...........-;;;;;....-H........;@....,;;;;;,..........;#&..                 
                   ...&#.....................#-.........#.....................&H*..                 
                   ...:H&........,.........-#@..........-#;..........,,......:#&,..                 
                    ...-,&###&+::-,,::+&###+......  ......-###H*:::,,::[email protected]####,....                  
                    ..........,,,,,,,,...........   ............,,,,,,,,..........                  
                     ............................   ..............................                  
                     ............................   .............................                   
                      .....................,.....   ............................                    
                       ....................,.....   .......,...................                     
                         ..................,,,...   .......,.................                       
                          ......................,.  ..,......................                       
                          ........................,,,.......................                        
                          ..................................................                        
                           .................................................                        
                           .............,-..................--.............                         
                            ...............--,,-----:-,. --...............                          
                             ..................,,----,,...................                          
                              ...........................................                           
                               .........................................                            
                                ......................................                              
                                 ....................................                               
                                   ................................                                 
                                    ..............................                                  
                                     .,,,,,,,,,,,,,,,,,,,,,,,,,,                                    
                                   ,&...,,,,,,,,,,,,,,,,,,,,,,[email protected],                                 
                                &HHH......,,,,,,,,,,,,,,,,,,.....-HHH&                              
                            :HHHHHHH&.........,,,,,,,,,,,........HHHHHHHH;                          
                         *HHHHHHHHHHHH+........................*[email protected]                       
                      -HHHHHHHHHHHHHHHHH&;..................;&HHHHHHHHHHHHHHHHH,                    
                     HHHHHHHHHHHHHHHHHHHHHHHH&*;:---::;*&HHHHHHHHHHHHHHHHHHHHHHH&                   
                    HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH                  

And here’s a cool fine-tuning trick: in the function Convert-ImageToAsciiArt, take a look at $characters. It is a string with the characters used in your ASCII art, and the characters are listed in descending brightness. For a black and white drawing, you could as well try:

   $characters = [char]0x2588, ' '  

psconf.eu – PowerShell Conference EU 2019 – June 4-7, Hannover Germany – visit www.psconf.eu There aren’t too many trainings around for experienced PowerShell scripters where you really still learn something new. But there’s one place you don’t want to miss: PowerShell Conference EU – with 40 renown international speakers including PowerShell team members and MVPs, plus 350 professional and creative PowerShell scripters. Registration is open at www.psconf.eu, and the full 3-track 4-days agenda becomes available soon. Once a year it’s just a smart move to come together, update know-how, learn about security and mitigations, and bring home fresh ideas and authoritative guidance. We’d sure love to see and hear from you!

Twitter This Tip! ReTweet this Tip!

Verifying Local User Account Passwords

In the previous tip, we asked Active Directory to validate user account passwords. The same can be done with local accounts. Your PowerShell code can use local account passwords to manage access to scripts or partial script functionality. Of course, you could also use the code below to create your own brute-force password penetration tool.

By default, below script uses your current user name. Make sure $UserName is the user account name for a local user account:

# specify local user name and password to test
$UserName = $env:USERNAME
$Password = Read-Host -Prompt "Enter password to test"

# test password
Add-Type -AssemblyName System.DirectoryServices.AccountManagement 
$type = [DirectoryServices.AccountManagement.ContextType]::Machine
$PrincipalContext = [DirectoryServices.AccountManagement.PrincipalContext]::new($type)
$PrincipalContext.ValidateCredentials($UserName,$Password)

Your learning points:

  • PowerShell can ask the local Windows user database to verify a password. This way, you can use Passwords maintained by Windows to decide whether a script should execute or what it should the user enable to do
  • Keep in mind that it is bad security practice to ask users for their passwords because they cannot know what you are going to do with their password.

psconf.eu – PowerShell Conference EU 2019 – June 4-7, Hannover Germany – visit www.psconf.eu There aren’t too many trainings around for experienced PowerShell scripters where you really still learn something new. But there’s one place you don’t want to miss: PowerShell Conference EU – with 40 renown international speakers including PowerShell team members and MVPs, plus 350 professional and creative PowerShell scripters. Registration is open at www.psconf.eu, and the full 3-track 4-days agenda becomes available soon. Once a year it’s just a smart move to come together, update know-how, learn about security and mitigations, and bring home fresh ideas and authoritative guidance. We’d sure love to see and hear from you!

Twitter This Tip! ReTweet this Tip!

Verifying Domain Account Passwords

PowerShell can easily verify a password against a domain account. In other words, you can bind script logic to passwords maintained in Active Directory.

Here is the code required to send a password to AD and get back a Boolean value: $true if the password is correct, else $false:

# specify user name and user domain
$UserDomain = $env:USERDOMAIN
$UserName = $env:USERNAME
$Password = Read-Host -Prompt "Enter password to test"

# test password
Add-Type -AssemblyName System.DirectoryServices.AccountManagement 
$ContextType = [System.DirectoryServices.AccountManagement.ContextType]::Domain
$PrincipalContext = [System.DirectoryServices.AccountManagement.PrincipalContext]::new($ContextType, $UserDomain)
$PrincipalContext.ValidateCredentials($UserName,$Password)

Note that this code requires an Active Directory and does not work with local accounts. By default, it uses your current account details. Adjust the $UserDomain, $UserName, and $Password variables accordingly. Note also that ValidateCredentials()checks clear-text string passwords. Be careful and do not store clear-text passwords in scripts. Also, better not ask users to enter passwords as clear text.

Your learning points:

  • PowerShell can easily connect to Active Directory and ask for a password validation

psconf.eu – PowerShell Conference EU 2019 – June 4-7, Hannover Germany – visit www.psconf.eu There aren’t too many trainings around for experienced PowerShell scripters where you really still learn something new. But there’s one place you don’t want to miss: PowerShell Conference EU – with 40 renown international speakers including PowerShell team members and MVPs, plus 350 professional and creative PowerShell scripters. Registration is open at www.psconf.eu, and the full 3-track 4-days agenda becomes available soon. Once a year it’s just a smart move to come together, update know-how, learn about security and mitigations, and bring home fresh ideas and authoritative guidance. We’d sure love to see and hear from you!

Twitter This Tip! ReTweet this Tip!

Waiting for a Service Status Change

Whenever you start or stop a service, it may take some time for the service to actually adopt the desired state – or it can of course fail. When you use Stop-Service, PowerShell waits until the desired service state is confirmed. If you want to respond to service changes initiated elsewhere, here is some monitoring code that pauses PowerShell until the desired service status is reached:

# wait 5 seconds for spooler service to stop
$serviceToMonitor = Get-Service -Name Spooler
$desiredStatus = [System.ServiceProcess.ServiceControllerStatus]::Stopped
$maxTimeout = New-TimeSpan -Seconds 5

try
{
  $serviceToMonitor.WaitForStatus($desiredStatus, $maxTimeout)
}
catch [System.ServiceProcess.TimeoutException]
{
  Write-Warning 'Service did not reach desired status within timeframe.'
}

You can use this chunk of code to respond to service changes triggered by outside systems, or double-check service status after own changes you committed to its settings.

Your learning points:

  • Most objects that you get from cmdlets (like Get-Service)have a number of useful methods. All service objects feature the WaitForStatus method, for example, and our example showed how it can be used.
  • To discover other methods hidden in objects, try this:
# get some object 
$objects = Get-Process 

# dump the methods
$objects | Get-Member -MemberType *method* | Select-Object -Property Name, Definition

psconf.eu – PowerShell Conference EU 2019 – June 4-7, Hannover Germany – visit www.psconf.eu There aren’t too many trainings around for experienced PowerShell scripters where you really still learn something new. But there’s one place you don’t want to miss: PowerShell Conference EU – with 40 renown international speakers including PowerShell team members and MVPs, plus 350 professional and creative PowerShell scripters. Registration is open at www.psconf.eu, and the full 3-track 4-days agenda becomes available soon. Once a year it’s just a smart move to come together, update know-how, learn about security and mitigations, and bring home fresh ideas and authoritative guidance. We’d sure love to see and hear from you!

Twitter This Tip! ReTweet this Tip!