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'
Related
I have two files, one with the servers listed in file A and I need to use that list to search file B for matches.
File A = Server Names (2 columns, Hostname/ServiceName)
File B = Server Metrics (3 columns, Hostname/ServiceName/ServiceOutput)
I need to use the two columns from "File A" to parse "File B" and when it finds a match it needs to write that row in "File B" to an output file. Each server should have three rows in the output file however, nothing is being written.
File A
host_display_name,service_display_name
US_Server1,Disk /
US_Server1,Disk /logs
US_Server1,mem
File B
Host_Name , ServiceName , Server_Ouput
US_Server1,Disk/,Disk Metrics
US_Server1,CPU/,CPU Metrics
US_Server1,Disk/logs,Disk Logs Metrics
US_Server1,APT,APT Metrics
US_Server1,User Count,User Count Metric
US_Server1,Java,Java Metrics
US_Server1,mem,Memory Metric
NONUS_Server2,Disk/,Disk Metrics
NONUS__Server2,Disk/logs,Disk Logs Metrics
NONUS_Server2,CPU/,CPU Metrics
NONUS_Server2,APT,APT Metrics
NONUS_Server2,User Count,User Count Metric
NONUS_Server2,Java,Java Metrics
NONUS_Server2,mem,Memory Metric
US_Server2,Disk/ ,Disk Metrics
US_Server2,Disk/logs,Disk Logs Metrics
US_Server2,CPU/,CPU Metrics
US_Server2,APT,APT Metrics
US_Server2,User Count,User Count Metric
US_Server2,Java,Java Metrics
US_Server2,mem,Memory Metric
Desired Output
Host_Name,ServiceName,Server_Ouput
US_Server1,Disk/,DiskMetrics
US_Server1,Disk/logs,DiskLogsMetrics
US_Server1,mem,MemoryMetric
US_Server2,Disk/,DiskMetrics
US_Server2,Disk/logs,DiskLogsMetrics
US_Server2,mem,MemoryMetric
CODE:
$Path = "C:\Projects\Excel_Data_Powershell"
$UserList = Import-Csv -Path "$($path)\Servers.csv"
$UserData = Import-Csv -Path "$($path)\services.csv"
$UserOutput = #()
ForEach ($name in $UserList)
{
$userMatch = $UserData | where {$_.host_name -eq $name.service_name}
If($userMatch)
{
# Process the data
$UserOutput += New-Object PsObject -Property #{HostName =$name.host_name;column1 =$userMatch.service_name;column2 =$userMatch.service_output}
}
else
{
$UserOutput += New-Object PsObject -Property #{UserName =$name.hostnames;servicename ="NA";serviceoutput ="NA"}
}
}
$UserOutput | ft
This is how you could filter fileB based on fileA, using Group-Object -AsHashtable for reference filtering:
$fileA = Import-Csv -Path path\to\fileA.csv | Group-Object HostName -AsHashTable -AsString
$fileB = Import-Csv -Path path\to\fileB.csv
$desiredOutput = $fileB.Where({
$_.ServiceName -in $fileA[$_.'Host_Name'].ServiceName
})
$desiredOutput | Export-Csv ..... -NoTypeInformation
Above should give you the following result:
Host_Name ServiceName Server_Ouput
--------- ----------- ------------
Server1 Disk / Disk Metrics
Server1 Disk /logs Disk Logs Metrics
Server1 mem Memory Metric
Server2 Disk / Disk Metrics
Server2 Disk /logs Disk Logs Metrics
Server2 mem Memory Metric
Server3 Disk / Disk Metrics
Server3 Disk /logs Disk Logs Metrics
Server3 mem Memory Metric
You're referencing host_name vs service_name in your where-object clause.
$UserData | where {$_.Host_Name -eq $name.HostName}
generates good results.
Below is my data in text file
Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 Z DVD-ROM 0 B No Media
Volume 1 System Rese NTFS Partition 500 MB Healthy System
Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
Volume 4 D DATA NTFS Partition 199 GB Healthy
Volume 5 E bit locker NTFS Partition 9 GB Healthy
Volume 6 F test NTFS Partition 10 GB Healthy
I have to write it in csv. tried below code but not able to handle to Blank values. e.g. for first row Label,Fs,Info values are blank
$data = get-content -Path "C:\d.txt"
$result = switch -Regex ($data) {
'^\s*Volume \d' {
$disk,$status,$Label,$Fs,$Type,$size,$Stat,$Info = $_.Trim() -split '\s{2,}'
[PsCustomObject]#{
'Server' = $server
'Volume ###' = $disk
'Ltr' = $status
'Label' = $Label
'Fs' = $Fs
'Type' = $Type
'Size' = $size
'Status' = $Stat
'Info' = $Info
}
}
}
# output on console screen
$result | Format-Table -AutoSize
# output to CSV file
$result | Export-Csv -Path "C:\$server.csv" -NoTypeInformation -Append
Output is coming like
Server Volume ### Ltr Label Fs Type Size Status Info
------ ---------- --- ----- -- ---- ---- ------ ----
AxxxxxxxxxxxxxP Volume 0 Z DVD-ROM 0 B No Media
AxxxxxxxxxxxxxP Volume 1 System Rese NTFS Partition 500 MB Healthy System
AxxxxxxxxxxxxxP Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
AxxxxxxxxxxxxxP Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
AxxxxxxxxxxxxxP Volume 4 D DATA NTFS Partition 199 GB Healthy
AxxxxxxxxxxxxxP Volume 5 E bit locker NTFS Partition 9 GB Healthy
AxxxxxxxxxxxxxP Volume 6 F test NTFS Partition 10 GB Healthy
Please let me know how to handle the spaces or any other way I can write it to csv
After executing #Mathias code
"Count","IsReadOnly","Keys","Values","IsFixedSize","SyncRoot","IsSynchronized"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
this is what I am trying to do
$server = $env:COMPUTERNAME
# Start by reading in the table
# Replace this statement with `
$lines = Get-Content "c:\d.txt"
$lines = $lines -split '\r?\n'
# Assign the first two lines to separate variables
$header, $guardRails, $lines = $lines
# Split the header into individual column names
$columnNames = #(
$header.Trim() -split '\s{2,}' |ForEach-Object Trim
)
# Use regex to match all the individual `---` sequences, grab their offset + length
$columnOffsets = #(
[regex]::Matches($guardRails, '(?<!-)-+(?!-)') |Select Index,Length
)
# Parse the data based on the offsets located above
foreach($line in $lines){
# Prepare a dictionary to hold the column values, add the Server property straight away
$properties = [ordered]#{
Server = $server
}
# Now we just need to iterate over the lists of column headers and extract the corresponding substring from the line
for($i = 0; $i -lt $columnNames.Length; $i++){
# Grab the column name and offset
$propertyName = $columnNames[$i]
$offset = $columnOffsets[$i]
# Grab the substring corresponding to the column
$propertyValue = $line.Substring($offset.Index, $offset.Length).Trim()
# Add the information to our property dictionary
$properties[$propertyName] = $propertyValue
}
# Output a new object based on the properties we grabbed from the column data
[pscustomobject]$properties
# output on console screen
$properties | Format-Table -AutoSize
# output to CSV file
$properties | Export-Csv -Path "C:\$server.csv" -NoTypeInformation -Append
}
Use the line below the header ( ---------- --- -----------...) to detect at which offsets to parse data for a specific column name:
# Start by reading in the table
# Replace this statement with `$lines = Get-Content .\path\to\file.txt` in your script
$lines = #'
Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 Z DVD-ROM 0 B No Media
Volume 1 System Rese NTFS Partition 500 MB Healthy System
Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
Volume 4 D DATA NTFS Partition 199 GB Healthy
Volume 5 E bit locker NTFS Partition 9 GB Healthy
Volume 6 F test NTFS Partition 10 GB Healthy
'# -split '\r?\n'
# Assign the first two lines to separate variables
$header, $guardRails, $lines = $lines
# Split the header into individual column names
$columnNames = #(
$header.Trim() -split '\s{2,}' |ForEach-Object Trim
)
# Use regex to match all the individual `---` sequences, grab their offset + length
$columnOffsets = #(
[regex]::Matches($guardRails, '(?<!-)-+(?!-)') |Select Index,Length
)
# Parse the data based on the offsets located above
$volumeInfo = foreach($line in $lines){
# Prepare a dictionary to hold the column values, add the Server property straight away
$properties = [ordered]#{
Server = 'Server123'
}
# Now we just need to iterate over the lists of column headers and extract the corresponding substring from the line
for($i = 0; $i -lt $columnNames.Length; $i++){
# Grab the column name and offset
$propertyName = $columnNames[$i]
$offset = $columnOffsets[$i]
# Grab the substring corresponding to the column
$propertyValue = $line.Substring($offset.Index, $offset.Length).Trim()
# Add the information to our property dictionary
$properties[$propertyName] = $propertyValue
}
# Output a new object based on the properties we grabbed from the column data
[pscustomobject]$properties
}
$volumeInfo |Export-Csv path\to\output.csv -NoTypeInformation
I import a CSV using import-csv command:
$P = Import-Csv "C:\MyCSV.csv"
I then run 'Get-Member':
$P | Get-Member
Output:
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Message NoteProperty string Message=ABC 1234 DEFGH 123:3212 IJKLM NOPQRST 23\13\19 ABC1234 0978AJD
I then run 'Format-Table':
$P | Format-Table
Output:
Message
-------
ABC 1234 DEFGH 123:3222 IJKNM NOPQRHT 23\13\19 ABC1234 0978AJD...
BAC 3214 DEFAH 123:3422 IJFLM NOPQRAT 23\13\18 ABC1234 0978AJD...
CEC 1534 DEFIH 123:3312 IJALM NOPQRFT 23\13\17 ABC1234 0978AJD...
3BC 1144 DAFGH 123:3612 IJZLM NOPQRGT 23\13\16 ABC1234 0978AJD...
I want to split this output up further by delimiting by space. I do not care about properly naming each new column. I just want to be able to then select whatever column header certain text falls under and export that output to a new CSV.
Ideal output:
Column1 Column2 Column3 Column4 etc
------- ------- ------- -------
ABC 1234 DEFGH 123:3222 etc
So I can then run a command such as:
select Column5,Column8
or a command like
select Column15,Column58
Can anyone assist me with this?
This ought to do the job:
# fake reading in a CSV file as text
# in real life, use Get-Content
$InStuff = #'
Message
ABC 1234 DEFGH 123:3222 IJKNM NOPQRHT 23\13\19 ABC1234 0978AJD
BAC 3214 DEFAH 123:3422 IJFLM NOPQRAT 23\13\18 ABC1234 0978AJD
CEC 1534 DEFIH 123:3312 IJALM NOPQRFT 23\13\17 ABC1234 0978AJD
3BC 1144 DAFGH 123:3612 IJZLM NOPQRGT 23\13\16 ABC1234 0978AJD
'# -split [environment]::NewLine
$ColCount = $InStuff[1].Split(' ').Count
$Collection = $InStuff |
Select-Object -Skip 1 |
ConvertFrom-Csv -Delimiter ' ' -Header (1..$ColCount).ForEach({"Column_$_"})
$Collection |
Select-Object -Property 'Column_3', 'Column_7'
Output:
Column_3 Column_7
-------- --------
DEFGH 23\13\19
DEFAH 23\13\18
DEFIH 23\13\17
DAFGH 23\13\16
What it does:
reads the file in as a text file, not a CSV file
gets a count on the # of columns
skips the 1st line
creates a CSV import
sets the delimiter to <space>
sets the header to the range of 1..$ColCount
filters for the desired columns
Lee, I am currently unable to edit my own post because my reputation is too low -_-. As such, I will respond to the post with the information you're requesting:
For your further insight, here is my current code that's not working:
$InStuff = Get-Content -Path 'MyCSV.csv'
$ColCount = $InStuff[1].Split(' ').Count
$Collection = $InStuff |
Select-Object -Skip 1 |
ConvertFrom-Csv -Delimiter ' ' -Header (1..$ColCount).ForEach({"Column_$_"})
$Collection
Output. As you can see, all columns except Column_1 are empty:
Column_1 : <134>Dec 13 13:50:23 10.137.119.42 MSWinEventLog 1 Security 123456789
Thu Dec 13 13:50:23 2018 4662 Microsoft-Windows-Security-Auditing MyCompany\dy625 N/A
Success Audit mydc1.dy625.com Directory Service Access An operation was performed on
an object. Subject : Security ID: S-123456 Account Name: dy625 Account
Domain: MyCompany Logon ID: XXXXXXXX Object: Object Server: DS Object
Type: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Object Name: %{XXXXXXXX-XXXXXXXX-XXXXXXXX}
Handle ID: 0x0 Operation: Operation Type: Object Access Accesses: Write
Property Access Mask: 0x20 Properties: Write Property {XXXX-XXXX-XXXXX} {XXXX-
XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} Additional Information:
Parameter 1: - Parameter 2: 123456
Column_2 :
Column_3 :
Column_4 :
Column_5 :
...
Column_1 : <134>Dec 13 13:50:18 10.137.119.42 MSWinEventLog 1 Security 123456789
Thu Dec 13 13:50:18 2018 4662 Microsoft-Windows-Security-Auditing MyCompany\dy626 N/A
Success Audit mydc1.dy625.com Directory Service Access An operation was performed on
an object. Subject : Security ID: S-123456 Account Name: dy626 Account
Domain: MyCompany Logon ID: XXXXXXXX Object: Object Server: DS Object
Type: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Object Name: %{XXXXXXXX-XXXXXXXX-XXXXXXXX}
Handle ID: 0x0 Operation: Operation Type: Object Access Accesses: Write
Property Access Mask: 0x20 Properties: Write Property {XXXX-XXXX-XXXXX} {XXXX-
XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} Additional Information:
Parameter 1: - Parameter 2: 123456
Column_2 :
Column_3 :
Column_4 :
Column_5 :
...
Column_1 : <134>Dec 13 13:50:14 10.137.118.22 MSWinEventLog 1 Security 123456789
Thu Dec 13 13:50:14 2018 4662 Microsoft-Windows-Security-Auditing MyCompany\dy627 N/A
Success Audit mydc1.dy625.com Directory Service Access An operation was performed on
an object. Subject : Security ID: S-123456 Account Name: dy627 Account
Domain: MyCompany Logon ID: XXXXXXXX Object: Object Server: DS Object
Type: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Object Name: %{XXXXXXXX-XXXXXXXX-XXXXXXXX}
Handle ID: 0x0 Operation: Operation Type: Object Access Accesses: Write
Property Access Mask: 0x20 Properties: Write Property {XXXX-XXXX-XXXXX} {XXXX-
XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} Additional Information:
Parameter 1: - Parameter 2: 123456
Column_2 :
Column_3 :
Column_4 :
Column_5 :
As I stated before, I think the issue is that I don't know how to re-implement the '-split [environment]::NewLine' command with the updated syntax. As you can, see it's missing. I think this is the cause of the issue.
When I input the raw text as you suggest, with the entire first 3 lines, your syntax works correctly, as expected.
$InStuff = #'
Message
<134>Dec 13 13:50:23 10.137.119.42 MSWinEventLog 1 Security 123456789 Thu Dec 13 13:50:23 2018 4662 Microsoft-Windows-Security-Auditing MyCompany\dy625 N/A Success Audit mydc1.dy625.com Directory Service Access An operation was performed on an object. Subject : Security ID: S-123456 Account Name: dy625 Account Domain: MyCompany Logon ID: XXXXXXXX Object: Object Server: DS Object Type: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Object Name: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Handle ID: 0x0 Operation: Operation Type: Object Access Accesses: Write Property Access Mask: 0x20 Properties: Write Property {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} Additional Information: Parameter 1: - Parameter 2: 123456
<134>Dec 13 13:50:18 10.137.119.42 MSWinEventLog 1 Security 123456789 Thu Dec 13 13:50:18 2018 4662 Microsoft-Windows-Security-Auditing MyCompany\dy626 N/A Success Audit mydc1.dy625.com Directory Service Access An operation was performed on an object. Subject : Security ID: S-123456 Account Name: dy626 Account Domain: MyCompany Logon ID: XXXXXXXX Object: Object Server: DS Object Type: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Object Name: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Handle ID: 0x0 Operation: Operation Type: Object Access Accesses: Write Property Access Mask: 0x20 Properties: Write Property {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} Additional Information: Parameter 1: - Parameter 2: 123456
<134>Dec 13 13:50:14 10.137.118.22 MSWinEventLog 1 Security 123456789 Thu Dec 13 13:50:14 2018 4662 Microsoft-Windows-Security-Auditing MyCompany\dy627 N/A Success Audit mydc1.dy625.com Directory Service Access An operation was performed on an object. Subject : Security ID: S-123456 Account Name: dy627 Account Domain: MyCompany Logon ID: XXXXXXXX Object: Object Server: DS Object Type: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Object Name: %{XXXXXXXX-XXXXXXXX-XXXXXXXX} Handle ID: 0x0 Operation: Operation Type: Object Access Accesses: Write Property Access Mask: 0x20 Properties: Write Property {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} {XXXX-XXXX-XXXXX} Additional Information: Parameter 1: - Parameter 2: 123456
'# -split [environment]::NewLine
$ColCount = $InStuff[1].Split(' ').Count
$Collection = $InStuff |
Select-Object -Skip 1 |
ConvertFrom-Csv -Delimiter ' ' -Header
(1..$ColCount).ForEach({"Column_$_"})
$Collection |
Select-Object -Property 'Column_3', 'Column_7'
Output:
$Collection |
Select-Object -Property 'Column_3', 'Column_7'
Column_3 Column_7
-------- --------
13:50:23 Security
13:50:18 Security
13:50:14 Security
Again, I think the issue is just that I don't know how to implement the '-split [environment]::NewLine'command.
$InStuff = Get-Content -Path 'MyCSV.csv' -split [environment]::NewLine
Error:
Get-Content : A parameter cannot be found that matches parameter name 'split'.
Anyway, I hope this sheds some clarity on the issue.
I have a NetApp log output in a log file which is the below format.
DeviceDetails.log file content
/vol/DBCXARCHIVE002_E_Q22014_journal/DBCXARCHIVE002_E_Q22014_journal 1.0t (1149038714880) (r/w, online, mapped)
Comment: " "
Serial#: e3eOF4y4SRrc
Share: none
Space Reservation: enabled (not honored by containing Aggregate)
Multiprotocol Type: windows_2008
Maps: DBCXARCHIVE003=33
Occupied Size: 1004.0g (1077986099200)
Creation Time: Wed Apr 30 20:14:51 IST 2014
Cluster Shared Volume Information: 0x0
Read-Only: disabled
/vol/DBCXARCHIVE002_E_Q32014_journal/DBCXARCHIVE002_E_Q32014_journal 900.1g (966429273600) (r/w, online, mapped)
Comment: " "
Serial#: e3eOF507DSuU
Share: none
Space Reservation: enabled (not honored by containing Aggregate)
Multiprotocol Type: windows_2008
Maps: DBCXARCHIVE003=34
Occupied Size: 716.7g (769556951040)
Creation Time: Tue Aug 12 20:24:14 IST 2014
Cluster Shared Volume Information: 0x0
Read-Only: disabled
Wherein the output is of only 2 devices , it has more than x devices appended in the log file.
I just need 4 details from each module ,
The first line contains 3 needed details
Device Name : /vol/DBCXARCHIVE002_E_Q22014_journal/DBCXARCHIVE002_E_Q22014_journal
Total Capacity : 1.0t (1149038714880)
Status : (r/w, online, mapped)
And the 4th Detail I need is Occupied Size: 1004.0g (1077986099200)
So the CSV output should look like below :
I am not just a beginner at coding and trying to achieve this with the below code, it does not help much though :/
$logfile = Get-Content .\DeviceDetails.log
$l1 = $logfile | select-string "/vol"
$l2 = $logfile | select-string "Occupied Size: "
$objs =#()
$l1 | ForEach {
$o = $_
$l2 | ForEach {
$o1 = $_
$Object22 = New-Object PSObject -Property #{
'LUN Name , Total Space, Status, Occupied Size' = "$o"
'Occupied Size' = "$o1"
}
}
$objs += $Object22
}
$objs
$obj = $null # variable to store each output object temporarily
Get-Content .\t.txt | ForEach-Object { # loop over input lines
if ($_ -match '^\s*(/vol.+?)\s+(.+? \(.+?\))\s+(\(.+?\))') {
# Create a custom object with all properties of interest,
# and store it in the $obj variable created above.
# What the regex's capture groups - (...) - captured is available in the
# the automatic $Matches variable via indices starting at 1.
$obj = [pscustomobject] #{
'Device Name' = $Matches[1]
'Total Space' = $Matches[2]
'Status' = $Matches[3]
'Occupied Size' = $null # filled below
}
} elseif ($_ -match '\bOccupied Size: (.*)') {
# Set the 'Occupied Size' property value...
$obj.'Occupied Size' = $Matches[1]
# ... and output the complete object.
$obj
}
} | Export-Csv -NoTypeInformation out.csv
- Note that Export-Csv defaults to ASCII output encoding; change that with the -Encoding parameter.
- To extract only the numbers inside (...) for the Total Space and Occupied Size columns, use
$_ -match '^\s*(/vol.+?)\s+.+?\s+\((.+?)\)\s+(\(.+?\))' and
$_ -match '\bOccupied Size: .+? \((.*)\)' instead.
Note how this solution processes the input file line by line, which keeps memory use down, though generally at the expense of performance.
As for what you tried:
You collect the entire input file as an array in memory ($logfile = Get-Content .\DeviceDetails.log)
You then filter this array twice into parallel arrays, containing corresponding lines of interest.
Things go wrong when you attempt to nest the processing of these 2 arrays. Instead of nesting, you must enumerate them in parallel, as their corresponding indices contain matching entries.
Additionally:
a line such as 'LUN Name , Total Space, Status, Occupied Size' = "$o" creates a single property named LUN Name , Total Space, Status, Occupied Size, which is not the intent.
in order to create distinct properties (to be reflected as distinct colums in CSV output), you must create them as such, which requires parsing the input into distinct values accordingly.
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.