PowerShell 5.1 using ExpandedProperty but not getting desired output - powershell

Given:
PowerShell 5.1
If I run the following:
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit*
I get this:
Status Name DisplayName
------ ---- -----------
Stopped BDESVC BitLocker Drive Encryption Service
Stopped Check Point Bit... Check Point Endpoint Security Bitlo...
But I want to expand both Name and DisplayName, so I do this:
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* | Select -ExpandProperty Name
and get this:
BDESVC
Check Point Bitlocker Management
How do I get all the columns with column headers, like the first output above except without ellipses?
Status Name DisplayName
------ ---- -----------
Stopped BDESVC BitLocker Drive Encryption Service
Stopped Check Point Bit... Check Point Endpoint Security Bitlo...

Get-Service -DisplayName *wmi*
Status Name DisplayName
------ ---- -----------
Stopped wmiApSrv WMI Performance Adapter
Running WMIRegistrationSe… Intel(R) Management Engine WMI Provid…
I find myself using | Out-GridView if desired output isn't being shown.
Get-Service -DisplayName *wmi* |
Out-GridView
Out-GridView Result
Alternatively, you could use | Format-List if you're not set on using Table View
Get-Service -DisplayName *wmi* |
Format-List
Name : wmiApSrv
DisplayName : WMI Performance Adapter
Status : Stopped
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : False
ServiceType : Win32OwnProcess
Name : WMIRegistrationService
DisplayName : Intel(R) Management Engine WMI Provider Registration
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32OwnProcess
If you only want Status,Name,DisplayName headers,
Get-Service -DisplayName *wmi* |
Select-Object -Property Status, Name, DisplayName |
Format-List
Status : Stopped
Name : wmiApSrv
DisplayName : WMI Performance Adapter
Status : Running
Name : WMIRegistrationService
DisplayName : Intel(R) Management Engine WMI Provider Registration

The ... are just a display problem (the data is there in full).
If you use Select-Object's -ExpandProperty parameter, you by definition only get property values, and since these values are strings in your case, that's all you get (albeit without truncation).
To prevent the for-display truncation, pipe to Format-Table -AutoSize, though note that this requires PowerShell to collect all output from the input command first, before starting to display output (see next section for alternatives).
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* | Format-Table AutoSize
Note: Since the console (terminal) window width is always the limiting factor, -AutoSize can result in fewer columns getting displayed.
If possible, you can exclude columns that aren't of interest, by specifying only those that are, via -Property (you may omit this parameter name, becasue it is positionally implied); e.g.:
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* |
Format-Table -Property Status, Name -AutoSize
Alternatives that avoid -AutoSize and its collect-everything-first behavior:
Use -Wrap, which doesn't truncate, but uses (artificial) line breaks to spread values that don't fit into the column across multiple lines.
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* | Format-Table -Wrap
If you know the maximum width of a column of interest ahead of time, you can use a calculated property to prescribe a column's width; e.g.:
Get-Service -ComputerName WKSP000D1E3F -DisplayName *bit* |
Format-Table Status,
#{ Expression='Name'; Width=40 },
DisplayName

Related

Obtain display name with spaces from powershell or cmd - AzuredAD only

