Split Strings in a Value column with Powercli - vmware

This is what I wrote to get output with powercli;
Get-VM -name SERVERX | Get-Annotation -CustomAttribute "Last EMC vProxy Backup"|select #{N='VM';E={$_.AnnotatedEntity}},Value
This is the output
VM Value
-- -----
SERVERX Backup Server=networker01, Policy=vmbackup, Workflow=Linux_Test_Production, Action=Linux_Test_Production, JobId=1039978, StartTime=2018-10-31T00:00:27Z, EndTime=2018-10-31T00:12:45Z
SERVERX1 Backup Server=networker01, Policy=vmbackup, Workflow=Linux_Test_Production, Action=Linux_Test_Production, JobId=1226232, StartTime=2018-12-06T00:00:29Z, EndTime=2018-12-06T00:0...
SERVERX2 Backup Server=networker01, Policy=vmbackup, Workflow=Linux_Test_Production, Action=Linux_Test_Production, JobId=1226239, StartTime=2018-12-05T23:58:27Z, EndTime=2018-12-06T00:0...
But I would like retrieve only "starttime" and "endtime" values
Desired output is;
VM Value
-- -----
SERVERX StartTime=2018-10-31T00:00:27Z, EndTime=2018-10-31T00:12:45Z
SERVERX1 StartTime=2018-12-06T00:00:29Z, EndTime=2018-1206T00:11:14Z
SERVERX2 StartTime=2018-12-05T23:58:27Z, EndTime=2018-12-06T00:11:20Z
How can I get this output?

This would be better suited in Powershell forum as this is just data manipulation.
Providing your output is always the same number of commas then
$myannotation = Get-VM -name SERVERX | Get-Annotation -CustomAttribute "Last EMC
vProxy Backup"|select #{N='VM';E={$_.AnnotatedEntity}},Value
$table1 = #()
foreach($a in $myannotation)
$splitter = $a.value -split ','
$splitbackupstart = $splitter[5]
$splitbackupend = $splitter[6]
$row = '' | select vmname, backupstart, backupend
$row.vmname = $a.AnnotatedEntity # or .vm would have to try
$row.backupstart = $splitbackupstart
$row.backupend= $splitbackupend
$table1 += $row
}
$table1
Untested. If you format of the string is going to change over time then a regex to search for starttime will be better.

Related

Is there a way to extract only the value from "free" field of Get-PSDrive?

I'm trying to take the value of free space from a drive, this is necessary to do an automatict procedure in a database server.
I got this script:
$query_drive_mount_point = #"
select distinct
convert(varchar(512), b.volume_mount_point) as [volume],
convert(varchar(512), b.logical_volume_name) as [logical_volume]
from sys.master_files as [a]
CROSS APPLY sys.dm_os_volume_stats(a.database_id, a.[file_id]) as [b]
"#
[regex]$get_drive = '\w\:\\'
[regex]$get_drive_name = '\w'
[regex]$get_drive_space = '\d'
$mount_point = Invoke-Sqlcmd -ServerInstance "$server_ip\$sql_engine,$sql_port" -Username "$sql_user" -Password "$sql_password" -Database Master -Query "$query_drive_mount_point"
$get_disk = $get_drive.Matches($mount_point) | Foreach-Object {$_.Value}
$get_disk_name = $get_drive_name.Matches($get_disk) | Foreach-Object {$_.Value}
$size_bytes_string = Get-PSDrive $get_disk_name | Select-Object -Property Free
[int]$size_bytes = $get_drive_space.Matches($size_bytes_string) | ForEach-Object {$_.Value}
$size_giga = ( ( ( $size_bytes )/1024 )/1024 )/1024
This code runs without problem until this line:
[int]$size_bytes = $get_drive_space.Matches($size_bytes_string) | ForEach-Object {$_.Value}
It throws this error:
There was not found overload for "Matches" and args numbers is "1".
En línea: 1 Carácter: 1
+ $size_bytes = $get_drive_space.Matches($size_bytes_string) | ForEach- ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
The last error is a traduction made by me, the os is in spanish.
Again, the objective is to store only the free space value.
You need to select the value from the property you need, so this line:
$size_bytes_string = Get-PSDrive $get_disk_name | Select-Object -Property Free to
Should be changed to the following:
$size_bytes_string = Get-PSDrive $get_disk_name | Select-Object -ExpandProperty Free
Alternatively you can format it as follows:
($size_bytes_string = Get-PSDrive $get_disk_name).Free
If you have PS version 5:
PS C:\> (($PSVersionTable).PSVersion)
Major Minor Build Revision
----- ----- ----- --------
5 1 18362 145
if not version 5, try to import the storage module.
You can get this information easier by using the below commandlet:
Get-disk # the command name
Get-Command -Module storage -Verb get -Noun disk # module
onliner code to select the size of the first hdd (disk 0):
[math]::Round((Get-Disk -Number 0).Size /1GB)
- Edited :
=========================================================================
if you load this assembly, you can get all the information you need,
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.SqlServer.SMO') | out-null
$sql = New-Object ('Microsoft.SqlServer.Management.Smo.Server')
You can run this commandlet to find what information you can get :
(($sql | gm) | measure).count
For example :
write-host $dbs.Parent
$dbs=$s.Databases
I believe you need a property called filegroup to get information about ldf&mdf files.

