├── Chapter 10 - Implementing Desired State Configuration ├── Page2.Htm ├── Index.Htm ├── Get-DSCEventLogEntry.ps1 ├── Get-DSCReport.ps1 ├── Recipe 10.3 - Finding and Installing DSC sources.ps1 ├── Setup-DSCWebApp.ps1 ├── Recipe 10.2 - Paramaterising DSC Configuration .ps1 ├── Recipe 10.5 -Configuring DSC LCM.ps1 ├── Recipe 10.4 - Using DSC with PSGallery Resources.ps1 └── Recipe 10.1 -Using DSC and built-in resources.ps1 ├── Chapter 04 - Managing Storage ├── Recipe 4.x - Using Storage Spaces Direct.ps1 ├── Recipe 4.9 Using Storage Spaces Direct LOG.txt ├── Recipe 4.1 - Using Disks.ps1 ├── Recipe 4.2 - Managing NTFS permissions.ps1 ├── Recipe 4.5 - Using File System Reporting.ps1 ├── Add-DiskstoSRV1+2.ps1 └── Recipe 4.3 - Managing storage replica.ps1 ├── Chapter 01 - Establishing a PowerShell Administrative Environment ├── doit.ps1 ├── 1.4 - Creating an internal PS repository.ps1 ├── 1.2 - Exploring Package Mangement.ps1 ├── 1.5 - Establish a script signing environment.ps1 └── 1.3 - Exploring PowerShellGet+PSGallery.ps1 ├── Chapter 08 - Leveraging containers ├── Recipe 8.1 - Setting up a container host.ps1 ├── docker networking.ps1 ├── Recipe 8.2 -Running the first container LOG.txt.txt ├── 8.x create a container using DOCKERFILE.ps1 ├── Recipe 8.3 - Deploy IIS in a container.ps1 ├── Recipe 8.2 - Deploying a hello world sample.ps1 └── 8.4 Create a container using DOCKERFILE.ps1 ├── PowerShellCookBook2019 ├── README.md ├── set-autologin.ps1 ├── LICENSE ├── ReskitNetwork.md └── README (PACKT).md ├── Chapter 03 - Deploying Active Directory ├── NewUsers.CSV ├── 3.6 - Finding expired computers and disabled users in AD.ps1 ├── 3.3 - Adding users to AD using a CSV.ps1 ├── 3.4 - Creating a group policy object.ps1 ├── 3.1 - Installing Active Directory with DNS.ps1 └── 3.5 - Reporting on AD Users.ps1 ├── Get-RecipeStructure.ps1 ├── set-autologin.ps1 ├── Chapter 12 - Exploring Azure ├── Ch 12 - Recipe Index.md ├── Recipe 12.2 - Azure Resources.ps1 ├── Recipe 12.1 - Getting Started.ps1 ├── Recipe 12.4 - Create Azure SMB share.ps1 ├── Recipe 12.6 - Create Azure VM.ps1 ├── Recipe 12.7 - Create and Use VPN.ps1 ├── Recipe 12.3 - Explore Storage Account.ps1 └── Recipe 12.5 - Create Azure Web SIte.ps1 ├── Chapter 07 - Managing Printers ├── Recipe 7-7 - Creating a Printer Pool.ps1 ├── Recipe 7.7 - Creating a Printer Pool.ps1 ├── Recipe 7.4 - Changing printer driver.ps1 ├── Recipe 7.5 - Printing a test page on a printer.ps1 ├── Recipe 7.2 - Publishing a printer.ps1 ├── Recipe 7.6 - Modiying printer security.ps1 ├── Recipe 7.x -Deploying Shared Printer.ps1 ├── Create-SalesTeam.ps1 ├── Recipe 7.3 - Changing spool folder.ps1 └── Recipe 7.1 - Installing and sharing printer.ps1 ├── Chapter 11 - Managing Hyper-V ├── Create-HV2VMs.ps1 ├── Recipe 11.2 - Creating a VM.ps1 ├── Recipe 11.2 - Using PowerShell Direct.ps1 ├── Recipe 11.3 - Using PowerShell Direct.ps1 ├── Recipe 11.8 - Managing VM state.ps1 ├── Recipe 11.5 - Configuring VM hardware.ps1 ├── Recipe 11.7 - Implementing nested Hyper-V.ps1 ├── Recipe 11.6 - Configuring Hyper-V networking.ps1 ├── Recipe 11.1 - Installing and Configuring Hyper-V.ps1 ├── Recipe 11.9 - Configuring VM and storage movement.ps1 ├── Bonus Recipe 1 - Create a VM from existing VHD.ps1 ├── Recipe 11.4 - Using VM Groups.ps1 ├── Recipe 11.10 - Configuring VM replication.ps1 ├── Recipe 11.11 - Managing VM Checkpoints.ps1 └── Recipe 11.12 - Creating a Hyper-V Status Report.ps1 ├── Chapter 02 - Managing Windows Networking ├── 2.3 - Installing and authorizing a DHCP server.ps1 ├── 2.5 - Convert IP address from static to DHCP.ps1 ├── 2.4 - Configuring DHCP Scopes.ps1 ├── 2.6 - Configuring DHCP Failover amd Load Balancing.ps1 ├── 2.2 - Configuring IP Addressing.ps1 └── 2.1 - New ways to do old things.ps1 ├── Chapter 13 - Monitoring Performance and Usage ├── Recipe 13.6 - Creating a Systems diagnostic report.ps1 ├── Recipe 13.1a - Stress Network.ps1 ├── Recipe 13.7 - Get Printer Usage report.ps1 ├── Recipe 13.2 - Using WMI to retreive performance counters.ps1 ├── Recipe 13.4 - Reporting on Performance Data.ps1 ├── Recipe 13.5 - Generating a perf monitoring graph.ps1 ├── Recipe 13.3b - Create performance collector set (CSV OUT).ps1 ├── Recipe 13.3 - Create+Use PLA Data Collector set.ps1 ├── Recipe 13.3a - Create performance collector set (TSV OUT).ps1 ├── Recipe 13.1 - Explore perf counters with Get-Counter.ps1 └── Recipe 13.8 - Creating a Hyper-V Status Report.ps1 ├── Chapter 09 - Managing Windows Internet Information Server ├── Recipe 9.3 - Manage TLS Cipher Suites.ps1 ├── Recipe 9.5 - Configuring IIS Bindings.ps1 ├── Recipe 9.2 - Install SSL.ps1 ├── Recipe 9.1 - Install IIS Server.ps1 ├── Recipe 9.2 - Configuring IIS for SSL.ps1 ├── Recipe 9.7 - Manage Applications and Application Pools.ps1 ├── Recipe 9.8 - Analyze IIS log files.ps1 ├── Recipe 9.6 - Configure IIS Logging and Log Files.ps1 └── Recipe 9.9 - Managing and monitoring NLB.ps1 ├── LICENSE ├── Chapter 06 - Deploying Windows Update ├── Recipe 6.4 - Creating computer target groups.ps1 ├── Recipe 6.5 - Configuring WSUS auto-approvals.ps1 ├── Recipe 6.6 - Managing Updates.ps1 ├── Recipe 6.3 - Configuring WIndows Update Client.ps1 ├── Recipe 6.1 - Installing WIndows Server Update Service.ps1 └── Recipe 6.2 - Configuring WSUS Update synchronization.ps1 ├── Chapter 05 - Managing Shared Data ├── Recipe 5.4 - Creating an iSCSI Target.ps1 ├── Recipe 5.3 - Accessing SMB Shares.ps1 ├── Recipe 5.5 - Using an iSCSI target.ps1 ├── Recipe 5.1 - Securing your SMB file server.ps1 ├── Recipe x - Creating a scale out file server..ps1 ├── Recipe 5.2 - Creating and securing SMB share.ps1 └── Recipe 5.6 - Configuring a DFS Namespace.ps1 ├── Chapter 14 - Troubleshooting WIndows Server ├── Recipe 14.X - Use TroubleShooting packs.ps1 ├── Recipe 14.2 - Using BPA.ps1 ├── Recipe 14.3 - Managing Event Logs.ps1 └── Recipe 14.1 - Check Network Connectivity.ps1 ├── ReskitNetwork.md └── Errata.md /Chapter 10 - Implementing Desired State Configuration/Page2.Htm: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter 04 - Managing Storage/Recipe 4.x - Using Storage Spaces Direct.ps1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter 04 - Managing Storage/Recipe 4.9 Using Storage Spaces Direct LOG.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Chapter 01 - Establishing a PowerShell Administrative Environment/doit.ps1: -------------------------------------------------------------------------------- 1 | cat '\\cookham24\d$\Dropbox\PACKT BOOK RECIPES 2019\logs\Server2019CookbookLogs\Ch 1 - Log Files\1.2 - Exploing package management LOG .txt' 2 | 3 | -------------------------------------------------------------------------------- /Chapter 08 - Leveraging containers/Recipe 8.1 - Setting up a container host.ps1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/doctordns/PowerShellCookBook2019/HEAD/Chapter 08 - Leveraging containers/Recipe 8.1 - Setting up a container host.ps1 -------------------------------------------------------------------------------- /Chapter 08 - Leveraging containers/docker networking.ps1: -------------------------------------------------------------------------------- 1 | docker network create -d transparent --gateway 10.10.10.254 --subnet 10.10.10.0/24 transparent 2 | 3 | docker run --rm -it --network transparent microsoft/nanoserver cmd -------------------------------------------------------------------------------- /PowerShellCookBook2019/README.md: -------------------------------------------------------------------------------- 1 | # PowerShellCookBook2019 Repository 2 | 3 | ## Contents 4 | This repository contains the recipes in Server 2019 Cookbook along with supporting material 5 | 6 | NB: This is a work in progress -------------------------------------------------------------------------------- /Chapter 03 - Deploying Active Directory/NewUsers.CSV: -------------------------------------------------------------------------------- 1 | Firstname, Initials, Lastname, UserPrincipalName, Alias, Description, Password 2 | S,K,Masterly, skm, Sylvester, Data Team, Christmas42 3 | C,B Smith, CBS, Claire, Claire,Receptionist, Christmas42 4 | Billy-Bob, Joe-Bob, Bob, BBJB, BBJB, One of the Bob's, Christmas42 5 | Malcolm, DoWrite, Duelittle, Malcolm, Malcolm, Mr Danger, Christmas42 6 | -------------------------------------------------------------------------------- /Get-RecipeStructure.ps1: -------------------------------------------------------------------------------- 1 | # Function to get the structure of a recipe 2 | function get-recipestructure 3 | { 4 | $Lines = Get-Content $psise.CurrentFile.FullPath 5 | $lineno = 0 6 | Foreach ($Line in $Lines) { 7 | $Lineno++ 8 | if ($line -match '^#') { 9 | "[{0,4}] {1}" -F $lineno,$line 10 | } 11 | } 12 | } 13 | 14 | set-alias grs get-recipeStructure 15 | grs -------------------------------------------------------------------------------- /set-autologin.ps1: -------------------------------------------------------------------------------- 1 | $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" 2 | $DefaultUsername = "reskit\administrator" 3 | $DefaultPassword = "Pa$$W0rd" 4 | Set-ItemProperty $RegPath "AutoAdminLogon" -Value "1" -type String 5 | Set-ItemProperty $RegPath "DefaultUsername" -Value "$DefaultUsername" -type String 6 | Set-ItemProperty $RegPath "DefaultPassword" -Value "$DefaultPassword" -type String -------------------------------------------------------------------------------- /PowerShellCookBook2019/set-autologin.ps1: -------------------------------------------------------------------------------- 1 | $RegPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" 2 | $DefaultUsername = "reskit\administrator" 3 | $DefaultPassword = "Pa$$W0rd" 4 | Set-ItemProperty $RegPath "AutoAdminLogon" -Value "1" -type String 5 | Set-ItemProperty $RegPath "DefaultUsername" -Value "$DefaultUsername" -type String 6 | Set-ItemProperty $RegPath "DefaultPassword" -Value "$DefaultPassword" -type String -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Index.Htm: -------------------------------------------------------------------------------- 1 | 2 | 3 | Main Page - ReskitApp Application 4 |

5 | HOME PAGE FOR RESKITAPP APPLICATION

6 | This is the root page of the RESKITAPP application 7 | Pushed via DSC



8 | 9 | Click to View Page 2 10 |
11 |

12 | -------------------------------------------------------------------------------- /Chapter 12 - Exploring Azure/Ch 12 - Recipe Index.md: -------------------------------------------------------------------------------- 1 | # Module 12 - Managing Azure 2 | 3 | This chapter looks using PowerShell to manage Azure 4 | 5 | Recipes in this chapter 6 | 7 | 8 | - 2.1 - Using PowerShell with Azure 9 | - 2.2 - Creating core Azure resources 10 | - 2.3 - Exploring your storage account 11 | - 2.4 - Creating and using an Azure SMB file share 12 | - 2.5 - Creating and using Azure websites 13 | - 2.6 - Creating and using Azure virtual machines 14 | -------------------------------------------------------------------------------- /Chapter 08 - Leveraging containers/Recipe 8.2 -Running the first container LOG.txt.txt: -------------------------------------------------------------------------------- 1 | # Recipe 8.2 - Managing The Hello World Sample 2 | # 3 | # Run on CH1 4 | 5 | # 1. Start by pruning everything and ensuring you start fresh 6 | docker system prune -a 7 | 8 | # 2. Get Base Container Images 9 | 10 | 11 | # Download the container base images: 12 | 13 | docker pull microsoft/nanoserver:1809 14 | docker pull microsoft/windowsservercore:1809 15 | 16 | docker run microsoft/dotnet-samples:dotnetapp-nanoserver:1809 -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7-7 - Creating a Printer Pool.ps1: -------------------------------------------------------------------------------- 1 | # Recipe7-7 - create Printer Pool 2 | # Run on PSRV printer server 3 | 4 | # 1. Add a port for the printer $P = 'SalesPP2' # new port name Add-PrinterPort -Name $P -PrinterHostAddress 10.10.10.62 # 2. Create the printer pool for SalesPrinter1: $P1='SalesPP' 5 | $P2='SalesPP2' 6 | rundll32.exe printui.dll,PrintUIEntry /Xs /n $p Portname $P1,$P2 # 3. View resultant details, showing both ports: $P = 'SalesPrinter1' Get-Printer $P | Format-Table -Property Name, Type, DriverName, PortName -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7.7 - Creating a Printer Pool.ps1: -------------------------------------------------------------------------------- 1 | # Recipe7-7 - create Printer Pool 2 | # Run on PSRV printer server 3 | 4 | # 1. Add a port for the printer 5 | $P = 'SalesPP2' # printer name 6 | Add-PrinterPort -Name $P -PrinterHostAddress 10.10.10.62 7 | 8 | # 2. Create the printer pool for SalesPrinter1: 9 | $P1='SalesPP' 10 | $P2='SalesPP2' 11 | rundll32.exe printui.dll,PrintUIEntry /Xs /n $p Portname $P1,$P2 12 | 13 | # 3. View resultant details: 14 | Get-Printer $P | 15 | Format-Table -Property Name, Type, DriverName, PortName 16 | -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7.4 - Changing printer driver.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 4-4 Change Printer Driver 2 | 3 | # 1. Add the print driver for the new printing device: 4 | $M2 = 'Xerox WorkCentre 6515 PCL6' 5 | Add-PrinterDriver -Name $M2 6 | 7 | # 2. Get the Sales group printer object and store it in $Printer: 8 | $Printern = 'SalesPrinter1' 9 | $Printer = Get-Printer -Name $Printern 10 | 11 | # 3. Update the driver using the Set-Printercmdlet: 12 | $Printer | Set-Printer -DriverName $M2 13 | 14 | # 4. Observe the result 15 | Get-Printer -Name $Printern | 16 | Format-Table -Property Name, DriverName, PortName, 17 | Published, Shared -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7.5 - Printing a test page on a printer.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 7-5 - Printing a test page on a printer 2 | 3 | # 1. Get the printer objects from WMI: 4 | $Printers = Get-CimInstance -ClassName Win32_Printer 5 | 6 | # 2. Display the number of printers defined on PSRV: 7 | '{0} Printers defined on this system' -f $Printers.Count 8 | 9 | # 3. Get the Sales Group printer WMI object: 10 | $Printer = $Printers | 11 | Where-Object Name -eq 'SalesPrinter1' 12 | 13 | # 4. Display the printer's details: 14 | $Printer | Format-Table -AutoSize 15 | 16 | # 5. Print a test page: 17 | Invoke-CimMethod -InputObject $Printer -MethodName PrintTestPage -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7.2 - Publishing a printer.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 7-2 Publishing a printer 2 | # 3 | # Run on Psrv 4 | # Uses Printer added in 7.1 5 | 6 | # 1. Get the printer to publish and store the returned object in $Printer: 7 | $Printer = Get-Printer -Name SalesPrinter1 8 | 9 | # 2. Observe the publication status: 10 | $Printer | Format-Table -Property Name, Published 11 | 12 | # 3. Publish and share the printer to AD: 13 | $Printer | Set-Printer -Location '10th floor 10E4' 14 | $Printer | Set-Printer -Shared $true -Published $true 15 | 16 | # 4. View the updated publication status: 17 | Get-Printer -Name SalesPrinter1 | 18 | Format-Table -Property Name, Location, Drivername,Published 19 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Create-HV2VMs.ps1: -------------------------------------------------------------------------------- 1 | # Create HV2 VMs for Chapter 11 2 | # 3 | # This snippet creates a set of VMs used in the Managing Hyper-V chapter. 4 | # Run this on HV2 5 | 6 | 7 | $VMLocation = 'C:\Vm\VMs' 8 | # Create VM1 9 | $VMN1 = 'SQLAcct1' 10 | New-VM -Name $VMN1 -Path "$VMLocation\$VMN1" 11 | # Create VM2 12 | $VMN2 = 'SQLAcct2' 13 | New-VM -Name $VMN2 -Path "$VMLocation\$VMN2" 14 | # Create VM3 15 | $VMN3 = 'SQLAcct3' 16 | New-VM -Name $VMN3 -Path "$VMLocation\$VMN3" 17 | # Create VM4 18 | $VMN4 = 'SQLMfg1' 19 | New-VM -Name $VMN4 -Path "$VMLocation\$VMN4" 20 | # Create VM5 21 | $VMN5 = 'SQLMfg2' 22 | New-VM -Name $VMN5 -Path "$VMLocation\$VMN5" 23 | -------------------------------------------------------------------------------- /Chapter 02 - Managing Windows Networking/2.3 - Installing and authorizing a DHCP server.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 2.3 - Installing and authorizing a DHCP server 2 | # 3 | # Run on DC1 4 | 5 | # 1. Install the DHCP Feature 6 | Install-WindowsFeature -Name DHCP -IncludeManagementTools 7 | 8 | # 2. Add the DHCP server's security groups 9 | Add-DHCPServerSecurityGroup -Verbose 10 | 11 | # 3. Let DHCP know it's all configured 12 | $RegHT = @{ 13 | Path = 'HKLM:\SOFTWARE\Microsoft\ServerManager\Roles\12' 14 | Name = 'ConfigurationState' 15 | Value = 2 16 | } 17 | Set-ItemProperty @RegHT 18 | d 19 | 20 | # 4. Authorise the DHCP server in AD 21 | Add-DhcpServerInDC -DnsName DC1.Reskit.Org 22 | 23 | # 5. Restart DHCP 24 | Restart-Service -Name DHCPServer –Force 25 | -------------------------------------------------------------------------------- /Chapter 02 - Managing Windows Networking/2.5 - Convert IP address from static to DHCP.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 2.5 - Converting IP address from static to DHCP 2 | # 3 | # Run on SRV2 4 | 5 | 6 | # 1.Get the existing IP address information 7 | $IPType = 'IPv4' 8 | $Adapter = Get-NetAdapter | 9 | Where-Object Status -eq 'up' 10 | $Interface = $Adapter | 11 | Get-NetIPInterface -AddressFamily $IPType 12 | $IfIndex = $Interface.ifIndex 13 | $IfAlias = $Interface.Interfacealias 14 | Get-NetIPAddress -InterfaceIndex $IfIndex -AddressFamily $IPType 15 | 16 | # 2. Set the interface to get its address from DHCP: 17 | Set-NetIPInterface -InterfaceIndex $IfIndex -DHCP Enabled 18 | 19 | # 3. Test the results: 20 | Get-NetIPAddress -InterfaceIndex $IfIndex -AddressFamily $IPType -------------------------------------------------------------------------------- /Chapter 02 - Managing Windows Networking/2.4 - Configuring DHCP Scopes.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 2.4 - Configuring DHCP Scopes 2 | 3 | # Run on DC1 4 | 5 | # 1. Create a Scope 6 | $SHT = @{ 7 | Name = 'Reskit' 8 | StartRange = '10.10.10.150' 9 | EndRange = '10.10.10.199' 10 | SubnetMask = '255.255.255.0' 11 | ComputerName = 'DC1.Reskit.Org' 12 | } 13 | Add-DhcpServerV4Scope @SHT 14 | 15 | # 2. Get Scopes from the server 16 | Get-DhcpServerv4Scope -ComputerName DC1.Reskit.Org 17 | 18 | # 3. Set Option Values 19 | $OHT = @{ 20 | ComputerName = 'DC1.Reskit.Org' 21 | DnsDomain = 'Reskit.Org' 22 | DnsServer = '10.10.10.10' 23 | } 24 | Set-DhcpServerV4OptionValue @OHT 25 | 26 | # 4. Get options set 27 | Get-DhcpServerv4OptionValue -ComputerName DC1.Reskit.Org -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.6 - Creating a Systems diagnostic report.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 13.6 - Creating a Systems Diagnostic report 2 | # 3 | # Run on SRV1 4 | 5 | # 1. Start the built-in data collector on the local system: 6 | $PerfReportName="System\System Diagnostics" 7 | $DataSet = New-Object -ComObject Pla.DataCollectorSet 8 | $DataSet.Query($PerfReportName,$null) 9 | $DataSet.Start($true) 10 | 11 | # 2. Wait for the data collector to finish: 12 | "Sleeping for [$($Dataset.Duration)] seconds" 13 | Start-Sleep -Seconds $Dataset.Duration 14 | 15 | # 3. Get the report and store it as HTML: 16 | $Dataset.Query($PerfReportName,$null) 17 | $PerfReport = $Dataset.LatestOutputLocation + "\Report.html" 18 | 19 | # 4. View the report: 20 | & $PerfReport -------------------------------------------------------------------------------- /Chapter 08 - Leveraging containers/8.x create a container using DOCKERFILE.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 8.X- Creating a Image using a Dockerfile 2 | # 3 | # run on CH1 4 | 5 | # 1. Create folder and Set-location to here 6 | $NIHT = @{ 7 | Path = 'C:\Foo\IISContainer' 8 | ItemType = 'Directory' 9 | ErrorAction = 'SilentlyContinue' 10 | } 11 | New-Item @NIHT 12 | Set-Location -Path $NIHT.Path 13 | 14 | # 2. Create DOCKERFILE 15 | $DF = @" 16 | FROM mcr.microsoft.com/windows/servercore:1809 17 | LABEL Description="IISDemo" Vendor="Microsoft" Version="Server2019" 18 | RUN powershell -Command Add-WindowsFeature Web-Server 19 | RUN powershell -Command GIP 20 | "@ 21 | $DF | Out-File -FilePath .\DOCKERFILE -Encoding ascii 22 | 23 | # 3. Build the image 24 | docker build -t iis . 25 | 26 | # 4. Run the image 27 | docker run --name iisdemo -p 80:80 iis 28 | 29 | # 5. Navigate to it 30 | Start-Process "http://ch1/" -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.2 - Creating a VM.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.2 - Creating a VM 2 | 3 | # 1. Set up the VM name and paths for this recipe: 4 | $VMname = 'PSDirect' 5 | $VMLocation = 'C:\Vm\VMs' 6 | $VHDlocation = 'C:\Vm\Vhds' 7 | $VhdPath = "$VHDlocation\PSDirect.Vhdx" 8 | $ISOPath = 'C:\builds\en_windows_server_2019_x64_dvd_4cb967d8.iso' 9 | 10 | # 2. Create a new VM: 11 | New-VM -Name $VMname -Path $VMLocation -MemoryStartupBytes 1GB 12 | 13 | # 3. Create a virtual disk file for the VM: 14 | New-VHD -Path $VhdPath -SizeBytes 128GB -Dynamic | Out-Null 15 | 16 | # 4. Add the virtual hard drive to the VM: 17 | Add-VMHardDiskDrive -VMName $VMname -Path $VhdPath 18 | 19 | # 5. Set ISO image in the VM's DVD drive: 20 | $IHT = @{ 21 | VMName = $VMName 22 | ControllerNumber = 1 23 | Path = $ISOPath 24 | } 25 | Set-VMDvdDrive @IHT 26 | 27 | # 6. Start the VM: 28 | Start-VM -VMname $VMname 29 | 30 | # 7. View the results: 31 | Get-VM -Name $VMname 32 | -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.3 - Manage TLS Cipher Suites.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 10-3 Manage TLS Cipher Suites 2 | 3 | # 1. Get the cipher suites on SRV1 and display 4 | Get-TlsCipherSuite | 5 | Format-Table Name, Exchange, Cipher, Hash, Certificate 6 | 7 | # 2. Find Cipher suites that support 3DES 8 | Get-TlsCipherSuite -Name 3DES | 9 | Format-Table Name, Exchange, Cipher, Hash, Certificate 10 | 11 | # 3 Disable 3DES based cipher suites 12 | Foreach ($CS in (Get-TlsCipherSuite -Name '3DES')) 13 | {Disable-TlsCipherSuite -Name $CS.Name} 14 | 15 | # 4. See if any cipher suites remain that support 3DES 16 | Get-TlsCipherSuite 3DES | 17 | Format-Table Name, Exchange, Cipher, Hash, Certificate 18 | 19 | # 5. Re-enable the 3DES cipher suite 20 | Enable-TlsCipherSuite -Name TLS_RSA_WITH_3DES_EDE_CBC_SHA 21 | 22 | # 6. Find Cipher suites that support 3DES 23 | Get-TlsCipherSuite 3DES | 24 | Format-Table -Property Name, Exchange, Cipher, 25 | ggeHash, Certificate 26 | 27 | -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.1a - Stress Network.ps1: -------------------------------------------------------------------------------- 1 | # Script 6-1b - Bonus script to stress network 2 | # This script allows you to variously stress systems to get perf counters to do nice things. 3 | 4 | # dc1 5 | Function Stress-DC1 { 6 | $sb = 7 | { 8 | invoke-command -computer DC1 -script { 9 | 1..1000000 | ForEach-Object {$u = get-aduser -filter *; $c = get-adcomputer -filter *} 10 | } 11 | } 12 | 13 | Start-job -Script $sb 14 | } 15 | 16 | Function Stress-CA { 17 | $sb = 18 | { 19 | invoke-command -computer CA -script { 20 | 1..10000000 | foreach {$i=0; $i++; $i=$i*$i*$i} 21 | 22 | } 23 | } 24 | 25 | Start-job -script $sb 26 | } 27 | 28 | Function Stress-FS1 { 29 | Start-Job -ScriptBlock {icm -ComputerName fs1 -ScriptBlock {dir . -rec}} 30 | Start-Job -ScriptBlock {icm -ComputerName fs1 -ScriptBlock {dir . -rec}} 31 | Start-Job -ScriptBlock {icm -ComputerName fs1 -ScriptBlock {dir . -rec}} 32 | Start-Job -ScriptBlock {icm -ComputerName fs1 -ScriptBlock {dir . -rec}} 33 | } 34 | 35 | 36 | # Here invoke them 37 | Stress-FS1 38 | stress-dc1 39 | stress-CA -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Get-DSCEventLogEntry.ps1: -------------------------------------------------------------------------------- 1 | # dsc debugging 2 | 3 | # 1. turn on DSC event logging 4 | wevtutil.exe set-log "Microsoft-Windows-Dsc/Analytic" /q:true /e:true 5 | wevtutil.exe set-log "Microsoft-Windows-Dsc/Debug" /q:True /e:true 6 | wevtutil.exe set-log "Microsoft-Windows-Dsc/Operational" /q:True /e:true 7 | # do stuff in dsc... 8 | 9 | 10 | # 2. Collect the logs: 11 | $DscEvents = [System.Array](Get-WinEvent "Microsoft-Windows-Dsc/Operational") 12 | $DscEvents += [System.Array](Get-WinEvent "Microsoft-Windows-Dsc/Analytic" -Oldest) 13 | $DscEvents += [System.Array](Get-WinEvent "Microsoft-Windows-Dsc/Debug" -Oldest) 14 | 15 | # Group based on Job ID 16 | $SeparateDscOperations = $DscEvents | Group {$_.Properties[0].Value} 17 | 18 | 19 | $SeparateDscOperations[0].Group 20 | 21 | # Look at errors 22 | $SeparateDscOperations | Where-Object {$_.Group.LevelDisplayName -contains "Error"} 23 | 24 | # last 30 minutes 25 | $DateLatest = (Get-Date).AddMinutes(-30) 26 | $SeparateDscOperations | Where-Object {$_.Group.TimeCreated -gt $DateLatest} | 27 | 28 | # finding errors -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.2 - Using PowerShell Direct.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11-2 - Using PS Direct with Hyper-V 2 | # 3 | # Run on HV1 after Tiger/PSDirect has been created on HV1 4 | 5 | # 1. Create a credential object for ReskitAdministrator: 6 | $RKAn = 'Reskit\Administrator' 7 | $PS = 'Pa$$w0rd' 8 | $RKP = ConvertTo-SecureString -String $PS -AsPlainText -Force 9 | $T = 'System.Management.Automation.PSCredential' 10 | $RKCred = New-Object -TypeName $T -ArgumentList $RKAn,$RKP 11 | 12 | # 2. Display the details of the psdirect VM: 13 | Get-VM -Name psdirect 14 | 15 | # 3. Invoke a command on the VM, specifying VM name: 16 | $SBHT = @{ 17 | VMName = 'psdirect' 18 | Credential = $RKCred 19 | ScriptBlock = {hostname} 20 | } 21 | Invoke-Command @SBHT 22 | 23 | # 4. Invoke a command based on VMID: 24 | $VMID = (Get-VM -VMName psdirect).VMId.Guid 25 | Invoke-Command -VMid $VMID -Credential $RKCred -ScriptBlock {hostname} 26 | 27 | # 5. Enter a PS remoting session with the psdirect VM: 28 | Enter-PSSession -VMName psdirect -Credential $RKCred 29 | Get-CimInstance -Class Win32_ComputerSystem 30 | Exit-PSSession -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Thomas Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Get-DSCReport.ps1: -------------------------------------------------------------------------------- 1 | function Get-DscReport 2 | { 3 | [CmdletBinding()] 4 | param 5 | ( 6 | $AgentId = "$(throw 'Please enter an agaet ID')", 7 | $serviceURL = "httpS://SRV1.RESKIT.ORG:8080/PSDSCPullServer.svc" 8 | ) 9 | 10 | $RequestUri = "$serviceURL/Nodes(AgentId= '$AgentId')/Reports" 11 | Write-Verbose "ServiceURI: [$RequestUri]" 12 | $request = Invoke-WebRequest -Uri $requestUri -ContentType "application/json;odata=minimalmetadata;streaming=true;charset=utf-8" ` 13 | -UseBasicParsing -Headers @{Accept = "application/json";ProtocolVersion = "2.0"} ` 14 | -ErrorAction SilentlyContinue -ErrorVariable ev 15 | Write-Verbose $Request 16 | $object = ConvertFrom-Json $request.content 17 | Write-Verbose $object 18 | return $object.value 19 | } 20 | 21 | $Session = New-CimSession srv2 22 | $AgentID = (Get-DscLocalConfigurationManager -CimSession $session).AgentId 23 | $Reports = Get-DscReport -verbose -AgentId $AgentID 24 | 25 | Foreach ($Reportin $Reports) 26 | | FT jobid, operationtype, refreshmode, status, EndTime 27 | -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Recipe 10.3 - Finding and Installing DSC sources.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 13-3 - Finding and installing DSC Resources 2 | 3 | # 1. Find available repositories 4 | Get-PSRepository 5 | 6 | # 2. See what DSC resources you can find 7 | Find-DscResource -Repository 'PSGallery' | 8 | Measure-Object 9 | 10 | # 3. See what IIS resources might exist 11 | Find-DscResource | 12 | Where-Object ModuleName -match 'web|iis' | 13 | Select-Object -Property ModuleName,Version -Unique | 14 | Sort-Object -Property ModuleName 15 | 16 | # 4. Examine the xWebAdministration module 17 | Find-DscResource -ModuleName 'xWebAdministration' 18 | 19 | # 5. Install the xWebAdministration module (on SRV1) 20 | Install-Module -Name 'xWebAdministration' -Force 21 | 22 | # 6. See local module details: 23 | Get-Module -Name xWebAdministration -ListAvailable 24 | 25 | # 7. See what is in the module 26 | Get-DscResource -Module xWebAdministration 27 | 28 | # 8 what is IN the module 29 | $Mod = Get-Module -Name xWebAdministration -ListAvailable 30 | $P = $Mod.Path 31 | $FP = Split-Path -Parent $P 32 | Get-ChildItem -Path $FP, $FP\DSCResources -------------------------------------------------------------------------------- /PowerShellCookBook2019/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Thomas Lee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Chapter 06 - Deploying Windows Update/Recipe 6.4 - Creating computer target groups.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 6.4 - Creating computer taget groups 2 | # 3 | # Run this on WSUS1 4 | 5 | # 1. Create a WSUS computer target group for the Domain Controllers 6 | $WSUSServer = Get-WsusServer -Name WSUS1 -port 8530 7 | $WSUSServer.CreateComputerTargetGroup('Domain Controllers') 8 | 9 | # 2. Examine existing target groups and viewing the new one 10 | $WSUSServer.GetComputerTargetGroups() | 11 | Format-Table -Property Name 12 | 13 | # 3. Find the DCs 14 | Get-WsusComputer -NameIncludes DC 15 | 16 | # 4. Add DC1 and DC2 to the Domain Controllers Target Group 17 | Get-WsusComputer -NameIncludes DC | 18 | Add-WsusComputer -TargetGroupName 'Domain Controllers' 19 | 20 | # 5. Get the DC group 21 | $DCGroup = $WSUSServer.GetComputerTargetGroups() | 22 | Where-Object Name -eq 'Domain Controllers' 23 | 24 | # 6. Find thecomputers in the group: 25 | Get-WsusComputer | 26 | Where-Object ComputerTargetGroupIDs -Contains $DCGroup.id | 27 | Sort-Object -Property FullDomainName | 28 | Format-Table -Property FullDomainName, ClientVersion, 29 | LastSyncTime 30 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.3 - Using PowerShell Direct.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.3 - Using PS Direct with Hyper-V 2 | 3 | # 1. Create a credential object for ReskitAdministrator: 4 | $RKAn = 'Administrator' 5 | $PS = 'Pa$$w0rd' 6 | $RKP = ConvertTo-SecureString -String $PS -AsPlainText -Force 7 | $T = 'System.Management.Automation.PSCredential' 8 | $RKCred = New-Object -TypeName $T -ArgumentList $RKAn,$RKP 9 | 10 | # 2. Display the details of the PSDirect VM: 11 | Get-VM -Name PSDirect 12 | 13 | # 3. Invoke a command on the VM, specifying VM name: 14 | $SBHT = @{ 15 | VMName = 'PSDirect' 16 | Credential = $RKCred 17 | ScriptBlock = {hostname} 18 | } 19 | Invoke-Command @SBHT 20 | 21 | # 4. Invoke a command based on VMID: 22 | $VMID = (Get-VM -VMName PSDirect).VMId.Guid 23 | $ICMHT = @{ 24 | VMid = $VMID 25 | Credential = $RKCred 26 | ScriptBlock = {hostname} 27 | } 28 | Invoke-Command @ICMHT 29 | 30 | 31 | 32 | 33 | $VMID = (Get-VM -VMName PSDirect).VMId.Guid 34 | Invoke-Command -VMid $VMID -Credential $RKCred -ScriptBlock {hostname} 35 | 36 | # 5. Enter a PS remoting session with the psdirect VM: 37 | Enter-PSSession -VMName psdirect -Credential $RKCred 38 | Get-CimInstance -Class Win32_ComputerSystem 39 | Exit-PSSession -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.8 - Managing VM state.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.8 - Managing VM state 2 | 3 | # 1. Get the VM's state to check if it is off 4 | Stop-VM -Name PSDirect -WarningAction SilentlyContinue 5 | Get-VM -Name PSDirect 6 | 7 | # 2. Start the VM, get its status, then wait until the VM has an 8 | # IP address assigned and the networking stack is working, then 9 | # examine the VM's state: 10 | Start-VM -VMName PSDirect 11 | Wait-VM -VMName PSDirect -For IPAddress 12 | Get-Vm -VMName PSDirect 13 | 14 | # 3. Suspend and view the PSDirect VM: 15 | Suspend-VM -VMName PSDirect 16 | Get-VM -VMName PSDirect 17 | 18 | # 4. Resumve the VM 19 | Resume-VM -VMName PSDirect 20 | Get-VM -VMName PSDirect 21 | 22 | # 5. Save the VM and check status: 23 | Save-VM -VMName PSDirect 24 | Get-VM -VMName PSDirect 25 | 26 | # 6. Resume the saved VM and view the status: 27 | Start-VM -VMName PSDirect 28 | Get-Vm -VMName PSDirect 29 | 30 | # 7. Restart a VM: 31 | Restart-VM -VMName PSDirect -Force 32 | Get-VM -VMName PSDirect 33 | 34 | # 8. Wait for VM to get an IP address: 35 | Wait-VM -VMName PSDirect -For IPaddress 36 | Get-VM -VMName PSDirect 37 | 38 | # 8. Perform a hard power off on the VM: 39 | Stop-VM -VMName PSDirect -TurnOff 40 | Get-VM -VMname PSDirect -------------------------------------------------------------------------------- /Chapter 05 - Managing Shared Data/Recipe 5.4 - Creating an iSCSI Target.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 5.4 - Creating an iSCSI Target 2 | # Run from SRV1 as Administrator@reskit.org 3 | 4 | # 1. Install the iSCSI target feature on SRV1 5 | Install-WindowsFeature FS-iSCSITarget-Server 6 | 7 | # 2. Explore iSCSI target server settings: 8 | Get-IscsiTargetServerSetting 9 | 10 | # 3. Create a folder on SRV1 to hold the iscis virtual disk 11 | $NIHT = @{ 12 | Path = 'C:\iSCSI' 13 | ItemType = 'Directory' 14 | ErrorAction = 'SilentlyContinue' 15 | } 16 | New-Item @NIHT | Out-Null 17 | 18 | 19 | # 4. Create an iSCSI disk (that is a LUN): 20 | $LP = 'C:\iSCSI\SalesData.Vhdx' 21 | $LN = 'SalesTarget' 22 | $VDHT = @{ 23 | Path = $LP 24 | Description = 'LUN For Sales' 25 | SizeBytes = 500MB 26 | } 27 | New-IscsiVirtualDisk @VDHT 28 | 29 | # 5. Set the iSCSI target, specifiying who can initiate 30 | # an iSCSI connection. 31 | $THT = @{ 32 | TargetName = $LN 33 | InitiatorIds = 'DNSNAME:FS1.Reskit.Org' 34 | } 35 | New-IscsiServerTarget @THT 36 | 37 | # 6. Create iSCSI disk target mapping: 38 | Add-IscsiVirtualDiskTargetMapping -TargetName $LN -Path $LP 39 | 40 | 41 | 42 | # Undo: 43 | Get-IscsiServerTarget | Remove-IscsiServerTarget 44 | Get-IscsiVirtualDisk | Remove-IscsiVirtualDisk 45 | Remove-item $LP 46 | -------------------------------------------------------------------------------- /Chapter 05 - Managing Shared Data/Recipe 5.3 - Accessing SMB Shares.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 5.3 - Acessing SMB shares 2 | # 3 | # run from CL1 4 | # Uses the foo share on FS1 created earlier 5 | 6 | # 1. Examine the SMB client's configuration 7 | Get-SmbClientConfiguration 8 | 9 | # 2. You require SMB signing from the client. You must run this 10 | # command from an elevated console on the client computer 11 | $CHT = @{Confirm=$false} 12 | Set-SmbClientConfiguration -RequireSecuritySignature $True @CHT 13 | 14 | # 3. Examine SMB client's network interface 15 | Get-SmbClientNetworkInterface | 16 | Format-Table 17 | 18 | # 4. Examine the shares provided by FS1 19 | net view \\FS1 20 | 21 | # 5. Create a drive mapping, mapping the r: to the share on server FS1 22 | New-SmbMapping -LocalPath r: -RemotePath \\FS1.Reskit.Org\foo 23 | 24 | # 6. View the shared folder mapping 25 | Get-SmbMapping 26 | 27 | # 7. View the shared folder contents 28 | Get-ChildItem -Path r: 29 | 30 | # 8. Run a program from the shared file 31 | # assumes this application is already on that share 32 | R:\MarsInstaller.exe 33 | 34 | # 9. View existing connections 35 | # Note: you need to run this in an elevated console) 36 | Get-SmbConnection 37 | 38 | # 10. What files are open on FS1? If any files are open you view them 39 | # by doing this on FS1: 40 | Get-SmbOpenFile -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Setup-DSCWebApp.ps1: -------------------------------------------------------------------------------- 1 | # Setup-DSCWebApp.ps1 2 | # 3 | 4 | # Setup for DSC Recipe 5 | # Create folder/share on DC1 6 | $SB = { 7 | New-Item C:\ReskitApp -ItemType Directory 8 | New-SMBShare -Name ReskitApp -Path C:\ReskitApp 9 | } 10 | Invoke-Command -ComputerName DC1 -ScriptBlock $SB | 11 | Out-Null 12 | # Create Index.Htm on DC1 13 | $HP = '\\DC1.Reskit.Org\C$\ReskitApp\Index.htm' 14 | $P2 = '\\DC1.Reskit.Org\C$\ReskitApp\Page2.htm' 15 | 16 | $Index = @" 17 | 18 | 19 | Main Page - ReskitApp Application 20 |

