output not a trimmed value and causing the output error - powershell

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

Related

PowerShell 5.1 using ExpandedProperty but not getting desired output

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

Create Union of Multiple Tables in Powershell

I'm trying to create a union of multiple tables in Powershell to output in a user-friendly format as a report, similar to a UNION query in SQL.
I have the following code:
$ft = #{auto=$true; Property=#("MachineName", "Status", "Name", "DisplayName")}
$hosts = #("svr001", "svr002")
$report = #()
ForEach ($h in $hosts) {
$results = Get-Service -CN $h -Name MyService
$report += $results | Format-Table #ft
# Other things occur here, which is why I'm creating $report for output later.
}
Write-Output $report
The output of this code is as follows:
MachineName Status Name DisplayName
----------- ------ ---- -----------
svr001 Running MyService MyServiceDisplayName
MachineName Status Name DisplayName
----------- ------ ---- -----------
svr002 Running MyService MyServiceDisplayName
Since you simply add arrays to do a union in Powershell (i.e.,
$union = #(0, 1, 2) + #(3, 4, 5)), my initial thought was that I should
get the following output:
MachineName Status Name DisplayName
----------- ------ ---- -----------
svr001 Running MyService MyServiceDisplayName
svr002 Running MyService MyServiceDisplayName
In retrospect, I think I understand why I do not get this output, but I'm
unclear how to create a union of the two tables from the first output example into a single table as in the second, and I haven't been able to locate anything in the docs or examples online that would send me in the right direction.
Move the Format-Table to the last command. Format-* cmdlets create special format-objects that you can't work with manually so theres no point in saving them. When you save the result of Format-* to an array, you're saving the "report" which is why you get two tables in the output (array consists of two reports).
Collect the data first, then use Format-Table when you want to display the results.
$ft = #{auto=$true; Property=#("MachineName", "Status", "Name", "DisplayName")}
$hosts = #("svr001", "svr002")
$report = #()
ForEach ($h in $hosts) {
$results = Get-Service -ComputerName $h -Name MyService
$report += $results
# Other things occur here, which is why I'm creating $report for output later.
}
#Write-Output is not necessary as it is default behaviour
$report | Format-Table #ft
Sample output (used wuauserv as servicename):
MachineName Status Name DisplayName
----------- ------ ---- -----------
localhost Stopped wuauserv Windows Update
frode-pc Stopped wuauserv Windows Update
The Get-Service Cmdlet also supports an array of strings for the -ComputerName parameter. This works for me:
Get-Service -CN $hosts -Name MyService | Format-Table #ft
Sample Output using wuauserv:
MachineName Status Name DisplayName
----------- ------ ---- -----------
Tim-SRV1 Running wuauserv Windows Update
Tim-SRV2 Stopped wuauserv Windows Update

In Powershell, how to make an array with custom objects of different sizes/types?

im writing a simple function in order to list subfolders of a particular server share. My problem is that i want all informations in the same array of custom objects. Here is what i did:
function Get-tDollar {
param(
[string]$srv
)
$share = Get-WmiObject -ComputerName $srv -Class Win32_Share -Filter "Name='share`$'" | Select __SERVER,#{n="nPath";e={"\\" + $_.__SERVER + ($_.Path -replace "C:")}}
$inc = 0
Get-ChildItem $share.nPath | % {
$inc++
Add-Member -InputObject $share -MemberType NoteProperty -Name "folder_$inc" -Value $_.Name
}
$share
}
And i use this function like that: #("srv1","srv2") | % { Get-TDollar -srv $_ }
All works fine when the number of subfolders is the same, but when its different, the array contains only the number of folders listed in the first share. For example, for my two first servers, i have this output:
__SERVER nPath folder_1
-------- ----- ------------
srv1 \\srv1\share scripts
srv2 \\srv2\share scripts
But, because srv2 has more folders than the first server, i want this output:
__SERVER nPath repertoire_1 repertoire_2
-------- ----- ------------ ------------
srv1 \\srv1\share scripts
srv2 \\srv2\share scripts config
I know i can first calculate which server has the higher number of folders and then place it in fisrt position, but it seems there are enough lines for something like that. Is there a more efficient/elegant way to do that?
You're getting bitten by the default formatting gremlin:
http://blogs.msdn.com/b/powershell/archive/2006/04/30/586973.aspx
Get-tDollar |
foreach { $_ | format-table }

PowerShell Select-Object returning more than specified?

Why does the following command return more attributes than in the Select?
$obj = Get-VM | Select VMName,State; $obj
Output:
VMName : blah-blah
State : Off
PSComputerName : host
RunspaceId : URI
And how do I just get the value for State?
$obj = Get-VM | Select VMName,State; $obj.State
The above should do the trick but doesn't :(
That should work, but it sounds like for some reason the assignment of the results of Get-VM to $obj is happening before anything gets piped to select. Try Get-VM | select VMName, State by itself at the prompt, and if you get the expected results, try this:
$obj = (Get-VM | select VMName, State); $obj
To get just the State property, you can do this:
(Get-VM).State
Problem found :)
The above command is just fine as it is, however when it get's wrapped in an Invoke-Command such that it's run against another machine then the results are modified to include run specific information and a 'follow-on Select' is required like this:
Invoke-Command -Comuptername XXXX -ScriptBlock {$obj = Get-VM | Select VMName,State; $obj} | Select State

