XlsxCommand is a PowerShell 7 Module with the following cmdlets: (1) Export-WorksheetXlsx to create Excel Worksheet tabs and store them as files in Excel Workbook format (XLSX), and (2) Import-WorksheetXlsx to read Excel Worksheet tabs from files in Excel Workbook format (XLSX).
The cell data processing of both included cmdlets are based on a strict two-dimensional tabular data structure with rows and columns, i.e., a ‘table’. The first row is the header row. The next rows are data rows.
An Excel Worksheet tab is a two-dimensional spread array, not a strict tabular structure. Hence, the included cmdlets only work best if the cells of each Worksheet tab in an Excel Workbook are organized as a ‘table’.
Like the PowerShell Import-Csv Cmdlet, the header row determines the number of columns and the column names. The column names are also the names of the properties of the output objects added to the PowerShell Pipeline. The header row is interpreted to be the column headers, unless you use the Header parameter to specify column headers. If any row has more values than the header row, the additional values are ignored. On the other hand, if the Schema parameter is used, then the names of the properties of the output objects added to the PowerShell Pipeline are determined by the provided type.
By 'major' we mean a dependency which provides most of the functionality for a feature.
By 'external' we mean a dependency whose design evolution is self-governing and separated from XlsxCommand.
XlsxCommand
| |
| |
V V
ExcelXLSXWorksheetWriter ExcelXLSXWorksheetReader
| | |
| | |
V V V
DocumentFormat.OpenXml IllyumL2T.Core
Export-WorksheetXlsx directly depends on ExcelXLSXWorksheetWriter for individual two-dimensional tabular grid and a set of two-dimensional tabular grids abstrations.
Export-WorksheetXlsx transitively depends on DocumentFormat.OpenXml for Microsoft Office Open XML Spreadsheet document format processing.
Import-WorksheetXlsx directly depends on ExcelXLSXWorksheetReader for individual two-dimensional tabular grid, a set of two-dimensional tabular grids, and LINQ-to-XLSX abstrations.
Import-WorksheetXlsx transitively depends on IllyumL2T.Core for cell value/field parsing in LINQ-to-XLSX processing.
Import-WorksheetXlsx transitively depends on DocumentFormat.OpenXml for Microsoft Office Open XML Spreadsheet document format processing.
The XlsxCommand module has been tested (installation and included cmdlets) on the following runtime environment:
The installation process includes a location for the XlsxCommand module. Such location is determined by the Scope parameter of the Install-Module Cmdlet. The accessibility of the installed module is also determined by the value of that Scope parameter (accessible to all users of the computer or accessible only to the current user of the computer).
As the default value for the Scope parameter varies, checking the related documentation is in order: Install-Module -Scope parameter
The following command does not require administrative permissions on the local machine. The use of its default parameter values may prompt for a confirmation as stated in the related documentation: Install-Module description
Install-Module -Name XlsxCommand
The following command does not require administrative permissions on the local machine:
Install-Module -Name XlsxCommand -Force
Export-WorksheetXlsx [-DestinationExcelXLSXFilePath] <string>
[-InputObject <psobject>]
[-InputHashtable <OrderedHashtable>]
[-Group <Object[]>]
[-DataType {String | Number | Date | Time}]
[-Align {Left | Center | Right}]
[-DataTypeMap <OrderedHashtable>]
[-AlignMap <OrderedHashtable>]
[<CommonParameters>]
Import-WorksheetXlsx [-ExcelXLSXFilePath] <string>
-TabNames
[<CommonParameters>]
Import-WorksheetXlsx [-ExcelXLSXFilePath] <string>
[-TabName <string>]
[-AsRawCellData]
[-Header <string[]>]
[-First <int>]
[-Last <int>]
[-Skip <int>]
[-Schema <PSTypeName>]
[<CommonParameters>]
This example writes the values of the ID, Name, and CPU properties of the first six current processes into a new Worksheet tab and stores them as a new Excel Workbook (XLSX) file at the given path:
Import-Module XlsxCommand
Get-Process | Select-Object -First 6 `
| Select-Object Id,Name,CPU `
| Export-WorksheetXlsx $home\Documents\FirstSixProcesses.xlsx
2. Create an Excel Workbook (XLSX) of one Worksheet tab with given cell formatting by column relative position.
This example writes the same values as the example #1 and specifies the cell data type and cell horizontal alignment for the corresponding data cells by property relative position:
Import-Module XlsxCommand
Get-Process | Select-Object -First 6 `
| Select-Object Id,Name,CPU `
| Export-WorksheetXlsx $home\Documents\FirstSixProcesses.xlsx `
-DataType Number,String,Number `
-Align Center,Left,Right
3. Create an Excel Workbook (XLSX) of one Worksheet tab with given cell formatting by property name.
This example writes the same values as the example #1 and specifies the cell data type and cell horizontal alignment for the corresponding data cells by property name:
Import-Module XlsxCommand
Get-Process | Select-Object -First 6 `
| Select-Object Id,Name,CPU `
| Export-WorksheetXlsx $home\Documents\FirstSixProcesses.xlsx `
-DataTypeMap @{Id='Number'; Name='String'; CPU='Number'} `
-AlignMap @{Id='Center'; Name='Left'; CPU='Right'}
This example writes the values of the DisplayName, ServiceType, and Status properties of the current services, grouped by Status, separated in different Worksheet tabs by group, into a new Excel Workbook (XLSX) file at the given path:
Import-Module XlsxCommand
$tabs = Get-Service `
| %{ [PSCustomObject]@{Service=$_.DisplayName; Type=$_.ServiceType; Status=$_.Status} } `
| group Status
Export-WorksheetXlsx $home\Documents\ServicesByStatus.xlsx -Group $tabs
This example writes the same values and tabs as the example #3 plus the example #4, and also specifies the cell data type and cell horizontal alignment for the corresponding data cells by property name:
Import-Module XlsxCommand
$serviceByStatus = Get-Service `
| %{ [PSCustomObject]@{Service=$_.DisplayName; Type=$_.ServiceType; Status=$_.Status} } `
| group Status
$processes = Get-Process | Select-Object -First 6 | Select-Object Id,Name,CPU
$typemap = @{Id='Number'; Name='String'; CPU='Number'; Service='String'; Type='String'; Status='String'}
$alignmap = @{Id='Center'; Name='Left'; CPU='Right'; Service='Left'; Type='Center'; Status='Center'}
$processes | Export-WorksheetXlsx C:\config\Processes.xlsx `
-Group $serviceByStatus `
-DataTypeMap $typemap `
-AlignMap $alignmap
This example writes the same values and tabs as the example #5, and also specifies the cell data type and cell horizontal alignment for the data cells by .NET CLR attributes in the corresponding properties of PowerShell classes:
Import-Module XlsxCommand
class ProcessView
{
[System.ComponentModel.DataAnnotations.DataType('Number')]
[System.ComponentModel.DataAnnotations.DisplayFormat(DataFormatString = 'Center')]
$Id
[System.ComponentModel.DataAnnotations.DataType('String')]
[System.ComponentModel.DataAnnotations.DisplayFormat(DataFormatString = 'Left')]
$Name
[System.ComponentModel.DataAnnotations.DataType('Number')]
[System.ComponentModel.DataAnnotations.DisplayFormat(DataFormatString = 'Right')]
$CPU
ProcessView($process)
{
$this.Id = $process.Id
$this.Name = $process.Name
$this.CPU = $process.CPU
}
}
class ServiceView
{
[System.ComponentModel.DataAnnotations.DataType('String')]
[System.ComponentModel.DataAnnotations.DisplayFormat(DataFormatString = 'Left')]
$Service
[System.ComponentModel.DataAnnotations.DataType('String')]
[System.ComponentModel.DataAnnotations.DisplayFormat(DataFormatString = 'Center')]
$Type
[System.ComponentModel.DataAnnotations.DataType('String')]
[System.ComponentModel.DataAnnotations.DisplayFormat(DataFormatString = 'Center')]
$Status
ServiceView($service)
{
$this.Service = $service.DisplayName
$this.Type = $service.ServiceType
$this.Status = $service.Status
}
}
$serviceByStatus = Get-Service | %{ [ServiceView]::new($_) } | group Status;
$processes = Get-Process | Select-Object -First 6 | %{ [ProcessView]::new($_) }
$processes | Export-WorksheetXlsx C:\config\Processes.xlsx -Group $serviceByStatus
This example writes the values of the Name, and LastWriteTime properties of found PDF files into a new Excel Workbook (XLSX) file at the given path. The cells in the column related to the Modified class property are written as values of Excel Date data type:
Import-Module XlsxCommand
class PDF
{
[System.ComponentModel.DataAnnotations.DataType('String')]
$FileName
[System.ComponentModel.DataAnnotations.DataType('Date')]
$Modified
PDF($file)
{
$this.FileName = $file.Name
$this.Modified = $file.LastWriteTime
}
}
ls $home\Documents -Filter *.pdf `
| %{ [PDF]::new($_) } `
| Export-WorksheetXlsx $home\Downloads\pdffiles.xlsx
This example reads all Worksheet tab names found in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds an instance of System.String to the PowerShell Pipeline per tab name:
Import-Module XlsxCommand
Import-WorksheetXlsx C:\config\Processes.xlsx -TabNames
Processes
Stopped
Running
This example reads the header row and the first three data rows from the first Worksheet tab (by default if TabName parameter is not specified) in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds one instance of System.Management.Automation.PSCustomObject to the PowerShell Pipeline per data row (the values of the properties are string representations of the cells in the row):
Import-Module XlsxCommand
Import-WorksheetXlsx C:\config\Processes.xlsx -First 3
Id Name CPU
-- ---- ---
2864 Process1 79.20
8208 Process2 48.56
6864 Process3 45.62
This example reads the header row and the next three data rows from the Worksheet tab named 'Stopped' in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds one instance of System.Management.Automation.PSCustomObject to the PowerShell Pipeline per data row (the values of the properties are string representations of the cells in the row):
Import-Module XlsxCommand
Import-WorksheetXlsx C:\config\Processes.xlsx -TabName 'Stopped' -First 3
Service Type Status
------- ---- ------
Agent Activation Service Win32OwnProcess Stopped
Witness Router Service Win32ShareProcess Stopped
Tabular Writer Service Win32OwnProcess Stopped
This example reads the header row and the last three data rows from the first Worksheet tab (by default if TabName parameter is not specified) in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds one instance of System.Management.Automation.PSCustomObject to the PowerShell Pipeline per data row. The values of the properties are string representations of each cell value in the row; in this example, some of those string values are null (see values of the CPU property):
Import-Module XlsxCommand
Import-WorksheetXlsx C:\config\Processes.xlsx -Last 3
Id Name CPU
-- ---- ---
4164 Process4 0.16
4436 Process5
748 Process6
This example ignores the header row and reads the first three data rows of the first Worksheet in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds one instance of a PowerShell class (which is a .NET reference type) to the PowerShell Pipeline per data row. The values of the properties are parsed from the corresponding values of each cell in the row by position into the corresponding property type. For the case of integer representations without separation characters for thousands, the values are parsed directly (see the $ProcessID property declaration):
Import-Module XlsxCommand
class ProcessView
{
[int]$ProcessID
[string]$ProcessName
}
Import-WorksheetXlsx C:\config\Processes.xlsx -First 3 -Schema [ProcessView]
ProcessID ProcessName
--------- -----------
2864 Process1
8208 Process2
6864 Process3
This example ignores the header row and reads the last three data rows of the first Worksheet in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds one instance of a PowerShell class (which is a .NET reference type) to the PowerShell Pipeline per data row. The values of the properties are parsed from the corresponding values of each cell in the row by position into the corresponding property type. For this case of floating-point numeric (double, whose default value is zero) representations, the parsing process (see Illyum/l2t) of the property values requires a custom .NET CLR attribute as shown:
$ProcessViewSource = @'
public class ProcessView
{
public int Id { get; set; }
public string Name { get; set; }
[IllyumL2T.Core.ParseBehavior(NumberStyle = System.Globalization.NumberStyles.Number)]
public double CPU { get; set; }
}
'@
$module_path = Split-Path (Get-Module XlsxCommand | select -expand Path)
$assemblies = @(
Join-Path $module_path 'IllyumL2T.Core.dll'
Join-Path $module_path 'netstandard.dll'
)
Add-Type -TypeDefinition $ProcessViewSource -ReferencedAssemblies $assemblies
Import-WorksheetXlsx C:\config\Processes.xlsx -Last 3 -Schema [ProcessView]
Id Name CPU
-- ---- ---
4164 Process4 0.16
4436 Process5 0.00
748 Process6 0.00
This example ignores the header row and reads the last three data rows of the first Worksheet in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds one instance of a PowerShell class (which is a .NET reference type) to the PowerShell Pipeline per data row. The values of the properties are parsed from the corresponding values of each cell in the row by position into the corresponding property type. For this case of nullable floating-point numeric (System.Nullable<double>, whose default value is null) representations, the parsing process (see Illyum/l2t) of the property values requires a custom .NET CLR attribute as shown:
$ProcessViewSource = @'
public class ProcessView
{
public int Id { get; set; }
public string Name { get; set; }
[IllyumL2T.Core.ParseBehavior(NumberStyle = System.Globalization.NumberStyles.Number)]
public double? CPU { get; set; }
}
'@
$module_path = Split-Path (Get-Module XlsxCommand | select -expand Path)
$assemblies = @(
Join-Path $module_path 'IllyumL2T.Core.dll'
Join-Path $module_path 'netstandard.dll'
)
Add-Type -TypeDefinition $ProcessViewSource -ReferencedAssemblies $assemblies
Import-WorksheetXlsx C:\config\Processes.xlsx -Last 3 -Schema [ProcessView]
Id Name CPU
-- ---- ---
4164 Process4 0.16
4436 Process5
748 Process6
This example attempts to read a cell value (45.62) and to parse it as an integer for a class property ($CPU) and shows the warning message of the corresponding parse failure. For that, this example ignores the header row and reads the third data row of the first Worksheet in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds one instance of a PowerShell class (which is a .NET reference type) to the PowerShell Pipeline for such third data row.
Import-Module XlsxCommand
class ProcessView
{
[int]$Id
[string]$Name
[int]$CPU
}
Import-WorksheetXlsx C:\config\Processes.xlsx -First 1 -Skip 2 -Schema [ProcessView]
WARNING: CPU: Unparsable System.Int32 >>> 45.62
Id Name CPU
-- ---- ---
6864 Process3 0
16. Read Excel dates, represented as numeric values, in data rows as .NET DateTime property values from a Worksheet tab.
This example reads from the first Worksheet in an Excel Workbook (XLSX) file named LogFile.xlsx. Such file was created at Excel Online service with the Blank workbook template. The first Worksheet contains two columns with a header row. The second column was filled with simple date values typed as <month-number><dash><day-number>:
Without explicit data type specification:
Import-Module XlsxCommand
Import-WorksheetXlsx C:\logs\LogFile.xlsx
LogName LogDate
------- -------
NameLog1 46204
NameLog2 46209
NameLog3 46211
With explicit data type specification:
Import-Module XlsxCommand
class LogRecord
{
[string]$LogName
[DateTime]$LogDate
}
Import-WorksheetXlsx C:\logs\LogFile.xlsx -Schema [LogRecord]
LogName LogDate
------- -------
NameLog1 7/1/2026 12:00:00 AM
NameLog2 7/6/2026 12:00:00 AM
NameLog3 7/8/2026 12:00:00 AM
17. Skip parsing the marked columns and read data rows of cells as instances of a PowerShell class from an Excel Worksheet tab.
This example skips the columns corresponding to the properties marked with the .NET CLR attribute System.ComponentModel.DataAnnotations.Schema.NotMapped, ignores the header row, and reads the first three data rows of the first Worksheet in the Excel Workbook (XLSX) created in example #5, or in example #6, and adds one instance of a PowerShell class (which is a .NET reference type) to the PowerShell Pipeline per data row:
Import-Module XlsxCommand
class ProcessView
{
[System.ComponentModel.DataAnnotations.Schema.NotMapped()]$IdIgnored
[string]$Name
}
Import-WorksheetXlsx C:\config\Processes.xlsx -First 3 -Schema [ProcessView]
IdIgnored Name
--------- ----
Process1
Process2
Process3