Compare two strings in powershell, regex * match, output DataSpace_ID field from string1 based on match, into switches listing string in own column

I have a list of switches in CSV and a list of data spaces where these switches are. In my list of Data Spaces, I have a DataSpace_ID field which represents its associated DataSpace_Name.
My list of switches has a Host_Name and IP_Address fields. What I want is using PowerShell and regex matching using Wildcards, I want to match the DataSpace field example, "ABC-COM" to the switch listing Host_Name which would be ABC-COM-3750-SW1. I only want to match up to ABC-COM...
Then for my result I want the output, based on the matches found, to associate the DataSpace_ID value found and include it in the output of the switch listing.
Let's say I match ABC-COM = DATASPACE_ID 1 and DEF-COM = DataSpace_ID 2, and my switch data is:
Host_Name IP_Address
ABC-COM-3750-SW1 IP 192.168.1.2
ABC-COM-3750-SW2 IP: 192.168.1.3
DEF-COM-3750-SW1 IP: 192.168.3.5
DEF-COM-3750-SW2 IP: 192.168.3.6
So, in the end you would have this output from the switch listing based on comparison of the dataspace listing, except it would add the DataSpace_ID Column from the other comparison listing of data space names... Switch listing Output would look like this:
DataSpace_ID Host_Name IP_Address
1 ABC-COM-3750-SW1 IP 192.168.1.2
1 ABC-COM-3750-SW2 IP: 192.168.1.3
2 DEF-COM-3750-SW1 IP: 192.168.3.5
2 DEF-COM-3750-SW2 IP: 192.168.3.6
Here is my latest code revised based on some of your input, I am not getting errors any longer, however my output is not returning any results either.
clear-host
$hash.clear()
$dataSpacesExport = Import-Csv -Path .\DataSpaces_Export.csv -Header 'DataSpace_ID', 'DataSpace_Name' -Delimiter ","
$accessSwitchesForExport = Import-Csv -Path .\AccessSwitchesForExport.csv -Header 'Host_Name', 'IP_Address' -Delimiter ","
# create hashtable
$hash = #{}
# Create Regex criteria
$re = [regex]".+(?=-\d+)"
$dataSpacesExport | ConvertFrom-Csv | % { $hash.Add($_,”$_”) }
# output
$accessSwitchesForExport | ConvertFrom-Csv |
Select-Object #{ n = "DataSpace_ID"; e = { $hash[$re.Match($_.Host_Name).Value] } },* |
Where-Object { $_.DataSpace_ID -ne $null }
My CSV files as some have asked for, example data would be:
DataSpaces and switches output examples are below in the post. DataSpaces contain a DataSpace_ID and DataSpace_Name, and switches csv contain a Host_Name and IP_Address fields.
Output, like below, based on comparison of two csv's should show:
Matching DataSpace_ID with matching Host_Name, and its associated IP Address in final table.
This is a solution using a hash table.
$dataSpacesExport = #"
DataSpace_ID,DataSpace_Name
1,ABC-COM
2,DEF-COM
"#
$accessSwitchesForExport = #"
Host_Name,IP_Address
ABC-COM-3750-SW1,IP: 192.168.1.2
ABC-COM-3750-SW2,IP: 192.168.1.3
DEF-COM-3750-SW1,IP: 192.168.3.5
DEF-COM-3750-SW2,IP: 192.168.3.6
GHI-COM-3750-SW2,IP: 192.168.3.6
"#
$re = [regex]".+(?=-\d+)"
# create hashtable
$id = #{}
$dataSpacesExport | ConvertFrom-Csv | ForEach-Object { $id[$_.DataSpace_Name] = $_.DataSpace_ID }
# output
$accessSwitchesForExport | ConvertFrom-Csv |
Select-Object #{ n = "DataSpace_ID"; e = { $id[$re.Match($_.Host_Name).Value] } },* |
Where-Object { $_.DataSpace_ID -ne $null }
The output is as follows.
DataSpace_ID Host_Name IP_Address
------------ --------- ----------
1 ABC-COM-3750-SW1 IP: 192.168.1.2
1 ABC-COM-3750-SW2 IP: 192.168.1.3
2 DEF-COM-3750-SW1 IP: 192.168.3.5
2 DEF-COM-3750-SW2 IP: 192.168.3.6
The following code is another solution. In this case, you do not need a regular expression.
$dataSpaces = $dataSpacesExport | ConvertFrom-Csv
$accessSwitchesForExport | ConvertFrom-Csv | ForEach-Object {
foreach ($ds in $dataSpaces) {
if (!$_.Host_Name.StartsWith($ds.DataSpace_Name)) { continue }
[pscustomobject]#{
DataSpace_ID = $ds.DataSpace_ID
Host_Name = $_.Host_Name
IP_Address = $_.IP_Address
}
break
}
}
Thank you everyone for your help! I used bits and pieces of the recommendations above to come up with the following result which works perfectly and generates that data needed.
#Set Present Working Directory for path to save data to.
#Clear any Hash Table Data prior to start of script //
$id.clear()
#Import current listing of Data Spaces and Access switches from CSV format //
$dataSpacesExport = import-csv -Header DataSpace_ID, DataSpace_Name -Path ".\DataSpaces_Export.csv"
$accessSwitchesForExport = import-csv -Header Host_Name, Device_IP -Delimiter "," -Path ".\AccessSwitchesForExport.csv"
#Regex text matching criteria //
$re = [regex]".+(?=-\d+)"
# create hashtable to store output //
$id=#{}
# Inject DataSpaces listing into Script for processing via hash table $id //
$dataSpacesExport | % {$id[$_.DataSpace_Name] = $_.DataSpace_ID}
# output - Compare Access Switch listing to DataSpaces Hashtable information, produce output to out-file sw_names.txt //
$accessSwitchesForExport |
Select-Object #{ n = "DataSpace_ID"; e = { $id[$re.Match($_.Host_Name).Value] } },* |
Where-Object { $_.DataSpace_ID -ne $null } | Out-File ./sw_names.txt -Force
Output is as expected and is now working.

