How to add a Environment Scope and Deployment Target Scope to a variable in OctopusDeploy - octopus-deploy

I have to generate a variable dynamically and set it to the variable list using Octopus Deploy REST API.
I don't know how to set the Environment Scope and Deployment Scope to that variable for different values.
Example - ENV_NAME -> [dev,sit,uat,prod - are values for ENV scope (dev,sit,uat,prod) and roles (x,y,z)] etc
How to set the corresponding values for each scope using Octopus REST API
Below is what I have to set the variable name and values
$variableList = #(
#{
Name = "API_ID"
Value = $api_id
Type = "String"
IsSensitive = $false
}
)
# Get space
$space = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/spaces/all" -Headers $header) | Where-Object {$_.Name -eq $spaceName}
# Get project
$project = (Invoke-RestMethod -Method Get -Uri "$octopusURL/api/$($space.Id)/projects/all" -Headers $header) | Where-Object {$_.Name -eq $projectName}
# Get project variables
$projectVariables = Invoke-RestMethod -Method Get -Uri "$octopusURL/api/$($space.Id)/variables/$($project.VariableSetId)" -Headers $header
foreach($variable in $variableList){
# Check to see if variable is already present
$variableToUpdate = $projectVariables.Variables | Where-Object {$_.Name -eq $variable.Name}
if ($null -eq $variableToUpdate)
{
# Create new object
$variableToUpdate = New-Object -TypeName PSObject
$variableToUpdate | Add-Member -MemberType NoteProperty -Name "Name" -Value $variable.Name
$variableToUpdate | Add-Member -MemberType NoteProperty -Name "Value" -Value $variable.Value
$variableToUpdate | Add-Member -MemberType NoteProperty -Name "Type" -Value $variable.Type
$variableToUpdate | Add-Member -MemberType NoteProperty -Name "IsSensitive" -Value $variable.IsSensitive
# Add to collection
$projectVariables.Variables += $variableToUpdate
$projectVariables.Variables
}
# Update the value
$variableToUpdate.Value = $variable.Value
}
# Update the collection
Invoke-RestMethod -Method Put -Uri "$octopusURL/api/$($space.Id)/variables/$($project.VariableSetId)" -Headers $header -Body ($projectVariables | ConvertTo-Json -Depth 10)

The OctopusDeploy-Api repo contains many sample scripts.
ModifyOrAddVariableToProject.ps1 does almost exactly what you are attempting to do here.
Two things to note, environment scopes have to be the Id of the environment, not the name as shown here, but roles can just be any string, under the scope type of Roles.
If you are trying to scope a variable to the deployment process, then the scope type is ProcessOwner and the value would be the Project Id, or to scope to a runbook it would be the Runbook Id.

Related

Is it possible to have powershell curl output only the content part? [duplicate]

