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

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

Related

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.

Identify all users with "full access" and "send on behalf" access to each shared mailbox where the user is disabled

We have the script here in the company when the user is fired, for a few months we leave the user disabled and do not delete it, however I need to clean our shared mailboxes and check which of these unblown users still have access to these mailboxes
Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize:Unlimited | Get-MailboxPermission |Select-Object Identity,User,AccessRights | Where-Object {($_.user -like '#')}|Export-Csv C:\Temp\sharedfolders.csv -NoTypeInformation
I already have my script that checks all shared mailboxes, but I need to create a kind of filter where the results show me only users who are no longer active in AD, someone can help me, please?
I think this is what you are looking for.
$mailboxes = Get-Mailbox -RecipientTypeDetails SharedMailbox -ResultSize unlimited
$mailboxes | Get-MailboxPermission | ForEach-Object{
$perm = $_
$ADuser = Get-ADUser $perm.user.securityidentifier.value
$perm | Add-Member -MemberType NoteProperty -Name UserEnabled -Value $ADuser.Enabled
$perm
} | Select-Object Identity, User, AccessRights, UserEnabled | Where-Object { ($_.user -like '#') -and $_.UserEnabled -eq $false } | Export-Csv C:\Temp\sharedfolders.csv -NoTypeInformation
Note it does require the Active Directory module to use the Get-ADuser command.

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.

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

Lazy loading in powershell?

Can we defer a variable initialization untill it is needed ?
What I would like to do is predefine some variables in my profile that will contain a list of AD computer:
let's say I want:
$OU1_workstation to be fill with computers found in OU=workstations,OU=OU1,dc=domain,dc=com
$OU2_workstation fill with computers found in
OU=workstations,OU=OU2,dc=domain,dc=com and so on...
I use the following script to do it but it takes 30sec to compute, so currently I can't put that in my profile...
Get-ADOrganizationalUnit -SearchScope onelevel -Filter "*" -Properties "name","distinguishedname" |%{
set-Variable -Name "$($_.name)_workstation" -value (Get-ADComputer -Searchbase "OU=workstations,$($_.Distinguishedname)" -Filter * )
}
What options are available in powershell ?
Finally, based on #Richard's reply of a previous question of mine, I've chosen the following path to achieve some sort of lazy loading : using a scriptproperty of a PSCustomObject.
So I can put this in my profile
#requires -module activedirectory
$server=New-Object PSCustomObject
Get-ADOrganizationalUnit -SearchScope onelevel -Filter "*" -Properties "name","distinguishedname" |
?{
$_.name -notmatch 'Administrateurs|Administration|Comptes de deploiement|Contacts|Domain Controllers|Groupes|Serveurs|Services'
} |
%{
$OU=$_.name
$s=[scriptblock]::Create("Get-ADComputer -SearchBase ""OU=servers,OU=$OU,DC=domain,DC=com"" -Filter 'name -notlike "" *old""' |select -expand name")
$server| Add-Member -MemberType ScriptProperty -name $OU -value $s -Force
}
then when needed I can call $server.OU1 to get all server under this OU, $server.OU2 etc...

Resources