21 | HOME PAGE FOR RESKITAPP APPLICATION

22 | This is the root page of the RESKITAPP application 23 |

24 | Pushed via DSC



25 | 26 | Click to View Page 2 27 |
28 |

29 | "@ 30 | $Index | 31 | Out-File -FilePath $HP -Force 32 | # Create Page2.htm on DC1 33 | $Page2 = @" 34 | 35 | 36 | ReskitApp Application - Page 2 37 |

38 | Page 2 For the ReskitApp Web Application

39 | 40 | Click to Go Home 41 |
42 | "@ 43 | $Page2 | 44 | Out-File -FilePath $P2 -Force 45 | -------------------------------------------------------------------------------- /Chapter 08 - Leveraging containers/Recipe 8.3 - Deploy IIS in a container.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 8.3 - Deploy iis in a container 2 | # 3 | # Run from CH1 4 | # Run inside the console, NOT the ISE 5 | 6 | # 1. Create reskitapp folder: 7 | $EA = @{ErrorAction='SilentlyContinue'} 8 | New-Item -Path C:\ReskitApp -ItemType Directory @EA 9 | 10 | # 2. Create a web page: 11 | $Fn = 'C:\Reskitapp\Index.htm' 12 | $Index = @" 13 | 14 | 15 | ReskitApp Container Application 16 |

17 | HOME PAGE FOR RESKITAPP APPLICATION

18 | Running in a container in Windows Server 2019

19 |



20 | "@ 21 | $Index | Out-File -FilePath $Fn 22 | 23 | # 3. Get a server core with IIS image from the Docker registry: 24 | docker pull mcr.microsoft.com/windows/servercore/iis 25 | 26 | # 4. Now run the image as a container named rkwebc: 27 | $image = 'mcr.microsoft.com/windows/servercore/iis' 28 | docker run -d -p80:80 --name rkwebc "$image" 29 | 30 | # 5.Copy our file into the container: 31 | Set-Location -Path C:\Reskitapp 32 | docker cp .\index.htm rkwebc:c:\inetpub\wwwroot\index.htm 33 | 34 | # 6. View the page: 35 | Start-Process "Http://CH1.Reskit.Org/Index.htm" 36 | 37 | # 7. Clean up: 38 | docker rm rkwebc -f | Out-Null 39 | docker image rm mcr.microsoft.com/windows/servercore/iis | 40 | Out-Null -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.5 - Configuring IIS Bindings.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 9.5 - Configure IIS bindings 2 | # 3 | # Run on SRV1 after running 9.1 4 | 5 | # 1. Import the web administration module 6 | Import-Module -Name WebAdministration 7 | 8 | # 2. Create and populate a new page 9 | $SitePath = 'C:\inetpub\WWW2' 10 | New-Item $SitePath -ItemType Directory | Out-Null 11 | $page = @' 12 | 13 | 14 | Main Page for WWW2.Reskit.Org 15 |

16 | HOME PAGE FOR WWW2.RESKIT.ORG

