├── Assets ├── CompInfo.ps1 ├── MMS2019Demo.ps1 ├── Mod4Script1.ps1 ├── Mod4Script1CIM.ps1 ├── Mod4Script2.ps1 ├── Mod5Script1.ps1 ├── Mod5Script2.ps1 ├── Mod5Script3.ps1 ├── PowerShell7Module │ ├── demo.ps1 │ └── errorscript.ps1 ├── R_and_j.xml ├── SavillSite │ ├── JohnSavillsPSMC.jpg │ └── index.htm ├── SavillTechWebBase.ps1 ├── SavillTechWebNoKey.ps1 ├── SavillTechWebOnPrem.ps1 ├── SavillTechWebSFNoKey.ps1 ├── Signme.ps1 ├── Unattend.xml ├── addnumbers.ps1 └── junk.txt ├── CompInfo └── CompInfo.psm1 ├── PowerShellMCHandout.pdf ├── README.md ├── Sample.ps1 ├── VSCodeKeyboardSettings.json └── VSCodeSettingsSample.json /Assets/CompInfo.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Gets information about passed servers 4 | .DESCRIPTION 5 | Gets information about passed servers using WMI 6 | .PARAMETER computer 7 | Names of computers to scan 8 | .EXAMPLE 9 | CompInfo.ps1 host1, host2 10 | Not very interesting 11 | #> 12 | [cmdletbinding()] 13 | Param( 14 | [Parameter(ValuefromPipeline=$true,Mandatory=$true)][string[]]$computers) 15 | foreach ($computername in $computers) 16 | { 17 | Write-Verbose "Querying $computername" 18 | $lookinggood = $true 19 | try 20 | { 21 | $win32CSOut = Get-CimInstance -ClassName win32_computersystem -ComputerName $computername -ErrorAction Stop 22 | } 23 | catch 24 | { 25 | "Something bad: $_" 26 | $lookinggood = $false 27 | } 28 | if($lookinggood) 29 | { 30 | $win32OSOut = Get-CimInstance -ClassName win32_operatingsystem -ComputerName $computername 31 | Write-Debug "Finished querying $computername" 32 | 33 | $paramout = @{'ComputerName'=$computername; 34 | 'Memory'=$win32CSOut.totalphysicalmemory; 35 | 'Free Memory'=$win32OSOut.freephysicalmemory; 36 | 'Procs'=$win32CSOut.numberofprocessors; 37 | 'Version'=$win32OSOut.version} 38 | 39 | $outobj = New-Object -TypeName PSObject -Property $paramout 40 | Write-Output $outobj 41 | } 42 | else 43 | { 44 | Write-Error "Failed for $computername" 45 | } 46 | } -------------------------------------------------------------------------------- /Assets/MMS2019Demo.ps1: -------------------------------------------------------------------------------- 1 | #dir | sort from cmd.exe 2 | dir | Sort-Object -Descending 3 | dir | Sort-Object lastwritetime 4 | 5 | $PSVersionTable 6 | $IsWindows 7 | $IsLinux 8 | 9 | https://github.com/powershell/powershell 10 | iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI" #One line install 11 | 12 | #Install using Chocolatey 13 | Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) 14 | choco upgrade powershell-core 15 | 16 | #Check compatibility 17 | get-module -ListAvailable –SkipEditionCheck 18 | https://devblogs.microsoft.com/powershell/the-next-release-of-powershell-powershell-7/ #changing in next release 19 | 20 | #Compat module 21 | Get-eventlog #fails 22 | Install-Module WindowsCompatibility -Scope CurrentUser 23 | Import-WinModule Microsoft.PowerShell.Management 24 | Get-EventLog -Newest 5 -LogName “security“ 25 | Get-WinEvent -LogName security -MaxEvents 5 #native core options 26 | 27 | $c = get-command get-eventlog 28 | $c 29 | $c.definition 30 | get-pssession #see the wincompat session to local 31 | 32 | #GIT config 33 | git config --global user.email "john@savilltech.com“ 34 | git config --global user.name "johnthebrit“ 35 | git config --list -------------------------------------------------------------------------------- /Assets/Mod4Script1.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [string]$computername='savazuusscdc01') 3 | Get-WmiObject -class win32_computersystem ` 4 | -ComputerName $computername | 5 | fl numberofprocessors,totalphysicalmemory 6 | -------------------------------------------------------------------------------- /Assets/Mod4Script1CIM.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [string]$computername='savazuusscdc01') 3 | Get-CimInstance -ClassName win32_computersystem ` 4 | -ComputerName $computername | 5 | fl numberofprocessors,totalphysicalmemory 6 | -------------------------------------------------------------------------------- /Assets/Mod4Script2.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory=$true)][string[]]$computers) 3 | foreach ($computername in $computers) 4 | { 5 | $win32CSOut = Get-CimInstance -ClassName win32_computersystem -ComputerName $computername 6 | $win32OSOut = Get-CimInstance -ClassName win32_operatingsystem -ComputerName $computername 7 | 8 | $paramout = @{'ComputerName'=$computername; 9 | 'Memory'=$win32CSOut.totalphysicalmemory; 10 | 'Free Memory'=$win32OSOut.freephysicalmemory; 11 | 'Procs'=$win32CSOut.numberofprocessors; 12 | 'Version'=$win32OSOut.version} 13 | 14 | $outobj = New-Object -TypeName PSObject -Property $paramout 15 | Write-Output $outobj 16 | } 17 | -------------------------------------------------------------------------------- /Assets/Mod5Script1.ps1: -------------------------------------------------------------------------------- 1 | Write-Host 'Number of arguments was :' ($args.Length) 2 | Write-Output 'and they were:' 3 | foreach($arg in $args) 4 | { 5 | Write-Output $arg 6 | } -------------------------------------------------------------------------------- /Assets/Mod5Script2.ps1: -------------------------------------------------------------------------------- 1 | Param([Parameter(Mandatory=$True,Position=2)][String]$Name, 2 | [Parameter(Mandatory=$True,Position=1)][String]$Greeting) 3 | Write-Host $Greeting $Name 4 | -------------------------------------------------------------------------------- /Assets/Mod5Script3.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [Parameter(Mandatory=$true)][string]$computername,[switch]$showlogprocs) 3 | if($showlogprocs) 4 | { 5 | Get-CimInstance -class win32_computersystem -ComputerName $computername ` 6 | | fl NumberOfLogicalProcessors,totalphysicalmemory 7 | } 8 | else 9 | { 10 | Get-CimInstance -class win32_computersystem -ComputerName $computername ` 11 | | fl numberofprocessors,totalphysicalmemory 12 | } 13 | -------------------------------------------------------------------------------- /Assets/PowerShell7Module/demo.ps1: -------------------------------------------------------------------------------- 1 | $localpath = "C:\Users\john\OneDrive\projects\PowerShellMC\Assets\PowerShell7Module" 2 | $localpath = "C:\Users\JohnSavill\Documents\Projects\PowerShellMC\Assets\PowerShell7Module" 3 | 4 | #Improved compatibility 5 | start-process notepad 6 | get-process | out-gridview -PassThru | stop-process 7 | start-process notepad 8 | Set-Clipboard -Value "Hello from PowerShell" #past into notepad then change notepad and copy 9 | Get-Clipboard 10 | 11 | #Module compatibility 12 | Get-pssession 13 | import-module azuread -UseWindowsPowerShell 14 | Get-pssession 15 | Get-module 16 | $c = get-command connect-azuread -module azuread 17 | $c 18 | $c.definition 19 | 20 | #foreach -parallel 21 | $nums=(1..10) 22 | Measure-Command {$nums | ForEach-Object {start-sleep -s 1}} 23 | Measure-Command {$nums | ForEach-Object -parallel {start-sleep -s 1} -ThrottleLimit 10 } 24 | 25 | #Ternary operator 26 | $path = "c:\dontfind" 27 | (Test-Path $path) ? "Path exists" : "Path not found" 28 | $path = "c:\windows" 29 | (Test-Path $path) ? "Path exists" : "Path not found" 30 | 31 | #Pipeline chain 32 | Write-Output 'Hello' && Write-Output 'World' 33 | Write-Error 'Hello' && Write-Output 'World' 34 | Write-Error 'Hello' || Write-Output 'World' 35 | Write-Output 'Hello' || Write-Output 'World' 36 | 37 | #null-coalescing 38 | $answer = $null 39 | $answer ?? 42 40 | 41 | $answer = "PowerShell" 42 | $answer ?? 42 43 | #can perform actions as well! 44 | {get-module -ListAvailable AzureAD} ?? {Install-Module AzureAD} 45 | 46 | 47 | $answer = $null 48 | $answer ??= 42 49 | $answer 50 | 51 | $answer = "PowerShell" 52 | $answer ??= 42 53 | $answer 54 | #member access 55 | Enable-ExperimentalFeature PSNullConditionalOperators #and restart powershell 56 | Get-ExperimentalFeature 57 | #start notepad 58 | start-process notepad 59 | $process = Get-Process -Name notepad 60 | ${process}?.id 61 | get-process notepad | Stop-Process 62 | $process = Get-Process -Name notepad 63 | ${process}?.id #won't even try to access the member since the object is null 64 | #element access 65 | $numbers = 1..10 66 | ${numbers}?[0] 67 | $numbers = $null 68 | ${numbers}?[0] #once again won't try to access 69 | 70 | #Better error messages 71 | Get-Childitem -Path c:\nothere 72 | ."$localpath\errorscript.ps1" 73 | -------------------------------------------------------------------------------- /Assets/PowerShell7Module/errorscript.ps1: -------------------------------------------------------------------------------- 1 | Write-Output "This is my error script" 2 | Get-ChildItem c:\wontfindanywherehere -------------------------------------------------------------------------------- /Assets/SavillSite/JohnSavillsPSMC.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnthebrit/PowerShellMC/c4147f1998d6ccd5ace433afee3b8616e32c1fca/Assets/SavillSite/JohnSavillsPSMC.jpg -------------------------------------------------------------------------------- /Assets/SavillSite/index.htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 |