Rename files in Powershell with a reference file

Sorry for previous confusion...
I've spent several hours today trying to write a powershell script that will pull a client ID off a PDF from system #1 (example, Smith,John_H123_20171012.pdf where the client ID is the H#### value), then look it up in an Excel spreadsheet that contains the client ID in system 1 and system 2, then rename the file to the format needed for system 2 (xxx_0000000123_yyy.pdf).
One gotcha is that client # is 2-4 digits in system 2 and always preceeded by 0's.
Using Powershell and regular expressions.
This is the first part I am trying to use for my initial rename:
Get-ChildItem -Filter *.pdf | Foreach-Object{
$pattern = "_H(.*?)_2"
$OrionID = [regex]::Match($file, $pattern).Groups[1].value
Rename-Item -NewName $OrionID
}
It is not accepting "NewName" because it states it is an empty string. I have run:
Get-Variable | select name,value,Description
And new name shows up as a name but with no value. How can I pass the output from the Regex into the rename?
Run this code line by line in debugger, you will understand how this works.
#Starts an Excel process, you can see Excel.exe as background process
$processExcel = New-Object -com Excel.Application
#If you set it to $False you wont see whats going on on Excel App
$processExcel.visible = $True
$filePath="C:\somePath\file.xls"
#Open $filePath file
$Workbook=$processExcel.Workbooks.Open($filePath)
#Select sheet 1
$sheet = $Workbook.Worksheets.Item(1)
#Select sheet with name "Name of some sheet"
$sheetTwo = $Workbook.Worksheets.Item("Name of some sheet")
#This will store C1 text on the variable
$cellString = $sheet.cells.item(3,1).text
#This will set A4 with variable value
$sheet.cells.item(1,4) = $cellString
#Iterate through all the sheet
$lastUsedRow = $sheet.UsedRange.Rows.count
$LastUsedColumn = $sheet.UsedRange.Columns.count
for ($i = 1;$i -le $lastUsedRow; $i++){
for ($j = 1;$j -le $LastUsedColumn; $j++){
$otherString = $sheet.cells.item($i,$j).text
}
}
#Create new Workbook and add sheet to it
$newWorkBook = $processExcel.Workbooks.Add()
$newWorkBook.worksheets.add()
$newSheet = $newWorkBook.worksheets.item(1)
$newSheet.name="SomeName"
#Close the workbook, if you set $False it wont save any changes, same as close without save
$Workbook.close($True)
#$Workbook.SaveAs("C:\newPath\newFile.xls",56) #You can save as the sheet, 56 is format code, check it o internet
$newWorkBook.close($False)
#Closes Excel app
$processExcel.Quit()
#This code is to remove the Excel process from the OS, this does not always work.
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($processExcel)
Remove-Variable processExcel
I ended up using a utility called "Bulk Rename Utility" and Excel. I can run the various renaming regex's through BRU and add the reference .txt file after some Excel formatting.

RegEx PowerShell match