17 | This is the root page for this site 18 | 19 | 20 | '@ 21 | $PAGE | OUT-FILE $sitepath\INDEX.HTML | Out-Null 22 | 23 | # 3.Create a new web site that uses Host headers 24 | $WSHT = @{ 25 | PhysicalPath = $SitePath 26 | Name = 'WWW2' 27 | HostHeader = 'WWW2.reskit.org' 28 | } 29 | New-Website @WSHT 30 | 31 | 32 | # 4. Create DNS record on DC1 33 | Invoke-Command -Computer DC1.Reskit.Org -ScriptBlock { 34 | $DNSHT = @{ 35 | ZoneName = 'Reskit.Org' 36 | Name = 'www2' 37 | IpAddress = '10.10.10.50' 38 | } 39 | Add-DnsServerResourceRecordA @DNSHT 40 | } 41 | 42 | # 5. And show the site 43 | $IE = New-Object -ComObject InterNetExplorer.Application 44 | $URL = 'http://www2.reskit.org' 45 | $IE.Navigate2($URL) 46 | $IE.Visible = $true -------------------------------------------------------------------------------- /Chapter 02 - Managing Windows Networking/2.6 - Configuring DHCP Failover amd Load Balancing.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 2.6 - Configuring DHCP Load Balancing and Failover 2 | 3 | # Run on DC2 4 | 5 | # 1. Install the DHCP Server feature on DC2: 6 | $FHT = @{ 7 | Name = 'DHCP','RSAT-DHCP' 8 | ComputerName = 'DC2.Reskit.Org'} 9 | Install-WindowsFeature @FHT 10 | 11 | # 2. Let DHCP know it's all configured: 12 | $IPHT = @{ 13 | Path = 'HKLM:\SOFTWARE\Microsoft\ServerManager\Roles\12' 14 | Name = 'ConfigurationState' 15 | Value = 2 16 | } 17 | Set-ItemProperty @IPHT 18 | 19 | # 3. Authorize the DHCP server in AD and view the results 20 | Add-DhcpServerInDC -DnsName DC2.Reskit.Org 21 | 22 | # 4. View the DHCP Servers authorised in the domain 23 | Get-DhcpServerInDC 24 | 25 | # 5. Configure failover and load balancing: 26 | $FHT= @{ 27 | ComputerName = 'DC1.Reskit.Org' 28 | PartnerServer = 'DC2.Reskit.Org' 29 | Name = 'DC1-DC2' 30 | ScopeID = '10.10.10.0' 31 | LoadBalancePercent = 60 32 | SharedSecret = 'j3RryIsG0d!' 33 | Force = $true 34 | } 35 | Add-DhcpServerv4Failover @FHT 36 | - 37 | 38 | # 5. Get acrive leases in the scope (from both servers!) 39 | 'DC1', 'DC2' | 40 | ForEach-Object {Get-DhcpServerv4Scope -ComputerName $_} 41 | 42 | 43 | # 6. Now get serve statistics from both servers 44 | 'DC1', 'DC2' | 45 | ForEach-Object { 46 | Get-DhcpServerv4ScopeStatistics -ComputerName $_} 47 | -------------------------------------------------------------------------------- /Chapter 02 - Managing Windows Networking/2.2 - Configuring IP Addressing.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 2.2 - Configuring IP addressing 2 | 3 | # Run on SRV2 4 | 5 | # 1 Get existing IP address information for SRV2: 6 | $IPType = 'IPv4' 7 | $Adapter = Get-NetAdapter | 8 | Where-Object Status -eq 'Up' |Select -First 1 9 | $Interface = $Adapter | 10 | Get-NetIPInterface -AddressFamily $IPType 11 | $IfIndex = $Interface.ifIndex 12 | $IfAlias = $Interface.Interfacealias 13 | Get-NetIPAddress -InterfaceIndex $Ifindex -AddressFamily $IPType 14 | 15 | # 2. Set the IP address for SRV2 16 | $IPHT = @{ 17 | InterfaceAlias = $IfAlias 18 | PrefixLength = 24 19 | IPAddress = '10.10.10.51' 20 | DefaultGateway = '10.10.10.254' 21 | AddressFamily = $IPType 22 | } 23 | New-NetIPAddress @IPHT | Out-Null 24 | 25 | # 3. Set DNS Server details 26 | $CAHT = @{ 27 | InterfaceIndex = $IfIndex 28 | ServerAddresses = '10.10.10.10' 29 | } 30 | Set-DnsClientServerAddress @CAHT 31 | 32 | # 4. Test new configuration 33 | Get-NetIPAddress -InterfaceIndex $IfIndex -AddressFamily IPv4 34 | Test-NetConnection -ComputerName DC1.Reskit.Org 35 | Resolve-DnsName -Name SRV2.Reskit.Org -Server DC1.Reskit.Org | 36 | Where-Object Type -eq 'A' 37 | 38 | 39 | # Undo 40 | $IPHT = @{ 41 | InterfaceAlias = $IfAlias 42 | PrefixLength = 24 43 | IPAddress = '10.10.10.51' 44 | DefaultGateway = '10.10.10.254' 45 | AddressFamily = $IPType 46 | } 47 | New-NetIPAddress @IPHT -------------------------------------------------------------------------------- /Chapter 04 - Managing Storage/Recipe 4.1 - Using Disks.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 4.1 - Manaing physical Disks and Volumes 2 | # 3 | # Run on SRV1 4 | # SRV1 has 2 extra disks that are 'bare' and just added to the VM 5 | 6 | 7 | # 1. Get physical disks on this system: 8 | Get-Disk | 9 | Format-Table -AutoSize 10 | 11 | # 2. Initialize the disks 12 | Get-Disk | 13 | Where PartitionStyle -eq Raw | 14 | Initialize-Disk -PartitionStyle GPT 15 | 16 | # 3. Re-display disks 17 | Get-Disk | 18 | Format-Table -AutoSize 19 | 20 | # 4. Create a F: volume in disk 1 21 | $NVHT1 = @{ 22 | DiskNumber = 1 23 | FriendlyName = 'Storage(F)' 24 | FileSystem = 'NTFS' 25 | DriveLetter = 'F' 26 | } 27 | New-Volume @NVHT1 28 | 29 | # 5. Create two volumes in Disk 2 - first create G: 30 | New-Partition -DiskNumber 2 -DriveLetter G -Size 4gb 31 | 32 | # 6. Create a second partition H: 33 | New-Partition -DiskNumber 2 -DriveLetter H -UseMaximumSize 34 | 35 | # 7. Format G: and H: 36 | $NVHT1 = @{ 37 | DriveLetter = 'G' 38 | FileSystem = 'NTFS' 39 | NewFileSystemLabel = 'Log'} 40 | Format-Volume @NVHT1 41 | $NVHT2 = @{ 42 | DriveLetter = 'H' 43 | FileSystem = 'NTFS' 44 | NewFileSystemLabel = 'GDShow'} 45 | Format-Volume @NVHT2 46 | 47 | # 8. Get partitions on this system 48 | Get-Partition | 49 | Sort-Object -Property DriveLetter | 50 | Format-Table -Property DriveLetter, Size, Type 51 | 52 | # 9. Get Volumes on SRV1 53 | Get-Volume | 54 | Sort-Object -Property DriveLetter 55 | -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.2 - Install SSL.ps1: -------------------------------------------------------------------------------- 1 | # Revipe 10-2 - Configure IIS for SSL 2 | 3 | # 1 - Import the WebAdministration module 4 | Import-Module -Name WebAdministration 5 | 6 | # 2 - Create a self signed certificate 7 | $CHT = @{ 8 | CertStoreLocation = 'CERT:\LocalMachine\MY' 9 | DnsName = 'SRV1.Reskit.Org' 10 | } 11 | $SSLCert = New-SelfSignedCertificate @CHT 12 | 13 | # 3. Copy the certificate to the root store on SRV1: 14 | $C = 'System.Security.Cryptography.X509Certificates.X509Store' 15 | $Store = New-Object -TypeName $C ` -ArgumentList 'Root','LocalMachine' 16 | $Store.Open(‘ReadWrite’) 17 | $Store.Add($SSLcert) 18 | $Store.Close() 19 | 20 | # 4. Create a new SSL binding on the Default Web Site 21 | New-WebBinding -Name 'Default Web Site' -Protocol https -Port 443 22 | 23 | # 5 ASssign the cert created earlier to this new binding 24 | $sslcert | New-Item -Path IIS:\SslBindings\0.0.0.0!443 25 | 26 | # 6. View the site using https! 27 | $IE = New-Object -ComObject InterNetExplorer.Application 28 | $URL = 'https://srv1.reskit.org' 29 | $IE.Navigate2($URL) 30 | $IE.Visible = $true 31 | 32 | 33 | 34 | 35 | # cLEAN UP 36 | Get-ChildItem Cert:\LocalMachine\MY | Where-Object SUBJECT -MATCH 'SRV1.RESKIT.ORG' | Remove-ItemProperty 37 | Get-ChildItem Cert:\LocalMachine\ROOT | Where-Object SUBJECT -MATCH 'SRV1.RESKIT.ORG' | Remove-Item 38 | Get-ChildItem IIS:\SslBindings | Where-Object port -eq 443 | Remove-Item 39 | remove-webbinding -Protocol https -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.1 - Install IIS Server.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 9.1 Install/configure IIS 2 | # 3 | # Run from SRV1 4 | 5 | 6 | # 1. Add Web Server feature, sub-features, and tools to SRV1 7 | $FHT = @{ 8 | Name = 'Web-Server' 9 | IncludeAllSubFeature = $true 10 | IncludeManagementTools = $true 11 | } 12 | Install-WindowsFeature @FHT 13 | 14 | # 2. See what actual features are installed 15 | Get-WindowsFeature -Name Web* | Where-Object Installed 16 | 17 | # 3. Check the WebAdministration module 18 | $Modules = @('WebAdministration', 'IISAdministration') 19 | Get-Module -Name $Modules -ListAvailable 20 | 21 | # 4 Get counts of commands in each module 22 | $C1 = (Get-Command -Module WebAdministration | 23 | Measure-Object | 24 | Select-Object -Property Count).Count 25 | $C2 = (Get-Command -Module IISAdministration | 26 | Measure-Object | 27 | Select-Object -Property Count).Count 28 | "$C1 commands in WebAdministration Module" 29 | "$C2 commands in IISAdministration Module" 30 | 31 | # 5. Look at the IIS provider 32 | Import-Module -Name WebAdministration 33 | Get-PSProvider -PSProvider WebAdministration 34 | 35 | # 6. What is in the IIS: 36 | Get-ChildItem -Path IIS:\ 37 | 38 | # 7. What is in sites folder? 39 | Get-Childitem -Path IIS:\Sites 40 | 41 | # 8. Look at the default web site: 42 | $IE = New-Object -ComObject InterNetExplorer.Application 43 | $URL = 'HTTP://SRV1' 44 | $IE.Navigate2($URL) 45 | $IE.Visible = $true 46 | -------------------------------------------------------------------------------- /Chapter 12 - Exploring Azure/Recipe 12.2 - Azure Resources.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 12.2 - Create Azure Assets 2 | # 3 | # 4 | 5 | # 1. Set Key variables: 6 | $Locname = 'uksouth' # location name 7 | $RgName = 'packt_rg' # resource group we are using 8 | $SAName = 'packt42sa' # Storage account name 9 | 10 | # 2. Login to your Azure Account 11 | $CredAZ = Get-Credential 12 | $Account = Login-AzAccount -Credential $CredAZ 13 | 14 | # 3. Create a resource group and tag it 15 | $RGTag = [Ordered] @{Publisher='Packt'} 16 | $RGTag += @{Author='Thomas Lee'} 17 | $RGHT = @{ 18 | Name = $RgName 19 | Location = $Locname 20 | Tag = $RGTag 21 | } 22 | $RG = New-AzResourceGroup @RGHT 23 | $RG 24 | 25 | # 4 View RG with Tags 26 | Get-AzResourceGroup -Name $RGName | 27 | Format-List -Property * 28 | 29 | # 5. Test to see if an SA name is taken 30 | Get-AzStorageAccountNameAvailability $SAName 31 | 32 | # 6. Create a new Storage Account 33 | $SAHT = @{ 34 | Name = $SAName 35 | SkuName = 'Standard_LRS' 36 | ResourceGroupName = $RgName 37 | Tag = $RGTag 38 | Location = $Locname 39 | 40 | } 41 | New-AzStorageAccount @SAHT 42 | 43 | # 7. Get overview of the SA in this Resource group 44 | $SA = Get-AzStorageAccount -ResourceGroupName $RgName 45 | $SA | 46 | Format-List -Property * 47 | 48 | 49 | # 8. Get Primary Endpoints for the SA 50 | $SA.PrimaryEndpoints 51 | 52 | # 9. Review SKU 53 | $SA.Sku 54 | 55 | # 10. View Context property 56 | $SA.Context -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.2 - Configuring IIS for SSL.ps1: -------------------------------------------------------------------------------- 1 | # Revipe 10-2 - Configure IIS for SSL/TLS 2 | 3 | # 1 - Import the WebAdministration module 4 | Import-Module -Name WebAdministration 5 | 6 | # 2 - Create a self signed certificate 7 | $CHT = @{ 8 | CertStoreLocation = 'CERT:\LocalMachine\MY' 9 | DnsName = 'SRV1.Reskit.Org' 10 | } 11 | $SSLCert = New-SelfSignedCertificate @CHT 12 | 13 | # 3. Copy the certificate to the root store on SRV1: 14 | $C = 'System.Security.Cryptography.X509Certificates.X509Store' 15 | $AL = ‘Root’, ‘LocalMachine’ 16 | $Store = New-Object -TypeName $C -ArgumentList $AL 17 | $Store.Open(‘ReadWrite’) 18 | $Store.Add($SSLcert) 19 | $Store.Close() 20 | 21 | # 4. Create a new SSL binding on the Default Web Site 22 | $NBHT = @{ 23 | Name = 'Default Web Site' 24 | Protocol = 'https' 25 | Port = 443 26 | } 27 | New-WebBinding @NBHT 28 | 29 | # 5 ASssign the cert created earlier to this new binding 30 | $SSLCert | New-Item -Path IIS:\SslBindings\0.0.0.0!443 31 | 32 | # 6. View the site using https! 33 | $IE = New-Object -ComObject InterNetExplorer.Application 34 | $URL = 'https://srv1.reskit.org' 35 | $IE.Navigate2($URL) 36 | $IE.Visible = $true 37 | 38 | 39 | 40 | 41 | <# cLEAN UP for testing 42 | ls Cert:\LocalMachine\MY | WHERE SUBJECT -MATCH 'SRV1.RESKIT.ORG' | ri 43 | ls Cert:\LocalMachine\ROOT | WHERE SUBJECT -MATCH 'SRV1.RESKIT.ORG' | ri 44 | ls IIS:\SslBindings | where port -eq 443 | ri 45 | remove-webbinding -Protocol https 46 | #> -------------------------------------------------------------------------------- /Chapter 12 - Exploring Azure/Recipe 12.1 - Getting Started.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 12-1 Getting started with Azure 2 | # 3 | # Run on CL 4 | 5 | # 1. Find core Azure Modules 6 | Find-Module -Name Az 7 | 8 | # 2. Install AZ modules 9 | Install-Module -Name Az -Force 10 | 11 | # 3. Discover Azure modules and how many cmdlets each contain 12 | $HT = @{ Label ='Cmdlets' 13 | Expression = {(Get-Command -module $_.name).count}} 14 | Get-Module Az* -ListAvailable | 15 | Sort {(Get-command -Module $_.Name).Count} -Descending | 16 | Format-Table -Property Name,Version,Author,$HT -AutoSize 17 | 18 | # 4. Find Azure AD cmdlets 19 | Find-Module AzureAD | 20 | Format-Table -Property Name,Version,Author -AutoSize -Wrap 21 | 22 | # 5. Download the AzureAD Module 23 | Install-Module -Name AzureAD -Force 24 | 25 | # 6. Discover Azure AD Module 26 | $FTHT = @{ 27 | Property = 'Name', 'Version', 'Author', 'Description' 28 | AutoSize = $true 29 | Wrap = $true 30 | } 31 | Get-Module -Name AzureAD -ListAvailable | 32 | Format-Table @FTHT 33 | 34 | # 7. Login To Azure 35 | $Subscription = Login-AzAccount 36 | 37 | # 8. Get Azure Subscription details 38 | $SubID = $Subscription.Context.Subscription.SubscriptionId 39 | Get-AzSubscription -SubscriptionId $SubId | 40 | Format-List -Property * 41 | 42 | # 9. Get Azure Locations 43 | Get-AzLocation | Sort-Object Location | 44 | Format-Table Location, Displayname 45 | 46 | # 10 Get Azure Environments 47 | Get-AzEnvironment | 48 | Format-Table -Property name, ManagementPortalURL 49 | -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.7 - Get Printer Usage report.ps1: -------------------------------------------------------------------------------- 1 | # 1. Run WevtUtil to turn on printer monitoring. 2 | wevtutil.exe sl "Microsoft-Windows-PrintService/Operational" /enabled:true 3 | 4 | # 2. Define a function 5 | 6 | Function Get-PrinterUsage { 7 | # 2.1 Get events from the print server event log 8 | $LogName = 'Microsoft-Windows-PrintService/Operational' 9 | $Dps = Get-WinEvent -LogName $LogName | 10 | Where-Object ID -eq 307 11 | Foreach ($Dp in $Dps) { 12 | # 2.2 Ceate a hash table3 with an event log record 13 | $Document = [ordered] @{} 14 | # 2.3 Populate the hash table with properties from the 15 | # Event log entry 16 | $Document.Id = $Dp.Properties[0].value 17 | $Document.Type = $Dp.Properties[1].value 18 | $Document.User = $Dp.Properties[2].value 19 | $Document.Computer = $Dp.Properties[3].value 20 | $Document.Printer = $Dp.Properties[4].value 21 | $Document.Port = $Dp.Properties[5].value 22 | $Document.Bytes = $Dp.Properties[6].value 23 | $Document.Pages = $Dp.Properties[7].value 24 | 25 | # 2.4 Create an object for this printer usage entry 26 | $UEntry = New-Object -TypeName PSObject -Property $Document 27 | 28 | # 2.5 And give it a more relecant tyhpe name 29 | $UEntry.pstypenames.clear() 30 | $UEntry.pstypenames.add("Packt.PrintUsage") 31 | 32 | # 2.6 Output the entry 33 | $UEntry 34 | } # End of foreach 35 | 36 | } # End of function 37 | 38 | # 3.0 Set and use an alias to get printer usage 39 | Get-PrinterUsage | Format-Table -------------------------------------------------------------------------------- /Chapter 03 - Deploying Active Directory/3.6 - Finding expired computers and disabled users in AD.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 3.5 - Finding expired computers and disabled users in AD 2 | 3 | # 1.Build the report header 4 | $RKReport = '' 5 | $RkReport += "*** Reskit.Org AD Daily AD report`n" 6 | $RKReport += "*** Generated [$(Get-Date)]`n" 7 | $RKReport += "***********************************`n`n" 8 | 9 | # 2. Report on computer accounts that have not logged in the past month 10 | $RkReport += "*** Machines not logged on in past month`n" 11 | $AMonthAgo = (Get-Date).AddMonths(-1) 12 | $ADCHT2 = @{ 13 | Properties = 'lastLogonDate' 14 | Filter = 'lastLogonDate -lt $AMonthAgo' 15 | } 16 | $RkReport += Get-ADComputer @ADCHT2 | 17 | Sort-Object -Property lastLogonDate | 18 | Format-Table -Property Name, LastLogonDate | 19 | Out-String 20 | 21 | # 3. Get users who have not logged on in the past month 22 | $RKReport += "*** Users not logged on in past month`n" 23 | $RkReport += Get-AdUser @ADCHT2 | 24 | Sort-Object -Property lastLogonDate | 25 | Format-Table -Property Name, LastLogonDate | 26 | Out-String 27 | 28 | # 4. Find any user accounts that are disabled 29 | 30 | $ADCHT3 = @{ 31 | Properties = 'Enabled' 32 | } 33 | $RKReport += "*** Disabled Users`n" 34 | $RkReport += Get-ADUser @Adcht3 -Filter {Enabled -ne $true}| 35 | Sort-Object -Property lastLogonDate | 36 | Format-Table -Property Name, LastLogonDate | 37 | Out-String 38 | 39 | # 5. Display the Report 40 | $RKReport -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.2 - Using WMI to retreive performance counters.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 12.2 - Get Performance Counters using CIM Cmdlets 2 | # 3 | # Run on SRV1 4 | 5 | # 1. Find Perf related counters in Root\CIMV2 namespace: 6 | Get-CimClass -ClassName Win32*perf* | Measure-Object | 7 | Select-Object -Property Count 8 | Get-CimClass -ClassName Win32*perfFormatted* | Measure-Object | 9 | Select-Object -Property Count 10 | Get-CimClass -ClassName Win32*perfraw* | Measure-Object | 11 | Select-Object -Property Count 12 | 13 | # 2. Find key Performance classes for the OS 14 | Get-CimClass "Win32_PerfFormatted*PerfOs*" | 15 | Select-Object -Property CimClassName 16 | 17 | # 3. Find key performance classes for the disk 18 | Get-CimClass "win32_PerfFormatted*Disk*" | 19 | Select-Object -Property CimClassName 20 | 21 | # 4. Get Memory counter samples 22 | $Class = 'Win32_PerfFormattedData_PerfOS_Memory' 23 | Get-CimInstance -ClassName $Class | 24 | Select-Object -Property PagesPerSec, AvailableMBytes 25 | 26 | # 5. Get CPU counter samples 27 | $Class2 = 'Win32_PerfFormattedData_PerfOS_Processor' 28 | Get-CimInstance -ClassName $Class2 | 29 | Where-Object Name -eq '_Total' | 30 | Select-Object -Property Name, PercentProcessortime 31 | 32 | # 6. Get Memory counter samples from a remote system 33 | $CHT = @{ 34 | ClassName = 'Win32_PerfFormattedData_PerfOS_Memory' 35 | ComputerName = 'DC1' 36 | } 37 | Get-CimInstance @CHT | 38 | Select-Object -Property PSComputerName, PagesPerSec, 39 | AvailableMBytes 40 | -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.4 - Reporting on Performance Data.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 13.4 - Create Performance Report 2 | # 3 | # Uses CSV output from Recipe 13.3 4 | # Run on SRV1 5 | 6 | # 1 - Import the CSV file of counters 7 | $Folder = 'C:\PerfLogs\Admin' 8 | $File = Get-ChildItem -Path $folder\*.csv -Recurse 9 | 10 | # 2. Import the performance counters. 11 | $Counters = Import-Csv $File.FullName 12 | "$($Counters.Count) counters in $($File.FullName)" 13 | 14 | # 3. Fix issue with 1st row in the counters 15 | $Counters[0] = $Counters[1] 16 | 17 | # 4. Obtain basic CPU stats 18 | $CN = '\\SRV1\Processor(_Total)\% Processor Time' 19 | $HT = @{ 20 | Name = 'CPU' 21 | Expression = {[System.Double] $_.$cn} 22 | } 23 | $Stats = $counters | 24 | Select-Object -Property *,$ht | 25 | Measure-Object -Property CPU -Average -Minimum -Maximum 26 | 27 | # 5. Add 95th percent value of CPU 28 | $CN = '\\srv1\Processor(_Total)\% Processor Time' 29 | $Row = [int]($Counters.Count * .95 ) 30 | $CPU = ($Counters.$CN | Sort-Object) 31 | $CPU95 = [double] $CPU[$Row] 32 | $AMHT = @{ 33 | InputObject = $Stats 34 | Name = 'CPU95' 35 | MemberType = 'NoteProperty' 36 | Value = $CPU95 37 | } 38 | Add-Member @AMHT 39 | 40 | # 6. Combine the results into a single report: 41 | $Stats.CPU95 = $Stats.CPU95.ToString('n2') 42 | $Stats.Average = $Stats.Average.ToString('n2') 43 | $Stats.Maximum = $Stats.Maximum.ToString('n2') 44 | $Stats.Minimum = $Stats.Minimum.ToString('n2') 45 | 46 | # 7. Display statistics 47 | $Stats | 48 | Format-Table -Property Property,Count, Maximum, CPU95, Minimum -------------------------------------------------------------------------------- /Chapter 14 - Troubleshooting WIndows Server/Recipe 14.X - Use TroubleShooting packs.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 14.3 - Use troubleshooting packs 2 | # 3 | # Run on SRV1 4 | 5 | # 6 | # NB: THis recipe was cut from the book, but here it is. 7 | # Using Get-TroubleshootingPack with -Answerfile does not work propertly. 8 | 9 | # 1. Get Trobleshooting packs 10 | $Path = 'C:\Windows\diagnostics\system' 11 | $TSPackfolders = Get-ChildItem -Path $Path -Directory 12 | $TSPacks = 13 | Foreach ($TSPack in $TSPackfolders) { 14 | Get-TroubleshootingPack -Path $TSPack.FullName} 15 | 16 | # 2. Display the packs 17 | $FTHT = @{ 18 | Property = 'Name', 19 | 'Version', 20 | 'MinimumVersion', 21 | 'Description' 22 | Wrap = $true 23 | AutoSize = $true 24 | } 25 | $TSPacks | Format-Table @FTHT 26 | 27 | # 3. Get a troubleshooting pack 28 | $TsPack = $TSPacks | Where-Object id -eq 'NetworkDiagnostics' 29 | 30 | # 4. look at the problems this pack looks for 31 | $TSPack.RootCauses 32 | 33 | # 5. And look at the solutions to these issues 34 | $TSPack.RootCauses.Resolutions 35 | 36 | # 6. Run this troubleshooting pack 37 | # (answering questions from the command line) 38 | $TsPack | Invoke-TroubleshootingPack 39 | 40 | # 7. Use get-TroubleshootingPack to create an answer file: 41 | $TSHT = @{ 42 | Path = $TSPack.Path 43 | AnswerFile = 'c:\Answers.xml' 44 | } 45 | Get-TroubleshootingPack @TSHT 46 | 47 | # 8. Display the XML: 48 | Get-Content -Path C:\Answers.xml 49 | 50 | # 9. Run WU pack using answer file 51 | $AFHT = @{ 52 | AnswerFile = 'C:\Answers.xml' 53 | Unattend = $true 54 | } 55 | $TsPack | 56 | Invoke-TroubleshootingPack @AFHT 57 | -------------------------------------------------------------------------------- /Chapter 06 - Deploying Windows Update/Recipe 6.5 - Configuring WSUS auto-approvals.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 6.5 - Configuring WSUS Auto Approvals 2 | # 3 | # Run on WSUS! 4 | 5 | # 1. Create the auto-approval rule: 6 | $WSUSServer = Get-WsusServer 7 | $ApprovalRule = 8 | $WSUSServer.CreateInstallApprovalRule('Critical Updates') 9 | 10 | # 2. Define a deadline for the rule: 11 | $Type = 'Microsoft.UpdateServices.Administration.' + 12 | 'AutomaticUpdateApprovalDeadline' 13 | $RuleDeadLine = New-Object -Typename $Type 14 | $RuleDeadLine.DayOffset = 3 15 | $RuleDeadLine.MinutesAfterMidnight = 180 16 | $ApprovalRule.Deadline = $RuleDeadLine 17 | 18 | # 3. Add update classifications to the rule: 19 | $UC = $ApprovalRule.GetUpdateClassifications() 20 | $C= $WSUSServer.GetUpdateClassifications() | 21 | Where-Object -Property Title -eq 'Critical Updates' 22 | $UC.Add($C) 23 | $D = $WSUSServer.GetUpdateClassifications() | 24 | Where-Object -Property Title -eq 'Definition Updates' 25 | $UC.Add($D) 26 | $ApprovalRule.SetUpdateClassifications($UpdateClassification) 27 | 28 | 29 | # 4. Assign the rule to a computer target group: 30 | $Type = 'Microsoft.UpdateServices.Administration.'+ 31 | 'ComputerTargetGroupCollection' 32 | $TargetGroups = New-Object $Type 33 | $TargetGroups.Add(($WSUSServer.GetComputerTargetGroups() | 34 | Where-Object -Property Name -eq "Domain Controllers")) 35 | $ApprovalRule.SetComputerTargetGroups($TargetGroups) 36 | 37 | # 5. Enable and save the rule: 38 | $ApprovalRule.Enabled = $true 39 | $ApprovalRule.Save() 40 | 41 | # 6. Get a list of approval rules 42 | $WSUSServer.GetInstallApprovalRules() | 43 | Format-Table -Property Name, Enabled, Action 44 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.5 - Configuring VM hardware.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.5 - Configuring VM Hardware 2 | # 3 | # Run on HV1, using PSDirect VM 4 | 5 | # 1. Turn off the VM1 VM 6 | Stop-VM -VMName PSDirect 7 | Get-VM -VMName PSDirect 8 | 9 | # 2. Set the StartupOrder in the VM's BIOS: 10 | $Order = 'IDE','CD','LegacyNetworkAdapter','Floppy' 11 | Set-VMBios -VmName PSDirect -StartupOrder $Order 12 | Get-VMBios PSDirect 13 | 14 | # 3. Set CPU count for PSDirect 15 | Set-VMProcessor -VMName PSDirect -Count 2 16 | Get-VMProcessor -VmName PSDirect | 17 | Format-Table VMName, Count 18 | 19 | # 4. Set PSDirect memory 20 | $VMHT = [ordered] @{ 21 | VMName = 'PSDirect' 22 | DynamicMemoryEnabled = $true 23 | MinimumBytes = 512MB 24 | StartupBytes = 1GB 25 | MaximumBytes = 2GB 26 | } 27 | Set-VMMemory @VMHT 28 | Get-VMMemory -VMName PSDirect 29 | 30 | # 5. Add a ScsiController to PSDirect 31 | Add-VMScsiController -VMName PSDirect 32 | Get-VMScsiController -VMName PSDirect 33 | 34 | # 6. Restart the VM 35 | Start-VM -VMName PSDirect 36 | Wait-VM -VMName PSDirect -For IPAddress 37 | 38 | # 7. Create a new VHDX file: 39 | $VHDPath = 'C:\Vm\Vhds\PSDirect-D.VHDX' 40 | New-VHD -Path $VHDPath -SizeBytes 8GB -Dynamic 41 | 42 | # 8. Add the VHD to the ScsiController: 43 | $VHDHT = @{ 44 | VMName = 'PSDirect' 45 | ControllerType = 'SCSI' 46 | ControllerNumber = 0 47 | ControllerLocation = 0 48 | Path = $VHDPath 49 | } 50 | Add-VMHardDiskDrive @VHDHT 51 | 52 | # 9. Get Volumes from PSDirect 53 | Get-VMScsiController -VMName PSDirect | 54 | Select-Object -ExpandProperty Drives 55 | 56 | 57 | 58 | 59 | 60 | PS C:\foo> -------------------------------------------------------------------------------- /Chapter 01 - Establishing a PowerShell Administrative Environment/1.4 - Creating an internal PS repository.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 1.4 - Creating an internal PowerShell repository 2 | 3 | # 1. Create repository folder 4 | $LPATH = 'C:\RKRepo' 5 | New-Item -Path $LPATH -ItemType Directory | Out-Null 6 | 7 | # 2. Share the folder for others 8 | $SMBHT = @{ 9 | Name = 'RKRepo' 10 | Path = $LPATH 11 | Description = 'Reskit Repopository' 12 | FullAccess = 'Everyone' 13 | } 14 | New-SmbShare @SMBHT 15 | 16 | # 3. Create the repository as trusted 17 | $Path = '\\SRV1\RKRepo' 18 | $REPOHT = @{ 19 | Name = 'RKRepo' 20 | SourceLocation = $Path 21 | PublishLocation = $Path 22 | InstallationPolicy = 'Trusted' 23 | } 24 | Register-PSRepository @REPOHT 25 | 26 | # 4. View configured repositories 27 | Get-PSRepository 28 | 29 | # 5. Create a Hello World module folder 30 | New-Item C:\HW -ItemType Directory 31 | 32 | # 6. And Create a very simple module 33 | $HS = @" 34 | Function Get-HelloWorld {'Hello World'} 35 | Set-Alias GHW Get-HelloWorld 36 | "@ 37 | $HS | Out-File C:\HW\HW.psm1 38 | 39 | # 7. Load and test the Module 40 | Import-Module -Name c:\hw -verbose 41 | GHW 42 | 43 | # 8. Create a Manifest for the new modle 44 | $NMHT = @{ 45 | Path = 'C:\HW\HW.psd1' 46 | RootModule = 'HW.psm1' 47 | Description = 'Hello World module' 48 | Author = 'DoctorDNS@Gmail.com' 49 | FunctionsToExport = 'Get-HelloWorld' 50 | } 51 | 52 | # 9. Publish the module: 53 | Publish-Module -Path C:\HW -Repository RKRepo 54 | 55 | # 10. See the results of publishing 56 | Find-Module -Repository RKRepo 57 | 58 | # 11. See repo folder 59 | Get-ChildItem -Path C:\RKRepo 60 | 61 | -------------------------------------------------------------------------------- /Chapter 05 - Managing Shared Data/Recipe 5.5 - Using an iSCSI target.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 5.5 - Using an ISCSI Target 2 | # 3 | # Run from FS1 4 | 5 | 6 | # 1. Adjust the iSCSI service to auto start, then start the service 7 | Set-Service MSiSCSI -StartupType 'Automatic' 8 | Start-Service MSiSCSI 9 | 10 | # 2. Setup portal to SRV1 11 | $PHT = @{ 12 | TargetPortalAddress = 'SRV1.Reskit.Org' 13 | TargetPortalPortNumber = 3260 14 | } 15 | New-IscsiTargetPortal @PHT 16 | 17 | # 3. Find and view the SalesTarget on portal 18 | $Target = Get-IscsiTarget | 19 | Where-Object NodeAddress -Match 'SalesTarget' 20 | $Target 21 | 22 | # 4. Connect to the target on SRV1 23 | $CHT = @{ 24 | TargetPortalAddress = 'SRV1.Reskit.Org' 25 | NodeAddress = $Target.NodeAddress 26 | } 27 | Connect-IscsiTarget @CHT 28 | 29 | 30 | # 5. View ICI disk from FST on SRV1 31 | $ISD = Get-Disk | 32 | Where-Object BusType -eq 'iscsi' 33 | $ISD | 34 | Format-Table -AutoSize 35 | 36 | # 6. Turn disk online and make R/W 37 | $ISD | 38 | Set-Disk -IsOffline $False 39 | $ISD | 40 | Set-Disk -Isreadonly $False 41 | 42 | # 7. Format the volume on FS1 43 | $NVHT = @{ 44 | FriendlyName = 'SalesData' 45 | FileSystem = 'NTFS' 46 | DriveLetter = 'I' 47 | } 48 | $ISD | 49 | New-Volume @NVHT 50 | 51 | # 8. Use the drive as a local drive: 52 | Set-Location -Path I: 53 | New-Item -Path I:\ -Name SalesData -ItemType Directory | 54 | Out-Null 55 | 'Testing 1-2-3' | 56 | Out-File -FilePath I:\SalesData\Test.Txt 57 | Get-ChildItem I:\SalesData 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | <# Undo it 66 | 67 | Disconnect-IscsiTarget -NodeAddress iqn.1991-05.com.microsoft:srv1-salestarget-target -Confirm:$false 68 | 69 | #> -------------------------------------------------------------------------------- /ReskitNetwork.md: -------------------------------------------------------------------------------- 1 | # Reskit Network Topology 2 | 3 | This file contains the details of the Reskit Network 4 | Suitably updated - this is nearly a hosts file for the HV host. 5 | 6 | ## Core Servers 7 | 8 | ``` powershell 9 | # Domain controllers 10 | 10.10.10.10 DC1.Reskit.Org 11 | 10.10.10.11 DC2.Reskit.Org 12 | 13 | # Certificate servers 14 | 10.10.10.20 RootCA.Reskit.Org 15 | 10.10.10.21 CA.Reskit.Org 16 | 17 | # General purpose servers 18 | 10.10.10.50 SRV1.Reskit.Org 19 | 10.10.10.51 SRV2.Reskit.Org 20 | ``` 21 | 22 | ## File and Storage Servers 23 | 24 | ```powershell 25 | # Scale-Out File server cluster address 26 | 10.10.10.100 FS.Reskit.Org # Cluster address 27 | 28 | # Individual nodes 29 | 10.10.10.101 FS1.Reskit.Org 30 | 10.10.10.102 FS2.Reskit.Org 31 | 32 | # Storage servers (iScsi targers. Storage Spaces Direct cluster) 33 | 10.10.10.111 SSRV1.Reskit.Org 34 | 10.10.10.112 SSRV2.Reskit.Org 35 | 10.10.10.113 SSRV3.Reskit.Org 36 | 37 | ``` 38 | 39 | ## Hyper-V nodes 40 | 41 | ```powershell 42 | # Hyper-V Cluster address 43 | 10.10.10.200 HV.Reskit.Org 44 | # Individual Hyper-V nodes 45 | 10.10.10.201 HV1.Reskit.Org 46 | 10.10.10.202 HV2.Reskit.Org 47 | ``` 48 | ## NLB IIS servers 49 | 50 | ```powershell 51 | 10.10.10.52 NLB1.Reskit.Org 52 | 10.10.10.52 NLB2.Reskit.Org 53 | ```` 54 | 55 | ## Print server 56 | 57 | ```powershell 58 | 10.10.10.60 PSRV.Reskit.Org 59 | ``` 60 | 61 | ## Windows Software Update Services (WSUS) 62 | 63 | ```powershell 64 | # WSUS server 65 | 10.10.10.240 WSUS1.Reskit.Org 66 | ``` 67 | 68 | ## IP address for the host 69 | 70 | ```powershell 71 | # Assign nice name for host 72 | 10.10.10.252 Home.Reskit.Org 73 | ``` 74 | -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Recipe 10.2 - Paramaterising DSC Configuration .ps1: -------------------------------------------------------------------------------- 1 | # Recipe 13-2 - Paramaterize DSC Configuratin 2 | 3 | # 1. Check status of DNS on SRV2 4 | Get-WindowsFeature DNS -ComputerName SRV2 5 | 6 | # 2. Create configuration 7 | Configuration ProvisionServices 8 | { 9 | param ( 10 | [Parameter(Mandatory=$true)] $NodeName, 11 | [Parameter(Mandatory=$true)] $FeatureName) 12 | Import-DscResource –ModuleName 'PSDesiredStateConfiguration' 13 | Node $NodeName 14 | { 15 | WindowsFeature $FeatureName 16 | { 17 | Name = $FeatureName 18 | Ensure = 'Present' 19 | IncludeAllSubFeature = $true 20 | } # End Windows Feature 21 | } # End Node configuration 22 | } # End of Configuration document 23 | 24 | # 3. Ensure an empty DSC folder exists, then create MOF file 25 | $NIHT = @{ 26 | Path = 'C:\DSC ' 27 | ItemType = 'Directory' 28 | ErrorAction = 'SilentlyContinue' 29 | } 30 | New-Item @NIHT| Out-Null 31 | Get-ChildItem -Path C:\DSC | Remove-Item -Force | Out-Null 32 | 33 | # 4. Clear any existing Configuration documents on SRV2 34 | $RIHT =@{ 35 | Path = '\\SRV2\c$\Windows\System32\configuration\*.mof' 36 | ErrorAction = 'SilentlyContinue' 37 | } 38 | Get-Childitem '\\SRV2\C$\Windows\System32\configuration\*.MOF' | 39 | Remove-Item @RIHT -Force 40 | 41 | # 5. Now run ProvisionServices to create the MOF to provision DNS on SRV2 42 | $PSHT = @{ 43 | OutputPath = 'C:\DSC' 44 | NodeName = 'SRV2' 45 | FeatureName = 'DNS' 46 | } 47 | ProvisionServices @PSHT 48 | 49 | # 6. Do it... 50 | Start-DscConfiguration -Path C:\DSC -Wait -Verbose 51 | 52 | # 7. Check results 53 | Get-Service -Name DNS -ComputerName SRV2 54 | -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.7 - Manage Applications and Application Pools.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 9.7 - Manage Applications and Applications Pools 2 | # 3 | # Run on SRV1 after running 9.5, and 9.1 4 | 5 | # 1. Import the web administration module 6 | Import-Module -Name WebAdministration 7 | 8 | # 2. Create new application poor 9 | New-WebAppPool -Name WWW2Pool 10 | 11 | # 3. Create new application in the pool 12 | $WAHT = @{ 13 | Name = 'WWW2' 14 | Site = 'WWW2' 15 | ApplicationPool = 'WWW2Pool' 16 | PhysicalPath = 'C:\inetpub\WWW2' 17 | } 18 | New-WebApplication @WAHT 19 | 20 | # 4. View the application pools 21 | Get-IISAppPool 22 | 23 | # 5. Set Application Pool Restart time 24 | $IPHT1 = @{ 25 | Path = 'IIS:\AppPools\WWW2Pool' 26 | Name = 'Recycling.periodicRestart.schedule' 27 | } 28 | Clear-ItemProperty @IPHT1 29 | $RestartAt = @('07:55', '19:55') 30 | New-ItemProperty @IPHT1 -Value $RestartAt 31 | 32 | # 6. Set Application Pool Maximum Private memory 33 | $IPHT2 = @{ 34 | Path = 'IIS:\AppPools\WWW2Pool' 35 | Name = 'Recycling.periodicRestart.privatememory' 36 | } 37 | Clear-ItemProperty @IPHT2 38 | [int32] $PrivMemMax = 150mb 39 | Set-ItemProperty -Path 'IIS:\AppPools\WWW2Pool' ` 40 | -Name Recycling.periodicRestart.privateMemory ` 41 | -Value $PrivMemMax 42 | 43 | # 7. Set max requests before a recycle and view 44 | $IPHT3 = @{ 45 | Path = 'IIS:\AppPools\WWW2Pool' 46 | Name = 'Recycling.periodicRestart.requests' 47 | } 48 | Clear-ItemProperty @IPHT3 49 | [int32] $MaxRequests = 104242 50 | Set-ItemProperty @IPHT3 -Value $MaxRequests 51 | Get-ItemProperty @IPHT3 52 | 53 | # 8. Recyle the app pool 54 | $Pool = Get-IISAppPool -Name WWW2Pool 55 | $Pool.Recycle() 56 | -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7.6 - Modiying printer security.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 4-7 - Modifying printer security 2 | # 3 | # Run on PSRV, after Create-Sales.ps1 has run 4 | 5 | # 1. Download the Set-PrinterPermissions script. 6 | $URL = 'https://gallery.technet.microsoft.com/scriptcenter/' + 7 | 'Modify-Printer-Permissions-149ae172/file/116651/1/' + 8 | 'Set-PrinterPermissions.ps1' 9 | $Target = 'C:\Foo\Set-PrinterPermissions.ps1' 10 | Start-BitsTransfer -Source $URL -Destination $Target 11 | 12 | # 2. Get help on the script 13 | Get-Help $Target 14 | 15 | # 3. Use PrintUI.DLL to bring up the printer properties GUI: 16 | rundll32.exe printui.dll,PrintUIEntry /p /nSalesprinter1 17 | 18 | # 4. From the GUI, click on Security to view the initial ACL. 19 | 20 | # 5. Remove the Everyone Group ACE from the printers ACL 21 | $SPHT1 = @{ 22 | ServerName = 'PSRV' 23 | Remove = $True 24 | AccountName = 'EVERYONE' 25 | SinglePrinterName = 'SalesPrinter1' 26 | } 27 | C:\foo\Set-PrinterPermissions.ps1 @SPHT1 28 | 29 | # 6. Add Sales group to ACL with Print permissions 30 | $SPHT2 = @{ 31 | ServerName = 'PSRV' 32 | AccountName = 'Reskit\Sales' 33 | AccessMask = 'Print' 34 | SinglePrinterName = 'SalesPrinter1' 35 | } 36 | C:\foo\Set-PrinterPermissions.ps1 @SPHT2 37 | 38 | # 7. Give SalesAdmins manage documents permission, and log 39 | $SPHT3 = @{ 40 | ServerName = 'PSRV' 41 | AccountName = 'Reskit\SalesAdmins' 42 | AccessMask = 'ManageDocuments' 43 | SinglePrinterName = 'SalesPrinter1' 44 | } 45 | C:\foo\Set-PrinterPermissions.ps1 @SPHT3 46 | 47 | # 8. Bring up the Printer Gui 48 | rundll32.exe printui.dll,PrintUIEntry /p /nSalesprinter1 49 | 50 | # 9. Click the security tab and view the updated ACL 51 | 52 | -------------------------------------------------------------------------------- /PowerShellCookBook2019/ReskitNetwork.md: -------------------------------------------------------------------------------- 1 | # Reskit Network Topology 2 | 3 | This file contains the details of the Reskit Network 4 | Suitably updated - this is nearly a hosts file for the HV host. 5 | 6 | ## Core Servers 7 | 8 | ``` powershell 9 | # Domain controllers 10 | 10.10.10.10 DC1.Reskit.Org 11 | 10.10.10.11 DC2.Reskit.Org 12 | 13 | # Certificate servers 14 | 10.10.10.20 RootCA.Reskit.Org 15 | 10.10.10.21 CA.Reskit.Org 16 | 17 | # General purpose servers 18 | 10.10.10.50 SRV1.Reskit.Org 19 | 10.10.10.51 SRV2.Reskit.Org 20 | ``` 21 | 22 | ## File and Storage Servers 23 | 24 | ```powershell 25 | # Scale-Out File server cluster address 26 | 10.10.10.100 FS.Reskit.Org # Cluster address 27 | 28 | # Individual nodes 29 | 10.10.10.101 FS1.Reskit.Org 30 | 10.10.10.102 FS2.Reskit.Org 31 | 32 | # Storage servers (iScsi targers. Storage Spaces Direct cluster) 33 | 10.10.10.111 SSRV1.Reskit.Org 34 | 10.10.10.112 SSRV2.Reskit.Org 35 | 10.10.10.113 SSRV3.Reskit.Org 36 | 37 | ``` 38 | 39 | ## Hyper-V nodes 40 | 41 | ```powershell 42 | # Hyper-V Cluster address 43 | 10.10.10.200 HV.Reskit.Org 44 | # Individual Hyper-V nodes 45 | 10.10.10.201 HV1.Reskit.Org 46 | 10.10.10.202 HV2.Reskit.Org 47 | ``` 48 | ## NLB IIS servers 49 | 50 | ```powershell 51 | 10.10.10.52 NLB1.Reskit.Org 52 | 10.10.10.52 NLB2.Reskit.Org 53 | ```` 54 | 55 | ## Print server 56 | 57 | ```powershell 58 | 10.10.10.60 PSRV.Reskit.Org 59 | ``` 60 | 61 | ## Windows Software Update Services (WSUS) 62 | 63 | ```powershell 64 | # WSUS server 65 | 10.10.10.240 WSUS1.Reskit.Org 66 | ``` 67 | 68 | ## IP address for the host 69 | 70 | ```powershell 71 | # Assign nice name for host 72 | 10.10.10.252 Home.Reskit.Org 73 | ``` 74 | -------------------------------------------------------------------------------- /Chapter 14 - Troubleshooting WIndows Server/Recipe 14.2 - Using BPA.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 14.2 - Using BPA 2 | # 3 | # Run on SRV1 4 | # uses DC1 5 | 6 | # 1. Get all BPA Models on SRV1 7 | Get-BpaModel | 8 | Format-Table -Property Name, Id, LastScanTime -Wrap 9 | 10 | # 2. Invoke BPA model for Web Server feature 11 | Invoke-BpaModel -ModelId Microsoft/Windows/WebServer 12 | 13 | # 3. Get the results of the BPA run 14 | $Results = Get-BpaResult -ModelId Microsoft/Windows/webServer 15 | 16 | # 4. Display how many tests/results in the BPA model 17 | $Results.Count 18 | 19 | # 5 How many errors and warnings were found? 20 | $Errors = $Results | Where-Object Severity -eq 'Error' 21 | $Warnings = $Results | Where-Object Severity -eq 'Warning' 22 | "Errors found : {0}" -f $Errors.Count 23 | "Warnings found : {0}" -f $Warnings.Count 24 | 25 | # 6. Look at other BPA Results: 26 | $Results | Format-Table -Property Title, Compliance -Wrap 27 | 28 | # 7. Use BPA Remotely - what models exist on DC1? 29 | Invoke-Command -ComputerName DC1 -ScriptBlock {Get-BpaModel} | 30 | Format-Table -Property Name, Id 31 | 32 | # 8. Run BPA Analyzer on DC1 33 | $ModelId = 'Microsoft/Windows/DirectoryServices' 34 | $SB = {Invoke-BpaModel -ModelId $using:ModelId} 35 | Invoke-Command -ComputerName DC1 -ScriptBlock $SB 36 | 37 | # 9. Get the results of DS BPA from DC1 38 | $SB = {Get-BpaResult -ModelId Microsoft/Windows/DirectoryServices} 39 | $RRESULTS = Invoke-Command -ComputerName DC1 -ScriptBlock $SB 40 | 41 | # 10 How many checks/results? 42 | "Total results returned: $($RResults.Count)" 43 | $RResults | Group-Object SEVERITY | 44 | Format-Table -Property Name, Count 45 | 46 | # 11. Use Set-BPAResult to just get errosr: 47 | $RResults | 48 | Where-Object Severity -EQ 'Error' | 49 | Format-List -Property Category,Problem,Impact,Resolution 50 | 51 | -------------------------------------------------------------------------------- /Chapter 01 - Establishing a PowerShell Administrative Environment/1.2 - Exploring Package Mangement.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 1.2 - Exploring Package Management 2 | # 3 | # Run from SRV1 4 | 5 | # 1. Review the cmdlets in the PackageManagement module: 6 | Get-Command -Module PackageManagement 7 | 8 | # 2. Review the installed providers with Get-PackageProvider: 9 | Get-PackageProvider | 10 | Format-Table -Property Name, 11 | Version, 12 | SupportedFileExtensions, 13 | FromtrustedSource 14 | 15 | # 3. The provider list initially includes msi, msu, and Programs 16 | # package providers. These providers expose applications and 17 | # updates installed on your computer which you can explore. 18 | Get-Package -ProviderName 'msu' | 19 | Select-Object -ExpandProperty Name 20 | 21 | # 4. The NuGet source contains developer library packages. The 22 | # details of NuGet are outside the scope of this book. 23 | Get-PackageProvider -Name NuGet -ForceBootstrap 24 | 25 | # 5. There are also other package providers you can explore: 26 | Find-PackageProvider | 27 | Select-Object -Property Name,Summary | 28 | Format-Table -Wrap -AutoSize 29 | 30 | # 6. Notice Chocolatey, which is another popular repository for Windows 31 | # administrators as well as power users. 32 | # Note that you cannot use this provider until you install it and 33 | # confirm the installation: 34 | Install-PackageProvider -Name Chocolatey -Force 35 | 36 | # 7. Verify Chocolatey is now in the list of installed providers: 37 | Get-PackageProvider | Select-Object -Property Name,Version 38 | 39 | # 8. Look for available software packages from the Chocolatey package provider. 40 | $Packages = Find-Package -ProviderName Chocolatey 41 | "$($Packages.Count) packages available from Chocolatey" 42 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.7 - Implementing nested Hyper-V.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.7 - Implementing nested Hyper-V 2 | # 3 | # Run on PSDirect 4 | 5 | # 1. Stop VM1 VM: 6 | Stop-VM -VMName PSDirect 7 | 8 | # 2. Change and view the VM's processor to support virtualization: 9 | $VMHT = @{ 10 | VMName = ‘PSDirect’ 11 | ExposeVirtualizationExtensions = $true 12 | } 13 | Set-VMProcessor @VMHT 14 | Get-VMProcessor -VMName PSDirect | 15 | Format-Table -Property Name, Count, 16 | ExposeVirtualizationExtensions 17 | 18 | # 3. Start the VM1 VM: 19 | Start-VM -VMName PSDirect 20 | Wait-VM -VMName PSDirect -For Heartbeat 21 | Get-VM -VMName PSDirect 22 | 23 | # 4. Create credentials 24 | $User = 'Wolf\Administrator' 25 | $PHT = @{ 26 | String = 'Pa$$w0rd' 27 | AsPlainText = $true 28 | Force = $true 29 | } 30 | $PSS = ConvertTo-SecureString @PHT 31 | $Type = 'System.Management.Automation.PSCredential' 32 | $CredRK = New-Object -TypeName $Type -ArgumentList $User,$PSS 33 | 34 | # 5. Create a script block for remote execution 35 | $SB = { 36 | Install-WindowsFeature -Name Hyper-V -IncludeManagementTools 37 | } 38 | 39 | # 6. Install Hyper-V inside the PSDirect VM 40 | $Session = New-PSSession -VMName PSDirect -Credential $CredRK 41 | $IHT = @{ 42 | Session = $Session 43 | ScriptBlock = $SB 44 | } 45 | Invoke-Command @IHT 46 | 47 | # 7. Restart the VM to finish adding Hyper-V: 48 | Stop-VM -VMName PSDirect 49 | Start-VM -VMName PSDirect 50 | Wait-VM -VMName PSDirect -For IPAddress 51 | Get-VM -VMName PSDirect 52 | 53 | # 8. Create a nested VM: 54 | $SB2 = { 55 | $VMname = 'NestedVM' 56 | New-VM -Name $VMname -MemoryStartupBytes 1GB 57 | } 58 | $IHT2 = @{ 59 | VMName = 'PSDirect' 60 | ScriptBlock = $SB2 61 | } 62 | Invoke-Command @IHT2 -Credential $CredRK 63 | 64 | -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.5 - Generating a perf monitoring graph.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 13.5 2 | # Create a performance monitoring Graph 3 | 4 | # 1. Load the Forms assembly 5 | Add-Type -AssemblyName System.Windows.Forms.DataVisualization 6 | 7 | # 2. Import the CSV data from earlier, and fix row 0 8 | $CSVFile = Get-ChildItem -path C:\PerfLogs\Admin\*.csv -rec 9 | $Counters = Import-Csv $CSVFile 10 | $Counters[0] = $Counters[1] # fix row 0 issues 11 | 12 | # 3. Create a chart object 13 | $CPUChart = New-Object System.Windows.Forms.DataVisualization.Charting.Chart 14 | 15 | # 4. Defne the chart dimensions 16 | $CPUChart.Width = 1000 17 | $CPUChart.Height = 600 18 | $CPUChart.Titles.Add("SRV1 CPU Utilisation") | Out-Null 19 | 20 | # 5 Create and define the chart area 21 | $ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea 22 | $ChartArea.Name = "SRV1 CPU Usage" 23 | $ChartArea.AxisY.Title = "% CPU Usage" 24 | $CPUChart.ChartAreas.Add($ChartArea) 25 | 26 | # 6. Identify the date/time column. 27 | $Name = ($counters[0] | Get-Member | 28 | Where-Object MemberType -EQ "NoteProperty")[0].Name 29 | 30 | # 7. Add the data points to the chart. 31 | $CPUChart.Series.Add("CPUPerc") | Out-Null 32 | $CPUChart.Series["CPUPerc"].ChartType = "Line" 33 | $CPUCounter = '\\SRV1\Processor(_Total)\% Processor Time' 34 | $counters | ForEach-Object{ 35 | $CPUChart.Series["CPUPerc"].Points.AddXY($_.$name,$_.$CPUCounter) | 36 | Out-Null 37 | } 38 | 39 | # 8. Ensure folder exists, then save the chart image as a png file in the folder: 40 | $NIHT = @{ 41 | Path = 'C:\Perflogs\Reports' 42 | ItemType = 'Directory' 43 | ErrorAction = 'SilentlyContinue' 44 | } 45 | New-Item @NIHT 46 | $CPUChart.SaveImage("C:\PerfLogs\Reports\Srv1CPU.Png", 'PNG') 47 | 48 | # 9. view the chart image 49 | MSPaint C:\PerfLogs\Reports\SRV1cpu.Png 50 | -------------------------------------------------------------------------------- /Chapter 06 - Deploying Windows Update/Recipe 6.6 - Managing Updates.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 6.6 - Managing Updates 2 | # 3 | # Run on WSUS1 after earlier recipes are completed. 4 | 5 | # 1. Open a PowerShell session, and view the overall status of all Windows updates 6 | # on WSUS1: 7 | $WSUSServer = Get-WsusServer 8 | $WSUSServer.GetStatus() 9 | 10 | # 2. View the computer targets: 11 | $WSUSServer.GetComputerTargets() | 12 | Sort-Object -Property FullDomainName | 13 | Format-Table -Property FullDomainName, IPAddress, Last* 14 | 15 | 16 | # 3 Search the WSUS server for updates with titles containing Windows Server 2016. 17 | # Then pull out the security updates amd sort by creation date: 18 | 19 | $ST = 'Windows Server 2016' 20 | $SU = 'Security Updates' 21 | $SecurityUpdates = $WSUSServer.SearchUpdates($ST) | 22 | Where-Object UpdateClassificationTitle -eq $SU | 23 | Sort-Object -Property CreationDate -Descending 24 | 25 | 26 | # 4. View the matching updates (first 10). 27 | $SecurityUpdates | 28 | Sort-Object -Property Title | 29 | Select-Object -First 10 | 30 | Format-Table -Property Title, Description 31 | 32 | 33 | # 5. Select one of the updates to approve based on the KB article ID: 34 | $SelectedUpdate = $SecurityUpdates | 35 | Where-Object KnowledgebaseArticles -eq 3194798 36 | 37 | # 6. Define the computer target group where you will approve this update: 38 | $DCTargetGroup = $WSUSServer.GetComputerTargetGroups() | 39 | Where-Object -Property Name -eq 'Domain Controllers' 40 | 41 | # 7. Approve the update for installation in the target group: 42 | $SelectedUpdate.Approve('Install',$DCTargetGroup) 43 | 44 | # 8. Select one of the updates to decline based on a KB article ID: 45 | $DeclinedUpdate = $SecurityUpdates | 46 | Where-Object -Property KnowledgebaseArticles -eq 4020821 47 | 48 | # 9. Decline the update: 49 | $DeclinedUpdate.Decline($DCTargetGroup) -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7.x -Deploying Shared Printer.ps1: -------------------------------------------------------------------------------- 1 | # Additional Recipe - not in final book 2 | # 3 | # Self provisioning methods for shared printers. 4 | 5 | # 1. Map a printer by using Printui.dll: 6 | $PrinterPath = "\\PSRV\SalesPrinter1" 7 | rundll32.exe printui.dll,PrintUIEntry /q /in /n$PrinterPath 8 | 9 | # 2. Set the default printer by using Printui.dll: 10 | rundll32 printui.dll,PrintUIEntry /y /n$PrinterPath 11 | 12 | # 3. Delete a printer by using Printui.dll: 13 | $PrinterPath = "\\Psrv\SalesPrinter1" 14 | rundll32.exe printui.dll,PrintUIEntry /q /dn /n$PrinterPath 15 | 16 | # 4. Map a printer by using WMI: 17 | $PrinterPath = "\\PrntSrv\Accounting HP" 18 | ([wmiclass]"Win32_Printer").AddPrinterConnection($PrinterPath) 19 | 20 | # 5. Set the default printer by using WMI: 21 | $PrinterPath = "\\Psrv\SalesPrinter1" 22 | $Filter = "DeviceID='$($PrinterPath.Replace('\','\\'))'" 23 | $Printer = Get-CimInstance -ClassName Win32_Printer | where name -eq 'SalesPrinter1' 24 | Invoke-CimMethod -InputObject $printer -MethodName SetDefaultPrinter 25 | (Get-WmiObject -Class Win32_Printer -Filter $filter).SetDefaultPrinter() 26 | 27 | #6. Remove a printer by using WMI: 28 | $PrinterPath = "\\PrntSrv\Accounting HP" 29 | $filter = "DeviceID='$($PrinterPath.Replace('\','\\'))'" 30 | (Get-WmiObject -Class Win32_Printer -Filter $filter).Delete() 31 | 32 | #7. Map a printer by using WScript 33 | $PrinterPath = "\\PrntSrv\Accounting HP" 34 | (New-Object -ComObject WScript.Network).AddWindowsPrinterConnection($PrinterPath) 35 | 36 | #8. Set the default printer by using WScript: 37 | $PrinterPath = "\\PrntSrv\Accounting HP" 38 | (New-Object -ComObject WScript.Network). 39 | SetDefaultPrinter($PrinterPath) 40 | 41 | #9. Remove a printer by using WScript: 42 | $PrinterPath = "\\PrntSrv\Accounting HP" 43 | (New-Object -ComObject WScript.Network).RemovePrinterConnection($PrinterPath 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.6 - Configuring Hyper-V networking.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.6 - Configuring Hyper-V Networking 2 | # 3 | # Run on HV1 4 | 5 | # 1. Get NIC details and any IP Address from the PSDirect VM 6 | Get-VMNetworkAdapter -VMName PSDirect 7 | 8 | # 2. Create a credential then get VM networking details 9 | $RKAn = 'localhost\Administrator' 10 | $PS = 'Pa$$w0rd' 11 | $RKP = ConvertTo-SecureString -String $PS -AsPlainText -Force 12 | $T = 'System.Management.Automation.PSCredential' 13 | $RKCred = New-Object -TypeName $T -ArgumentList $RKAn, $RKP 14 | $VMHT = @{ 15 | VMName = 'PSDirect' 16 | ScriptBlock = {Get-NetIPConfiguration } 17 | Credential = $RKCred 18 | } 19 | Invoke-Command @VMHT | Format-List 20 | 21 | # 3. Create a virtual switch on HV1 22 | $VSHT = @{ 23 | Name = 'External' 24 | NetAdapterName = 'Ethernet' 25 | Notes = 'Created on HV1' 26 | } 27 | New-VMSwitch @VSHT 28 | 29 | # 4. Connect VM1 to the switch 30 | Connect-VMNetworkAdapter -VMName PSDirect -SwitchName External 31 | 32 | # 5. See VM networking information: 33 | Get-VMNetworkAdapter -VMName PSDirect 34 | 35 | # 6. With VM1 now in the network, observe the IP address in the VM 36 | $NCHT = @{ 37 | VMName = 'PSDirect' 38 | ScriptBlock = {Get-NetIPConfiguration} 39 | Credential = $RKCred 40 | } 41 | Invoke-Command @NCHT 42 | 43 | # 7. View the hostname on VM1 44 | # Reuse the hash table from step 6 45 | $NCHT.ScriptBlock = {hostname} 46 | Invoke-Command @NCHT 47 | 48 | # 8. Change the name of the host in VM1 49 | # Reuse the hash table from steps 6,7 50 | $NCHT.ScriptBlock = {Rename-Computer -NewName Wolf -Force} 51 | Invoke-Command @NCHT 52 | 53 | # 9. Reboot and wait for the restarted VM1 54 | Restart-VM -VMName PSDirect -Wait -For IPAddress -Force 55 | 56 | # 10. Get hostname of the VM1 VM 57 | $NCHT.ScriptBlock = {hostname} 58 | Invoke-Command @NCHT -------------------------------------------------------------------------------- /Chapter 14 - Troubleshooting WIndows Server/Recipe 14.3 - Managing Event Logs.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 14.4 - Search Event Logs for specific events. 2 | # 3 | # Run on SRV1 4 | 5 | # 1. Get core event logs on SRV1 6 | Get-EventLog -LogName * 7 | 8 | # 2. Get remote classic event logs from DC1 9 | Get-EventLog -LogName * -ComputerName DC1 10 | 11 | # 3. Clear application log on DC1: 12 | Clear-EventLog -LogName Application -ComputerName DC1 13 | 14 | # 4. Look At the types of events on SRV1 15 | Get-EventLog -LogName Application | 16 | Group-Object -Property EntryType | 17 | Format-Table -Property Name, Count 18 | 19 | # 5. Examine which area created the events in the application log: 20 | Get-EventLog -LogName System | 21 | Group-Object -Property Source | 22 | Sort-Object -Property Count -Descending | 23 | Select-Object -First 10 | 24 | Format-Table -Property Name, Count 25 | 26 | # 6. Examine ALL event logs on SRV1 27 | $LocEventLogs = Get-WinEvent -ListLog * 28 | $LocEventLogs.Count 29 | $LocEventLogs | 30 | Sort-Object -Property RecordCount -Descending | 31 | Select-Object -First 10 32 | 33 | # 7. Examine ALL event logs on DC1 34 | $RemEventLogs = Get-WinEvent -ListLog * -ComputerName DC1 35 | $RemEventLogs.count 36 | $RemEventLogs | 37 | Sort-Object -Property RecordCount -Descending | 38 | Select-Object -First 10 39 | 40 | # 8. Look at New logs - Windows Update - what updates have been found 41 | $LN = 'Microsoft-Windows-WindowsUpdateClient/Operational' 42 | $Updates = Get-WinEvent -LogName $LN | 43 | Where-Object ID -EQ 41 44 | $Out = qoreach ($Update in $Updates) { 45 | $HT = @{} 46 | $HT.Time = [System.DateTime] $Update.TimeCreated 47 | $HT.Update = ($Update.Properties | Select-Object -First 1).Value 48 | New-Object -TypeName PSObject -Property $HT 49 | } 50 | $Out | Sort -Property Time 51 | Sort-Object -Property TimeCreated | 52 | Format-Table -Wrap 53 | -------------------------------------------------------------------------------- /Chapter 03 - Deploying Active Directory/3.3 - Adding users to AD using a CSV.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 3.3 - Adding Users to Active Directory using a CSV File 2 | 3 | # 0. Create CSV 4 | $CSVDATA = @' 5 | Firstname, Initials, Lastname, UserPrincipalName, Alias, Description, Password 6 | S,K,Masterly, SKM, Sylvester, Data Team, Christmas42 7 | C,B, Smith, CBS, Claire, Receptionist, Christmas42 8 | Billy, Bob, JoeBob, BBJB, BillyBob, A Bob, Christmas42 9 | Malcolm, Dudley, Duelittle, Malcolm, Malcolm, Mr Danger, Christmas42 10 | '@ 11 | $CSVDATA | Out-File -FilePath C:\Foo\Users.Csv 12 | 13 | # 1. Import a CSV file containing the details of the users you 14 | # want to add to AD: 15 | $Users = Import-CSV -Path C:\Foo\Users.Csv | 16 | Sort-Object -Property Alias 17 | $users | Sort-Object -Property Alias |Format-Table 18 | 19 | # 2. Add the users using the CSV 20 | ForEach ($User in $Users) { 21 | # Create a hash table of properties to set on created user 22 | $Prop = @{} 23 | # Fill in values 24 | $Prop.GivenName = $User.Firstname 25 | $Prop.Initials = $User.Initials 26 | $Prop.Surname = $User.Lastname 27 | $Prop.UserPrincipalName = 28 | $User.UserPrincipalName+"@reskit.org" 29 | $Prop.Displayname = $User.firstname.trim() + " " + 30 | $user.lastname.trim() 31 | $Prop.Description = $User.Description 32 | $Prop.Name = $User.Alias 33 | $PW = ConvertTo-SecureString -AsPlainText $user.password -Force 34 | $Prop.AccountPassword = $PW 35 | # To be safe! 36 | $Prop.ChangePasswordAtLogon = $true 37 | # Now create the user 38 | New-ADUser @Prop -Path 'OU=IT,DC=Reskit,DC=ORG' -Enabled:$true 39 | # Finally, display user created 40 | "Created $($Prop.Displayname)" 41 | } 42 | 43 | 44 | 45 | ### Remove the users created in the recipe 46 | 47 | $users = Import-Csv C:\foo\users.csv 48 | foreach ($User in $Users) 49 | { 50 | Get-ADUser -Identity $user.alias | remove-aduser 51 | } 52 | -------------------------------------------------------------------------------- /Chapter 02 - Managing Windows Networking/2.1 - New ways to do old things.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 2.1 - New ways to do old things 2 | # 3 | # Run on SRV1 4 | 5 | # 1. Ipconfig vs new cmdlets 6 | 7 | # Two variations on the old way 8 | ipconfig.exe 9 | ipconfig.exe /all 10 | 11 | # The new Way 12 | Get-NetIPConfiguration 13 | 14 | # Related cmdlets - but not for the book... 15 | Get-NetIPInterface 16 | Get-NetAdapter 17 | 18 | # 2. Pinging a computer 19 | 20 | # The old way 21 | Ping DC1.Reskit.Org -4 22 | 23 | # The New way 24 | Test-NetConnection DC1.Reskit.Org 25 | 26 | # And some new things Ping does not do! 27 | Test-NetConnection DC1.Reskit.Org -CommonTCPPort SMB 28 | $ILHT = @{InformationLevel = 'Detailed'} 29 | Test-NetConnection DC1.Reskit.Org -port 389 @ILHT 30 | 31 | # 3. Using Sharing folder from DC1 32 | 33 | # The old way to use a shared folder 34 | net use X: \\DC1.Reskit.Org\c$ 35 | 36 | # The new way using an SMB cmdlet 37 | New-SMBMapping -LocalPath 'Y:' -RemotePath \\DC1.Reskit.Org\c$ 38 | 39 | # See what is shared the old way: 40 | net use 41 | 42 | # And the new way 43 | Get-SMBMapping 44 | 45 | # 4. - Sharing a folder from SRV1 46 | 47 | # Now share the old way 48 | net share Windows=C:\windows 49 | # and the new way 50 | New-SmbShare -Path C:\Windows -Name Windows2 51 | # And see what has been shared the old way 52 | net share 53 | # and the new way 54 | Get-SmbShare 55 | 56 | # 5. Getting DNS Cache 57 | # The Old way to see the DNS Client Cache 58 | ipconfig /displaydns 59 | # Vs 60 | Get-DnsClientCache 61 | 62 | # 6. Clear the dnsclient client cache the old way 63 | Ipconfig /flushdns 64 | # Vs the new way 65 | Clear-DnsClientCache 66 | 67 | # 7. DNS Lookups 68 | Nslookup DC1.Reskit.Org 69 | Resolve-DnsName -Name DC1.Reskit.Org -Type ALL 70 | # 71 | 72 | 73 | <# undo 74 | Get-SmbMapping x: | Remove-SmbMapping -force 75 | Get-SmbMapping y: | Remove-SmbMapping -confirm:$false 76 | Get-SMBSHARE Windows* | Remove-SMBShare 77 | #> 78 | -------------------------------------------------------------------------------- /Chapter 05 - Managing Shared Data/Recipe 5.1 - Securing your SMB file server.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 5.1 - Securing your SMB file erver 2 | # Run on FS1 3 | 4 | # 1. - Add File Server features to FS1 5 | $Featuers = 'FileAndStorage-Services','File-Services', 6 | 'FS-FileServer','RSAT-File-Services' 7 | Add-WindowsFeature -Name $Featuers 8 | 9 | 10 | # 2. ` Retreive SMB Server settings 11 | Get-SmbServerConfiguration 12 | 13 | # 3. - Turn off SMB1 14 | $CHT = @{ 15 | EnableSMB1Protocol = $false 16 | Confirm = $false 17 | } 18 | Set-SmbServerConfiguration @CHT 19 | 20 | # 4.Turn on SMB signing and encryption 21 | $SHT1 = @{ 22 | RequireSecuritySignature = $true 23 | EnableSecuritySignature = $true 24 | EncryptData = $true 25 | Confirm = $false 26 | } 27 | Set-SmbServerConfiguration @SHT1 28 | 29 | # Step 5 - Turn off default server and workstations shares 30 | $SHT2 = @{ 31 | AutoShareServer = $false 32 | AutoShareWorkstation = $false 33 | Confirm = $false 34 | } 35 | Set-SmbServerConfiguration @SHT2 36 | 37 | # Step 6 - turn off server announcements 38 | $SHT3 = @{ 39 | ServerHidden = $true 40 | AnnounceServer = $false 41 | Confirm = $false 42 | } 43 | Set-SmbServerConfiguration @SHT3 44 | 45 | # Step 7 - restart the service with the new configuration 46 | Restart-Service lanmanserver 47 | 48 | 49 | <# undo and set back to defults 50 | 51 | Get-SMBShare foo* | remove-SMBShare -Confirm:$False 52 | 53 | Set-SmbServerConfiguration -EnableSMB1Protocol $true ` 54 | -RequireSecuritySignature $false ` 55 | -EnableSecuritySignature $false ` 56 | -EncryptData $False ` 57 | -AutoShareServer $true ` 58 | -AutoShareWorkstation $false ` 59 | -ServerHidden $False ` 60 | -AnnounceServer $True 61 | Restart-Service lanmanserver 62 | #> 63 | -------------------------------------------------------------------------------- /Chapter 01 - Establishing a PowerShell Administrative Environment/1.5 - Establish a script signing environment.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 1.6 - Establishing a script signing envionment 2 | # Performed on CL1 3 | 4 | # 1. Create a script-signing certificate 5 | $CHT = @{ 6 | Subject = 'Reskit Code Signing' 7 | Type = 'CodeSigning' 8 | CertStoreLocation = 'Cert:\CurrentUser\My' 9 | } 10 | $Cert = New-SelfSignedCertificate @CHT 11 | 12 | # 2. Display newly created certificate 13 | Get-ChildItem -Path Cert:\CurrentUser\my -CodeSigningCert | 14 | Where-Object {$_.Subjectname.Name -match $CHT.Subject} 15 | 16 | # 3. Create a simple script 17 | $Script = @" 18 | # Sample Script 19 | 'Hello World!' 20 | Hostname 21 | "@ 22 | $Script | Out-File -FilePath c:\foo\signed.ps1 23 | Get-ChildItem -Path C:\foo\signed.ps1 24 | 25 | # 4. Sign the script 26 | $SHT = @{ 27 | Certificate = $cert 28 | FilePath = 'C:\foo\signed.ps1' 29 | } 30 | Set-AuthenticodeSignature @SHT 31 | 32 | # 5. Look at script after signing 33 | Get-ChildItem -Path C:\foo\signed.ps1 34 | 35 | # 6. Test the signature 36 | Get-AuthenticodeSignature -FilePath C:\foo\signed.ps1 | 37 | Format-List 38 | 39 | # 7. Ensure certificate is trusted 40 | # Note ugly construct in opening the store! 41 | $DestStoreName = 'Root' 42 | $DestStoreScope = 'CurrentUser' 43 | $Type = 'System.Security.Cryptography.X509Certificates.X509Store' 44 | $MHT = @{ 45 | TypeName = $Type 46 | ArgumentList = ($DestStoreName, $DestStoreScope) 47 | } 48 | $DestStore = New-Object @MHT 49 | $DestStore.Open( 50 | [System.Security.Cryptography.X509Certificates.OpenFlags]:: 51 | ReadWrite) 52 | $DestStore.Add($cert) 53 | $DestStore.Close() 54 | 55 | # 8. Resign With a trusted cert 56 | Set-AuthenticodeSignature @SHT | Out-Null 57 | 58 | # 9. Check the cert 59 | Get-AuthenticodeSignature -FilePath C:\foo\signed.ps1 | 60 | Format-List 61 | 62 | 63 | 64 | 65 | 66 | 67 | # UnDo 68 | 69 | Gci cert:\ -recurse | where subject -match 'Reskit Code Signing' | RI -Force 70 | ri C:\foo\signed.ps1 71 | 72 | 73 | -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Create-SalesTeam.ps1: -------------------------------------------------------------------------------- 1 | # Create-SaleTeam 2 | 3 | # Creates the OU, groups, users and group memberships used in Reskit.Org 4 | 5 | # Create Sales OU 6 | $OUPath = 'DC=Reskit,DC=Org' 7 | New-ADOrganizationalUnit -Name Sales -Path $OUPath 8 | 9 | # Setup for creating users for sales 10 | $OUPath = 'OU=Sales,DC=Reskit,DC=Org' 11 | $Password = 'Pa$$w0rd' 12 | $PasswordSS = ConvertTo-SecureString -String $Password -AsPlainText -Force 13 | $NewUserHT = @{ 14 | AccountPassword = $PasswordSS; 15 | Enabled = $true; 16 | PasswordNeverExpires = $true; 17 | ChangePasswordAtLogon = $false 18 | Path = $OUPath 19 | } 20 | $Password = 'Pa$$w0rd' 21 | $PasswordSS = ConvertTo-SecureString -String $Password -AsPlainText -Force 22 | 23 | # Create Sales users Nigel, Samantha, Pippa, Jeremy 24 | 25 | New-ADUser @NewUserHT -SamAccountName Nigel -UserPrincipalName 'Nigel@reskit.org' ` 26 | -Name "Nigel" -DisplayName 'Nigel Hawthorne-Smyth' 27 | 28 | New-ADUser @NewUserHT -SamAccountName Samantha -UserPrincipalName 'Samantha@reskit.org' ` 29 | -Name "Samantha" -DisplayName 'Saamantha Rhees-Jenkins' 30 | 31 | New-ADUser @NewUserHT -SamAccountName Pippa -UserPrincipalName 'Pippa@reskit.org' ` 32 | -Name "Pippa" -DisplayName 'Pippa van Spergel' 33 | 34 | New-ADUser @NewUserHT -SamAccountName Jeremy -UserPrincipalName 'Jeremy@reskit.org' ` 35 | -Name "Jeremy" -DisplayName 'Jeremy Cadwalender' 36 | 37 | # Create Sales Groups 38 | $OUPath = 'OU=Sales,DC=Reskit,DC=Org' 39 | New-ADGroup -Name Sales -Path $OUPath -GroupScope Global 40 | New-ADGroup -Name SalesAdmins -Path $OUPath -GroupScope Global 41 | New-ADGroup -Name SalesPrinterUsers -Path $OUPath -GroupScope Global 42 | 43 | 44 | # Add users to the groups 45 | Add-ADGroupMember -Identity Sales -Members Nigel, Samantha, Pippa, Jeremy 46 | Add-ADGroupMember -Identity SalesAdmins -Members Nigel, Samantha 47 | Add-AdgroupMember -Identity SalesPrinterUsers -Members Sales, ThomasL 48 | 49 | -------------------------------------------------------------------------------- /Chapter 04 - Managing Storage/Recipe 4.2 - Managing NTFS permissions.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 4.2 - Managing NTFS Permissions 2 | # 3 | # Run on SRV1 4 | 5 | # 1. Download NTFSSecurity module from PSGallery 6 | Install-Module NTFSSecurity -Force 7 | 8 | # 2. Get commands in the module 9 | Get-Command -Module NTFSSecurity 10 | 11 | # 3. Create a new folder, and a file in the folder 12 | New-Item -Path C:\Secure1 -ItemType Directory | 13 | Out-Null 14 | "Secure" | Out-File -FilePath C:\Secure1\Secure.Txt 15 | Get-ChildItem -Path c:\Secure1 16 | 17 | # 4. View ACL of the folder: 18 | Get-NTFSAccess -Path C:\Secure1 | 19 | Format-Table -AutoSize 20 | 21 | # 5. View ACL of file 22 | Get-NTFSAccess C:\Secure1\Secure.Txt | 23 | Format-Table -AutoSize 24 | 25 | 26 | # 6. Create Sales group if it does not exist 27 | try { 28 | Get-ADGroup -Identity 'Sales' -ErrorAction Stop 29 | } 30 | catch { 31 | New-ADGroup -Name Sales -GroupScope Global | 32 | Out-Null 33 | } 34 | 35 | # 7. Display 36 | Get-ADGroup -Identity Sales 37 | 38 | 39 | # 8. Add explicit full control for DomainAdmins 40 | $AHT1 = @{ 41 | Path = 'C:\Secure1' 42 | Account = 'Reskit\Domain Admins' 43 | AccessRights = 'FullControl' 44 | } 45 | Add-NTFSAccess @AHT1 46 | 47 | # 9. Remove builtin\users access from secure.txt file 48 | $AHT2 = @{ 49 | Path = 'C:\Secure1\Secure.Txt' 50 | Account = 'Builtin\Users' 51 | AccessRights = 'FullControl' 52 | } 53 | 54 | Remove-NTFSAccess @AHT2 55 | 56 | # 10. Remove inherited rights for the folder: 57 | $IRHT1 = @{ 58 | Path = 'C:\Secure1' 59 | RemoveInheritedAccessRules = $True 60 | } 61 | Disable-NTFSAccessInheritance @IRHT1 62 | 63 | # 11. Add Sales group access to the folder 64 | $AHT3 = @{ 65 | Path = 'C:\Secure1\' 66 | Account = 'Reskit\Sales' 67 | AccessRights = 'FullControl' 68 | } 69 | Add-NTFSAccess @AHT3 70 | 71 | # 12. get results on path 72 | Get-NTFSAccess -Path C:\Secure1 | 73 | Format-Table -AutoSize 74 | 75 | # 13. and on the file 76 | Get-NTFSAccess -Path C:\Secure1\Secure.Txt | 77 | Format-Table -AutoSize 78 | 79 | 80 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.1 - Installing and Configuring Hyper-V.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11-1 - Installing and configuring Hyper-V 2 | # Run on CL1 3 | 4 | # 1. From CL1, install the Hyper-V feature on HV1, HV2 5 | $Sb = { 6 | Install-WindowsFeature -Name Hyper-V -IncludeManagementTools 7 | } 8 | Invoke-Command -ComputerName HV1, HV2 -ScriptBlock $Sb 9 | 10 | # 2. Reboot the servers to complete the installation 11 | Restart-Computer -ComputerName HV1, HV2 -Force 12 | 13 | # 3. Create a PSSession with both HV Servers (after reboot) 14 | $S = New-PSSession HV1, HV2 15 | 16 | # 4. Create and set the location for VMs and VHDs on HV1 and HV2 17 | # then view results 18 | $Sb = { 19 | New-Item -Path C:\Vm -ItemType Directory -Force | 20 | Out-Null 21 | New-Item -Path C:\Vm\Vhds -ItemType Directory -Force | 22 | Out-Null 23 | New-Item -Path C:\Vm\VMs -ItemType Directory -force | 24 | Out-Null 25 | Get-ChildItem -Path C:\Vm } 26 | Invoke-Command -ScriptBlock $Sb -Session $S 27 | 28 | # 5. Set default paths for Hyper-V VM hard disks and 29 | # VM configuration information 30 | $SB = { 31 | $VMs = 'C:\Vm\Vhds' 32 | $VHDs = 'C:\Vm\VMs\Managing Hyper-V' 33 | Set-VMHost -ComputerName Localhost -VirtualHardDiskPath $VMs 34 | Set-VMHost -ComputerName Localhost -VirtualMachinePath $VHDs 35 | } 36 | Invoke-Command -ScriptBlock $SB -Session $S 37 | 38 | # 5. Setup NUMA spanning 39 | $SB = { 40 | Set-VMHost -NumaSpanningEnabled $true 41 | } 42 | Invoke-Command -ScriptBlock $SB -Session $S 43 | 44 | # 6. Set up EnhancedSessionMode 45 | $SB = { 46 | Set-VMHost -EnableEnhancedSessionMode $true 47 | } 48 | Invoke-Command -ScriptBlock $SB -Session $S 49 | 50 | # 7. Setup host resource metering on HV1, HV2 51 | $SB = { 52 | $RMInterval = New-TimeSpan -Hours 0 -Minutes 15 53 | Set-VMHost -ResourceMeteringSaveInterval $RMInterval 54 | } 55 | Invoke-Command -ScriptBlock $SB -Session $S 56 | 57 | 58 | # 8. Review key VMHost settings: 59 | $SB = { 60 | Get-VMHost 61 | } 62 | $P = 'Name', 'V*Path','Numasp*', 'Ena*','RES*' 63 | Invoke-Command -Scriptblock $SB -Session $S | 64 | Format-Table -Property $P -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.8 - Analyze IIS log files.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 9.8 - Analyze IIS Log Files 2 | # 3 | # Run from SRV1 after previous recipes have created log entries for SRV1 4 | 5 | # 1. Define the location of log files and a temporary file 6 | $LogFolder = 'C:\inetpub\logs\LogFiles\W3SVC1' 7 | $LogFiles = Get-ChildItem $LogFolder\*.log -Recurse 8 | $LogTemp = "C:\inetpub\logs\LogFiles\W3SVC1\AllLogs.tmp" 9 | 10 | # 2. $Logs holds each line of each log file 11 | $Logs = @() # Create empty array 12 | # Remove the comment lines 13 | $LogFiles | 14 | ForEach { Get-Content $_ | 15 | Where-Object {$_ -notLike "#[D,F,S,V]*" } | 16 | Foreach { $Logs += $_ } # add log entry to $Logs array 17 | } 18 | 19 | # 3. Build a better header 20 | $LogColumns = ( $LogFiles | 21 | Select-Object -First 1 | 22 | Foreach { Get-Content $_ | 23 | Where-Object {$_ -Like "#[F]*" } } ) 24 | $LogColumns = $LogColumns -replace "#Fields: ", "" 25 | $LogColumns = $LogColumns -replace "-","" 26 | $LogColumns = $LogColumns -replace "\(","" 27 | $LogColumns = $LogColumns -replace "\)","" 28 | 29 | # 4. Save the updated log files 30 | $NL = [Environment]::NewLine 31 | $P = [System.String]::Join( [Environment]::NewLine, $Logs) 32 | $S = "{0}{1}{2}" -f $LogColumns, $NL,$P 33 | Set-Content -Path $LogTemp -Value $S 34 | 35 | # 5. Read the reformatted logs as a CSV file 36 | $Logs = Import-Csv -Path $LogTemp -Delimiter " " 37 | 38 | # 6. View Client IP addresses 39 | $Logs | 40 | Sort-Object -Property cip | 41 | Select-Object -Property CIP -Unique 42 | 43 | # 7. View User Agents used to communicate with SRV1 44 | $Logs | 45 | Sort-Object -property csUserAgent | 46 | Select-Object -Property csUserAgent -Unique 47 | 48 | # 8. View frequency of each user agent 49 | $Logs | 50 | Sort-Object -Property csUserAgent | 51 | Group-Object csuseragent | 52 | Sort-object -Property Count -Desc | 53 | Format-Table -Property Count, Name 54 | 55 | # 9. Who is using what: 56 | $Logs | 57 | Select-Object -Property CIP, CSUserAgent -Unique | 58 | Sort-Object -Property CIP 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Chapter 12 - Exploring Azure/Recipe 12.4 - Create Azure SMB share.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 12-4 - Create an Azure SMB Share 2 | 3 | # Run from CL1 4 | 5 | # 1. Define Variables 6 | $Locname = 'uksouth' # location name 7 | $RgName = 'packt_rg' # resource group we are using 8 | $SAName = 'packt42sa' # storage account name 9 | $ShareName = 'packtshare' # must be lower case! 10 | 11 | # 2. Login to your Azure Account and ensure the RG and SA is created. 12 | $CredAZ = Get-Credential 13 | $Account = Login-AzAccount -Credential $CredAZ 14 | 15 | # 3. Get Storage account, accountkey and context: 16 | $SA = Get-AzStorageAccount -ResourceGroupName $Rgname 17 | $SAKHT = @{ 18 | Name = $SAName 19 | ResourceGroupName = $RgName 20 | } 21 | $Sak = Get-AzStorageAccountKey @SAKHT 22 | $Key = ($Sak | Select-Object -First 1).Value 23 | $SCHT = @{ 24 | StorageAccountName = $SAName 25 | StorageAccountKey = $Key 26 | } 27 | $SACon = New-AzStorageContext @SCHT 28 | 29 | # 4. Add credentials to local store: 30 | $T = "$SAName.file.core.windows.net" 31 | cmdkey /add:$T /user:"AZURE\$SAName" /pass:$Key 32 | 33 | # 5. Create a share: 34 | New-AzStorageShare -Name $ShareName -Context $SACon 35 | 36 | # 6. Test that Share is reachable 37 | $TNCHT = @{ 38 | ComputerName = "$SAName.file.core.windows.net" 39 | Port = 445 40 | } 41 | Test-NetConnection @TNCHT 42 | 43 | # 7. Mount the share as Z: 44 | $Mount = 'Z:' 45 | $Rshare = "\\$SaName.file.core.windows.net\$ShareName" 46 | $SMHT = @{ 47 | LocalPath = $Mount 48 | RemotePath = $Rshare 49 | UserName = $SAName 50 | Password = $Key 51 | } 52 | New-SmbMapping @SMHT 53 | 54 | # 8. View the share in Azure: 55 | Get-AzStorageShare -Context $SACon | 56 | Format-List -Property * 57 | 58 | # 9. View local SMB mappings: 59 | Get-SmbMapping 60 | 61 | # 10. Now use the new share - create a file in the share: 62 | New-Item -Path Z:\Foo -ItemType Directory | Out-Null 63 | 'Azure and PowerShell Rock!!!' | 64 | Out-File -FilePath Z:\Foo\recipe.txt 65 | 66 | # 11. Retrievie details about the share contents: 67 | Get-ChildItem -Path z:\ -Recurse | 68 | Format-Table -Property FullName, Mode, Length 69 | 70 | # 12. Get the content from the file: 71 | Get-Content -Path Z:\Foo\recipe.txt -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.6 - Configure IIS Logging and Log Files.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 10-6 - Configure IIS Logging and log files 2 | 3 | # 1. Import the web administration module to ensure IIS provider is loaded 4 | Import-Module WebAdministration 5 | 6 | # 2. Look at where you are currently storing log files: 7 | $IPHT1 = @{ 8 | Path = 'IIS:\Sites\Default Web Site' 9 | Name = 'logfile.directory' 10 | } 11 | $LogfileLocation = (Get-ItemProperty @IPHT1).value 12 | $LF = [System.Environment]::ExpandEnvironmentVariables("$LF") 13 | Get-ChildItem $LogFileFolder -Recurse 14 | 15 | # 3. Change the folder to C:\IISLogs 16 | New-Item -Path C:\IISLogs -ItemType Directory 17 | $IPHT2 = @{ 18 | Path = 'IIS:\Sites\Default Web Site' 19 | Name = 'logfile.directory' 20 | } 21 | Set-ItemProperty @IPHT2 -Value 'C:\IISLogs' 22 | 23 | # 4. Change the Logging type: 24 | $IPHT3 = @{ 25 | Path = 'IIS:\Sites\Default Web Site' 26 | Name = 'logFile.logFormat' 27 | } 28 | Set-ItemProperty @IPHT3 -Value 'W3C' 29 | 30 | # 5. Change logging frequency: 31 | $IPHT3 = @{ 32 | Path = 'IIS:\Sites\Default Web Site' 33 | Name = 'logFile.period' 34 | } 35 | Set-ItemProperty @IPHT3 -Value Weekly 36 | 37 | # 6. Change logging to use a maximum size: 38 | $IPHT4 = @{ 39 | Path = 'IIS:\Sites\Default Web Site' 40 | Name = 'logFile.period' 41 | } 42 | Set-ItemProperty @IPHT4 -Value 'MaxSize' 43 | $Size = 1GB 44 | $IPHT5 = @{ 45 | Path = 'IIS:\Sites\Default Web Site' 46 | Name = 'logFile.truncateSize' 47 | } 48 | Set-ItemProperty @IPHT5 -Value $size 49 | 50 | # 7. Disable logging: 51 | $IPHT5 = @{ 52 | Path = 'IIS:\Sites\Default Web Site' 53 | Name = 'logFile.enabled' 54 | } 55 | Set-ItemProperty @IPHT5 -Value $false 56 | 57 | # 8. Delete old log files 58 | $LogDirs = Get-ChildItem -Path IIS:\Sites | 59 | Get-ItemProperty -Name logFile.directory.value | 60 | Select -Unique 61 | $Age = 30 # h0ow long to keep log files for 62 | $DaysOld = (Get-Date).AddDays(-$Age) 63 | foreach ($LogDir in $LogDirs){ 64 | $Dir = [Environment]::ExpandEnvironmentVariables($LogDir) 65 | $DIR 66 | Get-ChildItem -Path $Dir -Recurse -ErrorAction SilentlyContinue | 67 | Where-Object LastWriteTime -lt $DaysOld 68 | Remove-Item 69 | } 70 | 71 | -------------------------------------------------------------------------------- /Chapter 14 - Troubleshooting WIndows Server/Recipe 14.1 - Check Network Connectivity.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 14.1 - Check connectivity 2 | # 3 | # Run on SRV1 4 | # Uses SRV1, DC1, DC2 5 | 6 | # 1. Use Test-NetConnnection to test connection to DC1 7 | Test-Connection -ComputerName DC1 8 | 9 | # 2. Test with simple true/false return 10 | Test-Connection -ComputerName DC1 -Quiet 11 | 12 | # 3. Test multiple systems at once 13 | Test-Connection -ComputerName 'DC1','DC2','SRV2' -Count 1 14 | 15 | # 4. Test connectivity for SMB traffic with DC1 16 | Test-NetConnection -ComputerName DC1 -CommonTCPPort SMB 17 | 18 | # 5. Get detailed connectivity check, using DC1 with HTTP 19 | $TNCHT = @{ 20 | ComputerName = 'DC1' 21 | CommonTCPPort = 'HTTP' 22 | InformationLevel = 'Detailed' 23 | } 24 | Test-NetConnection @TNCHT 25 | 26 | # 6. Look for a particular port (i.e SMV# Recipe 14.1 - Check connectivity 27 | # 28 | # Run on SRV1 29 | # Uses SRV1, DC1, DC2 30 | 31 | # 1. Use Test-NetConnnection to test connection to DC1 32 | Test-Connection -ComputerName DC1 33 | 34 | # 2. Test with simple true/false return 35 | Test-Connection -ComputerName DC1 -Quiet 36 | 37 | # 3. Test multiple systems at once 38 | Test-Connection -ComputerName 'DC1','DC2','SRV2' -Count 1 39 | 40 | # 4. Test connectivity for SMB traffic with DC1 41 | Test-NetConnection -ComputerName DC1 -CommonTCPPort SMB 42 | 43 | # 5. Get detailed connectivity check, using DC1 with HTTP 44 | $TNCHT = @{ 45 | ComputerName = 'DC1' 46 | CommonTCPPort = 'HTTP' 47 | InformationLevel = 'Detailed' 48 | } 49 | Test-NetConnection @TNCHT 50 | 51 | # 6. Look for a particular port (i.e LDAP on DC1) 52 | Test-NetConnection -ComputerName DC1 -Port 389 53 | 54 | # 7. Look for a host that does not exist 55 | Test-NetConnection -ComputerName 10.10.10.123 56 | 57 | # 8. Look for a host that exists but a port/application 58 | # that does not exist: 59 | Test-NetConnection -ComputerName DC1 -PORT 9999 60 | 61 | 62 | on DC1) 63 | Test-NetConnection -ComputerName DC1 -Port 445 64 | 65 | # 7. Look for a host that does not exist 66 | Test-NetConnection -ComputerName 10.10.10.123 67 | 68 | # 8. Look for a host that exists but a port/application 69 | # that does not exist: 70 | Test-NetConnection -ComputerName DC1 -PORT 9999 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Chapter 04 - Managing Storage/Recipe 4.5 - Using File System Reporting.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 4.5 - Using Storage Reporting 2 | # 3 | # Run on SRV1 after you run Recipe 4.4 to install FSRM 4 | 5 | # 1. Create a new Storage report for large files on C:\ on SRV1 6 | $NRHT = @{ 7 | Name = 'Large Files on SRV1' 8 | NameSpace = 'C:\' 9 | ReportType = 'LargeFiles' 10 | LargeFileMinimum = 10MB 11 | Interactive = $true 12 | } 13 | New-FsrmStorageReport @NRHT 14 | 15 | # 2. Get reports 16 | Get-FsrmStorageReport * 17 | 18 | # 3. After Storage Report is run, view in filestore 19 | $Path = 'C:\StorageReports\Interactive' 20 | Get-ChildItem -Path $Path 21 | 22 | # 4. View the report 23 | $Rep = Get-ChildItem -Path $Path\*.html 24 | Invoke-item -Path $Rep 25 | 26 | # 5. Extract key information from the XML 27 | $XF = Get-ChildItem -Path $Path\*.xml 28 | $XML = [XML] (Get-Content -Path $XF) 29 | $Files = $XML.StorageReport.ReportData.Item 30 | $Files | Where-Object Path -NotMatch '^Windows|^Program|^Users'| 31 | Format-Table -Property name, path, 32 | @{ name ='Sizemb' 33 | expression = {(([int]$_.size)/1mb).tostring('N2')}}, 34 | DaysSinceLastAccessed -AutoSize 35 | 36 | # 6. Create a monthly task in task scheduler 37 | $Date = Get-Date '04:00' 38 | $NTHT = @{ 39 | Time = $Date 40 | Monthly = 1 41 | } 42 | $Task = New-FsrmScheduledTask @NTHT 43 | $NRHT = @{ 44 | Name = 'Monthly Files by files group report' 45 | Namespace = 'C:\' 46 | Schedule = $Task 47 | ReportType = 'FilesbyFileGroup' 48 | FileGroupINclude = 'text files' 49 | LargeFileMinimum = 25MB 50 | } 51 | New-FsrmStorageReport @NRHT | Out-Null 52 | 53 | # 7. Get details of the task 54 | Get-ScheduledTask | 55 | Where-Object taskname -Match 'Monthly' | 56 | Format-Table -AutoSize 57 | 58 | # 8. Run the task now 59 | Get-ScheduledTask -TaskName '*Monthly*' | 60 | Start-ScheduledTask 61 | Get-ScheduledTask -TaskName '*Monthly*' 62 | 63 | # 9. view the report 64 | $Path = 'C:\StorageReports\Scheduled' 65 | $Rep = Get-ChildItem -Path $path\*.html 66 | Invoke-item -Path $Rep 67 | 68 | 69 | 70 | 71 | # cleanup 72 | Unregister-ScheduledTask -TaskName "StorageReport-Monthly report on Big Files" -Confirm:$False 73 | Get-FsrmStorageReport | Remove-FsrmStorageReport -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7.3 - Changing spool folder.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 7.3 - Changing the spool directory. 2 | 3 | # 1. Load the System.Printing namespace and classes: 4 | Add-Type -AssemblyName System.Printing 5 | 6 | # 2. Define the required permissions—that is, the ability to administrate the server: 7 | $Permissions = 8 | [System.Printing.PrintSystemDesiredAccess]:: 9 | AdministrateServer 10 | 11 | # 3. Create a PrintServer object with the required permissions: 12 | $NOHT = @{ 13 | TypeName = 'System.Printing.PrintServer' 14 | ArgumentList = $Permissions 15 | } 16 | $PS = New-Object @NOHT 17 | 18 | 19 | # 4. Create a new spool path: 20 | $NIHT = @{ 21 | Path = 'C:\SpoolPath' 22 | ItemType = 'Directory' 23 | Force = $true 24 | ErrorAction = 'SilentlyContinue' 25 | } 26 | New-Item @NIHT | Out-Null 27 | 28 | # 5 Update the default spool folder path: 29 | $Newpath = 'C:\SpoolPath' 30 | $PS.DefaultSpoolDirectory = $Newpath 31 | 32 | # 6. Commit the change: 33 | $Ps.Commit() 34 | 35 | # 7. Restart the Spooler to accept the new folder: 36 | Restart-Service -Name Spooler 37 | 38 | # 8. Once the Spooler has restarted, view the results: 39 | New-Object -TypeName System.Printing.PrintServer | 40 | Format-Table -Property Name, 41 | DefaultSpoolDirectory 42 | 43 | 44 | 45 | # Another way to set the Spooler directory is by directly editing the registry as follows: 46 | 47 | 48 | # 9. First stop the Spooler service: 49 | Stop-Service -Name Spooler 50 | 51 | # 10. Create a new spool directory: 52 | $SPL = 'C:\SpoolViaRegistry' 53 | $NIHT2 = @{ 54 | Path = $SPL 55 | Itemtype = 'Directory' 56 | ErrorAction = 'SilentlyContinue' 57 | } 58 | New-Item @NIHT2 | Out-Null 59 | 60 | # 11. Create the spooler folder and configure in the registry 61 | $RPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\' + 62 | 'Print\Printers' 63 | $Spooldir = 'C:\SpoolViaRegistry' # Folder should exist 64 | $IP = @{ 65 | Path = $RPath 66 | Name = 'DefaultSpoolDirectory' 67 | Value = $SPL 68 | } 69 | Set-ItemProperty @IP 70 | 71 | # 12. Restart the Spooler: 72 | Start-Service -Name Spooler 73 | 74 | # 13. View the results: 75 | New-Object -TypeName System.Printing.PrintServer | 76 | Format-Table -Property Name, DefaultSpoolDirectory -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.3b - Create performance collector set (CSV OUT).ps1: -------------------------------------------------------------------------------- 1 | # 7.3 Create and add a data collector set 2 | # This script creates a CSV 3 | 4 | #region Create the counter 5 | # 1. Create and populate a new collector 6 | $Name = 'SRV1 Collector Set - CSV' 7 | $SRV1CS = New-Object -COM Pla.DataCollectorSet 8 | $SRV1CS.DisplayName = $Name 9 | $SRV1CS.Duration = 12*3600 # 12 hours - 19:00 10 | $SRV1CS.SubdirectoryFormat = 1 11 | $SRV1CS.SubdirectoryFormatPattern = 'yyyy\-MM' 12 | $JPHT = @{ 13 | Path = "$Env:SystemDrive" 14 | Childpath = "\PerfLogs\Admin\$Name" 15 | } 16 | $SRV1CS.RootPath = Join-Path "$Env:SystemDrive" "\PerfLogs\Admin\$Name" 17 | 18 | $SRV1Collector = $SRV1CS.DataCollectors.CreateDataCollector(0) 19 | $SRV1Collector.FileName = '$Name_' 20 | $SRV1Collector.FileNameFormat = 1 21 | $SRV1Collector.FileNameFormatPattern = "\-MM\-dd" 22 | $SRV1Collector.SampleInterval = 15 23 | $SRV1Collector.LogFileFormat = 0 # comma separated 24 | $SRV1Collector.LogAppend = $True 25 | 26 | # 2. Define counters of interest 27 | $Counters = @( 28 | '\Memory\Pages/sec', 29 | '\Memory\Available MBytes', 30 | '\Processor(_Total)\% Processor Time', 31 | '\PhysicalDisk(_Total)\% Disk Time', 32 | '\PhysicalDisk(_Total)\Disk Transfers/sec' , 33 | '\PhysicalDisk(_Total)\Avg. Disk Sec/Read', 34 | '\PhysicalDisk(_Total)\Avg. Disk Sec/Write', 35 | '\PhysicalDisk(_Total)\Avg. Disk Queue Length' 36 | ) 37 | 38 | # 3. Add the counters to the collector 39 | $SRV1Collector.PerformanceCounters = $Counters 40 | 41 | # 4. Create a schedule - start tomorrow morning at 07:00 42 | $StartDate = Get-Date -Day $((Get-Date).Day+1) -Hour 7 -Minute 0 -Second 0 43 | $Schedule = $SRV1CS.Schedules.CreateSchedule() 44 | $Schedule.Days = 127 45 | $Schedule.StartDate = $StartDate 46 | $Schedule.StartTime = $StartDate 47 | 48 | # 5. Create, add and start the collector set 49 | try 50 | { 51 | $SRV1CS.Schedules.Add($Schedule) 52 | $SRV1CS.DataCollectors.Add($SRV1Collector) 53 | $SRV1CS.Commit("$Name" , $null , 0x0003) | Out-Null 54 | $SRV1CS.Start($false); 55 | } 56 | catch [Exception] 57 | { 58 | Write-Host "Exception Caught: " $_.Exception -ForegroundColor Red 59 | return 60 | } 61 | -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Recipe 10.5 -Configuring DSC LCM.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 10.5 - Configuring LCM 2 | # 3 | 4 | # 1. Nuke any Local MOF files and configurations on SRV2, and ensure c:\DSC exists 5 | $RIHT =@{ 6 | Path = 'C:\Windows\System32\configuration\*.mof' 7 | ErrorAction = 'SilentlyContinue' 8 | } 9 | Get-Childitem @RIHT | 10 | Remove-Item @RIHT -Force 11 | $EASC = @{ 12 | ErrorAction = 'SilentlyContinue'} 13 | New-Item -Path c:\DSC -ItemType Directory @EASC | 14 | Out-Null 15 | 16 | # 2. Get Default settings for LCM: 17 | Get-DscLocalConfigurationManager | 18 | Format-List -Property ActionafterReboot, 19 | AllowModuleOverwrite, 20 | Configuration*, 21 | LCMState, 22 | PartialConfigurations, 23 | Reboot*, 24 | Refresh*, 25 | Report*, 26 | Resource* 27 | 28 | # 3. Create meta configuration for this host 29 | Configuration SRV2LcmConfig { 30 | Node Localhost{ 31 | LocalConfigurationManager { 32 | ConfigurationMode = 'ApplyOnly' 33 | RebootNodeIfNeeded = $true 34 | } 35 | } 36 | } 37 | 38 | # 4. Run the config and create the mof 39 | SRV2LcmConfig -OutputPath C:\DSC 40 | 41 | # 5. Set LCM 42 | Set-DscLocalConfigurationManager -Path c:\DSC -Verbose 43 | 44 | # 6. and check updated values: 45 | 46 | Get-DscLocalConfigurationManager | 47 | Format-List -Property ActionafterReboot, 48 | AllowModuleOverwrite, 49 | Configuration*, 50 | LCMState, 51 | PartialConfigurations, 52 | Reboot*, 53 | Refresh*, 54 | Report*, 55 | Resource* 56 | 57 | 58 | 59 | 60 | # Reset should u need to 61 | 62 | Configuration SRV2LcmConfig { 63 | Node Localhost{ 64 | LocalConfigurationManager { 65 | AllowModuleOverwrite = $false 66 | ConfigurationModeFrequencyMins = 15 67 | ConfigurationMode = 'ApplyAndMOnitor' 68 | RebootNodeIfNeeded = $false 69 | } 70 | } 71 | } 72 | SRV2LcmConfig -OutputPath c:\dsc 73 | Set-DscLocalConfigurationManager -Path c:\DSC -Verbose 74 | 75 | -------------------------------------------------------------------------------- /Chapter 05 - Managing Shared Data/Recipe x - Creating a scale out file server..ps1: -------------------------------------------------------------------------------- 1 | # Recipe 9.6 - Make file server fault tolerant 2 | # This recipe is run on FS1, but involves FS2 3 | # ISCSI initiator is setup on FS1, FS2 4 | 5 | # Step 1 - add clustering features 6 | Install-WindowsFeature –Name Failover-Clustering, ` 7 | -ComputerName FS1 ` 8 | –IncludeManagementTools 9 | 10 | Install-WindowsFeature –Name Failover-Clustering ` 11 | -ComputerName FS2 ` 12 | –IncludeManagementTools 13 | 14 | 15 | # Step 2 - Test the nodes 16 | $CheckOutput = 'c:\foo\clustercheck.htm' 17 | Test-Cluster -Node FS1, FS2 -ReportName $CheckOutput 18 | 19 | 20 | # Step 3 - View Validation test results 21 | Invoke-Item -Path $CheckOutput 22 | 23 | 24 | # Step 4 - Create The Cluster 25 | New-Cluster -Name FS ` 26 | -Node 'fs1.reskit.org', 'fs2.reskit.org' ` 27 | -StaticAddress 10.10.10.100 28 | 29 | # 5. Add the Cluster Scale Out File Server role: 30 | Add-ClusterScaleOutFileServerRole -Name SalesFS 31 | 32 | # 6. Add the Target to the CSV 33 | Get-ClusterResource | 34 | Where-Object OwnerGroup -Match 'Available' | 35 | Add-ClusterSharedVolume -Name VM 36 | 37 | # 7 add a normal FailOver share 38 | $SdFolder = 'S:\SalesData' 39 | New-SMBShare -Name SalesData ` 40 | -Path $SdFolder ` 41 | -Description 'SalesData' 42 | 43 | # 8. Add a Continously Avaliable share 44 | $HvFolder = 'C:\ClusterStorage\Volume1\HVData' 45 | New-Item -Path $HvFolder -ItemType Directory | 46 | Out-Null 47 | New-SMBShare -Name SalesHV -Path $HvFolder ` 48 | -Description 'Sales HV (CA)' ` 49 | -FullAccess 'Reskit\IT Team' ` 50 | -ContinuouslyAvailable:$true 51 | 52 | # 9. View Shares 53 | Get-SmbShare 54 | 55 | 56 | <# Remove it 57 | Get-SMBShare -name SalesData | Remove-SMBShare -Confirm:$False 58 | Get-SMBShare -name HVShare | Remove-SMBShare -Confirm:$False 59 | 60 | get-clusterresource | Stop-ClusterResource 61 | Stop-Cluster 62 | 63 | Get-ClusterSharedVolume | Remove-ClusterSharedVolume 64 | Get-Clusterresource | stop-clusterresource 65 | Get-ClusterGroup -Name salesfs | remove-clusterresource 66 | Get-ClusterResource | remove-clusterresource -Force 67 | Remove-Cluster -force -cleanupad 68 | #> 69 | 70 | # later 71 | Add-ClusterSharedVolume -Name HVCSV 72 | -------------------------------------------------------------------------------- /Chapter 07 - Managing Printers/Recipe 7.1 - Installing and sharing printer.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 7-1 Installing and sharing printers 2 | # 3 | # Run on Psrv.Reskit.Org 4 | 5 | # 1. Install the Print-Server feature on PSRV, along with the print management 6 | # tools: 7 | Install-WindowsFeature -Name Print-Server, RSAT-Print-Services 8 | 9 | 10 | # 2. Create a folder for the Xerox printer drivers: 11 | $NIHT = @{ 12 | Path = 'C:\Foo\Xerox' 13 | ItemType = 'Directory' 14 | Force = $true 15 | ErrorAction = "Silentlycontinue" 16 | } 17 | New-Item @NIHT | Out-Null 18 | 19 | #3. Download printer drivers for Xerox printers: 20 | $URL='http://download.support.xerox.com/pub/drivers/6510/'+ 21 | 'drivers/win10x64/ar/6510_5.617.7.0_PCL6_x64.zip' 22 | $Target='C:\Foo\Xerox\Xdrivers.zip' 23 | Start-BitsTransfer -Source $URL -Destination $Target 24 | 25 | # 4. Expand the zip file 26 | $Drivers = 'C:\Foo\Xerox\Drivers' 27 | Expand-Archive -Path $Target -DestinationPath $Drivers 28 | 29 | # 5. Install the drivers 30 | $M1 = 'Xerox Phaser 6510 PCL6' 31 | $P = 'C:\Foo\Xerox\Drivers\6510_5.617.7.0_PCL6_x64_Driver.inf\'+ 32 | 'x3NSURX.inf' 33 | rundll32.exe printui.dll,PrintUIEntry /ia /m "$M1" /f "$P" 34 | $M2 = 'Xerox WorkCentre 6515 PCL6' 35 | rundll32.exe printui.dll,PrintUIEntry /ia /m "$M2" /f "$P" 36 | 37 | 38 | # 6. Add a PrinterPort for a new printer: 39 | $PPHT = @{ 40 | Name = 'SalesPP' 41 | PrinterHostAddress = '10.10.10.61' 42 | } 43 | Add-PrinterPort @PPHT 44 | 45 | 46 | # 7. Add the printer 47 | $PRHT = @{ 48 | Name = 'SalesPrinter1' 49 | DriverName = $m1 50 | PortName = 'SalesPP' 51 | } 52 | Add-Printer @PRHT 53 | 54 | # 8. Share the printer: 55 | Set-Printer -Name SalesPrinter1 -Shared $True 56 | 57 | # 9. Review what you have done: 58 | Get-PrinterPort -Name SalesPP | 59 | Format-Table -Autosize -Property Name, Description, 60 | PrinterHostAddress, PortNumber 61 | Get-PrinterDriver -Name xerox* | 62 | Format-Table -Property Name, Manufacturer, 63 | DriverVersion, PrinterEnvironment 64 | Get-Printer -ComputerName PSRV -Name SalesPrinter1 | 65 | Format-Table -Property Name, ComputerName, 66 | Type, PortName, Location, Shared 67 | 68 | 69 | 70 | 71 | # undo things 72 | 73 | Remove-printer SalesPrinter1 74 | net stop spooler;net start spooler 75 | Remove-PrinterPort 'SalesPP' 76 | 77 | -------------------------------------------------------------------------------- /Chapter 06 - Deploying Windows Update/Recipe 6.3 - Configuring WIndows Update Client.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 6.3 - Configuring the Windows Update client Via GPO 2 | # 3 | # Run on CL1 4 | 5 | # 0. Get WIndows Upate module and install it 6 | Get-PackageProvider -Name NuGet -ForceBootstrap | Out-Null 7 | Install-Module PSWindowsUpdate -force 8 | 9 | # 1. Examine 10 | 11 | # 1. Define the WSUS server URL using the properties returned from GetWsusServer: 12 | $WSUSServer = Get-WsusServer -Name WSUS1.Reskit.Org -Port 8530 13 | $FS = "http{2}://{0}:{1}" 14 | $N = $WSUSServer.Name 15 | $P = 8530 # default port 16 | $WSUSServerURL = $FS -f $n, $p, ('','s')[$WSUSServer.UseSecureConnection] 17 | $WSUSServerURL 18 | 19 | # 2. Create a Group Policy Object (GPO) and link it to the domain: 20 | $PolicyName = 'Reskit WSUS Policy' 21 | New-GPO -Name $PolicyName 22 | New-GPLink -Name $PolicyName -Target 'DC=RESKIT,DC=Org' 23 | 24 | # 3. Add registry key settings to the group policy to assign the WSUS server: 25 | # Set to use WSUS not WU 26 | $KEY1 = 'HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU' 27 | $RVHT1 = @{ 28 | Name = $PolicyName 29 | Key = $KEY1 30 | ValueName = 'UseWUServer' 31 | Type = 'DWORD' 32 | Value = 1 33 | } 34 | Set-GPRegistryValue @RVHT1 | Out-Null 35 | # Set AU options 36 | $KEY2 = 'HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate\AU' 37 | $RVHT2 = @{ 38 | Name = $PolicyName 39 | Key = $KEY2 40 | ValueName = 'AUOptions' 41 | Type = 'DWORD' 42 | Value = 2 43 | } 44 | Set-GPRegistryValue @RVHT2 | Out-Null 45 | # Set WSUS Server URL 46 | $KEY3 = 'HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate' 47 | $RVHT3 = @{ 48 | Name = $PolicyName 49 | Key = $KEY3 50 | ValueName = 'WUServer' 51 | Type = 'String' 52 | Value = $WSUSServerURL 53 | } 54 | Set-GPRegistryValue @RVHT3 | Out-Null 55 | # Set WU Status server URL 56 | $KEY4 = 'HKLM\Software\Policies\Microsoft\Windows\WindowsUpdate' 57 | $RVHT4 = @{ 58 | Name = $PolicyName 59 | Key = $KEY4 60 | ValueName = 'WUStatusServer' 61 | Type = 'String' 62 | Value = $WSUSServerURL 63 | } 64 | Set-GPRegistryValue @RVHT4 | Out-Null 65 | 66 | 67 | # 4. Get a report on the GPO 68 | $RHT = @{ 69 | Name = $PolicyName 70 | ReportType = 'Html' 71 | Path = 'C:\foo\out.html' 72 | } 73 | Get-GPOReport @RHT 74 | Invoke-Item -Path $RHT.Path 75 | -------------------------------------------------------------------------------- /Chapter 03 - Deploying Active Directory/3.4 - Creating a group policy object.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 3.4 - Creating a group policy object 2 | 3 | # 1. Create Group Policy object 4 | $Pol = 5 | New-GPO -Name ITPolicy -Comment "IT GPO" -Domain Reskit.Org 6 | 7 | # 2. Ensure just computer settings are enabled 8 | $Pol.GpoStatus = 'UserSettingsDisabled' 9 | 10 | # 3. Configure the policy with two settings 11 | $EPHT1= @{ 12 | Name = 'ITPolicy' 13 | Key = 'HKLM\Software\Policies\Microsoft\Windows\PowerShell' 14 | ValueName = 'ExecutionPolicy' 15 | Value = 'Unrestricted' 16 | Type = 'String' 17 | } 18 | Set-GPRegistryValue @EPHT1 | Out-Null 19 | $EPHT2= @{ 20 | Name = 'ITPolicy' 21 | Key = 'HKLM\Software\Policies\Microsoft\Windows\PowerShell' 22 | ValueName = 'EnableScripts' 23 | Type = 'DWord' 24 | Value = 1 25 | } 26 | Set-GPRegistryValue @EPHT2 | Out-Null 27 | 28 | # 4. Create a screen saver GPO And set status and a comment 29 | $Pol2 = New-GPO -Name 'Screen Saver Time Out' 30 | $Pol2.GpoStatus = 'ComputerSettingsDisabled' 31 | $Pol2.Description = '15 minute timeout' 32 | 33 | # 5. Set a registry value 34 | $EPHT3= @{ 35 | Name = 'Screen Saver Time Out' 36 | Key = 'HKCU\Software\Policies\Microsoft\Windows\'+ 37 | 'Control Panel\Desktop' 38 | ValueName = 'ScreenSaveTimeOut' 39 | Value = 900 40 | Type = 'DWord' 41 | } 42 | Set-GPRegistryValue @EPHT3 | Out-Null 43 | 44 | # 6. Assign the GPOs to the IT OU 45 | $GPLHT1 = @{ 46 | Name = 'ITPolicy' 47 | Target = 'OU=IT,DC=Reskit,DC=org' 48 | } 49 | New-GPLink @GPLHT1 | Out-Null 50 | $GPLHT2 = @{ 51 | Name = 'Screen Saver Time Out' 52 | Target = 'OU=IT,DC=Reskit,DC=org' 53 | } 54 | New-GPLink @GPLHT2 | Out-Null 55 | 56 | # 7. Display the GPOs in the domain 57 | Get-GPO -All -Domain Reskit.Org | 58 | Sort -Property DisplayName | 59 | Format-Table -Property Displayname, Description, GpoStatus 60 | 61 | # 8. Create and view a GPO Report 62 | $RPath = 'C:\Foo\GPOReport1.HTML' 63 | Get-GPOReport -Name 'ITPolicy' -ReportType Html -Path $RPath 64 | Invoke-Item -Path $RPath 65 | 66 | 67 | 68 | # to undo for testing 69 | 70 | Remove-GPLink -Name 'Screen Saver Time Out' -Target 'OU=IT,DC=Reskit,DC=Org' 71 | Remove-GPLink -Name 'ITPolicy' -Target 'OU=IT,DC=Reskit,DC=Org' 72 | Get-GPO 'ITPolicy' | Remove-GPO 73 | Get-GPO 'Screen Saver Time Out' | remove-GPO 74 | Get-GPO -Domain 'Reskit.Org' -All | 75 | Format-Table -Property DisplayName, GPOStatus, Description -------------------------------------------------------------------------------- /Errata.md: -------------------------------------------------------------------------------- 1 | # Book Errata 2 | 3 | A considerable amount of time was expended proofreading the book details. 4 | Besides the author there were several other people who also looked for errors. 5 | Sadly, not all errors were caught during production but not all. 6 | 7 | This document describes the errors found. 8 | 9 | ## Errors 10 | 11 | ### Preface 12 | 13 | Page IX, 4th paragraph, second line, should read: 14 | "spelled out in full. Thus, no abbreviated parameter names or positional parameters. This" 15 | 16 | ### Chapter 1 - Establishing a PowerShell Administrative Environment 17 | 18 | Page 11 - small error in screen shots. they should not be different. 19 | Page 12, 2nd Paragraph, penultimate line - the sentence should read: "And for versions later than 1803, the 20 | mechanism may change again." 21 | And with the passage of time since the book was written, the mechanism has indeed changed again. 22 | 23 | Page 15 - Step 15 should read SRV1, not SRV2 24 | 25 | ### Chapter 2 -Managing Windows Networking 26 | 27 | Page 65/66 - Step 6 is not actually shown. The output (on page 66) is form step 7 not step 6. 28 | 29 | ### Chapter 4 - Managing Windows Storage 30 | 31 | Page 134 - The code is fine in the book, but the GITHUB copy had an error in step 5 which is fixed. 32 | 33 | ### Chapter 12 - Managing Azure 34 | 35 | Page 446, last paragraph in intro = this recipe does not check whether the RG and the SA are already created. 36 | Page 447, step 2 - the text is wrong, only login to the Azure account 37 | Page 447. step 5 - the name of the share should be $ShareName. 38 | 39 | 40 | 41 | 42 | 43 | ### Chapter 14 - Managing Performance and Usage 44 | 45 | page 467 - step 9, second line - the Counter should be $Counter2 46 | 47 | Page 471 - photo for step 9 is likewise incorrect in terms of counter name even though the output values are correct. 48 | 49 | Page 471 - the lead in to the graphic for step 9, the server name cited should be HV1. 50 | 51 | Page 479 - the values for LogFileFormat mentioned in the text are wrong and should be like this: 52 | '''powershell 53 | public enum LogFileFormat 54 | { 55 | CommaSeparated = 0, 56 | TabSeparated = 1, 57 | Sql = 2, 58 | Binary = 3, 59 | } 60 | ''' 61 | 62 | Page 482 - graphic for step 2 is incorrect. 63 | 64 | Page 493 - step 13. Error in getting CPU numbers 65 | # (Script updated too) 66 | '''powershell 67 | #this 68 | $VMReport.VMCPU = $VM.CPUUsage 69 | #should be 70 | $VMReport.VMCPU = $VM.ProcessorCount 71 | 72 | 73 | -------------------------------------------------------------------------------- /Chapter 04 - Managing Storage/Add-DiskstoSRV1+2.ps1: -------------------------------------------------------------------------------- 1 | # Add-DiskstoSrv1+2 2 | # 3 | # 4 | # Add two disks to SRV1/2 for Storage Chapter 5 | 6 | # Create volumes for Srv1, 2 7 | New-VHD -Path D:\v6\SRV1\SRV1-F.vhdx -SizeBytes 10gb -Dynamic 8 | New-VHD -Path D:\v6\SRV1\SRV1-G.vhdx -SizeBytes 10gb -Dynamic 9 | New-VHD -Path D:\v6\SRV2\SRV2-F.vhdx -SizeBytes 10gb -Dynamic 10 | New-VHD -Path D:\v6\SRV2\SRV2-G.vhdx -SizeBytes 10gb -Dynamic 11 | 12 | # Add disks 13 | Add-VMHardDiskDrive -VMName SRV1 -Path D:\v6\srv1\SRV1-F.vhdx -ControllerType SCSI -ControllerNumber 0 14 | Add-VMHardDiskDrive -VMName SRV1 -Path D:\v6\srv1\SRV1-G.vhdx -ControllerType SCSI -ControllerNumber 0 15 | Add-VMHardDiskDrive -VMName SRV2 -Path D:\v6\srv2\SRV2-F.vhdx -ControllerType SCSI -ControllerNumber 0 16 | Add-VMHardDiskDrive -VMName SRV2 -Path D:\v6\srv2\SRV2-G.vhdx -ControllerType SCSI -ControllerNumber 0 17 | 18 | # what have we here then? 19 | Get-VMHardDiskDrive -vmname srv1 20 | Get-VMHardDiskDrive -vmname srv2 21 | 22 | 23 | # Format the srv2 drives so that recipe 4.3 works 24 | $SB = { 25 | 26 | # Initialize the disks 27 | Get-Disk | 28 | Where PartitionStyle -eq Raw | 29 | Initialize-Disk -PartitionStyle GPT 30 | 31 | $NVHT1 = @{ 32 | DiskNumber = 1 33 | FriendlyName = 'Storage' 34 | FileSystem = 'NTFS' 35 | DriveLetter = 'F' 36 | } 37 | New-Volume @NVHT1 38 | # Create two volumes in Disk 2 - first create G: 39 | New-Partition -DiskNumber 2 -DriveLetter G -Size 4gb 40 | # Create a second partition H: 41 | New-Partition -DiskNumber 2 -DriveLetter H -UseMaximumSize 42 | # Format G: and H: 43 | $NVHT1 = @{ 44 | DriveLetter = 'G' 45 | FileSystem = 'NTFS' 46 | NewFileSystemLabel = 'Log'} 47 | Format-Volume @NVHT1 48 | $NVHT2 = @{ 49 | DriveLetter = 'H' 50 | FileSystem = 'NTFS' 51 | NewFileSystemLabel = 'GDShow'} 52 | Format-Volume @NVHT2 53 | } 54 | Invoke-Command -ComputerName SRV2 -ScriptBlock $SB -Credential $Credrk 55 | 56 | 57 | ### For testing - remove the disksfrom the VMs, delete them, and recreate them if necessary! 58 | 59 | # Remove disks from the VMs 60 | Get-VMHardDiskDrive -vmname srv1 | where ControllerType -eq scsi | remove-vmharddiskdrive 61 | Get-VMHardDiskDrive -vmname srv2 | where ControllerType -eq scsi | remove-vmharddiskdrive 62 | 63 | # remove disks 64 | Remove-Item -Path D:\v6\SRV1\SRV1-F.vhdx 65 | Remove-Item -Path D:\v6\SRV1\SRV1-G.vhdx 66 | Remove-Item -Path D:\v6\SRV2\SRV2-F.vhdx 67 | Remove-Item -Path D:\v6\SRV2\SRV2-G.vhdx 68 | -------------------------------------------------------------------------------- /Chapter 04 - Managing Storage/Recipe 4.3 - Managing storage replica.ps1: -------------------------------------------------------------------------------- 1 | # 4.3 - Manage Storage replica 2 | # 3 | # Run on SRV1, with SRV2, DC1 online 4 | 5 | 6 | # 1. Create Content on F: 7 | 1..100 | ForEach { 8 | $NF = "F:\CoolFolder$_" 9 | New-Item -Path $NF -ItemType Directory | Out-Null 10 | 1..100 | ForEach { 11 | $NF2 = "$NF\CoolFile$_" 12 | "Cool File" | Out-File -PSPath $NF2 13 | } 14 | } 15 | 16 | # 2. Show what is on F: locally 17 | Get-ChildItem -Path F:\ -Recurse | Measure-Object 18 | 19 | # 3. And examine the same drives remotely on SRV2 20 | $SB = { 21 | Get-ChildItem -Path F:\ -Recurse | 22 | Measure-Object 23 | } 24 | Invoke-Command -ComputerName SRV2 -ScriptBlock $SB 25 | 26 | # 4. Add storage replica feature to SRV1 27 | Add-WindowsFeature -Name Storage-Replica 28 | 29 | # 5. Restart SRV1 to finish the installation process 30 | Restart-Computer 31 | 32 | # 6. Add SR Feature to SRV2 33 | $SB= { 34 | Add-WindowsFeature -Name Storage-Replica | Out-Null 35 | } 36 | Invoke-Command -ComputerName SRV2 -ScriptBlock $SB 37 | 38 | # 7. And restart SRV2 Waiting for the restart 39 | $RSHT = @{ 40 | ComputerName = 'SRV2' 41 | Force = $true 42 | } 43 | Restart-Computer @RSHT -Wait -For PowerShell 44 | 45 | # 8. Create an SR Replica 46 | $SRHT = @{ 47 | SourceComputerName = 'SRV1' 48 | SourceRGName = 'SRV1RG' 49 | SourceVolumeName = 'F:' 50 | SourceLogVolumeName = 'G:' 51 | DestinationComputerName = 'SRV2' 52 | DestinationRGName = 'SRV2RG' 53 | DestinationVolumeName = 'F:' 54 | DestinationLogVolumeName = 'G:' 55 | LogSizeInBytes = 2gb 56 | } 57 | New-SRPartnership @SRHT -Verbose 58 | 59 | # 9. View it 60 | Get-SRPartnership 61 | 62 | # 10. And examine the same drives remotely on SRV2 63 | $SB = { 64 | Get-Volume | 65 | Sort-Object -Property DriveLetter | 66 | Format-Table 67 | } 68 | Invoke-Command -ComputerName SRV2 -ScriptBlock $SB 69 | 70 | 71 | # 11. Reverse the replication 72 | $SRHT2 = @{ 73 | NewSourceComputerName = 'SRV2' 74 | SourceRGName = 'SRV2RG' 75 | DestinationComputerName = 'SRV1' 76 | DestinationRGName = 'SRV1RG' 77 | Confirm = $false 78 | } 79 | Set-SRPartnership @SRHT2 80 | 81 | 82 | # 12 View RG 83 | Get-SRPartnership 84 | 85 | # 13. Examine the same drives remotely on SRV2 86 | $SB = { 87 | Get-ChildItem -Path F:\ -Recurse | 88 | Measure-Object 89 | } 90 | Invoke-Command -ComputerName SRV2 -ScriptBlock $SB 91 | 92 | -------------------------------------------------------------------------------- /Chapter 08 - Leveraging containers/Recipe 8.2 - Deploying a hello world sample.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 8.2 - Deploying a Hello World Application 2 | # 3 | # Run on CH1 4 | 5 | 6 | # 1. Find Hello-work containers at the Docker Hub 7 | docker search hello-world 8 | 9 | # 2. Pull the Docker official hello-world image 10 | docker pull hello-world 11 | 12 | # 3. Check the Image just downloaded 13 | docker image ls 14 | 15 | # 4. Run the hello-world container image 16 | docker run hello-world 17 | 18 | # 5. Look for Microsoft images on the Docker Hub: 19 | docker search microsoft 20 | 21 | # 6. Get nano server base image 22 | docker image pull mcr.microsoft.com/windows/nanoserver:1809 23 | 24 | # 7. Run the nanoserver base image: 25 | docker run mcr.microsoft.com/windows/nanoserver:1809 26 | 27 | # 8. Check the images available now on CH1: 28 | docker image ls 29 | 30 | # 9. Inspect the first image: 31 | $Images = docker image ls 32 | $Rxs = '(\w+) +(\w+) +(\w+) ' 33 | $OK = $Images[1] -Match $Rxs 34 | $Image = $Matches[1] # grab the image name 35 | docker inspect $image | ConvertFrom-Json 36 | 37 | # 10. Get another (older) image and try to run it: 38 | docker image pull microsoft/nanoserver | Out-Null 39 | docker run microsoft/nanoserver 40 | 41 | # 11. run it with isolation 42 | docker run --isolation=hyperv microsoft/nanoserver 43 | 44 | # 12. look at differences in run times with hyper-V 45 | # run with no isolation 46 | $S1 = Get-Date 47 | docker run hello-world | 48 | Out-Null 49 | $E1 = Get-Date 50 | $T1 = ($E1-$S1).TotalMilliseconds 51 | # run with isolation 52 | $S2 = Get-Date 53 | docker run --isolation=hyperv hello-world | Out-Null 54 | $E2 = get-date 55 | $T2 = ($E2-$S2).TotalMilliseconds 56 | "Without isolation, took : $T1 milliseconds" 57 | "With isolation, took : $T2 milliseconds" 58 | 59 | # 13. run a detached container! 60 | docker image pull microsoft/iis | out-null 61 | docker run -d -p 80:80 microsoft/iis ping -t localhost | 62 | Out-Null 63 | 64 | # 14. Use IIS: 65 | Start-Process http://CH1.Reskit.Org 66 | 67 | # 15. Is IIS loaded?IIS? 68 | Get-Windowsfeature -Name Web-Server 69 | 70 | # 16. check the container 71 | docker container ls 72 | 73 | # 17. And stop kill the contaienr 74 | $CS = (docker container ls)[1] | 75 | Where-Object {$_ -match '( \w+$)'} 76 | $CN = $Matches[0].trim() 77 | docker container stop ($CN) | Out-Null 78 | 79 | # 18. And remove all images 80 | docker rmi $(docker images -q) -f | out-Null 81 | 82 | # 19. and what's left? 83 | docker image ls 84 | docker container ls 85 | 86 | -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Recipe 10.4 - Using DSC with PSGallery Resources.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 10.4 - Using DSC with PS Gallery resources 2 | # 3 | # Run on SRV1 After 10.3 (Getting resources) 4 | 5 | # Step 1 - Copy xWebAdministration module to SRV2 6 | 7 | $CIHT = @{ 8 | Path = 'C:\Program Files\WindowsPowerShell\' + 9 | 'Modules\xWebAdministration' 10 | Destination = '\\SRV2\C$\Program Files\WindowsPowerShell\'+ 11 | 'Modules' 12 | Recurse = $True 13 | } 14 | Copy-Item @CIHT 15 | 16 | # 2. Clear any existing Configuration documents on SRV, and local mof files 17 | $RIHT =@{ 18 | Path = '\\SRV2\c$\Windows\System32\configuration\*.mof' 19 | ErrorAction = 'SilentlyContinue' 20 | } 21 | Get-Childitem @RIHT | 22 | Remove-Item @RIHT -Force 23 | Remove-Item C:\DSC\* -Recurse -Force 24 | 25 | # 3. Create Configuration: 26 | Configuration RKAppSRV2 { 27 | Import-DscResource -ModuleName xWebAdministration 28 | Import-DscResource -ModuleName PSDesiredStateConfiguration 29 | Node SRV2 { 30 | Windowsfeature IISSrv2 { 31 | Ensure = 'Present' 32 | Name = 'Web-Server' 33 | } 34 | Windowsfeature IISSrvTools { 35 | Ensure = 'Present' 36 | Name = 'Web-Mgmt-Tools' 37 | DependsOn = '[WindowsFeature]IISSrv2' 38 | } 39 | File RKAppFiles { 40 | Ensure = 'Present' 41 | Checksum = 'ModifiedDate' 42 | Sourcepath = '\\DC1\ReskitApp\' 43 | Type = 'Directory' 44 | Recurse = $true 45 | DestinationPath = 'C:\ReskitApp\' 46 | DependsOn = '[Windowsfeature]IISSrv2' 47 | MatchSource = $true 48 | } 49 | xWebAppPool ReskitAppPool { 50 | Name = 'RKAppPool' 51 | Ensure = 'Present' 52 | State = 'Started' 53 | DependsOn = '[File]RKAppFiles' 54 | } 55 | xWebApplication ReskitAppPool { 56 | Website = 'Default Web Site' 57 | WebAppPool = 'RKAppPool' 58 | Name = 'ReskitApp' 59 | PhysicalPath = 'C:\ReskitApp\' 60 | Ensure = 'Present' 61 | DependsOn = '[xWebAppPool]ReskitAppPool' 62 | } 63 | Log Completed { 64 | Message = 'Finished Configuring ReskitAp via DSC against SRV2' 65 | } 66 | } # End of SRV2 Configuration 67 | } # End of Configuration 68 | 69 | # 4. Run the configuration block to compile it 70 | RKAppSRV2 -OutputPath C:\DSC 71 | 72 | # 5. Deploy the configuration to SRV2 73 | Start-DscConfiguration -Path C:\DSC -Verbose -Wait 74 | 75 | # 6. Test Result 76 | Start-Process 'http://SRV2/ReskitApp/' 77 | -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.3 - Create+Use PLA Data Collector set.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 6.3 - Create and add a data collector set 2 | 3 | # 1. Create and populate a new collector 4 | $Name = 'SRV1 Collector Set' 5 | $SRV1CS = New-Object -COM Pla.DataCollectorSet 6 | $SRV1CS.DisplayName = $Name 7 | $SRV1CS.Duration = 12*3600 # 12 hours - 19:00 8 | $SRV1CS.SubdirectoryFormat = 1 9 | $SRV1CS.SubdirectoryFormatPattern = 'yyyy\-MM' 10 | $JPHT = @{ 11 | Path = "$Env:SystemDrive" 12 | ChildPath = "\PerfLogs\Admin\$Name" 13 | } 14 | $SRV1CS.RootPath = Join-Path @JPHT 15 | $SRV1Collector = $SRV1CS.DataCollectors.CreateDataCollector(0) 16 | $SRV1Collector.FileName = "$Name_" 17 | $SRV1Collector.FileNameFormat = 1 18 | $SRV1Collector.FileNameFormatPattern = "\-MM\-dd" 19 | $SRV1Collector.SampleInterval = 15 20 | $SRV1Collector.LogFileFormat = 3 # BLG separated 21 | $SRV1Collector.LogAppend = $True 22 | 23 | # 2. Define counters of interest 24 | $Counters = @( 25 | '\Memory\Pages/sec', 26 | '\Memory\Available MBytes', 27 | '\Processor(_Total)\% Processor Time', 28 | '\PhysicalDisk(_Total)\% Disk Time', 29 | '\PhysicalDisk(_Total)\Disk Transfers/sec' , 30 | '\PhysicalDisk(_Total)\Avg. Disk Sec/Read', 31 | '\PhysicalDisk(_Total)\Avg. Disk Sec/Write', 32 | '\PhysicalDisk(_Total)\Avg. Disk Queue Length' 33 | ) 34 | 35 | # 3. Add the counters to the collector 36 | $SRV1Collector.PerformanceCounters = $Counters 37 | 38 | # 4. Create a schedule - start tomorrow morning at 07:00 39 | $StartDate = Get-Date -Day $((Get-Date).Day+1) -Hour 7 -Minute 0 -Second 0 40 | $Schedule = $SRV1CS.Schedules.CreateSchedule() 41 | $Schedule.Days = 127 42 | $Schedule.StartDate = $StartDate 43 | $Schedule.StartTime = $StartDate 44 | 45 | # 5. Create, add and start the collector set 46 | try 47 | { 48 | $SRV1CS.Schedules.Add($Schedule) 49 | $SRV1CS.DataCollectors.Add($SRV1Collector) 50 | $SRV1CS.Commit("$Name" , $null , 0x0003) | Out-Null 51 | $SRV1CS.Start($false); 52 | } 53 | catch 54 | { 55 | Write-Host "Exception Caught: " $_.Exception -ForegroundColor Red 56 | return 57 | } 58 | 59 | ### at this point the collector set is live inside Windows 60 | 61 | # Not for the book... 62 | pause 63 | 64 | # 6. Remove the counter 65 | $DCStRemote = New-Object -COM Pla.DataCollectorSet 66 | $Name = 'SRV1 Collector Set' 67 | $DCstRemote.Query($Name,'LocalHost') 68 | $DCstRemote.Stop($true) 69 | $DCstRemote.Delete() 70 | 71 | # 7. Restart the counter 72 | $DCStRemote = New-Object -COM Pla.DataCollectorSet 73 | $Name = 'SRV1 Collector Set' 74 | $DCstRemote.Query($Name,'LocalHost') 75 | $DCstRemote.Start($true) -------------------------------------------------------------------------------- /Chapter 08 - Leveraging containers/8.4 Create a container using DOCKERFILE.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 8.4- Creating a Image using a Dockerfile 2 | # 3 | # run on CH1 4 | 5 | # 1. Create folder and Set-location to the folder on CH1 6 | $SitePath = 'C:\RKWebContainer' 7 | $NIHT = @{ 8 | Path = $SitePath 9 | ItemType = 'Directory' 10 | ErrorAction = 'SilentlyContinue' 11 | } 12 | New-Item @NIHT | Out-Null 13 | Set-Location -Path $NIHT.Path 14 | 15 | # 2. Create a script to run in the container to create a new site in the Containe 16 | $SB = { 17 | # 2.1 create folder in the container 18 | $SitePath = 'C:\RKWebContainer' 19 | $NIHT = @{ 20 | Path = $SitePath 21 | ItemType = 'Directory' 22 | ErrorAction = 'SilentlyContinue' 23 | } 24 | New-Item @NIHT | Out-Null 25 | Set-Location -Path $NIHT.Path 26 | # 2.1 Create a page for the site 27 | $PAGE = @' 28 | 29 | 30 | Main Page for RKWeb.Reskit.Org 31 |

