mirror of
https://github.com/dfinke/ImportExcel.git
synced 2025-12-06 00:23:20 +00:00
Added data validation
This commit is contained in:
99
AddDataValidation.ps1
Normal file
99
AddDataValidation.ps1
Normal file
@@ -0,0 +1,99 @@
|
||||
Function Add-ExcelDataValidationRule {
|
||||
<#
|
||||
.Synopsis
|
||||
Adds data validation to a range of cells
|
||||
.Example
|
||||
>
|
||||
>Add-ExcelDataValidationRule -WorkSheet $PlanSheet -Range 'E2:E1001' -ValidationType Integer -Operator between -Value 0 -Value2 100 `
|
||||
-ShowErrorMessage -ErrorStyle stop -ErrorTitle 'Invalid Data' -ErrorBody 'Percentage must be a whole number between 0 and 100'
|
||||
|
||||
This defines a validation rule on cells E2-E1001; it is an integer rule and requires a number between 0 and 100
|
||||
If a value is input with a fraction, negative number, or positive number > 100 a stop dialog box appears.
|
||||
.Example
|
||||
>
|
||||
>Add-ExcelDataValidationRule -WorkSheet $PlanSheet -Range 'B2:B1001' -ValidationType List -Formula 'values!$a$2:$a$1000'
|
||||
-ShowErrorMessage -ErrorStyle stop -ErrorTitle 'Invalid Data' -ErrorBody 'You must select an item from the list'
|
||||
This defines a list rule on Cells B2:1001, and the posible values are in a sheet named "values" at cells A2 to A1000
|
||||
Blank cells in this range are ignored. If $ signs are left out of the fomrmula B2 would be checked against A2-A1000
|
||||
B3, against A3-A1001, B4 against A4-A1002 up to B1001 beng checked against A1001-A1999
|
||||
.Example
|
||||
>
|
||||
>Add-ExcelDataValidationRule -WorkSheet $PlanSheet -Range 'I2:N1001' -ValidationType List -ValueSet @('yes','YES','Yes')
|
||||
-ShowErrorMessage -ErrorStyle stop -ErrorTitle 'Invalid Data' -ErrorBody "Select Yes or leave blank for no"
|
||||
Similar to the previous example but this time provides a value set; Excel comparisons are case sesnsitive, hence 3 versions of Yes.
|
||||
#>
|
||||
|
||||
[CmdletBinding()]
|
||||
Param(
|
||||
#The range of cells to be validate, e.g. "B2:C100"
|
||||
[Parameter(ValueFromPipeline = $true,Position=0)]
|
||||
[Alias("Address")]
|
||||
$Range ,
|
||||
#The worksheet where the cells should be validated
|
||||
[OfficeOpenXml.ExcelWorksheet]$WorkSheet ,
|
||||
#An option corresponding to a choice from the 'Allow' pull down on the settings page in the Excel dialog. Any means "any allowed" i.e. no Validation
|
||||
[ValidateSet('Any','Custom','DateTime','Decimal','Integer','List','TextLength','Time')]
|
||||
$ValidationType,
|
||||
#The operator to apply to Decimal, Integer, TextLength, DateTime and time fields, e.g. equal, between
|
||||
[OfficeOpenXml.DataValidation.ExcelDataValidationOperator]$Operator = [OfficeOpenXml.DataValidation.ExcelDataValidationOperator]::equal ,
|
||||
#For Decimal, Integer, TextLength, DateTime the [first] data value
|
||||
$Value,
|
||||
#When using the between operator, the second data value
|
||||
$Value2,
|
||||
#The [first] data value as a formula. Use absolute formulas $A$1 if (e.g.) you want all cells to check against the same list
|
||||
$Formula,
|
||||
#When using the between operator, the second data value as a formula
|
||||
$Formula2,
|
||||
#When using the list validation type, a set of values (rather than refering to Sheet!B$2:B$100 )
|
||||
$ValueSet,
|
||||
#Corresponds to the the 'Show Error alert ...' check box on error alert page in the Excel dialog
|
||||
[switch]$ShowErrorMessage,
|
||||
#Stop, Warning, or Infomation, corresponding to to the style setting in the Excel dialog
|
||||
[OfficeOpenXml.DataValidation.ExcelDataValidationWarningStyle]$ErrorStyle,
|
||||
#The title for the message box corresponding to to the title setting in the Excel dialog
|
||||
[String]$ErrorTitle,
|
||||
#The error message corresponding to to the Error message setting in the Excel dialog
|
||||
[String]$ErrorBody,
|
||||
#Corresponds to the the 'Show Input message ...' check box on input message page in the Excel dialog
|
||||
[switch]$ShowPromptMessage,
|
||||
#The prompt message corresponding to to the Input message setting in the Excel dialog
|
||||
[String]$PromptBody,
|
||||
#The title for the message box corresponding to to the title setting in the Excel dialog
|
||||
[String]$PromptTitle,
|
||||
#By default the 'Ignore blank' option will be selected, unless NoBlank is sepcified.
|
||||
[String]$NoBlank
|
||||
)
|
||||
if ($Range -is [Array]) {
|
||||
[void]$PSBoundParameters.Remove("Range")
|
||||
$Range | Add-ExcelDataValidationRule @PSBoundParameters
|
||||
}
|
||||
else {
|
||||
#We should accept, a worksheet and a name of a range or a cell address; a table; the address of a table; a named range; a row, a column or .Cells[ ]
|
||||
if (-not $WorkSheet -and $Range.worksheet) {$WorkSheet = $Range.worksheet}
|
||||
if ($Range.Address) {$Range = $Range.Address}
|
||||
|
||||
if ($Range -isnot [string] -or -not $WorkSheet) {Write-Warning -Message "You need to provide a worksheet and range of cells." ;return}
|
||||
#else we assume Range is a range.
|
||||
|
||||
$validation = $WorkSheet.DataValidations."Add$ValidationType`Validation"($Range)
|
||||
if ($validation.AllowsOperator) {$validation.Operator = $Operator}
|
||||
if ($PSBoundParameters.ContainsKey('value')) {
|
||||
$validation.Formula.Value = $Value
|
||||
}
|
||||
elseif ($Formula) {$validation.Formula.ExcelFormula = $Formula}
|
||||
elseif ($ValueSet) {Foreach ($v in $ValueSet) {$validation.Formula.Values.Add($V)}}
|
||||
if ($PSBoundParameters.ContainsKey('Value2')) {
|
||||
$validation.Formula2.Value = $Value2
|
||||
}
|
||||
elseif ($Formula2) {$validation.Formula2.ExcelFormula = $Formula}
|
||||
$validation.ShowErrorMessage = [bool]$ShowErrorMessage
|
||||
$validation.ShowInputMessage = [bool]$ShowPromptMessage
|
||||
$validation.AllowBlank = -not $NoBlank
|
||||
|
||||
if ($PromptTitle) {$validation.PromptTitle = $PromptTitle}
|
||||
if ($ErrorTitle) {$validation.ErrorTitle = $ErrorTitle}
|
||||
if ($PromptBody) {$validation.Prompt = $PromptBody}
|
||||
if ($ErrorBody) {$validation.Error = $ErrorBody}
|
||||
if ($ErrorStyle) {$validation.ErrorStyle = $ErrorStyle}
|
||||
}
|
||||
}
|
||||
@@ -926,7 +926,8 @@
|
||||
}
|
||||
if ($AutoSize) {
|
||||
try {
|
||||
$ws.Cells.AutoFitColumns()
|
||||
#Don't fit the all the columns in the sheet; if we are adding cells beside things with hidden columns, that unhides them
|
||||
$ws.Cells[($startAddress+':'+$endAddress)].AutoFitColumns()
|
||||
Write-Verbose -Message "Auto-sized columns"
|
||||
}
|
||||
catch { Write-Warning -Message "Failed autosizing columns of worksheet '$WorksheetName': $_"}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#region import everything we need
|
||||
Add-Type -Path "$($PSScriptRoot)\EPPlus.dll"
|
||||
. $PSScriptRoot\AddConditionalFormatting.ps1
|
||||
. $PSScriptRoot\AddDataValidation.ps1
|
||||
. $PSScriptRoot\Charting.ps1
|
||||
. $PSScriptRoot\ColorCompletion.ps1
|
||||
. $PSScriptRoot\ConvertExcelToImageFile.ps1
|
||||
@@ -34,6 +35,7 @@ Add-Type -Path "$($PSScriptRoot)\EPPlus.dll"
|
||||
. $PSScriptRoot\Set-CellStyle.ps1
|
||||
. $PSScriptRoot\Set-Column.ps1
|
||||
. $PSScriptRoot\Set-Row.ps1
|
||||
. $PSScriptRoot\Set-WorkSheetProtection
|
||||
. $PSScriptRoot\SetFormat.ps1
|
||||
. $PSScriptRoot\TrackingUtils.ps1
|
||||
. $PSScriptRoot\Update-FirstObjectProperties.ps1
|
||||
|
||||
@@ -52,6 +52,11 @@ Install-Module ImportExcel -scope CurrentUser
|
||||
```PowerShell
|
||||
Install-Module ImportExcel
|
||||
```
|
||||
# What's new
|
||||
- Changed the behavior of AutoSize in export excel so it only applies to the exported columns. Previously if something was exported next to pre-existing data, AutoSize would resize the whole sheet, potentially undoing things which had been set on the earlier data. If anyone relied on this behavior they will need to explictly tell the sheet to auto size with $sheet.cells.autofitColumns. (where $sheet points to the sheet, it might be $ExcelPackage.Workbook.Worksheets['Name'])
|
||||
- In Compare-Worksheet,the Key for comparing the sheets can now be written as a hash table with an expression - it is used with a Group-Object command so if it is valid in Group-Object it should be accepted; this allows the creation of composite keys when data being compared doesn't have a column which uniquely identifies rows.
|
||||
- In Set-ExcelRange , added a 'Locked' option eqivalent to the checkbox on the Protection Tab of the format cells dialog box in Excel.
|
||||
- Created a Set-WorksheetProtection function. This gives the same options the protection dialog in Excel but is 0.9 release at the moment.
|
||||
|
||||
# What's new 5.4.2
|
||||
|
||||
|
||||
80
Set-WorkSheetProtection.ps1
Normal file
80
Set-WorkSheetProtection.ps1
Normal file
@@ -0,0 +1,80 @@
|
||||
Function Set-WorkSheetProtection {
|
||||
[Cmdletbinding()]
|
||||
<#
|
||||
.Synopsis
|
||||
Sets protection on the worksheet
|
||||
.Description
|
||||
|
||||
.Example
|
||||
Set-WorkSheetProtection -WorkSheet $planSheet -IsProtected -AllowAll -AllowInsertColumns:$false -AllowDeleteColumns:$false -UnLockAddress "A:N"
|
||||
Turns on protection for the worksheet in $planSheet, checks all the allow boxes excel Insert and Delete columns and unlocks columns A-N
|
||||
#>
|
||||
param (
|
||||
#The worksheet where protection is to be applied.
|
||||
[Parameter(Mandatory=$true)]
|
||||
[OfficeOpenXml.ExcelWorksheet]$WorkSheet ,
|
||||
#Value of the "Protect Worksheet and Contents of locked cells" check box. Initially FALSE. use -IsProtected:$false to turn off it it has been switched on
|
||||
[switch]$IsProtected,
|
||||
#If provided sets all the ALLOW options to true or false and then allows them to be changed individually
|
||||
[switch]$AllowAll,
|
||||
#Opposite of the value in the 'Select locked cells' check box. Set to allow when Protect is first enabled
|
||||
[switch]$BlockSelectLockedCells,
|
||||
#Opposite of the value in the 'Select unlocked cells' check box. Set to allow when Protect is first enabled
|
||||
[switch]$BlockSelectUnlockedCells,
|
||||
#Value of the 'Format Cells' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowFormatCells,
|
||||
#Value of the 'Format Columns' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowFormatColumns,
|
||||
#Value of the 'Format Rows' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowFormatRows,
|
||||
#Value of the 'Insert Columns' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowInsertColumns,
|
||||
#Value of the 'Insert Columns' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowInsertRows,
|
||||
#Value of the 'Insert Hyperlinks' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowInsertHyperlinks,
|
||||
#Value of the 'Delete Columns' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowDeleteColumns,
|
||||
#Value of the 'Delete Rows' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowDeleteRows,
|
||||
#Value of the 'Sort' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowSort,
|
||||
#Value of the 'Use AutoFilter' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowAutoFilter,
|
||||
#Value of the 'Use PivotTable and PivotChart' check box. Set to block when Protect is first enabled
|
||||
[switch]$AllowPivotTables,
|
||||
##Opposite of the value in the 'Edit objects' check box. Set to allow when Protect is first enabled
|
||||
[switch]$BlockEditObject,
|
||||
##Opposite of the value in the 'Edit Scenarios' check box. Set to allow when Protect is first enabled
|
||||
[switch]$BlockEditScenarios,
|
||||
#Address range for cells to lock in the form "A:Z" or "1:10" or "A1:Z10"
|
||||
[string]$LockAddress,
|
||||
#Address range for cells to Unlock in the form "A:Z" or "1:10" or "A1:Z10"
|
||||
[string]$UnLockAddress
|
||||
)
|
||||
|
||||
if ($PSBoundParameters.ContainsKey('isprotected') -and $IsProtected -eq $false) {$worksheet.Protection.IsProtected = $false}
|
||||
elseif ($IsProtected) {
|
||||
$worksheet.Protection.IsProtected = $true
|
||||
foreach ($ParName in @('AllowFormatCells',
|
||||
'AllowFormatColumns', 'AllowFormatRows',
|
||||
'AllowInsertColumns', 'AllowInsertRows', 'AllowInsertHyperlinks',
|
||||
'AllowDeleteColumns', 'AllowDeleteRows',
|
||||
'AllowSort' , 'AllowAutoFilter', 'AllowPivotTables')) {
|
||||
if ($AllowAll -and -not $PSBoundParameters.ContainsKey($Parname)) {$worksheet.Protection.$ParName = $true}
|
||||
elseif ($PSBoundParameters[$ParName] -eq $true ) {$worksheet.Protection.$ParName = $true}
|
||||
}
|
||||
if ($BlockSelectLockedCells) {$worksheet.Protection.AllowSelectLockedCells = $false }
|
||||
if ($BlockSelectUnlockedCells) {$worksheet.Protection.AllowSelectUnLockedCells = $false }
|
||||
if ($BlockEditObject) {$worksheet.Protection.AllowEditObject = $false }
|
||||
if ($BlockEditScenarios) {$worksheet.Protection.AllowEditScenarios = $false }
|
||||
}
|
||||
Else {Write-Warning -Message "You haven't said if you want to turn protection off, or on." }
|
||||
|
||||
if ($UnlockAddress) {
|
||||
Set-ExcelRange -Range $WorkSheet.cells[$UnlockAddress] -Locked:$false
|
||||
}
|
||||
if ($lockAddress) {
|
||||
Set-ExcelRange -Range $WorkSheet.cells[$UnlockAddress] -Locked
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,9 @@
|
||||
#Set cells to a fixed height (rows or ranges only).
|
||||
[float]$Height,
|
||||
#Hide a row or column (not a range); use -Hidden:$false to unhide.
|
||||
[Switch]$Hidden
|
||||
[Switch]$Hidden,
|
||||
#Locks cells. Cells are locked by default use -locked:$false on the whole sheet and then lock specific ones, and enable protection on the sheet.
|
||||
[Switch]$Locked
|
||||
)
|
||||
process {
|
||||
if ($Range -is [Array]) {
|
||||
@@ -117,8 +119,8 @@
|
||||
elseif ($WorkSheet -and ($Range -is [string] -or $Range -is [OfficeOpenXml.ExcelAddress])) {
|
||||
$Range = $WorkSheet.Cells[$Range]
|
||||
}
|
||||
elseif ($Range -is [string]) {Write-Warning -Message "The range pararameter you have specified also needs a worksheet parameter."}
|
||||
|
||||
elseif ($Range -is [string]) {Write-Warning -Message "The range pararameter you have specified also needs a worksheet parameter." ;return}
|
||||
#else we assume Range is a range.
|
||||
if ($ResetFont) {
|
||||
$Range.Style.Font.Color.SetColor( ([System.Drawing.Color]::Black))
|
||||
$Range.Style.Font.Bold = $false
|
||||
@@ -241,6 +243,9 @@
|
||||
$Range -is [OfficeOpenXml.ExcelColumn] ) {$Range.Hidden = [boolean]$Hidden}
|
||||
else {Write-Warning -Message ("Can hide a row or a column but not a {0} object" -f ($Range.GetType().name)) }
|
||||
}
|
||||
if ($PSBoundParameters.ContainsKey('Locked')) {
|
||||
$Range.Style.Locked=$Locked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ Describe "Number format expansion and setting" {
|
||||
Remove-Item -Path $path -ErrorAction SilentlyContinue
|
||||
$n = [datetime]::Now.ToOADate()
|
||||
|
||||
$excel = 1..32 | ForEach-Object {$n} | Export-Excel -Path $path -show -WorksheetName s2 -PassThru
|
||||
$excel = 1..32 | ForEach-Object {$n} | Export-Excel -Path $path -WorksheetName s2 -PassThru
|
||||
$ws = $excel.Workbook.Worksheets[1]
|
||||
Set-ExcelRange -WorkSheet $ws -Range "A1" -numberFormat 'General'
|
||||
Set-ExcelRange -WorkSheet $ws -Range "A2" -numberFormat 'Number'
|
||||
|
||||
60
__tests__/Validation.tests.ps1
Normal file
60
__tests__/Validation.tests.ps1
Normal file
@@ -0,0 +1,60 @@
|
||||
$data = ConvertFrom-Csv -InputObject @"
|
||||
ID,Product,Quantity,Price
|
||||
12001,Nails,37,3.99
|
||||
12002,Hammer,5,12.10
|
||||
12003,Saw,12,15.37
|
||||
12010,Drill,20,8
|
||||
12011,Crowbar,7,23.48
|
||||
"@
|
||||
|
||||
$path = "$Env:TEMP\DataValidation.xlsx"
|
||||
|
||||
Describe "Data validation and protection" {
|
||||
Context "Data Validation rules" {
|
||||
BeforeAll {
|
||||
Remove-Item $path -ErrorAction SilentlyContinue
|
||||
$excelPackage = $Data | export-excel -WorksheetName "Sales" -path $path -PassThru
|
||||
$excelPackage = @('Chisel','Crowbar','Drill','Hammer','Nails','Saw','Screwdriver','Wrench') |
|
||||
Export-excel -ExcelPackage $excelPackage -WorksheetName Values -PassThru
|
||||
|
||||
$VParams = @{WorkSheet = $excelPackage.sales; ShowErrorMessage=$true; ErrorStyle='stop'; ErrorTitle='Invalid Data' }
|
||||
Add-ExcelDataValidationRule @VParams -Range 'B2:B1001' -ValidationType List -Formula 'values!$a$1:$a$10' -ErrorBody "You must select an item from the list.`r`nYou can add to the list on the values page" #Bucket
|
||||
Add-ExcelDataValidationRule @VParams -Range 'E2:E1001' -ValidationType Integer -Operator between -Value 0 -Value2 10000 -ErrorBody 'Quantity must be a whole number between 0 and 10000'
|
||||
Close-ExcelPackage -ExcelPackage $excelPackage
|
||||
|
||||
$excelPackage = Open-ExcelPackage -Path $path
|
||||
$ws = $excelPackage.Sales
|
||||
}
|
||||
It "Created the expected number of rules " {
|
||||
$ws.DataValidations.count | Should be 2
|
||||
}
|
||||
It "Created a List validation rule against a range of Cells " {
|
||||
$ws.DataValidations[0].ValidationType.Type.tostring() | Should be 'List'
|
||||
$ws.DataValidations[0].Formula.ExcelFormula | Should be 'values!$a$1:$a$10'
|
||||
$ws.DataValidations[0].Formula2 | Should benullorempty
|
||||
$ws.DataValidations[0].Operator.tostring() | should be 'any'
|
||||
}
|
||||
It "Created an integer validation rule for values between X and Y " {
|
||||
$ws.DataValidations[1].ValidationType.Type.tostring() | Should be 'Whole'
|
||||
$ws.DataValidations[1].Formula.Value | Should be 0
|
||||
$ws.DataValidations[1].Formula2.value | Should not benullorempty
|
||||
$ws.DataValidations[1].Operator.tostring() | should be 'between'
|
||||
}
|
||||
It "Set Error behaviors for both rules " {
|
||||
$ws.DataValidations[0].ErrorStyle.tostring() | Should be 'stop'
|
||||
$ws.DataValidations[1].ErrorStyle.tostring() | Should be 'stop'
|
||||
$ws.DataValidations[0].AllowBlank | Should be $true
|
||||
$ws.DataValidations[1].AllowBlank | Should be $true
|
||||
$ws.DataValidations[0].ShowErrorMessage | Should be $true
|
||||
$ws.DataValidations[1].ShowErrorMessage | Should be $true
|
||||
$ws.DataValidations[0].ErrorTitle | Should not benullorempty
|
||||
$ws.DataValidations[1].ErrorTitle | Should not benullorempty
|
||||
$ws.DataValidations[0].Error | Should not benullorempty
|
||||
$ws.DataValidations[1].Error | Should not benullorempty
|
||||
}
|
||||
}
|
||||
AfterAll {
|
||||
Close-ExcelPackage -NoSave $excelPackage
|
||||
}
|
||||
|
||||
}
|
||||
@@ -191,7 +191,7 @@
|
||||
}
|
||||
}
|
||||
#if font color was specified, set it on changed properties where the same key appears in both sheets.
|
||||
if ($diff -and $FontColor -and ($propList -contains $Key) ) {
|
||||
if ($diff -and $FontColor -and (($propList -contains $Key) -or ($key -is [hashtable])) ) {
|
||||
$updates = $diff.where({$_.SideIndicator -ne "=="}) | Group-object -Property $Key | Where-Object {$_.count -eq 2}
|
||||
if ($updates) {
|
||||
$XL1 = Open-ExcelPackage -path $Referencefile
|
||||
|
||||
Reference in New Issue
Block a user