Execution order of commands in scripts

This topic contains 3 replies, has 3 voices, and was last updated by  iain Barnetson 2 weeks, 1 day ago.

  • Author
    Posts
  • #102068

    Ramon Tan
    Participant

    Sir/Madam,
    I have a script of 6 lines as follows:
    cls
    #Get-PSDrive | Where-Object Description -eq "RECOVERY"
    wmic logicaldisk get caption,volumename
    Get-WmiObject win32_logicaldisk | select-object -property DeviceID,VolumeName
    Get-WmiObject win32_logicaldisk | Where-object VolumeName -eq "DDRIVE"
    Get-PSDrive | Where-Object Description -eq "RECOVERY"

    When I run it, the last line never gets executed (in the sense that I didn't get anything on the console).
    When I remove the '#' in Line 2 — which is identical to the last line, I get the outputs,
    but in a seemingly strange order: the output of Line 2 and Line 6 (the last) appear together
    at the end. I must be missing something about how console output is generated and handled.
    Any advice or tips or references to the right source of help will be highly appreciated.

  • #102070

    Don Jones
    Keymaster

    Yeah, so, the thing you're running into is that PowerShell commands don't just emit a bunch of text. Each of your commands, except WMIC, emits objects, which PowerShell's formatting system has to try to turn into text. Because you're filling the pipeline with so many different kinds of objects, the formatting system is probably losing its mind at some point and just giving up.

    Try running "Get-Service ; Get-Process" and you'll see how the formatting system can get a bit odd when you mix and match objects in the pipeline.

    If your goal is to produce some kind of "report" or something, the correct (for PowerShell) approach would be to query everything, store the results in variables, and then combine whatever info you want into a consistent set of custom objects. Output those to the pipeline, and you end up with cleaner and more consistent output.

    • #102077

      Ramon Tan
      Participant

      Thank you very much Mr Jones!
      Indeed, I changed the last line to add a pipe to:
      Out-File zzz.txt
      and the expected outputs were there. I have 2 more related questions.

      Question-1:
      I have been using files instead of variables, but generally, is it better to store such "temporary results" which are headed for more "textual massaging" in variables or files? The kind of temporary results I have in mind are not "big" nor "voluminous", i.e., no more than a few hundred lines, totalling no more than 10K bytes. If this question does not make sense, please ignore.

      Question-2 (what is the syntax for a script block's contents?):

      I still cannot find the documentation for the proper syntax inside a "script block" { }. For example:
      (Get-content AAA.txt) | Foreach-object {_$ -replace "ooo","ZZZ"} | Set-content AAA.txt

      What are the "allowable parameters" besides "-replace"? I am eager to know the full suite of what's allowed inside the { } block. Is there an IF-THEN-ELSE equivalents for simple processing?
      I've already discovered the .NET methods that can be easily used (Contains, ToChar, Substring, Compare, etc.) but need to know where documentation exists for script blocks, specifically for Foreach-object { }.

      Sincerest thanks to you for your help.
      Best,
      RTan

  • #102079

    iain Barnetson
    Participant

    I do something similar, here's a cut down version, see below, passing a list of servers in the $servers variable.

    filter Get-CapacitySize {
       '{0:N2} {1}' -f $(
          if ($_ -lt 1kb) { $_, 'Bytes' }
          elseif ($_ -lt 1mb) { ($_/1kb), 'KB' }
          elseif ($_ -lt 1gb) { ($_/1mb), 'MB' }
          elseif ($_ -lt 1tb) { ($_/1gb), 'GB' }
          elseif ($_ -lt 1pb) { ($_/1tb), 'TB' }
          else { ($_/1pb), 'PB' }
       )
    }
    
    $GetData = {
    [PSCustomObject]@{
            Volume = $(Get-Volume | Select-Object *)
            Disk = $(Get-Disk | Select-Object *)
        }
    }
    
    $snapshot  = Invoke-Command -ComputerName $Servers -ScriptBlock $GetData -ErrorAction SilentlyContinue
    
    $snapshot | ForEach-Object{
        $ComputerName = $_.PSComputerName
    
        $_.Volume | ?{$_.FileSystemLabel -notlike "system*" -Or  [string]::IsNullOrWhiteSpace($_.DriveLetter)}  |
        ForEach-Object{
            [PSCustomObject]@{
                ComputerName = $ComputerName
                #DriveLetter = $_.DriveLetter
                DriveLetter = ($_.CimInstanceProperties[0] -replace('DriveLetter =','') -replace('"','')).Trim()
                FileSystemLabel = $_.FileSystemLabel 
                DiskSize = $_.Size | Get-CapacitySize
                UsedSpace = ($_.Size - $_.SizeRemaining) | Get-CapacitySize
                FreeSpace = $_.SizeRemaining | Get-CapacitySize
                "% Free" = "{0:P0}" -f  [math]::round(($_.SizeRemaining/$_.Size),2)
            }
        }
    } | sort-object  { [INT]($_."% Free"  -replace '%')  } | Export-Excel -Path $xlsxFile -WorkSheetname Volumes -AutoSize -AutoFilter -FreezeTopRow -BoldTopRow 
    

You must be logged in to reply to this topic.