OrchestratorServiceModule.psm1
################################################################### # Copyright (c) Microsoft. All rights reserved. # This code is licensed under the Microsoft Public License. # THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF # ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY # IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR # PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. ################################################################### Add-Type -AssemblyName System.Web #[reflection.assembly]::loadwithpartialname("system.web") # Web service resource records per page [int] $c_RecordsPerPage = 50 function Get-OrchestratorServiceUrl { ###################################################################################################################### # Get-OrchestratorServiceUrl # # Create a complete URL for the Orchestrator web service. # # Usage: # Get-OrchestratorServiceUrl -Server <string> [-Port <string>] [-Version <string>] [-Query <string>] [-UseSSL] ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [String] $Server, [Parameter(Mandatory=$false)] [String] $Port = "81", [Parameter(Mandatory=$false)] [String] $Version = "Orchestrator2012", [Parameter(Mandatory=$false)] [String] $Query = "", [Parameter(Mandatory=$false)] [Switch] $UseSSL ) #determine the protocol $protocol = $( if ($UseSSL) {"https"} else {"http"} ) if ($Query -ne "") { #assure $Query doesn't start with / $Query = $Query.Trim() if ($Query.StartsWith('/') -or $Query.StartsWith('\')) {$Query = $Query.Substring(1)} } return -join ($protocol,"://",$Server,":",$Port,"/",$Version,"/Orchestrator.svc/",$Query) } function Get-OrchestratorJob { ###################################################################################################################### # Get-OrchestratorJob # # Get a Job or collection of Jobs. # Each Job is a custom PS object that represents a Job entity. # # Usage: # Get-OrchestratorJob -ServiceUrl <string> [-JobId <guid>] [-Page <int>] [-MaxPages <int>] [-Credentials <credential>] # Get-OrchestratorJob -ServiceUrl <string> [-ServerId <guid>] [-Status <csv string>] [-Page <int>] [-MaxPages <int>] [-Credentials <credential>] # Get-OrchestratorJob -ServiceUrl <string> [-RunbookId <guid>] [-Status <csv string>] [-Page <int>] [-MaxPages <int>] [-Credentials <credential>] # Get-OrchestratorJob -ServiceUrl <string> [-Status <csv string>] [-Page <int>] [-MaxPages <int>] [-Credentials <credential>] ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [String] $ServiceUrl, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials, [Parameter(Mandatory=$false)] [System.Guid] $JobId, [Parameter(Mandatory=$false)] [System.Guid] $RunbookId, [Parameter(Mandatory=$false)] [System.Guid] $ServerId, [Parameter(Mandatory=$false)] [String] $Status, [Parameter(Mandatory=$false)] [Int] $Page = 0, [Parameter(Mandatory=$false)] [Int] $MaxPages = 10 ) # Create the Status part of the query $statusquery = "" if (-not [string]::IsNullOrEmpty($Status)) { $temparray = $Status -split "," for ($i = 0; $i -lt $temparray.Count; $i++) { if ($i -gt 0) { $statusquery += "%20or%20"} $statusquery += "Status%20eq%20'" + $temparray[$i] + "'" } } # Create the full query if ($JobId -ne $null) { # get a specific Job $query = -join ("Jobs(guid'",$JobId.ToString(),"')") } elseif ($ServerId -ne $null) { # get all Jobs on a specific runbook server [with specific status] $query = -join ("Jobs()?`$filter=RunbookServerId%20eq%20guid'",$ServerId.ToString(),"'") if (-not [string]::IsNullOrEmpty($statusquery)) { $query = -join ($query,"%20and%20(",$statusquery,")") } } elseif ($RunbookId -ne $null) { # get all Jobs for a specific runbook [with specific status] $query = -join ("Jobs()?`$filter=RunbookId%20eq%20guid'",$RunbookId.ToString(),"'") if (-not [string]::IsNullOrEmpty($statusquery)) { $query = -join ($query,"%20and%20(",$statusquery,")") } } else { # get all Jobs in the system [with specific status] $query = "Jobs()" if (-not [string]::IsNullOrEmpty($statusquery)) { $query = -join ($query,"?`$filter=",$statusquery) } } # Create the full url $url = $ServiceUrl + $query $jobarray = $null if ($Page -eq 0) { # Get Jobs in all pages up to MaxPages for ($pg = 1; $pg -le $MaxPages; $pg++) { $a = getOrchestratorJobPage -Url $url -Page $pg -Credentials $Credentials $jobarray += $a[0] $maxjobs = $a[1] $lastRecord = $pg * $c_RecordsPerPage if ($lastRecord -ge $maxjobs) { break; } # No more jobs to get, so exit the for loop } } elseif ($Page -ge 1) { # Get Jobs in a specific page $a = getOrchestratorJobPage -Url $url -Page $Page -Credentials $Credentials $jobarray = $a[0] } # Return the array of Job objects return $jobarray } function getOrchestratorJobPage { ###################################################################################################################### # getOrchestratorJobPage # # Get a Job or collection of Jobs for the particular page. # # Usage: # getOrchestratorJobPage -Url <string> -Page <int> [-Credentials <credential>] ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [String] $Url, [Parameter(Mandatory=$true)] [Int] $Page, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials ) # Is this request for single job? [bool] $isSingleJob = $Url.Contains("Jobs(guid") if (-not $isSingleJob) { # Add the page query to the url $joinchar = $( if ($Url.EndsWith("Jobs()")) {"?"} else {"&"} ) $Url = -join ($Url,$joinchar,$(getPageQuery $Page)) } # Call the service and get the xml doc with Job information [xml] $xmlDoc = sendHttpGetRequest -Url $Url -credentials $Credentials # How many total jobs are there (all pages) $jobscounttotal = $( if ($isSingleJob) {1} else {getResourceCount($xmlDoc)} ) $jobarray = $null if ( ((($Page - 1) * $c_RecordsPerPage) -lt $jobscounttotal) -or ($isSingleJob)) { # This page is within range # Get the collection of Job nodes $jobnodes = getEntryNodes $xmlDoc # Create a custom PSObject for each Job and add each Job to an array $jobarray = @() foreach ($jobnode in $jobnodes) { # Create a Job object and add it to the array $jobarray += getJobObject -JobNode $jobnode } if ($jobarray.Length -eq 0) { $jobarray = $null } } # Return the array of Job objects and the count of total Job objects possible for all pages return @($jobarray,$jobscounttotal) } function getJobObject { ############################################################################## # getJobObject # # From an "entry" node for a Job construct a PS custom object ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement] $JobNode ) # Get the links to related entities $servicebaseurl = getBaseServiceUrl $JobNode $linknodes = $JobNode.link foreach ($linknode in $linknodes) { switch($linknode.title) { "Runbook" {$runbookurl = $servicebaseurl + $linknode.href; break} "Instances" {$instancesurl = $servicebaseurl + $linknode.href; break} "RunbookServer" {$runbookserverurl = $servicebaseurl + $linknode.href; break} } } # Get the runbook parameters try { $parametersxml = [xml] $JobNode.Item("content").Item("m:properties").Item("d:Parameters").InnerText $parameternodes = $parametersxml.Item("Data").SelectNodes("Parameter") $parameterarray = @() foreach($pn in $parameternodes) { $id = $pn.Item("ID").InnerText $props = @{ 'Name' = $pn.Item("Name").InnerText 'Id' = $id.SubString(1,$id.Length - 2) 'Value' = $pn.Item("Value").InnerText } $parameterarray += New-Object PSObject -Property $props } } catch { $parameterarray = $null } # Create the properties $propnode = $JobNode.Item("content").Item("m:properties") $properties = @{ 'Url_Service' = $servicebaseurl 'Parameters' = $parameterarray 'Url_Runbook' = $runbookurl 'Url_RunbookInstances' = $instancesurl 'Url_RunbookServer' = $runbookserverurl 'Url' = $JobNode.id 'Published' = $JobNode.published 'Updated' = $JobNode.updated 'Category' = $JobNode.category.term 'Id' = $propnode.Item("d:Id").InnerText 'RunbookId' = $propnode.Item("d:RunbookId").InnerText 'RunbookServers' = $propnode.Item("d:RunbookServers").InnerText 'RunbookServerId' = $propnode.Item("d:RunbookServerId").InnerText 'Status' = $propnode.Item("d:Status").InnerText 'ParentId' = $propnode.Item("d:ParentId").InnerText 'ParentIsWaiting' = [bool]$propnode.Item("d:ParentIsWaiting").InnerText 'CreatedBy' = $propnode.Item("d:CreatedBy").InnerText 'CreationTime' = $propnode.Item("d:CreationTime").InnerText 'LastModifiedBy' = $propnode.Item("d:LastModifiedBy").InnerText 'LastModifiedTime' = $propnode.Item("d:LastModifiedTime").InnerText } # Return the Job object $jobobject = New-Object PSObject -Property $properties return $jobobject } function Get-OrchestratorRunbookInstance { ###################################################################################################################### # Get-OrchestratorRunbookInstance # # Get a RunbookInstance or collection of RunbookInstance associated with a Job. # The RunbookInstance is a custom PS object that represents a RunbookInstance resource. # # Note: No paging enabled; so get up to 50 instances (the web service limit per page). # # Usage: # Get-OrchestratorRunbookInstance -Job <PSObject> [-Credentials <credential>] ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [PSObject] $Job, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials ) # Call the service and get the xml doc with RunbookInstance information [xml] $xmlDoc = sendHttpGetRequest -url $Job.Url_RunbookInstances -credentials $Credentials # Get the collection of RunbookInstance nodes $instancenodes = getEntryNodes $xmlDoc if ($instancenodes -ne $null) { # Create a custom PSObject for each RunbookInstance and add each to an array $instancearray = @() foreach ($instancenode in $instancenodes) { # Create a Job object and add it to the array $instancearray += getRunbookInstanceObject -InstanceNode $instancenode } # Return the array of Instance objects if ($instancearray.Length -eq 0) { $instancearray = $null } return $instancearray } else { # There are no Instances return $null } } function getRunbookInstanceObject { ############################################################################## # getRunbookInstanceObject # # From an "entry" node for a RunbookInstance construct a PS custom object ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement] $InstanceNode ) # Get the links to related entities $url_service = getBaseServiceUrl $InstanceNode $linknodes = $InstanceNode.link foreach ($linknode in $linknodes) { switch($linknode.title) { "Runbook" {$url_runbook = $url_service + $linknode.href; break} "Job" {$url_job = $url_service + $linknode.href; break} "Parameters" {$url_parameters = $url_service + $linknode.href; break} "ActivityInstances" {$url_activityinstances = $url_service + $linknode.href; break} "RunbookServer" {$url_runbookserver = $url_service + $linknode.href; break} } } # Create the properties $propnode = $InstanceNode.Item("content").Item("m:properties") $properties = @{ 'Url_Service' = $url_service 'Url_Runbook' = $url_runbook 'Url_Job' = $url_job 'Url_Parameters' = $url_parameters 'Url_ActivityInstances' = $url_activityinstances 'Url_RunbookServer' = $url_runbookserver 'Url' = $InstanceNode.id 'Published' = $InstanceNode.published 'Updated' = $InstanceNode.updated 'Category' = $InstanceNode.category.term 'Id' = $propnode.Item("d:Id").InnerText 'RunbookId' = $propnode.Item("d:RunbookId").InnerText 'JobId' = $propnode.Item("d:JobId").InnerText 'RunbookServerId' = $propnode.Item("d:RunbookServerId").InnerText 'Status' = $propnode.Item("d:Status").InnerText 'CreationTime' = $propnode.Item("d:CreationTime").InnerText 'CompletionTime' = $propnode.Item("d:CompletionTime").InnerText } # Return the Instance object $instanceobject = New-Object PSObject -Property $properties return $instanceobject } function Get-OrchestratorRunbookInstanceParameter { ###################################################################################################################### # Get-OrchestratorRunbookInstanceParameter # # Get a RunbookInstanceParameter or collection of RunbookInstanceParameter associated with a RunbookInstance. # The RunbookInstanceParameter is a custom PS object that represents a RunbookInstanceParameter resource. # # Usage: # Get-OrchestratorRunbookInstanceParameter -RunbookInstance <PSObject> [-Credentials <credential>] ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [PSObject] $RunbookInstance, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials ) # Call the service and get the xml doc with RunbookInstance information [xml] $xmlDoc = sendHttpGetRequest -url $RunbookInstance.Url_Parameters -credentials $Credentials # Get the collection of RunbookInstanceParameter nodes $paramnodes = getEntryNodes $xmlDoc if ($paramnodes -ne $null) { # Create a custom PSObject for each RunbookInstance and add each to an array $paramarray = @() foreach ($paramnode in $paramnodes) { # Create a Job object and add it to the array $paramarray += getRunbookInstanceParameterObject -InstanceParameterNode $paramnode } # Return the array of RunbookInstanceParameter objects if ($paramarray.Length -eq 0) { $paramarray = $null } return $paramarray } else { # There are no RunbookInstanceParameter return $null } } function getRunbookInstanceParameterObject { ############################################################################## # getRunbookInstanceParameterObject # # From an "entry" node for a RunbookInstanceParameter construct a PS custom object ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement] $InstanceParameterNode ) # Get the links to related entities $url_service = getBaseServiceUrl $InstanceParameterNode $linknodes = $InstanceParameterNode.link foreach ($linknode in $linknodes) { switch($linknode.title) { "RunbookInstance" {$url_runbookinstance = $url_service + $linknode.href; break} "RunbookParameter" {$url_runbookparameter = $url_service + $linknode.href; break} } } # Create the properties $propnode = $InstanceParameterNode.Item("content").Item("m:properties") $properties = @{ 'Url_Service' = $url_service 'Url_RunbookInstance' = $url_runbookinstance 'Url_RunbookParameter' = $url_runbookparameter 'Url' = $InstanceParameterNode.id 'Updated' = $InstanceParameterNode.updated 'Category' = $InstanceParameterNode.category.term 'Id' = $propnode.Item("d:Id").InnerText 'RunbookInstanceId' = $propnode.Item("d:RunbookInstanceId").InnerText 'RunbookParameterId' = $propnode.Item("d:RunbookParameterId").InnerText 'Name' = $propnode.Item("d:Name").InnerText 'Value' = $propnode.Item("d:Value").InnerText 'Direction' = $propnode.Item("d:Direction").InnerText 'GroupId' = $propnode.Item("d:GroupId").InnerText } # Return the Instance object $instanceobject = New-Object PSObject -Property $properties return $instanceobject } function Get-OrchestratorRunbook { ###################################################################################################################### # Get-OrchestratorRunbook # # Get a Runbook or collection of Runbooks. # Each Runbook is a custom PS object that represents a Runbook entity. # # Usage: # Get-OrchestratorRunbook -ServiceUrl <string> [-Credentials <credentials>] [-RunbookId <guid>] [-Page <int>] [-MaxPages <int>] # Get-OrchestratorRunbook -ServiceUrl <string> [-Credentials <credentials>] [-RunbookPath <string>] [-Page <int>] [-MaxPages <int>] ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [String] $ServiceUrl, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials, [Parameter(Mandatory=$false)] [System.Guid] $RunbookId, [Parameter(Mandatory=$false)] [String] $RunbookPath, [Parameter(Mandatory=$false)] [Int] $Page = 0, [Parameter(Mandatory=$false)] [Int] $MaxPages = 10 ) # Form full URL if ($RunbookId -ne $null) { # Url for getting a single runbook by its id $url = -join ($ServiceUrl,"Runbooks(guid'",$RunbookId.ToString(),"')") # Page will be 1 $Page = 1 } elseif (($RunbookPath -ne $null) -and ($RunbookPath.Length -gt 0)) { # Form the query $query = -join ("`$filter=startswith(Path,'",$RunbookPath.ToString(),"')") #$query = -join ("`$filter=Path eq '",$RunbookPath.ToString(),"'") $query = [System.Web.HttpUtility]::UrlPathEncode($query) # Url for getting one or more runbooks by path $url = -join ($ServiceUrl,"Runbooks()?",$query) } else { # Url for all runbooks $url = $ServiceUrl + "Runbooks()" } Write-Host "url = " $url ### Handle paging $rbarray = $null if ($Page -eq 0) { # Get Runbooks in all pages up to MaxPages for ($pg = 1; $pg -le $MaxPages; $pg++) { $a = getOrchestratorRunbookPage -Url $url -Page $pg -Credentials $Credentials $rbarray += $a[0] $maxrbs = $a[1] $lastRecord = $pg * $c_RecordsPerPage if ($lastRecord -ge $maxrbs) { break; } # No more jobs to get, so exit the for loop } } elseif ($Page -ge 1) { # Get Runbooks in a specific page $a = getOrchestratorRunbookPage -Url $url -Page $Page -Credentials $Credentials $rbarray = $a[0] } # Return the array of Runbook objects return $rbarray } function getOrchestratorRunbookPage { ###################################################################################################################### # getOrchestratorRunbookPage # # Get a Runbook or collection of Runbooks for a particular page # # Usage: # getOrchestratorRunbookPage -Url <string> -Page <int> [-Credentials <credentials>] ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [String] $Url, [Parameter(Mandatory=$true)] [Int] $Page, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials ) # Is this request for single runbook? $isSingleRunbook = $Url.Contains("Runbooks(guid") if (-not $isSingleRunbook) { # Add the page query to the url $joinchar = $( if ($Url.EndsWith("Runbooks()")) {"?"} else {"&"} ) $Url = -join ($Url,$joinchar,$(getPageQuery $Page)) } # Call the service and get the xml doc with Runbook records [xml] $xmlDoc = sendHttpGetRequest -url $Url -credentials $Credentials # How many total runbooks are there (all pages) $rbcounttotal = $( if($isSingleRunbook) {1} else {getResourceCount($xmlDoc)} ) $rbarray = $null if ( ((($Page - 1) * $c_RecordsPerPage) -lt $rbcounttotal) -or $isSingleRunbook ) { # This page is within range # Get the Runbook nodes $rbnodes = getEntryNodes $xmlDoc # Create a custom PSObject for each Runbook and add each Runbook to an array $rbarray = @() foreach ($rbnode in $rbnodes) { # Create a Runbook object and add it to the array $rbarray += getRunbookObject $rbnode } if ($rbarray.Length -eq 0) { $rbarray = $null } } # Return the array of Runbook objects and the count of total Runbook objects possible for all pages return @($rbarray,$rbcounttotal) } function getRunbookObject { ############################################################################## # getRunbookObject # # From an "entry" node for a Runbook construct a PS custom object # # Usage: # getRunbookObject -RbNode <xmlelement> ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement] $RbNode ) # Get the links to related entities $servicebaseurl = getBaseServiceUrl $RbNode $linknodes = $RbNode.link foreach ($linknode in $linknodes) { switch($linknode.title) { "Folder" {$folderurl = $servicebaseurl + $linknode.href; break} "Parameters" {$parametersurl = $servicebaseurl + $linknode.href; break} "Activities" {$activitiesurl = $servicebaseurl + $linknode.href; break} "Jobs" {$jobsurl = $servicebaseurl + $linknode.href; break} "Instances" {$instancesurl = $servicebaseurl + $linknode.href; break} "Diagram" {$diagramurl = $servicebaseurl + $linknode.href; break} } } # Get the runbook parameters (Name, Id, Type, Description) # # Call the service to get Parameters info for this runbook $pmurl = $parametersurl [xml] $xmlDoc = sendHttpGetRequest -url $pmurl # # Get the Parameter nodes $pmnodes = getEntryNodes $xmlDoc # # If there are parameters then get the info if ($pmnodes -ne $null) { $parameterarray = @() foreach($pn in $pmnodes) { $parameterarray += getRunbookParameterObject $pn } } else { # No parameters, so set to null $parameterarray = $null } $propnode = $RbNode.Item("content").Item("m:properties") $properties = @{ 'Url_Service' = $servicebaseurl 'Parameters' = $parameterarray 'Url_Folder' = $folderurl 'Url_Parameters' = $parametersurl 'Url_Activities' = $activitiesurl 'Url_Jobs' = $jobsurl 'Url_Instances' = $instancesurl 'Url_Diagram' = $diagramurl 'Url' = $RbNode.id 'Published' = $RbNode.published 'Updated' = $RbNode.updated 'Category' = $RbNode.category.term 'Name' = $propnode.Item("d:Name").InnerText 'Id' = $propnode.Item("d:Id").InnerText 'FolderId' = $propnode.Item("d:FolderId").InnerText 'Description' = $propnode.Item("d:Description").InnerText 'CreatedBy' = $propnode.Item("d:CreatedBy").InnerText 'CreationTime' = $propnode.Item("d:CreationTime").InnerText 'LastModifiedBy' = $propnode.Item("d:LastModifiedBy").InnerText 'LastModifiedTime' = $propnode.Item("d:LastModifiedTime").InnerText 'IsMonitor' = [System.Convert]::ToBoolean($propnode.Item("d:IsMonitor").InnerText) 'Path' = $propnode.Item("d:Path").InnerText 'CheckedOutBy' = $propnode.Item("d:CheckedOutBy").InnerText 'CheckedOutTime' = $propnode.Item("d:CheckedOutTime").InnerText } $rbobject = New-Object PSObject -Property $properties return $rbobject } function getRunbookParameterObject { ############################################################################## # getRunbookParameterObject # # From an "entry" node for a Runbook Parameter construct a PS custom object # # Usage: # getRunbookParameterObject -RbParamNode <xmlelement> ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement] $RbParamNode ) # Get the links to related entities $servicebaseurl = getBaseServiceUrl $RbParamNode $linknodes = $RbParamNode.link foreach ($linknode in $linknodes) { switch($linknode.title) { "Runbook" {$runbookurl = $servicebaseurl + $linknode.href; break} "Instances" {$instancesurl = $servicebaseurl + $linknode.href; break} } } # Create the properties $properties = @{ 'RunbookUrl' = $runbookurl 'InstancesUrl' = $instancesurl 'Url' = $RbParamNode.id 'Updated' = $RbParamNode.updated 'Category' = $RbParamNode.category.term 'Id' = $RbParamNode.Item("content").Item("m:properties").Item("d:Id").InnerText 'RunbookId' = $RbParamNode.Item("content").Item("m:properties").Item("d:RunbookId").InnerText 'Name' = $RbParamNode.Item("content").Item("m:properties").Item("d:Name").InnerText 'Type' = $RbParamNode.Item("content").Item("m:properties").Item("d:Type").InnerText 'Description' = $RbParamNode.Item("content").Item("m:properties").Item("d:Description").InnerText 'Direction' = $RbParamNode.Item("content").Item("m:properties").Item("d:Direction").InnerText } # Return the RunbookParameter object $rbpobject = New-Object PSObject -Property $properties return $rbpobject } function Stop-OrchestratorJob { ############################################################################## # Stop-OrchestratorJob # # Stop a Job # # Usage: # Stop-OrchestratorJob -Job <job> [-Credentials <credentials>] ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [PSObject] $Job, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials ) process { # Continue only if the Job is not already stopped if (-not ( ($Job.Status -eq "Pending") -or ($Job.Status -eq "Running") ) ) { return $false } # # Create the request object # $request = [System.Net.HttpWebRequest]::Create($Job.Url) # Set the credentials if ($Credentials -eq $null) { $request.UseDefaultCredentials = $true } else { $request.Credentials = $Credentials } $request.Timeout = 36000 # Build the request header $request.Method = "POST" $request.UserAgent = getUserAgent $request.Accept = "application/atom+xml,application/xml" $request.ContentType = "application/atom+xml" $request.KeepAlive = $true $request.Headers.Add("Accept-Encoding","identity") $request.Headers.Add("Accept-Language","en-US") $request.Headers.Add("DataServiceVersion","1.0;NetFx") $request.Headers.Add("MaxDataServiceVersion","3.0;NetFx") $request.Headers.Add("Pragma","no-cache") # Add header properties specific for Stop Job $request.Headers.Add("X-HTTP-Method","MERGE") # this is the LastModifiedTime $lastmodifiedtime = $Job.LastModifiedTime # change ":" to "%3A" $lmtime = $lastmodifiedtime.Replace(":","%3A") $tempstring = -join ("W/" , '"' , "datetime'" , $lmtime , "'" , '"') $request.Headers.Add("If-Match",$tempstring) # # Build the request body # # First request the job from the Orchestrator service and get the raw response that we will modify # Call the service and get the xml doc with Job information [xml] $jobxml = sendHttpGetRequest -url $Job.Url -credentials $credentials # Set <published> to CreationTime $jobxml.DocumentElement.Item("published").InnerText = $Job.CreationTime + "Z" # Set <updated> to LastModifiedTime $jobxml.DocumentElement.Item("updated").InnerText = $Job.LastModifiedTime + "Z" # Set <d:Status> to "Canceled" (this is what stops the Job) $jobxml.DocumentElement.Item("content").Item("m:properties").Item("d:Status").InnerText = "Canceled" # Remove the <link> nodes $linknode = $jobxml.DocumentElement.Item("link") while ($linknode -ne $null) { $jobxml.DocumentElement.RemoveChild($linknode) $linknode = $jobxml.DocumentElement.Item("link") } # Execute the service request and get the response [System.Net.HttpWebResponse]$response = sendHttpPostRequest -Request $request -RequestBody $jobxml.get_outerxml() return ($response.StatusCode -eq "NoContent") } } function Start-OrchestratorRunbook { ############################################################################## # Start-OrchestratorRunbook # # Start an instance of a runbook # # Usage: # Start-OrchestratorRunbook -Runbook <runbook> [-Credentials <credentials>] [-Parameters <hashtable>] [-RunbookServers <csv string>] ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [PSObject] $Runbook, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials, [Parameter(Mandatory=$false)] [String] $RunbookServers, [Parameter(Mandatory=$false)] [hashtable] $Parameters ) # If this is monitor runbook, assure it does not already have a job if ($Runbook.IsMonitor) { Write-Host "Runbook.IsMonitor = " $Runbook.IsMonitor $monjob = Get-OrchestratorJob -runbookid $Runbook.Id -status "Running,Pending" -serviceurl $Runbook.Url_Service -credentials $Credentials if ($monjob -ne $null) { Write-Host "Monitor already has running job: " $monjob.Id return $null } } # Create the request object $request = [System.Net.HttpWebRequest]::Create($Runbook.Url_Service + "Jobs") # Set the credentials if ($Credentials -eq $null) { $request.UseDefaultCredentials = $true } else { $request.Credentials = $Credentials } $request.Timeout = 36000 # Build the request header $request.Method = "POST" $request.UserAgent = getUserAgent $request.Accept = "application/atom+xml,application/xml" $request.ContentType = "application/atom+xml" $request.KeepAlive = $true $request.Headers.Add("Accept-Encoding","identity") $request.Headers.Add("Accept-Language","en-US") $request.Headers.Add("DataServiceVersion","1.0;NetFx") $request.Headers.Add("MaxDataServiceVersion","2.0;NetFx") $request.Headers.Add("Pragma","no-cache") # Get the RunbookId $rbid = $Runbook.Id # Format the RunbookServers string, if any $rbserverstring = "" if (-not [string]::IsNullOrEmpty($RunbookServers)) { $rbserverstring = -join ("<d:RunbookServers>",$RunbookServers,"</d:RunbookServers>") } # Format the Runbook parameters, if any $rbparamstring = "" if ($Parameters -ne $null) { # Format the param string from the Parameters hashtable $rbparamstring = "<d:Parameters><Data>" foreach ($p in $Parameters.GetEnumerator()) { $rbparamstring = -join ($rbparamstring,"<Parameter><ID>{",$p.key,"}</ID><Value>",$p.value,"</Value></Parameter>") } $rbparamstring += "</Data></d:Parameters>" } # Build the request body $requestBody = @" <?xml version="1.0" encoding="utf-8" standalone="yes"?> <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom"> <content type="application/xml"> <m:properties> <d:RunbookId m:type="Edm.Guid">$rbid</d:RunbookId> $rbserverstring $rbparamstring </m:properties> </content> </entry> "@ # Execute the service request and get the response $response = sendHttpPostRequest -Request $request -RequestBody $requestBody $job = $null if ($response -ne $null) { # Get the response xml with the Job node $responseXml = getResponseXml $response $response.Close() $jobnode = getEntryNodes $responseXml # Return the Job that was created $job = getJobObject $jobnode } return $job } function Get-OrchestratorCollection { ###################################################################################################################### # Get-OrchestratorCollection # # Get an array list with all of the collections exposed by the Orchestrator OData web service. # Each collection object contains the Title and Url properties. # # Usage: # Get-OrchestratorCollection -ServiceUrl <string> [-Credentials <credentials>] ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string] $ServiceUrl, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials ) # Get the service page xml document from the service [xml] $xmlDoc = sendHttpGetRequest -url $ServiceUrl -credentials $Credentials # Get the "collection" xml nodes (/service/workspace/collection) $collectionnodes = $xmlDoc.service.workspace.collection if ($collectionnodes -ne $null) { # Create an array that will hold all the xml collection nodes $collectionarray = @() # Create a custom PSObject for each collection and add each to the array foreach ($collectionnode in $collectionnodes) { $properties = @{ 'Title' = $collectionnode.title 'Url' = $ServiceUrl + $collectionnode.href } $collectionarray += New-Object PSObject -Property $properties } # Return the array of collection objects return $collectionarray } else { # No collections, so return null return $null } } function Get-Credentials { [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [string] $Domain, [Parameter(Mandatory=$true)] [string] $Username, [Parameter(Mandatory=$false)] [string] $Password ) if (-not([string]::IsNullOrEmpty($Password))) { return New-Object System.Net.NetworkCredential($Username,$Password,$Domain) } else { $credential = $Domain + "\" + $Username return Get-Credential -Credential $credential } } function getEntryNodes { ###################################################################################################################### # getEntryNodes # # Get the "entry" XmlElement or collection of XmlElement from the XML doc returned by the Orchestrator OData web service # Returns null if no nodes are found # # Usage: # getEntryNodes -XmlDoc <xmldoc> ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [xml] $XmlDoc ) $ns = New-Object Xml.XmlNamespaceManager $XmlDoc.NameTable $ns.AddNamespace( "a", "http://www.w3.org/2005/Atom") $ns.AddNamespace( "d", "http://schemas.microsoft.com/ado/2007/08/dataservices") $ns.AddNamespace( "m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") $entryNodes = $XmlDoc.SelectNodes("//a:entry",$ns) return $entryNodes } function getUserAgent { ###################################################################################################################### # getUserAgent # # Usage: # getUserAgent ###################################################################################################################### $UserAgent = "PowerShell API Client" return $( "{0} (PowerShell {1}; .NET CLR {2}; {3})" -f $UserAgent, $(if($Host.Version){$Host.Version}else{"1.0"}), [Environment]::Version, [Environment]::OSVersion.ToString().Replace("Microsoft Windows ", "Win") ) } function sendHttpGetRequest { ###################################################################################################################### # sendHttpGetRequest # # Make an HTTP Get request to a web site. # # Usage: # sendHttpGetRequest -Urlstring <string> [-Credentials <credential>] ###################################################################################################################### [CmdletBinding()] PARAM ( [Parameter(Mandatory=$true)] [String] $Urlstring, [Parameter(Mandatory=$false)] [System.Net.NetworkCredential] $Credentials ) # Create a request object $request = [System.Net.HttpWebRequest]::Create($Urlstring) # Set the credentials if ($Credentials -eq $null) { $request.UseDefaultCredentials = $true } else { $request.Credentials = $Credentials } # Build the User Agent $request.UserAgent = getUserAgent try { $response = [System.Net.HttpWebResponse] $Request.GetResponse() } catch [System.Net.WebException] { Write-Host "Exception occurred in $($MyInvocation.MyCommand): `n$($_.Exception.Message)" Write-Host "Response = " $response = $($_.Exception.Response) # Show the response with the error information if ($response.ContentLength -gt 0) { $reader = [IO.StreamReader] $response.GetResponseStream() $output = $reader.ReadToEnd() $reader.Close() Write-Host $output Write-Host "" } $response = $null } finally { $output = $null if (($response -ne $null) -and ($response.ContentLength -gt 0)) { $reader = [IO.StreamReader] $response.GetResponseStream() $output = $reader.ReadToEnd() [xml]$output = $output $reader.Close() } $response.Close() Write-Output $output } } function sendHttpPostRequest { ############################################################################## # sendHttpPostRequest # # Usage: # sendHttpPostRequest -Request <HttpWebRequest> -RequestBody <string> ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Net.HttpWebRequest] $Request, [Parameter(Mandatory=$true)] [string] $RequestBody ) # Add the body to the request $requeststream = new-object System.IO.StreamWriter $Request.GetRequestStream() # The Write method sends the request $requeststream.Write($RequestBody) $requeststream.Flush() $requeststream.Close() try { [System.Net.HttpWebResponse] $response = [System.Net.HttpWebResponse] $Request.GetResponse() } catch [System.Net.WebException] { Write-Host "Exception occurred in $($MyInvocation.MyCommand): `n$($_.Exception.Message)" Write-Host "Response = " $response = $($_.Exception.Response) if ($response.ContentLength -gt 0) { $reader = [IO.StreamReader] $response.GetResponseStream() $output = $reader.ReadToEnd() $reader.Close() Write-Host $output Write-Host "" } $response.Close() $response = $null } finally { Write-Output $response } } function getResponseXml { ###################################################################################################################### # getResponseXml ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Net.HttpWebResponse] $Response ) # Write the HttpWebResponse to String $responseStream = $Response.GetResponseStream() $readStream = new-object System.IO.StreamReader $responseStream $responseString = $readStream.ReadToEnd() # Close the streams $readStream.Close() $responseStream.Close() # Return the response as xml return [xml] $responseString } function getResourceCount { ###################################################################################################################### # getResourceCount # # Get the count of total resources from the XML doc returned by the Orchestrator OData web service # Returns null if no count node is found # # Usage: # getResourceCount -XmlDoc <xmldoc> ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [xml] $XmlDoc ) $ns = New-Object Xml.XmlNamespaceManager $XmlDoc.NameTable $ns.AddNamespace( "a", "http://www.w3.org/2005/Atom") $ns.AddNamespace( "d", "http://schemas.microsoft.com/ado/2007/08/dataservices") $ns.AddNamespace( "m", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata") $countNode = $XmlDoc.SelectSingleNode("//m:count",$ns) $count = $null if ($countNode -ne $null) { $count = $countNode.InnerText } Write-Host "count = " $count return $count } function getBaseServiceUrl { ############################################################################## # getBaseServiceUrl # # From an "entry" node get the base service URL ############################################################################## [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [System.Xml.XmlElement] $EntryNode ) $baseurl = $JobNode.base if ($baseurl -eq $null) { $s = "Orchestrator.svc/" $baseurl = $EntryNode.id $index = $baseurl.IndexOf($s) $baseurl = $baseurl.substring(0,$index + $s.Length) } return $baseurl } function getPageQuery { ###################################################################################################################### # getPageQuery # # Get a query string for a particular page # # Usage: # getPageQuery -Page <int> ###################################################################################################################### [CmdletBinding()] param ( [Parameter(Mandatory=$true)] [Int] $Page ) # Create the page query if ($Page -le 0) {$Page = 1} $skipcount = ($Page - 1) * $c_RecordsPerPage return -join ("`$skip=",$skipcount,"&`$top=",$c_RecordsPerPage,"&`$inlinecount=allpages") } ## Export the functions Export-ModuleMember -Function Get-OrchestratorServiceUrl Export-ModuleMember -Function Get-OrchestratorCollection Export-ModuleMember -Function Get-OrchestratorJob Export-ModuleMember -Function Get-OrchestratorRunbook Export-ModuleMember -Function Get-OrchestratorRunbookInstance Export-ModuleMember -Function Get-OrchestratorRunbookInstanceParameter Export-ModuleMember -Function Stop-OrchestratorJob Export-ModuleMember -Function Start-OrchestratorRunbook Export-ModuleMember -Function Get-Credentials |