Automatic select only member in the object list - bash

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.

Related

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

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.

How to write all PowerShell screen output to .csv report file

Fig1 Fig2 While I know this is a similar to many other questions regarding this, however, I have been having a difficult time figuring out how to make what I see on the screen go to the output file. I'm using PowerShell Version 5.1.16299.1146. Fig1 image is what I see on the PS screen. I want the script to see if a particular file is present and if it is TRUE or FALSE, write the information to the .csv file. Fig2 image is what actually gets written to the .csv report. I want the computer Name, Results (TRUE/FALSE), and Users + LastWriteTime written to the .csv file if it is found in the user's AppDate location for each user on a particular machine.
Set-ExecutionPolicy Bypass
$javausers = #()
$env:COMPUTERNAME = HostName
$TestPath = "$env:userprofile\AppData\LocalLow\Sun\Java\Deployment\deployment.properties"
$TestResult = if ( $(Try { Test-Path $TestPath.trim() } Catch { $false }) ) { Write-Output "True - deployment.properties" } Else { Write-Output "False - Path not found" }
$users = Get-ChildItem c:\users
foreach ($user in $users)
{
$folder = "C:\users\" + $user + "$env:userprofile\AppData\LocalLow\Sun\Java\Deployment\deployment.properties"
if ( $(Try { Test-Path $TestPath.trim() } Catch { $false }) ) { Write-Output "True - deployment.properties" $users -join ','} Else { Write-Output "False - Path not found" $users-join ','}
}
$javauser = New-Object System.Object
$javauser | Add-Member -MemberType NoteProperty -Name "Computer Name" -Value $env:COMPUTERNAME
#$javauser | Add-Member -MemberType NoteProperty -Name "Java User" -Value $TestPath
$javauser | Add-Member -MemberType NoteProperty -Name "Results" -Value $TestResult
$javauser | Add-Member -MemberType NoteProperty -Name "Users" -Value $folder
#$javauser | Add-Member -MemberType NoteProperty -Name "Users" -Value $users
$javausers += $javauser
$javausers | Export-Csv -NoTypeInformation -Path "C:\Temp\JavaUsersList.csv" -Append
To read other users folders you'll need to RunsAsAdmin.
#Requires -RunAsAdministrator
## Q:\Test\2019\08\29\SO_57714265.ps1
Set-ExecutionPolicy Bypass
$env:COMPUTERNAME = HostName
$DeplPath = "AppData\LocalLow\Sun\Java\Deployment\deployment.properties"
$javausers = foreach ($User in Get-ChildItem C:\Users -Directory){
$folder = Join-Path $User.FullName $DeplPath
if (Test-Path $folder) {
$TestResult = "True - deployment.properties"
} Else {
$TestResult = "False - Path not found"
}
[PSCustomObject]#{
"Computer Name" = $env:COMPUTERNAME
"Results" = $TestResult
"Users" = $user.Name
}
}
$javausers
#$javausers | Export-Csv -NoTypeInformation -Path "C:\Temp\JavaUsersList.csv" -Append
Sample output:
Computer Name Results Users
------------- ------- -----
VBoxWin10 False - Path not found SomeOne
VBoxWin10 False - Path not found Public
VBoxWin10 True - deployment.properties LotPings

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

Output on the basis of folder and file name

