Access next webpage after clicking - regex

Requirement : After clicking on webpage named in $ie.Navigate below. I Need to access HTML / OuterHTML source of Web-page which opens next.
Ex: When I open https://www.healthkartplus.com/search/all?name=Sporanox (by setting $control = Sporanox), below code simply clicks on first matching link. After link is clicked, I need to access HTML of resulting page.
Update : referred another SO question and learned that we can search appropriate window. Code seems to be working for some scenarios but not for all. For $ie2 I get problem accessing Document property.
function getStringMatch
{
# Loop through all 2 digit combinations in the $path directory
foreach ($control In $controls)
{
$ie = New-Object -COMObject InternetExplorer.Application
$ie.visible = $true
$site = $ie.Navigate("https://www.healthkartplus.com/search/all?name=$control")
$ie.ReadyState
while ($ie.Busy -and $ie.ReadyState -ne 4){ sleep -Milliseconds 100 }
$link = $null
$link = $ie.Document.get_links() | where-object {$_.innerText -eq "$control"}
$link.click()
while ($ie.Busy -and $ie.ReadyState -ne 4){ sleep -Milliseconds 100 }
$ie2 = (New-Object -COM 'Shell.Application').Windows() | ? {
$_.Name -eq 'Windows Internet Explorer' -and $_.LocationName -match "^$control"
}
# NEED outerHTML of new page. CURRENTLY it is working for some.
$ie.Document.body.outerHTML > d:\med$control.txt
}
}
$controls = "Sporanox"
getStringMatch

I think the issue is when you look for the links in the first page.
The link innerText is not equal to $control, it contains $control i.e. innerText is "Sporanox (100mg)".
The following might help:
$link = $ie.Document.get_links() | where-object {if ($_.innerText){$_.innerText.contains($control)}}
EDIT
Here is the complete code I'm using:
function getStringMatch
{
# Loop through all 2 digit combinations in the $path directory
foreach ($control In $controls)
{
$ie = New-Object -COMObject InternetExplorer.Application
$ie.visible = $true
$site = $ie.Navigate("https://www.healthkartplus.com/search/all?name=$control")
$ie.ReadyState
while ($ie.Busy -and $ie.ReadyState -ne 4){ sleep -Milliseconds 100 }
$link = $null
$link = $ie.Document.get_links() | where-object {if ($_.innerText){$_.innerText.contains($control)}}
$link.click()
while ($ie.Busy)
{
sleep -Milliseconds 100
}
# NEED outerHTML of new page. CURRENTLY it is working for some.
$ie.Document.body.outerHTML > d:\med$control.txt
}
}
$controls = "Sporanox"
getStringMatch

Related

Parse email body paragragh in Powershell