In PowerShell, how do you get an object's property value by specifying its name (a string)? I want something like the following:
$obj = get-something
# View the object's members:
$obj | gm
# I could retrieve a property by doing so:
write-host $obj.SomeProp
# But for many purposes, I would really want to:
write-host $obj | Get-PropertyByName "SomeProp"
Is there something similar to "Get-PropertyByName" in PowerShell?
Sure
write-host ($obj | Select -ExpandProperty "SomeProp")
Or for that matter:
$obj."SomeProp"
Expanding upon #aquinas:
Get-something | select -ExpandProperty PropertyName
or
Get-something | select -expand PropertyName
or
Get-something | select -exp PropertyName
I made these suggestions for those that might just be looking for a single-line command to obtain some piece of information and wanted to include a real-world example.
In managing Office 365 via PowerShell, here was an example I used to obtain all of the users/groups that had been added to the "BookInPolicy" list:
Get-CalendarProcessing conferenceroom#example.com | Select -expand BookInPolicy
Just using "Select BookInPolicy" was cutting off several members, so thank you for this information!
You can get a property by name using the Select-Object cmdlet and specifying the property name(s) that you're interested in. Note that this doesn't simply return the raw value for that property; instead you get something that still behaves like an object.
[PS]> $property = (Get-Process)[0] | Select-Object -Property Name
[PS]> $property
Name
----
armsvc
[PS]> $property.GetType().FullName
System.Management.Automation.PSCustomObject
In order to use the value for that property, you will still need to identify which property you are after, even if there is only one property:
[PS]> $property.Name
armsvc
[PS]> $property -eq "armsvc"
False
[PS]> $property.Name -eq "armsvc"
True
[PS]> $property.Name.GetType().FullName
System.String
As per other answers here, if you want to use a single property within a string, you need to evaluate the expression (put brackets around it) and prefix with a dollar sign ($) to declare the expression dynamically as a variable to be inserted into the string:
[PS]> "The first process in the list is: $($property.Name)"
The first process in the list is: armsvc
Quite correctly, others have answered this question by recommending the -ExpandProperty parameter for the Select-Object cmdlet. This bypasses some of the headache by returning the value of the property specified, but you will want to use different approaches in different scenarios.
-ExpandProperty <String>
Specifies a property to select, and indicates that an attempt should
be made to expand that property
https://technet.microsoft.com/en-us/library/hh849895.aspx
[PS]> (Get-Process)[0] | Select-Object -ExpandProperty Name
armsvc
powershell variables
Try this :
$obj = #{
SomeProp = "Hello"
}
Write-Host "Property Value is $($obj."SomeProp")"
Here is an alternative way to get an object's property value:
write-host $(get-something).SomeProp
$com1 = new-object PSobject #Task1
$com2 = new-object PSobject #Task1
$com3 = new-object PSobject #Task1
$com1 | add-member noteproperty -name user -value jindpal #Task2
$com1 | add-member noteproperty -name code -value IT01 #Task2
$com1 | add-member scriptmethod ver {[system.Environment]::oSVersion.Version} #Task3
$com2 | add-member noteproperty -name user -value singh #Task2
$com2 | add-member noteproperty -name code -value IT02 #Task2
$com2 | add-member scriptmethod ver {[system.Environment]::oSVersion.Version} #Task3
$com3 | add-member noteproperty -name user -value dhanoa #Task2
$com3 | add-member noteproperty -name code -value IT03 #Task2
$com3 | add-member scriptmethod ver {[system.Environment]::oSVersion.Version} #Task3
$arr += $com1, $com2, $com3 #Task4
write-host "windows version of computer1 is: "$com1.ver() #Task3
write-host "user name of computer1 is: "$com1.user #Task6
write-host "code of computer1 is: "$com1,code #Task5
write-host "windows version of computer2 is: "$com2.ver() #Task3
write-host "user name of computer2 is: "$com2.user #Task6
write-host "windows version of computer3 is: "$com3.ver() #Task3
write-host "user name of computer3 is: "$com1.user #Task6
write-host "code of computer3 is: "$com3,code #Task5
read-host

Automatic select only member in the object list

Is there a way to automatically address/select the only member in a object?
In my case the 3rd level member jobf can vary. But on that level it will always only have one member.
### get aeObject ###
try {
$response = Invoke-RestMethod -Method GET -Uri "$client_id/objects/$($i -replace "#","%23")" -Headers $header
}
catch {
Write-Error -Message "$($_.Exception.Message)"
$Error[0] | Format-List -Force
}
### modify JSON and import it ###
$JSON = $response | ConvertTo-Json -Depth 100 | ConvertFrom-Json
$JSON.data
if ($JSON.data.jobf.general_attributes.time_zone) {
$JSON.data.jobf.general_attributes.time_zone = "$TZ"
}
else {
$JSON.data.jobf.general_attributes | Add-Member -Name "time_zone" -MemberType NoteProperty -Value "$TZ"
}
enter image description here
You can use Get-Member to iterate the members at the third level, then filter out the noise and select the name of the first (and only one) member.
# Get the third level single item (eg: jobf, jobx, etc)
$Job = ($JSON.data | Get-Member -MemberType NoteProperty | Select-Object -First 1).Name
# Instead of "jobf", we use the value stored in $Job
if ($JSON.data.$Job.general_attributes.time_zone) {
$JSON.data.$Job.general_attributes.time_zone = "$TZ"
}
else {
$JSON.data.$Job.general_attributes | Add-Member -Name "time_zone" -MemberType NoteProperty -Value "$TZ"
}
References
Get-Member - Gets the properties and methods of objects.

