Pablo's Powershell Pow-Wow

Discussion in 'Business & Enterprise Computing' started by PabloEscobar, Sep 18, 2014.

  1. PabloEscobar

    PabloEscobar Member

    Jan 28, 2008
    Since the dawn of time, Windows sysadmins have been dreaming of day when they can be as lazy as their *nix brethren. Dreaming of that day, when we would have easy access to a scripting language with some actual, real power behind it... well, Dream no more friends, for that day has arrived...

    Powershell History

    Powershell is the answer to our prayers. Powershell (Originally Monad) was released in 2006 on XP SP2, Server 2003/2008 and Vista. It's use was fairly limited, because you couldn't rely on it being available across all environments. Windows 7 (and Server 2008R2) bought integration to the table, in addition to a stack of more useful cmdlets (more on what the hell a "cmdlet" is later). Powershell V2 also bought the amazing Integrated Scripting Environment to users Desktops and servers, DavidRa has kindly provided a PowerShell IDE - Basics guide to provide a quick rundown of its use, and just how handy it can be.

    Prior to Powershell, Windows admins had to rely on batch scripting (cmd.exe) or WSH Scripting (VBScript/Jscript). While it was (and is) possible to leverage these to perform work, their lack of integration with the rest of the system made it far more difficult than it needed to be.

    But that's enough history... What can PowerShell do for me you ask... The answer to that, is as varied as your imagination, While its used primarily as a scripting language, its ability to instantiate .NET classes, means that it can (but probably shouldn't) be used a general purpose programming language.

    About the Author

    I've been using powershell since V2, and consider myself proficient enough to achieve my tasks, as with any programming language, there are many ways to do things... The right way, the wrong way, and the Max Power way (which is the wrong way, but faster). For the most part, I'd consider a script successful if it achieves its goals, and doesn't break anything on the way. I'm a sysadmin scripting.Not a programmer.

    About this Thread

    I'm aiming post something "new" each week, if you have something you would like explained or a "how do I X in powershell" feel free to request it" I feel its more relevant to B&EC than to P&SD purely because the bulk of the examples will be related to things a windows Sysadmin would be doing, rather than things a programmer would be doing. Ad-hoc answers have been provided to people in specific threads where powershell has been useful, This thread will serve to have them all in a single handy-dandy place.

    Thread Index

    Powershell Resources
    Approved Verbs List (For your own cmdlets)
    Some Best Practices when creating Modules
    Microsoft Powershell Survival Guide
    Windows Powershell Blog - Cool New Stuff
    <More to Come>
    Last edited: Oct 24, 2014
  2. OP

    PabloEscobar Member

    Jan 28, 2008
    A Powershell Primer

    Powershell uses cmdlets (prounounced Commandlets) that get strung together to achieve something useful.
    A Powershell cmdlet will normally take the form of <verb>-<noun>. Thinking back to High school, a verb is a "Doing word" and a noun is a "thing". Lets look at an example

    Its pretty simply, our verb (get) and our noun (process) combine, all we are doing here, is GETting all the Processes on our machine.

    Here's what it looks like

    PS C:\Users\Pablo> get-process
    Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
    -------  ------    -----      ----- -----   ------     -- -----------
        602      25    12236      12592   202 1,288.03   6004 Agent
        145       9     6720       9244    37   554.61   1888 audiodg
        991      61   121696     139836   388 1,767.25   6516
        249      36   160584     174764   520   129.00    920 chrome
        176      22    36744      30208   203    37.45   1744 chrome
        218      27    58720      64120   296     4.00   2560 chrome
        175      22    36712      28308   199     2.72   3108 chrome
       1339      75   104048     204084   511   176.09   4200 chrome
        182      24    54712      54680   247     2.33   4968 chrome
        184      26    68228      65540   279     2.41   5436 chrome
        199      26    61496      65100   268     9.91   5492 chrome
        174      28   102940      96544   251    20.78   5500 chrome
        205      26    56220      58212   333     8.59   7056 chrome
       1502      48   214500     287852   623   224.59   7384 chrome
        184      24    47680      45132   241     1.25   7652 chrome
        206      26    56796      74072   291    48.25   7816 chrome
        184      27    70316      65964   265     2.02   8036 chrome
         30       3     1468        324    12     0.03   5820 cmd
         58       7      992        476    51     0.02   2488 conhost
         43       5      712       3136    44     0.00   2512 conhost
         53       6      764        444    48            4000 conhost
         52       6     1000        952    48     0.84   4232 conhost
         58       7     1144        732    51     0.28   5828 conhost
         58       7     1812       5404    52     0.06   7044 conhost
        458      13     2260       2480    45             412 csrss
        323      35     3448       4828   338             492 csrss
        403      17     6612      10476    77            1592 dasHost
         88       6     1068       1036    29            3848 dllhost
        217      27    26400      22752   378             836 dwm
       1727      96    84104     101072   699   217.91   3140 explorer
        701      62    14724       9656   478            1324 hdhomerun_service
        255      67    32504      17608   612   158.67   6900 hdhomerun_setup
        432      55   420056     410524   600 ...62.00   6624 Hearthstone
          0       0        0          4     0               0 Idle
        517      26    44564      13260   229     4.36   4804 LCore
       1163      25     8412      11136    79             544 lsass
        532      49    95224      68208   278            2000 MsMpEng
       1125      36   208520     216840   407    10.17   6668 mstsc
        271      16    11328       4108    53            2596 NisSrv
         94       8     1320        800    90     0.34   5200 notepad
        386      84    16680      19784   139    35.00   3308 NvBackend
         97       9     1268       2008    46            1584 NvNetworkService
        110       9     2628       1952    36             844 nvSCPAPISvr
        149      10     2668       1096    78            1676 nvstreamsvc
        453      39     8392       6864   176            3984 nvstreamsvc
        241      15     4068       7328   103     0.69   4464 nvtray
        157       9     1920       2760    58             800 nvvsvc
        185      13     4196       4504    97             884 nvvsvc
        322      17     7700      12068   119             872 nvxdsync
        473      19    29796      21904   130            1524 officeclicktorun
         94       8      980       1080    45            1716 PnkBstrA
        411      24    70436      72276   611     0.80   7568 powershell
        151      10     2124       9352    69     0.00   5212 RuntimeBroker
        986     174   155284      75884   922    88.63   5068 ScriptEditor
        612      55    27016      19272   331            4304 SearchIndexer
        257       9     3356       4196    21             536 services
       1298     142   150216     150576   512 2,550.33   4956 Skype
         44       2      280        208     4             296 smss
        425      25     4504       3784    73            1352 spoolsv
        775      39    10568      14584    98             276 svchost
        420      16     5620       7380    42             680 svchost
        476      14     4608       5688    30             720 svchost
        630      27    27732      25216  4206             816 svchost
        869      30    17876      17200    86             956 svchost
       2596      84    49964      50428   539             980 svchost
        700      37    15476      19924  1180            1124 svchost
        535      39    20236      18872   121            1392 svchost
        497      26     7056       8776    61            1792 svchost
        181      11     2260       4212    61            1808 svchost
        105      10     1192       2152    20            2700 svchost
        417      34     6208       8524   625            3032 svchost
        345      31    18204      21132   287            5224 svchost
        235      11     1696       2852   110            1828 synergyd
        167      13     1744       6992   109    27.36   4380 synergys
        945       0     1172       6856    12               4 System
        262      13     5380       9636    89     0.16   3660 taskhost
        288      24     4992       6124   285     6.89   4032 taskhostex
        496      29    25532       3876   115            1916 TracSrvWrapper
        253      21    22124      23556   213     0.45   2836 UserAccountBroker
        162      11     2000       2104    62            2144 vmware-usbarbitrator64
        488      41    11192       7104   204     2.08   3280 vmware-view
        247      15     2612       2548    65            2448 vmware-view-usbd
         76       7      752        392    40             484 wininit
        159       8     1332       1860    53             572 winlogon
        405      25     6140       3232    97            5560 wmpnetwk
        198      15     2488       1596    69            2024 wsnm
        236      11     1404       5864    39            3204 WUDFHost
        455      40    34364      63840   353     0.44   3472 WWAHost
    "Thats Great Pablo" I hear you say "tasklist.exe give me pretty much the same thing, why do I want powershell?", "Excellent question" I say...

    Here is my tasklist.exe output (I hope I don't have anything strange running :)).

    Image Name                     PID Session Name        Session#    Mem Usage
    ========================= ======== ================ =========== ============
    System Idle Process              0 Services                   0          4 K
    System                           4 Services                   0      6,836 K
    smss.exe                       296 Services                   0        208 K
    csrss.exe                      412 Services                   0      2,480 K
    wininit.exe                    484 Services                   0        392 K
    csrss.exe                      492 Console                    1      8,016 K
    services.exe                   536 Services                   0      4,160 K
    lsass.exe                      544 Services                   0     11,100 K
    winlogon.exe                   572 Console                    1      1,860 K
    svchost.exe                    680 Services                   0      7,372 K
    svchost.exe                    720 Services                   0      5,752 K
    nvvsvc.exe                     800 Services                   0      2,760 K
    dwm.exe                        836 Console                    1     22,668 K
    nvSCPAPISvr.exe                844 Services                   0      1,952 K
    nvxdsync.exe                   872 Console                    1     12,068 K
    nvvsvc.exe                     884 Console                    1      4,504 K
    svchost.exe                    956 Services                   0     16,972 K
    svchost.exe                    980 Services                   0     48,136 K
    svchost.exe                    276 Services                   0     14,592 K
    svchost.exe                    816 Services                   0     20,144 K
    svchost.exe                   1124 Services                   0     19,924 K
    spoolsv.exe                   1352 Services                   0      3,792 K
    svchost.exe                   1392 Services                   0     18,936 K
    officeclicktorun.exe          1524 Services                   0     21,904 K
    NvNetworkService.exe          1584 Services                   0      2,008 K
    dasHost.exe                   1592 Services                   0     10,512 K
    nvstreamsvc.exe               1676 Services                   0      1,096 K
    PnkBstrA.exe                  1716 Services                   0      1,076 K
    svchost.exe                   1792 Services                   0      8,812 K
    svchost.exe                   1808 Services                   0      4,212 K
    synergyd.exe                  1828 Services                   0      2,852 K
    TracSrvWrapper.exe            1916 Services                   0      3,876 K
    MsMpEng.exe                   2000 Services                   0     67,888 K
    wsnm.exe                      2024 Services                   0      1,596 K
    hdhomerun_service.exe         1324 Services                   0      9,656 K
    vmware-usbarbitrator64.ex     2144 Services                   0      2,104 K
    vmware-view-usbd.exe          2448 Services                   0      2,548 K
    NisSrv.exe                    2596 Services                   0        852 K
    svchost.exe                   2700 Services                   0      2,152 K
    svchost.exe                   3032 Services                   0      8,536 K
    dllhost.exe                   3848 Services                   0      1,036 K
    nvstreamsvc.exe               3984 Console                    1      6,864 K
    conhost.exe                   4000 Console                    1        444 K
    taskhostex.exe                4032 Console                    1      7,048 K
    explorer.exe                  3140 Console                    1    120,896 K
    NvBackend.exe                 3308 Console                    1     19,820 K
    SearchIndexer.exe             4304 Services                   0     19,228 K
    nvtray.exe                    4464 Console                    1      7,328 K
    LCore.exe                     4804 Console                    1     13,260 K
    Skype.exe                     4956 Console                    1    150,628 K
    ScriptEditor.exe              5068 Console                    1     75,828 K
    wmpnetwk.exe                  5560 Services                   0      3,232 K
    cmd.exe                       5820 Console                    1      1,080 K
    conhost.exe                   5828 Console                    1      2,528 K
    conhost.exe                   2488 Console                    1        476 K
    notepad.exe                   5200 Console                    1        800 K
    vmware-view.exe               3280 Console                    1      7,104 K
    Agent.exe                     6004 Console                    1     12,568 K
    conhost.exe                   4232 Console                    1        952 K                6516 Console                    1    139,824 K
    hdhomerun_setup.exe           6900 Console                    1     17,608 K
    WWAHost.exe                   3472 Console                    1     63,840 K
    RuntimeBroker.exe             5212 Console                    1      9,352 K
    UserAccountBroker.exe         2836 Console                    1     23,556 K
    mstsc.exe                     6668 Console                    1    216,840 K
    Hearthstone.exe               6624 Console                    1    410,528 K
    audiodg.exe                   1888 Services                   0      9,256 K
    taskhost.exe                  3660 Console                    1      9,636 K
    synergys.exe                  4380 Console                    1      6,992 K
    conhost.exe                   2512 Console                    1      3,136 K
    chrome.exe                    4200 Console                    1    210,612 K
    chrome.exe                    7384 Console                    1    317,828 K
    chrome.exe                    1744 Console                    1     33,636 K
    chrome.exe                    5500 Console                    1    102,820 K
    chrome.exe                    3108 Console                    1     27,184 K
    chrome.exe                    7816 Console                    1     80,584 K
    chrome.exe                     920 Console                    1    112,680 K
    chrome.exe                    8036 Console                    1     66,048 K
    chrome.exe                    7652 Console                    1     45,132 K
    chrome.exe                    5436 Console                    1     65,580 K
    chrome.exe                    7056 Console                    1     58,172 K
    chrome.exe                    4968 Console                    1     54,588 K
    chrome.exe                    5492 Console                    1     64,096 K
    WUDFHost.exe                  3204 Services                   0      5,884 K
    chrome.exe                    2560 Console                    1     61,996 K
    powershell.exe                7568 Console                    1     56,792 K
    conhost.exe                   7044 Console                    1      5,464 K
    chrome.exe                    6048 Console                    1     89,932 K
    chrome.exe                    3404 Console                    1     60,384 K
    chrome.exe                    4916 Console                    1     56,236 K
    WmiPrvSE.exe                  6500 Services                   0      6,680 K
    tasklist.exe                  5948 Console                    1      5,448 K
    clip.exe                      3900 Console                    1      2,672 K

    Both get-process and tasklist.exe appear to return a bunch of text, but, like a beautiful girl in a wonderbra, looks can be deceiving...

    If I want to get the PID of my hearthstone process, to parse the output of tasklist.exe, I would need something like

    C:\Users\Pablo>for /f "tokens=2 delims=," %F in ('tasklist /nh /fi "imagename eq
    Hearthstone.exe" /fo csv') do @echo %~F
    Sure, it gets the answer (6624) but its like its in a different language... lets see if we can achieve the same thing in powershell

    PS C:\Users\Adam> Get-Process | where-object {$ -eq "Hearthstone"} | select-object Name,ID | Format-table -autosize
    Name          Id
    ----          --
    Hearthstone 6624
    This is introducing a few more basic concepts. | (the character probably above your backslash key) is a pipe, its function is to control the powershell "pipeline". $_ represents the object being passed down the pipeline, so lets break it down...

    Get_Process - We are getting a list of our processes
    | - we are piping it to another cmdlet
    where-object - is used to filter a group of objects (more on this later) based on properties
    {$ -eq "Hearthstone"} - What we are filtering for (in this case, processes named Hearthstone
    | - we pipe our trimmed list (which really only contains one entry) to
    select-object Name,ID - We pick a few properties (the Name, and ID) of our object
    | - and pipe them to
    Format-table -auto which formats them in a table, autosized for the screen.

    At this point, you'd be forgiven for thinking that there is little benefit to using get-process, when compared to tasklist, but therein lies the rub.

    tasklist returns a text list of processes on the system.
    get-process returns objects (there's that word again)

    Lets take a closer look at what powershell is actually returning when you ask it to "Get-process"

    PS C:\Users\Pablo> get-process | get-member
      TypeName: System.Diagnostics.Process
    Name                       MemberType     Definition                                                                   
    ----                       ----------     ----------                                                                   
    Handles                    AliasProperty  Handles = Handlecount                                                        
    Name                       AliasProperty  Name = ProcessName                                                           
    NPM                        AliasProperty  NPM = NonpagedSystemMemorySize64                                             
    PM                         AliasProperty  PM = PagedMemorySize64                                                       
    VM                         AliasProperty  VM = VirtualMemorySize64                                                     
    WS                         AliasProperty  WS = WorkingSet64                                                            
    Disposed                   Event          System.EventHandler Disposed(System.Object, System.EventArgs)                
    ErrorDataReceived          Event          System.Diagnostics.DataReceivedEventHandler ErrorDataReceived(System.Objec...
    Exited                     Event          System.EventHandler Exited(System.Object, System.EventArgs)                  
    OutputDataReceived         Event          System.Diagnostics.DataReceivedEventHandler OutputDataReceived(System.Obje...
    BeginErrorReadLine         Method         void BeginErrorReadLine()                                                    
    BeginOutputReadLine        Method         void BeginOutputReadLine()                                                   
    CancelErrorRead            Method         void CancelErrorRead()                                                       
    CancelOutputRead           Method         void CancelOutputRead()                                                      
    Close                      Method         void Close()                                                                 
    CloseMainWindow            Method         bool CloseMainWindow()                                                       
    CreateObjRef               Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)              
    Dispose                    Method         void Dispose(), void IDisposable.Dispose()                                   
    Equals                     Method         bool Equals(System.Object obj)                                               
    GetHashCode                Method         int GetHashCode()                                                            
    GetLifetimeService         Method         System.Object GetLifetimeService()                                           
    GetType                    Method         type GetType()                                                               
    InitializeLifetimeService  Method         System.Object InitializeLifetimeService()                                    
    Kill                       Method         void Kill()                                                                  
    Refresh                    Method         void Refresh()                                                               
    Start                      Method         bool Start()                                                                 
    ToString                   Method         string ToString()                                                            
    WaitForExit                Method         bool WaitForExit(int milliseconds), void WaitForExit()                       
    WaitForInputIdle           Method         bool WaitForInputIdle(int milliseconds), bool WaitForInputIdle()             
    __NounName                 NoteProperty   System.String __NounName=Process                                             
    BasePriority               Property       int BasePriority {get;}                                                      
    Container                  Property       System.ComponentModel.IContainer Container {get;}                            
    EnableRaisingEvents        Property       bool EnableRaisingEvents {get;set;}                                          
    ExitCode                   Property       int ExitCode {get;}                                                          
    ExitTime                   Property       datetime ExitTime {get;}                                                     
    Handle                     Property       System.IntPtr Handle {get;}                                                  
    HandleCount                Property       int HandleCount {get;}                                                       
    HasExited                  Property       bool HasExited {get;}                                                        
    Id                         Property       int Id {get;}                                                                
    MachineName                Property       string MachineName {get;}                                                    
    MainModule                 Property       System.Diagnostics.ProcessModule MainModule {get;}                           
    MainWindowHandle           Property       System.IntPtr MainWindowHandle {get;}                                        
    MainWindowTitle            Property       string MainWindowTitle {get;}                                                
    MaxWorkingSet              Property       System.IntPtr MaxWorkingSet {get;set;}                                       
    MinWorkingSet              Property       System.IntPtr MinWorkingSet {get;set;}                                       
    Modules                    Property       System.Diagnostics.ProcessModuleCollection Modules {get;}                    
    NonpagedSystemMemorySize   Property       int NonpagedSystemMemorySize {get;}                                          
    NonpagedSystemMemorySize64 Property       long NonpagedSystemMemorySize64 {get;}                                       
    PagedMemorySize            Property       int PagedMemorySize {get;}                                                   
    PagedMemorySize64          Property       long PagedMemorySize64 {get;}                                                
    PagedSystemMemorySize      Property       int PagedSystemMemorySize {get;}                                             
    PagedSystemMemorySize64    Property       long PagedSystemMemorySize64 {get;}                                          
    PeakPagedMemorySize        Property       int PeakPagedMemorySize {get;}                                               
    PeakPagedMemorySize64      Property       long PeakPagedMemorySize64 {get;}                                            
    PeakVirtualMemorySize      Property       int PeakVirtualMemorySize {get;}                                             
    PeakVirtualMemorySize64    Property       long PeakVirtualMemorySize64 {get;}                                          
    PeakWorkingSet             Property       int PeakWorkingSet {get;}                                                    
    PeakWorkingSet64           Property       long PeakWorkingSet64 {get;}                                                 
    PriorityBoostEnabled       Property       bool PriorityBoostEnabled {get;set;}                                         
    PriorityClass              Property       System.Diagnostics.ProcessPriorityClass PriorityClass {get;set;}             
    PrivateMemorySize          Property       int PrivateMemorySize {get;}                                                 
    PrivateMemorySize64        Property       long PrivateMemorySize64 {get;}                                              
    PrivilegedProcessorTime    Property       timespan PrivilegedProcessorTime {get;}                                      
    ProcessName                Property       string ProcessName {get;}                                                    
    ProcessorAffinity          Property       System.IntPtr ProcessorAffinity {get;set;}                                   
    Responding                 Property       bool Responding {get;}                                                       
    SessionId                  Property       int SessionId {get;}                                                         
    Site                       Property       System.ComponentModel.ISite Site {get;set;}                                  
    StandardError              Property       System.IO.StreamReader StandardError {get;}                                  
    StandardInput              Property       System.IO.StreamWriter StandardInput {get;}                                  
    StandardOutput             Property       System.IO.StreamReader StandardOutput {get;}                                 
    StartInfo                  Property       System.Diagnostics.ProcessStartInfo StartInfo {get;set;}                     
    StartTime                  Property       datetime StartTime {get;}                                                    
    SynchronizingObject        Property       System.ComponentModel.ISynchronizeInvoke SynchronizingObject {get;set;}      
    Threads                    Property       System.Diagnostics.ProcessThreadCollection Threads {get;}                    
    TotalProcessorTime         Property       timespan TotalProcessorTime {get;}                                           
    UserProcessorTime          Property       timespan UserProcessorTime {get;}                                            
    VirtualMemorySize          Property       int VirtualMemorySize {get;}                                                 
    VirtualMemorySize64        Property       long VirtualMemorySize64 {get;}                                              
    WorkingSet                 Property       int WorkingSet {get;}                                                        
    WorkingSet64               Property       long WorkingSet64 {get;}                                                     
    PSConfiguration            PropertySet    PSConfiguration {Name, Id, PriorityClass, FileVersion}                       
    PSResources                PropertySet    PSResources {Name, Id, Handlecount, WorkingSet, NonPagedMemorySize, PagedM...
    Company                    ScriptProperty System.Object Company {get=$this.Mainmodule.FileVersionInfo.CompanyName;}    
    CPU                        ScriptProperty System.Object CPU {get=$this.TotalProcessorTime.TotalSeconds;}               
    Description                ScriptProperty System.Object Description {get=$this.Mainmodule.FileVersionInfo.FileDescri...
    FileVersion                ScriptProperty System.Object FileVersion {get=$this.Mainmodule.FileVersionInfo.FileVersion;}
    Path                       ScriptProperty System.Object Path {get=$this.Mainmodule.FileName;}                          
    Product                    ScriptProperty System.Object Product {get=$this.Mainmodule.FileVersionInfo.ProductName;}    
    ProductVersion             ScriptProperty System.Object ProductVersion {get=$this.Mainmodule.FileVersionInfo.Product...
    Get-process returns a collection of objects of type System.Diagnostics.Process which have the properties and methods listed, what this means, is that I can easily trim and parse my list of processes without the nightmare of cmd.exe find and tokens.

    Lets take a closer look at my Hearthstone process

    PS C:\Users\Adam> Get-Process | where {$ -eq "Hearthstone"}
    Handles  NPM(K)    PM(K)      WS(K) VM(M)   CPU(s)     Id ProcessName
    -------  ------    -----      ----- -----   ------     -- -----------
        432      55   420100     410592   600 ...37.77   6624 Hearthstone
    by default get-process will only display a subset of most of the properties, because displaying them all, every time would get very ugly. We used the "Select-Object" cmdlet above to limit what was displayed to Name and ID before, but we can also use it to make get-process show us ALL THE THINGS!

    PS C:\Users\Adam> Get-Process | where {$ -eq "Hearthstone"} | select *
    __NounName                 : Process
    Name                       : Hearthstone
    Handles                    : 432
    VM                         : 629567488
    WS                         : 420446208
    PM                         : 430182400
    NPM                        : 56384
    Path                       : C:\Program Files (x86)\Hearthstone\Hearthstone.exe
    Company                    : 
    CPU                        : 11442.109375
    FileVersion                :
    ProductVersion             :
    Description                : 
    Product                    : 
    Id                         : 6624
    PriorityClass              : Normal
    HandleCount                : 432
    WorkingSet                 : 420446208
    PagedMemorySize            : 430182400
    PrivateMemorySize          : 430182400
    VirtualMemorySize          : 629567488
    TotalProcessorTime         : 03:10:42.1093750
    BasePriority               : 8
    ExitCode                   : 
    HasExited                  : False
    ExitTime                   : 
    Handle                     : 952
    MachineName                : .
    MainWindowHandle           : 1704722
    MainWindowTitle            : Hearthstone
    MainModule                 : System.Diagnostics.ProcessModule (Hearthstone.exe)
    MaxWorkingSet              : 1413120
    MinWorkingSet              : 204800
    Modules                    : {System.Diagnostics.ProcessModule (Hearthstone.exe), System.Diagnostics.ProcessModule 
                                 (ntdll.dll), System.Diagnostics.ProcessModule (wow64.dll), 
                                 System.Diagnostics.ProcessModule (wow64win.dll)...}
    NonpagedSystemMemorySize   : 56384
    NonpagedSystemMemorySize64 : 56384
    PagedMemorySize64          : 430182400
    PagedSystemMemorySize      : 282192
    PagedSystemMemorySize64    : 282192
    PeakPagedMemorySize        : 574971904
    PeakPagedMemorySize64      : 574971904
    PeakWorkingSet             : 482820096
    PeakWorkingSet64           : 482820096
    PeakVirtualMemorySize      : 822407168
    PeakVirtualMemorySize64    : 822407168
    PriorityBoostEnabled       : True
    PrivateMemorySize64        : 430182400
    PrivilegedProcessorTime    : 00:40:02.7812500
    ProcessName                : Hearthstone
    ProcessorAffinity          : 15
    Responding                 : True
    SessionId                  : 1
    StartInfo                  : System.Diagnostics.ProcessStartInfo
    StartTime                  : 14/09/2014 5:33:27 PM
    SynchronizingObject        : 
    Threads                    : {6136, 5276, 5804, 5016...}
    UserProcessorTime          : 02:30:39.3281250
    VirtualMemorySize64        : 629567488
    EnableRaisingEvents        : False
    StandardInput              : 
    StandardOutput             : 
    StandardError              : 
    WorkingSet64               : 420446208
    Site                       : 
    Container                  : 
    Such Info.. I really need to close my programs when I finish my gaming sessions.

    You'll notice that I've shortened where-object and select-object to where and select these are known as aliases, and can be veiwed using the get-alias command

    PS C:\Users\Pablo> get-alias where,select
    CommandType     Name
    -----------     ----
    Alias           where -> Where-Object
    Alias           select -> Select-Object
    That wraps up this weeks Powershell Pow-wow, Feedback, questions, comments always welcome. Come back next week, when I'll write more random stuff that might or might not be useful for you.
    gabgab1982 and tree86ers like this.
  3. m0n4g3

    m0n4g3 Member

    Aug 5, 2009
    Perth, WA
    if i could i'd +1.


    Great thread, and i'd be happy to add to it when it comes to some AD/Exchange stuff.
  4. glimmerman

    glimmerman Member

    Nov 3, 2005
    thanks for this... i've always been too lazy to learn powershell... maybe this time i'll actually read through it :)
  5. Wynne

    Wynne Member

    Sep 22, 2003
    Great post!

    There is an approved verb list, it is here -

    No point remembering them or even knowing their intention, just know that it exists so when you use you future ps-fu for Good, creating scripts which use weird verbs is Bad.

    :D Get-ADSubnets.ps1
    :upset: Audit-ADSubnets.ps1
  6. FiShy

    FiShy Member

    Aug 15, 2001
    I can hear the screams of my former team mates using powershell in his environment.... he loves when I ask him to write somthing for me as he can return to the real world and use real tools.
  7. -stanna

    -stanna Member

    Oct 4, 2010
    subscribed for future posts, should be interesting reading to make many a lives easier!
  8. freaky_beeky

    freaky_beeky Member

    Dec 2, 2004
    There is a way easier way than that
    Very Important for modules...

    Just to contribute to this thread, these are some of the best baselines I have read for PowerShell and ensure that new scripters have a decent structure to build from. The original link died, so i used to find it again here


    For those just starting some awesome ways to use help are:

    Get-Help Get-ChildItem -Online
    Get-Help Get-ChildItem -ShowWindow
    Some handy stuff, (you can also just use 'help' instead of get-help)

    This thread is an awesome idea by the way. I hope to be able to contribute!
    Last edited: Sep 19, 2014
  9. OP

    PabloEscobar Member

    Jan 28, 2008
    I was going to write a breif bit in the first post about using get-command, and then recommended people type the command into google to get to the technet help...

    but -online rocks my socks, and I'd never even thought to look for it :).

    Today I learned :).

    Building Modules might come a bit later, but some of the best-practices outined in the article is good.

    I try to not use aliases in production scripts, but because things like select and where get used so often in one-liners... they sneak in far to often :).

    Version control of scripts is something that is often overlooked (or has been everywhere I've ever looked). Tiny change to production program code that might effect the 5 people that use it gets fully version controlled and change managed. Massive change to login script that runs on 1000 desktops everyday... have at it my friend, have at it.
  10. colmaz

    colmaz Member

    Jan 8, 2007
    Perth, WA
    I did a PowerShell v3.0 course earlier this year and the top lessons were:
    1. Verb-Noun
      All cmdlets are in this form, e.g. Get-Help, Get-ChildItems
    2. Everything is an object
      Anything you manipulate will be an object with properties and methods
    3. Get-Command
      Use the -Verb and -Noun parameters to find a cmdlet, e.g. Get-Command -Noun *DNS*
    4. Get-Help
      Helps with getting more information about a cmdlet. Btw, -ShowWindow is only supported from PowerShell v3.0 (Windows 8 Native, so you'll need to install WMF 3.0 on a Windows Vista/7 workstation). Run Update-Help to update it from TechNet
    5. Get-Member
      Lists the object type, property names and type, and the methods of an object
    Since doing the course, all new scripts have been created using PowerShell. I had to tell myself that there were to be no more VBScripts written after the course and stick to it. It wasn't easy at first, but now, about 6 months later, I consider myself very capable with PowerShell and I am now assisting those around me with writing their own PowerShell scripts.
    As an example, I recently created a script which accepts an XML (from command line parameter), runs commands depending on their type (MSI's, batch script/command, PowerShell scripts or Windows Updates) and does a validation (file exists, DLL version, Patch installed) to confirm if the command needs to be run, reboots if necessary and runs again after Windows has restarted. It also has debugging included in it using the Common Parameters. It took me around 50% of work time over 3 weeks to get it finalised and working the way I wanted it to and I am quite proud of my effort
  11. freaky_beeky

    freaky_beeky Member

    Dec 2, 2004

    That sounds like a neat wrapper script there colmaz. Well done on making the shift from VBS to PowerShell.

    Get-Member is really useful but that can be a pain for trying to read variables like hashtables.

    Examples of alternatives:
    gwmi -query "select * from win32_bios"
    gwmi -query "select * from win32_bios" | gm
    gwmi -query "select * from win32_bios" | ft * -AutoSize -Wrap
    gwmi -query "select * from win32_computersystem" | fl *
    (gwmi -query "select * from win32_computersystem").gettype()
    used all aliases to make it more entertaining for those playing at home.

    Get-alias <alias> works to translate the specific alias as well.
  12. OP

    PabloEscobar Member

    Jan 28, 2008
    I don't use get member all that often... especially not for properties...

    Normally I'll just get the object I want and | FL * to list them all.

    Its much easier to determine that the property I'm getting is the one I want, especially early on in the piece

    Get-ADuser gives me a Microsoft.ActiveDirectory.Management.ADUser Object.

    Its got the following properties relating to name.

    DistinguishedName Property              System.String DistinguishedName {get;set;}                                                                                                                         
    GivenName         Property              System.String GivenName {get;set;}                                                                                                 
    Name              Property              System.String Name {get;}                                                                                                          
    SamAccountName    Property              System.String SamAccountName {get;set;}                                                                                            
    Surname           Property              System.String Surname {get;set;}                                                                                                   
    UserPrincipalName Property              System.String UserPrincipalName {get;set;}
    But if I just get my user account (get-aduser -identity Pescobar | FL *) I can easily see what I want - be it my Display name (the Name Property) or my username (SamAccountName)

    DistinguishedName : CN=Pablo Escobarr,OU=Test,OU=Staff,OU=Company,DC=test,DC=local
    GivenName         : Pablo
    Name              : Pablo Escobar
    SamAccountName    : PEscobar
    Surname           : Escobar
    UserPrincipalName : pescobar@test.local
  13. m0n4g3

    m0n4g3 Member

    Aug 5, 2009
    Perth, WA
    Funny you should say that... that's exactly what i do as well HAH! :)
  14. OP

    PabloEscobar Member

    Jan 28, 2008
    Get-ChildItem and Get-Date

    Round 2... Fight <Guile'sTheme.mp3>

    I learn by doing, you might learn differently, but you're not the one writing this post. Most of the examples I'll post here have been useful for me at some point or another. Hopefully they will be useful to you also.

    Bossman: Hey Pablo, The Disk on serverX is filling up again, can you clear the SomeShittyApp logs for me, we only really need to keep a 30 days worth.

    I could do it in a Batch file -

    but I take a look at it, It's a nightmare to understand, and it only handles dates in certain formats, so without further ado, Lets see how to do it in powershell


    Anyone familar with batch (or bash) scripting will know "cd" to change directory or "dir"/"ls" to get a folder listing. These will work in Powershell, but are aliases (remember them) to native powershell commands

    Get-Alias cd,ls,dir | FT CommandType,DisplayName -autosize
    CommandType DisplayName         
    ----------- -----------         
          Alias cd -> Set-Location  
          Alias ls -> Get-ChildItem 
          Alias dir -> Get-ChildItem
    This shows us that the actual commands being run are set-location and get-childitem... so instead of using the aliases, we will be using the actual commands.

    Our application (SomeCrappyApp) has a log location of C:\SomeCrappyApp\Logs, so we should change to that directory and list out all the files in it

    Pretty straight forward

    Set-Location C:\SomeCrappyApp\Logs
        Directory: C:\SomeCrappyApp\Logs
    Mode                LastWriteTime         Length Name                                                                                                                            
    ----                -------------         ------ ----                                                                                                                            
    -a----       21/02/2014  10:29 AM       12037437 u_ex140220.log                                                                                                                  
    -a----       22/02/2014  10:30 AM       12450321 u_ex140221.log                                                                                                                  
    -a----       23/02/2014  10:30 AM       12451563 u_ex140222.log                                                                                                                  
    -a----       24/02/2014  10:30 AM        6180251 u_ex140223.log                                                                                                                  
    -a----       25/02/2014  10:30 AM        6115918 u_ex140224.log                                                                                                                  
    -a----       26/02/2014  10:30 AM        6119139 u_ex140225.log                                                                                                                  
    -a----       27/02/2014  10:30 AM        6122943 u_ex140226.log                                                                                                                  
    [I]<snip for readability>[/I]                                                                                                               
    -a----       23/09/2014   9:30 AM         847303 u_ex140922.log                                                                                                                  
    -a----       24/09/2014   9:30 AM         766800 u_ex140923.log                                                                                                                  
    -a----       25/09/2014   9:30 AM         767315 u_ex140924.log                                                                                                                  
    -a----       25/09/2014   9:30 AM         302713 u_ex140925.log                                                                                                                  

    A pretty familiar output... but as with everything in powershell, Its far more than a simple listing of files in a directory, Its a Group of Objects. This is a good time to clarify a little bit about how the pipeline works;

    Consider the following

    $var = "Monkey"
    Write-Host -Object $var -ForegroundColor Red
    $var | Write-Host -ForegroundColor Blue
    In this case, the second and third line do the same thing, They both write the word "Monkey to the screen, one in red, one in blue.

    If we do the same thing using the get-member and get-childitem cmdlet, we get a different output

    $var = Get-ChildItem
    get-member -InputObject $var
    $var | Get-Member
    [COLOR="Red"]   TypeName: System.Object[]
    Name           MemberType            Definition                                                                                                                                  
    ----           ----------            ----------                                                                                                                                  
    Count          AliasProperty         Count = Length                                                                                                                              
    Add            Method                int IList.Add(System.Object value)                                                                                                          
    [I]<snip for readability>[/I]                                                                                     
    LongLength     Property              long LongLength {get;}                                                                                                                      
    Rank           Property              int Rank {get;}                                                                                                                             
    SyncRoot       Property              System.Object SyncRoot {get;}   [/COLOR]
       TypeName: System.IO.FileInfo
    Name                      MemberType     Definition                                                                                                                              
    ----                      ----------     ----------                                                                                                                              
    Mode                      CodeProperty   System.String Mode{get=Mode;}                                                                                                           
    AppendText                Method         System.IO.StreamWriter AppendText()                                                                                                     
    CopyTo                    Method         System.IO.FileInfo CopyTo(string destFileName), System.IO.FileInfo CopyTo(string destFileName, bool overwrite)                          
    Create                    Method         System.IO.FileStream Create()                                                                                                           
    CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)                                                                         
    [I]<snip for readability>[/I]   
    LastAccessTimeUtc         Property       datetime LastAccessTimeUtc {get;set;}                                                                                                   
    LastWriteTime             Property       datetime LastWriteTime {get;set;}                                                                                                       
    LastWriteTimeUtc          Property       datetime LastWriteTimeUtc {get;set;}                                                                                                    
    Length                    Property       long Length {get;}                                                                                                                      
    Name                      Property       string Name {get;}                                                                                                                      
    BaseName                  ScriptProperty System.Object BaseName {get=if ($this.Extension.Length -gt 0){$this.Name.Remove($this.Name.Length - $this.Extension.Length)}else{$thi...
    LinkType                  ScriptProperty System.Object LinkType {get=[Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods]::GetLinkType($this.FullName);}         
    Target                    ScriptProperty System.Object Target {get=[Microsoft.PowerShell.Commands.InternalSymbolicLinkLinkCodeMethods]::GetTarget($this.FullName);}              
    VersionInfo               ScriptProperty System.Object VersionInfo {get=[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName);}                    
    In this case, the Red output is telling us the properties and methods of the collection of objects that Get-ChildItem returned, while the Blue output is telling us what properties and methods are available for each of the entries within that collection.

    But again, I digress (I seem to be doing that alot).

    Back to our goal... Looking at the blue output above, you can see that get-childitem gives us some useful properties to go on "LastWriteTime looks like it will do what we want. So we can use where-object (from Our first post) to cut down our working list of files.

    Set-Location C:\SomeCrappyApp\Logs
    Get-ChildItem | Where-Object {$_.LastWriteTime -lt ((Get-Date).AddDays(-30))}
        Directory: C:\SomeCrappyApp\Logs
    Mode                LastWriteTime         Length Name                                                                                                                            
    ----                -------------         ------ ----                                                                                                                            
    -a----       21/02/2014  10:29 AM       12037437 u_ex140220.log                                                                                                                  
    -a----       22/02/2014  10:30 AM       12450321 u_ex140221.log                                                                                                                  
    -a----       23/02/2014  10:30 AM       12451563 u_ex140222.log                                                                                                                  
    -a----       24/02/2014  10:30 AM        6180251 u_ex140223.log                                                                                                                  
    -a----       25/02/2014  10:30 AM        6115918 u_ex140224.log                                                                                                                  
    -a----       26/02/2014  10:30 AM        6119139 u_ex140225.log                                                                                                                  
    [I]<Snipped for Readability>     [/I]                                                                                                        
    -a----       22/08/2014   7:43 PM           1557 u_ex140822.log                                                                                                                  
    -a----       23/08/2014   7:44 PM           1555 u_ex140823.log                                                                                                                  
    -a----       24/08/2014   7:45 PM           1557 u_ex140824.log                                                                                                                  
    -a----       25/08/2014   7:45 PM           1555 u_ex140825.log      
    So now, instead of the full list, we get a list going back 30 days, There's a whole lot of brackets going on in our where-object cmdlet though, lets see what they are doing

    As before $_ represents the object being past along, so

    $_.LastWriteTime - The "LastWriteTime" property of the File object that has been passed down the pipeline.
    -lt - Comparison operator for less than (more on that later)
    (Get-Date).AddDays(-30) - This is where we need to go a little more in depth... Get-Date grabs the current date... simple right.

    Thursday, 25 September 2014 9:46:28 PM
    Get-Date | FL *
    DisplayHint : DateTime
    DateTime    : Thursday, 25 September 2014 9:48:27 PM
    Date        : 25/09/2014 12:00:00 AM
    Day         : 25
    DayOfWeek   : Thursday
    DayOfYear   : 268
    Hour        : 21
    Kind        : Local
    Millisecond : 300
    Minute      : 48
    Month       : 9
    Second      : 27
    Ticks       : 635472785073000826
    TimeOfDay   : 21:48:27.3000826
    Year        : 2014
    But because its powershell, and everything is an object... Get-Member tells us that its more than just a simple String with the Date and Time in 4omething to our object (namely Subtract 30 days from it).

    Get-Date | Get-Member -MemberType Method
       TypeName: System.DateTime
    Name                 MemberType Definition                                                                                                                                       
    ----                 ---------- ----------                                                                                                                                       
    Add                  Method     datetime Add(timespan value)                                                                                                                     
    AddDays              Method     datetime AddDays(double value)                                                                                                                   
    AddHours             Method     datetime AddHours(double value)                                                                                                                  
    AddMilliseconds      Method     datetime AddMilliseconds(double value)                                                                                                           
    [I]<snipped for readability>[/I]
    ToType               Method     System.Object IConvertible.ToType(type conversionType, System.IFormatProvider provider)                                                          
    ToUInt16             Method     uint16 IConvertible.ToUInt16(System.IFormatProvider provider)                                                                                    
    ToUInt32             Method     uint32 IConvertible.ToUInt32(System.IFormatProvider provider)                                                                                    
    ToUInt64             Method     uint64 IConvertible.ToUInt64(System.IFormatProvider provider)                                                                                    
    ToUniversalTime      Method     datetime ToUniversalTime()                                                                                                                       
    Here are our Methods, Put simply, a Method is a way to "Do" things to objects. If your car is an object, then its properties might be Colour, Model, Seats, Weight and its Methods would be Accelerate and Brake

    So back to our entry ((Get-Date).AddDays(-30)) - Remember high school - BODMAS (or BOMDAS for you Heathens out there)... either way, "Brackets Off" so the brackets get evaluated from inside to outside

    (Get-Date) gets replaced with our System.DateTime Object and we can .AddDays(-30) to it, because .AddDays is a method of that Object, (high school maths again "X + - Y" and "X - Y" are the same) so we add -30 days to today, and come up with a date 30 days in the past

    Tuesday, 26 August 2014 10:01:48 PM
    These methods save us a metric fuckton of time and complexity, as anyone who has ever tried parsing dates and times in batch script will tell you. Get-Date use the windows system commands to calculate dates and time, saving you to have to learn all the bullshit that goes into our calendar. I can manipulate dates in any way I want. I can also feed Get-Date a date (in many formats) and have it generate a system.datetime object for me.

    What Day is Christmas this year?... easy

    Get-Date("25/12/14") | FL DayOfWeek
    DayOfWeek : Thursday
    Brilliant, Means Boxing Day is Friday, so 4 day weekend :)... But again, I digress. lets finish it up

    We've got our List (get-childitem) we've trimmed it down, so it only includes files older than 30 days ( Where-Object {$_.LastWriteTime -lt ((Get-Date).AddDays(-30))}) now, we need to nuke them... as above, By 7default, powershell will alias your archaic deletion commands, (del, rm) to their modern day, powershell equivalents. (remove-item)

    So, all we do is pipe our filtered list to the Remove-Item cmdlet, and Bam, the files are gone... What If I've done something wrong, What If my filter is wrong, and it nukes all my files... and there you have your answer.

    Remove-Item supports the -whatif Parameter... -whatif shows you what will happen, without actually making it happen... so lets fire this baby up.

    Set-Location C:\SomeCrappyApp\Logs
    Get-ChildItem | Where-Object {$_.LastWriteTime -lt ((Get-Date).AddDays(-30))} | Remove-Item -WhatIf
    What if: Performing the operation "Remove File" on target "C:\SomeCrappyApp\Logs\u_ex140220.log".
    What if: Performing the operation "Remove File" on target "C:\SomeCrappyApp\Logs\u_ex140221.log".
    What if: Performing the operation "Remove File" on target "C:\SomeCrappyApp\Logs\u_ex140222.log".
    What if: Performing the operation "Remove File" on target "C:\SomeCrappyApp\Logs\u_ex140223.log".
    <snipped for readability>
    What if: Performing the operation "Remove File" on target "C:\SomeCrappyApp\Logs\u_ex140824.log".
    What if: Performing the operation "Remove File" on target "C:\SomeCrappyApp\Logs\u_ex140825.log".
    So there you go, You can now clean out your old log files with the click of a button, all in mostly plain English


    Operators... one of the strangest things coming from the world of vbs for me was the operators... consider the following vbscript

    [B]x = 5[/B]
    if [B]x = 5[/B] then msgbox("X equals 5")
    the first line sets the variable "X" to 5, and the second line checkes that Variable X equals 5... yet they both use the same operator... this was natural to me for a long time... but looking back, I can see how it can quickly lead to confusion. Some languages use a double equals (==) to perform comparisons, powershell does not - has a list of powershell compraison operators.

    Forget about using =, <, > and != to perform comparisons on your values.... get to using -eq -lt -gt and -ne for your comparison needs.

    Some of these can be tricky, do not get confused between -contains and -like. -like is used for comparing strings -contains is used to check a collection of objects for a specific object.


    As always, Discussion below, if you have a task that you think powershell might help you with, and would like to understand how... feel free to post it up, and if you're lucky, I might write it up next week.
    Last edited: Sep 26, 2014
  15. Rezin

    Rezin Member

    Oct 27, 2002
    Any particular reason for doing that? Why would you use Get-ChildItem instead of ls?
  16. OP

    PabloEscobar Member

    Jan 28, 2008
    Primarily: Personal Preference, Foggy reasons given below...

    If I'm just doing a quick one-liner to get shit done, I'll use aliases, but if I'm writing a script that is going to be kept around, I'll use the full command. Its less likely (but not impossible) that someone has aliased the full command to something, but its not improbably to think that some unix hating windows neckbeard has removed the unix-tainted "ls" alias from a system.

    Although none of the standard aliases have changed yet, its not inconvievable to see a PS build where they do not get set by default, and are instead set in your profile... using the full command means that my scripts will function long into the future, and be more understandable by more people.

    Get-ChildItem leaves nobody in two minds about what it does... in Linux, ls returns a list of files as a string... which a bad unix neckbeard would try to parse to achieve a terrible outcome. (
  17. Rezin

    Rezin Member

    Oct 27, 2002
    Good call.
  18. DavidRa

    DavidRa Member

    Jun 8, 2002
    NSW Central Coast
    Pablo - I think at this point (or soon) you should introduce ISE. Happy to help with the content if you aren't familiar.

    As scripts get bigger and more complex, debugging with Write-Output, Write-Warning etc is unmanageable. Especially if you have scripts calling other scripts.

    Yeah I've written some mega PSH (example). Reminds me I need to update it for 2012+... :(
  19. OP

    PabloEscobar Member

    Jan 28, 2008
    I'm not a massive fan of ISE, so only really use it for ad-hoc script customisations. Most of my time is spent in Quests (dells) PowerGUI (free), or more recently, Sapien's Powershell Studio (paid).

    If you want to post up an ISE Primer, I'll gladly link it in the First Post. IDE's can be a bit of a Vi/Emacs holy war type quagmire though, which I'd like to avoid :).
  20. DavidRa

    DavidRa Member

    Jun 8, 2002
    NSW Central Coast
    Fair enough. Not interested in a holy war (there's no point, vi wins that easily :tongue:). I think it's more important that people starting out have a tool that helps not only with syntax but with being able to debug things. "Why is this happening", "Dammit what was the value of that variable" etc.

    PowerShell IDE - Basics

    So you've been writing your PoSH scripts in Notepad, or Notepad++, or TextPad - a plain text editor. You've probably got the hang of debugging using Write-Output, or even perhaps Write-Warning, Write-Debug or Write-Error.

    Bossman wants a way to kill off Command Prompts on a machine that's gone rogue - there are thousands of Command Prompts all hung, with different randomly set positions and title bars. It's a mess, but you can't get your script working!

    Your script looks a little like this:

    $Jobs = Get-Process | Where-Object { $_.Name -eq "cmd.exe" }
    # Write-Output "Got $Jobs.Count processes"
    # $Jobs[0] | fl
    ForEach ($Job in $Jobs) {
      # Write-Output $Job.Name
      # $Job | ft
      if (-not $Job.Responding) { $Job.Kill() }
    There's debugging spread throughout the script. Every time you want to debug, you're uncommenting debug code (or commenting it out). You're developing by running commands at the normal PowerShell prompt and digging through the output. Wouldn't it be nice if there were some tools to make it easier? There are a number of PoSH editors out there - I'm going to show you PowerShell ISE, on the basis that it's both free and available almost everywhere PowerShell is sold.

    Other options include:
    • Dell's PowerGUI - be a little careful if you value portability, as some of the add-on packs can be "non-standard"
    • Sapien's PowerShell Studio - looks good, but $499 is a bit exxy (it does more than ISE, but you'll need to make your own determination as to whether it's worth it for you)
    Both PowerGUI and PowerShell Studio let you compile your scripts - but again for ease of access and bug fixing, and unless you're writing shrinkwrap quality scripts, I'd tend to avoid doing that (it doesn't mean you can run without the right version of PSH, nor any dependencies). The one advantage compilation does have is the ability to ensure all appropriate scripts are contained in a single file so you can't get things going missing.

    Enough of the marketing, on with the show!

    You can start PowerShell ISE at the powershell or command prompt, with the command "ISE". I've pasted in the code above so you can see the first advantage of a good editor - syntax highlighting. Also known as idiot formatting, but when you have a string containing quotes and double-quotes, the colours after the string tell you whether you have the right number of the right quotes.

    The top pane is the script and the bottom pane is the output and an "immediate" prompt - you can do your exploration right within the editor. On the right I've shown the Commands tab, though I generally don't use it myself. It's an easy way to search for a command, get its params and stick it into your script.

    Let's try that Get-Process command we have in our script in the immediate pane:

    Click to view full size!

    Two things are immediately obvious - you get a list of possible commands matching what you've typed so far, and when you pause a moment, you'll see help for the currently selected option. Don't worry if you tab or click away, you can bring that back with Ctrl+Space - "auto-complete". Auto-complete also works in the editor, so go nuts. Auto-complete all the things!

    Let's see if we can make our script above more efficient - on the end of the Get-Process command, add a space and a hyphen - now you can see the list of possible parameters. Hovering over one shows its type (for example, Name expects a string[] - which is a PowerShell array of strings or just a single string by itself). Use Ctrl+Space to bring up the auto-complete list if it's gone away, select Name, and press Enter to accept the offered choice. Now add the name of the process we're after - cmd.exe, and press return:

    Click to view full size!

    OK well that explains why it's not terminating those hung Command Prompts - it's all working but the command name is cmd not cmd.exe! Rather than immediately fixing it, though, let's look at the biggest reason to use an IDE - debugging. The concepts you need to know:

    • Setting a breakpoint [F9] will pause the script, before the breakpoint line is run;
    • Step Into [F10] means you'll dive into a function and debug it line by line;
    • Step Over [F11] means you'll run the function as a step, and debug only the script you're in;
    • You can only debug scripts on disk (i.e. those that are saved) but you can run an unsaved script.
    We'll set a breakpoint on the first line - save the script somewhere, then place your cursor on line 1 and press the F9 key. Notice the colour change - this indicates the breakpoint.

    Click to view full size!

    Now press F5 to run.

    Click to view full size!

    See the line is now yellow - that indicates the "next" piece of code that will run. In the output window you can see PowerShell telling you about the breakpoint (so you always know if the script is running or paused). If you hover over $Jobs with your mouse, you'll see its current value ($null). Press F10 to step over the whole line of code and hover the mouse on $Jobs again. Note it's still null? This tells us the command didn't return any processes to work on. Bug found!

    Click to view full size!

    Right. Kill off the script with Shift+F5 (Debug > Stop Debugger), we know the rest won't work. Let's replace the first line with our fix, and run it again. This time after we step over Get-Process - we have jobs. Good stuff.

    Click to view full size!

    Now you can step through your ForEach statement one job at a time - hover over $Job each time to see the new object your loop is working on.

    Click to view full size!
    Last edited: Sep 28, 2014

Share This Page