I am creating a script to parse outlook email body, so that I can get say an (ID number, date, name) after strings ID: xxxxxx Date: xxxxxx Name:xxxxx. I was looking around and could not fine anything that allows me to take the string after a match.
What I manage so far is to query for the email that was send by the specific users from outlook.
Add-Type -Assembly "Microsoft.Office.Interop.Outlook"
$Outlook = New-Object -ComObject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
foreach ($items in $inbox.items){if (($items.to -like "*email*") -or ($items.cc -like "*email.add*")){$FindID = $items.body}}
Now that I have the email body in the for loop I am wondering how I can parse the content?
In between the paragraphs will be a text something like this
ID: xxxxxxxx
Name: xxxxxxxxx
Date Of Birth : xxxxxxxx
I did some testing on the below to see if I can add that into the for loop but it seem like I cannot break the paragraphs.
$FindID| ForEach-Object {if (($_ -match 'ID:') -and ($_ -match ' ')){$testID = ($_ -split 'ID: ')[1]}}
I get the following results which I cannot get just the ID.
Sample Result when i do $testID
xxxxxxxx
Name: xxxxxxxxx
Date Of Birth : xxxxxxxx
Regards,
xxxxx xxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
How do I get just the results I want? I am just struggling at that portion.
You'll need a Regular Expression with (named) capture groups to grep the values. See example on rexgex101.com.
Provdid $item.bodyis not html and a single string, this could work:
## Q:\Test\2018\07\24\SO_51492907.ps1
Add-Type -Assembly "Microsoft.Office.Interop.Outlook"
$Outlook = New-Object -ComObject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $namespace.GetDefaultFolder(
[Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
## see $RE on https://regex101.com/r/1B2rD1/1
$RE = [RegEx]'(?sm)ID:\s+(?<ID>.*?)$.*?Name:\s+(?<Name>.*?)$.*?Date Of Birth\s*:\s*(?<DOB>.*?)$.*'
$Data = ForEach ($item in $inbox.items){
if (($item.to -like "*email*") -or
($item.cc -like "*email.add*")){
if (($item.body -match $RE )){
[PSCustomObject]#{
ID = $Matches.ID
Name = $Matches.Name
DOB = $Matches.DOB
}
}
}
}
$Data
$Data | Export-CSv '.\data.csv' -NoTypeInformation
Sample output with above anonimized mail
> Q:\Test\2018\07\24\SO_51492907.ps1
ID Name DOB
-- ---- ---
xxxxxx... xxxxxxx... xxxxxx...
I don't have Outlook available at the moment, but i think this will work
Add-Type -Assembly "Microsoft.Office.Interop.Outlook"
$Outlook = New-Object -ComObject Outlook.Application
$namespace = $Outlook.GetNameSpace("MAPI")
$inbox = $namespace.GetDefaultFolder([Microsoft.Office.Interop.Outlook.OlDefaultFolders]::olFolderInbox)
$inbox.items | Where-Object { $_.To -like "*email*" -or $_.CC -like "*email.add*"} {
$body = $_.body
if ($body -match '(?s)ID\s*:\s*(?<id>.+)Name\s*:\s*(?<name>.+)Date Of Birth\s*:\s*(?<dob>\w+)') {
New-Object -TypeName PSObject -Property #{
'Subject' = $_.Subject
'Date Received' = ([datetime]$_.ReceivedTime).ToString()
'ID' = $matches['id']
'Name' = $matches['name']
'Date of Birth' = $matches['dob']
}
}
}

parsing solution file using powershell

I have a solution file that includes some projects inside and I'd like to delete some of them using PowerShell.
The aim is to delete a block of text that contains a string (let's say "abcxyz") starting with "Project" and ends with "EndProject" in the next line (or more than that).
For example:
Project("{1111-2222-FFFF-3333}") = "AutoRun", "..\generate\Infra\generate\generate.csproj", "{999999-UUUUUU-GGGGGG-ABCDEFGH}"
EndProject
Project("{5555-2222-FFFF-3333}") = "SetupSec", "..\generate\Setup.csproj", "{999999-UUUUUU-GGGGGG-ABCDEFGH}"
EndProject
Project("{4444-2222-FFFF-3333}") = "Common.Fyyy", "..\generate\Infra\Common\Common.csproj", "{999999-UUUUUU-GGGGGG-ABCDEFGH}"
EndProject
Project("{9999-2222-FFFF-3333}") = "Command.Console", "..\generate\Path\Console.csproj", "{999999-UUUUUU-GGGGGG-ABCDEFGH}"
EndProject
Project("{7777-2222-FFFF-3333}") = "Infra.GUI", "..\..\generate\GUI.csproj", "{999999-UUUUUU-GGGGGG-ABCDEFGH}"
ProjectSection(ProjectDependencies) = postProject
{AAAA-2222-FFFF-3333} = {999999-UUUUUU-GGGGGG-ABCDEFGH}
EndProjectSection
EndProject
In the example above, I'd like to remove projects contains the string "Infra" in any case.
Is there a simple way of doing it using PowerShell Regex?
(deletion should be done to entire solution file from Project to EndProject)
Thanks,
Shai.
I came here looking for a similar solution. What I did was create this powershell function. It may just be a good jumping off point where you can tailor to your more specific requirements, but it works for me. Enjoy...
function Remove-SourceControl() {
param (
[string]$sourceFilePathname
)
$tempFile = New-TemporaryFile
$filterOn = $false
$fileVersionCorrect = $false
$backupFile = "$sourceFilePathname (backup)"
Copy-Item $sourceFilePathname $backupFile
$rowIndex = 1
Get-Content -Path:$sourceFilePathname | ForEach-Object {
if ($_ -like "*Microsoft Visual Studio Solution File, Format Version 12.00*" ) {
$fileVersionCorrect = $true
}
if ($fileVersionCorrect -eq $true) {
if ($_ -like "*TeamFoundationVersionControl*") { $filterOn = $true }
if (!$filterOn) {
Write-Output $_ | Out-File -FilePath:$tempFile -Append
}
if ($filterOn -and $_ -like "*EndGlobalSection*") { $filterOn = $false }
} else {
Write-Output $_ | Out-File -FilePath:$tempFile -Append
}
$rowIndex++
}
if ($fileVersionCorrect -eq $true) {
Copy-Item $tempFile $sourceFilePathname -Force
}
Remove-Item $tempFile
}
$path = "c:\some-folder-pathname"
Remove-SourceControl "$path\MySoluton.sln"
Assuming your actual file is consistent with the sample data, you can do this without needing to mess with regex at all:
Get-Content $ProjectFile -Delimiter 'EndProject' |
Where-Object {$_ -notlike '*Infra*'} |
Add-Content $NewProjectFile
That will break up the file into separate projects, and then filter out any of them that contain the string "Infra", and write the rest to a new file.
Your question is "is there a simple way in Powershell" and the answer is: No.
Solution files are a nasty old format with various widely-separated parts that depend on each other. It is possible to edit them by hand but it is hard to get right and easy to get wrong.
If you simply want to delete some projects, open the file in Visual Studio, delete the projects, and save it.
If this question is to solve part of a larger problem, you should ask a new question, how to solve that larger problem.

Creating a ticket in VMWare using PowerCLI when free storage in datastore is too less

I am able to get the free space as ouptut by using the following code.
$body +=echo "------------Free space on Datastore.--------------"`r`n""`r`n""
$body +=get-datastore -name *datastore1* | sort Name | ForEach-Object {
$output=New-Object -TypeName PSObject -Property #{
Freespace = "$([math]::Round($_.FreeSpaceGB, 2)) GB"
Datastore_Name = $_.Name
}
}
Write-Output $output
Is it possible to raise a ticket if the free space is less than 2 GB? If so, how should I change my code?
EDIT :
if (get-datastore | where {$_.FreeSpaceGB -lt 2}){"dosomething"}
or
foreach ($ds in (get-datastore | where {$_.FreeSpaceGB -lt 2})){"dosomething"}