I am try to pull just the display name (first and last name) from cmd or powershell. (AzureAD - not on-prem AD)
I have gotten a couple of different commands but all of them keep the name together.
Examples:
$env:UserName = jatonjustice
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name = azureAD\jatonjustice
I am trying to find a way where the result has the first and last name separated or maybe just the first and just the last name as an alternate idea.(Like: `Jaton Justice') I can't parse it myself as I don't know what the display name will be upfront. (AzureAD - not on-prem AD)
Any ideas for this?
research:
How do I get the current username in Windows PowerShell?
How to get an Azure Active Directory username in Windows Powershell?
Thanks
$env:UserName should return SamAccountName, rather than user's name.
'Get-ADUser -Property *' should show you all info about the user you are querying, you should be able to find a property called GivenName and Surname.
$search = [adsisearcher]"(SamAccountName=$env:USERNAME)"
$search.PropertiesToLoad.AddRange(#('givenname','sn'))
$adAccount = $search.FindOne()
$firstName = $adAccount.Properties.givenname
$lastName = $adAccount.Properties.sn
$fullname = "$firstName $lastName"
All you are after is explained and detailed by examples in the PowerShell help files. More on that later.
As for ...
'but all of them keep the name together. Examples:'
...and they are supposed to, by design.
Using those, you are asking for the local logged-on username (SamAccountName, which is a short name defined in the user profile on the localhost and in ADDS/AAD - for the UPN, SamAccountName#DomainName.com) with those, not ADDS/AAD name specifics.
If you want First and last from the locally logged-on user, then you have to have that populated in the account, or you have to ask for it from ADDS/AAD. What is your use case?
If you are on PSv5x and higher there is this module:
# Results
<#
Get-Module -Name '*local*'
ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Binary 1.0.0.0 Microsoft.PowerShell.LocalAccounts {Add-LocalGroupMember, Disable-LocalUser, Enable-LocalUser, Get-LocalGroup...}
#>
You get local user details this way.
Get-LocalUser | Select-Object -Property '*' -First 1
# Results
<#
AccountExpires :
Description : Built-in account for administering the computer/domain
Enabled : False
FullName :
PasswordChangeableDate :
PasswordExpires :
UserMayChangePassword : True
PasswordRequired : True
PasswordLastSet :
LastLogon :
Name : Administrator
SID : S-1-5-21-2047949552-857980807-821054962-500
PrincipalSource : Local
ObjectClass : User
#>
Note that on his local account, Fullname is not populated. So, obviously, you can't use that, nor can you extrapolate from the name/SamAccoutnName property.
So, you can ask for the locally logged on username in a number of ways,...
# Get loggedon users
$env:UserName
[System.Environment]::UserName
[System.Security.Principal.WindowsIdentity]::GetCurrent().Name
(Invoke-CimMethod -InputObject $(
Get-CimInstance Win32_Process -Filter "name = 'explorer.exe'"
) -MethodName GetOwner).User
Get-WmiObject Win32_Process -Filter "name='explorer.exe'" |
Select Name, #{
Name = 'UserName'
Expression = {"$($PSItem.GetOwner().Domain)\$($PSItem.GetOwner().User)"}
} |
Sort-Object UserName, Name
(Get-Process -Name 'explorer' -IncludeUserName).UserName
(
Get-WMIObject -ClassName Win32_ComputerSystem |
Select-Object -Property Username
).username
[adsisearcher]"(SamAccountName=$env:USERNAME)"
whoami
... then use that Name/SamAccountName to ask ADDS/AAD what the user FullName or whatever you wish is.
If you are on an earlier version, you need to install one of these modules from Microsofts' powershelgallery.com...
Find-Module -Name '*local*'
# Results
<#
Version Name Repository Description
------- ---- ---------- -----------
...
1.6 localaccount PSGallery A Simple module to allow the management of local users and groups on a computer
1.0.0.0 Microsoft.PowerShell.LocalAccounts PSGallery Provides cmdlets to work with local users and local groups
3.0 LocalUserManagement PSGallery a module that performs various local user management functions
...
0.1.1 LocalAccountManagement PSGallery Manage local and remote user accounts and profiles
...
#>
... and do the same thing or use WMI, ADSI, etc.
[adsisearcher]"(SamAccountName=$env:USERNAME)"
# Results
<#
CacheResults : True
ClientTimeout : -00:00:01
PropertyNamesOnly : False
Filter : (SamAccountName=TestUser)
PageSize : 0
PropertiesToLoad : {}
ReferralChasing : External
SearchScope : Subtree
ServerPageTimeLimit : -00:00:01
ServerTimeLimit : -00:00:01
SizeLimit : 0
SearchRoot :
Sort : System.DirectoryServices.SortOption
Asynchronous : False
Tombstone : False
AttributeScopeQuery :
DerefAlias : Never
SecurityMasks : None
ExtendedDN : None
DirectorySynchronization :
VirtualListView :
Site :
Container :
#>
Now, back to my 'read the help file comment.'
Get-ADUser | MS DOcs
https://learn.microsoft.com/en-us/powershell/module/activedirectory/get-aduser?view=windowsserver2019-ps
# Example 3: Get all of the properties for a specified user
Get-ADUser -Identity $env:USERNAME -Properties '*'
# Results
<#
Surname : David
Name : Chew David
UserPrincipalName :
GivenName : David
Enabled : False
SamAccountName : ChewDavid
ObjectClass : user
SID : S-1-5-21-2889043008-4136710315-2444824263-3544
ObjectGUID : e1418d64-096c-4cb0-b903-ebb66562d99d
DistinguishedName : CN=Chew David,OU=NorthAmerica,OU=Sales,OU=UserAccounts,DC=FABRIKAM,DC=COM
#>

how to format Powershell output in specific way?

I need to scan my network for specific processes on servers. I've done this script:
28..31 | ForEach-Object { Get-Process -ComputerName "192.168.0.$_" -Name svc* }
Now how can I format output so it shows on which IP address found process shown? Thank you.
I suggest switching to PowerShell's remoting, because:
it provides a framework for executing any command remotely - rather than relying on individual cmdlets to support a -ComputerName parameter and uses a firewall-friendly transport.
it will continue to be supported in PowerShell [Core] v6+, where the cmdlet-individual -ComputerName parameters aren't supported anymore; this obsolete remoting method uses an older, less firewall-friendly form of remoting that the - obsolete since v3 - WMI cmdlets also use (the latter were replaced by the CIM cmdlets).
It is therefore better to consistently use the firewall-friendly PowerShell remoting with its generic remoting commands (Invoke-Command, Enter-PSSession, ...).
If you use Invoke-Command to target (multiple) remote computers, the objects returned automatically contain and display the name of the originating computer, via the automatically added .PSComputerName property:
# Create the array of IP addresses to target:
$ips = 28..31 -replace '^', '192.168.0.'
# Use a *single* Invoke-Command call to target *all* computers at once.
# Note: The results will typically *not* reflect the input order of
# given IPs / computer names.
Invoke-Command -ComputerName $ips { Get-Process -Name svc* }
You'll see output such as the following - note the PSComputerName column:
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName PSComputerName
------- ------ ----- ----- ------ -- -- ----------- --------------
1013 18 7464 13732 52.72 8 0 svchost 192.168.0.30
...
Note that you can suppress automatic display of the .PSComputerName property with Invoke-Command's -HideComputerName parameter.
However, the property is still available programmatically, which allows you to do the following:
Invoke-Command -ComputerName $ips { Get-Process -Name svc* } -HideComputerName |
Format-Table -GroupBy PSComputerName
This yields display output grouped by computer name / IP:
PSComputerName: 192.168.0.30
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
1013 18 7464 13732 52.72 8 0 svchost
...
PSComputerName: 192.168.0.28
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
1007 17 7112 12632 65.45 11 0 svchost
...
If you wanted to sort by IP address before grouping, you could insert | Sort-Object { [version] $_.PSComputerName }[1] before the Format-Table call.
For sorting by computer names, just
| Sort-Object PSComputerName would do.
[1] Casting to [version] is a trick to ensure proper sorting of IP addresses; IP address strings can be interpreted as [version] (System.Version) instances, and such instances are directly comparable, using the numeric values of the version components (first by .MajorVersion, then by .MinorVersion, ...)
here's one way to do the job. [grin] what it does ...
builds the ip final octet range
sets the IPv4 base octets
builds the list of processes to search for
sets the "no response" text
iterates thru the 4th octet range
builds the IPv4 address
checks to see if it is online/responding
if so, gets the hostname
for my version of PoSh [win7, ps5.1] the Get-Process cmdlet will NOT accept an ip address. a hostname is required.
corrects for the damaged hostname returned when one uses ATT for inet service
creates an ordered hashtable to use for building the property list
builds the various props as needed
converts the hashtable to a PSCustomObject
sends that to the $Results collection
shows it on screen
sends it to a CSV file
here's the code ...
$4thOctetRange = 64..66
$IpBase = '192.168.1'
$ProcessList = #(
'AutoHotKey'
'BetterNotBeThere'
'DisplayFusion'
'Foobar2000'
)
$NoResponse = '__n/a__'
$Results = foreach ($4OR_Item in $4thOctetRange)
{
$Ip = '{0}.{1}' -f $IpBase, $4OR_Item
$Online = Test-Connection -ComputerName $Ip -Count 1 -Quiet
if ($Online)
{
# getting the hostname is REQUIRED by my version of Get-Process
# it will not accept an IP address
# version info = win7, ps5.1
# this may need adjusting for your returned hostname
# mine shows Hostname.attlocal.net
# that is not valid with any query i make, so i removed all after the 1st dot
$HostName = ([System.Net.Dns]::GetHostByAddress($Ip)).HostName.Split('.')[0]
}
else
{
$HostName = $NoResponse
}
$TempProps = [ordered]#{}
$TempProps.Add('IpAddress', $Ip)
$TempProps.Add('Online', $Online)
$TempProps.Add('HostName', $HostName)
foreach ($PL_Item in $ProcessList)
{
if ($TempProps['Online'])
{
# if the process aint found, the "SilentlyContinue" forces a $Null
# the "[bool]" then coerces that to a "False"
$TempProps.Add($PL_Item, [bool](Get-Process -ComputerName $HostName -Name $PL_Item -ErrorAction SilentlyContinue))
}
else
{
$TempProps.Add($PL_Item, $NoResponse)
}
}
# send the object out to the $Results collection
[PSCustomObject]$TempProps
}
# send to screen
$Results
# send to CSV file
$Results |
Export-Csv -LiteralPath "$env:TEMP\Senator14_RemoteProcessFinder.csv" -NoTypeInformation
truncated screen output ...
IpAddress : 192.168.1.65
Online : True
HostName : ZK_01
AutoHotKey : True
BetterNotBeThere : False
DisplayFusion : True
Foobar2000 : True
IpAddress : 192.168.1.66
Online : False
HostName : __n/a__
AutoHotKey : __n/a__
BetterNotBeThere : __n/a__
DisplayFusion : __n/a__
Foobar2000 : __n/a__
csv file content ...
"IpAddress","Online","HostName","AutoHotKey","BetterNotBeThere","DisplayFusion","Foobar2000"
"192.168.1.64","False","__n/a__","__n/a__","__n/a__","__n/a__","__n/a__"
"192.168.1.65","True","ZK_01","True","False","True","True"
"192.168.1.66","False","__n/a__","__n/a__","__n/a__","__n/a__","__n/a__"

output not a trimmed value and causing the output error

I have written few powershell command to perform some auditing on HyperV Clusters. The command works fine, But can anyone help me to trim the output, so that I can collect what I need ?
##Audit-CreatingDC
$AuditDC = Invoke-Command -ComputerName $ComputerName {Get-ChildItem -Path HKLM:\cluster\resources -recurse | get-itemproperty -name CreatingDC -erroraction 'silentlycontinue'}| ft CreatingDC,PSComputerName
####Audit-iSCSI
#Show which hosts are not communicating to the storage with the ‘-s’ and where there are duplicated targets:
$AuditISCSI = Invoke-Command -ComputerName $ComputerName { get-iscsisession } | FT PSComputerName, InitiatorPortalAddress, IsConnected -autosize
######Discover checkdsk errors - "Scan Needed". Execute using txt of one node from each cluster.
$AuditCHKDSK = Invoke-Command -ComputerName $ComputerName { get-volume | Where-Object –FilterScript { $_.HealthStatus -eq "Scan Needed" }} | FT PSComputerName, FileSystem, HealthStatus -autosize
And the output for each is below
CreatingDC PSComputerName
---------- --------------
\\dc-sc-02.oim.corp.com slcoc037
PSComputerName InitiatorPortalAddress IsConnected
-------------- ---------------------- -----------
slcoc037 10.214.61.107 True
PSComputerName FileSystem HealthStatus
-------------- ---------- ------------
slcoc037 CSVFS 1
But I need the output for above in this format
\\dc-sc-02.oim.corp.com
10.241.81.107
CSVFS 1
Can anyone help me to trim these 3 commands ?
You probably already know that almost all powershell outputs are objects. Objects have properties. Displaying a particular property would use the syntax $Object.Propertyname. In your case, CreatingDC is a property of the $AuditDC Variable object. Applying that logic, all you need to do is, display it like this:
$AuditDC.CreatingDC
$AuditISCSI.InitiatorPortalAddress
$AuditCHKDSK.FileSystem

How do I add a column of incrementing values to cmdlet output?

Suppose I call Get-Service and want to assign a new column ID with the cmdlet output that prints incrementing integers so that:
ID Status Name DisplayName
-- ------ ---- -----------
0 Running AdobeARMservice Adobe Acrobat Update Service
1 Stopped AeLookupSvc Application Experience
2 Stopped ALG Application Layer Gateway Service
I'm trying to use Select-Object right now to add this column, but I don't quite understand how to iterate a variable in this sort of expression. Here's what I've got:
Get-Service |
Select-Object #{ Name = "ID" ; Expression= { } }, Status, Name, DisplayName |
Format-Table -Autosize
Is there a way to iterate integers within Expression= { }, or am I going about this problem the wrong way?
You can do it this way, though you will need to maintain some counter variable outside of the main expression.
$counter = 0
Get-Service |
Select-Object #{ Name = "ID" ; Expression= {$global:counter; $global:counter++} }, Status, Name, DisplayName |
Format-Table -Autosize
Another option, which is perhaps cleaner
Get-Service `
|% {$counter = -1} {$counter++; $_ | Add-Member -Name ID -Value $counter -MemberType NoteProperty -PassThru} `
| Format-Table ID
I asked the same question a different way and got the following answer
$x = 10
Get-Service |
Select-Object #{ Name = "ID" ; Expression={ (([ref]$x).Value++) }}, Status, Name, DisplayName | Format-Table -Autosize
It wasn't at all clear to me that the expression is being invoked within Select-Object's scope, not the pipe's. The [ref] qualifier bumps the increment's result up to the pipe's scope achieving the same result as explicitly specifying the variable as global.

Display all service names matching a string pattern

I'm trying to display the name (just the name) of all of the installed services that contain the string "SQL". For example, I want to see
SQLAgent$SQL2008_R2
SQLBrowser
SQLWriter
So I try this:
Get-WmiObject Win32_Service
This displays all of the services, but as a list.
Exit Code : 0
Name : ProtectedStorage
ProcessId : 664
StartMode : Manual
State : Running
Status : OK
Exit Code : 1077
Name : QWAVE
ProcessId : 0
StartMode : Manual
State : Stopped
Status : OK
(etc...)
This is good, but I just want to see the name. So I type:
Get-WmiObject Win32_Service | select-object Name
And I get what I expect:
sppuinotfy
SQLAgent$SQL2008_RT
SQLBrowser
SQLWriter
SSDPSRV
(etc ..)
All is good. I take the next step of filtering the names to only include SQL related ones:
Get-WmiObject Win32_Service | select-object Name | select-string -pattern 'SQL'
And now it's confusing. Here is my output:
#{Name=BcmSqlStartupSvc}
#{Name=MSOLAP$SQL2008_R2}
#{Name=MSSQL$SQL2008_R2}
(etc ...)
Why am I getting this output, instead of just the names?
What should I be typing to get just the names?
You can use Get-Service instead of get-WMIObject and do it like this"
get-service sql* | select -expand name
The easiest way to achieve that is using -Filter Parameter
Get-WMIObject Win32_Service -Filter "Name LIKE '%SQL%'" |
Select -ExpandProperty Name
In case, you want to go with your code only, here is the way you can modify it:
Get-WmiObject Win32_Service | Select-Object -ExpandProperty Name |
Select-String -pattern 'SQL'
Edit: LIKE operator takes a few meta characters to support matching pattern.
[] - for range matching. For example, Name LIKE '[a-f]%' will list all services starting with any letter from a to f.
^ - not. For example, Name LIKE '[^a-f]%' will list services that do not start with any letter from a to f.
_ - matches one letter. For example, Name LIKE 'S_L%' will list services that start with S and followed by any letter.
Get-Service | Where-Object {$_.Name -match "SQL"} |Select-Object Name