PowerShell's Write-Debug won't output arrays, but Write-Output does. Is this on purpose?

Shown below, an array works fine as input for Write-Output but not for Write-Debug (I expected them to be more similar than that).
PS C:\> [string[]]$test = #("test1", "test2", "test3")
PS C:\> Write-Output $test
test1
test2
test3
PS C:\> $DebugPreference = "Inquire"
PS C:\> Write-Debug $test
Write-Debug : Cannot convert 'System.String[]' to the type 'System.String' required by parameter 'Message'. Specified method is not supported.
At line:1 char:12
+ Write-Debug <<<< $test
+ CategoryInfo : InvalidArgument: (:) [Write-Debug], ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgument,Microsoft.PowerShell.Commands.WriteDebugCommand
PS C:\>
I'm thinking this is just an unfortunate design, but hoping for a sensible explanation. Am I using Write-Debug correctly? If so, anyone have a favorite simple workaround?
I kept having the same problem, and none of the solutions I found above or anywhere else would work in the general case.
For example, the first answer above works only because the array is an array of strings. If it's an array of anything else, that solution breaks, and Write-Debug will output the object type, and not its value as one would expect.
Finally I found a general solution: The key point is to first convert the input object to a string using the Out-String command. Once everything is a string, the above solution works. Using "Out-String -stream" improves the output alignment.
Example:
PS C:\> gwmi win32_bios
SMBIOSBIOSVersion : 786F3 v01.34
Manufacturer : Hewlett-Packard
Name : Default System BIOS
SerialNumber : CZC8196Q8S
Version : HPQOEM - 20120709
PS C:\> gwmi win32_bios | ft -auto
SMBIOSBIOSVersion Manufacturer Name SerialNumber Version
----------------- ------------ ---- ------------ -------
786F3 v01.34 Hewlett-Packard Default System BIOS CZC8196Q8S HPQOEM - ...
PS C:\> $DebugPreference = "Continue"
PS C:\> gwmi win32_bios | ft -auto | Write-Debug
DEBUG: Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
DEBUG: Microsoft.PowerShell.Commands.Internal.Format.GroupStartData
DEBUG: Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData
DEBUG: Microsoft.PowerShell.Commands.Internal.Format.GroupEndData
PS C:\> gwmi win32_bios | ft -auto | Out-String | Write-Debug
DEBUG: SMBIOSBIOSVersion Manufacturer Name SerialNumber Version
----------------- ------------ ---- ------------ -------
786F3 v01.34 Hewlett-Packard Default System BIOS CZC8196Q8S HPQOEM - ...
PS C:\> gwmi win32_bios | ft | Out-String -stream | Write-Debug
DEBUG:
DEBUG: SMBIOSBIOSVersi Manufacturer Name SerialNumber Version
DEBUG: on
DEBUG: --------------- ------------ ---- ------------ -------
DEBUG: 786F3 v01.34 Hewlett-Packard Default Syst... CZC8196Q8S HPQOEM - 201...
DEBUG:
DEBUG:PS C:\>
If you want write-debug to handle each one separately:
[string[]]$test = #("test1", "test2", "test3")
Write-Output $test
test1
test2
test3
$DebugPreference = "Inquire"
$test | Write-Debug
DEBUG: test1
DEBUG: test2
DEBUG: test3
Write-Debug is designed for outputting simple messages when debug preferences are set in a particular way. It takes only a string, not just anything like Write-Host does (and magically formats). You will have to format your output yourself into a single string.
You could combine Write-Host and Write-Debug if you have extra info to output before prompting the user:
if ($DebugPreference -ne 'SilentlyContinue') {
Write-Host 'such-and-such array:' $array
}
Write-Debug 'such-and-such array dumped'
Write-Host is used because it will always write to the console host, rather than to the script's output, as Write-Output does. If you where redirecting standard output of the script to a file, Write-Output would end up in the file, while Write-Host would still be seen in the console.
You could also try doing something like this if your array is of simply enough types that an automatic call to ToString() on them (if they're not strings already) gets you what you want:
$array = 'Alice','Bob','Charlie'
Write-Debug ([String]::Join("`n", $array))
Write-Debug:
Write-Debug [-Message] <string> [<CommonParameters>]
It expects a string. It is unable to convert a string array to a string as the error says. The reason why it expects a string is because it writes debug messages to the console from a script or command.
Note that Write-Output and Write-Host take an object:
Write-Output [-InputObject] <PSObject[]> [<CommonParameters>]
and
Write-Host [[-Object] <Object>] ...