Parse Volume Status of RSTCLI using Powershell - powershell

I'm trying to parse output from rstcli64 (Intel Rapid Storage Technology Command Line Interface) with powershell for use with Hyper-v 2012 bare metal server. The goal is to find any volumes or disks with a status that is not "normal" by returning $true for 'OK' or $false for anything other than normal or $null. The ultimate goal to is to create an alert for Icinga. When it's all done I'll be posting the working script. Here's where I'm at, and I may be going about this in completely the wrong way:
I start with rstcli64:
rstcli64 --information --volume
Which outputs:
--VOLUME INFORMATION--
Name: Volume0
Raid Level: 10
Size: 466 GB
StripeSize: 64 KB
Num Disks: 4
State: Normal
System: True
Initialized: False
Cache Policy: Off
--DISKS IN VOLUME: Volume0 --
ID: 0-0-0-0
Type: Disk
Disk Type: SATA
State: Normal
Size: 233 GB
Free Size: 0 GB
System Disk: False
Usage: Array member
Serial Number: WD-WCAT1F483065
Model: WDC WD2502ABYS-18B7A0
ID: 0-1-0-0
Type: Disk
Disk Type: SATA
State: Normal
Size: 233 GB
Free Size: 0 GB
System Disk: False
Usage: Array member
Serial Number: WD-WCAT1F468139
Model: WDC WD2502ABYS-18B7A0
ID: 0-2-0-0
Type: Disk
Disk Type: SATA
State: Normal
Size: 233 GB
Free Size: 0 GB
System Disk: False
Usage: Array member
Serial Number: WD-WCAT1H077856
Model: WDC WD2502ABYS-18B7A0
ID: 0-3-0-0
Type: Disk
Disk Type: SATA
State: Normal
Size: 233 GB
Free Size: 0 GB
System Disk: False
Usage: Array member
Serial Number: WD-WCAT1F522503
Model: WDC WD2502ABYS-18B7A0
rstcli64 :
+ CategoryInfo : NotSpecified: (:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
0
I'm interested in anywhere the 'State:' entry exits so I filter that out with Select-String, which I'm using like this, with this output:
rstcli64 --information --volume 2> Out-Null | select-string -Pattern "State:"
State: Normal
State: Normal
State: Normal
State: Normal
State: Normal
... and this is about as far as I've gotten. I need to find out how return $true if all of the "State:" fields -eq "Normal", and $false if either there is no output ($null I assume) or if there is any "State:" -ne "Normal".
Any help is much appreciated. Thank you.
EDIT: Thanks for the help! This is what I ended up using TheMadTechnician's logic in: http://baremetalwaveform.com/?p=311

Well that's easy enough to do from where you're at. Run a RegEx match or run a -like and see if there are any that -match or -like and look for 'Normal'. Get a count, if the total number of Status -gt 0 and that count -eq the matched count then you're all set.
$Status = rstcli64 --information --volume 2> Out-Null | select-string -Pattern "State:"
If(($status.count -gt 0) -and ($status.count -eq ($status|Where{$_ -match "Normal"}).count)){
"All is well"
}else{
"Stuff be broke!"
}

Another approach that will capture the counts of the states
$states = rstcli64 --information --volume 2> Out-Null | select-string -Pattern "State:"
$notNormalStates = $states | Select-String -Pattern "Normal" -NotMatch
if ($state.Count -gt 0 -and $notNormalStates.Count -eq 0){
Write-Host "Everything Ok"
} Else {
Write-Host "Something Wrong"
}
You could pipe the results of Select-String into Select-String again and spit out result that dont have "Normal". If you were just interested in the non normal state count you could use either of the following.
$notNormalCount = (rstcli64 --information --volume 2> Out-Null | select-string -Pattern "State:" | Select-String -Pattern "Normal" -NotMatch).Count
Also you could regex to just have one Select-String cmdlet
$notNormalCount = (rstcli64 --information --volume 2> Out-Null | Select-String -Pattern "State:\s+(?!.*Normal).*").Count
The regex would match "State:" followed by any whitespace followed by anything as long as its not "Normal" using a Negative Lookahead. Its worth noting that Regex is better designed to "match" things than to "not match" things.

Related

How to process out put of diskpart command using PowerShell

I'm trying to capture volume number from diskpart command output. At present I'm doing it like this:
Using batch script:
#echo off
set VOLNO=''
set DRIVE=C
for /f "tokens=2,3" %%a in ('echo list volume ^| diskpart') do (
if %%b==%DRIVE% set VOLNO=%%a
)
echo Volume No. for C Drive is: %VOLNO%
Output:
Volume No. for C Drive is: 2
Using PowerShell:
$dp = "list volume" | diskpart | ? { $_ -match "^ [^-]" }>
$dp
Output:
Volume ### Ltr Label Fs Type Size Status Info
Volume 0 E DVD-ROM 0 B No Media
Volume 1 System Rese NTFS Partition 350 MB Healthy System
Volume 2 C NTFS Partition 59 GB Healthy Boot
Volume 3 D New Volume NTFS Partition 49 GB Healthy
I want to capture the Volume-Number e.g. it's 2 for C:\ to a variable using PowerShell.
Adjust your regular expression so that you can extract the desired information via capturing groups. I generally recommend building custom objects from the extracted information, to facilitate further processing.
Something like this should do what you want:
$drive = 'c'
'list volume' | diskpart | Where-Object {
$_ -match 'Volume (\d+)\s+([a-z])\s+'
} | ForEach-Object {
New-Object -Type PSObject -Property #{
'DriveLetter' = $matches[2]
'VolumeNumber' = [int]$matches[1]
}
} | Where-Object {
$_.DriveLetter -eq $drive
} | Select-Object -Expand VolumeNumber
A concise solution that uses -match to find the line of interest and the unary form of -split to split it into whitespace-separated tokens that can be accessed by index:
$drive = 'C'
$volNo = (-split (('list volume' | diskpart) -match " $drive "))[1]
"Volume No. for $drive Drive is: $volNo"
Note that diskpart must be run from an elevated session.

