How to become a SHiPS wright - Building with SHiPS

Aac3dafaab7a7c2063d2526ba5936305?s=47 Glenn
April 27, 2019

How to become a SHiPS wright - Building with SHiPS

A Shipwright an artisan skilled in one or more of the tasks required to build vessels. A SHiPSwright is an artisan skilled in one or more of the tasks required to build PowerShell Providers. The SHiPS toolkit has been around for a while but it can be a little difficult to get started.

Links
https://github.com/PowerShell/SHiPS

Aac3dafaab7a7c2063d2526ba5936305?s=128

Glenn

April 27, 2019
Tweet

Transcript

  1. Becoming a SHiPS wright Building with SHiPS @glennsarti glenn-sarti

  2. @glennsarti

  3. @glennsarti Becoming a SHiPS wright

  4. @glennsarti What is SHiPS?

  5. @glennsarti SHiPS is a PowerShell provider. More accurately it is

    a provider platform that simplifies developing PowerShell providers. - https://www.powershellgallery.com/packages/SHiPS
  6. @glennsarti PowerShell providers provide access to data and components that

    would not otherwise be easily accessible at the command line. The data is presented in a consistent format that resembles a file system drive.. - about_providers
  7. @glennsarti PS C:\Users\glenn.sarti> Get-PSProvider Name Capabilities Drives ---- ------------ ------

    Registry ShouldProcess {HKLM, HKCU} Alias ShouldProcess {Alias} Environment ShouldProcess {Env} FileSystem Filter, ShouldProcess, Credentials {C} Function ShouldProcess {Function} Variable ShouldProcess {Variable}
  8. @glennsarti PS C:\Users\glenn.sarti> Get-ChildItem HKLM:\System Hive: HKEY_LOCAL_MACHINE\System Name Property ----

    -------- ActivationBroker ControlSet001 DriverDatabase Version : 167772160 SchemaVersion : 65536 Architecture : 9 UpdateDate : {64, 148, 108, 19...} OemInfMap : {255, 255, 255, 255...} HardwareConfig LastConfig : {a4c71b4c-22d3-11b2-a85c-f593fd660ebe} LastId : 0 …
  9. @glennsarti Why do I need SHiPS?

  10. @glennsarti Providers are great

  11. @glennsarti Providers are hard

  12. @glennsarti Providers are hard

  13. @glennsarti Providers are hard

  14. @glennsarti File System 9,965 Registry 4,373 Certificates 3,454 Functions 388

    Aliases 358 Environment 246 Variables 239
  15. @glennsarti File System 13,113 Registry 7,521 Certificates 6,602 Functions 3,537

    Aliases 3,507 Environment 3,388 Variables 3,395
  16. @glennsarti SHiPS is a PowerShell provider. More accurately it is

    a provider platform that simplifies developing PowerShell providers. - https://www.powershellgallery.com/packages/SHiPS
  17. @glennsarti When did SHiPS become a thing?

  18. @glennsarti 2018 2019 2014 2015 2016 2017 Simplex P2F Azure

    Cloud Shell Public Preview SHiPS on PS Gallery Releases (0.8.1) SHiPS
  19. @glennsarti Module You are here SHiPS P2F PowerShell

  20. @glennsarti using namespace Microsoft.PowerShell.SHiPS # Root class Parent : SHiPSDirectory

    { Parent([string]$name): base($name) { } [object[]] GetChildItem() { return [Child]::new("Child"); } } class Child : SHiPSLeaf { Child($name): base($name) { } }
  21. @glennsarti What things can I SHiPS-ify?

  22. @glennsarti Deepak - https://github.com/DexterPOSH Glenn - https://github.com/glennsarti Ravi - https://github.com/rchaganti

    Patrick - https://github.com/SeeminglyScience PS - https://github.com/PowerShell
  23. @glennsarti

  24. @glennsarti Directed Acyclical Graph

  25. @glennsarti Directed Acyclical Graph

  26. @glennsarti Directed Acyclical Graph

  27. @glennsarti Directed Acyclical Graph A B C D A/B/C

  28. @glennsarti Directed Acyclical Graph A B C D

  29. @glennsarti Directed Acyclical Graph ❌ A B C D A/B/C/A/B/C/A

  30. @glennsarti Directed Acyclical Graph A B C D A/B/C A/B/D/C

  31. @glennsarti DAGs in the wild …

  32. @glennsarti Filesystem Registry

  33. @glennsarti Filesystem Registry

  34. @glennsarti AD Org. Units Certificates

  35. @glennsarti AD Org. Units Certificates

  36. @glennsarti Azure Resource Groups

  37. @glennsarti Azure Resource Groups

  38. @glennsarti Azure DevOps Pipelines

  39. @glennsarti Azure DevOps Pipelines

  40. @glennsarti

  41. @glennsarti DAGs are everywhere!

  42. @glennsarti And?

  43. @glennsarti Austin Cathy Ben Bill Chris

  44. @glennsarti Austin Bill SHiPSDirectory SHiPSLeaf GetChildItem

  45. @glennsarti Become a SHiPS wright

  46. @glennsarti Step 0 Put the computer away

  47. @glennsarti

  48. @glennsarti

  49. @glennsarti Step 0.5 Install SHiPS https://github.com/PowerShell/SHiPS#installing-ships

  50. @glennsarti Step 1 Create root object

  51. @glennsarti Root

  52. @glennsarti @{ RootModule = 'PSSummitNA2019.psm1' ModuleVersion = '1.0' GUID =

    '2e946999-7d90-4bfb-88f1-9336e3a01587' Author = 'glenn.sarti' CompanyName = 'Glenn Sarti' Description = 'A PowerShell Provider for the Pow…' # Modules that must be imported into the global … RequiredModules = @('SHiPS') }
  53. @glennsarti using namespace Microsoft.PowerShell.SHiPS # Root [SHiPSProvider(UseCache=$true)] class Summit2019 :

    SHiPSDirectory { Summit2019([string]$name): base($name) { } [object[]] GetChildItem() { $obj = @() return $obj; } }
  54. @glennsarti using namespace Microsoft.PowerShell.SHiPS # Root [SHiPSProvider(UseCache=$true)] class Summit2019 :

    SHiPSDirectory { Summit2019([string]$name): base($name) { } [object[]] GetChildItem() { $obj = @() return $obj; } }
  55. @glennsarti using namespace Microsoft.PowerShell.SHiPS # Root [SHiPSProvider(UseCache=$true)] class Summit2019 :

    SHiPSDirectory { Summit2019([string]$name): base($name) { } [object[]] GetChildItem() { $obj = @() return $obj; } }
  56. @glennsarti using namespace Microsoft.PowerShell.SHiPS # Root [SHiPSProvider(UseCache=$true)] class Summit2019 :

    SHiPSDirectory { Summit2019([string]$name): base($name) { } [object[]] GetChildItem() { $obj = @() return $obj; } }
  57. @glennsarti using namespace Microsoft.PowerShell.SHiPS # Root [SHiPSProvider(UseCache=$true)] class Summit2019 :

    SHiPSDirectory { Summit2019([string]$name): base($name) { } [object[]] GetChildItem() { $obj = @() return $obj; } }
  58. @glennsarti using namespace Microsoft.PowerShell.SHiPS # Root [SHiPSProvider(UseCache=$true)] class Summit2019 :

    SHiPSDirectory { Summit2019([string]$name): base($name) { } [object[]] GetChildItem() { $obj = @() return $obj; } } ???
  59. @glennsarti PS > Import-Module .\PSSummitNA2019.psd1

  60. @glennsarti PS > Import-Module .\PSSummitNA2019.psd1 PS > New-PSDrive -Name Summit2019

    ` -PSProvider SHiPS ` -Root 'PSSummitNA2019#Summit2019' Name Used (GB) Free (GB) Provider Root ---- --------- --------- -------- ---- Summit2019 SHiPS PSSum…
  61. @glennsarti PS > Import-Module .\PSSummitNA2019.psd1 PS > New-PSDrive -Name Summit2019

    ` -PSProvider SHiPS ` -Root 'PSSummitNA2019#Summit2019' Name Used (GB) Free (GB) Provider Root ---- --------- --------- -------- ---- Summit2019 SHiPS PSSum… PS > gci Summit2019:\ PS >
  62. @glennsarti Step 2 Create directories

  63. @glennsarti Speakers Agenda

  64. @glennsarti # Directory Nodes # Speakers [SHiPSProvider(UseCache=$true)] class Speakers :

    SHiPSDirectory { Speakers([string]$name): base($name) { } [object[]] GetChildItem() { return @() } } # Agenda [SHiPSProvider(UseCache=$true)]
  65. @glennsarti } } # Agenda [SHiPSProvider(UseCache=$true)] class Agenda : SHiPSDirectory

    { Agenda([string]$name): base($name) { } [object[]] GetChildItem() { return @() } }
  66. @glennsarti # Root [SHiPSProvider(UseCache=$true)] class Summit2019 : SHiPSDirectory { Summit2019([string]$name):

    base($name) { } [object[]] GetChildItem() { $obj = @() return $obj; } } # Directory Nodes # Speakers
  67. @glennsarti # Root [SHiPSProvider(UseCache=$true)] class Summit2019 : SHiPSDirectory { Summit2019([string]$name):

    base($name) { } [object[]] GetChildItem() { $obj = @() $obj += [Speakers]::new('Speakers’); $obj += [Agenda]::new('Agenda’); return $obj; } }
  68. @glennsarti PS > Import-Module .\PSSummitNA2019.psd1 PS > New-PSDrive -Name Summit2019

    ` -PSProvider SHiPS ` -Root 'PSSummitNA2019#Summit2019' Name Used (GB) Free (GB) Provider Root ---- --------- --------- -------- ---- Summit2019 SHiPS PSSum…
  69. @glennsarti PS > gci Summit2019:\ Directory: Summit2019: Mode Name ----

    ---- + Speakers + Agenda PS >
  70. @glennsarti Step 3 Create Speaker leaves

  71. @glennsarti Bob Alice

  72. @glennsarti # Private Functions $Script:DataSource = Join-Path -Path $PSScriptRoot -ChildPath

    'Data' Function Get-SpeakersObject { if ($Script:SpeakerObject -eq $null) { $Script:SpeakerObject = Get-Content … | ConvertFrom-Json } Write-Output $Script:SpeakerObject } Function Remove-HTML($RawString) { $result = $RawString $result = $result -replace '<[^>]+>',‘’ Write-Output $result }
  73. @glennsarti # Leaf Nodes # A Speaker [SHiPSProvider(UseCache=$true)] class Speaker

    : SHiPSLeaf { [String]$Name; [String]$FirstName; [String]$LastName; [String]$Bio; Speaker ([string]$name, [Object]$data): base($name) { $this.PopulateFromData($data) } [void] PopulateFromData([Object]$data) { $this.Name = $data.name # VERY basic name splitting $NameArray = $this.Name -split " ", 2 $this.FirstName = $NameArray[0] $this.LastName = $NameArray[1] $this.Bio = Remove-HTML -RawString $data.overview } }
  74. @glennsarti # Leaf Nodes # A Speaker [SHiPSProvider(UseCache=$true)] class Speaker

    : SHiPSLeaf { [String]$Name; [String]$FirstName; [String]$LastName; [String]$Bio; Speaker ([string]$name, [Object]$data): base($name) { $this.PopulateFromData($data) } [void] PopulateFromData([Object]$data) { $this.Name = $data.name # VERY basic name splitting $NameArray = $this.Name -split " ", 2 $this.FirstName = $NameArray[0] $this.LastName = $NameArray[1] $this.Bio = Remove-HTML -RawString $data.overview } }
  75. @glennsarti # Leaf Nodes # A Speaker [SHiPSProvider(UseCache=$true)] class Speaker

    : SHiPSLeaf { [String]$Name; [String]$FirstName; [String]$LastName; [String]$Bio; Speaker ([string]$name, [Object]$data): base($name) { $this.PopulateFromData($data) } [void] PopulateFromData([Object]$data) { $this.Name = $data.name # VERY basic name splitting $NameArray = $this.Name -split " ", 2 $this.FirstName = $NameArray[0] $this.LastName = $NameArray[1] $this.Bio = Remove-HTML -RawString $data.overview } }
  76. @glennsarti # Leaf Nodes # A Speaker [SHiPSProvider(UseCache=$true)] class Speaker

    : SHiPSLeaf { [String]$Name; [String]$FirstName; [String]$LastName; [String]$Bio; Speaker ([string]$name, [Object]$data): base($name) { $this.PopulateFromData($data) } [void] PopulateFromData([Object]$data) { $this.Name = $data.name # VERY basic name splitting $NameArray = $this.Name -split " ", 2 $this.FirstName = $NameArray[0] $this.LastName = $NameArray[1] $this.Bio = Remove-HTML -RawString $data.overview } }
  77. @glennsarti # Speakers [SHiPSProvider(UseCache=$true)] class Speakers : SHiPSDirectory { Speakers([string]$name):

    base($name) { } [object[]] GetChildItem() { return @() } }
  78. @glennsarti # Speakers [SHiPSProvider(UseCache=$true)] class Speakers : SHiPSDirectory { Speakers([string]$name):

    base($name) { } [object[]] GetChildItem() { $obj = New-Object System.Collections.ArrayList($null) (Get-SpeakersObject).items | ForEach-Object -Process { $obj.Add([Speaker]::new($_.name, $_)) } return $obj; }
  79. @glennsarti PS > gci Summit2019:\Speakers | Select-Object -First 5 Directory:

    Summit2019:\Speakers Mode Name ---- ---- . James O'Neill . Christoph Bergmeister . Walter Legowski . Paul DeArment Jr . Daniel Bohannon PS >
  80. @glennsarti PS > gci Summit2019:\Speakers | select -First 1 –Property

    * SSItemMode : . PSPath : SHiPS\SHiPS::PSSummitNA2019#Summit2019\Speakers\James PSParentPath : SHiPS\SHiPS::PSSummitNA2019#Summit2019\Speakers PSChildName : James O'Neill PSDrive : Summit2019 PSProvider : SHiPS\SHiPS PSIsContainer : False Name : James O'Neill FirstName : James LastName : O'Neill Bio : James O'Neill spent the first 10 years of this century talking about it to anyone who will listen ever since. and DSC to automate processes for one of Britiain's be … PS >
  81. @glennsarti Step 4 Expand objects

  82. @glennsarti Session 1 Session 2 Session 3 Day 1 All

  83. @glennsarti Function Get-SessionsObject { … } Function Get-Sessions($Filter) { …

    } Function ConvertFrom-EpochTime($Value) { … }
  84. @glennsarti # A Session on the agenda [SHiPSProvider(UseCache=$true)] class AgendaSession

    : SHiPSLeaf { [String]$Id; [String]$Name; [datetime]$Start; [datetime]$End; [String]$Location; [String]$Description; Hidden [Object] $Data AgendaSession([string]$id, $data): base($id) { $this.Id = $Id $this.Data = $data
  85. @glennsarti # A Session on the agenda [SHiPSProvider(UseCache=$true)] class AgendaSession

    : SHiPSLeaf { [String]$Id; [String]$Name; [datetime]$Start; [datetime]$End; [String]$Location; [String]$Description; Hidden [Object] $Data AgendaSession([string]$id, $data): base($id) { $this.Id = $Id $this.Data = $data
  86. @glennsarti [String]$Description; Hidden [Object] $Data AgendaSession([string]$id, $data): base($id) { $this.Id

    = $Id $this.Data = $data $this.Name = $data.name $this.Description = Remove-HTML $data.overview $this.Start = ConvertFrom-EpochTime -Value $data.start_time $this.End = ConvertFrom-EpochTime -Value $data.end_time $this.Location = ($data.regions | Select-Object -First 1 | ForEach-Object { $_.name }) } }
  87. @glennsarti Session 1 Session 2 Session 3 Day 1 All

  88. @glennsarti # AgendaTrackSummary [SHiPSProvider(UseCache=$true)] class AgendaTrackSummary : SHiPSDirectory { [String]$Name;

    [Int]$Sessions; Hidden [Hashtable]$Filter; AgendaTrackSummary([string]$name, [Hashtable]$filter): base($name) { $this.Name = $name $this.Filter = $filter $this.Sessions = (Get-Sessions -Filter $this.Filter | Measure-Object).Count; } [object[]] GetChildItem() { $obj = New-Object System.Collections.ArrayList($null)
  89. @glennsarti # AgendaTrackSummary [SHiPSProvider(UseCache=$true)] class AgendaTrackSummary : SHiPSDirectory { [String]$Name;

    [Int]$Sessions; Hidden [Hashtable]$Filter; AgendaTrackSummary([string]$name, [Hashtable]$filter): base($name) { $this.Name = $name $this.Filter = $filter $this.Sessions = (Get-Sessions -Filter $this.Filter | Measure-Object).Count; } [object[]] GetChildItem() { $obj = New-Object System.Collections.ArrayList($null)
  90. @glennsarti } [object[]] GetChildItem() { $obj = New-Object System.Collections.ArrayList($null) Get-Sessions

    -Filter $this.Filter | ForEach-Object -Process { $obj.Add([AgendaSession]::new($_.Id, $_)) } return $obj; } }
  91. @glennsarti [object[]] GetChildItem() { return @() }

  92. @glennsarti [object[]] GetChildItem() { $obj = New-Object System.Collections.ArrayList($null) $obj.Add([AgendaTrackSummary]::new('All', @{

    })) $obj.Add([AgendaTrackSummary]::new('Day 1 - Mon', @{ 'Day' = 29 })) $obj.Add([AgendaTrackSummary]::new('Day 2 - Tue', @{ 'Day' = 30 })) $obj.Add([AgendaTrackSummary]::new('Day 3 - Wed', @{ 'Day' = 1 })) $obj.Add([AgendaTrackSummary]::new('Day 4 - Thu', @{ 'Day' = 2 })) $trackList = @{} (Get-SessionsObject).sessions | ForEach-Object -Process { $_.tracks | ForEach-Object -Process { $trackList[$_.name] = $true } } $trackList.GetEnumerator() | ForEach-Object -Process { $obj.Add([AgendaTrackSummary]::new($_.Key, @{ 'Track' = $_.Key })) } return $obj; }
  93. @glennsarti [object[]] GetChildItem() { $obj = New-Object System.Collections.ArrayList($null) $obj.Add([AgendaTrackSummary]::new('All', @{

    })) $obj.Add([AgendaTrackSummary]::new('Day 1 - Mon', @{ 'Day' = 29 })) $obj.Add([AgendaTrackSummary]::new('Day 2 - Tue', @{ 'Day' = 30 })) $obj.Add([AgendaTrackSummary]::new('Day 3 - Wed', @{ 'Day' = 1 })) $obj.Add([AgendaTrackSummary]::new('Day 4 - Thu', @{ 'Day' = 2 })) $trackList = @{} (Get-SessionsObject).sessions | ForEach-Object -Process { $_.tracks | ForEach-Object -Process { $trackList[$_.name] = $true } } $trackList.GetEnumerator() | ForEach-Object -Process { $obj.Add([AgendaTrackSummary]::new($_.Key, @{ 'Track' = $_.Key })) } return $obj; }
  94. @glennsarti PS > gci Summit2019:\Agenda | ` Select-Object -Property Name,

    Sessions | ` Format-Table
  95. @glennsarti Name Sessions ---- -------- All 80 Day 1 -

    Mon 9 Day 2 - Tue 25 Day 3 - Wed 26 Day 4 - Thu 20 In the Cloud 8 Meal 9 Vendor 2 General 12 Bits and Bytes 14 Automate All the Things 17 OnRamp 3 PowerShell Language 17
  96. @glennsarti PS > gci 'Summit2019:\Agenda\Day 2 – Tue' | `

    Select-Object -First 5
  97. @glennsarti Directory: Summit2019:\Agenda\Day 2 - Tue Mode Name ---- ----

    . 61513 . 61461 . 61464 . 61475 . 61494 PS>
  98. @glennsarti PS > gci 'Summit2019:\Agenda\Day 2 – Tue' | `

    Select-Object -First 5 –Property *
  99. @glennsarti SSItemMode : . PSPath : SHiPS\SHiPS::PSSummitNA2019#Summit2019\Agenda\Day 2 - Tu

    PSParentPath : SHiPS\SHiPS::PSSummitNA2019#Summit2019\Agenda\Day 2 - Tu PSChildName : 61513 PSDrive : Summit2019 PSProvider : SHiPS\SHiPS PSIsContainer : False Id : 61513 Name : Breakfast Start : 30/04/2019 08:00:00 End : 30/04/2019 09:00:00 Location : Center Hall A Description : Join us for a hot breakfast. We'll have announcements SSItemMode : . PSPath : SHiPS\SHiPS::PSSummitNA2019#Summit2019\Agenda\Day 2 - Tu
  100. @glennsarti Step 5 Add content

  101. @glennsarti # VERY basic name splitting $NameArray = $this.Name -split

    " ", 2 $this.FirstName = $NameArray[0] $this.LastName = $NameArray[1] $this.Bio = Remove-HTML -RawString $data.overview } [string] GetContent() { return "# " + $this.Name + "`n`n## Bio`n`n" + $this.Bio } }
  102. @glennsarti $this.Name = $data.name $this.Description = Remove-HTML $data.overview $this.Start =

    ConvertFrom-EpochTime -Value $data.start_time $this.End = ConvertFrom-EpochTime -Value $data.end_time $this.Location = ($data.regions | Select-Object -First 1 | ForEach- } [string] GetContent() { return "### " + $this.name + "`n`n" + ` "Time:" + $this.Start.ToString('hh:mm tt') + ` " Location:" + $this.Location + "`n`n" + ` $this.Description + "`n`n" } }
  103. @glennsarti PS > Get-Content 'Summit2019:\Speakers\Glenn Sarti' # Glenn Sarti ##

    Bio I’m located in Perth (Western Australia) where I now work at Puppet as Senior Software Developer on the Windows team. Fro … PS >
  104. @glennsarti PS > Get-Content 'Summit2019:\Agenda\Day 2 - Tue\61451' ### Parselmouth

    - bending the PowerShell language Time:11:00 AM Location:406 I want to introduce the audience to the high-level design of the tokenizer, parser and compiler in PowerShell Core, and then take it a step … PS >
  105. @glennsarti Step 6 Add leaf connections

  106. @glennsarti Root Alice Session 2 Session 3 Day 1 All

    Speakers Agenda Bob Session 1
  107. @glennsarti Bob Session 1 ❌

  108. @glennsarti class Speaker : SHiPSLeaf { … [String[]]$SessionIDs; [String[]]$Sessions; [int]$NumSessions;

    [String[]]$SessionTimes; [void] PopulateFromData([Object]$data) { … $this.Sessions = @() $this.SessionIDs = @() $this.SessionTimes = @() Get-Sessions -Filter @{ 'Speaker' = $data.Id} | ForEach-Object { $this.Sessions += $_.name $start = (ConvertFrom-EpochTime -Value $_.start_time).ToString("d MMM, hh:mm tt") $this.SessionIDs += $_.id $this.SessionTimes += $start } $this.NumSessions = $this.Sessions.Count } …
  109. @glennsarti class Speaker : SHiPSLeaf { … [String[]]$SessionIDs; [String[]]$Sessions; [int]$NumSessions;

    [String[]]$SessionTimes; [void] PopulateFromData([Object]$data) { … $this.Sessions = @() $this.SessionIDs = @() $this.SessionTimes = @() Get-Sessions -Filter @{ 'Speaker' = $data.Id} | ForEach-Object { $this.Sessions += $_.name $start = (ConvertFrom-EpochTime -Value $_.start_time).ToString("d MMM, hh:mm tt") $this.SessionIDs += $_.id $this.SessionTimes += $start } $this.NumSessions = $this.Sessions.Count } …
  110. @glennsarti class AgendaSession : SHiPSLeaf { … [String[]]$Speakers AgendaSession([string]$id, $data):

    base($id) { … $this.Speakers = $this.Data.item_ids | ForEach-Object -Process { $SpeakerID = $_ Write-Output (Get-SpeakersObject).items | ` Where-Object { $_.id -eq $SpeakerId } | ` ForEach-Object { Write-Output $_.name } } } …
  111. @glennsarti class AgendaSession : SHiPSLeaf { … [String[]]$Speakers AgendaSession([string]$id, $data):

    base($id) { … $this.Speakers = $this.Data.item_ids | ForEach-Object -Process { $SpeakerID = $_ Write-Output (Get-SpeakersObject).items | ` Where-Object { $_.id -eq $SpeakerId } | ` ForEach-Object { Write-Output $_.name } } } …
  112. @glennsarti PS > gci 'Summit2019:\Speakers\Glenn Sarti' | Select * ...

    Name : Glenn Sarti FirstName : Glenn LastName : Sarti Bio : I’m located in Perth (Western Australia)… SessionIDs : {61496, 61497} Sessions : {Beyond Pester 102: Acceptance testing w… NumSessions : 2 SessionTimes : {30 Apr, 02:00 PM, 1 May, 11:00 AM}
  113. @glennsarti PS > gci 'Summit2019:\Agenda\Day 2 - Tue\61451' | Select

    * ... Id : 61451 Name : Parselmouth - bending the PowerShell lang… Start : 30/04/2019 11:00:00 End : 30/04/2019 11:45:00 Location : 406 Description : I want to introduce the audience to the … Speakers : Mathias Jessen
  114. @glennsarti Step 7 Make it pretty

  115. @glennsarti PS > Get-Help about_Format.ps1xml

  116. @glennsarti @{ RootModule = 'PSSummitNA2019.psm1’ ModuleVersion = '1.0’ GUID =

    '2e946999-7d90-4bfb-88f1-9336e3a01587’ Author = 'glenn.sarti’ CompanyName = 'Glenn Sarti’ Description = 'A PowerShell Provider for the Pow…’ # Modules that must be imported into the global … RequiredModules = @('SHiPS’) FormatsToProcess = @('PSSummitNA2019.Format.ps1xml') }
  117. @glennsarti PS > gci Summit2019:\Speakers | ` Select-Object –First 3

    | Format-Table Mode Name ---- ---- . James O'Neill . Christoph Bergmeister . Walter Legowski
  118. @glennsarti Name Session Times Bio ---- ------------- --- James O'Neill

    {2 May, 01:00 PM} James O'Neill spe… Christoph Bergmeister {30 Apr, 02:00 PM} I am a developer … Walter Legowski {1 May, 11:00 AM} ###**Walter Legow…
  119. @glennsarti PS > gci 'Summit2019:\Agenda\In the Cloud' | ` Sort-Object

    –Property Start | ` Select-Object –First 3 | Format-List Mode : . Name : 61464 Mode : . Name : 61501 Mode : . Name : 61466
  120. @glennsarti Id : 61464 Name : Introduction to Serverless Functions

    Start : 30/04/2019 09:00:00 Location : 405 Speakers : Kirk Munro Description : I've spent a lot of time working with server … Id : 61501 Name : Demystifying Microsoft's Cloud Automation products Start : 30/04/2019 11:00:00 Location : 405 Speakers : Jaap Brasser Description : Azure offers an evergrowing suite of produ … Id : 61466 Name : It’s PowerShell In the Cloud – Welcome to Azure Cloud Shell Start : 30/04/2019 13:00:00 Location : 405 Speakers : Michael Bender Description : As more organizations move towards the cloud and using Microsoft …
  121. @glennsarti What did I just see?

  122. @glennsarti • Start with some planning • Create the root

    object first • … then the Directories • … then the Leaves • Expand – Test – Iterate • Then make it pretty
  123. @glennsarti More please …

  124. @glennsarti Using an API

  125. @glennsarti

  126. @glennsarti Credentials

  127. @glennsarti PS> New-PSDrive -Name Github -PSProvider SHiPS ` -root 'Github#Root’

    ` -Credential (Get-Credential 'glennsarti') PowerShell credential request Enter your credentials. Password for user glennsarti: ********* The provider does not support the use of credentials. Perform the operation At line:1 char:1 + New-PSDrive -Name Github -PSProvider SHiPS -root 'Github#Root' -Crede ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotImplemented: (:) [], PSNotSupportedException + FullyQualifiedErrorId : NotSupported PS > ☹
  128. @glennsarti • Github Issue #110 • Environment Variables • Files

    / Registry • Anything outside of PS
  129. @glennsarti Runspaces

  130. @glennsarti Default Runspace PS>

  131. @glennsarti Default Runspace $Global:GithubToken Set-GitHubToken PS> Import-Module .\Github.psd1

  132. @glennsarti Default Runspace $Global:GithubToken Set-GitHubToken PS> Set-GitHubToken abc123 abc123

  133. @glennsarti Default Runspace $Global:GithubToken Set-GitHubToken PS> New-PSDrive –Name Github –Provider

    SHiPS … abc123 Drive Runspace $Global:GithubToken Set-GitHubToken
  134. @glennsarti Caching

  135. @glennsarti … for better navigation user experience … an author

    can decide to set UseCache to true, to cache data returned from Get-ChildItem to memory in the current PowerShell session. - SHiPS documentation [SHiPSProvider(UseCache=$true)] class Speaker : SHiPSLeaf {
  136. @glennsarti Set-Content, Filtering, Dynamic Parameters

  137. @glennsarti Set-Content 'Summit2019:\Speakers\Glenn Sarti' Set-Content

  138. @glennsarti PS > gci Summit2019:\Speakers –Filter Glenn* PS > gci

    Summit2019:\Speakers | ` Where-Object { $_.Name –like 'Glenn*'} Filtering
  139. @glennsarti PS > gci Summit2019:\Agenda\All | ` Where-Object { $_.Track

    –eq 'General' } PS > gci Summit2019:\Agenda –Track General PS > gci Summit2019:\Agenda –Day 2 PS > gci Summit2019:\Agenda –Speaker 'Glenn Sarti' … or combine them -Track General –Day 2 Dynamic Parameters
  140. @glennsarti See /samples/DynamicParameter for documentation

  141. @glennsarti Testing?

  142. @glennsarti Making SHiPS better

  143. @glennsarti Doesn’t support credentials Tiny supported cmdlet list Doesn’t support

    New, Remove, Rename, Move, Copy, *ItemProperty No Drive information within Provider Context
  144. @glennsarti SHiPS is still young

  145. @glennsarti Wrapping up…

  146. @glennsarti SHiPS is a UX module Start small and iterate

    Read the docs Remember the DAG
  147. THANK YOU! Please use the event app or Socio to

    submit a session rating! @glennsarti http://glennsarti.github.io/ https://speakerdeck.com/glennsarti https://github.com/glennsarti/PSSummitNA2019-Ships
  148. @glennsarti Resources Ravikanth Chaganti PS Conf EU 2018 - SHiPS:

    Walk-through a bare-metal system configuration https://github.com/psconfeu/2018/tree/master/Ravikanth%20Chaganti/SHiPS SHiPS GH Repo https://github.com/PowerShell/SHiPS SHiPS PS Gallery https://www.powershellgallery.com/packages/SHiPS https://www.powershellgallery.com/packages?q=ships about_format.ps1xml https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/ about_format.ps1xml?view=powershell-5.1
  149. @glennsarti Resources Writing a PowerShell Formatting File https://docs.microsoft.com/en-us/powershell/developer/format/ writing-a-powershell-formatting-file SHiPS

    Default formatting https://github.com/PowerShell/SHiPS/blob/master/src/Modules/SHiPS.formats.ps1xml Images https://unsplash.com