netsh result to a PowerShell object

I am trying to work with NETSH from PowerShell. I want see a result from this command such as an object, but netsh returns a string:
netsh wlan show hostednetwork | Get-Member
TypeName: System.String
...
My script must work on system with rather localization, and I can't use -match for parsing a string to an object directly.
How I can solve my trouble?
$netshResult = Invoke-Command -Computername localhost {netsh int tcp show global}
$result = #{}
$netshObject = New-Object psobject -Property #{
ReceiveSideScalingState = $Null
ChimneyOffloadState = $Null
NetDMAState = $Null
}
$netshResult = $netshResult | Select-String : #break into chunks if colon only
$i = 0
while($i -lt $netshResult.Length){
$line = $netshResult[$i]
$line = $line -split(":")
$line[0] = $line[0].trim()
$line[1] = $line[1].trim()
$result.$($line[0]) = $($line[1])
$i++
}
$netshObject.ReceiveSideScalingState = $result.'Receive-Side Scaling State'
$netshObject.ChimneyOffloadState = $result.'Chimney Offload State'
$netshObject.NetDMAState = $result.'NetDMA State'
You got a few alternatives, none of which are nice.
1) Read the netsh output into a string[] and use a custom record parser to create your own object. That is, look at the output on different locales and find out if, say, Hosted newtork settings is always the first header followed by bunch of - characters. If that's the case, assume that next element in array is Mode and so on. This is very error prone, but usually MS command line tools only translate messages, not their order.
2) Look for .Net API for the same information. There is System.Net.NetworkInformation which contains a bunch of connection things. It's a start, though I am not sure if it has info you need.
3) Failing the previous options, use P/Invoke to call native Win32 API. It's a lot of work, so look for pre-existing wrapper libraries before rolling your own.
I recently wrote a cmdlet to parse arbitrary, multi-line text using regular expressions, called ConvertFrom-Text. (Not a great name, if you ask me, but it conforms to the PowerShell naming rules; suggestions are welcome!) So assuming you have that cmdlet, here is one possible solution to your question. (Caveat emptor! The regular expression given was derived from a very small sample of netsh output, so may need some tuning.)
$regex = [regex] '(?ms)(?:^\s*$\s*)?^(?<section>.*?)\s*-+\s*(?<data>.*?)\s*^\s*$'
$result = netsh wlan show hostednetwork | Out-String |
ConvertFrom-Text -pattern $regex -multiline
$result | % {
$dataObj = [PsCustomObject]#{}
$_.Data -split "`r`n" | % {
$element = $_ -split '\s*:\s*'
Add-Member -InputObject $dataObj -MemberType NoteProperty -Name $element[0].Trim() -Value $element[1].Trim()
}
$_.Data = $dataObj # Replace data text with data object
}
$result
On my test system, netsh wlan show hostednetwork returns this:
Hosted network settings
-----------------------
Mode : Allowed
Settings : <Not configured>
Hosted network status
---------------------
Status : Not available
And the output of the $result variable in the code above yields this:
section data
------- ----
Hosted network settings #{Mode=Allowed; Settings=<Not configured>}
Hosted network status #{Status=Not available}
So $result is an array of objects with section and data properties, and the latter is an object with properties defined by the output of the netsh command.
Of course, the above does not get you very far without the ConvertFrom-Text cmdlet. So here is the implementation. (I have copious documentation and examples for it, which will be publicly available once I eventually add it to my open-source PowerShell library.)
filter ConvertFrom-Text
{
[CmdletBinding()]
Param (
[Parameter(Mandatory=$true,Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[string[]]$InputObject,
[Parameter(Mandatory=$true,Position=1)]
[regex]$Pattern,
[switch]$RequireAll,
[switch]$Multiline
)
if ($Multiline) {
$dataString = $InputObject -join "`n"
IterateByMatch $dataString $Pattern
}
else {
IterateByLine $InputObject $Pattern
}
}
function IterateByLine([string[]]$data, [regex]$regex)
{
$data | ForEach-Object {
if ($PSItem -match $regex)
{
New-Object PSObject -Property (GetRegexNamedGroups $matches)
}
elseif ($RequireAll) {
throw "invalid line: $_"
}
}
}
function IterateByMatch([string[]]$data, [regex]$regex)
{
$regex.matches($data) | Foreach-Object {
$match = $_
$obj = new-object object
$regex.GetGroupNames() |
Where-Object {$_ -notmatch '^\d+$'} |
Foreach-Object {
Add-Member -InputObject $obj NoteProperty `
$_ $match.groups[$regex.GroupNumberFromName($_)].value
}
$obj
}
}
function Get-RegexNamedGroups($hash)
{
$newHash = #{};
$hash.keys | ? { $_ -notmatch '^\d+$' } | % { $newHash[$_] = $hash[$_] }
$newHash
}

How I can show and add items to Sharepoint List via Powershell?

hi I want to show and add items in Sharepoint via Powershell (I use for testing a list and a libary)
The name is Powershell-Test
the Url is
http//intranet/departments/it/abt/Lists/Powershell-Test/AllItems.aspx
I enable remote on the Sharepoint Server and make a remote connection to this from my localhost.
Enter-PSSession -ComputerName [sharepoint server] -Authentication Negotiate -Credential [Domain\name]
if((Get-PSSnapin -Name Microsoft.Sharepoint.Powershell -ErrorAction SilentlyContinue) -eq $null)
{
Add-PSSnapin Microsoft.Sharepoint.Powershell
}
$webURL = "http//intranet/departments/it/abt/Lists/"
$listname = "Powershell-Test"
$web = Get-SPWeb $webURL
$web.lists | format-table title
$list = $web.LIsts[$listName]
$list.items | foreach { $_[„Title“] + „`n“ + $_[„Body“] }
The Problem is that I don#t get the connection to the list :(
How I can to this?
I presume you have permission to access the site.
I also presume you don't have a site or subsite with the name "Lists".
I don't think you can use Get-SPWeb with the path "/Lists/" within it (unless the site was named "lists").
Could you try:
if ((Get-PSSnapin -Name Microsoft.SharePoint.Powershell -ErrorAction SilentlyContinue) -eq $null) {
Add-PSSnapin Microsoft.SharePoint.Powershell
}
$siteURL = "http//intranet/departments/it/abt/"
$web = Get-SPWeb $siteURL
$list = $web.Lists["Powershell-Test"]
$list.Items | foreach { $_["Title"] + "`n" + $_["Body"] }