PowerShell -gt comparison operator not working

I am currently using a PowerShell script to read the output of a file and then if the number is higher than I want, it sends an email. Script is below -
$Output = 'D:\alec.data\QueuedJobss.txt'
d:
set-location -Path 'D:\program files\veritas\netbackup\bin\admincmd'
.\bpdbjobs -summary -L > $Output
$Queued = (Select-String -Path $Output -Pattern '(?<=Queued:\s+)\d+').Matches.Value
if ($Queued -gt 1)
It is creating the file, but it's not sending it to me. I know my email scripts are working because they're the same ones I always use. It seems it's having a hard time interpreting the string. I do not receive any errors on the code. The output it's reading from looks like this -
Summary of jobs on usctest01
Queued: 6
Waiting-to-Retry: 0
Active: 0
Successful: 25863
Partially Successful: 113
Failed: 184
Incomplete: 0
Suspended: 0
Total: 26160
if you check out get-member on $Queued by running $Queued | gm you will see this: TypeName: System.String
so $Queued is a string and thus -gt does not work. however if you cast the the variable as integer as follows (the [int] tells the variable to be an integer) you can use -gt as shown in your example:
[int]$Queued = (Select-String -Path $Output -Pattern '(?<=Queued:\s+)\d+').Matches.Value
running $Queued | gm now will show you this: TypeName: System.Int32

How to know, After which Partition unallocated space is available ? (Powershell or Command)