32 | HOME PAGE FOR RKWEBr.RESKIT.ORG

33 | Containers and PowerShell Rock! 34 |
35 | '@ 36 | $PAGE | OUT-FILE $SitePath\Index.html | Out-Null 37 | #2.2 Create a new web site in the container that uses Host headers 38 | $WSHT = @{ 39 | PhysicalPath = $SitePath 40 | Name = 'RKWeb' 41 | HostHeader = 'RKWeb.Reskit.Org' 42 | } 43 | New-Website @WSHT 44 | } # End of script block 45 | # 2.5 Save script block to file 46 | $SB | Out-File $SitePath\Config.ps1 47 | 48 | # 3. Create a new A record for our soon to be containerized site: 49 | Invoke-Command -Computer DC1.Reskit.Org -ScriptBlock { 50 | $DNSHT = @{ 51 | ZoneName = 'Reskit.Org' 52 | Name = 'RKWeb' 53 | IpAddress = '10.10.10.221' 54 | } 55 | Add-DnsServerResourceRecordA @DNSHT 56 | } 57 | 58 | # 4. Create Dockerfile 59 | $DF = @" 60 | FROM mcr.microsoft.com/windows/servercore:1809 61 | LABEL Description="RKWEB Container" Vendor="PS Partnership" Version="1.0.0.42" 62 | RUN powershell -Command Add-WindowsFeature Web-Server 63 | RUN powershell -Command GIP 64 | WORKDIR C:\\RKWebContainer 65 | COPY Config.ps1 \Config.ps1 66 | RUN powershell -command ".\Config.ps1" 67 | "@ 68 | # to add in maybe 69 | # Run powershell -Command c:/config.ps1 70 | $DF | Out-File -FilePath .\Dockerfile -Encoding ascii 71 | 72 | # 5. Build the image: 73 | docker build -t rkwebc . 74 | 75 | # 6. Run the image: 76 | docker run -d --name rkwebc -p 80:80 rkwebc 77 | 78 | # 7. Now navigate to the container: 79 | Invoke-WebRequest -UseBasicParsing HTTP://RKweb.Reskit.Org 80 | Start-Process "http://RKWeb.Reskit.Org" 81 | 82 | # 8. test net connection 83 | Test-NetConnection -ComputerName localhost -Port 80 84 | 85 | # 7. clean up forcibly 86 | docker container rm rkwebc -f 87 | -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.3a - Create performance collector set (TSV OUT).ps1: -------------------------------------------------------------------------------- 1 | # 11.3 - Create and add a data collector set 2 | # This variant creates a TSV Output file 3 | # 4 | # Run on SRV1 5 | 6 | # 1. Create and populate a new collector 7 | $Name = 'SRV1 Collector Set - tsv' 8 | $SRV1CS = New-Object -COM Pla.DataCollectorSet 9 | $SRV1CS.DisplayName = $Name 10 | $SRV1CS.Duration = 12*3600 # 12 hours - 19:00 11 | $SRV1CS.SubdirectoryFormat = 1 12 | $SRV1CS.SubdirectoryFormatPattern = 'yyyy\-MM' 13 | $JPHT = @{ 14 | Path = "$Env:SystemDrive" 15 | ChildPath = "\PerfLogs\Admin\$Name" 16 | } 17 | $SRV1CS.RootPath = Join-Path @JPHT 18 | $SRV1Collector = $SRV1CS.DataCollectors.CreateDataCollector(0) 19 | $SRV1Collector.FileName = "$Name_" 20 | $SRV1Collector.FileNameFormat = 1 21 | $SRV1Collector.FileNameFormatPattern = "\-MM\-dd" 22 | $SRV1Collector.SampleInterval = 15 23 | $SRV1Collector.LogFileFormat = 1 # Tab separated 24 | $SRV1Collector.LogAppend = $True 25 | 26 | # 2. Define counters of interest 27 | $Counters = @( 28 | '\Memory\Pages/sec', 29 | '\Memory\Available MBytes', 30 | '\Processor(_Total)\% Processor Time', 31 | '\PhysicalDisk(_Total)\% Disk Time', 32 | '\PhysicalDisk(_Total)\Disk Transfers/sec' , 33 | '\PhysicalDisk(_Total)\Avg. Disk Sec/Read', 34 | '\PhysicalDisk(_Total)\Avg. Disk Sec/Write', 35 | '\PhysicalDisk(_Total)\Avg. Disk Queue Length' 36 | ) 37 | 38 | # 3. Add the counters to the collector 39 | $SRV1Collector.PerformanceCounters = $Counters 40 | 41 | # 4. Create a schedule - start tomorrow morning at 07:00 42 | $StartDate = Get-Date -Day $((Get-Date).Day+1) -Hour 7 -Minute 0 -Second 0 43 | $Schedule = $SRV1CS.Schedules.CreateSchedule() 44 | $Schedule.Days = 127 45 | $Schedule.StartDate = $StartDate 46 | $Schedule.StartTime = $StartDate 47 | 48 | # 5. Create, add and start the collector set 49 | try 50 | { 51 | $SRV1CS.Schedules.Add($Schedule) 52 | $SRV1CS.DataCollectors.Add($SRV1Collector) 53 | $SRV1CS.Commit("$Name" , $null , 0x0003) | Out-Null 54 | $SRV1CS.Start($false); 55 | } 56 | catch [Exception] 57 | { 58 | Write-Host "Exception Caught: " $_.Exception -ForegroundColor Red 59 | return 60 | } 61 | 62 | 63 | pause 64 | 65 | # 6. Remove the counter 66 | $DCStRemote = New-Object -COM Pla.DataCollectorSet 67 | $Name = 'SRV1 Collector Set - tsv' 68 | $DCstRemote.Query($Name,'LocalHost') 69 | $DCstRemote.Stop($true) 70 | $DCstRemote.Delete() 71 | 72 | # 7 and start the counter too 73 | $DCStRemote = New-Object -COM Pla.DataCollectorSet 74 | $Name = 'SRV1 Collector Set' 75 | $DCstRemote.Query($Name,'LocalHost') 76 | $DCstRemote.Start($true) -------------------------------------------------------------------------------- /Chapter 12 - Exploring Azure/Recipe 12.6 - Create Azure VM.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 12.6 - Create an Azure VM 2 | # 3 | # Run on CL1 4 | 5 | # 1. Define key variables 6 | $Locname = 'uksouth' # location name 7 | $RgName = 'packt_rg' # resource group name 8 | $SAName = 'packt42sa' # Storage account name 9 | $VNName = 'packtvnet' # Virtual Network Name 10 | $CloudSN = 'packtcloudsn' # Cloud subnet name 11 | $NSGName = 'packt_nsg' # NSG name 12 | $Ports = @(80, 3389) # ports to open in VBM 13 | $IPName = 'Packt_IP1' # Private IP Address name 14 | $User = 'AzureAdmin' # User Name 15 | $UserPS = 'JerryRocks42!' # User Password 16 | $VMName = 'Packt42VM' # VM Name 17 | 18 | # 2. Login to azure account 19 | $CredAZ = Get-Credential 20 | Login-AzAccount -Credential $CredAZ 21 | 22 | # 3. Ensure the resource group is created: 23 | $RG = Get-AzResourceGroup -Name $RgName -ErrorAction SilentlyContinue 24 | if (-not $rg) { 25 | $RGTag = @{Publisher = 'Packt'} 26 | $RGTag += @{Author = 'Thomas Lee'} 27 | $RGHT1 = @{ 28 | Name = $RgName 29 | Location = $Locname 30 | Tag = $RGTag 31 | } 32 | $RG = New-AzResourceGroup @RGHT1 33 | Write-Host "RG $RgName created" 34 | } 35 | 36 | # 4. Ensure the Storage Account is created 37 | $SA = Get-AzStorageAccount -Name $SAName -ResourceGroupName $RgName -ErrorAction SilentlyContinue 38 | if (-not $SA) { 39 | $SATag = [Ordered] @{Publisher = 'Packt'} 40 | $SATag += @{Author = 'Thomas Lee'} 41 | $SAHT - @{ 42 | Name = $SAName 43 | ResourceGroupName = $RgName 44 | Location = $Locname 45 | Tag = $SATag 46 | $SkuName = 'Standard_LRS' 47 | } 48 | $SA = New-AzStorageAccount @SAHT 49 | Write-Host "SA $SAName created" 50 | } 51 | 52 | 53 | # 5. Create VM credentials 54 | $T = 'System.Management.Automation.PSCredential' 55 | $P = ConvertTo-SecureString -String $UserPS -AsPlainText -Force 56 | $VMCred = New-Object -TypeName $T -ArgumentList $User, $P 57 | 58 | # 6. Create a simple VM using defaults 59 | $VMHT = @{ 60 | ResourceGroupName = $RgName 61 | Location = $Locname 62 | Name = $VMName 63 | VirtualNetworkName = $VNName 64 | SubnetName = $CloudSN 65 | SecurityGroupName = $NSGName 66 | PublicIpAddressName = $IPName 67 | OpenPorts = $Ports 68 | Credential = $VMCred 69 | } 70 | New-AzVm @VMHT 71 | 72 | 73 | 74 | # 7. Get the VM's External IP address 75 | $VMIP = Get-AzPublicIpAddress -ResourceGroupName $RGname 76 | $VMIP = $VMIP.IpAddress 77 | "VM Public IP Address: [$VMIP]" 78 | 79 | # 8. Connect to the VM 80 | mstsc /v:"$VMIP" 81 | -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.1 - Explore perf counters with Get-Counter.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 13.1 - Using Get-Counter to get performance counters 2 | # 3 | # Run on SRV1 4 | # Uses DC1,DC2,HV1,HV2,SRV1,SRV2 5 | 6 | # 1. Discover performance counter sets on SRV1: 7 | $CounterSets = Get-Counter -ListSet * 8 | $CS1 = 'There are {0} counter sets on [{1}]' 9 | $CS1 -f $CounterSets.count,(hostname) 10 | 11 | # 2. Discover performance counter sets on remote systems 12 | $Machines = 'DC1','DC2','HV1','HV2','SRV1','SRV2' 13 | Foreach ($Machine in $Machines) 14 | { 15 | $RCounters = Get-Counter -ListSet * -ComputerName $Machine 16 | $CS2 = "There are {0} counters on [{1}]" 17 | $CS2 -f $RCounters.Count, $Machine 18 | } 19 | 20 | # 3 List key performance counter sets 21 | Get-Counter -ListSet Processor, Memory, Network*,*Disk | 22 | Sort-Object -Property CounterSetName | 23 | Format-Table -Property CounterSetName 24 | 25 | # 4. Get description of the memory counter set 26 | Get-Counter -ListSet Memory | 27 | Format-Table -Property Name, Description -Wrap 28 | 29 | # 5. Get and display counters in the memory counter set 30 | $CountersMem = (Get-Counter -ListSet Memory).Counter 31 | 'Memory counter set has [{0}] counters:' -f $countersMem.Count 32 | $CountersMem 33 | 34 | # 6. Get and display a sample from each counter in the memory counter set 35 | $Counters = (Get-Counter -ListSet Memory).counter 36 | $FS = '{0,-19} {1,-60} {2,-10}' 37 | $FS -f 'At', 'Counter', 'Value' # Display header row 38 | foreach ($Counter in $Counters) 39 | { 40 | $C = Get-Counter -Counter $Counter 41 | $T = $C.Timestamp # Time 42 | $N = $C.CounterSamples.Path.Trim() # Counter Name 43 | $V = $C.CounterSamples.CookedValue # Value 44 | '{0,-15} {1,-59} {2,-14}' -f $T, $N, $V 45 | } 46 | 47 | # 7. Explore Counter Set types for key perf counters 48 | Get-Counter -ListSet Processor, Memory, Network*, *Disk* | 49 | Select-Object -Property CounterSetName, CounterSetType 50 | 51 | # 8. Explore a local performance counter sample set 52 | $Counter1 = '\Memory\Page Faults/sec' 53 | $PFS = Get-Counter -Counter $Counter1 54 | $PFS 55 | 56 | # 9. Look at remote performance counter sample set on HV1: 57 | $Counter2 = '\\HV1\Memory\Page Faults/sec' 58 | $RPFS = Get-Counter -Counter $Counter1 59 | $RPFS 60 | 61 | 62 | # 10. Look inside a counter sample set 63 | $PFS | Get-Member -MemberType *Property | 64 | Format-Table -Wrap 65 | 66 | # 11. What is inside a local multi-value counter sample 67 | $Counter3 = '\Processor(*)\% Processor Time' 68 | $CPU = Get-Counter -Counter $Counter3 69 | $CPU 70 | 71 | # 12. Vew a multi-value counter sample on HV2 72 | $Counter4 = '\\hv2\Processor(*)\% Processor Time' 73 | $CPU = Get-Counter -Counter $Counter4 74 | $CPU 75 | -------------------------------------------------------------------------------- /Chapter 03 - Deploying Active Directory/3.1 - Installing Active Directory with DNS.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 3.1 - Installing Active Directory with DNS 2 | 3 | # This recipe uses DC1 and DC2 4 | # The recipe starts on DC1, then uses DC2. 5 | # DC1 is initially a stand-alone work group server you convert 6 | # into a DC with DNS. 7 | # Then you convert DC2 (a domain joined server) to a DC and setup DNS there too. 8 | 9 | 10 | ### Part 1 - run on DC1 11 | 12 | # 1. Install the AD Domain Services feature and management tools 13 | Install-WindowsFeature AD-Domain-Services -IncludeManagementTools 14 | 15 | # 2. Install DC1 as forest root server (DC1.Reskit.Org) 16 | $PSSHT = @{ 17 | String = 'Pa$$w0rd' 18 | AsPlainText = $true 19 | Force = $true 20 | } 21 | $PSS = ConvertTo-SecureString @PSSHT 22 | $ADHT = @{ 23 | DomainName = 'Reskit.Org' 24 | SafeModeAdministratorPassword = $PSS 25 | InstallDNS = $true 26 | DomainMode = 'WinThreshold' 27 | ForestMode = 'WinThreshold' 28 | Force = $true 29 | NoRebootOnCompletion = $true 30 | } 31 | Install-ADDSForest @ADHT 32 | 33 | # 3. Restart computer 34 | Restart-Computer -Force 35 | 36 | # 4. After reboot, log back into DC1 as Reskit\Administrator, then 37 | Get-ADRootDSE | 38 | Format-Table -Property dns*, *functionality 39 | 40 | 41 | 42 | ### Part 2 - run on DC2 43 | # Assumes DC1 is now a DC, DC2 is another workgroup server 44 | 45 | # 5. Check DC1 can be resolved, and 46 | # can be reached over 445 and 389 from DC2 47 | Resolve-DnsName -Name DC1.Reskit.Org -Type A 48 | Test-NetConnection -ComputerName DC1.Reskit.Org -Port 445 49 | Test-NetConnection -ComputerName DC1.Reskit.Org -Port 389 50 | 51 | # 6. Add the AD DS features on DC2 52 | $Features = 'AD-Domain-Services', 'DNS','RSAT-DHCP', 'Web-Mgmt-Tools' 53 | Install-WindowsFeature -Name $Features 54 | 55 | # 7. Promote DC2 to be a DC in the Reskit.Org domain 56 | $URK = "administrator@reskit.org" 57 | $PSS = ConvertTo-SecureString -String 'Pa$$w0rd' -AsPlainText -Force 58 | $CredRK = New-Object system.management.automation.PSCredential $URK,$PSS 59 | $IHT =@{ 60 | DomainName = 'Reskit.org' 61 | SafeModeAdministratorPassword = $PSS 62 | SiteName = 'Default-First-Site-Name' 63 | NoRebootOnCompletion = $true 64 | Force = $true 65 | } 66 | Install-ADDSDomainController @IHT -Credential $CredRK 67 | 68 | # 8 Reboot DC2 69 | Restart-Computer -Force 70 | 71 | # 9. After reboot, logon to DC1 and view the forest 72 | Get-AdForest | 73 | Format-Table -Property *master*,globaL*,Domains 74 | 75 | # 10. View details of the domain 76 | Get-ADDomain | 77 | Format-Table -Property DNS*,PDC*,*master,Replica* 78 | 79 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.9 - Configuring VM and storage movement.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.9 - Configuring VM and storage movement 2 | 3 | # 1. View the PSDirect VM on HV1 and verify that it is turned off and not saved 4 | Get-VM -Name PSDirect -Computer HV1 5 | 6 | # 2. Get the VM configuration location 7 | (Get-VM -Name PSDirect).ConfigurationLocation 8 | 9 | # 3. Get Hard Drive locations 10 | Get-VMHardDiskDrive -VMName PSDirect | 11 | Format-Table -Property VMName, ControllerType, Path 12 | 13 | # 4. Move the VM's to the C\PSDirectNew folder: 14 | $MHT = @{ 15 | Name = 'PSDirect' 16 | DestinationStoragePath = 'C:\PSDirectNew' 17 | } 18 | Move-VMStorage @MHT 19 | 20 | # 5. View the configuration details after moving the VM's storage: 21 | (Get-VM -Name PSDirect).ConfigurationLocation 22 | Get-VMHardDiskDrive -VMName PSDirect | 23 | Format-Table -Property VMName, ControllerType, Path 24 | 25 | # 6. Get the VM details for VMs from HV2: 26 | Get-VM -ComputerName HV2 27 | 28 | # 7. Enable VM migration from both HV1 and HV2: 29 | Enable-VMMigration -ComputerName HV1, HV2 30 | 31 | # 8. Configure VM Migration on both hosts: 32 | $SVHT = @{ 33 | UseAnyNetworkForMigration = $true 34 | ComputerName = 'HV1', 'HV2' 35 | VirtualMachineMigrationAuthenticationType = 'Kerberos' 36 | VirtualMachineMigrationPerformanceOption = 'Compression' 37 | } 38 | Set-VMHost @SVHT 39 | 40 | # 9. Move the VM to HV2 41 | $Start = Get-Date 42 | $VMHT = @{ 43 | Name = 'PSDirect' 44 | ComputerName = 'HV1' 45 | DestinationHost = 'HV2' 46 | IncludeStorage = $true 47 | DestinationStoragePath = 'C:\PSDirect' # on HV2 48 | } 49 | Move-VM @VMHT 50 | $Finish = Get-Date 51 | ($Finish - $Start) 52 | 53 | # 10. Display the time taken to migrate 54 | $OS = "Migration took: [{0:n2}] minutes" 55 | ($os -f ($($finish-$start).TotalMinutes)) 56 | 57 | # 11. Check the VMs on HV1 58 | Get-VM -ComputerName HV2 59 | 60 | # 12. Check the VMs on HV2 61 | Get-VM -ComputerName HV2 62 | 63 | # 13. Look at the details of the moved VM 64 | ((Get-VM -Name PSDirect -Computer HV2).ConfigurationLocation) 65 | Get-VMHardDiskDrive -VMName PSDirect -Computer HV2 | 66 | Format-Table -Property VMName, Path 67 | 68 | ### Move it back (not for publication) 69 | 70 | # 14. Move the VM to HV1 71 | $Start = Get-Date 72 | $VMHT2 = @{ 73 | Name = 'PSDirect' 74 | ComputerName = 'HV2' 75 | DestinationHost = 'HV1' 76 | IncludeStorage = $true 77 | DestinationStoragePath = 'C:\vm\vhds\PSDirect' # on HV1 78 | } 79 | Move-VM @VMHT2 80 | $Finish = Get-Date 81 | ($Finish - $Start) 82 | 83 | # 10. Display the time taken to migrate 84 | $OS = "Migration took: [{0:n2}] minutes" 85 | ($os -f ($($finish-$start).TotalMinutes)) 86 | -------------------------------------------------------------------------------- /Chapter 12 - Exploring Azure/Recipe 12.7 - Create and Use VPN.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 12-7 - Create and use Azure VPN 2 | 3 | # 1. Define Variables 4 | $Locname = 'uksouth' # location name 5 | $RgName = 'packt_rg' # resource group name 6 | $GWSubnetName = 'GatewaySubnet' 7 | $GWName = 'pactvpngw' 8 | $GWIPName = 'gwip' 9 | $NetworkName = 'PacktVnet' 10 | $GWIPName = 'gwip' 11 | $VPNClientAddressPool = "172.16.201.0/24" 12 | 13 | # 2. If necessary 14 | Login-AzureRmAccount 15 | 16 | # 3. Create a self signed root ca cert and a user cert 17 | $P2SRootCertFileName = 'C:\PacktCARootCert.cer' 18 | $P2SRootCertName = 'PacktRootCert' 19 | $Mc = 'C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\x64\makecert.exe' 20 | & $Mc -sky exchange -r -n "CN=PACKTCA" -pe -a sha1 -len 2048 -ss Root $P2SRootCertFileName 21 | & $Mc -n "CN=VPNUserCert" -pe -sky exchange -m 12 -ss My -in "PACKTCA" -is root -a sha1 22 | $Cert = New-Object -Typename System.Security.Cryptography.X509Certificates.X509Certificate2 ` 23 | -ArgumentList $P2sRootCertName 24 | $CertBase64 = [system.convert]::ToBase64String($Cert.RawData) 25 | $P2SRootCert = New-AzureRmVpnClientRootCertificate -Name $P2SRootCertName -PublicCertData $CertBase64 26 | 27 | # 4. Create the RMGateway objects 28 | $Vnet = Get-AzureRmVirtualNetwork -Name $NetworkName -ResourceGroupName $RgName 29 | $Subnet = Get-AzureRmVirtualNetworkSubnetConfig -Name $GWSubnetName -VirtualNetwork $Vnet 30 | $PIPHT = @{ 31 | Name = $GWIPName 32 | ResourceGroupName = $RgName 33 | Location = $Locname 34 | AllocationMethod = 'Dynamic' 35 | Tag = "@{Owner = 'PACKT'; Type = 'IP'}" 36 | } 37 | $Pip2 = New-AzureRmPublicIpAddress -@$PIPHT 38 | $IPCHT = @{ 39 | Name = $GWIPName 40 | Subnet = $subnet 41 | PublicIpAddress = $Pip2 42 | } 43 | $IpConf = New-AzureRmVirtualNetworkGatewayIpConfig @IPCHT 44 | 45 | # 5. Create the Gateway 46 | $Start = Get-Date 47 | New-AzureRmVirtualNetworkGateway -Name $GWName -ResourceGroupName $RgName ` 48 | -Location $Locname -IpConfigurations $ipconf ` 49 | -GatewayType Vpn -VpnType RouteBased ` 50 | -EnableBgp $false -GatewaySku Standard ` 51 | -VpnClientAddressPool $VPNClientAddressPool ` 52 | -VpnClientRootCertificates $p2srootcert ` 53 | -Tag @{Owner = 'PACKT'; Type = 'Gateway'} 54 | $Finish = Get-Date 55 | "Creating the gateway took $(($Finish-$Start).totalminutes) minutes" 56 | 57 | 58 | # 6. Get the VPN client package URL 59 | $URHT = @{ 60 | ResourceGroupName = $RGName 61 | VirtualNetworkGatewayName = $GWName 62 | ProcessorArchitecture = 'Amd64' 63 | $Url = $Urls.Split('"')[1] 64 | } 65 | $Urls = Get-AzureRmVpnClientPackage @URHT 66 | 67 | # 7. Get the VPN Package 68 | $wc = New-Object System.Net.WebClient 69 | $wc.DownloadFile($URL, 'C:\PacktVPNClient.EXE') 70 | Get-ChildItem -path C:\PacktVPNClient.EXE 71 | 72 | # 8. Install VPN Package 73 | C:\PacktVPNClient.EXE -------------------------------------------------------------------------------- /Chapter 06 - Deploying Windows Update/Recipe 6.1 - Installing WIndows Server Update Service.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 6.1 - Installing WIndows Server Update Services 2 | # 3 | # Run as administrator on WSUS1 4 | 5 | 6 | # 1. Install the Windows Update feature and tools 7 | $IFHT = @{ 8 | Name = 'UpdateServices' 9 | IncludeManagementTools = $true 10 | } 11 | Install-WindowsFeature @IFHT 12 | 13 | # 2. Determine the features installed on WSUS1 server after installation of WSUW 14 | Get-WindowsFeature | Where-Object Installed 15 | 16 | # 3. Create a folder for WSUS update content 17 | $WSUSDir = 'C:\WSUS' 18 | If (-Not (Test-Path -Path $WSUSDir -ErrorAction SilentlyContinue)) 19 | {New-Item -Path $WSUSDir -ItemType Directory | Out-Null} 20 | 21 | # 4. Perform post-installation configuration using WsusUtil.exe 22 | $CMD ="$env:ProgramFiles\" + "Update Services\Tools\WsusUtil.exe " 23 | & $CMD Postinstall CONTENT_DIR=$WSUSDir 24 | 25 | # 5. View the post installation log file 26 | $LOG = "$env:localappdata\temp\WSUS_Post*.log" 27 | Get-ChildItem -Path $LOG 28 | 29 | # 6. View some websites on this machine, noting the WSUS website 30 | Get-Website -Name ws* | Format-Table -AutoSize 31 | 32 | # 7. View the cmdlets in the UpdateServices module 33 | Get-Command -Module UpdateServices 34 | 35 | # 8. Inspect the TypeName and properties of the object 36 | # created with GetWsusServer 37 | $WSUSServer = Get-WsusServer 38 | $WSUSServer.GetType().Fullname 39 | $WSUSServer | Select-Object -Property * 40 | 41 | # 9. The object is of type UpdateServer in the 42 | # Microsoft.UpdateServices.Internal.BaseApi namespace, and 43 | # is the main object you use to manage WSUS from PowerShell. 44 | ($WSUSServer | Get-Member -MemberType Method).count 45 | $WSUSServer | Get-Member -MemberType Method 46 | 47 | 48 | # 10. View WSUS Configuration 49 | $WSUSServer.GetConfiguration() | 50 | Select-Object -Property SyncFromMicrosoftUpdate,LogFilePath 51 | 52 | # 11. Get product categories after initial install: 53 | $WSUSProducts = Get-WsusProduct -UpdateServer $WSUSServer 54 | $WSUSProducts.Count 55 | $WSUSProducts 56 | 57 | # 12. Display subscription information 58 | $WSUSSubscription = $WSUSServer.GetSubscription() 59 | $WSUSSubscription | Select-Object -Property * | Format-List 60 | 61 | 62 | # 13. Get the latest categories of products available from Microsoft Update 63 | # servers. 64 | $WSUSSubscription.StartSynchronization() 65 | Do { 66 | Write-Output $WSUSSubscription.GetSynchronizationProgress() 67 | Start-Sleep -Seconds 5 68 | } 69 | While ($WSUSSubscription.GetSynchronizationStatus() -ne 70 | 'NotProcessing') 71 | 72 | # 14. Once synchronization is complete, check the results of the synchronization: 73 | $WSUSSubscription.GetLastSynchronizationInfo() 74 | 75 | # 15.Review the categories of the products available after synchronzation: 76 | $WSUSProducts = Get-WsusProduct -UpdateServer $WSUSServer 77 | $WSUSProducts.Count 78 | $WSUSProducts -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Bonus Recipe 1 - Create a VM from existing VHD.ps1: -------------------------------------------------------------------------------- 1 | # create vm from vhdx 2 | 3 | # 1. Create variables 4 | $Locname = 'uksouth' # location name 5 | $RgName = 'packt_rg' # resource group we are using 6 | $SAName = 'packt42sa' # storage account name 7 | $CName = 'vhd' # a blob container 8 | $VHDName = 'server42.vhd' # vhd name 9 | $OP = 'd:\test\windows server 2016.vhdx' 10 | $LP = 'd:\test\ws2016.vhd' # local path to vhdx 11 | 12 | $Cred = Get-Credential thomas_lee@msn.com 13 | $Acct = Login-AzAccount -Credential $cred 14 | 15 | # 2. Convert vhdx to vhd 16 | $s = Get-Date 17 | Convert-VHD –Path $OP -DestinationPath $LP 18 | $e = Get-Date 19 | $e - $s 20 | 21 | # 3. upload 22 | $URL = "https://$SAName.blob.core.windows.net/$Cname/$vhdName" 23 | $s2 = get-date 24 | Add-AzVhd -ResourceGroupName $RgName -Destination $URL -LocalFilePath $LP 25 | $e2 = get-date 26 | $e2-$s2 27 | 28 | 29 | # 4. Create a managed image 30 | $IC = New-AzImageConfig -Location $Locname 31 | $IC = Set-AzImageOsDisk -Image $IC -OsType Windows -OsState Generalized -BlobUri $URL 32 | $Image = New-AzImage -ImageName $imageName -ResourceGroupName $RGName -Image $IC 33 | 34 | # 5, Create the networking resources 35 | $singleSubnet = New-AzVirtualNetworkSubnetConfig -Name $subnetName -AddressPrefix 10.0.0.0/24 36 | $vnet = New-AzVirtualNetwork -Name $vnetName -ResourceGroupName $resourceGroup -Location $location ` 37 | -AddressPrefix 10.0.0.0/16 -Subnet $singleSubnet 38 | $pip = New-AzPublicIpAddress -Name $ipName -ResourceGroupName $resourceGroup -Location $location ` 39 | -AllocationMethod Dynamic 40 | $rdpRule = New-AzNetworkSecurityRuleConfig -Name $ruleName -Description 'Allow RDP' -Access Allow ` 41 | -Protocol Tcp -Direction Inbound -Priority 110 -SourceAddressPrefix Internet -SourcePortRange * ` 42 | -DestinationAddressPrefix * -DestinationPortRange 3389 43 | $nsg = New-AzNetworkSecurityGroup -ResourceGroupName $resourceGroup -Location $location ` 44 | -Name $nsgName -SecurityRules $rdpRule 45 | $nic = New-AzNetworkInterface -Name $nicName -ResourceGroupName $resourceGroup -Location $location ` 46 | -SubnetId $vnet.Subnets[0].Id -PublicIpAddressId $pip.Id -NetworkSecurityGroupId $nsg.Id 47 | $vnet = Get-AzVirtualNetwork -ResourceGroupName $resourceGroup -Name $vnetName 48 | 49 | # Start building the VM configuration 50 | $vm = New-AzVMConfig -VMName $vmName -VMSize $vmSize 51 | 52 | # Set the VM image as source image for the new VM 53 | $vm = Set-AzVMSourceImage -VM $vm -Id $image.Id 54 | 55 | # Finish the VM configuration and add the NIC. 56 | $vm = Set-AzVMOSDisk -VM $vm -DiskSizeInGB $diskSizeGB -CreateOption FromImage -Caching ReadWrite 57 | $vm = Set-AzVMOperatingSystem -VM $vm -Windows -ComputerName $computerName -Credential $cred ` 58 | -ProvisionVMAgent -EnableAutoUpdate 59 | $vm = Add-AzVMNetworkInterface -VM $vm -Id $nic.Id 60 | 61 | # Create the VM 62 | New-AzVM -VM $vm -ResourceGroupName $resourceGroup -Location $location -------------------------------------------------------------------------------- /Chapter 05 - Managing Shared Data/Recipe 5.2 - Creating and securing SMB share.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 5.2 - Creating and securing SMB shares 2 | # 3 | # Run from FS1 4 | 5 | # 0 Just in case 6 | $EAHT = @{Erroraction='SilentlyContinue'} 7 | New-Item -Path c:\Foo -ItemType Directory @EAHT 8 | 9 | # 1. Discover existing shares and access rights 10 | Get-SmbShare -Name * | 11 | Get-SmbShareAccess | 12 | Format-Table -GroupBy Name 13 | 14 | # 2. Share a folder 15 | New-SmbShare -Name Foo -Path C:\Foo 16 | 17 | # 3. Update the share to have a description 18 | $CHT = @{Confirm=$False} 19 | Set-SmbShare -Name Foo -Description 'Foo share for IT' @CHT 20 | 21 | # 4. Set folder enumeration mode 22 | $CHT = @{Confirm = $false} 23 | Set-SMBShare -Name Foo -FolderEnumerationMode AccessBased @CHT 24 | 25 | # 5. Set encryption on for Foo share 26 | Set-SmbShare –Name Foo -EncryptData $true @CHT 27 | 28 | # 6. Remove all access to foo share 29 | $AHT1 = @{ 30 | Name = 'foo' 31 | AccountName = 'Everyone' 32 | Confirm = $false 33 | } 34 | Revoke-SmbShareAccess @AHT1 | Out-Null 35 | 36 | # 7. Add reskit\administrators R/O 37 | $AHT2 = @{ 38 | Name = 'foo' 39 | AccessRight = 'Read' 40 | AccountName = 'Reskit\ADMINISTRATOR' 41 | ConFirm = $false 42 | } 43 | Grant-SmbShareAccess @AHT2 | Out-Null 44 | 45 | # 8. Add system full access 46 | $AHT3 = @{ 47 | Name = 'foo' 48 | AccessRight = 'Full' 49 | AccountName = 'NT Authority\SYSTEM' 50 | Confirm = $False 51 | } 52 | Grant-SmbShareAccess @AHT3 | Out-Null 53 | 54 | # 9. Set Creator/Owner to Full Access 55 | $AHT4 = @{ 56 | Name = 'foo' 57 | AccessRight = 'Full' 58 | AccountName = 'CREATOR OWNER' 59 | Confirm = $False 60 | } 61 | Grant-SmbShareAccess @AHT4 | Out-Null 62 | 63 | # 10. Grant Saves Team read access, SalesAdmins has Full access 64 | $AHT5 = @{ 65 | Name = 'Foo' 66 | AccessRight = 'Read' 67 | AccountName = 'Sales' 68 | Confirm = $false 69 | } 70 | Grant-SmbShareAccess @AHT5 | Out-Null 71 | $AHT6 = @{ 72 | Name = 'Foo' 73 | AccessRight = 'Full' 74 | AccountName = 'SalesAdmins' 75 | Confirm = $false 76 | } 77 | Grant-SmbShareAccess @AHT6 | Out-Null 78 | 79 | # 11. Review share access 80 | Get-SmbShareAccess -Name Foo | 81 | Sort-Object AccessRight 82 | 83 | # 12. Set file ACL to be same as share acl 84 | Set-SmbPathAcl -ShareName 'Foo' 85 | 86 | 87 | # 13. Create a file in c:\foo 88 | 'foo' | Out-File -FilePath C:\Foo\Foo.Txt 89 | 90 | 91 | # 14. Set file ACL to be same as share acl 92 | Set-SmbPathAcl -ShareName 'Foo' 93 | 94 | # 15. View folder ACL using Get-NTFSAccess 95 | Get-NTFSAccess -Path C:\Foo | 96 | Format-Table -AutoSize 97 | 98 | # 16. View file ACL 99 | Get-NTFSAccess -Path C:\Foo\Foo.Txt | 100 | Format-Table -AutoSize 101 | 102 | 103 | 104 | 105 | # reset for testing 106 | 107 | <# reset the shares 108 | Get-smbshare foo | remove-smbshare -Confirm:$false 109 | 110 | #> 111 | -------------------------------------------------------------------------------- /PowerShellCookBook2019/README (PACKT).md: -------------------------------------------------------------------------------- 1 | # Learn Windows Server 2019 2 | 3 | TO DO: Insert a photo of the book cover. 4 | 5 | ## Introduction 6 | 7 | This is the code repository for Administering Windows Server 2019 with PowerShell Cookbook, published by Packt. 8 | This repository is based on the [author's personal GitHub repository](https://github.com/doctordns/PowerShellCookBook2019). 9 | 10 | ** Write, deploy, and maintain your Server 2019 ** 11 | 12 | ## What This Book is About 13 | 14 | ... intro 15 | 16 | This book covers the following: 17 | 18 | TODO: Add list of chapters 19 | 20 | If you feel this book is for you, get your [copy](https://www.amazon.com/dp/1789134323) today! 21 | 22 | ## Instructions and Navigation 23 | 24 | All of the code is organized into folders. 25 | Each folder contains the recipes in a chapter of the book. 26 | 27 | The PowerShell code in each recipe looks like the following: 28 | 29 | ```powerShell 30 | $JG420 = Get-ADUser -Identity 'JerryGarcia' 31 | If ($JG420.enabled) { 32 | "User [$($JG402.SAMACCOUNTNAME)] is enabled 33 | } 34 | ``` 35 | 36 | ## What do you need to follow this book 37 | 38 | As the practical examples involve the use of Windows Server 2019, Windows 10 and Azure, you need access to all of these. 39 | You can obtain the ISO images for WIndow 10 and Windows Server 2019 from the Internet. 40 | aYou can also get a free Azure subscription to test the Azure related recipes. 41 | The book also uses some third party software - details of where to find such tools is contained in the relevant chapter. 42 | 43 | With the following software and hardware list you can run all code files present in the book (Chapter 1-7). 44 | 45 | ### Software and Hardware List 46 | 47 | | Chapter | Software required | OS required | 48 | | -------- | ------------------------------------ | ----------------------------------- | 49 | | 1-7 | Any text editor, Visual Studio Code | Computer with Windows, Linux or macOS | 50 | 51 | We also provide a PDF file that has color images of the screenshots/diagrams used in this book. [Click here to download it](https://www.packtpub.com/sites/default/files/downloads/LearnCloudFormation_ColorImages.pdf). 52 | 53 | ## Related Books 54 | 55 | This is a list of books you may find helpful in your PowerShell journey. 56 | 57 | 1. Month of lunches by Don Jones 58 | 59 | 2. PowerShell Cook Book by Lee Holmes 60 | 61 | ## Get to Know the Author 62 | 63 | **Thomas Lee** is a consultant, trainer and author. 64 | He has more than 50 years of experience in various software and hardware development projects for various companies across the globe. 65 | 66 | I'll say more about him in due course! 67 | 68 | He's a wonderful guy. Really!! 69 | 70 | ## Other book by the author 71 | 72 | * [title](https:/) 73 | 74 | ### Suggestions and Feedback 75 | 76 | [Click here](https://docs.google.com/forms/d/e/1FAIpQLSdy7dATC6QmEL81FIUuymZ0Wy9vH1jHkvpY57OiMeKGqib_Ow/viewform) if you have any feedback or suggestions. 77 | 78 | If you have issues with the specific recipes, file an issue at: 79 | [The recipe Git Hub Repository](https://github.com/doctordns/PowerShellCookBook2019/issues) 80 | -------------------------------------------------------------------------------- /Chapter 06 - Deploying Windows Update/Recipe 6.2 - Configuring WSUS Update synchronization.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 3-2 - Configuring WUS update synchronization 2 | 3 | # 1. Locate the versions of WIndows Server supported by Windows Update 4 | Get-WsusProduct | 5 | Where-Object -FilterScript {$_.product.title -match 6 | '^Windows Server'} 7 | 8 | # 2. And get updat titles for Windows 10 9 | Get-WsusProduct -TitleIncludes 'Windows 10' 10 | 11 | # 3. Create and view a list of software product titles to include 12 | $CHP = 13 | (Get-WsusProduct | 14 | Where-Object -FilterScript {$_.product.title -match 15 | '^Windows Server'}).Product.Title 16 | $CHP += @('Microsoft SQL Server 2016','Windows 10') 17 | $CHP 18 | 19 | 20 | # 4. Assign the desired products to include in Windows Update: 21 | Get-WsusProduct | 22 | Where-Object {$PSItem.Product.Title -in $CHP} | 23 | Set-WsusProduct 24 | 25 | # 5. Updates are classified into distinct categories; a view which classifications of 26 | # updates are available: 27 | Get-WsusClassification 28 | 29 | # 6. Build a list of desired update classifications to make available on your WSUS 30 | # server and view the list: 31 | $CCL = @('Critical Updates', 32 | 'Definition Updates', 33 | 'Security Updates', 34 | 'Service Packs', 35 | 'Update Rollups', 36 | 'Updates') 37 | 38 | # 7. Set the list of desired update classifications in WSUS: 39 | Get-WsusClassification | 40 | Where-Object {$_.Classification.Title -in 41 | $CCL} | 42 | Set-WsusClassification 43 | 44 | # 8. Get Synchronization details 45 | $WSUSServer = Get-WsusServer 46 | $WSUSSubscription = $WSUSServer.GetSubscription() 47 | 48 | 49 | 50 | # 9. Start synchronizing available updates 51 | $WSUSSubscription.StartSynchronization() 52 | 53 | # 10 loop and wait for syncronization to complete 54 | $IntervalSeconds = 5 55 | $NP = 'NotProcessing' 56 | Do { 57 | $WSUSSubscription.GetSynchronizationProgress() 58 | Start-Sleep -Seconds $IntervalSeconds 59 | } While ($WSUSSubscription.GetSynchronizationStatus() -eq $NP) 60 | 61 | 62 | # 11. Synchronize the updates which can take a long while to compelete. 63 | $IntervalSeconds = 1 64 | $NP = 'NotProessing' 65 | # Wait for synchronizing to start 66 | Do { 67 | Write-Output $WSUSSubscription.GetSynchronizationProgress() 68 | Start-Sleep -Seconds $IntervalSeconds 69 | } 70 | While ($WSUSSubscription.GetSynchronizationStatus() -eq $NP) 71 | # Wait for all phases of process to end 72 | Do { 73 | Write-Output $WSUSSubscription.GetSynchronizationProgress() 74 | Start-Sleep -Seconds $IntervalSeconds 75 | } 76 | Until ($WSUSSubscription.GetSynchronizationStatus() -eq $NP) 77 | 78 | # 12. When the final loop is complete, check the results of the 79 | # synchronization: 80 | $WSUSSubscription.GetLastSynchronizationInfo() 81 | 82 | # 13. Configure automatic synchronization to run once per day: 83 | $WSUSSubscription = $WSUSServer.GetSubscription() 84 | $WSUSSubscription.SynchronizeAutomatically = $true 85 | $WSUSSubscription.NumberOfSynchronizationsPerDay = 1 86 | $WSUSSubscription.Save() -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.4 - Using VM Groups.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.4 - Using VM Groups 2 | # 3 | # Run on HV2 4 | 5 | 6 | # 0. Create VMs on HV2 7 | # Use the script: Create-HV2VMs.ps1 8 | 9 | # 1. Setup Hyper-V VM groups and display group 10 | $VHGHT1 = @{ 11 | Name = 'SQLAccVMG' 12 | GroupType = 'VMCollectionType' 13 | } 14 | $VMGroupACC = New-VMGroup @VHGHT1 15 | $VHGHT2 = @{ 16 | Name = 'SQLMfgVMG' 17 | GroupType = 'VMCollectionType' 18 | } 19 | $VMGroupMFG = New-VMGroup @VHGHT2 20 | 21 | # 2. Create arrays of group member VM Names 22 | $ACCVMs = 'SQLAcct1', 'SQLAcct2','SQLAcct3' 23 | $MFGVms = 'SQLMfg1', 'SQLMfg2' 24 | 25 | # 3. Add members to the Accounting SQL VMgroup 26 | Foreach ($Server in $ACCVMs) { 27 | $VM = Get-VM -Name $Server 28 | Add-VMGroupMember -Name SQLAccVMG -VM $VM 29 | } 30 | 31 | # 4. Add memvers to the Manufacturing SQL VM Group 32 | Foreach ($Server in $MfgVMs) { 33 | $VM = Get-VM -Name $Server 34 | Add-VMGroupMember -Name SQLMfgVMG -VM $VM 35 | } 36 | 37 | # 5 Create a management collection VMGroup 38 | $VMGHT = @{ 39 | Name = 'VMMGSQL' 40 | GroupType = 'ManagementCollectionType' 41 | } 42 | $VMMGSQL = New-VMGroup @VMGHT 43 | 44 | # 6. Add the two VMCollectionType groups to the VMManagement group 45 | Add-VMGroupMember -Name VMMGSQL -VMGroupMember $VMGroupACC, 46 | $VMGroupMFG 47 | 48 | # 7. Set FormatEnumerationLimit to a higher value, then view the VMGroups 49 | $FormatEnumerationLimit = 99 50 | Get-VMGroup | 51 | Format-Table -Property Name, GroupType, VMGroupMembers, 52 | VMMembers 53 | 54 | # 8. Stop all the SQL VMs 55 | Foreach ($VM in ((Get-VMGroup VMMGSQL).VMGroupMembers.vmmembers)) { 56 | Stop-VM -Name $vm.name -WarningAction SilentlyContinue 57 | } 58 | 59 | # 9. Set CPU count in ALL SQL VMs to 4 60 | Foreach ($VM in ((Get-VMGroup VMMGSQL).VMGroupMembers.VMMembers)) { 61 | Set-VMProcessor -VMName $VM.name -Count 4 62 | } 63 | 64 | # 10. Set Accounting SQL VMs to have 6 processors 65 | Foreach ($VM in ((Get-VMGroup SQLAccVMG).VMMembers)) { 66 | Set-VMProcessor -VMName $VM.name -Count 6 67 | } 68 | 69 | # 11. Check Processor counts for all VMs sorted by CPU Count: 70 | $VMS = (Get-VMGroup -Name VMMGSQL).VMGroupMembers.VMMembers 71 | Get-VMProcessor -VMName $VMS.name | 72 | Sort-Object -Property Count -Descending | 73 | Format-Table -Property VMName, Count 74 | 75 | # 12. Remove VMs from VM Groups 76 | $VMs = (Get-VMGroup -Name SQLAccVMG).VMMEMBERS 77 | Foreach ($VM in $VMS) { 78 | $X = Get-VM -vmname $VM.name 79 | Remove-VMGroupMember -Name SQLAccVMG -VM $x 80 | } 81 | $VMs = (Get-VMGroup -Name SQLMFGVMG).VMMEMBERS 82 | Foreach ($VM in $VMS) { 83 | $X = Get-VM -vmname $VM.name 84 | Remove-VMGroupMember -Name SQLmfgvMG -VM $x 85 | } 86 | 87 | # 13. Remove VMGrouwps from VMManagementGroups 88 | $VMGS = (Get-VMGroup -Name VMMGSQL).VMMembers 89 | Foreach ($VMG in $VMGS) { 90 | $X = Get-VMGroup -vmname $VMG.name 91 | Remove-VMGroupMember -Name VMMGSQL -VMGroupName $x 92 | } 93 | # 14. Remove all the VMGroups 94 | Remove-VMGroup SQLACCVMG -force 95 | Remove-VMGroup SQLMFGVMG -force 96 | Remove-VMGroup VMMGSQL -Force -------------------------------------------------------------------------------- /Chapter 13 - Monitoring Performance and Usage/Recipe 13.8 - Creating a Hyper-V Status Report.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11-12 Creating a Hyper-V Status Report 2 | 3 | # 1. Create a basic report object hash table 4 | $ReportHT = [Ordered] @{} 5 | 6 | # 2. Get the host details and add them to the Report object 7 | $HostDetails = Get-CimInstance -ClassName Win32_ComputerSystem 8 | $ReportHT.HostName = $HostDetails.Name 9 | $ReportHT.Maker = $HostDetails.Manufacturer 10 | $ReportHT.Model = $HostDetails.Model 11 | 12 | # 3. Add the PowerShell version information 13 | $ReportHT.PSVersion = $PSVersionTable.PSVersion.tostring() 14 | # Add OS information: 15 | $OS = Get-CimInstance -Class Win32_OperatingSystem 16 | $ReportHT.OSEdition = $OS.Caption 17 | $ReportHT.OSArch = $OS.OSArchitecture 18 | $ReportHT.OSLang = $OS.OSLanguage 19 | $ReportHT.LastBootTime = $os.LastBootUpTime 20 | $Now = Get-Date 21 | $UTD = [float] ("{0:n3}" -f (($Now -$OS.LastBootUpTime).Totaldays)) 22 | $ReportHT.UpTimeDays = $UTD 23 | 24 | # 4. Add a count of processors in the host 25 | $PHT = @{ 26 | ClassName = 'MSvm_Processor' 27 | Namespace = 'root/virtualization/v2' 28 | } 29 | $Proc = Get-CimInstance @PHT 30 | $ReportHT.CPUCount = ($Proc | 31 | Where-Object elementname -Match 'Logical Processor').COUNT 32 | 33 | # 5. Add the current host CPU usage 34 | $Cname = '\\.\processor(_total)\% processor time' 35 | $CPU = Get-Counter -Counter $Cname 36 | $ReportHT.HostCPUUsage = $CPU.CounterSamples.CookedValue 37 | 38 | # 6. Add the total host physical memory: 39 | $Memory = Get-Ciminstance -Class Win32_ComputerSystem 40 | $HostMemory = [float] ( "{0:n2}" -f ($Memory.TotalPhysicalMemory/1GB)) 41 | $ReportHT.HostMemoryGB = $HostMemory 42 | 43 | # 7. Add the memory allocated to VMs: 44 | $Sum = 0 45 | Get-VM | Foreach-Object {$sum += $_.MemoryAssigned + $Total} 46 | $Sum = [float] ( "{0:N2}" -f ($Sum/1gb) ) 47 | $ReportHT.AllocatedMemoryGB = $Sum 48 | 49 | # 8. Create the host report object: 50 | $Reportobj = New-Object -TypeName PSObject -Property $ReportHT 51 | 52 | # 9. Create report Header 53 | $Report = "Hyper-V Report for: $(hostname)`n" 54 | $Report += "At: [$(Get-Date)]" 55 | 56 | 57 | # 10 Add report object to report: 58 | $Report += $Reportobj | Out-String 59 | 60 | # 11. Get VM details on the local VM host and create a container array for individual 61 | # VM related objects: 62 | $VMs = Get-VM -Name * 63 | $VMHT = @() 64 | 65 | # 12. Get VM details for each VM into an object added to the hash table container: 66 | Foreach ($VM in $VMs) { 67 | # Create VM Report hash table 68 | $VMReport = [ordered] @{} 69 | # Add VM's Name 70 | $VMReport.VMName = $VM.VMName 71 | # Add Status 72 | $VMReport.Status = $VM.Status 73 | # Add Uptime 74 | $VMReport.Uptime = $VM.Uptime 75 | # Add VM CPU 76 | $VMReport.VMCPU = $VM.CPUProcessorCount 77 | # Replication Mode/Status 78 | $VMReport.ReplMode = $VM.ReplicationMode 79 | $VMReport.ReplState = $Vm.ReplicationState 80 | 81 | # Create object from Hash table, add to array 82 | $VMR = New-Object -TypeName PSObject -Property $VMReport 83 | $VMHT += $VMR 84 | } 85 | 86 | # 123 Finish creating the report 87 | $Report += $VMHT | Format-Table | Out-String 88 | 89 | # 13. Display the report: 90 | $Report 91 | -------------------------------------------------------------------------------- /Chapter 12 - Exploring Azure/Recipe 12.3 - Explore Storage Account.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 12-3 Explore Azure Storage Account 2 | 3 | # Run from CL1 4 | 5 | # 1. Define key variables 6 | $Locname = 'uksouth' # location name 7 | $RgName = 'packt_rg' # resource group we are using 8 | $SAName = 'packt42sa' # storage account name 9 | $CName = 'packtcontainer' # a blob container name 10 | $CName2 = 'packtcontainer2' # a second blob container name 11 | 12 | # 2. Login to your Azure Account and ensure the RG and SA is created. 13 | $CredAz = Get-Credential 14 | $Account = Login-AzAccount -Credential $CredAz 15 | 16 | # 3. Ensure the RG and SA is created. 17 | $RGHT = @{ 18 | Name = $RgName 19 | ErrorAction = 'SilentlyContinue' 20 | } 21 | $RG = Get-AzResourceGroup @RGHT 22 | if (-not $RG) { 23 | $RGTag = [Ordered] @{Publisher='Packt'} 24 | $RGTag += @{Author='Thomas Lee'} 25 | $RGHT2 = @{ 26 | Name = $RgName 27 | Location = $Locname 28 | Tag = $RGTag 29 | } 30 | $RG = New-AzResourceGroup @RGHT2 31 | "RG $RgName created" 32 | } 33 | $SAHT = @{ 34 | Name = $SAName 35 | ResourceGroupName = $RgName 36 | ErrorAction = 'SilentlyContinue' 37 | } 38 | $SA = Get-AzStorageAccount @SAHT 39 | if (-not $SA) { 40 | $SATag = [Ordered] @{Publisher = 'Packt'} 41 | $SATag += @{Author = 'Thomas Lee'} 42 | $SAHT = @{ 43 | Name = $SAName 44 | ResourceGroupName = $RgName 45 | Location = $Locname 46 | Tag = $SATag 47 | SkuName = 'Standard_LRS' 48 | } 49 | $SA = New-AzStorageAccount @SAHT 50 | "SA $SAName created" 51 | } 52 | 53 | # 4. Get and display the storage account key 54 | $SAKHT = @{ 55 | Name = $SAName 56 | ResourceGroupName = $RgName 57 | } 58 | $Sak = Get-AzStorageAccountKey @SAKHT 59 | $Sak 60 | 61 | # 5. Extract the first key's 'password' 62 | $Key = ($Sak | Select-Object -First 1).Value 63 | 64 | # 6. Get the Storage Account context which encapsulates credentials 65 | # for the storage account) 66 | $SCHT = @{ 67 | StorageAccountName = $SAName 68 | StorageAccountKey = $Key 69 | } 70 | $SACon = New-AzStorageContext @SCHT 71 | $SACon 72 | 73 | # 7. Create 2 blob containers 74 | $CHT = @{ 75 | Context = $SACon 76 | Permission = ‘Blob’ 77 | } 78 | New-AzStorageContainer -Name $CName @CHT 79 | New-AzStorageContainer -Name $CName2 @CHT 80 | 81 | # 8. View blob containers 82 | Get-AzStorageContainer -Context $SACon | 83 | Select-Object -ExpandProperty CloudBlobContainer 84 | 85 | 86 | # 9. Create a blob 87 | 'This is a small Azure blob!!' | Out-File .\azurefile.txt 88 | $BHT = @{ 89 | Context = $SACon 90 | File = '.\azurefile.txt' 91 | Container = $CName 92 | } 93 | $Blob = Set-AzStorageBlobContent @BHT 94 | $Blob 95 | 96 | # 10. Construct and display the blob name 97 | $BlobUrl = "$($Blob.Context.BlobEndPoint)$CName/$($Blob.name)" 98 | $BlobUrl 99 | 100 | # 11. view the URL via IE 101 | $IE = New-Object -ComObject InterNetExplorer.Application 102 | $IE.Navigate2($BlobUrl) 103 | $IE.Visible = $true -------------------------------------------------------------------------------- /Chapter 01 - Establishing a PowerShell Administrative Environment/1.3 - Exploring PowerShellGet+PSGallery.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 1.3 - Exploring PowerShellGet 2 | # This recipe looks at what you can get with the tools in the PowerShellGet module 3 | # Run on CL1 and uses DC1, SRV1 4 | # Run as administrator 5 | 6 | # 0. Before you use this recipe, ensure the NuGet provider has been installed: 7 | Install-PackageProvider -Name NuGet -ForceBootstrap 8 | 9 | 10 | # 1. Review the commands available in the PowerShellGet module: 11 | Get-Command -Module PowerShellGet 12 | 13 | 14 | # 2. View the NuGet PackageProvider version: 15 | Get-PackageProvider -Name NuGet | 16 | Select-Object -Property Version 17 | 18 | # 3. View the current version of PowerShellGet 19 | Get-Module -Name PowerShellGet -ListAvailable 20 | 21 | # 4. Install PowerShellGet: 22 | Install-Module -Name PowerShellGet -Force 23 | 24 | # 5. Check the version of PowerShellGet: 25 | Get-Module -Name PowerShellGet -ListAvailable 26 | 27 | # 6. View the default PSGallery repository for PowerShellGet: 28 | Get-PSRepository 29 | 30 | # 7. Review the package providers in the PSGallery repository: 31 | Find-PackageProvider -Source PSGallery | 32 | Select-Object -Property Name, Summary | 33 | Format-Table -Wrap -autosize 34 | 35 | # 8. Use the Get-Command cmdlet to find Find-* cmdlets in PowerShellGet: 36 | Get-Command -Module PowerShellGet -Verb Find 37 | 38 | # 9. Request all the commands in the PowerShellGet module 39 | # and display the count: 40 | $Commands = Find-Command -Module PowerShellGet 41 | $CommandCount = $Commands.Count 42 | 43 | # 10. Request all the available modules in the PowerShell Gallery 44 | $Modules = Find-Module -Name * 45 | $ModuleCount=$Modules.Count 46 | 47 | # 11. Get DSC resources available in PSGallery 48 | $DSCResources = Find-DSCResource 49 | $DSCResourcesCount = $DSCResources.Count 50 | 51 | # 12. Get DSC resources available in PSGallery 52 | "$CommandCount commands available in PowerShellGet" 53 | "$ModuleCount Modules available in the PowerShell Gallery" 54 | "$DSCResourcesCount DSCResources available in PowerShell Gallery" 55 | 56 | 57 | # 13. Install the TreeSize module, as an example, or choose your own. As this is a 58 | # public repository, Windows does not trust it by default, so you must approve the 59 | # installation: 60 | Install-Module -Name TreeSize -Force 61 | 62 | # 14. Review and test the commands in the module: 63 | Get-Command -Module TreeSize 64 | Get-TreeSize -Path C:\Windows\System32\Drivers -Depth 1 65 | 66 | # 15. Remove the module: 67 | Uninstall-Module -Name TreeSize 68 | 69 | # 16. Create a download folder: 70 | $NIHT = @{ 71 | ItemType = 'Directory' 72 | Path = "$env:HOMEDRIVE\DownloadedModules" 73 | } 74 | New-Item @NIHT | Out-Null 75 | 76 | # 17. Download the module and save it to the folder 77 | $Path = "$env:HOMEDRIVE\DownloadedModules" 78 | Save-Module -Name TreeSize -Path $Path 79 | Get-ChildItem -Path $Path -Recurse | format-Table Fullname 80 | 81 | # 18. Import the treesize module: 82 | $ModuleFolder = "$env:HOMEDRIVE\downloadedModules\TreeSize" 83 | Get-ChildItem -Path $ModuleFolder -Filter *.psm1 -Recurse | 84 | Select-Object -ExpandProperty FullName -First 1 | 85 | Import-Module -Verbose 86 | -------------------------------------------------------------------------------- /Chapter 10 - Implementing Desired State Configuration/Recipe 10.1 -Using DSC and built-in resources.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 10.1 - Using DSC and built-in resources 2 | # 3 | # Run on SRV1 4 | 5 | # 0. Create initial documents for Reskit application 6 | # Also share the application on DC1 7 | # create folders/share 8 | $SB = { 9 | New-Item C:\ReskitApp -ItemType Directory 10 | New-SMBShare -Name ReskitApp -Path C:\ReskitApp 11 | } 12 | Invoke-Command -ComputerName DC1 -ScriptBlock $SB | 13 | Out-Null 14 | # create index.htm 15 | $HP = '\\dc1.reskit.org\c$\reskitapp\Index.htm' 16 | $Index = @" 17 | 18 | 19 | Main Page - ReskitApp Application 20 |