How can i get an overview of UWP registered URIs and aliases?

I want to use the "URI style launching" for UWP apps (for example: MS ToDo) from a win32 Application, command line or UWP apps.
UWP has a specific shell URI-Schemas available to launch them.
For example you can press win+R and enter ms-todo: and MS ToDo will start.
Respectively open cmd and enter start ms-todo: and MS ToDo will start.
How can i get a list with all local available URIs?
tl;dr
They are listed in Settings > Apps > Default Apps > Choose default apps by protocol
Getting details for all apps with Powershell
$result = [System.Collections.ArrayList]#();
foreach ($appx in Get-AppxPackage)
{
$location = $appx.InstallLocation
$manifest = "$location\AppxManifest.xml"
if($location -ne $null -and (Test-Path $manifest -PathType Leaf))
{
[xml]$xml = Get-Content $manifest
$ns = new-object Xml.XmlNamespaceManager $xml.NameTable
$ns.AddNamespace("main", "http://schemas.microsoft.com/appx/manifest/foundation/windows10")
$ns.AddNamespace("uap", "http://schemas.microsoft.com/appx/manifest/uap/windows10")
$ns.AddNamespace("uap3", "http://schemas.microsoft.com/appx/manifest/uap/windows10/3")
$ns.AddNamespace("uap5", "http://schemas.microsoft.com/appx/manifest/uap/windows10/5")
$uriElements = $xml.SelectNodes("//uap:Extension[#Category = 'windows.protocol']/uap:Protocol/#Name", $ns)
$uris = $uriElements | select -ExpandProperty '#text'
$appIds = $xml.SelectNodes("//main:Application/#Id", $ns) | select -ExpandProperty '#text'
if ($appIds.Count -eq 0) {
continue;
}
$aliases = $xml.SelectNodes("//main:Extensions/uap5:Extension[#Category = 'windows.appExecutionAlias']/uap5:AppExecutionAlias/uap5:ExecutionAlias/#Alias", $ns) | select -ExpandProperty '#text'
#$result[$appx.Name] = $uris
$tmp = New-Object -TypeName PSObject
$tmp | Add-Member –MemberType NoteProperty –Name Name –Value "$($appx.Name)"
$tmp | Add-Member –MemberType NoteProperty –Name URIs –Value ($uris -join "`n")
$tmp | Add-Member –MemberType NoteProperty –Name Aliases –Value ($aliases -join "`n")
$tmp | Add-Member –MemberType NoteProperty –Name Package –Value "$($appx.PackageFamilyName)"
$tmp | Add-Member –MemberType NoteProperty –Name AppIds –Value ($appIds -join "`n")
$tmp | Add-Member –MemberType NoteProperty –Name Folder –Value $appx.InstallLocation
$null = $result.Add($tmp)
}
}
$result | Sort-Object -Property Name | Out-GridView
Result
The manual way for a single App:
I'm only aware of a slighly cumbersome manual way have to do do for every single app.
In this case "Microsoft.Todos"
Execute
Get-AppxPackage -Name Microsoft.Todos
Read Property "InstallationLocation"
C:\Program Files\WindowsApps\Microsoft.Todos_2.27.32662.0_x64__8wekyb3d8bbwe
Open AppxManifest.xml
C:\Program Files\WindowsApps\Microsoft.Todos_2.27.32662.0_x64__8wekyb3d8bbwe\AppxManifest.xml
Look for protocol entries:
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="ms-to-do">
<uap:DisplayName>ms-resource:app_name_ms_todo</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
<uap:Extension Category="windows.protocol">
<uap:Protocol Name="ms-todo">
<uap:DisplayName>ms-resource:app_name_ms_todo</uap:DisplayName>
</uap:Protocol>
</uap:Extension>
As you can see "ms-to-do" and "ms-todo" are the associated URIs.