I am trying to use Command or PowerShell to know where on a disk unallocated space is available.
For example below the unallocated space is present after G: drive (or Partition 1).
Using the command echo list disk | diskpart I can only know the Unallocated space.
Is there any way to know this information?
Solution for Windows 8/2012 Server or newer:
I think you could do this (needs to be run with Administrator rights) to return an object with each volume that can be extended (from which you can then deduce there is free space after the volume):
Get-Volume | Where DriveLetter -ne $null | ForEach-Object {
$Size = Get-PartitionSupportedSize -DriveLetter $_.DriveLetter
If ($Size.SizeMax -gt $_.Size) { $_ }
}
Get-Volume | Where DriveLetter -ne $null gets all drives that have a letter
$Size = Get-PartitionSupportedSize -DriveLetter $_.DriveLetter gets the sizemin and sizemax of each drive
If ($Size.SizeMax -gt $_.Size) { $_ } returns the volumes which can be extended (their size max is bigger than the current volume size).

Another grep / awk q, parsing diskpart output

I've googled this a lot and there are a lot of similar questions but I can't figure out how to put them together to make it work for me. Also, the fact that MS decided to leave dynamic volumes out of their PowerShell cmdlets is really frustrating.
In the following code I'm trying to identify that "Disk 2" is dynamic.
PS C:\Windows\system32> echo 'list disk' | diskpart
Microsoft DiskPart version 10.0.14393.0
Copyright (C) 1999-2013 Microsoft Corporation.
On computer: AHPAP2704
DISKPART>
Disk ### Status Size Free Dyn Gpt
-------- ------------- ------- ------- --- ---
Disk 0 Online 65 GB 0 B
Disk 1 Online 20 GB 0 B *
Disk 2 Offline 50 GB 0 B *
Ideally from the output above I'm going to set a variable to identify the dynamic volume (my script will always only have one) so when complete I'm left with something like $DynDisk = 2.
When I pipe the output to Get-Member the only member types containing property in the name are Chars and Length.
Is there an easy way to get the data into an array or a better method? Or, any chance there is some hidden grep and awk like cmdlets out there?
diskpart output isn't trimmed, so you can parse the relevant information from the end of the string, e.g. like this:
$re = 'disk (\d+)\s+(\w+)\s+(\d+ .?b)\s+(\d+ .?b) (.*)'
'list disk' | diskpart | Select-String -Pattern $re | ForEach-Object {
New-Object -Type PSObject -Property #{
ID = [int]$_.Matches.Groups[1].Value
Status = $_.Matches.Groups[2].Value -eq 'online'
Size = $_.Matches.Groups[3].Value
FreeSpace = $_.Matches.Groups[4].Value
Dynamic = $_.Matches.Groups[5].Value.Substring(0, 3).Trim() -eq '*'
GPT = $_.Matches.Groups[5].Value.Substring(4, 3).Trim() -eq '*'
}
}
All I needed was another half hour of googling.
https://gallery.technet.microsoft.com/DiskPartexe-Powershell-0f7a1bab
That script creates 3 objects which have properties I know now to handle

Fill multi dimension array with plain text in Powershell

