Powershell script not working (Misspelling Project) - powershell

$app = New - Object - ComObject 'Word.Application'
$app.visible = $true
$doc = $app.Documents.Add(
}
$doc.Content.text = 'Here's an exmple of mispeled txt."
$selection = $app.Selection
$report = #(
}
foreach($word in ($doc.Words | Select - ExpandProperty Text)) {
if (!($app.CheckSpelling($word))) {
$result = New - Object - TypeName psobject - Property #(Mispelled = $word)
$sug = $app.GetSpellingSuggestions($word) | Select - ExpandProperty name
if ($sug) {
$report += New - Object psobject - Property # {
Misspelled = $word;
Suggestions = $sug
}
} else {
$report += New - Object - TypeName psobject - Property # {
Misspelled $word; =
Suggestions "No Suggestion"
}
}
}
}
$Sreport | Select - Property Misspelled, Suggestions
Hello. I found this script online, from which I'm trying to output a list of misspelled English words together with their spelling recommendations, using MS Word's spelling corrections via Powershell. I don't have coding knowledge, so I don't know why isn't the script working. Could someone help me out? Thanks!

This works, i think! You didnt mention the output you wanted so hope this is ok.
You were on the right track but had some syntax and bracket issues
$app = New-Object -ComObject 'Word.Application'
$app.visible = $false
$doc = $app.Documents.Add()
$doc.Content.text = Get-Content "C:\Temp\TestFile.txt" # This will get the text of the file specified
$selection = $app.Selection
$report = #() # an empty array which we will fill with spelling mistakes
foreach($word in ($doc.Words | Select -ExpandProperty Text)) { # loop through each word in the text
# if the word is misspelled then process it
if (!($app.CheckSpelling($word))) {
# get list of correction suggestions for this word
$suggestion = $app.GetSpellingSuggestions($word) | Select -ExpandProperty name
# if there are suggestions then add it to the report
if ($suggestion) {
$report += New-Object psobject -Property #{
Misspelled = $word;
Suggestions = $suggestion
}
}
# else if there are no suggestions then add an entry saying just that
else {
$report += New-Object -TypeName psobject -Property #{
Misspelled = $word;
Suggestions = "No Suggestion"
}
}
}
}
# push the results to a file
$report | Out-File "C:\Temp\results.txt"

Related

Powershell: Output a search from a csv to a small gui

