├── 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
9 |
10 |
11 |
12 |
13 |
14 |
15 | NanoVM2
16 |
17 |
18 |
--------------------------------------------------------------------------------
/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)
[Using Try-Catch](https://youtu.be/2eByC9N1xIQ)
[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)
[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 #to add into PowerShell instance
18 | Get-Command –Module #to list commands in a module
19 | Get-Command -Module | Select-Object -Unique Noun | Sort-Object Noun
20 | Get-Command -Module | Select -Unique Noun | Sort Noun #Lazy version :-)
21 |
22 | (Get-Module ).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
30 | Get-Command –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 ""
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 = ""
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": "",
29 | "sync.autoDownload": true,
30 | "git.autofetch": true,
31 | "sync.autoUpload": true
32 | }
--------------------------------------------------------------------------------