Created
May 11, 2020 14:35
-
-
Save jdhitsolutions/111ba054133bde290592d7436af30fa5 to your computer and use it in GitHub Desktop.
A Visual Studio Code PowerShell snippet of my remote function framworrk
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"Remoting Function": { | |
"prefix": "Remoting Function Framework", | |
"body": [ | |
"Function Verb-Noun {\r", | |
"\r", | |
" #TODO: Create help documentation for your command\r", | |
"\r", | |
" [cmdletbinding(DefaultParameterSetName = \"computer\")]\r", | |
" #TODO: Add and modify parameters as necessary\r", | |
" Param(\r", | |
" [Parameter(\r", | |
" ParameterSetName = \"computer\",\r", | |
" Mandatory,\r", | |
" Position = 0,\r", | |
" ValueFromPipeline,\r", | |
" ValueFromPipelineByPropertyName,\r", | |
" HelpMessage = \"Enter the name of a computer to query. The default is the local host.\"\r", | |
" )]\r", | |
" [ValidateNotNullOrEmpty()]\r", | |
" [Alias(\"cn\")]\r", | |
" [string[]]$$ComputerName,\r", | |
" [Parameter(\r", | |
" ParameterSetName = \"computer\",\r", | |
" HelpMessage = \"Enter a credential object or username.\"\r", | |
" )]\r", | |
" [Alias(\"RunAs\")]\r", | |
" [PSCredential]$$Credential,\r", | |
" [Parameter(ParameterSetName = \"computer\")]\r", | |
" [switch]$$UseSSL,\r", | |
"\r", | |
" [Parameter(ParameterSetName = \"computer\")]\r", | |
" [ValidateSet(\"Default\", \"Basic\", \"Credssp\", \"Digest\", \"Kerberos\", \"Negotiate\", \"NegotiateWithImplicitCredentialqhel\")]\r", | |
" [string]$$Authentication = \"Default\",\r", | |
"\r", | |
" [Parameter(\r", | |
" ParameterSetName = \"session\",\r", | |
" ValueFromPipeline\r", | |
" )]\r", | |
" [ValidateNotNullOrEmpty()]\r", | |
" [System.Management.Automation.Runspaces.PSSession[]]$$Session,\r", | |
"\r", | |
" [ValidateScript( {$$_ -ge 0})]\r", | |
" [int32]$$ThrottleLimit = 32\r", | |
" )\r", | |
" DynamicParam {\r", | |
" #Add an SSH dynamic parameter if in PowerShell 7\r", | |
" if ($$isCoreCLR) {\r", | |
"\r", | |
" $$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary\r", | |
"\r", | |
" #a CSV file with dynamic parameters to create\r", | |
" #this approach doesn't take any type of parameter validation into account\r", | |
" $$data = @\"\r", | |
"Name,Type,Mandatory,Default,Help\r", | |
"HostName,string[],1,,\"Enter the remote host name.\"\r", | |
"UserName,string,0,,\"Enter the remote user name.\"\r", | |
"Subsystem,string,0,\"powershell\",\"The name of the ssh subsystem. The default is powershell.\"\r", | |
"Port,int32,0,,\"Enter an alternate SSH port\"\r", | |
"KeyFilePath,string,0,,\"Specify a key file path used by SSH to authenticate the user\"\r", | |
"SSHTransport,switch,0,,\"Use SSH to connect.\"\r", | |
"\"@\r", | |
"\r", | |
" $$data | ConvertFrom-Csv | ForEach-Object -begin { } -process {\r", | |
" $$attributes = New-Object System.Management.Automation.ParameterAttribute\r", | |
" $$attributes.Mandatory = ([int]$$_.mandatory) -as [bool]\r", | |
" $$attributes.HelpMessage = $$_.Help\r", | |
" $$attributes.ParameterSetName = \"SSH\"\r", | |
" $$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]\r", | |
" $$attributeCollection.Add($$attributes)\r", | |
" $$dynParam = New-Object -Type System.Management.Automation.RuntimeDefinedParameter($$_.name, $($$_.type -as [type]), $$attributeCollection)\r", | |
" $$dynParam.Value = $$_.Default\r", | |
" $$paramDictionary.Add($$_.name, $$dynParam)\r", | |
" } -end {\r", | |
" return $$paramDictionary\r", | |
" }\r", | |
" }\r", | |
" } #dynamic param\r", | |
"\r", | |
" Begin {\r", | |
" #capture the start time. The Verbose messages can display a timespan.\r", | |
" $$start = Get-Date\r", | |
" #the first verbose message uses a pseudo timespan to reflect the idea we're just starting\r", | |
" Write-Verbose \"[00:00:00.0000000 BEGIN ] Starting $($$myinvocation.mycommand)\"\r", | |
"\r", | |
" #a script block to be run remotely\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) BEGIN ] Defining the scriptblock to be run remotely.\"\r", | |
"\r", | |
" #TODO: define the scriptblock to be run remotely\r", | |
" $$sb = {\r", | |
" param([string]$$VerbPref = \"SilentlyContinue\", [bool]$$WhatPref)\r", | |
"\r", | |
" $$VerbosePreference = $$VerbPref\r", | |
" $$WhatIfPreference = $$WhatPref\r", | |
" #TODO: add verbose messaging\r", | |
" #the timespan assumes an accurate clock on the remote computer\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$using:start) REMOTE ] Doing something remotely on $([System.Environment]::MachineName).\"\r", | |
"\r", | |
" \"[$([System.Environment]::MachineName)] Hello, World\"\r", | |
"\r", | |
" } #scriptblock\r", | |
"\r", | |
" #parameters to splat to Invoke-Command\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) BEGIN ] Defining parameters for Invoke-Command.\"\r", | |
"\r", | |
" #TODO: Update arguments as needed. This framework assumes any arguments are NOT coming through the pipeline and will be the same for all remote computers\r", | |
" #TODO: You will need to handle parameters like -WhatIf that you want to pass remotely\r", | |
"\r", | |
" $$icmParams = @{\r", | |
" Scriptblock = $$sb\r", | |
" Argumentlist = $$VerbosePreference, $$WhatIfPreference\r", | |
" HideComputerName = $$False\r", | |
" ThrottleLimit = $$ThrottleLimit\r", | |
" ErrorAction = \"Stop\"\r", | |
" Session = $$null\r", | |
" }\r", | |
"\r", | |
" #initialize an array to hold session objects\r", | |
" [System.Management.Automation.Runspaces.PSSession[]]$$All = @()\r", | |
"\r", | |
" If ($$Credential.username) {\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) BEGIN ] Using alternate credential for $($$credential.username).\"\r", | |
" }\r", | |
"\r", | |
" } #begin\r", | |
"\r", | |
" Process {\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) PROCESS] Detected parameter set $($$pscmdlet.ParameterSetName).\"\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) PROCESS] Detected PSBoundParameters:`n$($$PSBoundParameters | Out-String)\"\r", | |
"\r", | |
" $$remotes = @()\r", | |
" if ($$PSCmdlet.ParameterSetName -match \"computer|ssh\") {\r", | |
" if ($$pscmdlet.ParameterSetName -eq 'ssh') {\r", | |
" $$remotes += $$PSBoundParameters.HostName\r", | |
" $$param = \"HostName\"\r", | |
" }\r", | |
" else {\r", | |
" $$remotes += $$PSBoundParameters.ComputerName\r", | |
" $$param = \"ComputerName\"\r", | |
" }\r", | |
"\r", | |
" foreach ($$remote in $$remotes) {\r", | |
" $$PSBoundParameters[$$param] = $$remote\r", | |
" $$PSBoundParameters[\"ErrorAction\"] = \"Stop\"\r", | |
" Try {\r", | |
" #create a session one at a time to better handle errors\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) PROCESS] Creating a temporary PSSession to $$remote.\"\r", | |
" #save each created session to $$tmp so it can be removed at the end\r", | |
" #TODO: If your function will add parameters they will need to be removed from $$PSBoundParamters or you will need to adjust the the command to create the New-PSSession\r", | |
" $$all += New-PSSession @PSBoundParameters -OutVariable +tmp\r", | |
" } #Try\r", | |
" Catch {\r", | |
" #TODO: Decide what you want to do when the new session fails\r", | |
" Write-Warning \"Failed to create session to $remote. $($$_.Exception.Message).\"\r", | |
" #Write-Error $$_\r", | |
" } #catch\r", | |
" } #foreach remote\r", | |
" }\r", | |
" Else {\r", | |
" #only add open sessions\r", | |
" foreach ($$sess in $$session) {\r", | |
" if ($$sess.state -eq 'opened') {\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) PROCESS] Using session for $($$sess.ComputerName.toUpper()).\"\r", | |
" $$all += $$sess\r", | |
" } #if open\r", | |
" } #foreach session\r", | |
" } #else sessions\r", | |
" } #process\r", | |
"\r", | |
" End {\r", | |
"\r", | |
" $$icmParams[\"session\"] = $$all\r", | |
"\r", | |
" Try {\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) END ] Querying $($$all.count) computers.\"\r", | |
"\r", | |
" Invoke-Command @icmParams | ForEach-Object {\r", | |
" #TODO: PROCESS RESULTS FROM EACH REMOTE CONNECTION IF NECESSARY\r", | |
" $$_\r", | |
" } #foreach result\r", | |
" } #try\r", | |
" Catch {\r", | |
" Write-Error $$_\r", | |
" } #catch\r", | |
"\r", | |
" if ($$tmp) {\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) END ] Removing $($$tmp.count) temporary PSSessions.\"\r", | |
" $$tmp | Remove-PSSession\r", | |
" }\r", | |
" Write-Verbose \"[$(New-TimeSpan -start $$start) END ] Ending $($$myinvocation.mycommand)\"\r", | |
" } #end\r", | |
"} #close function" | |
], | |
"description": "Create a remoting based PowerShell function" | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This snippet is derived from https://gist.github.com/jdhitsolutions/5978a209cc912132ea2052a33a855327