maybe one of you experts can help a complete newbie (I don't know if what I want is even feasible).
Let's assume I have a CSV file with various data. (see csv_screenshot)csv_screenshot
I import this data via Powershell into a small GUI . How can I make it so that when I search for "Paris", I really only get the output for Paris in the GUI as a list view like this (see powershell_screenshot)
powershell_screenshot
Currently the output in the GUI looks like this (see current_result.png). How do I get it nicely formatted as a list in there. I really want to insert it like this (via Out Grid View it is no problem)
current_result.png
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Windows.Forms.Application]::EnableVisualStyles();
function search_csv {
$Input = $textbox_Search.text
$Input = "*$Input*"
$Input_Result = import-csv -path C:\Users\check.csv -Header "Location", "Client", "Mobile Device"
$output_TextBox.text = $Input_Result -like $Input
}
$search_csvtool = New-Object System.Windows.Forms.Form
$search_csvtool.Text = "CSV Search"
$search_csvtool.Size = New-Object System.Drawing.Size(674,500)
$search_csvtool.FormBorderStyle ="FixedDialog"
$search_csvtool.TopMost = $true
$search_csvtool.MaximizeBox = $false
$search_csvtool.MinimizeBox = $true
$search_csvtool.ControlBox = $true
$search_csvtool.StartPosition = "CenterScreen"
$search_csvtool.Font = "Courier New"
$label_Search = New-Object System.Windows.Forms.Label
$label_Search.Location = New-Object System.Drawing.Size(195,18)
$label_Search.Size = New-Object System.Drawing.Size(265,32)
$label_Search.TextAlign ="MiddleCenter"
$label_Search.Text = "Please enter "
$search_csvtool.Controls.Add($label_Search)
$textbox_Search = New-Object System.Windows.Forms.TextBox
$textbox_Search.Location = New-Object System.Drawing.Size(195,50)
$textbox_Search.Size = New-Object System.Drawing.Size(266,37)
$search_csvtool.Controls.Add($textbox_Search)
$button_Search = New-Object System.Windows.Forms.Button
$button_Search.Location = New-Object System.Drawing.Size(195,80)
$button_Search.Size = New-Object System.Drawing.Size(266,24)
$button_Search.TextAlign = "MiddleCenter"
$button_Search.Text = "Search"
$button_Search.Add_Click({search_csv})
$search_csvtool.Controls.Add($button_Search)
$output_TextBox = New-Object System.Windows.Forms.TextBox
$output_TextBox.Multiline = $true;
$output_TextBox.Location = New-Object System.Drawing.Size(16,130)
$output_TextBox.Size = New-Object System.Drawing.Size(627,314)
$output_TextBox.ScrollBars = "Vertical"
$output_TextBox.ReadOnly = $true;
$search_csvtool.Controls.Add($output_TextBox)
$search_csvtool.Add_Shown({$search_csvtool.Activate()})
[void] $search_csvtool.ShowDialog()
Ok, so here's what I meant in my comment:
Start the code with
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$csvData = Import-Csv -path 'C:\Users\check.csv' -Header "Location", "Client", "Mobile Device"
function search_csv {
$searchThis = $textbox_Search.Text.Trim()
# use $script: scoping here to reference the $csvData variable
$data = $script:csvData | Where-Object {$_.Location -like "*$searchThis*"}
if ($data) {
$output_TextBox.Text = ($data | Format-List | Out-String).Trim()
}
else {
$output_TextBox.Text = "Not found.."
}
}
Then create the rest of the form as you did.
Important: Destroy the form when done with a last new code line:
$search_csvtool.Dispose()
You should then have this result:
As per your comment to empty the textbox when nothing (or just whitespace) has been entered, you could change the function to:
function search_csv {
$searchThis = $textbox_Search.Text.Trim()
# use $script: scoping here to reference the $csvData variable
$data = $script:csvData | Where-Object {$_.Location -like "*$searchThis*"}
if ([string]::IsNullOrWhiteSpace($searchThis)) {
$output_TextBox.Clear()
}
elseif ($data) {
$output_TextBox.Text = ($data | Format-List | Out-String).Trim()
}
else {
$output_TextBox.Text = "Not found.."
}
}
However, as postanote already commented, it would be much better to simply disable the search button and only enable it when something other that whitespace has been entered.
To do that, you need to add an eventhandler to the textbox:
$textbox_Search = New-Object System.Windows.Forms.TextBox
$textbox_Search.Location = New-Object System.Drawing.Size(195,50)
$textbox_Search.Size = New-Object System.Drawing.Size(266,37)
$textbox_Search.Add_TextChanged({
# enable the button when there is at least one non-whitespace character present
$button_Search.Enabled = $this.Text -match '\S'
# or use
# $button_Search.Enabled = (-not [string]::IsNullOrWhiteSpace($this.Text))
})
$search_csvtool.Controls.Add($textbox_Search)
And initialize the button to be disabled at startup:
$button_Search = New-Object System.Windows.Forms.Button
$button_Search.Location = New-Object System.Drawing.Size(195,80)
$button_Search.Size = New-Object System.Drawing.Size(266,24)
$button_Search.TextAlign = "MiddleCenter"
$button_Search.Text = "Search"
# initialize to Disabled; will be enabled as soon as there is text entered in the $textbox_Search
$button_Search.Enabled = $false
$button_Search.Add_Click({search_csv})
$search_csvtool.Controls.Add($button_Search)
Inside an event handler, you can refer to the object itself using automatic variable $this
You should be able to go thru your string output line by line and change this.
That stated, you probably won't like how it looks. Normalized colons will probably look better.
This code should do the trick. I'll let you be the judge of if it looks "better"
$dataLines = ($data | Format-List | Out-String).Trim() -split '(?>\r\n|\n)'
$dataText = #(
foreach ($dataLine in $dataLines) {
$dataLine -replace '\s{1,}\:', ':'
}
) -join [Environment]::Newline
$output_TextBox.Text = $dataText

How to fix Cannot index into a null array in PowerShell