I have some directories structure like below, where the last folder name will be the current date changing everyday, as below:
D:\data\Backup\WINDOWSDATA\18-03-2015
D:\data\Backup\LINUXDATA\18-03-2015
D:\data\Backup\UBUNTUDATA\18-03-2015
Under each date folder (18-03-2015) there will be maximum four .dat files having different time stamps in their names, as given below:
BKP_DS_FETCHER_6AM.dat
BKP_DS_FETCHER_10AM.dat
BKP_DS_FETCHER_2PM.dat
BKP_DS_FETCHER_6PM.dat
I am trying to generate following results in an output.txt file on the basis of simple logic that is if .dat file is there for a particular time, there should come Success otherwise Failed in output.txt for example as below:
output.txt:
FOLDER_NAME 6AM 10AM 2PM 6PM
WINDOWSDATA Success Failed Success Success
LINUXDATA Success Success Failed Success
UBUNTUDATA Failed Success Success Success
Please can somebody help me show the way to achieve it (in Batch or Powershell) ?
Push-Location D:\data\Backup
$todayDir = Get-Item (get-date -Format 'dd-MM-yyyy') -ErrorAction SilentlyContinue
if($todayDir)
{
Push-Location $todayDir
$logResult = #{}
dir -Directory | foreach {
$logResult.($_.Name) = $_.Name | Get-ChildItem -Filter '*.dat' |
foreach {
$isMatch = $_.Name -match 'BKP_DS_FETCHER_(?<hour>.*).dat$'
if($isMatch) {
$Matches.hour
}
}
}
$hourProperties = ($logResult.Values | foreach {$_}) | Sort-Object | Get-Unique
$logResult.Keys | foreach {
$obj = New-Object pscustomobject
$obj | Add-Member -MemberType NoteProperty -Name 'FOLDER_NAME' -Value $_
foreach($p in $hourProperties) {
$v=$null
if($logResult[$_] -contains $p) {
$v = 'Success'
}
else {
$v = 'Failed'
}
$obj | Add-Member -MemberType NoteProperty -Name $p -Value $v
}
$obj
} | Format-Table
Pop-Location
}
Pop-Location
Here is a way to do it in PowerShell:
$date = Get-Date -Format 'yyyy-MM-dd'
$basePath = 'D:\data\Backup\'
$outputPath = 'D:\data\Backup\output_' + $date + '.txt'
$baseFileName = 'BKP_DS_FETCHER_[HOUR].dat'
$hours = #( '6AM', '10AM', '2PM', '6PM' )
function Check-Folder( $folderName )
{
$resultLine = New-Object -TypeName System.Object
$resultLine | Add-Member -MemberType NoteProperty -Name 'FOLDER_NAME' -Value $folderName
foreach( $h in $script:hours )
{
$path = $script:basePath + $folderName + '\' + $script:date + '\' + $script:baseFileName.Replace('[HOUR]',$h)
#Write-Host $path
if( Test-Path -Path $path )
{
$resultLine | Add-Member -MemberType NoteProperty -Name $h -Value 'Success'
}
else
{
$resultLine | Add-Member -MemberType NoteProperty -Name $h -Value 'Failed'
}
}
return $resultLine
}
$results = #()
$results += Check-Folder 'WINDOWSDATA'
$results += Check-Folder 'LINUXDATA'
$results += Check-Folder 'UBUNTUDATA'
$results | Format-Table -AutoSize | Out-File -FilePath $outputPath
Output will look like this:
FOLDER_NAME 6AM 10AM 2PM 6PM
----------- --- ---- --- ---
WINDOWSDATA Success Failed Success Success
LINUXDATA Failed Failed Failed Failed
UBUNTUDATA Failed Success Failed Failed

Loop through all bindings configured in IIS with powershell