Errors with Get-ChildItem trying to scan network for all .mdb files

I am very new to using powershell and trying to execute a script that scans the entire network for all .mdb and .accdb files, for example, and generates a spreadsheet containing the data on them that I process elsewhere.
I put the sensistive data that I didnt want to provide in ()s
Here is my code:
#single threaded
import-module activedirectory
$arr = #()
$computers = Get-ADComputer -filter 'name -like "(employee computers)*"' | Select -Exp Name
foreach ($computer in $computers) {
Write-Host "Scanning" $computer "..."
gci \\$computer\c$\* -Include *.mdb, *.accdb -Recurse | ? {$_.PSIsContainer -eq $False} | % {
$obj = New-Object PSObject
$obj | Add-Member NoteProperty Directory $_.DirectoryName
$obj | Add-Member NoteProperty Name $_.Name
$obj | Add-Member NoteProperty FullName $_.FullName
$obj | Add-Member NoteProperty Size $_.Length
$obj | Add-Member NoteProperty CreationTime $_.CreationTime
$obj | Add-Member NoteProperty LastWriteTime $_.LastWriteTime
$arr += $obj
Write-Host "Scanning..."
}}
$arr | Export-CSV -notypeinformation '(path)\EmployeeDBs.csv'
This has been working pretty well so far, but for certain machines and/or directories on some machines I am receiving the following error messages:
Get-ChildItem : The specified network name is no longer available
[Get-ChildItem], IOException
+ FullyQualifiedErrorId : DirIOError,Microsoft.PowerShell.Commands.GetChildItemCommand
and
Get-ChildItem : An object at the specified path \\(employee computer)\c$ does not exist.
[Get-ChildItem], IOException
+ FullyQualifiedErrorId : ItemDoesNotExist,Microsoft.PowerShell.Commands.GetChildItemCommand
I have been googling around but havent had much luck in understanding these error messages. Would somebody be able to explain what the issues are?
I am thinking (hoping) that they are permissions problems because I am testing the scripts on my personal machine before I run them from the admin machine
Any insight is greatly appreciated!
EDIT: below is my edited code for asynchronous execution:
import-module activedirectory
$computers = Get-ADComputer -filter 'name -like "wa-150*"' | Select -Exp Name
Get-job | Remove-Job -Force
Remove-Item -path (path)\EmployeeDBs.txt
foreach ($computer in $computers) {
$scriptBlock = {gci \\$($args[0])\c$\Users\z*\Desktop\* -Include *.mdb, *.accdb -Recurse | ? {$_.PSIsContainer -eq $False} | % {
$obj = New-Object PSObject
$obj | Add-Member NoteProperty Directory $_.DirectoryName
$obj | Add-Member NoteProperty Name $_.Name
$obj | Add-Member NoteProperty Size $_.Length
$obj | Add-Member NoteProperty CreationTime $_.CreationTime
$obj | Add-Member NoteProperty LastWriteTime $_.LastWriteTime
Write-Output -InputObject $obj
}
}
while ((Get-Job -State Running).Count -ge 20) {
Write-Host "Full - Waiting ... "
Start-Sleep -Seconds 5;
}
Start-Job -name $computer -ScriptBlock $scriptBlock -ArgumentList $computer
#Invoke-Command -ScriptBlock $scriptBlock -ArgumentList $computer
}
Get-Job | Wait-Job | Receive-Job | Out-File -Append -FilePath '(path)\EmployeeDBs.txt'
Write-Host "Done"