21 | HOME PAGE FOR RESKITAPP APPLICATION

22 | This is the root page of the RESKITAPP application 23 |

24 | Pushed via DSC



25 | 26 | Click to View Page 2 27 |
28 |

29 | "@ 30 | $Index | 31 | Out-File -FilePath $HP -Force 32 | # create page2.htm 33 | $P2 = '\\DC1.Reskit.Org\C$\Reskitapp\Page2.htm' 34 | $Page2 = @" 35 | 36 | 37 | ReskitApp Application - Page 2 38 |

39 | Page 2 For the ReskitApp Web Application

40 | 41 | Click to Go Home 42 |
43 | "@ 44 | $Page2 | 45 | Out-File -FilePath $P2 -Force 46 | 47 | #### Recipe begins here 48 | 49 | # 1. Discover DSC resources on SRV1 50 | Get-DscResource | 51 | Format-Table -Property Name, ModuleName, Version 52 | 53 | # 2. Look at File Resource 54 | Get-DscResource -Name File | 55 | Format-List -Property * 56 | 57 | # 3 Get DSC Resource Syntax 58 | Get-DscResource -Name File -Syntax 59 | 60 | # 4. Create/compile a configuration block 61 | Configuration PrepareSRV2 { 62 | Import-DscResource –ModuleName 'PSDesiredStateConfiguration' 63 | Node SRV2 64 | { 65 | File BaseFiles 66 | { 67 | DestinationPath = 'C:\ReskitApp\' 68 | SourcePath = '\\DC1\ReskitApp\' 69 | MatchSource = $true 70 | Ensure = 'Present' 71 | Recurse = $True 72 | } 73 | } 74 | } 75 | 76 | # 5. View configuration function 77 | Get-Item -Path Function:\PrepareSRV2 78 | 79 | # 6. Create output folder for DSC 80 | $Conf = { 81 | $EASC = @{ErrorAction = 'SilentlyContinue'} 82 | New-Item -Path C:\ReskitApp -ItemType Directory @EASC 83 | } 84 | Invoke-command -ComputerName SRV2 -ScriptBlock $Conf | 85 | Out-Null 86 | 87 | # 7. Run function to produce MOF file 88 | PrepareSRV2 -OutputPath C:\DSC 89 | 90 | # 8. View MOF File 91 | Get-Content -Path C:\DSC\SRV2.mof 92 | 93 | # 9. Make it so Mr Riker 94 | Start-DscConfiguration -Path C:\DSC -Wait -Verbose 95 | 96 | # 10. Observe results 97 | Get-ChildItem -Path '\\SRV2\C$\ReskitApp' 98 | 99 | # 11. Induce configuration drift: 100 | Remove-Item -Path \\SRV2\C$\ReskitApp\Index.htm 101 | 102 | # 12. Fix configuration drift 103 | Start-DscConfiguration -Path C:\DSC\ -Wait -Verbose 104 | 105 | # 13. What happens if NO config drift? 106 | Start-DscConfiguration -Path C:\DSC\ -Wait -Verbose -------------------------------------------------------------------------------- /Chapter 09 - Managing Windows Internet Information Server/Recipe 9.9 - Managing and monitoring NLB.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 9.9 - Managing and monitoring network load balancing 2 | # 3 | # Uses NLB1, 2 - run on NLB1 4 | # end of recipe uses DC1 5 | 6 | 7 | # 1. Install web-server (and .NET 3.5) feature NLB1, NLB2: 8 | $IHT1 = @{ 9 | Name = 'Web-Server' 10 | IncludeManagementTools = $True 11 | IncludeAllSubFeature = $True 12 | Source = 'D:\sources\sxs' 13 | } 14 | Install-WindowsFeature @IHT1 -ComputerName NLB1 15 | Install-WindowsFeature @IHT1 -ComputerName NLB2 16 | 17 | 18 | # 2. And add NLB to NLB1, NLB2 19 | $IHT2 = @{ 20 | Name = 'NLB' 21 | IncludeManagementTools = $True 22 | IncludeAllSubFeature = $True 23 | } 24 | Install-WindowsFeature @IHT -ComputerName NLB1 | Out-Null 25 | Install-WindowsFeature @IHT -ComputerName NLB2 | Out-Null 26 | 27 | 28 | # 3. Confirm NLB and Web-Server feats are loaded on both systems: 29 | $SB = { 30 | Get-WindowsFeature Web-Server, NLB 31 | } 32 | Invoke-Command -ScriptBlock $SB -ComputerName NLB1, NLB2 | 33 | Format-table -Property DisplayName,PSComputername,Installstate 34 | 35 | # 4. Create the NLB cluster, initially on NLB1: 36 | $NLBHT1 = @{ 37 | InterFaceName = 'Ethernet' 38 | ClusterName = 'ReskitNLB' 39 | ClusterPrimaryIP = '10.10.10.55' 40 | SubnetMask = '255.255.255.0' 41 | OperationMode = 'Multicast' 42 | } 43 | New-NlbCluster @NLBHT1 44 | 45 | # 5. Add NLB2 to the ReskitNLB cluster: 46 | $NLBHT2 = @{ 47 | NewNodeName = 'NLB2.Reskit.Org' 48 | NewNodeInterface = 'Ethernet' 49 | InterfaceName = 'Ethernet' 50 | } 51 | Add-NlbClusterNode @NLBHT2 52 | 53 | # 6. Create a network firewall rule: 54 | $SB = { 55 | $NFTHT =@{ 56 | DisplayGroup = 'File and Printer Sharing' 57 | Enabled = 'True' 58 | } 59 | Set-NetFirewallRule @NFTHT 60 | } 61 | Invoke-Command -ScriptBlock $SB -ComputerName NLB1 62 | Invoke-Command -ScriptBlock $SB -ComputerName NLB2 63 | 64 | 65 | # 7. Create a default document—differently on each machine: 66 | 'NLB Cluster: Hosted on NLB1' | 67 | Out-File -FilePath C:\inetpub\wwwroot\index.html 68 | 'NLB Cluster: Greetings from NLB2' | 69 | Out-File -FilePath \\nlb2\c$\inetpub\wwwroot\index.html 70 | 71 | # 8. check VIP 72 | Get-NlbClusterVip 73 | 74 | # 9. Add a DNS A record for the cluster: 75 | $SB = { 76 | $NAHT = @{ 77 | Name = 'ReskitNLB' 78 | IPv4Address = '10.10.10.55' 79 | ZoneName = 'Reskit.Org' 80 | } 81 | Add-DnsServerResourceRecordA @NAHT 82 | } 83 | Invoke-Command -ComputerName DC1 -ScriptBlock $SB 84 | 85 | # DO REMAINDER OF THIS RECIPE FROM DC1 86 | 87 | # 10. view the cluster node details From DC1 88 | Get-NlbClusterNode -HostName NLB1.Reskit.Org 89 | 90 | # 11. View the NLB site from DC1 91 | Start-Process 'HTTP://ReskitNLB.Reskit.Org' 92 | 93 | # 12. Stop one node (the one that responded in step 10): 94 | Stop-NlbClusterNode -HostName NLB1 95 | Clear-DnsClientCache 96 | 97 | # 13. view the cluster node details from NLB1 98 | Get-NlbClusterNode -HostName NLB1 99 | 100 | # 14. Then view the site again (from DC1): 101 | Start-Process 'HTTP://ReskitNLB.Reskit.Org' 102 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.10 - Configuring VM replication.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.10 - Configuring VM replication 2 | 3 | # 1. Configure HV1 and HV2 to be trusted for delegation in AD on DC1 4 | $Sb1 = { 5 | Set-ADComputer -Identity HV1 -TrustedForDelegation $True 6 | } 7 | Invoke-Command -ComputerName DC1 -ScriptBlock $Sb1 8 | $Sb2 = { 9 | Set-ADComputer -Identity HV2 -TrustedForDelegation $True} 10 | Invoke-Command -ComputerName DC1 -ScriptBlock $Sb2 11 | 12 | 13 | # 2. Reboot the HV1 and HV2: 14 | Restart-Computer -ComputerName HV1 -Force 15 | Restart-Computer -ComputerName HV2 -Force 16 | 17 | # 3. Once both systems are restarted, logon back to HV2, 18 | # set up both servers as a replication server 19 | $VMRHT = @{ 20 | ReplicationEnabled = $true 21 | AllowedAuthenticationType = 'Kerberos' 22 | KerberosAuthenticationPort = 42000 23 | DefaultStorageLocation = 'C:\Replicas' 24 | ReplicationAllowedFromAnyServer = $true 25 | ComputerName = 'HV1', 'HV2' 26 | } 27 | Set-VMReplicationServer @VMRHT 28 | 29 | # 4. Enable PSDirect on HV2 to be a replica source 30 | $VMRHT = @{ 31 | VMName = 'PSDirect' 32 | Computer = 'HV2' 33 | ReplicaServerName = 'HV1' 34 | ReplicaServerPort = 42000 35 | AuthenticationType = 'Kerberos' 36 | CompressionEnabled = $true 37 | RecoveryHistory = 5 38 | } 39 | Enable-VMReplication @VMRHT 40 | 41 | # 5. View the replication status of HV2 42 | Get-VMReplicationServer -ComputerName HV2 43 | 44 | # 6. Check PSDIrect on HV2: 45 | Get-VM -ComputerName HV2 -VMName PSDirect 46 | 47 | # 7. Start the initial replication 48 | Start-VMInitialReplication -VMName PSDirect -ComputerName HV2 49 | 50 | # 8. Examine the initial replication state on HV1 just after 51 | # you start the initial replication 52 | Measure-VMReplication -ComputerName HV2 53 | 54 | # 9. Wait for replication to finish, then examine the 55 | # replication status on HV1 56 | Measure-VMReplication -ComputerName HV2 57 | 58 | # 10. Test PSDirect failover to HV1 59 | $SB = { 60 | $VM = Start-VMFailover -AsTest -VMName PSDirect -Confirm:$false 61 | Start-VM $VM 62 | } 63 | Invoke-Command -ComputerName HV1 -ScriptBlock $SB 64 | 65 | # 11. View the status of VMs on HV2: 66 | Get-VM -ComputerName HV1 67 | 68 | # 12. Stop the failover test 69 | $SB = { 70 | Stop-VMFailover -VMName PSDirect 71 | } 72 | Invoke-Command -ComputerName HV1 -ScriptBlock $SB 73 | 74 | # 13. View the status of VMs on HV1 and HV2 after failover stopped 75 | Get-VM -ComputerName HV1 76 | 77 | Get-VM -ComputerName HV2 78 | 79 | # 14. Stop VM1 on HV2 prior to performing a planned failover 80 | Stop-VM PSDirect -ComputerName HV2 81 | 82 | # 15. Start VM failover from H1 83 | Start-VMFailover -VMName PSDirect -ComputerName HV1 -Confirm:$false 84 | 85 | #16. Complete the failover 86 | $CHT = @{ 87 | VMName = 'PSDIrect' 88 | ComputerName = 'HV1' 89 | Confirm = $false 90 | } 91 | Complete-VMFailover @CHT 92 | 93 | # 17. Start the replicated VM on HV1 94 | Start-VM -VMname PSDirect -ComputerName HV1 95 | 96 | # 18. See VMs on HV1 and HV2 after the planned failover 97 | Get-VM -ComputerName HV1 98 | Get-VM -ComputerName HV2 99 | 100 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.11 - Managing VM Checkpoints.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11-10 - Managing VM Checkpoints 2 | 3 | # 1. Create credentials for PSDirect 4 | $RKAn = 'Wolf\Administrator' 5 | $PS = 'Pa$$w0rd' 6 | $RKP = ConvertTo-SecureString -String $PS -AsPlainText -Force 7 | $T = 'System.Management.Automation.PSCredential' 8 | $RKCred = New-Object -TypeName $T -ArgumentList $RKAn,$RKP 9 | 10 | # 2. Look at C: in PSDirect before we start 11 | $SB = { Get-ChildItem -Path C:\ } 12 | $ICHT = @{ 13 | VMName = 'PSDirect' 14 | ScriptBlock = $SB 15 | Credential = $RKCred 16 | } 17 | Invoke-Command @ICHT 18 | 19 | # 3. Create a snapshot of PSDirect1 on HV1: 20 | $CPHT = @{ 21 | VMName = 'PSDirect' 22 | ComputerName = 'HV1' 23 | SnapshotName = 'Snapshot1' 24 | } 25 | Checkpoint-VM @CPHT 26 | 27 | # 4. Look at the files created to support the checkpoints 28 | $Parent = Split-Path -Parent (Get-VM -Name PSdirect | 29 | Select-Object -ExpandProperty HardDrives).Path | 30 | Select -First 1 31 | Get-ChildItem -Path $Parent 32 | 33 | # 5. Create some content in a file on PSDIrect and display it 34 | $SB = { 35 | $FileName1 = 'C:\File_After_Checkpoint_1' 36 | Get-Date | Out-File -FilePath $FileName1 37 | Get-Content -Path $FileName1 38 | } 39 | $ICHT = @{ 40 | VMName = 'PSDirect' 41 | ScriptBlock = $SB 42 | Credential = $RKCred 43 | } 44 | Invoke-Command @ICHT 45 | 46 | # 6. Take a second checkpoint 47 | $SNHT = @{ 48 | VMName = 'PSDirect' 49 | ComputerName = 'HV1' 50 | SnapshotName = 'Snapshot2' 51 | } 52 | Checkpoint-VM @SNHT 53 | 54 | # 7. Get the VM checkpoint details for PSDirect 55 | Get-VMSnapshot -VMName PSDirect 56 | 57 | # 8. Look at the files supporting the two checkpoints 58 | Get-ChildItem -Path $Parent 59 | 60 | # 9. Create and display another file in PSdirect (ie after you have taken Snapshot2) 61 | $SB = { 62 | $FileName2 = 'C:\File_After_Checkpoint_2' 63 | Get-Date | Out-File -FilePath $FileName2 64 | Get-ChildItem -Path C:\ -File 65 | } 66 | $ICHT = @{ 67 | VMName = 'PSDirect' 68 | ScriptBlock = $SB 69 | Credential = $RKCred 70 | 71 | } 72 | Invoke-Command @ICHT 73 | 74 | # 10. Restore VM1 back to the checkpoint named Snapshot1 75 | $Snap1 = Get-VMSnapshot -VMName PSDirect -Name Snapshot1 76 | Restore-VMSnapshot -VMSnapshot $Snap1 -Confirm:$false 77 | Start-VM -Name PSDirect 78 | Wait-VM -For IPAddress -Name PSDirect 79 | 80 | # 11. See what files we have now on PSDirect 81 | $SB = { 82 | Get-ChildItem -Path C:\ 83 | } 84 | $ICHT = @{ 85 | VMName = 'PSDirect' 86 | ScriptBlock = $SB 87 | Credential = $RKCred 88 | } 89 | Invoke-Command @ICHT 90 | 91 | # 12. Roll forward to Snapshot2 92 | $Snap2 = Get-VMSnapshot -VMName PSdirect -Name Snapshot2 93 | Restore-VMSnapshot -VMSnapshot $Snap2 -Confirm:$false 94 | Start-VM -Name PSDirect 95 | Wait-VM -For IPAddress -Name PSDirect 96 | 97 | # 13. Observe the files you now have on VM2 98 | $SB = { 99 | Get-ChildItem -Path C:\ 100 | } 101 | $ICHT = @{ 102 | VMName = 'PSDirect' 103 | ScriptBlock = $SB 104 | Credential = $RKCred 105 | } 106 | Invoke-Command @ICHT 107 | 108 | # 14. Restore to Snapshot1 again: 109 | $Snap1 = Get-VMSnapshot -VMName PSDirect -Name Snapshot1 110 | Restore-VMSnapshot -VMSnapshot $Snap1 -Confirm:$false 111 | Start-VM -Name PSDirect 112 | Wait-VM -For IPAddress -Name PSDirect 113 | 114 | # 15. Check snapshots and VM data files again: 115 | Get-VMSnapshot -VMName PSDirect 116 | Get-ChildItem -Path $Parent 117 | 118 | # 16. Remove all the snapshots from HV1: 119 | Get-VMSnapshot -VMName PSDirect | 120 | Remove-VMSnapshot 121 | 122 | # 17. Check VM data files again: 123 | Get-ChildItem -Path $Parent -------------------------------------------------------------------------------- /Chapter 05 - Managing Shared Data/Recipe 5.6 - Configuring a DFS Namespace.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 5.6 - Configuring a DFS Namespace 2 | # 3 | # Run on CL1 4 | 5 | 6 | # 1. Add DFSN Rsat Tools to CL1 7 | Get-WindowsCapability -Online -Name *FileServices.Tools* | 8 | Add-WindowsCapability -Online | 9 | Out-Null 10 | 11 | # 2. Install DFS Namespace, DFS Replication, and the related management tools: 12 | $IHT = @{ 13 | Name = 'FS-DFS-Namespace' 14 | IncludeManagementTools = $True 15 | } 16 | Install-WindowsFeature @IHT -ComputerName SRV1 17 | Install-WindowsFeature @IHT -ComputerName SRV2 18 | 19 | # 3. View the DFSN module and the DFSN cmdlets: 20 | Get-Module -Name DFSN -ListAvailable 21 | 22 | # 4. Create folders and shares for DFS Root: 23 | $SB = { 24 | New-Item -Path C:\ShareData -ItemType Directory -Force | 25 | Out-Null 26 | New-SmbShare -Name ShareData -Path C:\ShareData -FullAccess Everyone 27 | } 28 | Invoke-Command -ComputerName SRV1, SRV2 -ScriptBlock $SB | 29 | Out-Null 30 | 31 | # 5. Create DFS Namespace Root pointing to ShareData: 32 | $NSHT = @{ 33 | Path = '\\Reskit.Org\ShareData' 34 | TargetPath = '\\SRV1\ShareData' 35 | Type = 'DomainV2' 36 | Description = 'Reskit Shared Data DFS Root' 37 | } 38 | New-DfsnRoot @NSHT 39 | 40 | # 6. Add a second target and view results: 41 | $NSHT2 = @{ 42 | Path = '\\Reskit.Org\ShareData' 43 | TargetPath = '\\Srv2\ShareData' 44 | } 45 | New-DfsnRootTarget @NSHT2 | Out-Null 46 | Get-DfsnRootTarget -Path \\Reskit.Org\ShareData 47 | 48 | # 7. Create IT Data shares and populate: 49 | # FS1 folders/shares 50 | $SB = { 51 | New-Item -Path C:\IT2 -ItemType Directory | Out-Null 52 | New-SmbShare -Name 'ITData' -Path C:\IT2 -FullAccess Everyone 53 | # Add content to files in root 54 | 'Root' | Out-File -FilePath C:\IT2\Root.Txt 55 | } 56 | Invoke-Command -ScriptBlock $SB -Computer FS1 | Out-Null 57 | # FS2 folders/shares 58 | $SB = { 59 | New-Item -Path C:\IT2 -ItemType Directory | Out-Null 60 | New-SmbShare -Name 'ITData' -Path C:\IT2 -FullAccess Everyone 61 | 'Root' | Out-File -FilePath c:\IT2\Root.Txt 62 | } 63 | Invoke-Command -ScriptBlock $SB -Computer FS2 | Out-Null 64 | # DC1 folders/shares 65 | $SB = { 66 | #New-Item -Path C:\ITM -ItemType Directory | Out-Null 67 | New-SmbShare -Name 'ITM' -Path C:\ITM -FullAccess Everyone 68 | 'Root' | Out-File -Filepath C:\ITM\Root.Txt 69 | } 70 | Invoke-Command -ScriptBlock $SB -Computer DC1 | Out-Null 71 | # DC2 folders/shares 72 | $SB = { 73 | New-Item C:\ITM -ItemType Directory | Out-Null 74 | New-SmbShare -Name 'ITM' -Path C:\ITM -FullAccess Everyone 75 | 'Root' | Out-File -FilePath c:\ITM\Root.Txt 76 | } 77 | Invoke-Command -ScriptBlock $SB -Computer DC2 78 | 79 | # 8. Create DFS Namespace and set DFS targets 80 | $NSHT1 = @{ 81 | Path = '\\Reskit\ShareData\IT\ITData' 82 | TargetPath = '\\FS1\ITData' 83 | EnableTargetFailback = $true 84 | Description = 'IT Data' 85 | } 86 | New-DfsnFolder @NSHT1 | Out-Null 87 | 88 | $NSHT2 = @{ 89 | Path = '\\Reskit\ShareData\IT\ITData' 90 | TargetPath = '\\FS2\ITData' 91 | } 92 | New-DfsnFolderTarget @NSHT2 | Out-Null 93 | 94 | $NSHT3 = @{ 95 | Path = '\\Reskit\ShareData\IT\ITManagement' 96 | TargetPath = '\\DC1\ITM' 97 | EnableTargetFailback = $true 98 | Description = 'IT Management Data' 99 | } 100 | New-DfsnFolder @NSHT3 | Out-Null 101 | 102 | $NSHT4 = @{ 103 | Path = '\\Reskit\ShareData\IT\ITManagement' 104 | TargetPath = '\\DC2\ITM' 105 | } 106 | New-DfsnFolderTarget @NSHT4 | Out-Null 107 | 108 | # 9. View the hierarchy 109 | Get-ChildItem -Path \\Reskit.Org\ShareData\IT -Recurse 110 | 111 | -------------------------------------------------------------------------------- /Chapter 11 - Managing Hyper-V/Recipe 11.12 - Creating a Hyper-V Status Report.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 11.2 Creating a Hyper-V Status Report 2 | 3 | # 1. Create a basic report object hash table 4 | $ReportHT = [Ordered] @{} 5 | 6 | # 2. Get the host details and add them to the Report object 7 | $HostDetails = Get-CimInstance -ClassName Win32_ComputerSystem 8 | $ReportHT.HostName = $HostDetails.Name 9 | $ReportHT.Maker = $HostDetails.Manufacturer 10 | $ReportHT.Model = $HostDetails.Model 11 | 12 | # 3. Add the PowerShell version information 13 | $ReportHT.PSVersion = $PSVersionTable.PSVersion.tostring() 14 | # Add OS information: 15 | $OS = Get-CimInstance -Class Win32_OperatingSystem 16 | $ReportHT.OSEdition = $OS.Caption 17 | $ReportHT.OSArch = $OS.OSArchitecture 18 | $ReportHT.OSLang = $OS.OSLanguage 19 | $ReportHT.LastBootTime = $os.LastBootUpTime 20 | $Now = Get-Date 21 | $UTD = [float] ("{0:n3}" -f (($Now -$OS.LastBootUpTime).Totaldays)) 22 | $ReportHT.UpTimeDays = $UTD 23 | 24 | # 4. Add a count of processors in the host 25 | $PHT = @{ 26 | ClassName = 'MSvm_Processor' 27 | Namespace = 'root/virtualization/v2' 28 | } 29 | $Proc = Get-CimInstance @PHT 30 | $ReportHT.CPUCount = ($Proc | 31 | Where-Object elementname -match 'Logical Processor').COUNT 32 | 33 | # 5. Add the current host CPU usage 34 | $Cname = '\\.\processor(_total)\% processor time' 35 | $CPU = Get-Counter -Counter $Cname 36 | $ReportHT.HostCPUUsage = $CPU.CounterSamples.CookedValue 37 | 38 | # 6. Add the total host physical memory: 39 | $Memory = Get-Ciminstance -Class Win32_ComputerSystem 40 | $HostMemory = [float] ( "{0:n2}" -f ($Memory.TotalPhysicalMemory/1GB)) 41 | $ReportHT.HostMemoryGB = $HostMemory 42 | 43 | # 7. Add the memory allocated to VMs: 44 | $Sum = 0 45 | Get-VM | Foreach-Object {$sum += $_.MemoryAssigned + $Total} 46 | $Sum = [float] ( "{0:N2}" -f ($Sum/1gb) ) 47 | $ReportHT.AllocatedMemoryGB = $Sum 48 | 49 | # 8. Create and view the host report object: 50 | $Reportobj = New-Object -TypeName PSObject -Property $ReportHT 51 | $ReportBase = $Reportobj | Out-String 52 | 53 | # 9. Create some New VMs: 54 | New-VM -VMName SQL1 | Out-Null 55 | New-VM -VMName SQL2 | Out-Null 56 | New-VM -VMName OM1 | Out-Null 57 | 58 | # 10. Get VM details on the local VM host and create a container array for individual 59 | # VM related objects: 60 | $VMs = Get-VM -Name * 61 | $VMHT = @() 62 | 63 | # 11. Get VM details for each VM into an object added to the hash table container: 64 | Foreach ($VM in $VMs) { 65 | # Create VM Report hash table 66 | $VMReport = [ordered] @{} 67 | # Add VM's Name 68 | $VMReport.VMName = $VM.VMName 69 | # Add Status 70 | $VMReport.Status = $VM.Status 71 | # Add Uptime 72 | $VMReport.Uptime = $VM.Uptime 73 | # Add VM CPU 74 | $VMReport.VMCPU = $VM.CPUUsage 75 | # Replication Mode/Status 76 | $VMReport.ReplMode = $VM.ReplicationMode 77 | $VMReport.ReplState = $Vm.ReplicationState 78 | # Create object from Hash table, add to array 79 | $VMR = New-Object -TypeName PSObject -Property $VMReport 80 | $VMHT += $VMR 81 | } 82 | 83 | # 12. Display the array of objects as a table: 84 | $VMDetails = $VMHT | 85 | Sort-Object -Property Uptime -Descending | 86 | Format-Table | 87 | Out-String 88 | 89 | # 13. Now create the report 90 | $ReportBody = "Hyper-V Status Report`n" 91 | $ReportBody += "---------------------`n`n" 92 | $ReportBody += "Created on:" 93 | $ReportBody += (Get-Date | Out-String) 94 | $ReportBody += "Hyper-V Server Details:" 95 | $ReportBody += $ReportBase 96 | $ReportBody += 'VM Details on this host:' 97 | $ReportBody += $VMDetails 98 | 99 | 100 | # 14. Display the Report 101 | $ReportBody 102 | 103 | 104 | 105 | 106 | 107 | # remove fake VMs 108 | # get-vm -vmname SQL1, SQL1, OM1? | Remove-VM 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /Chapter 03 - Deploying Active Directory/3.5 - Reporting on AD Users.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 3.5 - Reporting on AD Users 2 | 3 | # 1. Define a function Get-ReskitUser 4 | # The function returns objects related to users in reskit.org 5 | Function Get-ReskitUser { 6 | # Get PDC Emulator DC 7 | $PrimaryDC = Get-ADDomainController -Discover -Service PrimaryDC 8 | # Get Users 9 | $ADUsers = Get-ADUser -Filter * -Properties * -Server $PrimaryDC 10 | # Iterate through them and create $Userinfo hash table: 11 | Foreach ($ADUser in $ADUsers) { 12 | # Create a userinfo HT 13 | $UserInfo = [Ordered] @{} 14 | $UserInfo.SamAccountname = $ADUser.SamAccountName 15 | $Userinfo.DisplayName = $ADUser.DisplayName 16 | $UserInfo.Office = $ADUser.Office 17 | $Userinfo.Enabled = $ADUser.Enabled 18 | $userinfo.LastLogonDate = $ADUser.LastLogonDate 19 | $UserInfo.ProfilePath = $ADUser.ProfilePath 20 | $Userinfo.ScriptPath = $ADUser.ScriptPath 21 | $UserInfo.BadPWDCount = $ADUser.badPwdCount 22 | New-Object -TypeName PSObject -Property $UserInfo 23 | } 24 | } # end of function 25 | 26 | # 2. Get the users 27 | $RKUsers = Get-ReskitUser 28 | 29 | # 3. Build the report header 30 | $RKReport = '' 31 | $RkReport += "*** Reskit.Org AD Report`n" 32 | $RKReport += "*** Generated [$(Get-Date)]`n" 33 | $RKReport += "*******************************`n`n" 34 | 35 | # 4. Report on Disabled users 36 | $RkReport += "*** Disabled Users`n" 37 | $RKReport += $RKUsers | 38 | Where-Object {$_.Enabled -NE $true} | 39 | Format-Table -Property SamAccountName, Displayname | 40 | Out-String 41 | 42 | # 5. Report users who have not recently logged on 43 | $OneWeekAgo = (Get-Date).AddDays(-7) 44 | $RKReport += "`n*** Users Not logged in since $OneWeekAgo`n" 45 | $RkReport += $RKUsers | 46 | Where-Object {$_.Enabled -and $_.LastLogonDate -le $OneWeekAgo} | 47 | Sort-Object -Property LastlogonDate | 48 | Format-Table -Property SamAccountName,lastlogondate | 49 | Out-String 50 | 51 | # 6. Users with high invalid password attempts 52 | # 53 | $RKReport += "`n*** High Number of Bad Password Attempts`n" 54 | $RKReport += $RKUsers | Where-Object BadPwdCount -ge 5 | 55 | Format-Table -Property SamAccountName, BadPwdCount | 56 | Out-String 57 | 58 | # 7. Add Another report header line for this part of the 59 | # report and create an empty array of priviledged users 60 | $RKReport += "`n*** Privileged User Report`n" 61 | $PUsers = @() 62 | 63 | # 8. Query the Enterprise Admins/Domain Admins/Scheme Admins 64 | # groups for members and add to the $Pusers array 65 | # Get Enterprise Admins group members 66 | $Members = Get-ADGroupMember -Identity 'Enterprise Admins' -Recursive | 67 | Sort-Object -Property Name 68 | $PUsers += foreach ($Member in $Members) { 69 | Get-ADUser -Identity $Member.SID -Properties * | 70 | Select-Object -Property Name, 71 | @{Name='Group';expression={'Enterprise Admins'}}, 72 | whenCreated,LastlogonDate 73 | } 74 | # Get Domain Admins group members 75 | $Members = 76 | Get-ADGroupMember -Identity 'Domain Admins' -Recursive | 77 | Sort-Object -Property Name 78 | $PUsers += Foreach ($Member in $Members) 79 | {Get-ADUser -Identity $member.SID -Properties * | 80 | Select-Object -Property Name, 81 | @{Name='Group';expression={'Domain Admins'}}, 82 | WhenCreated, Lastlogondate,SamAccountName 83 | } 84 | # Get Schema Admins members 85 | $Members = 86 | Get-ADGroupMember -Identity 'Schema Admins' -Recursive | 87 | Sort-Object Name 88 | $PUsers += Foreach ($Member in $Members) { 89 | Get-ADUser -Identity $member.SID -Properties * | 90 | Select-Object -Property Name, 91 | @{Name='Group';expression={'Schema Admins'}}, ` 92 | WhenCreated, Lastlogondate,SamAccountName 93 | } 94 | 95 | # 9 Add the special users to the report 96 | $RKReport += $PUsers | Out-String 97 | 98 | # 10. Display the report 99 | $RKReport -------------------------------------------------------------------------------- /Chapter 12 - Exploring Azure/Recipe 12.5 - Create Azure Web SIte.ps1: -------------------------------------------------------------------------------- 1 | # Recipe 12.5 - Create an Azure Web App 2 | 3 | # 1. Define Variables 4 | $Locname = 'uksouth' # location name 5 | $RgName = 'packt_rg' # resource group we are using 6 | $SAName = 'packt42sa' # storage account name 7 | $AppSrvName = 'packt42' 8 | $AppName = 'packt42website' 9 | 10 | # 2. Login to your Azure Account and ensure RG exists 11 | $CredAZ = Get-Credential 12 | Login-AzAccount -Credential $CredAz 13 | 14 | # 3. Ensure Resource Group is created 15 | $RGHT1 = @{ 16 | Name = $RgName 17 | ErrorAction = 'Silentlycontinue' 18 | } 19 | $RG = Get-AzResourceGroup @RGHT1 20 | if (-not $RG) { 21 | $RGTag = [Ordered] @{Publisher='Packt'} 22 | $RGTag += @{Author='Thomas Lee'} 23 | $RGHT2 = @{ 24 | Name = $RgName 25 | Location = $Locname 26 | Tag = $RGTag 27 | } 28 | $RG = New-AzResourceGroup @RGHT2 29 | Write-Host "RG $RgName created" 30 | } 31 | 32 | # 4. Ensure the Stoage Account is created. 33 | $SAHT = @{ 34 | Name = $SAName 35 | ResourceGroupName = $RgName 36 | ErrorAction = 'SilentlyContinue' 37 | } 38 | $SA = Get-AzStorageAccount @SAHT 39 | if (-not $SA) { 40 | $SATag = [Ordered] @{Publisher='Packt'} 41 | $SATag += @{Author='Thomas Lee'} 42 | $SAHT = @{ 43 | Name = $SAName 44 | ResourceGroupName = $RgName 45 | Location = $Locname 46 | Tag = $SATag 47 | SkuName = 'Standard_LRS' 48 | } 49 | $SA = New-AStorageAccount @SAHT 50 | "SA $SAName created" 51 | } 52 | 53 | # 5. Create app service plan 54 | $SPHT = @{ 55 | ResourceGroupName = $RgName 56 | Name = $AppSrvName 57 | Location = $Locname 58 | Tier = 'Free' 59 | } 60 | New-AzAppServicePlan @SPHT | Out-Null 61 | 62 | # 6. View the service plan 63 | $PHT = @{ 64 | ResourceGroupName = $RGname 65 | Name = $AppSrvName 66 | } 67 | Get-AzAppServicePlan @PHT 68 | 69 | # 7. Create the new azure webapp 70 | $WAHT = @{ 71 | ResourceGroupName = $RgName 72 | Name = $AppName 73 | AppServicePlan = $AppSrvName 74 | Location = $Locname 75 | } 76 | New-AzWebApp @WAHT | Out-Null 77 | 78 | # 8. View application details 79 | $WebApp = Get-AzWebApp -ResourceGroupName $RgName -Name $AppName 80 | $WebApp | 81 | Format-Table -Property Name, State, Hostnames, Location 82 | 83 | # 9 Now see the web site 84 | $SiteUrl = "https://$($WebApp.DefaultHostName)" 85 | $IE = New-Object -ComObject InterNetExplorer.Application 86 | $IE.Navigate2($SiteUrl) 87 | $IE.Visible = $true 88 | 89 | # 10. Install the PSFTP module 90 | Install-module PSFTP -Force | Out-Null 91 | Import-Module PSFTP 92 | 93 | # 11. Get publishing profile XML and extract FTP upload details 94 | $APHT = @{ 95 | ResourceGroupName = $RgName 96 | Name = $AppName 97 | OutputFile = 'C:\Foo\pdata.txt' 98 | } 99 | $x = [xml] (Get-AzWebAppPublishingProfile @APHT) 100 | $x.publishData.publishProfile[1] 101 | 102 | # 12. Extract crededentials and site details 103 | $UserName = $x.publishData.publishProfile[1].userName 104 | $UserPwd = $x.publishData.publishProfile[1].userPWD 105 | $Site = $x.publishData.publishProfile[1].publishUrl 106 | 107 | # 13. Connect to the FTP site 108 | $FTPSN = 'FTPtoAzure' 109 | $PS = ConvertTo-SecureString $UserPWD -AsPlainText -Force 110 | $T = 'System.Management.automation.PSCredentiaL' 111 | $Cred = New-Object -TypeName $T -ArgumentList $UserName,$PS 112 | $FTPHT = @{ 113 | Credentials = $Cred 114 | Server = $Site 115 | Session = $FTPSN 116 | UsePassive = $true 117 | } 118 | Set-FTPConnection @FTPHT 119 | $Session = Get-FTPConnection -Session $FTPSN 120 | 121 | # 15. Create a Web Page and upload it 122 | 'My First Azure Web Site' | Out-File -FilePath C:\Foo\Index.Html 123 | $Filename = 'C:\foo\index.html' 124 | $IHT = @{ 125 | Path = '/' 126 | LocalPath = 'C:\foo\index.html' 127 | Session = $FTPSN 128 | } 129 | Add-FTPItem @IHT 130 | 131 | 132 | # 16. NoW look at the site using default browser (Chrome): 133 | $SiteUrl = "https://$($WebApp.DefaultHostName)" 134 | Start-Process -FilePath $SiteUrl --------------------------------------------------------------------------------