I'm looking for a way to go through all binding settings already configured in my IIS.
Im using this to work with the IIS in Powershell:
Import-Module WebAdministration
So far I was able to get the main required information i want:
$Websites = Get-ChildItem IIS:\Sites
My array $Websites is filled correctly and with the following command...
$Websites[2]
..I recieve this result:
Name ID State Physical Path Bindings
---- -- ----- ------------- --------------
WebPage3 5 D:\Web\Page3 http *:80:WebPage3
https *:443:WebPage3
Now here's the part I having a hard time with:
I want to check if the binding is correct. In order to do that I only need the binding. I tried:
foreach ($site in $Websites)
{
$site = $Websites[0]
$site | select-string "http"
}
Debugging that code shows me that $Site doesn't contain what I expected: "Microsoft.IIs.PowerShell.Framework.ConfigurationElement". I currently have no clue how to explicitly get to the binding information in order to to something like this (inside the foreach loop):
if ($site.name -eq "WebPage3" -and $site.Port -eq "80") {
#website is ok
}
else {
#remove all current binding
#add correct binding
}
Thank you for your help!
Solution:
Import-Module WebAdministration
$Websites = Get-ChildItem IIS:\Sites
foreach ($Site in $Websites) {
$Binding = $Site.bindings
[string]$BindingInfo = $Binding.Collection
[string]$IP = $BindingInfo.SubString($BindingInfo.IndexOf(" "),$BindingInfo.IndexOf(":")-$BindingInfo.IndexOf(" "))
[string]$Port = $BindingInfo.SubString($BindingInfo.IndexOf(":")+1,$BindingInfo.LastIndexOf(":")-$BindingInfo.IndexOf(":")-1)
Write-Host "Binding info for" $Site.name " - IP:"$IP", Port:"$Port
if ($Site.enabledProtocols -eq "http") {
#DO CHECKS HERE
}
elseif($site.enabledProtocols -eq "https") {
#DO CHECKS HERE
}
}
I don't know exactly what you are trying to do, but I will try. I see that you reference $Websites[2] which is webPage3.
You can do it like this:
$site = $websites | Where-object { $_.Name -eq 'WebPage3' }
Then when you look at $site.Bindings, you will realize that you need the Collection member:
$site.bindings.Collection
On my machine this returns this:
protocol bindingInformation
-------- ------------------
http *:80:
net.tcp 808:*
net.pipe *
net.msmq localhost
msmq.formatname localhost
https *:443:
And the test might then look like this:
$is80 = [bool]($site.bindings.Collection | ? { $_.bindingInformation -eq '*:80:' })
if ($is80) {
#website is ok
} else {
#remove all current binding
#add correct binding
}
I sent content of Collection to pipeline and filtere only objects where property bindingInformation is equal to desired value (change it). Then I cast it to [bool]. This will return $true if there is desired item, $false otherwise.
I found that if there were multiple bindings on a site then if I needed to script access to individual parts of the bindings otherwise I only got the first binding. To get them all I needed the script to be extended as below:
Import-Module WebAdministration
$Websites = Get-ChildItem IIS:\Sites
foreach ($Site in $Websites) {
$Binding = $Site.bindings
[string]$BindingInfo = $Binding.Collection
[string[]]$Bindings = $BindingInfo.Split(" ")
$i = 0
$header = ""
Do{
Write-Output ("Site :- " + $Site.name + " <" + $Site.id +">")
Write-Output ("Protocol:- " + $Bindings[($i)])
[string[]]$Bindings2 = $Bindings[($i+1)].Split(":")
Write-Output ("IP :- " + $Bindings2[0])
Write-Output ("Port :- " + $Bindings2[1])
Write-Output ("Header :- " + $Bindings2[2])
$i=$i+2
} while ($i -lt ($bindings.count))
}
I had something similar to the last answer, but this corrects to HTTPS sites and adds a bit more information that is useful.
Import-Module WebAdministration
$hostname = hostname
$Websites = Get-ChildItem IIS:\Sites
$date = (Get-Date).ToString('MMddyyyy')
foreach ($Site in $Websites) {
$Binding = $Site.bindings
[string]$BindingInfo = $Binding.Collection
[string[]]$Bindings = $BindingInfo.Split(" ")#[0]
$i = 0
$status = $site.state
$path = $site.PhysicalPath
$fullName = $site.name
$state = ($site.name -split "-")[0]
$Collection = ($site.name -split "-")[1]
$status = $site.State
$anon = get-WebConfigurationProperty -Filter /system.webServer/security/authentication/AnonymousAuthentication -Name Enabled -PSPath IIS:\sites -Location $site.name | select-object Value
$basic = get-WebConfigurationProperty -Filter /system.webServer/security/authentication/BasicAuthentication -Name Enabled -PSPath IIS:\ -location $site.name | select-object Value
Do{
if( $Bindings[($i)] -notlike "sslFlags=*"){
[string[]]$Bindings2 = $Bindings[($i+1)].Split(":")
$obj = New-Object PSObject
$obj | Add-Member Date $Date
$obj | Add-Member Host $hostname
$obj | Add-Member State $state
$obj | Add-Member Collection $Collection
$obj | Add-Member SiteName $Site.name
$obj | Add-Member SiteID $site.id
$obj | Add-member Path $site.physicalPath
$obj | Add-Member Protocol $Bindings[($i)]
$obj | Add-Member Port $Bindings2[1]
$obj | Add-Member Header $Bindings2[2]
$obj | Add-member AuthAnon $Anon.value
$obj | Add-member AuthBasic $basic.value
$obj | Add-member Status $status
$obj #take this out if you want to save to csv| export-csv "c:\temp\$date-$hostname.csv" -Append -notypeinformation
$i=$i+2
}
else{$i=$i+1}
} while ($i -lt ($bindings.count))
}

Resources