I have the following website http://www.shazam.com/charts/top-100/australia which displays songs, I want to capture the songs using RegEx & PowerShell. The PowerShell code below is what I have so far:
$ie = New-Object -comObject InternetExplorer.Application
$ie.navigate('http://www.shazam.com/charts/top-100/australia')
Start-Sleep -Seconds 10
$null = $ie.Document.body.innerhtml -match 'data-chart-position="1"(.|\n)*data-track-title=.*content="(.*)"><a href(.|\n)*data-track-artist=\W\W>(.|\n)*<meta\scontent="(.*)"\sitemprop';$shazam01artist = $matches[5];$shazam01title = $matches[2]
data-chart-position
data-track-title
data-track-artist
Each of the songs listed have the 3 values (above) associated with each of them, I want to capture the Artist & Title for each song based on the different chart positions (numbers). So a regular expression to find the actual chart position, then the trailing Artist & Title.
If I run the RegEx separately for Artist & Title (code below), it finds them, however it only finds the first Artist & Title. I need to find the Artist & Title for each song based on the different chart position.
$null = $ie.Document.body.innerhtml -match 'data-track-artist=\W\W>(.|\n)*<meta\scontent="(.*)"\sitemprop';$shazam01artist = $matches[2]
$null = $ie.Document.body.innerhtml -match 'data-track-title=.*content="(.*)"><a href';$shazam01title = $matches[1]
$shazam01artist
$shazam01title
Using regex to parse partial HTML is an absolute nightmare, you might want to reconsider that approach.
Invoke-WebRequest returns a property called ParsedHtml, that contains a reference to a pre-parsed HTMLDocument object. Use that instead:
# Fetch the document
$Top100Response = Invoke-WebRequest -Uri 'http://www.shazam.com/charts/top-100/australia'
# Select all the "article" elements that contain charted tracks
$Top100Entries = $Top100Response.ParsedHtml.getElementsByTagName("article") |Where-Object {$_.className -eq 'ti__container'}
# Iterate over each article
$Top100 = foreach($Entry in $Top100Entries){
$Properties = #{
# Collect the chart position from the article element
Position = $Entry.getAttribute('data-chart-position',0)
}
# Iterate over the inner paragraphs containing the remaining details
$Entry.getElementsByTagName('p') |ForEach-Object {
if($_.className -eq 'ti__artist') {
# the ti__artist paragraph contains a META element that holds the artist name
$Properties['Artist'] = $_.getElementsByTagName('META').item(0).getAttribute('content',0)
} elseif ($_.className -eq 'ti__title') {
# the ti__title paragraph stores the title name directly in the content attribute
$Properties['Title'] = $_.getAttribute('content',0)
}
}
# Create a psobject based on the details we just collected
New-Object -TypeName psobject -Property $Properties
}
Now, let's see how Tay-Tay's doing down under:
PS C:\> $Top100 |Where-Object { $_.Artist -match "Taylor Swift" }
Position Title Artist
-------- ----- ------
42 Bad Blood Taylor Swift Feat. Kendrick Lamar
Sweet!

Pick last item from list in Powershell

I'm trying to map a drive letter using this line of code which will give me a list of drives available from d to z.
ls function:[d-z]: -n | ? { !(test-path $_) }
I'd like to then pick the last letter, not random, from the list. How would I go about doing that? New to Powershell, thanks for the help.
You can use Select-Object -Last 1 at the end of that pipeline.
you can just start at the back of the list and go up.
last item: $array[-1]
Second to last: $array[-2]
and so on.
If you look for a much more verbose, but (in my opinion) readable-improved version:
# Get all drives which are used (unavailable)
# Filter for the "Name" property ==> Drive letter
$Drives = (Get-PSDrive -PSProvider FileSystem).Name
# Create an array of D to Z
# Haven't found a more elegant version...
$Letters = [char[]]([char]'D'..[char]'Z')
# Filter out, which $Letters are not in $Drives (<=)
# Again, filter for their letter
$Available = (Compare-Object -ReferenceObject $Letters -DifferenceObject $Drives | Where {$_.SideIndicator -eq "<="}).InputObject
# Get the last letter
$LastLetter = $Available[-1]
Try this:
ls function:[d-z]: -n|?{!(test-path $_)} | Select-Object -Last 1
Another option that doesn't require trying all paths from D-Z is to parse Get-Psdrive. Here's an example:
$lettersInUse = Get-Psdrive | ? { $_.Name.Length -eq 1 } | % { $_.Name }
$lastDriveLetter = [Char]'Z'
while ($lettersInUse -contains $lastDriveLetter) {
$lastDriveLetter = [Char]($lastDriveLetter - 1)
}
$lastDriveLetter
In case you have an array
$newArray = #(git tag --list)
$lastmember = $newArray[$newArray.Count – 1]
In case you have a list
$newArray | Select-Object -Last 1