diff --git a/James ONeill/Excel/Excel-Talk.ipynb b/James ONeill/Excel/Excel-Talk.ipynb new file mode 100644 index 0000000..d2844bd --- /dev/null +++ b/James ONeill/Excel/Excel-Talk.ipynb @@ -0,0 +1,1007 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notebook info" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "#!about" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "cd $env:temp\n", + "del $env:temp\\*.xlsx\n", + "$PSVersionTable |out-string" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simple exports \n", + "First examples use `Get-NetAdapter` - not available in all versions of PowerShell, but you can use something else " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**1** Simplest export - picks some defaults, picks a random file name, opens Excel." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "Get-NetAdapter\n", + "Get-NetAdapter | Export-Excel" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**2** Specify the file name, and just export some data - **separate operation to open Excel no defaults**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "Get-NetAdapter | Sort-Object MacAddress |\n", + " Select-Object Name, MacAddress, Status, LinkSpeed, MediaType |\n", + " Export-excel -path Net1.xlsx" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "start .\\Net1.xlsx" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**3** Make it look a bit nicer don't treat 802.3 as a number and auto-open Excel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "Get-NetAdapter | Sort-Object MacAddress |\n", + " Select-Object Name, MacAddress, Status, LinkSpeed, MediaType |\n", + " Export-excel -path Net2.xlsx `\n", + " -NoNumberConversion MediaType `\n", + " -AutoSize `\n", + " -AutoFilter `\n", + " -BoldTopRow `\n", + " -FreezeTopRow `\n", + " -Show \n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**4** Conditional formatting.\n", + "\n", + "When the file is opened you can click the filter option and filter by color\n", + "\n", + "There are multiple ways to do Conditional formatting. This is creates \"IF Text Contains \"UP\" Green foreground\" as a rule (with no area limit) and applies it in the export step. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$cf = New-ConditionalText -Text \"up\" -ConditionalTextColor Green -BackgroundColor White -PatternType None\n", + "Get-NetAdapter | Sort-Object MacAddress |\n", + " Select-Object MacAddress, Status, LinkSpeed, MediaType |\n", + " Export-excel -path Net3.xlsx `\n", + " -Show `\n", + " -AutoSize `\n", + " -AutoFilter `\n", + " -BoldTopRow `\n", + " -FreezeTopRow `\n", + " -ConditionalFormat $cf\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Simpler lists and not starting at A1, and headerless data " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**1** Just send strings - \n", + "Lorem-ipsum is dull - I like http://www.cupcakeipsum.com `CupCake-ipsum.txt` is in the download set, just change the path below\n", + "\n", + "If we specify a *start column* we can add data in the blank space on the right\n", + "\n", + "**This will insert 20 columns - one by one**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "del cupcake*.xlsx -ea SilentlyContinue\n", + "$cupcake = Get-Content \"C:\\Users\\mcp\\Documents\\WindowsPowerShell\\cupcake-ipsum.txt\" -Encoding UTF8\n", + "$cupcake.count\n", + "$col = 1 ;\n", + "foreach ($c in $cupcake) {\n", + " $c -split \"\\s+\" | Export-Excel -Path cupcake1.xlsx -StartColumn $col\n", + " $col++\n", + "}\n", + "\n", + " start cupcake1.xlsx\n", + " \n", + " ### Make Changes and save as cupcake2 - we'll come back to that." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**DID YOU MAKE AND SAVE CHANGES ?**\n", + "\n", + "**2** Quick Demo of appending rows.\n", + "\n", + "**This will take our 20 columns and append them one after the other **" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$cupcake[0] -split \"\\s+\" | Export-Excel -path cupcakelong.xlsx -ClearSheet\n", + " foreach ($c in $cupcake) {$c -split \"\\s+\" | Export-Excel -Path cupcakelong.xlsx -Append }\n", + "\n", + " start cupcakelong.xlsx" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**3** Taking control of the leaders and/or start / end rows\n", + "\n", + "**This data doesn't have a header row so a normal import won't work correctly**" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "Import-Excel -path cupcakelong.xlsx | select -First 3 | ft \n", + "\n", + "\n", + "## ERROR EXPECTED !! \n", + "Import-Excel .\\cupcake1.xlsx " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can specify a header row, No headers - which will give properties P1,P2,P3 or we can name the properties" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "Import-Excel -HeaderName \"String\" cupcakelong.xlsx -EndRow 4 | ft \n", + "Import-Excel -NoHeader cupcake1.xlsx -EndRow 4 | ft" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sending more data - tweaking conditional formats" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We want to get some data for the next part - use get-sql and query the database of F1 results.\n", + "You can get the database from https://1drv.ms/f/s!AhfYu7-CJv4egbt5FD7Cdxi8jSz3aQ and `installModule GetSQL` but it needs the office ODBC drivers\n", + "\n", + "`Get-Sql -excel -connection \"xlfile\" ` sets up a SQL connection to an excel file (-Access makes it an access file, -MSSQLServer makes it a sql box, and anything else is an ODBC string)\n", + "\n", + "`-Session xxx` allows multiple connections to be opened at once and defines `xxx` as an alias `for Get-SQL <>` \n", + "\n", + "Main reason for using `Get-Sql` is we can build up the table as below. RacePos (position) is a string (includes DNF, retired etc.) \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "Get-SQL -Excel -Connection C:\\Users\\mcp\\onedrive\\public\\f1\\f1Results.xlsx -Session f1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**We are doing per row imports there is a faster way to *do* data ** \n", + "\n", + "`-AutoNameRange` means we can then refer to `cells[\"Wins\"]`\n", + "\n", + "This time we will *re-open the file* and apply conditional formatting to the *Wins* column " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "del .\\f1winners.xlsx -ea SilentlyContinue\n", + "\n", + "f1 -Table \"Results\" -GroupBy \"DriverName\" -Select \"DriverName\",\"Count (RaceDate) as wins\" -Where \"RacePos\" -eq \"'1'\" -Verbose |\n", + " Select-Object -Property drivername,wins | \n", + " Where-Object -Property wins -ge 5 | \n", + " Sort-Object wins -Descending | \n", + " Export-Excel -path f1winners.xlsx -AutoNameRange -AutoSize\n", + "\n", + "#re-open excel - we could use -passthru instead. \n", + "\n", + "$excel = Open-ExcelPackage -Path .\\f1winners.xlsx\n", + "Add-ConditionalFormatting -Address $excel.Sheet1.Cells[\"Wins\"] -ThreeIconsSet Flags\n", + "Close-ExcelPackage -Show -ExcelPackage $excel" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That mapping of values to flags isn't v. good - very few are > 2/3 maximum value or even > 1/3 ... \n", + "\n", + "So lets take control of which values get which flags - this time we will use `-passthru` to avoid re-opening \n", + "```\n", + " $excel = get | select | sort | Export-Excel -PassThru -Path abc.XLSX \n", + " manipulate $excel\n", + "either Export-Excel -Package $excel \n", + "OR Close-ExcelPackage $excel\n", + "```\n", + "\n", + "`Close-Excel` supports `-Show` and saves by default: `-NoSave` releases file without updating - worth remembering if you open for read only." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "del .\\f1winners.xlsx\n", + "\n", + "$excel = f1 -Table \"Results\" -GroupBy \"DriverName\" -Select \"DriverName\",\"Count (RaceDate) as Wins\" -Where \"RacePos\" -eq \"'1'\" |\n", + " Select-Object -Property Drivername,Wins | \n", + " Where-Object -Property Wins -ge 5 |\n", + " Sort-Object -Property Wins -Descending |\n", + " Export-Excel -path f1winners.xlsx -AutoNameRange -AutoSize -PassThru\n", + "\n", + "$cf = Add-ConditionalFormatting -Address $excel.Sheet1.Cells[\"Wins\"] -ThreeIconsSet Flags -PassThru\n", + "\n", + "#Examine the icons on the conditional formatting we have set \n", + "\n", + "$cf | Out-String\n", + "$cf.Icon2 | gm | Out-String\n", + "\n", + "[System.Enum]::GetNames([OfficeOpenXml.ConditionalFormatting.eExcelConditionalFormattingValueObjectType]) | Out-String\n", + "\n", + "#OK ... lets make those percentiles so we get even thirds\n", + "$cf.icon2.type=\"Percentile\"\n", + "$cf.icon3.type=\"Percentile\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "Close-ExcelPackage -Show -ExcelPackage $excel\n", + "\n", + "#Leave things tidy\n", + "f1 -Close" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bigger datasets `Send-SQLDataToExcel`, neater command lines, formulas (named ranges)\n", + "A different (and bigger) database - My pictures from Adobe Lightroom\n", + "*For the download* I've provided `pictureinfo.csv` just do `$pictureInfo = import-csv pictureinfo.csv`\n", + "\n", + "First pass is just to see what the data looks like " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$SQL =@\"\n", + "SELECT rootfile.baseName || '.' || rootfile.extension AS fileName,\n", + " metadata.dateDay , metadata.dateMonth, metadata.dateYear,\n", + " image.fileFormat ,\n", + " Image.captureTime AS dateTaken ,\n", + " metadata.hasGPS ,\n", + " metadata.FocalLength AS FocalLength,\n", + " metadata.Aperture AS apertureValue,\n", + " metadata.ISOSpeedRating AS ISOSpeed,\n", + " metadata.ShutterSpeed AS shutterSpeedValue,\n", + " Camera.Value AS cameraModel,\n", + " LensRef.value AS lensModel\n", + "FROM Adobe_images image\n", + "JOIN AgLibraryFile rootFile ON rootfile.id_local = image.rootFile\n", + "JOIN AgharvestedExifMetadata metadata ON image.id_local = metadata.image\n", + "LEFT JOIN AgInternedExifLens LensRef ON LensRef.id_Local = metadata.lensRef\n", + "LEFT JOIN AgInternedExifCameraModel Camera ON Camera.id_local = metadata.cameraModelRef\n", + "WHERE Camera.Value like \"Pentax%\"\n", + "ORDER BY fileName\n", + "\"@\n", + "\n", + "#Just use the default session this time\n", + "Get-SQL -Connection \"DSN=LR\"\n", + "#PowerShell has an implied alias xxx for get-xxx so SQL = Get-SQL ; get-sql takes -SQL parameter and we've put the query in $sql so I run \"sequel sequel sequel\" \n", + "$pictureInfo = SQL -SQL $sql\n", + "Get-SQL -Close\n", + "\n", + "Export-Excel -InputObject $pictureInfo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First revision - exclude some row properties add a Pivot table and chart" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$pictureinfo | Select-Object -Property *,@{n=\"taken\";e={[datetime]$_.datetaken}} |\n", + " Export-Excel -ExcludeProperty datetaken,RowError,RowState,Table,ItemArray,HasErrors `\n", + " -IncludePivotTable `\n", + " -PivotRows cameraModel `\n", + " -PivotColumns lensmodel `\n", + " -PivotData @{'Taken'='Count'} `\n", + " -IncludePivotChart `\n", + " -ChartType ColumnStacked" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "But the command line is getting unwieldy so use *definitions* like we did for Conditional formatting - they have more options too. \n", + "For a better demo we'll use `Send-SqlDataToExcel` which bolts `Get-SQL` logic onto `Export-Excel` using \"Load the whole table in one\" instead of pipe row by row. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$cDef = New-ExcelChartDefinition -Title \"Lens and Camera Usage\" `\n", + " -ChartType ColumnStacked `\n", + " -Row 17 -Column 0 `\n", + " -Width 375 -height 500\n", + " \n", + "$pdef = New-PivotTableDefinition -PivotTableName PicturePivot `\n", + " -PivotRows cameraModel `\n", + " -PivotColumns Lensmodel `\n", + " -PivotData @{'dateTaken'='Count'} `\n", + " -PivotChartDefinition $cDef `\n", + " -Activate\n", + "\n", + "$cdef | out-string\n", + "$pdef | out-string\n", + "$pdef.PicturePivot | out-string\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`Export-Excel` will take a data table (which is faster than cell by cell). `Send-SqlDataToExcel` wraps getting the table and sending it and takes all the parameters export Excel takes. \n", + "\n", + "If you have downloaded the csv use the following although it is slower\n", + "```\n", + "$excel = $pictureinfo | \n", + " Select-Object -Property *,@{n=\"taken\";e={[datetime]$_.datetaken}} -first 1000 |\n", + " Export-Excel -ExcludeProperty datetaken,RowError,RowState,Table,ItemArray,\n", + " HasErrors -path picturedemo.xlsx -PivotTableDefinition $pdef -AutoNameRange -PassThru\n", + "$sheet = $excel.Sheet1\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "del picturedemo.xlsx -ea SilentlyContinue\n", + "$excel = Send-SQLDataToExcel -Connection \"DSN=LR\" -SQL $SQL `\n", + " -path picturedemo.xlsx `\n", + " -PivotTableDefinition $pdef `\n", + " -AutoNameRange `\n", + " -PassThru\n", + "$sheet = $excel.Sheet1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "We can access the sheet by name ... and access its cells or ranges of cells in multiple ways" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "\"Sheet dimension is $($sheet.Dimension.Start.Address):$($sheet.Dimension.End.Address) \"\n", + "\"Row 2 col 1 has value $($sheet.cells[2,1].value)\"\n", + "\"Range apertureValue is $($sheet.cells[\"apertureValue\"].Address)\"\n", + "# Can select with cells[\"B:B\"] cells[\"2:2\"] cells[\"a1:b2\"]\n", + "\n", + "\"Things we can set on cells / ranges\"\n", + "$sheet.cells[\"A1\"] |Out-String \n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instead of working on $sheet.cells[] we can use `Set-ExcelRange` \n", + "`Set-ExcelColumn` selects a column as a range and calls `Set-ExcelRange` to apply values, number formats, width. etc. If NO column is selected it will add a new column on the right. \n", + "\n", + "If we want to find a column we can use range names or something like this\n", + "```PowerShell\n", + " $col = 1 \n", + " while ($col -lt $sheet.Dimension.Columns -and $sheet.cells[1,$col].Value -ne \"apertureValue\") {$col++}\n", + " Set-ExcelColumn -Worksheet $sheet -Column $col -NumberFormat \"0.00\"\n", + "```\n", + "But we often need to change more than 1 column - so the version in the next cell is better.\n", + "\n", + "**The next cell also adds columns containing an Excel formula..**. using auto created ranges in the formula (the data had \"apertureValue\" and \"shutterSpeedValue\" as columns, they are now ranges) \n", + "Then \n", + "- Auto fit everything\n", + "- Present it as a table, \"Light1\" style \n", + "- Add save. We could do that with Close-ExcelPackage... but didn't fix the top row do that now -it's an option in Export-Excel so use that and close and show the file in one line\n", + "\n", + "\n", + "```\n", + "$excel = Send-SQLDataToExcel -PassThru\n", + "$sheet = $excel.Sheet1\n", + "Set-ExcelColumn -Worksheet $sheet ... # three times\n", + "Add-ExcelTable -Range $sheet.cells[$($sheet.Dimension.address)] ... \n", + "Export-Excel -ExcelPackage $excel ...\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "1..$sheet.Dimension.Columns | \n", + " Where-Object {$sheet.cells[1,$_].value -in @(\"apertureValue\",\"shutterSpeedValue\") } |\n", + " Set-ExcelColumn -Worksheet $sheet -NumberFormat \"0.00\"\n", + " \n", + "Set-ExcelColumn -Worksheet $sheet `\n", + " -Heading \"f. stop\" `\n", + " -Value \"=SQRT(POWER(2,apertureValue))\" `\n", + " -NumberFormat '\"f/\"0.0'\n", + "\n", + "Set-ExcelColumn -Worksheet $sheet `\n", + " -Heading \"Exposure time\" `\n", + " -Value '=IF(shutterSpeedValue<-1.5, ROUND(1/POWER(2,shutterSpeedValue),0), IF(shutterSpeedValue<2, 1/POWER(2,shutterSpeedValue),\"1/\"&TEXT(POWER(2,shutterSpeedValue),\"0\" )))' \n", + " \n", + "#this tries to render the cells, which is slow and WINDOWS ONLY\n", + "$sheet.Cells[$sheet.Dimension.Address].AutoFitColumns() \n", + "\n", + "Add-ExcelTable -Range $sheet.cells[$($sheet.Dimension.address)] -TableStyle Light1 -TableName \"Pictures\"\n", + "\n", + "Export-Excel -ExcelPackage $excel -WorksheetName sheet1 -FreezeTopRow -Show\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## More on Formulas \n", + "\n", + "`-AutoNameRange` with the picture data made each column a named range - apertureValue, cameraModel,dateDay ... ShutterSpeed\n", + "\n", + "If we give the module the value ` \"=SQRT(POWER(2,apertureValue))\" ` it puts the formula in the cell (if you change cell values REMOVE THE = SIGN !)\n", + "\n", + "Excel transforms it to `=SQRT(POWER(2,@apertureValue))` with an @ sign which means the apertureValue column at this row. So we don't need to use H2,H3,H4\n", + "\n", + "When we export data objects we can make properties hold formulas " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$data = ConvertFrom-Csv @\"\n", + "Day,Location,Cucumber,Tomato,Lettuce,Asparagus,Potato\n", + "Monday,London,46,35,41,49,30\n", + "Tuesday,London,30,26,36,38,27\n", + "Wednesday,London,25,26,27,31,30\n", + "Thursday,London,47,32,44,21,37\n", + "Friday,London,38,40,35,27,39\n", + "Saturday,London,32,29,39,32,31\n", + "Sunday,London,28,31,37,29,39\n", + "Monday,Edinburgh,29,26,36,25,35\n", + "Tuesday,Edinburgh,44,48,32,26,28\n", + "Wednesday,Edinburgh,46,43,38,41,26\n", + "Thursday,Edinburgh,39,39,36,31,20\n", + "Friday,Edinburgh,36,38,47,30,24\n", + "Saturday,Edinburgh,33,27,39,47,39\n", + "Sunday,Edinburgh,43,42,35,37,28\n", + "Monday,Glasgow,29,30,25,29,47\n", + "Tuesday,Glasgow,32,36,46,38,22\n", + "Wednesday,Glasgow,20,33,26,44,27\n", + "Thursday,Glasgow,21,29,25,35,46\n", + "Friday,Glasgow,39,36,45,28,32\n", + "Saturday,Glasgow,22,34,33,33,29\n", + "Sunday,Glasgow,27,23,29,24,24\n", + "Monday,Birmingham,27,34,49,35,31\n", + "Tuesday,Birmingham,39,41,41,31,20\n", + "Wednesday,Birmingham,33,46,28,40,47\n", + "Thursday,Birmingham,21,46,38,29,20\n", + "Friday,Birmingham,31,32,21,32,31\n", + "Saturday,Birmingham,44,20,46,26,29\n", + "Sunday,Birmingham,47,41,42,23,29\n", + "Monday,Cardiff,34,37,40,30,41\n", + "Tuesday,Cardiff,47,41,26,24,49\n", + "Wednesday,Cardiff,27,40,38,26,32\n", + "Thursday,Cardiff,29,28,43,26,22\n", + "Friday,Cardiff,21,43,23,37,27\n", + "Saturday,Cardiff,42,44,47,38,47\n", + "Sunday,Cardiff,37,31,21,28,26\n", + "\"@" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$data | Add-Member -PassThru -NotePropertyName \"Total\" -NotePropertyValue \"=Cucumber+Tomato+Lettuce+Asparagus+Potato\" -Force | export-excel -now -AutoNameRange" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$excelpath = \".\\SubTotals.xlsx\"\n", + "$WorksheetName = \"Sheet1\"\n", + "$changeColumnName = \"Day\"\n", + "$aggregateColumn = @{\"Cucumber\" = 9\n", + " \"Tomato\" = 9 \n", + " \"Lettuce\" = 9\n", + " \"Asparagus\" = 9\n", + " \"Potato\" = 9\n", + " \"Total\" = 9 } \n", + "<# $aggregateFunctions = @{\"AVERAGE\"=1;\"COUNT\"=2; \"COUNTA\"=3;\"MAX\"=4;\"MIN\"=5;\"PRODUCT\";= 6;\n", + " \"STDEV\"= 7;\"STDEVP\"= 8;\"SUM\"=9;\"VAR\"= 10;\"VARP\"=11} \n", + "# CountA=non empty cells VarP and StDevP = \"population\" not \"sample\" #add 100 to ignore hidden cells #>\n", + "del $excelpath -ErrorAction SilentlyContinue \n", + "\n", + "$data = $data | Sort-Object $changeColumnName\n", + "$Header = $data[0].PSObject.Properties.Name\n", + "$aggregateFormulas = @{} \n", + "\n", + "foreach ($k in $aggregateColumn.Keys) {\n", + " $columnNo = 0 ; \n", + " while ($columnNo -lt $header.count -and $header[$columnNo] -ne $k) {$columnNo ++}\n", + " $aggregateFormulas[$k] = \"=SUBTOTAL({0},{1}{{0}}:{1}{{1}})\" -f $aggregateColumn[$k], (Get-ExcelColumnName ($columnNo+1) ).ColumnName \n", + "}\n", + "$aggregateFormulas" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "#Work through the data as a we send it to excel adding a subtotals row when the value in .changeColumnName changes. Keep note of the new rows.\n", + "\n", + "$insertedRows = @()\n", + "$previousValue = $data[0].$changeColumnName\n", + "$currentRow = $lastChangeRow = 2\n", + "$excel = $data | \n", + " ForEach-Object -process {\n", + " # if the value in change column has changed output the subtotal row before the data \n", + " if ($_.$changeColumnName -ne $previousValue) { \n", + " $newobj = @{$changeColumnName = $previousValue} \n", + " foreach ($k in $aggregateFormulas.Keys) {\n", + " $newobj[$k] = $aggregateformulas[$k] -f $lastChangeRow, ($currentRow - 1) # <== Insert subtotal formula for these rows\n", + " }\n", + " [pscustomobject]$newobj\n", + " $insertedRows += $currentRow \n", + " $currentRow += 1 \n", + " $lastChangeRow = $currentRow \n", + " $previousValue = $_.$changeColumnName\n", + " } \n", + " #Always ouput the data\n", + " $_ \n", + " $currentRow += 1 \n", + " } -end { #Won't have output subtotals after final rows so put that in\n", + " $newObj = @{$changeColumnName = $previousValue}\n", + " foreach ($k in $aggregateFormulas.Keys) {\n", + " $newobj[$k] = $aggregateformulas[$k] -f $lastChangeRow, ($currentRow - 1)\n", + " }\n", + " [pscustomobject]$newobj\n", + " $insertedRows += $currentRow \n", + " } | Export-Excel -Path $ExcelPath -PassThru -AutoSize -AutoFilter -AutoNameRange -BoldTopRow -WorksheetName $WorksheetName -Activate -ClearSheet \n", + "\n", + " \n", + "#Format the inserted rows. \n", + "$ws = $excel.$WorksheetName\n", + "foreach ($r in $insertedrows) {$ws.Row($r).style.font.bold = $true }\n", + "\n", + "$range = $ws.Dimension.Address\n", + "$ExcelPath = $excel.File.FullName\n", + "$SheetIndex = $ws.index\n", + "Close-ExcelPackage $excel #Don't show yet\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "EPPlus can't apply outlining so we'll cheat and use the COM model " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "$excelApp = New-Object -ComObject \"Excel.Application\" \n", + "$excelWorkBook = $excelApp.Workbooks.Open($ExcelPath) \n", + "$ws = $excelWorkBook.Worksheets.item($SheetIndex)\n", + "$null = $ws.Range($range).Select()\n", + "$null = $excelapp.ActiveCell.AutoOutline()\n", + "$null = $ws.Outline.ShowLevels(1,$null)\n", + "$excelWorkBook.Save()\n", + "$excelApp.Visible = $true\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Not for this demo :-) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "ipmo ~\\Documents\\GitHub\\PowerShellPivot\\PowerShellPivot.psd1\n", + "Get-Item $env:temp\\chart.xlsx -ea SilentlyContinue | del \n", + "\n", + "$locations = $data.location | Sort-Object -Unique\n", + "\n", + "$cd1 = New-ExcelChartDefinition -ChartType ColumnClustered -XRange Product -YRange $locations -SeriesHeader $locations -Title (\"Veg Sales to {0:d}\" -f (get-date))\n", + "$cd2 = New-ExcelChartDefinition -ChartType Doughnut -XRange Product -YRange $locations -SeriesHeader $locations -Title (\"Veg Sales to {0:d}\" -f (get-date)) -Row 20 \n", + "\n", + "$data | Invoke-PSMelt -ValueName Sales -VarName Product -Id Day, Location |\n", + " ConvertTo-CrossTab -ValueName Sales -RowName Product -ColumnName Location -Aggregate Sum |\n", + " Export-Excel $env:temp\\chart.xlsx -ExcelChartDefinition $cd1,$cd2 -AutoNameRange -AutoSize -BoldTopRow -Show" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Comparing and merging " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "dotnet_interactive": { + "language": "pwsh" + }, + "vscode": { + "languageId": "dotnet-interactive.pwsh" + } + }, + "outputs": [], + "source": [ + "compare-worksheet -Referencefile .\\cupcake1.xlsx -Differencefile .\\cupcake2.xlsx -NoHeader -BackgroundColor LightGreen -FontColor Red -Show\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".NET (PowerShell)", + "language": "PowerShell", + "name": ".net-pwsh" + }, + "language_info": { + "name": "PowerShell" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/James ONeill/Excel/PSCONFEU22_Excel.pptx b/James ONeill/Excel/PSCONFEU22_Excel.pptx new file mode 100644 index 0000000..ff21aa3 Binary files /dev/null and b/James ONeill/Excel/PSCONFEU22_Excel.pptx differ diff --git a/James ONeill/Excel/Readme.me b/James ONeill/Excel/Readme.me new file mode 100644 index 0000000..12d408c --- /dev/null +++ b/James ONeill/Excel/Readme.me @@ -0,0 +1 @@ +Files From my "Management Readable format talk including a zipped version of the big data set diff --git a/James ONeill/Excel/cupcake-ipsum.txt b/James ONeill/Excel/cupcake-ipsum.txt new file mode 100644 index 0000000..95729ea --- /dev/null +++ b/James ONeill/Excel/cupcake-ipsum.txt @@ -0,0 +1,20 @@ +Cupcake ipsum dolor sit amet caramels caramels lollipop. Lollipop gummi-bears cheesecake pudding fruitcake candy-canes. Liquorice dragée halvah sweet ice-cream lollipop jelly soufflé. Sweet brownie ice-cream brownie cake macaroon pudding oat-cake pie. Cotton-candy apple-pie cookie pie cookie cookie cookie. Gummies chocolate lollipop icing oat-cake marshmallow cupcake cookie. Fruitcake croissant powder pudding cake caramels dragée sugar-plum. Toffee sweet tart cake. Cheesecake macaroon caramels. Topping fruitcake carrot cake lemon-drops dessert candy-canes. Chupa-chups liquorice biscuit cake. Fruitcake wafer icing tiramisu cheesecake gingerbread chocolate-bar pie. +Cotton-candy chocolate-bar marzipan topping macaroon. Cake gummi-bears oat-cake gingerbread danish candy-canes candy-canes bonbon. Topping sesame-snaps macaroon sweet jelly toffee lollipop gummi-bears fruitcake. Chocolate-bar chocolate-cake fruitcake dragée candy-canes. Sugar-plum muffin lemon-drops jelly. Jelly pudding fruitcake chocolate-cake sugar-plum jelly-beans dessert bonbon. Sesame-snaps soufflé marshmallow danish sesame-snaps. Jujubes biscuit jelly-o halvah gummies gummies lollipop donut. Cupcake marzipan gummi-bears cupcake candy-canes. Brownie topping toffee caramels jujubes fruitcake carrot cake dragée. Bear-claw croissant liquorice tart gummies bonbon. Wafer candy-canes soufflé bear-claw icing chocolate-cake dragée marzipan. Sweet jujubes macaroon oat-cake brownie bear-claw chocolate. +Pie gummi-bears bonbon muffin liquorice marzipan jelly-o toffee pudding. Sweet lollipop cake tiramisu lollipop pie chocolate-cake ice-cream pastry. Cupcake candy chocolate-bar. Liquorice marzipan bonbon apple-pie brownie powder brownie. Cotton-candy apple-pie halvah cake sugar-plum marshmallow. Ice-cream pudding chocolate-bar muffin gummies cookie tart donut. Macaroon jelly macaroon carrot cake candy pie brownie. Jujubes tart gingerbread donut. Sesame-snaps bonbon bonbon caramels dragée halvah powder dragée fruitcake. Candy lollipop pudding donut chocolate-cake ice-cream chocolate lollipop. Cake pastry brownie. Toffee jujubes liquorice marshmallow cotton-candy soufflé donut tiramisu. Croissant gummies cotton-candy. Cheesecake tart macaroon marzipan jelly-o sugar-plum. +Sweet roll gummi-bears soufflé danish halvah. Cupcake oat-cake candy. Chocolate-cake jelly macaroon. Biscuit chocolate-cake jelly fruitcake pastry powder. Pastry toffee muffin. Croissant pie jujubes. Oat-cake cheesecake lemon-drops gingerbread. Sesame-snaps oat-cake marshmallow bonbon chocolate-cake. Sesame-snaps marshmallow cookie lemon-drops ice-cream donut. Bonbon liquorice lollipop sweet roll. Chupa-chups macaroon oat-cake dragée jelly-o soufflé. Sweet cupcake dragée candy marzipan cotton-candy cake apple-pie bonbon. Oat-cake gingerbread gummies. Bonbon tootsie roll jelly-o tart jelly-o jujubes pastry. +Carrot cake oat-cake tiramisu chocolate-cake donut chocolate-bar jelly-beans biscuit dragée. Chocolate tart croissant cake marshmallow marzipan muffin toffee. Cupcake gingerbread jelly-o. Bear-claw gingerbread jelly-o sweet roll halvah. Sesame-snaps tootsie roll carrot cake topping tootsie roll brownie topping. Macaroon jelly soufflé marzipan apple-pie icing topping muffin. Bonbon icing jelly-beans topping biscuit. Ice-cream candy-canes muffin caramels topping cotton-candy. Gummi-bears halvah carrot cake. Jelly-o powder biscuit pastry gummi-bears cupcake. Fruitcake tiramisu gummi-bears candy-canes donut. Chupa-chups muffin cheesecake apple-pie. Candy marshmallow jelly-beans. Gummi-bears icing caramels ice-cream jelly-o soufflé icing cheesecake. +Donut sugar-plum chocolate soufflé cheesecake. Gummies muffin danish muffin danish pastry fruitcake sugar-plum sesame-snaps. Topping macaroon chocolate-cake apple-pie gingerbread. Topping chocolate-cake dragée tootsie roll. Croissant dessert gingerbread sugar-plum sugar-plum. Marzipan caramels chocolate-bar cheesecake dragée. Sugar-plum carrot cake jujubes brownie chocolate-cake. Icing pastry chocolate-bar oat-cake cupcake halvah. Toffee liquorice pudding pastry sugar-plum dessert toffee. Liquorice croissant topping bonbon marzipan. Brownie fruitcake icing cupcake dragée chupa-chups biscuit soufflé jelly-beans. Soufflé gummi-bears sesame-snaps marshmallow pudding sesame-snaps. Lollipop lemon-drops wafer croissant donut croissant carrot cake macaroon. +Dragée dessert halvah. Gingerbread chocolate-cake toffee tart chupa-chups gummies icing cheesecake cheesecake. Gummies candy-canes jujubes fruitcake. Pastry macaroon cotton-candy gummies pudding halvah pastry. Caramels biscuit icing tart wafer. Pie caramels bear-claw lollipop halvah gummi-bears dessert. Powder cotton-candy soufflé cookie tootsie roll halvah cheesecake cupcake cookie. Apple-pie apple-pie toffee biscuit pudding jelly-o brownie bear-claw pudding. Tiramisu chupa-chups muffin pie pudding gummies fruitcake cookie topping. Tiramisu tart candy marshmallow pudding. Jelly cake macaroon. Dessert cookie cheesecake cake bear-claw sweet marshmallow halvah toffee. Caramels soufflé cake. +Donut halvah pudding donut chocolate apple-pie candy-canes. Powder chupa-chups croissant croissant marzipan lollipop icing croissant croissant. Jelly-beans chocolate-bar cupcake candy. Gummi-bears cookie chupa-chups gingerbread cookie dessert. Soufflé tiramisu bonbon chocolate-cake. Sweet bear-claw tiramisu lemon-drops. Candy-canes croissant soufflé chupa-chups lemon-drops. Chupa-chups lemon-drops cake ice-cream. Jelly jujubes powder halvah soufflé marshmallow cheesecake marzipan marzipan. Dessert cake jelly cheesecake fruitcake cheesecake tiramisu. Donut cupcake bear-claw. Sesame-snaps tart biscuit. +Soufflé chupa-chups carrot cake bear-claw marshmallow caramels. Jelly-o cookie tiramisu cake bonbon pudding soufflé soufflé halvah. Gingerbread tiramisu sesame-snaps gummies cake cotton-candy. Jelly dragée pudding jelly brownie gummi-bears. Caramels halvah gingerbread bonbon icing pudding. Muffin fruitcake jujubes powder croissant soufflé caramels jelly sweet. Oat-cake gingerbread chocolate-cake marzipan cake caramels macaroon. Pie marzipan tiramisu. Lemon-drops bear-claw dragée wafer. Bear-claw lollipop cotton-candy macaroon carrot cake oat-cake fruitcake gummi-bears cake. Marzipan tart topping. Wafer cake cupcake cake marshmallow icing dragée tart bear-claw. +Cookie cotton-candy cake tiramisu liquorice ice-cream cheesecake cookie. Chupa-chups oat-cake ice-cream ice-cream. Gummies caramels dessert oat-cake lemon-drops gummies wafer chocolate. Oat-cake bonbon sesame-snaps cotton-candy fruitcake. Brownie wafer marzipan. Lemon-drops chocolate-bar cake cotton-candy. Candy cupcake bear-claw chocolate. Bonbon chocolate-bar sugar-plum sweet pudding. Fruitcake candy-canes jelly-o toffee candy pudding chocolate-cake jelly. Cookie soufflé jelly-o powder jujubes pastry fruitcake. Dragée candy marshmallow tootsie roll chupa-chups chupa-chups muffin sweet. Wafer soufflé brownie chocolate-bar. Ice-cream halvah muffin. Toffee jelly-beans candy-canes wafer cookie cheesecake cake biscuit dragée. +Liquorice chocolate-bar toffee cake cupcake sweet roll candy. Macaroon powder liquorice dessert sesame-snaps sesame-snaps gummies macaroon cheesecake. Tootsie roll sesame-snaps lollipop topping lollipop powder. Sugar-plum cupcake cake chocolate-bar marzipan bonbon tart candy. Gummi-bears fruitcake apple-pie candy lemon-drops cotton-candy marzipan caramels. Cake cookie toffee cookie jelly-o chocolate-cake halvah chocolate-bar wafer. Sugar-plum wafer tootsie roll cheesecake lemon-drops cookie biscuit. Pastry cotton-candy muffin sesame-snaps dessert liquorice carrot cake halvah wafer. Chupa-chups biscuit topping. Carrot cake lemon-drops cheesecake sweet. Chocolate-bar chocolate-cake macaroon tootsie roll jelly halvah sesame-snaps. Sugar-plum oat-cake caramels topping sweet roll. Soufflé biscuit icing cupcake. Gummi-bears fruitcake sweet topping cookie gummi-bears candy-canes. +Tart topping chupa-chups. Marzipan tootsie roll ice-cream dragée sweet powder topping. Croissant sweet cotton-candy biscuit danish. Cheesecake gingerbread topping powder cake sweet gummi-bears soufflé pie. Chocolate jujubes icing croissant. Bear-claw gummi-bears apple-pie cheesecake fruitcake macaroon sesame-snaps tootsie roll toffee. Sugar-plum chocolate-cake muffin lollipop cake lemon-drops pudding soufflé. Cheesecake cupcake dessert cake cotton-candy dragée. Chupa-chups cupcake pudding chocolate-cake muffin. Powder caramels dragée candy-canes pudding. Jelly apple-pie cotton-candy carrot cake. Powder brownie powder chocolate-bar soufflé cotton-candy. Cookie tootsie roll oat-cake icing powder carrot cake. +Cookie carrot cake candy jelly-o. Dessert croissant soufflé bonbon. Candy croissant carrot cake wafer gingerbread candy gummi-bears chupa-chups jelly. Cake croissant candy sweet. Sweet bonbon oat-cake muffin pie. Chocolate halvah bonbon. Dessert pastry tiramisu biscuit cupcake marshmallow chocolate. Cookie gummi-bears cupcake. Oat-cake apple-pie soufflé gummies gummi-bears. Gummies cookie jelly-o cotton-candy. Apple-pie biscuit sweet. Pie chocolate-bar danish cotton-candy. +Oat-cake sweet bonbon. Cookie lemon-drops wafer soufflé. Dragée bonbon marzipan. Chocolate-bar bonbon lollipop jelly apple-pie. Sweet roll chocolate wafer dessert. Sugar-plum candy liquorice marzipan jelly topping. Candy-canes jelly-beans chocolate-cake jelly-o jelly-beans jelly-beans jujubes chocolate-bar oat-cake. Tiramisu bear-claw pudding cotton-candy brownie chocolate-cake chupa-chups pastry. Sweet muffin toffee dragée croissant sweet roll macaroon dragée brownie. Jujubes marzipan brownie cotton-candy gingerbread ice-cream oat-cake. Oat-cake sweet roll ice-cream tootsie roll ice-cream candy dragée halvah. Fruitcake sweet roll cupcake sweet roll pie wafer jelly chupa-chups muffin. Candy fruitcake candy-canes. Lollipop bear-claw wafer muffin. +Pudding chupa-chups tart. Sugar-plum candy lollipop pie carrot cake candy-canes oat-cake pastry gummi-bears. Gummi-bears marzipan cheesecake macaroon apple-pie cupcake gummi-bears. Cotton-candy powder biscuit marshmallow chocolate-cake jelly wafer. Cake sugar-plum chocolate-bar croissant cotton-candy jujubes toffee. Lollipop jujubes jelly-o oat-cake carrot cake danish chupa-chups. Candy chupa-chups brownie oat-cake cotton-candy dragée marzipan jelly icing. Cake bonbon apple-pie fruitcake. Pie cotton-candy jelly-beans icing. Sweet gummies jelly-o dessert fruitcake. Marzipan soufflé soufflé sweet donut apple-pie cake apple-pie croissant. Dessert jujubes cheesecake chocolate liquorice dragée wafer sugar-plum. Icing bonbon chupa-chups dessert soufflé carrot cake pudding. Danish bear-claw cupcake croissant cotton-candy. +Apple-pie liquorice marshmallow sesame-snaps macaroon sugar-plum oat-cake donut apple-pie. Macaroon chocolate bonbon bonbon fruitcake bear-claw pudding macaroon sweet roll. Chocolate candy lollipop cookie jelly-beans donut biscuit. Wafer croissant powder icing cake jelly-beans macaroon soufflé. Oat-cake pastry lollipop dragée cake. Candy-canes biscuit pudding wafer halvah. Dessert ice-cream dessert tart sugar-plum toffee jelly-o. Danish croissant liquorice chocolate-bar croissant croissant bear-claw. Cupcake marshmallow oat-cake sesame-snaps croissant biscuit. Pudding jujubes brownie cake gingerbread marshmallow chocolate-cake. Candy bear-claw bear-claw jelly-beans topping chocolate-cake. Gummi-bears chocolate toffee gummies ice-cream. Lollipop sesame-snaps candy cake macaroon bonbon muffin donut. Fruitcake macaroon marzipan. +Toffee candy-canes pastry dragée oat-cake jelly-o tiramisu caramels. Muffin jelly-beans bonbon cotton-candy chocolate-cake dessert chocolate sugar-plum. Marshmallow icing dragée. Pudding chupa-chups sugar-plum fruitcake wafer cake macaroon. Gummi-bears gummi-bears bonbon cake oat-cake tootsie roll icing chupa-chups. Ice-cream fruitcake dessert ice-cream soufflé sugar-plum. Jelly powder wafer ice-cream. Dessert chupa-chups jujubes gingerbread soufflé. Soufflé chocolate-cake chocolate-cake. Jujubes bear-claw pastry caramels toffee soufflé tiramisu powder muffin. Brownie jelly chocolate-cake pastry lollipop sweet. Marzipan jujubes bonbon muffin. Icing bonbon jelly cake powder chocolate-cake chocolate-bar. Gummies chupa-chups pudding wafer bonbon gummies biscuit gummies tiramisu. +Sesame-snaps pastry pudding jelly cake apple-pie jelly gummi-bears chocolate-bar. Sesame-snaps cheesecake soufflé oat-cake dragée macaroon macaroon. Sesame-snaps cotton-candy chupa-chups gingerbread. Danish halvah tootsie roll sesame-snaps candy cake ice-cream. Cotton-candy jelly-beans tiramisu tiramisu cake liquorice. Tootsie roll donut bear-claw candy cake brownie liquorice carrot cake tootsie roll. Gingerbread gummies chupa-chups danish cotton-candy marshmallow croissant. Jelly-beans cotton-candy-candy canes donut oat-cake dragée macaroon. Bear-claw marshmallow soufflé cheesecake macaroon dragée gummi-bears bear-claw gummies. Chocolate-cake pie sugar-plum chocolate-cake cookie jelly-o gummi-bears jujubes. Pastry marshmallow bonbon gummi-bears sesame-snaps marzipan croissant donut jujubes. Icing cupcake fruitcake dragée lemon-drops carrot cake. +Powder icing sugar-plum macaroon. Muffin gummi-bears gummies chocolate-bar bonbon marzipan marzipan bonbon. Cookie dragée pastry tart donut bonbon. Sugar-plum icing sweet roll toffee. Bear-claw sweet brownie. Biscuit liquorice chocolate-bar marshmallow chocolate candy pastry. Chocolate pastry marshmallow sesame-snaps dessert gingerbread liquorice biscuit pudding. Cotton-candy chupa-chups topping jelly croissant jujubes gummi-bears dessert cookie. Macaroon sesame-snaps topping pudding cupcake gingerbread jelly-beans brownie jelly. Halvah jelly chocolate-bar. Caramels chocolate-bar pastry oat-cake jelly-o tootsie roll bonbon jujubes. Marzipan halvah cake. +Chocolate apple-pie lemon-drops marshmallow soufflé halvah cake cotton-candy sugar-plum. Bonbon cheesecake icing dessert cotton-candy-candy cake topping icing. Cheesecake liquorice dessert jelly-o halvah powder sweet roll. Gingerbread cheesecake fruitcake gummi-bears chupa-chups macaroon wafer tart. Gummi-bears wafer sweet roll candy marzipan cake icing soufflé toffee. Halvah croissant soufflé bear-claw ice-cream halvah pudding cupcake. Pie lollipop liquorice sweet. Jelly-beans sugar-plum soufflé marshmallow. Candy cookie chupa-chups tart bear-claw lemon-drops gummi-bears fruitcake. Sweet roll lollipop muffin sweet roll cake cheesecake chupa-chups tootsie roll cheesecake. Chocolate gingerbread topping soufflé caramels. Halvah danish halvah pudding halvah bonbon. Cotton-candy oat-cake powder caramels croissant jelly-o chocolate-cake tiramisu candy. \ No newline at end of file diff --git a/James ONeill/Excel/pictureinfo.zip b/James ONeill/Excel/pictureinfo.zip new file mode 100644 index 0000000..3aaea27 Binary files /dev/null and b/James ONeill/Excel/pictureinfo.zip differ diff --git a/James ONeill/GraphPlusPlus/Demo_Main.ps1 b/James ONeill/GraphPlusPlus/Demo_Main.ps1 new file mode 100644 index 0000000..37e05fc --- /dev/null +++ b/James ONeill/GraphPlusPlus/Demo_Main.ps1 @@ -0,0 +1,73 @@ +Get-Module | ForEach-Object {get-command -Module $_ -CommandType Cmdlet,Function} | Measure-Object | ForEach-Object count +Import-Module Microsoft.Graph.PlusPlus +Connect-Graph + +Get-Module | ForEach-Object {get-command -Module $_ -CommandType Cmdlet,Function} | Measure-Object | ForEach-Object count + +#Select some users and put them in a new team. For my demo I pre-set value of department => group membership +$GroupName = 'Presenters' +$newProjectName = "Vienna" +Get-GraphUserList -Filter "Department eq '$GroupName'" -OutVariable users | Format-Table Organization +New-GraphTeam -Name $GroupName -Description "The $GroupName Department" -Visibility public -Members $users -OutVariable newTeam + +Get-GraphTeam $newTeam -Drive -OutVariable teamdrive | Set-GraphHomeDrive ; $teamDrive +#later we will add a tab in teams for this drive + +#special folder tab completes +Get-GraphDrive -SpecialFolder Documents +Get-GraphDrive / + +#Send a local file to onedrive, and open it -use it for exporting in a moment. +Get-ChildItem $env:temp\Test*.xlsx -OutVariable files + +#Destination tab completes - use General for preference +$files | Copy-ToGraphFolder -OutVariable item -Destination 'root:/General' + +Start-Process $item.webUrl + +#Leave the window open to see export happen - itempath tab completes - use the file from the previous - +Get-GraphUserList -MembersOnly | Select-Object Organization | Export-GraphWorkSheet -SheetName sheet1 -ItemPath 'root:/General/test.xlsx' -Show + +#groups upgraded to teams have channels for the teams App +Get-GraphTeam $newTeam -Channels -OutVariable teamFirstChannel + +$null = New-GraphChannelMessage -Channel $teamFirstChannel -Content "Please keep posts in 'General' to admin and questions about using the group. Use the wiki or OneNote for shared notes." + +#create a New channel - with its own notebook section and a planner with 3 buckets & an initial task. Make them tabs in teams. +$newChannel = New-GraphChannel -Team $newTeam -Name $newProjectName -Description "For anything about project $newProjectName" +#The next commnd will fail - want to make a point about that! +$newTeamplan = New-GraphTeamPlan -Team $newTeam -PlanName $newProjectName +#The point to make: when you create a team yoy aren't added as a member and that stops you creating the planner so add (current user is in globalVar) and go again +Add-GraphTeamMember -Group $Newteam -Member $GraphUser +$newTeamplan = New-GraphTeamPlan -Team $newTeam -PlanName $newProjectName +Add-GraphPlanBucket -Plan $NewTeamplan -Name 'Backlog', 'To-Do','Not Doing' +Add-GraphPlanTask -Plan $newTeamplan -Title "Project $newProjectName Objectives" -Bucket "To-Do" -DueDate ([datetime]::Today.AddDays(7)) -AssignTo $users[-1].Mail + +#Add Planner and one note to teams. +Add-GraphPlannerTab -TabLabel 'Planner' -Channel $newChannel -Plan $NewTeamplan | Out-Null + +#Groups have a calendar - add a meeting and invite members +$pattern = New-GraphRecurrence -Type weekly -DaysOfWeek wednesday -NumberOfOccurrences 52 +$attendees = ((Get-GraphTeam -Team $newTeam -Members) + (Get-GraphTeam -Team $newTeam -Owners ) )| New-GraphAttendee -AttendeeType optional +Add-GraphEvent -Team $newTeam -Subject "Midweek team lunch" -Attendees $attendees -Start ([datetime]::Today.AddHours(12)) -End ([datetime]::Today.AddHours(12)) -Recurrence $Pattern + +Get-GraphTeam $newTeam -Notebooks -OutVariable teamnotebook +New-GraphOneNoteSection -Notebook $teamNotebook -SectionName $newProjectName -OutVariable NewSection +$NewSection | Set-GraphOneNoteHome +Add-GraphOneNotePage -HTMLPage "Project $newProjectName