I am working on a Powershell script to monitor a SAN.
I successfully extracted a text file containing all the values from the system in Powershell with this code:
& "NaviSecCli.exe" -user xxxx -password xxxx -h host -f "C:\LUNstate.txt" lun -list
$Path = "C:\LUNstate.txt"
$Text = "Capacity \(GBs\)"
$Name = "^Name"
Get-Content $Path | Select-String -pattern $Text,$Name
This generates the following output:
Name: TEST-DATASTORE-1
User Capacity (GBs): 1536.000
Consumed Capacity (GBs): 955.112
Name: CV Snapshot Mountpoint
User Capacity (GBs): 1024.000
Consumed Capacity (GBs): 955.112
Now I can split the values through the colon, by putting the output into a variable:
$LUNArray = Get-Content $Path | Select-String -pattern $Text,$Name
$LUNArray | foreach {
$LUNArray = $_ -split ': '
Write-Host $LUNArray[0]
Write-Host $LUNArray[1]
}
The only interesting data is stored in $LUNArray[1], so I can just leave out Write-Host $LUNArray[0] which gives me the following output:
TEST-DATASTORE-1
1536.000
955.112
CV Snapshot Mountpoint
1024.000
955.112
Now the tricky part, I would like to put the data into a multi dimensional array. So I would get the following array layout:
LUN Usercap ConsCap
TEST-DATASTORE-1 1536.000 955.112
CV Snapshot Mountpoint 1024.000 955.112
The input file looks like this:
LOGICAL UNIT NUMBER 201
Name: TEST-DATASTORE-1
UID: 60:06:E4:E3:11:50:E4:E3:11:20:A4:D0:C6:E4:E3:11
Current Owner: SP B
Default Owner: SP B
Allocation Owner: SP B
User Capacity (Blocks): 3221225472
User Capacity (GBs): 1536.000
Consumed Capacity (Blocks): 2005641216
Consumed Capacity (GBs): 956.364
Pool Name: Pool HB Hasselt
Raid Type: Mixed
Offset: 0
Auto-Assign Enabled: DISABLED
Auto-Trespass Enabled: DISABLED
Current State: Ready
Status: OK(0x0)
Is Faulted: false
Is Transitioning: false
Current Operation: None
Current Operation State: N/A
Current Operation Status: N/A
Current Operation Percent Completed: 0
Is Pool LUN: Yes
Is Thin LUN: Yes
Is Private: No
Is Compressed: No
Tiering Policy: Lowest Available
Initial Tier: Lowest Available
Tier Distribution:
Capacity: 100.00%
LOGICAL UNIT NUMBER 63920
Name: CV Snapshot Mountpoint
UID: 60:50:38:00:14:50:38:00:C6:64:50:38:00:50:38:00
Current Owner: SP B
Default Owner: SP B
Allocation Owner: SP B
User Capacity (Blocks): 2147483648
User Capacity (GBs): 1024.000
Consumed Capacity (Blocks): 2005641216
Consumed Capacity (GBs): 956.364
Pool Name: Pool HB Hasselt
Raid Type: Mixed
Offset: 0
Auto-Assign Enabled: DISABLED
Auto-Trespass Enabled: DISABLED
Current State: Ready
Status: OK(0x0)
Is Faulted: false
Is Transitioning: false
Current Operation: None
Current Operation State: N/A
Current Operation Status: N/A
Current Operation Percent Completed: 0
Is Pool LUN: Yes
Is Thin LUN: Yes
Is Private: No
Is Compressed: No
Tiering Policy: Lowest Available
Initial Tier: Lowest Available
Tier Distribution:
Capacity: 100.00%
...
$filePath = 'absolute path'
$content = [IO.File]::ReadAllText($filePath)
[regex]::Matches(
$content,
'(?x)
Name: [ ]* ([^\n]+) # name
\n User [ ] (Capacity) [^:]+: [ ]* ([^\n]+) # capacity
\n Consumed [ ] \2 [^:]+:[ ]* ([^\n]+)' # Consumed
) |
ForEach-Object {
$LUN = $_.groups[1].value
$Usercap = $_.groups[3].value
$ConsCap = $_.groups[4].value
# process $Lun, $Usercap and $ConsCap
}
Build a list of custom objects, like this:
& "NaviSecCli.exe" -user xxxx -password xxxx -h host -f "C:\LUNstate.txt" lun -list
$datafile = 'C:\LUNstate.txt'
$pattern = 'Name:\s+(.*)[\s\S]+(User Capacity).*?:\s+(.*)\s+(Consumed Capacity).*?:\s+(.*)'
$LUNArray = (Get-Content $datafile | Out-String) -split '\r\n(\r\n)+' |
Select-String $pattern -AllMatches |
Select-Object -Expand Matches |
% {
New-Object -Type PSObject -Property #{
'LUN' = $_.Groups[1].Value
$_.Groups[2].Value = $_.Groups[3].Value
$_.Groups[4].Value = $_.Groups[5].Value
}
}
The data can be displayed for instance like this:
"{0}: {1}" -f $LUNArray[1].LUN, $LUNArray[1].'Consumed Capacity'