I'm trying to convert my CSV file to Excel file with some Table format and style but I'm getting "Cannot index into a null array" for some reason. I'll be really appreciated if I can get any help or suggestion. Thanks
function Convert-to-Excel{
$params = #{
AutoSize = $true
TableStyle = 'Medium6'
BoldTopRow = $true
WorksheetName = 'Audit Log'
PassThru = $true
Path = "C:\AuditLogSearch\$((Get-Date).AddDays(-7).ToString('yyyy-MM-dd')) _ $(Get-Date -Format "yyyy-MM-dd") Audit-Log-Records11.xlsx"
}
$modifiedFile = Import-Csv "C:\AuditLogSearch\Modified-Audit-Log-Records.csv"
$actionReference = Import-Csv "C:\AuditLogSearch\Reference\Action.csv"
$xlsx = foreach ($u in $modifiedFile) {
$u.User = (Get-AzureADUser -ObjectId $u.User).DisplayName
New-Object PsObject -Property #{
User = $u.User
"Search Criteria" = $u."Search Criteria"
"Result Status" = $u."Result Status"
"Date & Time" = $u."Date & Time"
"Type of Action" = if (($actionReference | where-object { $_.Name -eq $u."Type of Action" }).Value -ne $null) { ($actionReference | where-object { $_.Name -eq $u."Type of Action" }).Value }
else { $u."Type of Action" }
} | Export-Excel #params
$ws = $xlsx.Workbook.Worksheets[$params.Worksheetname]
$ws.View.ShowGridLines = $false # => This will hide the GridLines on your file
Close-ExcelPackage $xlsx
}
}
You're closing the Excel Package on the first iteration of your loop hence why when it goes to the next it's trying to do something like this:
$null[$null] # => InvalidOperation: Cannot index into a null array
Try modifying your function so it looks like this instead:
First, construct the object[]:
$result = foreach ($u in $modifiedFile) {
$u.User = (Get-AzureADUser -ObjectId $u.User).DisplayName
New-Object PsObject -Property #{
User = $u.User
"Search Criteria" = $u."Search Criteria"
"Result Status" = $u."Result Status"
"Date & Time" = $u."Date & Time"
"Type of Action" = if (($actionReference.........
else { $u."Type of Action" }
}
}
Then export it to Excel:
$xlsx = $result | Export-Excel #params
$ws = $xlsx.Workbook.Worksheets[$params.Worksheetname]
$ws.View.ShowGridLines = $false # => This will hide the GridLines on your file
Close-ExcelPackage $xlsx
One thing to note, PassThru = $true on the $params means that instead of saving the Excel directly we want to save the object on a variable for "further manipulation" and by further manipulation what I mean is, in this case, hiding the GridLines of the worksheet ($ws.View.ShowGridLines = $false) and then closing the package (store it on the disk).
If you don't require to perform any modifications over the worksheet you can just remove the PassThru altogether and do:
$result | Export-Excel #params
Which will close the package and store the Excel on your disk.

Extract sections from range found in word document

Below code works fine, we got start and end point which needs to be extracted but im not able to get range.set/select to work
I'm able to get the range from below, just need to extra and save it to CSV file...
$found = $paras2.Range.SetRange($startPosition, $endPosition) - this piece doesn't work.
$file = "D:\Files\Scan.doc"
$SearchKeyword1 = 'Keyword1'
$SearchKeyword2 = 'Keyword2'
$word = New-Object -ComObject Word.Application
$word.Visible = $false
$doc = $word.Documents.Open($file,$false,$true)
$sel = $word.Selection
$paras = $doc.Paragraphs
$paras1 = $doc.Paragraphs
$paras2 = $doc.Paragraphs
foreach ($para in $paras)
{
if ($para.Range.Text -match $SearchKeyword1)
{
Write-Host $para.Range.Text
$startPosition = $para.Range.Start
}
}
foreach ($para in $paras1)
{
if ($para.Range.Text -match $SearchKeyword2)
{
Write-Host $para.Range.Text
$endPosition = $para.Range.Start
}
}
Write-Host $startPosition
Write-Host $endPosition
$found = $paras2.Range.SetRange($startPosition, $endPosition)
# cleanup com objects
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($doc) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($word) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
This line of code is the problem
$found = $paras2.Range.SetRange($startPosition, $endPosition)
When designating a Range by the start and end position it's necessary to do so relative to the document. The code above refers to a Paragraphs collection. In addition, it uses SetRange, but should only use the Range method. So:
$found = $doc.Range.($startPosition, $endPosition)

Powershell: Property stored in a variable

I would like to find all cells in a range based on a property value using EPPlus. Let's say I need to find all cells with bold text in an existing spreadsheet. I need to create a function that will accept a configurable properties parameter but I'm having trouble using a property stored in a variable:
$cellobject = $ws.cells[1,1,10,10]
$properties = 'Style.Font.Bold'
$cellobject.$properties
$cellobject.{$properties}
$cellobject.($properties)
$cellobject."$properties"
None of these work and cause a call depth overflow.
If this way wont work, is there something in the library I can use?
Edited: To show the final solution I updated the function with concepts provided by HanShotFirst...
function Get-CellObject($ExcelSheet,[string]$PropertyString,[regex]$Value){
#First you have to get the last row with text,
#solution for that is not provided here...
$Row = Get-LastUsedRow -ExcelSheet $ExcelSheet -Dimension $true
while($Row -gt 0){
$range = $ExcelSheet.Cells[$Row, 1, $Row, $ExcelSheet.Dimension.End.Column]
foreach($cellObject in $range){
if($PropertyString -like '*.*'){
$PropertyArr = $PropertyString.Split('.')
$thisObject = $cellObject
foreach($Property in $PropertyArr){
$thisObject = $thisObject.$Property
if($thisObject -match $Value){
$cellObject
}
}
}
else{
if($cellObject.$PropertyString -match $Value){
$cellObject
}
}
}
$Row--
}
}
#The ExcelSheet parameter takes a worksheet object
Get-CellObject -ExcelSheet $ws -Property 'Style.Font.Bold' -Value 'True'
Dot walking into properties does not really work with a string. You need to separate the layers of properties. Here is an example for an object with three layers of properties.
# create object
$props = #{
first = #{
second = #{
third = 'test'
}
}
}
$obj = New-Object -TypeName psobject -Property $props
# outputs "test"
$obj.first.second.third
# does not work
$obj.'first.second.third'
# outputs "test"
$a = 'first'
$b = 'second'
$c = 'third'
$obj.$a.$b.$c
In your example this would be something like this:
$cellobject = $ws.cells[1,1,10,10]
$p1 = 'Style'
$p2 = 'Font'
$p3 = 'Bold'
$cellobject.$p1.$p2.$p3
Or you can do it a bit dynamic. This should produce the same result:
$cellobject = $ws.cells[1,1,10,10]
$props = 'Style.Font.Bold'.Split('.')
$result = $cellobject
foreach ($prop in $props) {
$result = $result.$prop
}
$result
And since its Friday, here is a function for it :)
function GetValue {
param (
[psobject]$InputObject,
[string]$PropertyString
)
if ($PropertyString -like '*.*') {
$props = $PropertyString.Split('.')
$result = $InputObject
foreach ($prop in $props) {
$result = $result.$prop
}
} else {
$result = $InputObject.$PropertyString
}
$result
}
# then call the function
GetValue -InputObject $cellobject -PropertyString 'Style.Font.Bold'