A default home for your notes.

" +Add-GraphOneNoteTab -TabLabel 'Project Notebook' -Channel $newChannel -Notebook $Newsection + +$teamDrive | Add-GraphSharePointTab -TabLabel "Team Drive" -Channel $NewChannel + +Get-GraphTeam $newTeam -Site -OutVariable Site +$cols = 'AssignedTo', 'IssueStatus', 'TaskDueDate', 'V3Comments' | ForEach-Object {Get-GraphSiteColumn -Raw -name $_} +$cols += Get-GraphSiteColumn -Raw -Name 'priority' -ColumnGroup 'Core Task and Issue Columns' +$newlist = New-GraphList -Name "$newProjectName Issue Tracking" -Columns $cols -Site $site -Template genericList + +Add-GraphListItem -List $newlist -Fields @{Title='Demo Item';IssueStatus='Active';Priority='(2) Normal';} + +$newlist | Add-GraphSharePointTab -Channel $NewChannel + +New-GraphChannelMessage -Channel $teamFirstChannel -Content "A new channel has been added for Project $newProjectName with its own planner, one note section and issues list on the team site. Take a look " + +Start-Process $newlist.webUrl \ No newline at end of file diff --git a/James ONeill/GraphPlusPlus/PSCONFEU22_GraphPlusPlus.pptx b/James ONeill/GraphPlusPlus/PSCONFEU22_GraphPlusPlus.pptx new file mode 100644 index 0000000..27e23f3 Binary files /dev/null and b/James ONeill/GraphPlusPlus/PSCONFEU22_GraphPlusPlus.pptx differ diff --git a/James ONeill/GraphPlusPlus/Readme.md b/James ONeill/GraphPlusPlus/Readme.md new file mode 100644 index 0000000..060389d --- /dev/null +++ b/James ONeill/GraphPlusPlus/Readme.md @@ -0,0 +1,2 @@ +Slides and demo script from my Graph ++ Talk +