diff --git a/demos/1-PowerShellGet.ps1 b/demos/1-PowerShellGet.ps1 index 8a3a704953..769fa6f449 100644 --- a/demos/1-PowerShellGet.ps1 +++ b/demos/1-PowerShellGet.ps1 @@ -4,11 +4,13 @@ Get-PackageProvider #(should show 2 providers - NuGet,PowerShellGet) ## Using PowerShellGet find and install other demos +# Value: equivalent of pypi +# Look for all the modules we'll be demoing today +Find-Module -Tag 'Open PowerShell','Demos' +# Pipe this to Install-Module to install them Find-Module -Tag 'Open PowerShell','Demos' | Install-Module -Verbose Get-Module - -# Find and Download node.js from nuget.org -Find-Package -Name node.js -ProviderName NuGet -Verbose -Source http://nuget.org/api/v2 +# Note that ScriptAnalyzer gets installed because the VSCode demo is dependent upon it # Register trusted endpoints Register-PackageSource -Name NuGet -Location http://nuget.org/api/v2 -Trusted -ProviderName NuGet diff --git a/demos/apache.ps1 b/demos/apache.ps1 new file mode 100644 index 0000000000..e9f3cd2bcf --- /dev/null +++ b/demos/apache.ps1 @@ -0,0 +1,14 @@ +# Get-ApacheVHosts +# Enumerate configured virtual hosts (web sites) on an apache server + +# New-ApacheVHost +# Given defined parameters, create a $ServerName.conf virtual host config file at $VHostsDirectory + +# Get-ApacheModules +# List installed Apache Modules + +# Demo execution: +# Run Get-ApacheVHosts and enumerate configured virtual hosts +# Run Get-ApacheModules to show installed Apache modules +# Run New-ApacheVHost to create a new virtual host and restart Apache +# Run Get-ApacheVhosts to show the newly created virtual host diff --git a/demos/crontab.ps1 b/demos/crontab.ps1 new file mode 100644 index 0000000000..d90e2dbdb8 --- /dev/null +++ b/demos/crontab.ps1 @@ -0,0 +1,9 @@ +# Use the crontab module available at ./modules/CronTab + +# Get the existing cron jobs + +# Sort them by data + +# Create a new one using a DateTime object + +# Show in bash that the new cron job exists diff --git a/demos/dsc.ps1 b/demos/dsc.ps1 new file mode 100644 index 0000000000..c1fdd69037 --- /dev/null +++ b/demos/dsc.ps1 @@ -0,0 +1,11 @@ +# DSC MOF Compilation +# DSC Configuration() script that: +# Defines base configuration users, groups, settings +# Uses PS function to set package configuration (ensure=Present) for an array of packages +# Probes for the existence of a package (Apache or MySQL) and conditionally configures the workload. I.e., if Apache is installed, configure Apache settings + +# Demo execution: +# Show the .ps1 +# Run the .ps1 to generate a MOF +# Apply the MOF locally with Start-DSCConfiguration +# Show the newly configured state \ No newline at end of file diff --git a/demos/json.ps1 b/demos/json.ps1 new file mode 100644 index 0000000000..4804ffc699 --- /dev/null +++ b/demos/json.ps1 @@ -0,0 +1,11 @@ +# Get-Mongostat +# Get mongodb statistics with parsed JSON + +# journalctl is a native tool to emit SystemD's journal, which includes diagnostic info pertaining to SystemD services +# Show-JournalCtl +# Given journalctl parameters, run journalctl with a -o json to emit JSON, e.g. journalctl $Parameters -o json --no-pager +# Return structured data from Journal + +# Demo execution +# Show journatcl example +# Using Where & Sort, filter journal output to drill into a specific problem (e.g. service failed to start) \ No newline at end of file diff --git a/demos/modules/ApacheHTTPServer/ApacheVirtualHosts.psm1 b/demos/modules/ApacheHTTPServer/ApacheVirtualHosts.psm1 new file mode 100644 index 0000000000..94710c8130 --- /dev/null +++ b/demos/modules/ApacheHTTPServer/ApacheVirtualHosts.psm1 @@ -0,0 +1,173 @@ +$moduleRoot = Split-Path -Path $MyInvocation.MyCommand.Path + + +Function New-ApacheVHost { + [CmdletBinding()] + param ( + [parameter (Mandatory = $true)][string]$ServerName, + [string]$VHostsDirectory, + [parameter (Mandatory = $true)][string]$DocumentRoot, + [parameter (Mandatory = $true)][string]$VirtualHostIPAddress, + [string[]]$ServerAliases, + [parameter (Mandatory = $true)][string]$VirtualHostPort, + [string]$ServerAdmin, + [string]$CustomLogPath, + [string]$ErrorLogPath + ) + + if ($VHostsDirectory -notlike "*/*"){ + #Try to find default + if (Test-Path "/etc/httpd/conf.d"){ + $VHostsDirectory = "/etc/httpd/conf.d/" + } + if (Test-Path "/etc/apache2/sites-enabled"){ + $VHostsDirectory = "/etc/apache2/sites-enabled" + } + } + + if (!(Test-Path $VHostsDirectory)){ + Write-Error "Specified virtual hosts directory does not exist: $VHostsDirectory" + exit 1 + } + + $vHostDef = ".*:[0-9]*)(?.*)\((?.*)\)" + $VHostProps = $matches + $vhobject |Add-Member -type NoteProperty -name "ServerName" -value $matches.ServerName.Trim() + $vhobject |Add-Member -type NoteProperty -name "ListenAddress" -value $matches.Listen.Trim() + $vhobject |Add-Member -type NoteProperty -name "ConfFile" -value $matches.ConfFile.Trim() + $Vhosts += $vhobject + } + + } + + Return $Vhosts + +} + +Function Restart-ApacheHTTPServer{ + [CmdletBinding()] + Param( + [boolean]$Graceful + ) + + if ($Graceful -eq $null){$Graceful = $fase} + + $cmd = $null + if (Test-Path "/usr/sbin/apache2ctl"){ + $cmd = "/usr/sbin/apache2ctl" + }elseif(Test-Path "/usr/sbin/httpd"){ + $cmd = "/usr/sbin/httpd" + } + + if ($cmd -eq $null){ + Write-Error "Unable to find httpd/apache2ctl command" + exit -1 + } + + if ($Graceful){ + $cmd = $cmd += " -k graceful" + }else{ + $cmd = $cmd += " -k restart" + } + + Invoke-Expression $Cmd +} + +Function Get-ApacheModules{ + $cmd = $null + if (Test-Path "/usr/sbin/apache2ctl"){ + $cmd = "/usr/sbin/apache2ctl" + }elseif(Test-Path "/usr/sbin/httpd"){ + $cmd = "/usr/sbin/httpd" + } + + if ($cmd -eq $null){ + Write-Error "Unable to find httpd/apache2ctl command" + exit -1 + } + + $cmd = $cmd += " -M |grep -v Loaded" + + $ApacheModules = @() + function New-ModuleObj { + New-Object PSObject -Property @{} + } + + + $Results = Invoke-Expression $cmd + Foreach ($mod in $Results){ + $modObj = New-ModuleObj + $modObj | Add-Member -type NoteProperty -name "Module" -value $mod.trim() + $ApacheModules += $modObj + } + + Return $ApacheModules + +} diff --git a/demos/modules/CronTab/CronTab.ps1xml b/demos/modules/CronTab/CronTab.ps1xml new file mode 100644 index 0000000000..1d1f1f90d8 --- /dev/null +++ b/demos/modules/CronTab/CronTab.ps1xml @@ -0,0 +1,69 @@ + + + + + + Default + + CronJob + + + + + + 10 + Left + + + + 10 + Left + + + + 10 + Left + + + + 10 + Left + + + + 10 + Left + + + + Left + + + + + + + Minute + + + Hour + + + DayOfMonth + + + Month + + + DayOfWeek + + + Command + + + + + + + + \ No newline at end of file diff --git a/demos/modules/CronTab/CronTab.psd1 b/demos/modules/CronTab/CronTab.psd1 new file mode 100644 index 0000000000..23d9d95f05 Binary files /dev/null and b/demos/modules/CronTab/CronTab.psd1 differ diff --git a/demos/modules/CronTab/CronTab.psm1 b/demos/modules/CronTab/CronTab.psm1 new file mode 100644 index 0000000000..f8bd2e7c4f --- /dev/null +++ b/demos/modules/CronTab/CronTab.psm1 @@ -0,0 +1,189 @@ +$crontabcmd = "/usr/bin/crontab" + +#TODO fix after https://github.com/PowerShell/PowerShell/issues/932 is fixed +#class CronJob { +# [string] $Minute +# [string] $Hour +# [string] $DayOfMonth +# [string] $Month +# [string] $DayOfWeek +# [string] $Command +#} + +# Internal helper functions + +function Get-CronTab ([String] $user) { + $crontab = Invoke-CronTab -user $user -arguments "-l" -noThrow + if ($crontab -is [System.Management.Automation.ErrorRecord]) { + if ($crontab.Exception.Message.StartsWith("no crontab for ")) { + $crontab = $null + } + else { + throw $crontab.Exception + } + } + [string[]] $crontab +} + +function ConvertTo-CronJob ([String] $crontab) { + $split = $crontab.split(" ", 6) + $cronjob = New-Object -TypeName PSObject -Property @{ #TODO: change to CronJob type + PSTypeName="CronJob"; + Minute = $split[0]; + Hour = $split[1]; + DayOfMonth= $split[2]; + Month =$split[3]; + DayOfWeek = $split[4]; + Command = $split[5] + } + $cronjob +} + +function Invoke-CronTab ([String] $user, [String] $arguments, [Switch] $noThrow) { + If ($user -ne [String]::Empty) { + $arguments = "-u $UserName $arguments" + } + + $cmd = "$crontabcmd $arguments 2>&1" + Write-Verbose $cmd + $output = Invoke-Expression $cmd + if ($LastExitCode -ne 0 -and -not $noThrow) { + $e = New-Object System.InvalidOperationException -ArgumentList $output.Exception.Message + throw $e + } else { + $output + } +} + +function Import-CronTab ([String] $user, [String[]] $crontab) { + $temp = New-TemporaryFile + [String]::Join([Environment]::NewLine,$crontab) | Set-Content $temp.FullName + Invoke-CronTab -user $user $temp.FullName + Remove-Item $temp +} + +# Public functions + +function Remove-CronJob { +<# +.SYNOPSIS + Removes the exactly matching cron job from the cron table +.DESCRIPTION + Removes the exactly matching cron job from the cron table +.EXAMPLE + Get-CronJob | ? {%_.Command -like 'foo *'} | Remove-CronJob +.RETURNVALUE + None +.PARAMETER UserName + Optional parameter to specify a specific user's cron table +.PARAMETER Job + Cron job object returned from Get-CronJob +#> + [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact="High")] + param ( + [Alias("u")][Parameter(Mandatory=$false)][String] $UserName, + [Alias("j")][Parameter(Mandatory=$true,ValueFromPipeline=$true)][PSTypeName("CronJob")] $Job #TODO use CronJob type + ) + process { + + [string[]] $crontab = Get-CronTab -user $UserName + [string[]] $newcrontab = $null + $found = $false + + foreach ($line in $crontab) { + $cronjob = ConvertTo-CronJob -crontab $line + if ((Compare-object $cronjob.psobject.properties $Job.psobject.properties) -eq $null) { + $found = $true + } else { + $newcrontab += $line + } + } + + if (-not $found) { + $e = New-Object System.Exception -ArgumentList "Job not found" + throw $e + } + if ($pscmdlet.ShouldProcess($Job.Command,"Remove")) { + Import-CronTab -user $UserName -crontab $newcrontab + } + } +} + +function New-CronJob { +<# +.SYNOPSIS + Create a new cron job +.DESCRIPTION + Create a new job in the cron table. Date and time parameters can be specified + as ranges such as 10-30, as a list: 5,6,7, or combined 1-5,10-15. An asterisk + means 'first through last' (the entire allowed range). Step values can be used + with ranges or with an asterisk. Every 2 hours can be specified as either + 0-23/2 or */2. +.EXAMPLE + New-CronJob -Minute 10-30 -Hour 10-20/2 -DayOfMonth */2 -Command "/bin/bash -c 'echo hello' > ~/hello" +.RETURNVALUE + If successful, an object representing the cron job is returned +.PARAMETER UserName + Optional parameter to specify a specific user's cron table +.PARAMETER Minute + Valid values are 0 to 59. If not specified, defaults to *. +.PARAMETER Hour + Valid values are 0-23. If not specified, defaults to *. +.PARAMETER DayOfMonth + Valid values are 1-31. If not specified, defaults to *. +.PARAMETER Month + Valid values are 1-12. If not specified, defaults to *. +.PARAMETER DayOfWeek + Valid values are 0-7. 0 and 7 are both Sunday. If not specified, defaults to *. +.PARAMETER Command + Command to execute at the scheduled time and day. +#> + [CmdletBinding()] + param ( + [Alias("u")][Parameter(Mandatory=$false)][String] $UserName, + [Alias("mi")][Parameter(Position=1)][String[]] $Minute = "*", + [Alias("h")][Parameter(Position=2)][String[]] $Hour = "*", + [Alias("dm")][Parameter(Position=3)][String[]] $DayOfMonth = "*", + [Alias("mo")][Parameter(Position=4)][String[]] $Month = "*", + [Alias("dw")][Parameter(Position=5)][String[]] $DayOfWeek = "*", + [Alias("c")][Parameter(Mandatory=$true,Position=6)][String] $Command + ) + process { + # TODO: validate parameters, note that different versions of crontab support different capabilities + $line = "{0} {1} {2} {3} {4} {5}" -f [String]::Join(",",$Minute), [String]::Join(",",$Hour), + [String]::Join(",",$DayOfMonth), [String]::Join(",",$Month), [String]::Join(",",$DayOfWeek), $Command + [string[]] $crontab = Get-CronTab -user $UserName + $crontab += $line + Import-CronTab -User $UserName -crontab $crontab + ConvertTo-CronJob -crontab $line + } +} + +function Get-CronJob { +<# +.SYNOPSIS + Returns the current cron jobs from the cron table +.DESCRIPTION + Returns the current cron jobs from the cron table +.EXAMPLE + Get-CronJob -UserName Steve +.RETURNVALUE + CronJob objects +.PARAMETER UserName + Optional parameter to specify a specific user's cron table +#> + [CmdletBinding()] + [OutputType([PSObject])] + param ( + [Alias("u")][Parameter(Mandatory=$false)][String] $UserName + ) + process { + $crontab = Get-CronTab -user $UserName + ForEach ($line in $crontab) { + if ($line.Trim().Length -gt 0) + { + ConvertTo-CronJob -crontab $line + } + } + } +} diff --git a/demos/modules/README.md b/demos/modules/README.md new file mode 100644 index 0000000000..9a7f330f3a --- /dev/null +++ b/demos/modules/README.md @@ -0,0 +1 @@ +# Samples diff --git a/demos/remoting.ps1 b/demos/remoting.ps1 new file mode 100644 index 0000000000..fe909db1b9 --- /dev/null +++ b/demos/remoting.ps1 @@ -0,0 +1,2 @@ +# Show PSRP working over OpenSSH +# Includes Windows -> Linux and Linux -> Windows \ No newline at end of file diff --git a/demos/rest.ps1 b/demos/rest.ps1 new file mode 100644 index 0000000000..a7b8c799fd --- /dev/null +++ b/demos/rest.ps1 @@ -0,0 +1,7 @@ +# Get all repositories from the GitHub API, sort by most pull requests, most stars, most forks, etc. + +# Get repo info (json) from the github api +# Convert json to PS object +# Set the private status to false +# Convert back to json +# Push the new json back to the github api \ No newline at end of file diff --git a/demos/xml.ps1 b/demos/xml.ps1 new file mode 100644 index 0000000000..151ee628fb --- /dev/null +++ b/demos/xml.ps1 @@ -0,0 +1,42 @@ +Dev: XML legacy [ETS?] +What are some xml workloads we can simplify with XML parsing? +Maybe cracking open some repository metadata? +JEE servers use XML pretty extensively for configuration. Perhaps a script to adjust JEE server settings? Obviously, parsing XML in bash is fraught with danger... + +PS /etc/tomcat> $tomcatserverfile="/usr/share/tomcat/conf/server.xml" +PS /etc/tomcat> [xml]$tomcatconfig=Get-Content $tomcatserverfile +PS /etc/tomcat> $tomcatconfig.Server + + +port : 8005 +shutdown : SHUTDOWN +#comment : { Security listener. Documentation at /docs/config/listeners.html + + , APR library loader. Documentation at /docs/apr.html , Initialize Jasper prior to webapps are loaded. Documentation at + /docs/jasper-howto.html , Prevent memory leaks due to use of particular java/javax APIs...} +Listener : {Listener, Listener, Listener, Listener...} +GlobalNamingResources : GlobalNamingResources +Service : Service + + + + +PS /etc/tomcat> $tomcatconfig.Server.port +8005 +PS /etc/tomcat> $tomcatconfig.Server.Listener + +className SSLEngine +--------- --------- +org.apache.catalina.core.AprLifecycleListener on +org.apache.catalina.core.JasperListener +org.apache.catalina.core.JreMemoryLeakPreventionListener +org.apache.catalina.mbeans.GlobalResourcesLifecycleListener +org.apache.catalina.core.ThreadLocalLeakPreventionListener + + +PS /etc/tomcat> $tomcatconfig.Server.Service + +name #comment +---- -------- +Catalina {The connectors can use a shared executor, you can define one or more named thread pools, ... +