11 |

12 | -------------------------------------------------------------------------------- /Assets/SavillTechWebBase.ps1: -------------------------------------------------------------------------------- 1 | configuration WebConfig 2 | { 3 | Node IsWebServer 4 | { 5 | WindowsFeature IIS 6 | { 7 | Ensure = 'Present' 8 | Name = 'Web-Server' 9 | IncludeAllSubFeature = $true 10 | } 11 | } 12 | 13 | Node NotWebServer 14 | { 15 | WindowsFeature IIS 16 | { 17 | Ensure = 'Absent' 18 | Name = 'Web-Server' 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /Assets/SavillTechWebNoKey.ps1: -------------------------------------------------------------------------------- 1 |  2 | Set-ExecutionPolicy unrestricted -Force 3 | 4 | Enable-PSRemoting -Force 5 | 6 | # uses http://gallery.technet.microsoft.com/scriptcenter/xWebAdministration-Module-3c8bb6be 7 | 8 | #Copy the modules to the folder 9 | $username = "savillmasterazurestore" 10 | $password = convertto-securestring -String "R6yw==" -AsPlainText -Force 11 | $cred = new-object -typename System.Management.Automation.PSCredential ` 12 | -argumentlist $username, $password 13 | 14 | New-PSDrive –Name T –PSProvider FileSystem –Root “\\savillmasterazurestore.file.core.windows.net\tools” -Credential $cred 15 | Copy-Item -Path "T:\DSC\xWebAdministration" -Destination $env:ProgramFiles\WindowsPowerShell\Modules -Recurse 16 | Remove-PSDrive -Name T 17 | 18 | Configuration SavillTechWebsite 19 | { 20 | param 21 | ( 22 | # Target nodes to apply the configuration 23 | [string[]]$NodeName = 'localhost' 24 | ) 25 | # Import the module that defines custom resources 26 | Import-DscResource -Module xWebAdministration 27 | Node $NodeName 28 | { 29 | # Install the IIS role 30 | WindowsFeature IIS 31 | { 32 | Ensure = "Present" 33 | Name = "Web-Server" 34 | } 35 | #Install ASP.NET 4.5 36 | WindowsFeature ASPNet45 37 | { 38 | Ensure = “Present” 39 | Name = “Web-Asp-Net45” 40 | } 41 | # Stop the default website 42 | xWebsite DefaultSite 43 | { 44 | Ensure = "Present" 45 | Name = "Default Web Site" 46 | State = "Stopped" 47 | PhysicalPath = "C:\inetpub\wwwroot" 48 | DependsOn = "[WindowsFeature]IIS" 49 | } 50 | # Copy the website content 51 | File WebContent 52 | { 53 | Ensure = "Present" 54 | SourcePath = "C:\Program Files\WindowsPowerShell\Modules\xWebAdministration\SavillSite" 55 | DestinationPath = "C:\inetpub\SavillSite" 56 | Recurse = $true 57 | Type = "Directory" 58 | DependsOn = "[WindowsFeature]AspNet45" 59 | } 60 | # Create a new website 61 | xWebsite SavTechWebSite 62 | { 63 | Ensure = "Present" 64 | Name = "SavillSite" 65 | State = "Started" 66 | PhysicalPath = "C:\inetpub\SavillSite" 67 | DependsOn = "[File]WebContent" 68 | } 69 | } 70 | } 71 | 72 | SavillTechWebsite -MachineName localhost 73 | 74 | Start-DscConfiguration -Path .\SavillTechWebsite -Wait -Verbose -------------------------------------------------------------------------------- /Assets/SavillTechWebOnPrem.ps1: -------------------------------------------------------------------------------- 1 |  2 | #Set-ExecutionPolicy unrestricted -Force 3 | #Enable-PSRemoting -Force 4 | 5 | #uses https://www.powershellgallery.com/packages/xWebAdministration/2.4.0.0 6 | Install-Module -Name xWebAdministration 7 | 8 | Configuration SavillTechWebsite 9 | { 10 | param 11 | ( 12 | # Target nodes to apply the configuration 13 | [string[]]$NodeName = 'localhost' 14 | ) 15 | Import-DscResource –ModuleName 'PSDesiredStateConfiguration' 16 | # Import the module that defines custom resources 17 | Import-DscResource -Module xWebAdministration 18 | Node $NodeName 19 | { 20 | # Install the IIS role 21 | WindowsFeature IIS 22 | { 23 | Ensure = "Present" 24 | Name = "Web-Server" 25 | } 26 | #Install ASP.NET 4.5 27 | WindowsFeature ASPNet45 28 | { 29 | Ensure = “Present” 30 | Name = “Web-Asp-Net45” 31 | } 32 | # Stop the default website 33 | xWebsite DefaultSite 34 | { 35 | Ensure = "Present" 36 | Name = "Default Web Site" 37 | State = "Stopped" 38 | PhysicalPath = "C:\inetpub\wwwroot" 39 | DependsOn = "[WindowsFeature]IIS" 40 | } 41 | # Copy the website content 42 | File WebContent 43 | { 44 | Ensure = "Present" 45 | SourcePath = "C:\Source\SavillSite" 46 | DestinationPath = "C:\inetpub\SavillSite" 47 | Recurse = $true 48 | Type = "Directory" 49 | DependsOn = "[WindowsFeature]AspNet45" 50 | } 51 | # Create a new website 52 | xWebsite SavTechWebSite 53 | { 54 | Ensure = "Present" 55 | Name = "SavillSite" 56 | State = "Started" 57 | PhysicalPath = "C:\inetpub\SavillSite" 58 | DependsOn = "[File]WebContent" 59 | } 60 | } 61 | } 62 | 63 | #Create the MOF 64 | SavillTechWebsite -NodeName localhost 65 | 66 | #Apply the configuration 67 | Start-DscConfiguration -Path .\SavillTechWebsite -Wait -Verbose 68 | 69 | #Test 70 | $IE=new-object -com internetexplorer.application 71 | $IE.navigate2("127.0.0.1") 72 | $IE.visible=$true 73 | 74 | #View the configuration 75 | Get-DscConfiguration 76 | 77 | #Remove if wanted but does not roll back the changes 78 | Remove-DscConfigurationDocument -Stage Current 79 | Remove-WindowsFeature -Name Web-Server 80 | Remove-Item -Path C:\inetpub\*.* -Recurse -Force -------------------------------------------------------------------------------- /Assets/SavillTechWebSFNoKey.ps1: -------------------------------------------------------------------------------- 1 | $hostname = (hostname).ToUpper() 2 | 3 | Write-Verbose -Verbose:$true "[$hostname] Starting the node configuration" 4 | 5 | #Set-ExecutionPolicy unrestricted -Force #This is set automatically when called by Azure script extension 6 | 7 | Write-Verbose -Verbose:$true "[$hostname] Enabling Remoting" 8 | 9 | Enable-PSRemoting -Force 10 | 11 | # uses http://gallery.technet.microsoft.com/scriptcenter/xWebAdministration-Module-3c8bb6be 12 | 13 | Write-Verbose -Verbose:$true "[$hostname] Copying content from Azure Files to PowerShell Modules path" 14 | 15 | #Copy the modules to the folder 16 | $username = "savillmasterazurestore" 17 | $password = convertto-securestring -String "R6yw==" -AsPlainText -Force 18 | $cred = new-object -typename System.Management.Automation.PSCredential ` 19 | -argumentlist $username, $password 20 | 21 | New-PSDrive –Name T –PSProvider FileSystem –Root “\\savillmasterazurestore.file.core.windows.net\tools” -Credential $cred 22 | Copy-Item -Path "T:\DSC\xWebAdministration" -Destination $env:ProgramFiles\WindowsPowerShell\Modules -Recurse 23 | Remove-PSDrive -Name T 24 | 25 | Write-Verbose -Verbose:$true "[$hostname] Applying DSC Configuration" 26 | 27 | $configString=@" 28 | Configuration SavillTechWebsite 29 | { 30 | param 31 | ( 32 | # Target nodes to apply the configuration 33 | [string[]]`$NodeName = `'localhost`' 34 | ) 35 | # Import the module that defines custom resources 36 | Import-DscResource -Module xWebAdministration 37 | Node `$NodeName 38 | { 39 | # Install the IIS role 40 | WindowsFeature IIS 41 | { 42 | Ensure = `"Present`" 43 | Name = `"Web-Server`" 44 | } 45 | #Install ASP.NET 4.5 46 | WindowsFeature ASPNet45 47 | { 48 | Ensure = `“Present`” 49 | Name = `“Web-Asp-Net45`” 50 | } 51 | # Stop the default website 52 | xWebsite DefaultSite 53 | { 54 | Ensure = `"Present`" 55 | Name = `"Default Web Site`" 56 | State = `"Stopped`" 57 | PhysicalPath = `"C:\inetpub\wwwroot`" 58 | DependsOn = `"[WindowsFeature]IIS`" 59 | } 60 | # Copy the website content 61 | File WebContent 62 | { 63 | Ensure = `"Present`" 64 | SourcePath = `"C:\Program Files\WindowsPowerShell\Modules\xWebAdministration\SavillSite`" 65 | DestinationPath = `"C:\inetpub\SavillSite`" 66 | Recurse = `$true 67 | Type = `"Directory`" 68 | DependsOn = `"[WindowsFeature]AspNet45`" 69 | } 70 | # Create a new website 71 | xWebsite SavTechWebSite 72 | { 73 | Ensure = '"Present`" 74 | Name = `"SavillSite`" 75 | State = `"Started`" 76 | PhysicalPath = `"C:\inetpub\SavillSite`" 77 | DependsOn = `"[File]WebContent`" 78 | } 79 | } 80 | } 81 | "@ 82 | Invoke-Expression $configString 83 | 84 | 85 | SavillTechWebsite -MachineName localhost 86 | 87 | Start-DscConfiguration -Path .\SavillTechWebsite -Wait -Verbose -------------------------------------------------------------------------------- /Assets/Signme.ps1: -------------------------------------------------------------------------------- 1 | Write-Output "Hello World" 2 | -------------------------------------------------------------------------------- /Assets/Unattend.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | UABhADUANQB3AAcgBkAA== 8 | false</PlainText> 9 | </AdministratorPassword> 10 | </UserAccounts> 11 | </component> 12 | </settings> 13 | <settings pass="offlineServicing"> 14 | <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS"> 15 | <ComputerName>NanoVM2</ComputerName> 16 | </component> 17 | </settings> 18 | </unattend> -------------------------------------------------------------------------------- /Assets/addnumbers.ps1: -------------------------------------------------------------------------------- 1 | function Add-Numbers { 2 | Param( 3 | [int[]]$Numbers 4 | ) 5 | $Total = [int]0 6 | foreach($Number in $Numbers) { 7 | $Total += $Number 8 | } 9 | return $Total 10 | } 11 | 12 | $PizzasEaten = [int]0 13 | 14 | $PizzasEaten = Add-Numbers(2,5,10) 15 | 16 | $Message = "Pizzas so far $PizzasEaten" 17 | Write-Output $Message 18 | 19 | $PizzasEaten = Add-Numbers($PizzasEaten,3) 20 | 21 | $Message = "Final pizzas eaten $PizzasEaten" 22 | Write-Output $Message -------------------------------------------------------------------------------- /Assets/junk.txt: -------------------------------------------------------------------------------- 1 | test 2 | test5432 3 | this is a test 4 | another test 5 | 6 | 7 | 8 | 47 57.36 81.54 8.75 8972 1 ShellExperienceHost 9 | 22 12.65 30.75 34.34 6648 1 sihost 10 | 91 82.95 69.79 8.63 14588 1 Snagit32 11 | 105 142.49 192.52 33.16 15248 1 SnagitEditor 12 | 22 27.23 29.95 0.00 92 0 svchost 13 | 31 15.34 21.26 0.00 896 0 svchost 14 | 0 0.21 10.61 0.00 4 0 System 15 | 123 433.39 403.68 171.45 1744 1 Teams 16 | 67 90.54 109.45 103.28 10348 1 Teams 17 | 86 187.23 141.50 105.97 16772 1 Todo 18 | 75 69.60 4.23 1.55 13912 1 WinStore.App -------------------------------------------------------------------------------- /CompInfo/CompInfo.psm1: -------------------------------------------------------------------------------- 1 | function Get-CompInfo 2 | { 3 | <# 4 | .SYNOPSIS 5 | Gets information about passed servers 6 | .DESCRIPTION 7 | Gets information about passed servers using WMI 8 | .PARAMETER computer 9 | Names of computers to scan 10 | .EXAMPLE 11 | CompInfo.ps1 host1, host2 12 | Not very interesting 13 | #> 14 | [cmdletbinding()] 15 | Param( 16 | [Parameter(ValuefromPipeline=$true,Mandatory=$true)][string[]]$computers) 17 | foreach ($computername in $computers) 18 | { 19 | Write-Verbose "Querying $computername" 20 | $lookinggood = $true 21 | try 22 | { 23 | $win32CSOut = Get-CimInstance -ClassName win32_computersystem -ComputerName $computername -ErrorAction Stop 24 | } 25 | catch 26 | { 27 | "Something bad: $_" 28 | $lookinggood = $false 29 | } 30 | if($lookinggood) 31 | { 32 | $win32OSOut = Get-CimInstance -ClassName win32_operatingsystem -ComputerName $computername 33 | Write-Debug "Finished querying $computername" 34 | 35 | $paramout = @{'ComputerName'=$computername; 36 | 'Memory'=$win32CSOut.totalphysicalmemory; 37 | 'Free Memory'=$win32OSOut.freephysicalmemory; 38 | 'Procs'=$win32CSOut.numberofprocessors; 39 | 'Version'=$win32OSOut.version} 40 | 41 | $outobj = New-Object -TypeName PSObject -Property $paramout 42 | Write-Output $outobj 43 | } 44 | else 45 | { 46 | Write-Output "Failed for $computername" 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /PowerShellMCHandout.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/johnthebrit/PowerShellMC/c4147f1998d6ccd5ace433afee3b8616e32c1fca/PowerShellMCHandout.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PowerShell Master Class GitHub Repo 2 | ## PowerShell Master Class Assets 3 | 4 | All content Copyright 2019 John Savill. All rights reserved 5 | No part of this course to be used without express permission from the author 6 | john@savilltech.com 7 | @NTFAQGuy 8 | https://savilltech.com 9 | https://youtube.com/NTFAQGuy 10 | 11 | YouTube Playlist for the videos that these materials are for - https://www.youtube.com/playlist?list=PLlVtbbG169nFq_hR7FcMYg32xsSAObuq8 12 | 13 | | Module | Additional References | 14 | |--|--| 15 | | [1 PowerShell Fundamentals](https://youtu.be/sQm4zRvvX58) | | 16 | | [2 Connecting Commands](https://youtu.be/K_LsLq5yGgk) | | 17 | | [3 Remote Management](https://youtu.be/PMRkM9jlMMw) | | 18 | | [Getting ready for DevOps](https://youtu.be/yavDKHV-OOI) | | 19 | | [4 Creating a PowerShell Script](https://youtu.be/sQm4zRvvX58) |[Azure PowerShell](https://youtu.be/RQMdJ-9-lxY) <br> [Using Try-Catch](https://youtu.be/2eByC9N1xIQ) <br>[Debug PowerShell](https://youtu.be/2cpU82i6YPU)| 20 | | [5 Advanced Scripting](https://youtu.be/BVU7MxlyMmA) | | 21 | | [6 Data and Objects](https://youtu.be/Bmsa6F69afA) | | 22 | | [7 Desired State Configuration](https://youtu.be/D-jmIk4xaWw) | | 23 | | [8 Automation Technologies](https://youtu.be/n2dlNA3Z-mc) | [Azure Functions with PowerShell](https://youtu.be/fIycfLlgph0) <br> [Azure Functions with PowerShell 2](https://youtu.be/0e2WlHCulZE)| 24 | | [PowerShell 7](https://youtu.be/K9EUntTP7jM) | | 25 | 26 | ## Getting a Clone 27 | Once Git is installed to have a local clone of the repository: 28 | 29 | ```sh 30 | New-Item -ItemType Directory -Path C:\PowerShellMC 31 | cd c:\PowerShellMC 32 | git clone https://github.com/johnthebrit/PowerShellMC.git . 33 | ``` 34 | 35 | To update, make sure you are in the folder downloaded to and run 36 | 37 | ```sh 38 | git pull 39 | ``` 40 | 41 | ## Useful Links and Info 42 | 43 | | Feature | Link | 44 | |---------------------|-------------------------------------------| 45 | | PowerShell Core | https://github.com/powershell/powershell | 46 | | Visual Studio Code | https://code.visualstudio.com/Download | 47 | | Git | https://git-scm.com/downloads | 48 | 49 | Chocolatey Install 50 | 51 | ```sh 52 | Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')) 53 | ``` 54 | 55 | Chocolately PowerShell Core upgrade - 56 | 57 | ```sh 58 | Choco outdated 59 | Choco upgrade powershell-core 60 | ``` 61 | 62 | ## References 63 | 64 | Windows PowerShell Compatibility - https://github.com/PowerShell/WindowsCompatibility 65 | 66 | Installing PowerShell Core on Ubuntu - https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-6#ubuntu-1804 67 | 68 | Installing VS Core on Ubuntu - https://linuxize.com/post/how-to-install-visual-studio-code-on-ubuntu-18-04/ 69 | https://www.ubuntu18.com/install-visual-studio-code-ubuntu-18/ 70 | 71 | Setting up SSH - https://docs.microsoft.com/en-us/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-6 72 | 73 | Secrets of PowerShell Remoting eBook - https://leanpub.com/secretsofpowershellremoting 74 | -------------------------------------------------------------------------------- /Sample.ps1: -------------------------------------------------------------------------------- 1 | #region Module 1 - PowerShell Fundamentals 2 | 3 | #Basic Pipeline 4 | dir | Sort-Object -Descending 5 | 6 | dir | Sort-Object lastwritetime 7 | 8 | dir | sort-object –descending –property lastwritetime 9 | 10 | #To show the object types being passed 11 | dir | foreach {"$($_.GetType().fullname) - $_.name"} #lazy quick version using alias 12 | Get-ChildItem | ForEach-Object {"$($_.GetType().fullname) - $_.name"} #Proper script version 13 | 14 | #Modules 15 | Get-Module #to see those loaded 16 | Get-Module –listavailable #to see all available 17 | Import-Module <module> #to add into PowerShell instance 18 | Get-Command –Module <module> #to list commands in a module 19 | Get-Command -Module <module> | Select-Object -Unique Noun | Sort-Object Noun 20 | Get-Command -Module <module> | Select -Unique Noun | Sort Noun #Lazy version :-) 21 | 22 | (Get-Module <module name>).Version #make sure module has been imported first or will not get output 23 | (Get-Module az.compute).Version 24 | Install-Module Az 25 | Update-Module Az 26 | 27 | 28 | #Help 29 | Get-Command –Module <module> 30 | Get-Command –Noun <noun> 31 | Update-Help 32 | 33 | #Hello World 34 | Write-Output "Hello World" 35 | 36 | #Hello Universe 37 | Write-Output "Hello Universe" 38 | 39 | #Use a variable 40 | $name = "John" 41 | Write-Output "Hello $name" 42 | 43 | #Use an environment variable 44 | Write-Output "Hello $env:USERNAME" 45 | 46 | #endregion 47 | 48 | 49 | #region Module 2 - Connecting Commands 50 | 51 | #Looking at variable type 52 | notepad 53 | $proc = Get-Process –name notepad 54 | $proc.GetType().fullname 55 | $proc | Get-Member 56 | 57 | get-process | Where-Object {$_.handles -gt 900} | Sort-Object -Property handles | 58 | ft name, handles -AutoSize 59 | 60 | #Must be elevated 61 | Get-WinEvent -LogName security -MaxEvents 10 | Select-Object -Property Id, TimeCreated, Message | 62 | Sort-Object -Property TimeCreated | convertto-html | out-file c:\sec.html 63 | 64 | $xml = [xml](get-content .\R_and_j.xml) 65 | $xml.PLAY 66 | $xml.PLAY.ACT 67 | $xml.PLAY.ACT[0].SCENE[0].SPEECH 68 | $xml.PLAY.ACT.SCENE.SPEECH | Group-Object speaker | Sort-Object count 69 | 70 | 71 | #Output to file 72 | Get-Process > procs.txt 73 | Get-Process | Out-File procs.txt #what is really happening 74 | get-process | Export-csv c:\stuff\proc.csv 75 | get-process | Export-clixml c:\stuff\proc.xml 76 | 77 | #Limiting objects returned 78 | Get-Process | Sort-Object -Descending -Property StartTime | Select-Object -First 5 79 | Get-Process | Measure-Object 80 | Get-Process | Measure-Object WS -Sum 81 | 82 | #PowerShell Core or Windows PowerShell 83 | Get-WinEvent -LogName security -MaxEvents 5 84 | Invoke-Command -ComputerName savazuusscdc01, savazuusedc01 ` 85 | -ScriptBlock {get-winevent -logname security -MaxEvents 5} 86 | 87 | #Windows PowerShell only 88 | Get-EventLog -LogName Security -newest 10 89 | Invoke-command -ComputerName savdaldc01,savdalfs01,localhost ` 90 | -ScriptBlock {Get-EventLog -LogName Security -newest 10} 91 | 92 | 93 | #Comparing 94 | get-process | Export-csv d:\temp\proc.csv 95 | Compare-Object -ReferenceObject (Import-Csv d:\temp\proc.csv) -DifferenceObject (Get-Process) -Property Name 96 | 97 | notepad 98 | $procs = get-process 99 | get-process -Name notepad | Stop-Process 100 | $procs2 = get-process 101 | Compare-Object -ReferenceObject $procs -DifferenceObject $procs2 -Property Name 102 | 103 | 104 | # -confirm and -whatif 105 | get-aduser -filter * | Remove-ADUser -whatif 106 | 107 | Get-ADUser -Filter * -Properties "LastLogonDate" ` 108 | | where {$_.LastLogonDate -le (Get-Date).AddDays(-60)} ` 109 | | sort-object -property lastlogondate -descending ` 110 | | Format-Table -property name, lastlogondate -AutoSize 111 | 112 | Get-ADUser -Filter * -Properties "LastLogonDate" ` 113 | | where {$_.LastLogonDate -le (Get-Date).AddDays(-60)} ` 114 | | sort-object -property lastlogondate -descending ` 115 | | Disable-ADAccount -WhatIf 116 | 117 | $ConfirmPreference = "medium" 118 | notepad 119 | Get-Process | where {$_.name –eq "notepad"} | Stop-Process 120 | notepad 121 | get-process | where {$_.name -eq "notepad"} | stop-process -confirm:$false 122 | $ConfirmPreference = "high" 123 | Get-Process | where {$_.name –eq "notepad"} | Stop-Process 124 | 125 | 126 | #Using $_ 127 | 128 | Get-Process | Where-Object {$_.name –eq "notepad"} | Stop-Process 129 | 130 | #Simply notation 131 | Get-Process | where {$_.HandleCount -gt 900} 132 | Get-Process | where {$psitem.HandleCount -gt 900} 133 | Get-Process | where HandleCount -gt 900 134 | Get-Process | ? HandleCount -gt 900 135 | 136 | 137 | $UnattendFile = "unattend.xml" 138 | $xml = [xml](gc $UnattendFile) 139 | $child = $xml.CreateElement("TimeZone", $xml.unattend.NamespaceURI) 140 | $child.InnerXml = "Central Standard Time" 141 | $null = $xml.unattend.settings.Where{($_.Pass -eq 'oobeSystem')}.component.appendchild($child) 142 | #$xml.Save($UnattendFile) 143 | $xml.InnerXml 144 | 145 | $resources = Get-AzResourceProvider -ProviderNamespace Microsoft.Compute 146 | $resources.ResourceTypes.Where{($_.ResourceTypeName -eq 'virtualMachines')}.Locations 147 | 148 | 149 | #endregion 150 | 151 | 152 | #region Module 3 - Remote Management 153 | 154 | #enabling WinRM and PS Remoting 155 | Enable-PSRemoting 156 | 157 | Invoke-Command -ComputerName savazuusscdc01 {$env:computername} 158 | Invoke-Command -ComputerName savazuusscds01 {$var=10} 159 | Invoke-Command -ComputerName savazuusscds01 {$var} 160 | 161 | #Filter on remote and perform actions or strange results 162 | Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock {get-eventlog -logname security} | select-object -First 10 163 | Invoke-command -computername savazuusscdc01 -scriptblock {get-eventlog -logname security | select-object -first 10} 164 | Invoke-command -computername savazuusscdc01 -scriptblock {get-eventlog -logname security -newest 10} 165 | 166 | Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock {get-process} | where {$_.name -eq "notepad"} | Stop-Process 167 | Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock {get-process | where {$_.name -eq "notepad"} | Stop-Process } 168 | 169 | Measure-Command {Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock {get-process} | where {$_.name -eq "notepad"} } 170 | Measure-Command {Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock {get-process | where {$_.name -eq "notepad"}} } 171 | 172 | 173 | #Sessions 174 | $session = New-PSSession -ComputerName savazuusscds01 175 | Invoke-Command -SessionName $session {$var=10} 176 | Invoke-Command -SessionName $session {$var} 177 | Enter-PSSession -Session $session #also interactive 178 | Get-PSSession 179 | $session | Remove-PSSession 180 | 181 | #Multiple machines 182 | $dcs = "savazuusedc01", "savazuusscdc01" 183 | Invoke-Command -ComputerName $dcs -ScriptBlock {$env:computername} 184 | $sess = New-PSSession -ComputerName $dcs 185 | $sess 186 | icm –session $sess –scriptblock {$env:computername} 187 | 188 | #Implicit remoting 189 | $adsess = New-PSSession -ComputerName savazuusscdc01 190 | Import-Module -Name ActiveDirectory -PSSession $adsess 191 | Get-Module #type different from the type on the actual DC 192 | Get-Command -Module ActiveDirectory #functions instead of cmdlets 193 | Get-ADUser -Filter * 194 | $c = Get-Command Get-ADUser 195 | $c.Definition 196 | Remove-Module ActiveDirectory 197 | Import-Module -Name ActiveDirectory -PSSession $adsess -Prefix OnDC 198 | Get-Command -Module ActiveDirectory 199 | Get-OnDCADUser -Filter * #I don't have regular Get-ADUser anymore 200 | 201 | #Execution operator & 202 | $comm = "get-process" 203 | $comm #Nope 204 | &$comm #Yep! 205 | 206 | 207 | #PowerShell Core Compatibility with Windows PowerShell modules 208 | get-module -ListAvailable -SkipEditionCheck 209 | Get-EventLog #Fails in PowerShell Core 210 | Install-Module WindowsCompatibility -Scope CurrentUser 211 | Import-WinModule Microsoft.PowerShell.Management 212 | Get-EventLog -Newest 5 -LogName "security" 213 | #Behind the scenes 214 | $c = Get-Command get-eventlog 215 | $c 216 | $c.definition 217 | Get-PSSession #Note the WinCompat session to local machine 218 | 219 | 220 | #Alternate endpoint 221 | Enable-WSManCredSSP -Role "Server" -Force 222 | New-PSSessionConfigurationFile –ModulesToImport OneTech, ActiveDirectory, Microsoft.PowerShell.Utility ` 223 | –VisibleCmdLets ('*OneTech*','*AD*','format*','get-help') ` 224 | -VisibleFunctions ('TabExpansion2') -VisibleAliases ('exit','ft','fl') –LanguageMode ConstrainedLanguage ` 225 | -VisibleProviders FileSystem ` 226 | –SessionType ‘RestrictedRemoteServer’ –Path ‘c:\dcmonly.pssc’ 227 | Register-PSSessionConfiguration -Name "DCMs" -Path C:\dcmonly.pssc -StartupScript C:\PSData\DCMProd.ps1 228 | 229 | $pssc = Get-PSSessionConfiguration -Name "DCMs" 230 | $psscSd = New-Object System.Security.AccessControl.CommonSecurityDescriptor($false, $false, $pssc.SecurityDescriptorSddl) 231 | 232 | $Principal = "savilltech\DCMs" 233 | $account = New-Object System.Security.Principal.NTAccount($Principal) 234 | $accessType = "Allow" 235 | $accessMask = 268435456 236 | $inheritanceFlags = "None" 237 | $propagationFlags = "None" 238 | $psscSd.DiscretionaryAcl.AddAccess($accessType,$account.Translate([System.Security.Principal.SecurityIdentifier]),$accessMask,$inheritanceFlags,$propagationFlags) 239 | Set-PSSessionConfiguration -Name "DCMs" -SecurityDescriptorSddl $psscSd.GetSddlForm("All") -Force 240 | #Set-PSSessionConfiguration -Name "DCMs" -ShowSecurityDescriptorUI 241 | Restart-Service WinRM 242 | 243 | 244 | #Enabling HTTPS 245 | Winrm create winrm/config/Listener?Address=*+Transport=HTTPS @{Hostname="host";CertificateThumbprint="thumbprint"} 246 | #e.g. 247 | cd Cert:\LocalMachine\My 248 | Get-ChildItem #or ls remember. Find the thumbprint you want 249 | winrm create winrm/config/listener?address=*+Transport=HTTPS @{Hostname="savazuusscdc01.savilltech.net";CertificateThumbprint="B4B3FAE3F30944617E477F77756D6ABCB9980E38"} 250 | New-NetFirewallRule -DisplayName "Windows Remote Management (HTTPS-In)" -Name "Windows Remote Management (HTTPS-In)" -Profile Any -LocalPort 5986 -Protocol TCP 251 | 252 | #To view - must be elevated 253 | winrm enumerate winrm/config/Listener 254 | 255 | #Connect using SSL 256 | Invoke-Command savazuusscdc01.savilltech.net -ScriptBlock {$env:computername} -UseSSL 257 | #Short name will fail as using cert can override 258 | $option = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck 259 | Enter-PSSession -ComputerName savazuusscdc01 -SessionOption $option -useSSL 260 | 261 | #Connection via SSH hostname instead of computername 262 | Invoke-Command -HostName savazuussclnx01 -ScriptBlock {get-process} -UserName john 263 | 264 | #Mix of WinRM and SSH 265 | New-PSSession -ComputerName savazuusscds01 #winrm 266 | New-PSSession -HostName savazuussclnx01 -UserName john 267 | Get-PSSession -OutVariable sess 268 | $sess 269 | invoke-command $sess {get-process *s} 270 | $sess | Remove-PSSession 271 | 272 | #endregion 273 | 274 | 275 | #region Module 4 - PowerShell Scripting 276 | 277 | #Shows write-host vs write-output 278 | function Receive-Output 279 | { 280 | process { write-host $_ -ForegroundColor Green} 281 | } 282 | Write-Output "this is a test" | Receive-Output 283 | Write-Host "this is a test" | Receive-Output 284 | Write-Output "this is a test" 285 | 286 | #' vs " 287 | $name = "John" 288 | Write-Output "Hello $name" 289 | Write-Output 'Hello $name' 290 | $query = "SELECT * FROM OS WHERE Name LIKE '%SERVER%'" 291 | Write-Output "Hello `t`t`t World" 292 | 293 | #User input 294 | $name = Read-Host "Who are you?" 295 | $pass = Read-Host "What's your password?" -AsSecureString 296 | [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pass)) 297 | 298 | 299 | Get-CimInstance -ClassName Win32_Logical #ctrl space to intelli sense all the name spaces available 300 | 301 | #endregion 302 | 303 | 304 | #region Module 5 - Advanced PowerShell Scripting 305 | 306 | function first3 {$input | Select-Object -First 3} 307 | get-process | first3 308 | 309 | #Code signing 310 | $cert = @(gci cert:\currentuser\my -codesigning)[0] 311 | Set-AuthenticodeSignature signme.ps1 $cert 312 | 313 | #endregion 314 | 315 | 316 | #region Module 6 - Parsing Data and Working With Objects 317 | 318 | #Credentials 319 | #This is not good 320 | $user = "administrator" 321 | $password = 'Pa55word' 322 | $securePassword = ConvertTo-SecureString $password ` 323 | -AsPlainText -Force 324 | $cred = New-Object System.Management.Automation.PSCredential ($user, $securePassword) 325 | 326 | #An encrypted string 327 | $encryptedPassword = ConvertFrom-SecureString (ConvertTo-SecureString -AsPlainText -Force "Password123") 328 | $securepassword = ConvertTo-SecureString "<the huge value from previous command>" 329 | 330 | #Another file 331 | $credpath = "c:\temp\MyCredential.xml" 332 | New-Object System.Management.Automation.PSCredential("john@savilltech.com", (ConvertTo-SecureString -AsPlainText -Force "Password123")) | Export-CliXml $credpath 333 | $cred = import-clixml -path $credpath 334 | 335 | #Using Key Vault 336 | Select-AzSubscription -Subscription (Get-AzSubscription | where Name -EQ "SavillTech Dev Subscription") 337 | $cred = Get-Credential 338 | 339 | #Store username and password in keyvault 340 | Set-AzKeyVaultSecret -VaultName 'SavillVault' -Name 'SamplePassword' -SecretValue $cred.Password 341 | $secretuser = ConvertTo-SecureString $cred.UserName -AsPlainText -Force #have to make a secure string 342 | Set-AzKeyVaultSecret -VaultName 'SavillVault' -Name 'SampleUser' -SecretValue $secretuser 343 | 344 | #Getting back 345 | #$username = (get-azkeyvaultsecret -vaultName 'SavillVault' -Name 'SampleUser').SecretValueText 346 | #$password = (get-azkeyvaultsecret -vaultName 'SavillVault' -Name 'SamplePassword').SecretValue 347 | #(get-azkeyvaultsecret -vaultName 'SavillVault' -Name 'SamplePassword').SecretValueText #Can get the plain text via key vault 348 | #[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)) #Inspect if want to double check 349 | #This has changed 350 | $keyvaultname = 'SavillVault' 351 | $username = (get-azkeyvaultsecret -vaultName $keyvaultname -Name 'SampleUser' -AsPlainText) 352 | $password = (get-azkeyvaultsecret -vaultName $keyvaultname -Name 'SamplePassword').SecretValue 353 | $passwordtext = (get-azkeyvaultsecret -vaultName $keyvaultname -Name 'SamplePassword'-AsPlainText) 354 | 355 | 356 | 357 | #Recreate 358 | $newcred = New-Object System.Management.Automation.PSCredential ($username, $password) 359 | #Test 360 | invoke-command -ComputerName savazuusscdc01 -Credential $newcred -ScriptBlock {whoami} 361 | 362 | #Var types 363 | $number=42 364 | $boolset=$true 365 | $stringval="hello" 366 | $charval='a' 367 | $number.GetType() 368 | $boolset.GetType() 369 | $stringval.GetType() 370 | $charval.GetType() 371 | 372 | [char]$newchar= 'a' 373 | $newchar.GetType() 374 | 375 | 42 –is [int] 376 | 377 | $number = [int]42 378 | $number.ToString() | gm 379 | 380 | $string1 = "the quick brown fox jumped over the lazy dog" 381 | $string1 -like "*fox*" 382 | $string2 = $string1 + " who was not amused" 383 | 384 | 385 | #Time 386 | $today=Get-Date 387 | $today | Select-Object –ExpandProperty DayOfWeek 388 | [DateTime]::ParseExact("02-25-2011","MM-dd-yyyy",[System.Globalization.CultureInfo]::InvariantCulture) 389 | $christmas=[system.datetime]"25 December 2019" 390 | ($christmas - $today).Days 391 | $today.AddDays(-60) 392 | $a = new-object system.globalization.datetimeformatinfo 393 | $a.DayNames 394 | 395 | #Variable Scope 396 | function test-scope() 397 | { 398 | write-output $defvar 399 | write-output $global:globvar 400 | write-output $script:scripvar 401 | write-output $private:privvar 402 | $funcvar = "function" 403 | $private:funcpriv = "funcpriv" 404 | $global:funcglobal = "globfunc" 405 | } 406 | 407 | $defvar = "default/local" #default 408 | get-variable defvar -scope local 409 | $global:globvar = "global" 410 | $script:scripvar = "script" 411 | $private:privvar = "private" 412 | test-scope 413 | $funcvar 414 | $funcglobal #this should be visible 415 | 416 | #Variables with Invoke-Command 417 | $message = "Message to John" 418 | Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock {Write-Host $message} 419 | 420 | $ScriptBlockContent = { 421 | param ($MessageToWrite) 422 | Write-Host $MessageToWrite } 423 | Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock $ScriptBlockContent -ArgumentList $message 424 | #or 425 | Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock {Write-Output $args} -ArgumentList $message 426 | 427 | Invoke-Command -ComputerName savazuusscdc01 -ScriptBlock {Write-Host $using:message} 428 | 429 | 430 | #Hash Tables 431 | $favthings = @{"Julie"="Sushi";"Ben"="Trains";"Abby"="Princess";"Kevin"="Minecraft"} 432 | $favthings.Add("John","Crab Cakes") 433 | $favthings.Set_Item("John","Steak") 434 | $favthings.Get_Item("Abby") 435 | 436 | #Custom objects 437 | $cusobj = New-Object PSObject 438 | Add-Member -InputObject $cusobj -MemberType NoteProperty ` 439 | -Name greeting -Value "Hello" 440 | 441 | $favthings = @{"Julie"="Sushi";"Ben"="Trains";"Abby"="Princess";"Kevin"="Minecraft"} 442 | $favobj = New-Object PSObject -Property $favthings 443 | #In PowerShell v3 can skip a step 444 | $favobj2 = [PSCustomObject]@{"Julie"="Sushi";"Ben"="Trains";"Abby"="Princess";"Kevin"="Minecraft"} 445 | 446 | 447 | #Foreach 448 | $names = @("Julie","Abby","Ben","Kevin") 449 | $names | ForEach-Object -Process { Write-Output $_} 450 | $names | ForEach -Process { Write-Output $_} 451 | $names | ForEach { Write-Output $_} 452 | $names | % { Write-Output $_} 453 | 454 | #Foreach vs Foreach 455 | ForEach-Object -InputObject (1..100) { 456 | $_ 457 | } | Measure-Object 458 | 459 | ForEach ($num in (1..100)) { 460 | $num 461 | } | Measure-Object 462 | 463 | 'Z'..'A' 464 | 465 | #Accessing property values 466 | $samacctname = "John" 467 | Get-ADUser $samacctname -Properties mail 468 | Get-ADUser $samacctname -Properties mail | select-object mail 469 | Get-ADUser $samacctname -Properties mail | select-object mail | get-member 470 | Get-ADUser $samacctname -Properties mail | select-object -ExpandProperty mail | get-member 471 | Get-ADUser $samacctname -Properties mail | select-object -ExpandProperty mail 472 | 473 | 474 | #endregion 475 | 476 | 477 | #region Module 7 - Desired State Configuration 478 | 479 | #Imperative install 480 | Import-Module ServerManager 481 | #Check and install Web Server Role if not installed 482 | If (-not (Get-WindowsFeature "Web-Server").Installed) 483 | { 484 | try { 485 | Add-WindowsFeature Web-Server 486 | } 487 | catch { 488 | Write-Error $_ 489 | } 490 | } 491 | 492 | #Get all providers 493 | Get-DscResource 494 | 495 | #endregion 496 | 497 | 498 | #region Module 8 - Automation Technologies 499 | 500 | #Short workflow 501 | Workflow MyWorkflow {Write-Output "Hello from Workflow!"} 502 | MyWorkflow 503 | 504 | #Long workflow 505 | Workflow LongWorkflow 506 | { 507 | Write-Output -InputObject "Loading some information..." 508 | Start-Sleep -Seconds 10 509 | CheckPoint-Workflow 510 | Write-Output -InputObject "Performing process list..." 511 | Get-process -PSPersist $true #this adds checkpoint 512 | Start-Sleep -Seconds 10 513 | CheckPoint-Workflow 514 | Write-Output -InputObject "Cleaning up..." 515 | Start-Sleep -Seconds 10 516 | 517 | } 518 | LongWorkflow –AsJob –JobName LongWF –PSPersist $true 519 | Suspend-Job LongWF 520 | Get-Job LongWF 521 | Receive-Job LongWF –Keep 522 | Resume-Job LongWF 523 | Get-Job LongWF 524 | Receive-Job LongWF –Keep 525 | Remove-Job LongWF #removes the saved state of the job 526 | 527 | #Parallel execution 528 | workflow paralleltest 529 | { 530 | parallel 531 | { 532 | get-process -Name w* 533 | get-process -Name s* 534 | get-service -name x* 535 | get-eventlog -LogName Application -newest 10 536 | } 537 | } 538 | paralleltest 539 | 540 | workflow compparam 541 | { 542 | param([string[]]$computers) 543 | foreach –parallel ($computer in $computers) 544 | { 545 | Get-CimInstance –Class Win32_OperatingSystem –PSComputerName $computer 546 | Get-CimInstance –Class win32_ComputerSystem –PSComputerName $computer 547 | } 548 | } 549 | compparam -computers savazuusscdc01, savazuusedc01 550 | 551 | #Parallel and Sequence 552 | workflow parallelseqtest 553 | { 554 | parallel 555 | { 556 | sequence 557 | { 558 | get-process -Name w* 559 | get-process -Name s* 560 | } 561 | get-service -name x* 562 | get-eventlog -LogName Application -newest 10 563 | } 564 | } 565 | parallelseqtest 566 | 567 | Workflow RestrictionCheck 568 | { 569 | $msgtest = "Hello" 570 | #msgtest.ToUpper() 571 | $msgtest = InlineScript {($using:msgtest).ToUpper()} 572 | Write-Output $msgtest 573 | } 574 | RestrictionCheck 575 | 576 | #Calling a function 577 | $FunctionURL = "<your URI>" 578 | Invoke-RestMethod -Method Get -Uri $FunctionURL 579 | 580 | Invoke-RestMethod -Method Get -Uri "$($FunctionURL)&name=John" 581 | 582 | $JSONBody = @{name = "World"} | ConvertTo-Json 583 | Invoke-RestMethod -Method Post -Body $JSONBody -Uri $FunctionURL 584 | #endregion -------------------------------------------------------------------------------- /VSCodeKeyboardSettings.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "ctrl+shift+t", 4 | "command": "shellLauncher.launch" 5 | }, 6 | { 7 | "key": "f8", 8 | "command": "PowerShell.RunSelection", 9 | "when": "editorTextFocus && editorLangId == 'powershell'" 10 | }, 11 | { 12 | "key": "ctrl+shift+f8", 13 | "command": "workbench.action.terminal.runSelectedText", 14 | "when": "editorTextFocus && editorLangId == 'powershell'" 15 | } 16 | ] -------------------------------------------------------------------------------- /VSCodeSettingsSample.json: -------------------------------------------------------------------------------- 1 | { 2 | 3 | "git.ignoreMissingGitWarning": true, 4 | "powershell.powerShellExePath": "c:\\Program Files\\PowerShell\\6\\pwsh.exe", 5 | "editor.minimap.enabled": false, 6 | "window.menuBarVisibility": "default", 7 | "files.trimTrailingWhitespace": true, 8 | "files.trimFinalNewlines": true, 9 | "terminal.integrated.shell.windows": "c:\\Program Files\\PowerShell\\6\\pwsh.exe", 10 | "editor.tabCompletion": "on", 11 | "files.defaultLanguage": "powershell", 12 | "powershell.integratedConsole.focusConsoleOnExecute": false, 13 | "git.path": "C:\\Program Files\\Git\\bin\\git.exe", 14 | "shellLauncher.shells.windows": [{ 15 | "shell": "c:\\Program Files\\PowerShell\\6\\pwsh.exe", 16 | "label": "PowerShell Core" 17 | }, 18 | { 19 | "shell": "C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe", 20 | "label": "Windows PowerShell" 21 | }, 22 | { 23 | "shell": "C:\\Windows\\system32\\cmd.exe", 24 | "label": "Windows Command Prompt" 25 | } 26 | 27 | ], 28 | "sync.gist": "<GIST ID>", 29 | "sync.autoDownload": true, 30 | "git.autofetch": true, 31 | "sync.autoUpload": true 32 | } --------------------------------------------------------------------------------