PowerShell Maintainig the order of a DataTable in PSObject

I'm trying to import an excel sheet and it works fine. However, the order of the columns is not kept. For example text that is written in the first column is being output as the second Property instead of the first.
Example input file:
ServerName | First name | Last name
C:\Drive | Bob | Johnson
The example above gives the following output as PSObject, which is incorrect as it's not in the same order as the file above is. It should start with the ServerName first, instead of:
First name : Bob
ServerName : C:\Drive
Last name : Johnson
The code:
Function Import-Excel {
[CmdletBinding()]
Param (
[String]$FileName,
[String]$WorksheetName
)
Process {
$OleDbConnection = New-Object 'System.Data.OleDb.OleDbConnection'
$OleDbCommand = New-Object 'System.Data.OleDb.OleDbCommand'
$OleDbAdapter = New-Object 'System.Data.OleDb.OleDbDataAdapter'
$DataTable = New-Object 'System.Data.DataTable'
$ConnString = 'Provider=Microsoft.ACE.OLEDB.12.0;Data Source='
$ConnString += $FileName
$ConnString += ';Extended Properties="Excel 12.0;HDR=YES;IMEX=1";'
$OleDbConnection.ConnectionString = $ConnString
$OleDbConnection.Open()
$OleDbCommand.Connection = $OleDbConnection
$OleDbCommand.CommandText = "SELECT * FROM [$WorksheetName$]"
$OleDbAdapter.SelectCommand = $OleDbCommand
$OleDbAdapter.Fill($DataTable) | Out-Null
$OleDbConnection.Close()
$columnArray = #()
foreach ($Col in $DataTable.Columns.ColumnName) {
$ColumnArray += $Col.toString()
}
$returnObject = #()
foreach ($Ro in $DataTable.Rows) {
$i=0;
$rowObject = #{}
foreach ($colu in $Ro.ItemArray) {
$rowObject += #{$columnArray[$i]=$colu.toString()}
$i++
}
$returnObject += New-Object PSObject -Property $rowObject
}
return $returnObject
}
}
I've tried so far by using an ArrayList instead. This works fine to keep the order of the input correct, but New-Object PSObject does not accept an ArrayList as input.
Thank you for your help.
Found my answer here.
It appears to be possible to have an Ordered hashtable:
$rowObject = [Ordered]#{}