Having issues parsing an event log (ID 4725) and outputting the target username field using Powershell

Basically, I am trying to write some code that will run off of a scheduled task any time the event ID 4725 is triggered. This specific event states that a particular user had their AD account disabled (Windows Server 2016).
What I need to do is take the username from this event ID and output it as a variable #UserName to be used in the restmethod URI.
# Variables
$params = #{"action"="move";"destination"="/Shared/IT/Archived User Data/"}
$json = $params|ConvertTo-Json
$eventRecordId = 4725
$eventChannel = "Security"
# Gets the latest "disabled user account" event log and outputs the disabled user's name to a variable called $UserName
Get-EventLog –Log Security -InstanceId 4725 -Newest 1 | $UserName = ?{Group-Object -Property "TargetUserName"}
Echo $UserName
# Calls the Egnyte API to move the disabled user's home folder to the archive folder
Invoke-RestMethod `
-Method Post `
-body $json `
-Uri 'https://xxxxxx.egnyte.com/pubapi/v1/fs/private/"$UserName"' `
-Headers #{Authorization = "Bearer xxxxxxxxxxxxxxxxxxxxxxx"
Contenttype = "application/json"}
Expected results: Take the username from the target-username field in the security event-log ID 4725, output it to variable "#UserName", and then input it into the rest-method API.
Actual results: The variable is not being created.
OK Lets take a look at this Event 4725 template
(Get-WinEvent -ListProvider * -ErrorAction Ignore).Events |
Where-Object {$_.Id -eq 4725} |
select * |
Format-List
We can see there is a TargetUserName
<data name="TargetUserName" inType="win:UnicodeString" outType="xs:string"/>
So lets parse that Message into XML,
Get-EventLog returns a type System.Diagnostics.EventLogEntry
So first we need to change that object into a System.Diagnostics.Eventing.Reader.EventLogRecord so we can convert to XML
We can ether Make a new call using Get-WinEvent which will return the type System.Diagnostics.Eventing.Reader.EventLogRecord which has a method for turning data into XML
Or We can get the Index from the current record and call Get-WinEvent looking for the EventRecordID.
Below is a function i wrote that will parse the message field and make a new psobject with property ParsedMessage
function Parse-WindowsEvents(){
param(
[Parameter(Position=1, ValueFromPipeline)]
#[System.Diagnostics.Eventing.Reader.EventRecord[]]$Events
[object[]]$Events
)
process{
$ArrayList = New-Object System.Collections.ArrayList
$Events | %{
$EventObj = $_
$EventObjFullName = $_.GetType().FullName
if($EventObjFullName -like "System.Diagnostics.EventLogEntry"){
$EventObj = Get-WinEvent -LogName security -FilterXPath "*[System[EventRecordID=$($_.get_Index())]]"
}elseif($EventObjFullName -like "System.Diagnostics.Eventing.Reader.EventLogRecord"){
}else{
throw "Not An Event System.Diagnostics.Eventing.Reader.EventLogRecord or System.Diagnostics.EventLogEntry"
}
$PsObject = New-Object psobject
$EventObj.psobject.properties | %{
$PsObject | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.Value
}
$XML = [xml]$EventObj.toXml()
$PsObject2 = New-Object psobject
$XML.Event.EventData.Data | %{
$PsObject2 | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_."#text"
}
$PsObject | Add-Member -MemberType NoteProperty -Name ParsedMessage -Value $PsObject2
$ArrayList.add($PsObject) | out-null
}
return $ArrayList
}
}
$Username = Get-EventLog –Log Security -InstanceId 4725 -Newest 1 | Parse-WindowsEvents | select -ExpandProperty ParsedMessage | select TargetUserName
$Username.TargetUserName
#or
$Username = (Get-EventLog –Log Security -InstanceId 4725 -Newest 1 | Parse-WindowsEvents | select -ExpandProperty ParsedMessage).TargetUserName
$Username

Resources